# ADDITIVE SYNTHESIS

Jean Baptiste Joseph Fourier demonstrated around 1800 that any continuous function can be perfectly described as a sum of sine waves. This in fact means that you can create any sound, no matter how complex, if you know which sine waves to add together.

This concept really excited the early pioneers of electronic music, who imagined that sine waves would give them the power to create any sound imaginable and previously unimagined. Unfortunately, they soon realized that while adding sine waves is easy, interesting sounds must have a large number of sine waves which are constantly varying in frequency and amplitude, which turns out to be a hugely impractical task.

However, additive synthesis can provide unusual and interesting sounds. Moreover both, the power of modern computers, and the ability of managing data in a programming language offer new dimensions of working with this old tool. As with most things in Csound there are several ways to go about it. We will try to show some of them, and see how they are connected with different programming paradigms.

## What are the main parameters of Additive Synthesis?

Before going into different ways of implementing additive synthesis in Csound, we shall think about the parameters to consider. As additive synthesis is the addition of several sine generators, the parameters are on two different levels:

**For each sine**, there is a frequency and an amplitude with an envelope.-
- The
**frequency**is usually a constant value. But it can be varied, though. Natural sounds usually have very slight changes of partial frequencies. - The
**amplitude**must at least have a simple envelope like the well-known ADSR. But more complex ways of continuously altering the amplitude will make the sound much more lively.

- The
**For the sound as a whole**, these are the relevant parameters:-
- The total
**number of sinusoids**. A sound which consists of just three sinusoids is of course "poorer" than a sound which consists of 100 sinusoids. - The
**frequency ratios**of the sine generators. For a classical harmonic spectrum, the multipliers of the sinusoids are 1, 2, 3, ... (If your first sine is 100 Hz, the others are 200, 300, 400, ... Hz.) For an inharmonic or noisy spectrum, there are probably no simple integer ratios. This frequency ratio is mainly responsible for our perception of timbre. - The
**base frequency**is the frequency of the first partial. If the partials are showing an harmonic ratio, this frequency (in the example given 100 Hz) is also the overall perceived pitch. - The
**amplitude ratios**of the sinusoids. This is also very important for the resulting timbre of a sound. If the higher partials are relatively strong, the sound appears more brilliant; if the higher partials are soft, the sound appears dark and soft. - The
**duration ratios**of the sinusoids. In simple additive synthesis, all single sines have the same duration, but they may also differ. This usually relates to the envelopes: if the envelopes of different partials vary, some partials may die away faster than others.

- The total

It is not always the aim of additive synthesis to imitate natural sounds, but it can definitely be learned a lot through the task of first analyzing and then attempting to imitate a sound using additive synthesis techniques. This is what a guitar note looks like when spectrally analyzed:

*Spectral analysis of a guitar tone in time (courtesy of W. Fohl, Hamburg) *

Each partial has its own movement and duration. We may or may not be able to achieve this successfully in additive synthesis. Let us begin with some simple sounds and consider ways of programming this with Csound; later we will look at some more complex sounds and advanced ways of programming this.

## Simple Additions of Sinusoids inside an Instrument

If additive synthesis amounts to the adding sine generators, it is straightforward to create multiple oscillators in a single instrument and to add the resulting audio signals together. In the following example, instrument 1 shows a harmonic spectrum, and instrument 2 an inharmonic one. Both instruments share the same amplitude multipliers: 1, 1/2, 1/3, 1/4, ... and receive the base frequency in Csound's pitch notation (octave.semitone) and the main amplitude in dB.

