ignatius
ignatius

Reputation: 199

How to store audio data in a wrapped PortAudio callback

I'm trying to build an appilcation with GUI to record some audio using PortAudio library, therefore I'm using Qt (c++). To do thath, I have to wrap the PortAudio library to give it an object oriented style and I'm encountering some problemas with the audiocallback.

Preliminary explanation:

PortAudio uses a callback function like this:

static int recCallback(const void *inputBuffer,
                          void *outputBuffer,
                          unsigned long framesPerBuffer,
                          const PaStreamCallbackTimeInfo* timeInfo,
                          PaStreamCallbackFlags statusFlags,
                          void *userData)

Then, this callback is called in the PortAudio function Pa_OpenStream:

Pa_OpenStream(
            &stream,
            &inputParameters,
            NULL,                  
            SAMPLE_RATE,
            FRAMES_PER_BUFFER,
            paClipOff,     
            recordCallback,
            &data );

*userData in the callback function is the same pointer as &data in Pa_OpenStream, which is an array to store the audiobuffer so the audio can be writeen to a file. This can be done in the recCallback as:

static int recordCallback( const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo* timeInfo,
                       PaStreamCallbackFlags statusFlags,
                       void *userData )
{
//POINTER TO DATA DESTINATION
paTestData *data = (paTestData*)userData;
//POINTER TO INPUT BUFFER
SAMPLE *rptr = (SAMPLE*)inputBuffer;
... //MANIPUALTE AUDIO HERE

The problem arises when making the callback function a member of a class, for instance WrapperClass. I took a template for the wrapping from here.

class WrapperClass
{
 virtual int processingCallback(const void *inputBuffer,
                             void *outputBuffer,
                             unsigned long framesPerBuffer,
                             const PaStreamCallbackTimeInfo* timeInfo,
                             PaStreamCallbackFlags statusFlags);

  //portaudio need a static member function as callback,
  //this calls the non-static processing callback 
  method bypassing the object via userData
  static int paStaticCallback(const void *inputBuffer,
                          void *outputBuffer,
                          unsigned long framesPerBuffer,
                          const PaStreamCallbackTimeInfo* timeInfo,
                          PaStreamCallbackFlags statusFlags,
                          void *userData)
{return((WrapperClass*)userData)->processingCallback(inputBuffer,                              outputBuffer, framesPerBuffer, timeInfo, statusFlags,data);
  }

So, the static callback takes de *userdata argument as an object for the other callback. Now, the callback function is called in Pa_OpenStream as follows:

Pa_OpenStream(&stream,
                  &inputStreamParam,
                  &outputStreamParam,
                  sampleRate,
                  frameLength,
                  paNoFlag,
                  &WrapperClass::paStaticCallback,
                  this);

I think that in that way I'm sending the staticCallback a WrapperClass object, and then calling the virtual callback.

What I dont understand is that now I missed the argument *userData for storing the audio in the non-static callback, I can't figure out how to manage to have the pointer to the array in the "efective" callback function (the non-static one)

Thank you, hope have beeing clear enough

Upvotes: 0

Views: 708

Answers (1)

Ross Bencina
Ross Bencina

Reputation: 4173

The PortAudio distribution includes a C++ wraper in the bindings/cpp directory.

You don't have to wrap PortAudio to give it an OO style. The PortAudio C API works perfectly well in C++.

To answer your question: I would expect that the client of your code would subclass WrapperClass, override the processingCallback function, and have their data (e.g. array) as a member variable.

Upvotes: 1

Related Questions