Additive Synthesis

For this blog entry, I felt a good topic to cover would be additive synthesis and its implementation in C.  Based on Fourier theory, additive synthesis concerns combining simple periodic waveforms (such as sine or cosine waves) together that result in more complex sounds.  Put another way, any waveform can be expressed as a sum of sine waves due to the principle of the harmonic series which states that any sound contains an infinite number of overtones, or partials, as a diverging series.  These overtones, of a certain frequency and amplitude, when expressed as simple sinusoidal waves form the building blocks of a more complex waveform.  Mathematically this can be defined (for partials k = 1 to N, w = (2πf)/sample rate, and ø as the phase offset) as:

We can now, for example, create a sawtooth wave using this equation.  But first, here is a snippet of C code that generates a simple sine wave and outputs it to a raw binary data file (these can be read by most audio editing software like Audacity) as well as a text file that can be plotted (I used Gnuplot):

Here is the graph of the sine wave as well as the soundfile (converted to .wav from .raw):

Sine wave at 440Hz

Now let’s move on to generating the sawtooth wave and we’ll see how the simple sinusoidal wave above is transformed into a more complex waveform through the use of the Fourier series equation.  I set the total number of partials to 30 for this demonstration, and sawtooth waves contain all partials of the harmonic series with the amplitude of each equal to 1/partial (ak = 1/k).  We also set the phase offset as ø = -π/2.

Here is the graph and the soundfile output of the sawtooth wave:

Sawtooth wave at 440Hz

Now for something really funky!  If we go back to the Fourier series equation above as we defined it, both amplitude and frequency were invarying.  This is, as we know, not how sound behaves and really isn’t very interesting.  To generate much more interesting and complex waveforms, we set both the amplitude (a) and the frequency (f) as finite, time-varying functions.  I set up my code to read in a breakpoint file for both amplitude and frequency, each containing a few random values at arbitrary time locations to illustrate this.  (A breakpoint file contains data set up similar to coordinates, or points, that can be plotted.  In this case we have a amplitude vs. time and frequency vs. time.)  Here is the plot of the amplitude stream …

… and the frequency stream …

 

 

… and the C code that implements this:

The code that reads the breakpoint data uses linear interpolation to find the value at time n / sample rate.  The normalize_buffer routine adjusts the resulting amplitude to fit within the values of -1 and +1 and then scales it to the desired amplitude set by the user (in this case 0.7).  Following is a snapshot of the resulting waveform (just before the 1 second mark) in Gnuplot as well as the soundfile output; the result of just summing together simple sinusoidal waves as seen in the first Gnuplot above!

Crazy wave at.. ??Hz

This is a short and simple example of how flexible and powerful the Fourier series can be at creating textures and complex waveforms through additive synthesis.  The possibilities just escalate from here, depending on the time-varying functions that determine the amplitude and frequencies applied to the individual sinusoidal waves, i.e. the harmonics.

It must be pointed out that the code used to implement these routines above is brute force and not optimal.  For instance, to calculate these 3-second waves at a 44.1 kHz sampling rate with 30 partials requires 30 iterations through 132,300 (3 * 44,100) samples of data for a total of 3,969,000 loop iterations!  Calculating sine and cosine values is actually quite a costly operation, so this is unacceptable for most practical purposes.  One alternative is wavetable synthesis, whereby the data for one period of a basic wave is stored in a table and can then be looked up and utilized by the program.  This is much more efficient (though depending on the size of the table, there can be a loss in precision) as redundant trigonometric calculations don’t have to be repeatedly calculated.  This is potentially another topic for another time however.

For now, hope this was an interesting look into additive synthesis using the Fourier series and how with relatively few lines of code we can make some pretty cool things happen.

Advertisements

5 thoughts on “Additive Synthesis

  1. Ava

    is there a way that i could see this code in its entirely. i’m interested in seeing exactly what you did so i can understand everything further

    Reply
  2. Christian Post author

    I’m afraid I’ve done some pruning of old coding projects since this was posted, and this one was a casualty. Otherwise I’d put it up on Git Hub.

    I’d be happy to answer any questions you have though.

    Reply
  3. b_thats_me

    hi there, may i ask what you used to draw the breakpoint file, in the above example, like what program and what file format ?

    thanks 🙂

    Reply
    1. Christian Post author

      It was a program called Plot for OS X. Unfortunately it is no longer maintained as far as I can tell, and broke in OS X 10.10. It was able to import in a variety of formats, and I just used a tab-separated ASCII text file. i.e. rows of \t value pairs.

      Reply
      1. b_thats_me

        thx christian for letting me know … i will try to find something similar … i ve generally been looking to find a program that can extract points from a bezier / or a drawn curve … if you know any programs that can do that would be great to share if i find one ill post it here too … best

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s