**EXAMPLE 04A01_AddSynth_simple.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;example by Andrés Cabrera sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 ;harmonic additive synthesis ;receive general pitch and volume from the score ibasefrq = cpspch(p4) ;convert pitch values to frequency ibaseamp = ampdbfs(p5) ;convert dB to amplitude ;create 8 harmonic partials aOsc1 poscil ibaseamp, ibasefrq, giSine aOsc2 poscil ibaseamp/2, ibasefrq*2, giSine aOsc3 poscil ibaseamp/3, ibasefrq*3, giSine aOsc4 poscil ibaseamp/4, ibasefrq*4, giSine aOsc5 poscil ibaseamp/5, ibasefrq*5, giSine aOsc6 poscil ibaseamp/6, ibasefrq*6, giSine aOsc7 poscil ibaseamp/7, ibasefrq*7, giSine aOsc8 poscil ibaseamp/8, ibasefrq*8, giSine ;apply simple envelope kenv linen 1, p3/4, p3, p3/4 ;add partials and write to output aOut = aOsc1 + aOsc2 + aOsc3 + aOsc4 + aOsc5 + aOsc6 + aOsc7 + aOsc8 outs aOut*kenv, aOut*kenv endin instr 2 ;inharmonic additive synthesis ibasefrq = cpspch(p4) ibaseamp = ampdbfs(p5) ;create 8 inharmonic partials aOsc1 poscil ibaseamp, ibasefrq, giSine aOsc2 poscil ibaseamp/2, ibasefrq*1.02, giSine aOsc3 poscil ibaseamp/3, ibasefrq*1.1, giSine aOsc4 poscil ibaseamp/4, ibasefrq*1.23, giSine aOsc5 poscil ibaseamp/5, ibasefrq*1.26, giSine aOsc6 poscil ibaseamp/6, ibasefrq*1.31, giSine aOsc7 poscil ibaseamp/7, ibasefrq*1.39, giSine aOsc8 poscil ibaseamp/8, ibasefrq*1.41, giSine kenv linen 1, p3/4, p3, p3/4 aOut = aOsc1 + aOsc2 + aOsc3 + aOsc4 + aOsc5 + aOsc6 + aOsc7 + aOsc8 outs aOut*kenv, aOut*kenv endin </CsInstruments> <CsScore> ; pch amp i 1 0 5 8.00 -10 i 1 3 5 9.00 -14 i 1 5 8 9.02 -12 i 1 6 9 7.01 -12 i 1 7 10 6.00 -10 s i 2 0 5 8.00 -10 i 2 3 5 9.00 -14 i 2 5 8 9.02 -12 i 2 6 9 7.01 -12 i 2 7 10 6.00 -10 </CsScore> </CsoundSynthesizer>

## Simple Additions of Sinusoids via the Score

A typical paradigm in programming: If you find some almost identical lines in your code, consider to abstract it. For the Csound Language this can mean, to move parameter control to the score. In our case, the lines

aOsc1 poscil ibaseamp, ibasefrq, giSine aOsc2 poscil ibaseamp/2, ibasefrq*2, giSine aOsc3 poscil ibaseamp/3, ibasefrq*3, giSine aOsc4 poscil ibaseamp/4, ibasefrq*4, giSine aOsc5 poscil ibaseamp/5, ibasefrq*5, giSine aOsc6 poscil ibaseamp/6, ibasefrq*6, giSine aOsc7 poscil ibaseamp/7, ibasefrq*7, giSine aOsc8 poscil ibaseamp/8, ibasefrq*8, giSine

can be abstracted to the form

aOsc poscil ibaseamp*iampfactor, ibasefrq*ifreqfactor, giSine

with the parameters *iampfactor* (the relative amplitude of a partial) and *ifreqfactor* (the frequency multiplier) transferred to the score.

The next version simplifies the instrument code and defines the variable values as score parameters:

**EXAMPLE 04A02_AddSynth_score.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;example by Andrés Cabrera and Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 iBaseFreq = cpspch(p4) iFreqMult = p5 ;frequency multiplier iBaseAmp = ampdbfs(p6) iAmpMult = p7 ;amplitude multiplier iFreq = iBaseFreq * iFreqMult iAmp = iBaseAmp * iAmpMult kEnv linen iAmp, p3/4, p3, p3/4 aOsc poscil kEnv, iFreq, giSine outs aOsc, aOsc endin </CsInstruments> <CsScore> ; freq freqmult amp ampmult i 1 0 7 8.09 1 -10 1 i . . 6 . 2 . [1/2] i . . 5 . 3 . [1/3] i . . 4 . 4 . [1/4] i . . 3 . 5 . [1/5] i . . 3 . 6 . [1/6] i . . 3 . 7 . [1/7] s i 1 0 6 8.09 1.5 -10 1 i . . 4 . 3.1 . [1/3] i . . 3 . 3.4 . [1/6] i . . 4 . 4.2 . [1/9] i . . 5 . 6.1 . [1/12] i . . 6 . 6.3 . [1/15] </CsScore> </CsoundSynthesizer>

