Audio Programming in C: Creating Your IR Reverberation Effector

2_1
If you are a sound producer who is trying to apply the reverb effects on your track right now, usually there are two options without turning on those vintage gears on your rack:
  • Those fancy digital reverb plug-ins such as Lexicon PCM series (Assuming you totally understand each knob there…)
  • Mounting a decent impulse response and just let the plug-in works for you, like Altiverb products…
Guess most of the person will use Altiverb coz it’s simple enough to get a satisfying result so they always saying like ‘Yes, the plug-in is really amazing!’ (Or maybe just because they always hear some kind of whispering like ‘ Hey! The impulse response you are using now is from Carnegie Hall’……) Anyway, for this topic, we can try to see what exactly happened behind its beautiful interface.

Before we start, I assume you already know a little bit about C programming. And there is one more involved library you should know called libsndfile.

http://www.mega-nerd.com/libsndfile/

So basically, libsndfile is just a common cross-platform library for reading and writing audio. You could save lots of time with its help, such as instead of reading the header file of a .wav sound, just use the SF_INFO structure they offered:

     typedef struct
      {    sf_count_t  frames ;     
           int         samplerate ;
           int         channels ;
           int         format ;
           int         sections ;
           int         seekable ;
       } SF_INFO ;

Now let’s get it to work!

  • First, we start with the situation that you have two audio files on your laptop:

1. The dry signal waiting for being processed:

2.The impulse response which just is an audio to record how the environment interacts with an impulse signal.

  • As a good C programmer, probably you always need to think about allocating memory first. Here it is:

2_2

Basically, you can see that there should be three buffer to handle input file, output file, and IR(impulse response) file. And those ‘sfinfo’ for every single file, are the  SF_INFO structure we mentioned before.

  • And also, an error checking section will always be good…

2_3

From the screenshot above, you can see that first, I used sf_open function to read the dry signal and IR, do the error checking in the middle section, define the audio info for the output file and open it in the end.

  • Then, we should allocate buffers for both dry signal, IR, and output signal. From now on, you are about to deal with the sound sample by sample. And NEVER FORGET HOW MANY CHANNELS THERE…

2_4

So you may notice that besides we run the malloc for each channel of a file, the way how we define the length of the output file should attract you as well. Now let’s review something related to signal processing:

y = x[n] * h[k]

Imagine you are doing a convolution right now, and x is your dry signal which contains 8 samples, h is your 4 samples long impulse response file, and this is what exactly happened:

2_5

Generally, you are just multiplying each sample of you signal file with each sample in IR, and add them vertically for each column. Finally, you will get an 11 samples long file as your output. So we can conclude this useful formula:

Output File Length = Input File Length + IR Length – 1

Right now you should understand how we get the number of output frames in the program. (line.131)

  • Then, the next step will be the implementing convolution in our program.

2_6

The oframes will be the frame length of our output file, and each frame contains two samples for channel L and R. Similiar, start it with dealing with the channels.

The nested loop from line.45 to line.58 would be the core of this program. In the outer loop, you are just walk through every single sample of the current channel, and for each sample, using the inner loop to multiply it with samples in IR and do the summation in the end. Just like what the chart indicated above.

So the way we do convolution above is the most common way that might take a while to process your file, which depends on the length of frames. If possible, we can have another topic to introduce how to implement FFT here so the processed can be finished way faster. And you can treat that way as almost ‘in real-time’ so might be helpful to do the real-time HRTF rendering.

That’s it! After that, what you need to do is just write the output file, close the file, and free the buffer! Now let’s check what you got:

is that amazing? So now you know how the Altiverb works for you, it’s not a big deal, right?

  • In the end, here is a tip for reading and writing file: Like we mentioned before, if your program doesn’t work, go back to check if you forgot to deal with the channel in each part. Hope the scripts below can help you to handle the separate channel buffer and frame.

2_7


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s