Showing posts with label wav. Show all posts
Showing posts with label wav. Show all posts

Monday, July 11, 2011

Loading a wav File with SndfileHandle

Assuming you have libsndfile installed and properly building with your project (check here), it is time to read some audio from disk into an array. I think it's most convenient to use the C++ wrapper class 'SndfileHandle' defined in the sndfile.hh include as shown below:


#include "testApp.h"
#include <sndfile.hh>
#include <stdio.h>



void testApp::setup(){

.
.
.



const char* fn = "/Users/.../test.wav";
SndfileHandle myf = SndfileHandle(fn);
printf ("Opened file '%s'\n", fn) ;
printf ("    Sample rate : %d\n", myf.samplerate ()) ;
printf ("    Channels    : %d\n", myf.channels ()) ;
printf ("    Error       : %s\n", myf.strError());
printf ("    Frames      : %d\n"int(myf.frames())); 
puts("");



 static float buffer [1024]; 
 myf.read (buffer, 1024);
.
.
.



Aside - The 'frame' terminology initially confused me, as I tend to think of 'frames' as being chunks of multiple samples across the time axis (as in STFT analysis). In the libsndfile world however, a 'frame' is all of the values/samples for each channel at a given time instant. For example, if you have a stereo (2-channel) file, a frame will consist of two values or samples. If you have a mono (1-channel) file, a frame will consist of only one value or sample.

It's fairly non-obvious what is actually stored in our float buffer after the call to the SndfileHandle read() method. if you were dealing with MATLAB, you'd have a 2-dimensional array with each column holding the samples for either the right or left channel after a similar call to wavread(). You might even think it would make more sense for the read() method to return the samples corresponding to each channel separately. However, the read() method implemented in libsndfile fills up a 1-dimensional array of values.

For a mono (1-channel) audio file, the interpretation is simple. The buffer is filled with the audio samples just as you might expect:


buffer = [sample1, sample2, sample3, sample4, etc]


For a stereo (2-channel) audio file, the interpretation is less obvious. The buffer is filled with the audio samples in an interleaved fashion:


buffer = [left_sample1, right_sample1, left_sample2, right_sample2, etc]


This pattern continues for n-channel multichannel files.

If you want to inspect the contents of 'buffer' by hand, place a breakpoint after the read() function (double click in the wide column to the left of the text. A little blue tab/flag should appear). Next, go to Build -> Build and Debug, and wait until your program halts at the breakpoint. Now, go to Run -> Show -> Expressions. Enter the following in the the text field at the bottom of the dialogue:


*buffer @ 1024


Hopefully any newcomers to libsndfile and xcode will find this useful!