You might say: Okay, where is the simplification? There are even more lines than before! - This is true, and this is certainly just a step on the way to a better code. The main benefit now is *flexibility*. Now our code is capable of realizing any number of partials, with any amplitude, frequency and duration ratios. Using the Csound score abbreviations (for instance a dot for repeating the previous value in the same p-field), you can do a lot of copy-and-paste, and focus on what is changing from line to line.

Note also that you are now calling **one instrument in multiple instances** at the same time for performing additive synthesis. In fact, each instance of the instrument contributes just one partial for the additive synthesis. This call of multiple and simultaneous instances of one instrument is also a typical procedure for situations like this, and for writing clean and effective Csound code. We will discuss later how this can be done in a more elegant way than in the last example.

## Creating Function Tables for Additive Synthesis

Before we continue on this road, let us go back to the first example and discuss a classical and abbreviated method of playing a number of partials. As we mentioned at the beginning, Fourier stated that any periodic oscillation can be described as a sum of simple sinusoids. If the single sinusoids are static (no individual envelope or duration), the resulting waveform will always be the same.

You see four sine generators, each with fixed frequency and amplitude relations, and mixed together. At the bottom of the illustration you see the composite waveform which repeats itself at each period. So - why not just calculate this composite waveform first, and then read it with just one oscillator?

This is what some Csound GEN routines do. They compose the resulting shape of the periodic wave, and store the values in a function table. GEN10 can be used for creating a waveform consisting of harmonically related partials. After the common GEN routine p-fields

<table number>, <creation time>, <size in points>, <GEN number>

you have just to determine the relative strength of the harmonics. GEN09 is more complex and allows you to also control the frequency multiplier and the phase (0-360°) of each partial. We are able to reproduce the first example in a shorter (and computational faster) form:

**EXAMPLE 04A03_AddSynth_GEN.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;example by Andrés Cabrera and Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 giHarm ftgen 1, 0, 2^12, 10, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8 giNois ftgen 2, 0, 2^12, 9, 100,1,0, 102,1/2,0, 110,1/3,0, \ 123,1/4,0, 126,1/5,0, 131,1/6,0, 139,1/7,0, 141,1/8,0 instr 1 iBasFreq = cpspch(p4) iTabFreq = p7 ;base frequency of the table iBasFreq = iBasFreq / iTabFreq iBaseAmp = ampdb(p5) iFtNum = p6 aOsc poscil iBaseAmp, iBasFreq, iFtNum aEnv linen aOsc, p3/4, p3, p3/4 outs aEnv, aEnv endin </CsInstruments> <CsScore> ; pch amp table table base (Hz) i 1 0 5 8.00 -10 1 1 i . 3 5 9.00 -14 . . i . 5 8 9.02 -12 . . i . 6 9 7.01 -12 . . i . 7 10 6.00 -10 . . s i 1 0 5 8.00 -10 2 100 i . 3 5 9.00 -14 . . i . 5 8 9.02 -12 . . i . 6 9 7.01 -12 . . i . 7 10 6.00 -10 . . </CsScore> </CsoundSynthesizer>

As you can see, for non-harmonically related partials, the construction of a table must be done with a special care. If the frequency multipliers in our first example started with 1 and 1.02, the resulting period is acually very long. For a base frequency of 100 Hz, you will have the frequencies of 100 Hz and 102 Hz overlapping each other. So you need 100 cycles from the 1.00 multiplier and 102 cycles from the 1.02 multiplier to complete one period and to start again both together from zero. In other words, we have to create a table which contains 100 respectively 102 periods, instead of 1 and 1.02. Then the table values are not related to 1 - as usual - but to 100. That is the reason we have to introduce a new parameter *iTabFreq* for this purpose.

This method of composing waveforms can also be used for generating the four standard historical shapes used in a synthesizer. An **impulse** wave can be created by adding a number of harmonics of the same strength. A **sawtooth** has the amplitude multipliers 1, 1/2, 1/3, ... for the harmonics. A **square** has the same multipliers, but just for the odd harmonics. A **triangle** can be calculated as 1 divided by the square of the odd partials, with swaping positive and negative values. The next example creates function tables with just ten partials for each standard form.

