How do you play or record audio (to .WAV) on Linux in C++?

守給你的承諾、 提交于 2019-12-12 08:41:10

问题


Hello, I've been looking for a way to play and record audio on a Linux (preferably Ubuntu) system. I'm currently working on a front-end to a voice recognition toolkit that'll automate a few steps required to adapt a voice model for PocketSphinx and Julius.

Suggestions of alternative means of audio input/output are welcome, as well as a fix to the bug shown below.

Here is the current code I've used so far to play a .WAV file:

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 );
    }    
}

NOTE: If you want the rest of the code to this file, you can download it here directly from Launchpad.

Update: I tried using GStreamermm, and this won't work:

    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);

回答1:


The "Hello World" application in the GStreamer documentation shows how to play an Ogg/Vorbis file. To make this work with WAV files, you can simply replace "oggdemux" with "wavparse" and replace "vorbisdec" with "identity" (the identity plugin does nothing -- it's just a placeholder).

To install development support for GStreamer (on Ubuntu)...

sudo apt-get install libgstreamer0.10-dev

You need the following on the gcc command-line to enable the use of GStreamer libraries...

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

By the way, you may find it useful to use "gst-launch" for prototyping GStreamer pipelines before writing the code.

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

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

A feature of GStreamer that may be useful for voice recognition is that it is easy to insert audio quality filters into a pipeline -- so you could, for example, reduce noise that might otherwise be in the recording. A pointer to a list of the GStreamer "good" plugins is here.

Also of interest, "PocketSphinx" (which seems to be related to your project) already has some GStreamer integration. See Using PocketSphinx with GStreamer and Python




回答2:


GStreamer/Pulse/JACK are great. For simple and fast things you might use SoX http://sox.sourceforge.net/



来源:https://stackoverflow.com/questions/4934074/how-do-you-play-or-record-audio-to-wav-on-linux-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!