Как вы воспроизводите или записываете аудио (в .WAV) в Linux на C++?

Здравствуйте, я искал способ воспроизведения и записи звука в системе Linux (предпочтительно Ubuntu). В настоящее время я работаю над внешним интерфейсом для набора инструментов распознавания голоса, который автоматизирует несколько шаги, необходимые для адаптации модели голоса для PocketSphinx и Julius.

Предложения по альтернативным средствам ввода/вывода звука приветствуются, а также исправление ошибки, показанной ниже.

Вот текущий код, который я использовал до сих пор для воспроизведения файла .WAV:

void Engine::sayText ( const string OutputText ) {
    string audioUri = "temp.wav";
    string requestUri = this->getRequestUri( OPENMARY_PROCESS , OutputText.c_str( ) );
    int error , audioStream;
    pa_simple *pulseConnection;
    pa_sample_spec simpleSpecs;
    simpleSpecs.format = PA_SAMPLE_S16LE;
    simpleSpecs.rate = 44100;
    simpleSpecs.channels = 2;

    eprintf( E_MESSAGE , "Generating audio for '%s' from '%s'..." , OutputText.c_str( ) , requestUri.c_str( ) );
    FILE* audio = this->getHttpFile( requestUri , audioUri );
    fclose(audio);
    eprintf( E_MESSAGE , "Generated audio.");

    if ( ( audioStream = open( audioUri.c_str( ) , O_RDONLY ) ) < 0 ) {
        fprintf( stderr , __FILE__": open() failed: %s\n" , strerror( errno ) );
        goto finish;
    }

    if ( dup2( audioStream , STDIN_FILENO ) < 0 ) {
        fprintf( stderr , __FILE__": dup2() failed: %s\n" , strerror( errno ) );
        goto finish;
    }

    close( audioStream );

    pulseConnection = pa_simple_new( NULL , "AudioPush" , PA_STREAM_PLAYBACK , NULL , "openMary C++" , &simpleSpecs , NULL , NULL , &error );

    for (int i = 0;;i++ ) {
        const int bufferSize = 1024;
        uint8_t audioBuffer[bufferSize];
        ssize_t r;
        eprintf( E_MESSAGE , "Buffering %d..",i);
        /* Read some data ... */
        if ( ( r = read( STDIN_FILENO , audioBuffer , sizeof (audioBuffer ) ) ) <= 0 ) {
            if ( r == 0 ) /* EOF */
                break;

            eprintf( E_ERROR , __FILE__": read() failed: %s\n" , strerror( errno ) );
    if ( pulseConnection )
        pa_simple_free( pulseConnection );

        }

        /* ... and play it */
        if ( pa_simple_write( pulseConnection , audioBuffer , ( size_t ) r , &error ) < 0 ) {
            fprintf( stderr , __FILE__": pa_simple_write() failed: %s\n" , pa_strerror( error ) );
    if ( pulseConnection )
        pa_simple_free( pulseConnection );

        }

        usleep(2);

    }
    /* Make sure that every single sample was played */
    if ( pa_simple_drain( pulseConnection , &error ) < 0 ) {
        fprintf( stderr , __FILE__": pa_simple_drain() failed: %s\n" , pa_strerror( error ) );
    if ( pulseConnection )
        pa_simple_free( pulseConnection );
    }    
}

ПРИМЕЧАНИЕ. Если вам нужен остальной код этого файла, вы можете загрузить его здесь прямо из Launchpad.

Обновление: я пытался использовать GStreamermm, и это не сработает:

    Glib::RefPtr<Pipeline> pipeline;
    Glib::RefPtr<Element> sink, filter, source;
    Glib::RefPtr<Gio::File> audioSrc = Gio::File::create_for_path(uri);

    pipeline = Pipeline::create("audio-playback");
    source = ElementFactory::create_element("alsasrc","source");
    filter = ElementFactory::create_element("identity","filter");
    sink = ElementFactory::create_element("alsasink","sink");
    //sink->get_property("file",audioSrc);
    if (!source || !filter || !sink){
        showErrorDialog("Houston!","We got a problem.");
        return;
    }
    pipeline->add(source)->add(filter)->add(sink);
    source->link(sink);

    pipeline->set_state(Gst::STATE_PLAYING);
    showInformation("Close this to stop recording");
    pipeline->set_state(Gst::STATE_PAUSED);