**EXAMPLE 04A04_Standard_waveforms.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giImp ftgen 1, 0, 4096, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 giSaw ftgen 2, 0, 4096, 10, 1,1/2,1/3,1/4,1/5,1/6,1/7,1/8,1/9,1/10 giSqu ftgen 3, 0, 4096, 10, 1, 0, 1/3, 0, 1/5, 0, 1/7, 0, 1/9, 0 giTri ftgen 4, 0, 4096, 10, 1, 0, -1/9, 0, 1/25, 0, -1/49, 0, 1/81, 0 instr 1 asig poscil .2, 457, p4 outs asig, asig endin </CsInstruments> <CsScore> i 1 0 3 1 i 1 4 3 2 i 1 8 3 3 i 1 12 3 4 </CsScore> </CsoundSynthesizer>

## Triggering Sub-instruments for the Partials

Performing additive synthesis by designing partial strengths into function tables has the disadvantage that once a note has begun there is no way of varying the relative strengths of individual partials. There are various methods to circumvent the inflexibility of table-based additive synthesis such as morphing between several tables (using for example the ftmorf opcode). Next we will consider another approach: triggering one instance of a sub-instrument for each partial, and exploring the possibilities of creating a spectrally dynamic sound using this technique.

Let us return to the second instrument (05A02.csd) which already made some abstractions and triggered one instrument instance for each partial. This was done in the score; but now we will trigger one complete note in one score line, not just one partial. The first step is to assign the desired number of partials via a score parameter. The next example triggers any number of partials using this one value:

**EXAMPLE 04A05_Flexible_number_of_partials.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 ;master instrument inumparts = p4 ;number of partials ibasfreq = 200 ;base frequency ipart = 1 ;count variable for loop ;loop for inumparts over the ipart variable ;and trigger inumpartss instanes of the subinstrument loop: ifreq = ibasfreq * ipart iamp = 1/ipart/inumparts event_i "i", 10, 0, p3, ifreq, iamp loop_le ipart, 1, inumparts, loop endin instr 10 ;subinstrument for playing one partial ifreq = p4 ;frequency of this partial iamp = p5 ;amplitude of this partial aenv transeg 0, .01, 0, iamp, p3-0.1, -10, 0 apart poscil aenv, ifreq, giSine outs apart, apart endin </CsInstruments> <CsScore> ; number of partials i 1 0 3 10 i 1 3 3 20 i 1 6 3 2 </CsScore> </CsoundSynthesizer>

This instrument can easily be transformed to be played via a midi keyboard. The next example connects the number of synthesized partials with the midi velocity. So if you play softly, the sound will have fewer partials than if a key is struck with force.

**EXAMPLE 04A06_Play_it_with_Midi.csd**

<CsoundSynthesizer> <CsOptions> -o dac -Ma </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 massign 0, 1 ;all midi channels to instr 1 instr 1 ;master instrument ibasfreq cpsmidi ;base frequency iampmid ampmidi 20 ;receive midi-velocity and scale 0-20 inparts = int(iampmid)+1 ;exclude zero ipart = 1 ;count variable for loop ;loop for inparts over the ipart variable ;and trigger inparts instances of the sub-instrument loop: ifreq = ibasfreq * ipart iamp = 1/ipart/inparts event_i "i", 10, 0, 1, ifreq, iamp loop_le ipart, 1, inparts, loop endin instr 10 ;subinstrument for playing one partial ifreq = p4 ;frequency of this partial iamp = p5 ;amplitude of this partial aenv transeg 0, .01, 0, iamp, p3-.01, -3, 0 apart poscil aenv, ifreq, giSine outs apart/3, apart/3 endin </CsInstruments> <CsScore> f 0 3600 </CsScore> </CsoundSynthesizer>

Although this instrument is rather primitive it is useful to be able to control the timbre in this way using key velocity. Let us continue to explore some other methods of creating parameter variation in additive synthesis.

## User-controlled Random Variations in Additive Synthesis

