PortAudio Tutorial

Writing a Callback Function

To write a program using PortAudio, you must include the "portaudio.h" include file. You may wish to read "portaudio.h" because it contains a complete description of the PortAudio functions and constants.
#include "portaudio.h"
The next task is to write your custom callback function. It is a function that is called by the PortAudio engine whenever it has captured audio data, or when it needs more audio data for output.

Your callback function is often called by an interrupt, or low level process so you should not do any complex system activities like allocating memory, or reading or writing files, or printf(). Just crunch numbers and generate audio signals. What is safe or not safe will vary from platform to platform. On the Macintosh, for example, you can only call "interrupt safe" routines. Also do not call any PortAudio functions in the callback except for Pa_StreamTime() and Pa_GetCPULoad().

Your callback function must return an int and accept the exact parameters specified in this typedef:

typedef int (PortAudioCallback)(
               void *inputBuffer, void *outputBuffer,
               unsigned long framesPerBuffer,
               PaTimestamp outTime, void *userData );
Here is an example callback function from the test file "patests/patest_saw.c". It calculates a simple left and right sawtooth signal and writes it to the output buffer. Notice that in this example, the signals are of float data type. The signals must be between -1.0 and +1.0. You can also use 16 bit integers or other formats which are specified during setup. You can pass a pointer to your data structure through PortAudio which will appear as userData.
int patestCallback(  void *inputBuffer, void *outputBuffer,
                     unsigned long framesPerBuffer,
                     PaTimestamp outTime, void *userData )
{
    unsigned int i;
/* Cast data passed through stream to our structure type. */
    paTestData *data = (paTestData*)userData;
    float *out = (float*)outputBuffer;
        
    for( i=0; i<framesPerBuffer; i++ )
    {
    /* Stereo channels are interleaved. */
        *out++ = data->left_phase;              /* left */
        *out++ = data->right_phase;             /* right */

    /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
        data->left_phase += 0.01f;
    /* When signal reaches top, drop back down. */
        if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;

    /* higher pitch so we can distinguish left and right. */
        data->right_phase += 0.03f; 
        if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
    }
    return 0;
}
home | contents | previousnext