person jackyalcine    schedule 08.02.2011    source источник
comment
Это был бы лучший вопрос для stackoverflow.   -  person Michael K    schedule 08.02.2011
comment
Я бы рассмотрел библиотеку gstreamer для воспроизведения и записи. Но я полагаю, что Pulse также должен иметь параметры записи?   -  person Petriborg    schedule 08.02.2011
comment
@Michael Я разместил это на странице программирования, потому что предположил, что это связано с программированием. @Petriborg Можете ли вы продемонстрировать, как это сделать, или хорошую ссылку о том, как это сделать? GStreamer, кажется, поддерживает только OGG, а CMUSphinx нуждается в файлах WAV.   -  person jackyalcine    schedule 08.02.2011
comment
Где ошибка? что вы получаете, когда пытаетесь скомпилировать? Что вы хотите в качестве альтернативы?   -  person Tom    schedule 08.02.2011
comment
@ Том, это не ошибка программирования; это больше похоже на отсутствие кода. Когда он скомпилирован и запущен (вы можете попробовать, зайдя на панель запуска, загрузив и запустив), вместо того, чтобы услышать «Добро пожаловать в речь», вы услышите ПИФ! И я хочу что-то работающее :)   -  person jackyalcine    schedule 08.02.2011


Ответы (2)


Приложение "Hello World" в в документации GStreamer показано, как воспроизводить файл Ogg/Vorbis. Чтобы это работало с файлами WAV, вы можете просто заменить «oggdemux» на «wavparse» и заменить «vorbisdec» на «identity» (плагин Identity ничего не делает — это просто заполнитель).

Чтобы установить поддержку разработки для GStreamer (в Ubuntu)...

sudo apt-get install libgstreamer0.10-dev

Вам нужно следующее в командной строке gcc, чтобы включить использование библиотек GStreamer...

$(pkg-config --cflags --libs gstreamer-0.10)

Кстати, вам может оказаться полезным использовать «gst-launch» для прототипирования конвейеров GStreamer перед написанием кода.

## recording
gst-launch-0.10 autoaudiosrc ! wavenc ! filesink location=temp.wav

## playback
gst-launch-0.10 filesrc location=temp.wav ! wavparse ! autoaudiosink

Функция GStreamer, которая может быть полезна для распознавания голоса, заключается в том, что в конвейер легко вставлять фильтры качества звука, чтобы вы могли, например, уменьшить шум, который в противном случае мог бы быть в записи. Указатель на список «хороших» плагинов GStreamer: здесь.

Также интересно, что «PocketSphinx» (который, кажется, связан с вашим проектом) уже имеет некоторую интеграцию с GStreamer. См. раздел Использование PocketSphinx с GStreamer и Python.

person Brent Bradburn    schedule 08.02.2011
comment
Я не использовал Python для этого приложения; в основном это код на C++, так как это язык, который я знаю лучше всего, но вы мне очень помогли, и я отвечу своим статусом. - person jackyalcine; 08.02.2011
comment
Кроме того, я пытаюсь реализовать очень простой способ адаптации голосовых моделей для PocketSphinx/CMUSphinx. - person jackyalcine; 09.02.2011

GStreamer/Pulse/JACK отлично подходят. Для простых и быстрых вещей вы можете использовать SoX http://sox.sourceforge.net/

person Daniel Voina    schedule 27.02.2011
comment
У них есть API? я не могу использовать командную строку; Мне также нужно иметь возможность регулировать громкость. - person jackyalcine; 01.03.2011
comment
@Jacky Alcine: libsox — это библиотека для чтения/записи форматов звуковых файлов и процессоров звуковых эффектов. Он в основном разработан для использования SoX, но полезен для любого звукового приложения. Да, SoX тоже можно использовать как либу - подробности смотрите в архиве - person Daniel Voina; 01.03.2011