In natural sounds, there is movement and change all the time. Even the best player or singer will not be able to play a note in the exact same way twice. And within a tone, the partials have some unsteadiness all the time: slight excitations in the amplitudes, uneven durations, slight frequency fluctuations. In an audio programming environment like Csound, we can achieve these movements with random deviations. It is not so important whether we use randomness or not, rather in which way. The boundaries of random deviations must be adjusted as carefully as with any other parameter in electronic composition. If sounds using random deviations begin to sound like mistakes then it is probably less to do with actually using random functions but instead more to do with some poorly chosen boundaries.

Let us start with some random deviations in our subinstrument. These parameters can be affected:

- The
**frequency**of each partial can be slightly detuned. The range of this possible maximum detuning can be set in cents (100 cent = 1 semitone). - The
**amplitude**of each partial can be altered, compared to its standard value. The alteration can be measured in Decibel (dB). - The
**duration**of each partial can be shorter or longer than the standard value. Let us define this deviation as a percentage. If the expected duration is five seconds, a maximum deviation of 100% means getting a value between half the duration (2.5 sec) and the double duration (10 sec).

The following example shows the effect of these variations. As a base - and as a reference to its author - we take the "bell-like sound" which Jean-Claude Risset created in his Sound Catalogue.^{1}

**EXAMPLE 04A07_Risset_variations.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 ;frequency and amplitude multipliers for 11 partials of Risset's bell giFqs ftgen 0, 0, -11,-2,.56,.563,.92, .923,1.19,1.7,2,2.74, \ 3,3.74,4.07 giAmps ftgen 0, 0, -11, -2, 1, 2/3, 1, 1.8, 8/3, 1.46, 4/3, 4/3, 1, 4/3 giSine ftgen 0, 0, 2^10, 10, 1 seed 0 instr 1 ;master instrument ibasfreq = 400 ifqdev = p4 ;maximum freq deviation in cents iampdev = p5 ;maximum amp deviation in dB idurdev = p6 ;maximum duration deviation in % indx = 0 ;count variable for loop loop: ifqmult tab_i indx, giFqs ;get frequency multiplier from table ifreq = ibasfreq * ifqmult iampmult tab_i indx, giAmps ;get amp multiplier iamp = iampmult / 20 ;scale event_i "i", 10, 0, p3, ifreq, iamp, ifqdev, iampdev, idurdev loop_lt indx, 1, 11, loop endin instr 10 ;subinstrument for playing one partial ;receive the parameters from the master instrument ifreqnorm = p4 ;standard frequency of this partial iampnorm = p5 ;standard amplitude of this partial ifqdev = p6 ;maximum freq deviation in cents iampdev = p7 ;maximum amp deviation in dB idurdev = p8 ;maximum duration deviation in % ;calculate frequency icent random -ifqdev, ifqdev ;cent deviation ifreq = ifreqnorm * cent(icent) ;calculate amplitude idb random -iampdev, iampdev ;dB deviation iamp = iampnorm * ampdb(idb) ;calculate duration idurperc random -idurdev, idurdev ;duration deviation (%) iptdur = p3 * 2^(idurperc/100) p3 = iptdur ;set p3 to the calculated value ;play partial aenv transeg 0, .01, 0, iamp, p3-.01, -10, 0 apart poscil aenv, ifreq, giSine outs apart, apart endin </CsInstruments> <CsScore> ; frequency amplitude duration ; deviation deviation deviation ; in cent in dB in % ;;unchanged sound (twice) r 2 i 1 0 5 0 0 0 s ;;slight variations in frequency r 4 i 1 0 5 25 0 0 ;;slight variations in amplitude r 4 i 1 0 5 0 6 0 ;;slight variations in duration r 4 i 1 0 5 0 0 30 ;;slight variations combined r 6 i 1 0 5 25 6 30 ;;heavy variations r 6 i 1 0 5 50 9 100 </CsScore> </CsoundSynthesizer>

For a midi-triggered descendant of the instrument, we can - as one of many possible choices - vary the amount of possible random variation on the key velocity. So a key pressed softly plays the bell-like sound as described by Risset but as a key is struck with increasing force the sound produced will be increasingly altered.

**EXAMPLE 04A08_Risset_played_by_Midi.csd**

