Monday, August 5, 2013

Writing Portaudio Callbacks in Octave

It is now possible to have Octave functions supply audio data to be played by audioplayer objects. Stereo and mono playback is supported, the function must supply a specified number of audio frames and make sure to return a valid PortAudio status value (0 for continue, 1 for completed and 2 for abort). For example, put the following in a file called callback_noise.m:

function [ left, right, status ] = callback_noise (frames)
left = randn (1, frames) - 0.5;
right = randn (1, frames) - 0.5;
status = 0;

You can now use this as a callback as shown below.

player = audioplayer ('callback_noise', 44100);
play (player);
# play for as much you like
stop (player);

This will play white noise on both channels, which is not really interesting. To make matters more interesting we can use global variables to store state between callback calls. The following will play sine waves of different frequencies in both channels, place it in a file called callback_sine.m:

function [ left, right, status ] = callback_sine (frames)
global lphase = 0.0;
global rphase = 0.0;
incl = 440.0 / 44100.0;
incr = 443.0 / 44100.0;
nl = incl * frames;
nr = incr * frames;
left = sin (2.0 * pi * [lphase:incl:lphase+nl]);
right = sin (2.0 * pi * [rphase:incr:rphase+nr]);
status = 0;
lphase = lphase + nl;
rphase = rphase + nr;

Both of these examples will play for as long as you don't use the stop method on the player object you created. This shows an advantage of this mode of operation over having to store all data in memory at one time. This way only small portion of audio has to be stored at any given time.

During audioplayer object construction all the parameters work the same way as when passing audio data. You can supply bit depth and device ID in addition to sampling frequency if you want to.

No comments:

Post a Comment