The adventure continues. This time we occupy the world of tremolo as a digital signal processing effect; also known as amplitude modulation. My studies into the area of audio programming has progressed quite far I must say, covering the likes of filters and delays (get your math hats ready), reverb, and even plug-in development. In order to really solidify what I’ve been learning though, I decided to go back and create a program from scratch that will apply tremolo and vibrato to an existing audio file, and that’s where this blog entry comes in. For now I am just covering the tremolo effect as there is plenty to discuss here on that, while vibrato will be the subject of the next blog entry.
Tremolo in and of itself is pretty straightforward to implement, both on generating signals and on existing soundfiles. (Vibrato on the other hand is easy enough to apply on to signals being generated, but a bit more complex when it comes to sound input). Nonetheless, several challenges were met along the way that required a fair amount of research, experimentation and problem solving to overcome, but in doing so I’ve only expanded my knowledge in the area of DSP and audio programming. I think this is why I enjoy adventure games so much — chasing down solutions and the feeling you get when you solve a problem!
The tremolo effect is simply implemented by multiplying a signal by an LFO (low frequency oscillator). While LFOs are normally between 0 – 20 Hz, a cap of 10 Hz works well for tremolo. The other specification we need is depth — the amount of modulation the LFO will apply on to the original signal — specified in percent. A modulation depth of 100%, for example, will alternate between full signal strength to complete suppression of the signal at the frequency rate of the LFO. For a more subtle effect, a depth of around 30% or so will result in a much smoother amplitude variance of the signal. With this information we can develop a mathematical formula for deriving the modulating signal in which we can base our code on. This is also where I encountered one of my first big challenges. The formula I used at first (from the book Audio Programming) was:
ModSignal = 1 + DEPTH * sin(w * FREQ)
where w = 2 * pi / samplerate. This signal, derived from the LFO defined by the sine operation, would be used to modulate the incoming sound signal:
Signal = Signal * ModSignal
This produced the desired tremolo effect quite nicely. But when the original signal approached full amplitude, overmodulation would occur resulting in a nasty digital distortion. As can be seen in the above equation for the modulating signal, it will exceed 1 for values of sine > 0. Essentially this equation is a DC offset, which takes a normally bipolar signal and shifts it up or down. This is what we want to create the tremolo effect, but after realizing what was causing distortion in the output, I set about finding a new equation to calculate the modulating signal. After some searching, I found this:
ModSignal = (1 – DEPTH) + DEPTH * (sin(w * FREQ))2
This equation was much better in that it never exceeds 1, so it won’t result in overmodulation of the original signal. I did however make one personal modification to it; I decided not to square the sine operation after experimenting around with it in the main processing loop. Ideally we want to perform as few calculations (especially costly ones) within loops as possible. This is especially important in audio where responsiveness and efficiency are so important in real-time applications. To compensate for this I scale the DEPTH parameter from a percentage to a range of 0 – 0.5. From here we can now get into the code. First, initialization occurs:
Then the main processing loop:
With expandability and flexibility in mind, I began creating my own “oscillator” class which can be seen here:
This is where the power of C++ and object-oriented programming start to show itself. It affords the programmer much needed flexibility and efficiency in creating objects that can be portable between different programs and functions for future use, and this is definitely important for me as I can utilize these for upcoming plug-ins or standalone audio apps. Furthermore, by designing it with flexibility in mind, this will allow for the modulation of the modulator so-to-speak. In other words, we can time-vary the modulation frequency or depth through the use of envelopes or other oscillators. Values extracted from an envelope or oscillator can be passed into the “oscillator” class which processes and updates its internal data with the proper function calls. This will allow for anything from ramp ups of the tremolo effect to entirely new and more complex effects derived from amplitude modulation itself!
But now let’s get on to the listening part! For this demonstration I extracted a short segment of the Great Fairy Fountain theme from the Zelda 25th Anniversary CD release, probably my favorite theme from all of Zelda.
Here it is after being modulated with a frequency of 4.5 Hz at a depth of 40%:
And for a little more extreme tremolo, we can modulate it at 7.0 Hz at a depth of 85%:
This brings up another challenge that had to be overcome during the development of this program. Prior to this most of the work I had been studying in the book “Audio Programming” dealt with mono soundfiles. For this I really wanted to get into handling stereo files and this presented a few problems as I had to learn exactly how to properly process the buffer that holds all the sound data for stereo files. I am using libsndfile (http://www.mega-nerd.com/libsndfile/) to handle I/O on the actual soundfile being processed and this required me to search around and further adapt my code to work properly with this library. At one point I was getting very subtle distortion in all of my outputs as well as tremolo rates that were double (or even quadruple) the rates that I had specified. It took a lot of investigation and trial & error before I discovered the root of the problem lie in how I was handling the stereo files.
In closing off this blog entry, here is a further processing I did on the Zelda sample. After applying tremolo to it using the program I wrote, I put it through the pitch shifter VST plug-in I implemented to come up with a very eerie result. ‘Till next time!