Additive Synthesis#

In additive synthesis we start with very simple waveforms, for example, a bunch of sine waves. To create more complex signals and therefore sounds, we add them together. Adding two waveforms together can lead to a sound that is very distinct from the sound generated by the two separated waveforms. For example, two sine waves can cancel each other out, leaving us with silence.

The power and beauty of additive synthesis is the level of control in our hands to generate our sound. Most analog, as well as digital synthesizers offer a variety of basic waveforms for building sounds. However, if the wave’s shape is predefined, we have no control (outside of filtering) over the individual harmonics. In contrast, additive synthesis gives us granular and independent control over each wave’s parameters. We can directly control the power of each frequency of the final result over time (amplitude modulation). In fact, we can also change and detune frequencies over time (frequency modulation).

Additive synthesis is suitable for various types of sound, but it suits very well for xylophones, bells, and other metallic instruments, typically inharmonic sounds. Even if these instruments vibrate inharmonically, they do not necessarily lack pitch. For example, bells, xylophones, and even drums can be tuned. Nevertheless, using only harmonic waveforms, such as a sawtooth wave, square wave, or triangle wave, would not be enough to synthesize such instruments.

Using the following code, we can generate an approximation of the sawtooth wave using 12 harmonics by using additive synthesis. We put all odd harmonics in the left and all even harmonics in the right channel. Additionally, each harmonic has its distinct randomized envelope. Therefore, even if the harmonics are the same, if we run the code multiple times, the sound is different because each time, the envelopes are different. We can not do the same using a predefined sawtooth wave!

(
Ndef(\sine_sum, {
    var sig, amp, odd, even, env;
    amp = 0.1;
    odd = Array.series(6, 1, 2);
    even = odd + 1;
    env = EnvGen.ar(Env.perc(
        attackTime: {Rand(0.001, 0.1)}!6, 
        releaseTime: {Rand(1.0, 1.3)}!6, 
        curve: {Rand(-6, -2)}!6));
    sig = [
        Mix.ar(SinOsc.ar(freq: odd * \freq.kr(400), mul: 1/odd * env)), 
        Mix.ar(SinOsc.ar(freq: even * \freq.kr(400), mul: 1/even * env))
    ];
    sig*0.1;
}).play;
)

Let us also listen to some inharmonics, created by additive synthesis. We use 20 partials with a random frequency between 150 and 4000. Higher frequencies are more likely. Again, each inharmonic partial has its individual envelope. It sounds like a bell and is quite inharmonic.

(
Ndef(\inharmonics, {
    var sig, inharmonics, env, partials = 20;
    env = EnvGen.ar(Env.perc(
        attackTime: 0, 
        releaseTime: {Rand(0.2, 2.0)}!partials, 
        level: {Rand(0, 1.0)}!partials, 
        curve: -4));

    inharmonics = Array.fill(partials, {exprand(150, 4000)});
    sig = SinOsc.ar(inharmonics) * partials.reciprocal * env * 3.0;
    sig = Splay.ar(sig);
    sig;
}).play;
)

The flexibility and power of additive synthesis come at a price. We require an oscillator for each of the partials, which can quickly lead to a computational overload – especially if our goal is real-time synthesis. To create an exciting sound, we need a lot of oscillators, i.e., we need complexity. For this reason, additive synthesis is hard to realize on analog synthesizers, and even digital synths can reach their limit quite fast.

However, modern computers are getting faster and faster, which might lead to a future revival of additive synthesis. Even if it is the basic technique of sound synthesis, it might become even more important – especially if we consider the possibilities of generative sound design supported by machine learning techniques.

Nevertheless, before we get ahead of ourselves, let us dive into the very basics of additive synthesis. Let us explore the basic waveforms we might want to combine.