<CsoundSynthesizer> <CsOptions> -o dac -Ma </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 ;frequency and amplitude multipliers for 11 partials of Risset's bell giFqs ftgen 0, 0, -11, -2, .56,.563,.92,.923,1.19,1.7,2,2.74,3,\ 3.74,4.07 giAmps ftgen 0, 0, -11, -2, 1, 2/3, 1, 1.8, 8/3, 1.46, 4/3, 4/3, 1,\ 4/3 giSine ftgen 0, 0, 2^10, 10, 1 seed 0 massign 0, 1 ;all midi channels to instr 1 instr 1 ;master instrument ;;scale desired deviations for maximum velocity ;frequency (cent) imxfqdv = 100 ;amplitude (dB) imxampdv = 12 ;duration (%) imxdurdv = 100 ;;get midi values ibasfreq cpsmidi ;base frequency iampmid ampmidi 1 ;receive midi-velocity and scale 0-1 ;;calculate maximum deviations depending on midi-velocity ifqdev = imxfqdv * iampmid iampdev = imxampdv * iampmid idurdev = imxdurdv * iampmid ;;trigger subinstruments indx = 0 ;count variable for loop loop: ifqmult tab_i indx, giFqs ;get frequency multiplier from table ifreq = ibasfreq * ifqmult iampmult tab_i indx, giAmps ;get amp multiplier iamp = iampmult / 20 ;scale event_i "i", 10, 0, 3, ifreq, iamp, ifqdev, iampdev, idurdev loop_lt indx, 1, 11, loop endin instr 10 ;subinstrument for playing one partial ;receive the parameters from the master instrument ifreqnorm = p4 ;standard frequency of this partial iampnorm = p5 ;standard amplitude of this partial ifqdev = p6 ;maximum freq deviation in cents iampdev = p7 ;maximum amp deviation in dB idurdev = p8 ;maximum duration deviation in % ;calculate frequency icent random -ifqdev, ifqdev ;cent deviation ifreq = ifreqnorm * cent(icent) ;calculate amplitude idb random -iampdev, iampdev ;dB deviation iamp = iampnorm * ampdb(idb) ;calculate duration idurperc random -idurdev, idurdev ;duration deviation (%) iptdur = p3 * 2^(idurperc/100) p3 = iptdur ;set p3 to the calculated value ;play partial aenv transeg 0, .01, 0, iamp, p3-.01, -10, 0 apart poscil aenv, ifreq, giSine outs apart, apart endin </CsInstruments> <CsScore> f 0 3600 </CsScore> </CsoundSynthesizer>

It will depend on the power of your computer whether you can play examples like this in realtime. Have a look at chapter 2D (Live Audio) for tips on getting the best possible performance from your Csound orchestra.

In the next example we will use additive synthesis to make a kind of a wobble bass. It starts as a bass, then evolve to something else, and then ends as a bass again. We will first generate all the inharmonic partials with a loop. Ordinary partials are arithmetic, we add the same value to one partial to get to the next. In this example we will instead use geometric partials, we will multiplicate one partial with a certain number (kfreqmult) to get the next partial frequency. This number is not constant, but is generated by a sine oscilator. This is frequency modulation. Then some randomness is added to make a more interesting sound, and chorus effect to make the sound more "fat". The exponential function, exp, is used because if we move upwards in common musical scales, then the frequencies grow exponentially.

** EXAMPLE 04A09_Wobble_bass.csd**

<CsoundSynthesizer> ; Wobble bass made with additive synthesis <CsOptions> ; and frequency modulation -odac </CsOptions> <CsInstruments> ; Example by Bjørn Houdorf, March 2013 sr = 44100 ksmps = 1 nchnls = 2 0dbfs = 1 instr 1 kamp = 24 ; Amplitude kfreq expseg p4, p3/2, 50*p4, p3/2, p4 ; Base frequency iloopnum = p5 ; Number of all partials generated alyd1 init 0 alyd2 init 0 seed 0 kfreqmult oscili 1, 2, 1 kosc oscili 1, 2.1, 1 ktone randomh 0.5, 2, 0.2 ; A random input icount = 1 loop: ; Loop to generate partials to additive synthesis kfreq = kfreqmult * kfreq atal oscili 1, 0.5, 1 apart oscili 1, icount*exp(atal*ktone) , 1 ; Modulate each partials anum = apart*kfreq*kosc asig1 oscili kamp, anum, 1 asig2 oscili kamp, 1.5*anum, 1 ; Chorus effect to make the sound more "fat" asig3 oscili kamp, 2*anum, 1 asig4 oscili kamp, 2.5*anum, 1 alyd1 = (alyd1 + asig1+asig4)/icount ;Sum of partials alyd2 = (alyd2 + asig2+asig3)/icount loop_lt icount, 1, iloopnum, loop ; End of loop outs alyd1, alyd2 ; Output generated sound endin </CsInstruments> <CsScore> f1 0 128 10 1 i1 0 60 110 50 e </CsScore> </CsoundSynthesizer>

