octave:1> audioinfo('technical_difficulties.wav')For further information about this functionality refer to MATLAB manual pages on these functions: here and here.
ans =
scalar structure containing the fields:
Filename = technical_difficulties.wav
CompressionMethod =
NumChannels = 2
SampleRate = 44100
TotalSamples = 305576
Duration = 6.9292
BitsPerSample = 16
BitRate = -1
Title =
Artist =
Comment =
octave:2> [y, Fs] = audioread('technical_difficulties.wav');
octave:3> player = audioplayer(y, Fs);
octave:4> play(player);
Tuesday, August 20, 2013
Audio File Reading and Writing
I have implemented audioinfo and audioread and they should work exactly as in MATLAB. Here is an example session.
Sunday, August 18, 2013
Further Development
Since we already have a working version of the audioplayer and audiorecorder functionality that allows one to write callbacks in Octave here is my plan for further development. There are some issues to be ironed out but I think the interface and functionality will stay more or less the same. We have the firm "pencils down" date set at September 23 by Google.
- October 19-25 implement audioread and audioinfo using libsndfile.
- October 26-September 1 implement audiowrite.
- Use the remainder of the time to integrate everything into Octave proper and fix any issues, write documentation, tests, etc.
Saturday, August 17, 2013
Changes to Octave Callback Interface
The interface to PortAudio that allows you to write callback functions in Octave underwent slight changes. From now on sound is returned in a single Matrix with one or two columns (depending on number of channels) with as many rows as there are audio frames. An example playing back sine waves of different frequencies on the two channels is given below.
function [ sound, status ] = callback_sine (frames)An example of it's use is given below.
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]);
sound = [left', right'];
status = 0;
lphase = lphase + nl;
rphase = rphase + nr;
endfunction
player = audioplayer(@callback_sine);It is also possible to use Octave functions to process recorded data. An example that writes recorded data in to a text file is given below.
play(player);
# play as long as you want
stop(player);
function status = callback_record (sound)Here is a plot of the resulting file with me clapping three times. Only one channel is plotted.
fid = fopen('record.txt', 'at');
for index = 1:rows(sound)
fprintf(fid, "%.4f, %.4f\n", sound(index, 1), sound(index, 2));
endfor
fclose(fid);
status = 0;
endfunction
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;
endfunction
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;
endfunction
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.
function [ left, right, status ] = callback_noise (frames)
left = randn (1, frames) - 0.5;
right = randn (1, frames) - 0.5;
status = 0;
endfunction
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;
endfunction
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.
Subscribe to:
Posts (Atom)