Next: FM synthesis on SND Up: SND Previous: Tutorials-and-More about SND

Signal theory tells us that by means of the Fourier Transform, any periodic waveform can be represented as a sum of harmonically related sinusoids, each one with its own particular amplitude and phase. The timbre or the spectra of a sound can be viewed from two different perspectives known as the ``time domain'' and the ``frequency domain''. Depending on conditions and how a sound is being analyzed one view might be more useful than the other. For example in the case of additive synthesis, the frequency domain is more useful while if we were to edit a complete chunk of sound the time domain will certainly be more useful.

In theory the Fourier Transform (FFT) generates most of the information necessary to reconstruct a signal from a complex sound. Additive synthesis can be used for reconstructing a signal by synthesizing each partial as given on the FFT of the original signal but more generally speaking additive synthesis is used to sum and mix sinusoids to produce more complex sounds. This allows for control over the individual simple components by means of individual envelopes for amplitude and frequency.

Therefore one should be able to add up a bunch of sine waves and get any complex arbitrary signal. The simplest case is when all overtones are integer multiples of the fundamental frequency. In this simple case the waveform is periodic. As the periodic waveform repeats over time we can implement additive synthesis by using a table to store the values of one cycle instead of adding the output of all the equivalent sine oscillators (it is a lot more efficient). Here's a simple Snd instrument inspired on Fernando Lopez-Lezcano's (circa 1996) that implements additive synthesis by using the table-lookup unit generator. This is called harmonic synthesis by means of wave-table synthesis.

 ``` (define dowave (lambda* (start-time dur frequency amplitude harmonics) (let* ((start (floor (* start-time (srate)))) (len (floor (* dur (srate)))) ;; ;; create a table called "waveform" with the harmonics ;; (waveform (partials->wave harmonics )) ;; ;; create the table lookup unit generator ;; (s (make-table-lookup :frequency frequency :wave waveform)) ;; ;; add a simple amplitude envelope... ;; (amp-env (make-env :envelope '(0 0 0.5 1 1 0) :duration dur :scaler amplitude)) (output (make-vct len))) (do ((i 0 (1+ i))) ((= i len)) (vct-set! output i (* (env amp-env) (table-lookup s)) )) (vct->channel output start len)))) ```
You can try the following function calls to listen to the tones.

• Open a new sound:

 ``` (new-sound "/zap/test.snd") ```
• A simple function call to produce a single tone sound.

 ``` (dowave 0 1 400 .5 '(1 .5 )) ```
• A function call to produce a ``square-wave'' sound.

 ``` (dowave 0 1 400 .5 '(1 1 3 .33 5 0.2 7 0.14286 )) ```
Open the frequencies view or F-view on Snd's graphic interface to get a good look at the spectra of the sound. Move the sliders to see how the sound evolves.

• A simple function call to do a ``Sawtooth'' sound.

 ``` (dowave 0 1 400 .5 '(1 1 2 .5 3 .333 4 .25)) ```
• A call to have a ``triangular-wave'' sound.

 ``` (dowave 0 1 400 .5 '(1 1 3 0.1111 5 0.04 7 0.20408)) ```
• Type the (play) function call to listen the sound (you can always type ' C-x u ' to undo or erase the active sound you just created on Snd's editing window).

 ``` (play) ```

In Partial Synthesis the overtones are not integer multiples of a fundamental frequency and thus we do not resort to the previous shortcut of a table. Therefore, in this case each component (partial) needs to be implemented independently and separately and furthermore sum each signal component to get the more complex sound. This means a lot of computing resources which translate in more computations and time.

Here is a very simple instrument that implements additive synthesis with three partials.

 ``` (define doadd (lambda* (start-time duration frequency amplitude #:key (partial1 1.0)(amp1 0.3) (partial2 2.0)(amp2 0.3) (partial3 3.0)(amp3 0.3) (ampenv '(0 0 0.5 1 1 0))) ;; (let* ((start (floor (* start-time (srate)))) (len (floor (* duration (srate)))) (sine1 (make-oscil :frequency (* partial1 frequency))) (sine2 (make-oscil :frequency (* partial2 frequency))) (sine3 (make-oscil :frequency (* partial3 frequency))) (amp-env (make-env :envelope ampenv :scaler amplitude :start start :end len)) (output (make-vct len))) ;; (vct-map! output (lambda () (* (env amp-env) (+ (* amp1 (oscil sine1)) (* amp2 (oscil sine2)) (* amp3 (oscil sine3)))))) (vct->channel output start len )) )) ```
The function calls for this instruments are as follows:

• Open a new sound:

 ``` (new-sound "/zap/test.snd") ```
• A simple function call to the instrument with it default values:

 ``` (doadd 0 1 440 0.75 ) ```
In the most general case all parameters of each sine wave are also a function of time (that is, they are controlled by envelopes). This is the most interesting case but also the most expensive computationally and the most difficult to control. But the problem is: "how do we create or generate the enormous amount of data that we need to accurately represent hundreds of points in the envelopes or all partials?"

• Import from somewhere else ?
• Program generated ?
• High level musical concepts ?
• Synth parameters ?
• Manually ?
• Analysis -> Re-synthesis ?

Next: FM synthesis on SND Up: SND Previous: Tutorials-and-More about SND