## gbuzz, buzz and GEN11

gbuzz is useful for creating additive tones made of of harmonically related cosine waves. Rather than define attributes for every partial individually gbuzz allows us to define global aspects for the additive tone, specifically, the number of partials in the tone, the partial number of the lowest partial present and an amplitude coefficient multipler which shifts the peak of spectral energy in the tone. Number of harmonics (knh) and lowest hamonic (klh) although k-rate arguments are only interpreted as integers by the opcode therefore changes from integer to integer will result in discontinuities in the output signal. The amplitude coefficient multiplier allows smooth modulations.

In the following example a 100Hz tone is created in which the number of partials it contains rises from 1 to 20 across its 8 second duration. A spectrogram/sonogram displays how this manifests spectrally. A linear frequency scale is employed so that partials appear equally spaced.

** EXAMPLE 04A10_gbuzz.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 ; a cosine wave gicos ftgen 0, 0, 2^10, 11, 1 instr 1 knh line 1, p3, 20 ; number of harmonics klh = 1 ; lowest harmonic kmul = 1 ; amplitude coefficient multiplier asig gbuzz 1, 100, knh, klh, kmul, gicos outs asig, asig endin </CsInstruments> <CsScore> i 1 0 8 e </CsScore> </CsoundSynthesizer>

The total number of partials only reaches 19 because the line function only reaches 20 at the very conclusion of the note.

In the next example the number of partials contained within the tone remains constant but the partial number of the lowest partial rises from 1 to 20.

** EXAMPLE 04A11_gbuzz_partials_rise.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 ; a cosine wave gicos ftgen 0, 0, 2^10, 11, 1 instr 1 knh = 20 klh line 1, p3, 20 kmul = 1 asig gbuzz 1, 100, knh, klh, kmul, gicos outs asig, asig endin </CsInstruments> <CsScore> i 1 0 8 e </CsScore> </CsoundSynthesizer>

In the sonogram it can be seen how, as lowermost partials are removed, additional partials are added at the top ot the spectrum. This is because the total number of partials remains constant at 20.

In the final gbuzz example the amplitude coefficient multiplier rises from 0 to 2. It can be heard (and seen in the sonogram) how, when this value is zero greatest emphasis is placed on the lowermost partial and when this value is 2 the uppermost partial has the greatest emphasis.

** EXAMPLE 04A12_gbuzz_amp_coeff_rise.csd**

<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 ; a cosine wave gicos ftgen 0, 0, 2^10, 11, 1 instr 1 knh = 20 klh = 1 kmul line 0, p3, 2 asig gbuzz 1, 100, knh, klh, kmul, gicos fout "gbuzz3.wav",4,asig endin </CsInstruments> <CsScore> i 1 0 8 e </CsScore> </CsoundSynthesizer>

buzz is a simplified version of gbuzz with fewer parameters – it does not provide for modulation of the lowest partial number and amplitude coefficient multiplier.

GEN11 creates a function table waveform using the same parameters as gbuzz. When a gbuzz tone is required but no performance time modulation of its parameters is needed GEN11 may provide a more efficient option. GEN11 also opens the possibility of using its waveforms in a variety of other opcodes. gbuzz, buzz and GEN11 may prove useful as a source in subtractive synthesis.

Additive synthesis can still be an exciting way of producing sounds. The nowadays computational power and programming structures open the way for new discoveries and ideas. The later examples were intended to show some of these potentials of additive synthesis in Csound.

- Jean-Claude Risset, Introductory Catalogue of Computer Synthesized Sounds (1969), cited after Dodge/Jerse, Computer Music, New York / London 1985, p.94
^{^}