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
You can try the following function calls to listen to the tones.
(define (dowave start-time dur frequency amplitude harmonics)
(let* ((start (seconds->samples start-time))
(len (seconds->samples (+ start-time dur)))
;; 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)
(do ((i start (1+ i)))
((= i len))
(outa i (* (env amp-env) (table-lookup s)) ))
- Load your instrument:
- A simple function call to produce a single tone sound.
(with-sound () (dowave 0 4 600 .7 '(1 .5 )))
- A function call to produce a “square-wave” sound.
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.
(with-sound () (dowave 0 1 400 .7 '(1 1 3 .33 5 0.2 7 0.14286 )))
- A simple function call to do a “Sawtooth” sound.
(with-sound () (dowave 0 1 400 .7 '(1 1 2 .5 3 .333 4 .25)))
- A call to have a “triangular-wave” sound.
(with-sound ()(dowave 0 1 400 .7 '(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).
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
Here is a very simple instrument that implements additive synthesis
with three partials.
The function calls for this instruments are as follows:
(define* (doadd start-time duration frequency amplitude
(partial1 1.0)(amp1 0.3)
(partial2 2.0)(amp2 0.2)
(partial3 3.0)(amp3 0.1)
(ampenv '(0 0 0.5 1 1 0)))
(let* ((start (seconds->samples start-time))
(len (seconds->samples (+ start-time duration)))
(sine1 (make-oscil :frequency (* partial1 frequency)))
(sine2 (make-oscil :frequency (* partial2 frequency)))
(sine3 (make-oscil :frequency (* partial3 frequency)))
(amp-env (make-env :envelope ampenv
:end len)) )
(do ((i start (1+ i)))
((= i len))
(outa i (* (env amp-env)
(+ (* amp1 (oscil sine1))
(* amp2 (oscil sine2))
(* amp3 (oscil sine3))))))
- Load “doadd.scm”:
- A simple function call to the instrument with it default values:
(with-sound() (doadd 0 1 660 0.75 ))
- A call with different factors on the second and third harmonics.
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?"
(with-sound() (doadd 0 1 660 0.75 :partial2 4.0 :partial3 6.0))
- Import from somewhere else ?
- Program generated ?
- High level musical concepts ?
- Synth parameters ?
- Manually ?
- Analysis –> Re-synthesis ?
ADDITIVE SYNTHESIS OF INHARMONIC TONES.
Jean Claude Risset, among the pioneers of computer music, experimented
exhaustively on the synthesis of natural sounds by means of a
computer. He researched instrumental sounds such like a trumpet, by
employing spectrum analysis tools at the time (circa 1964), revealing
amplitudes and frequencies of partials of these instruments but most
importantly, how each partial will differ depending on its frequency,
duration and amplitude (i.e. the basis for additive synthesis). Later
he joined John Chowning on persuit for complex spectra on FM Synthesis
J.C. Risset.Amid his work, there were synthesis of Inharmonic tones. For
this he found that the higher the frequency of a partial component of
a sound, the faster its decay, calling this a principle because a much more natural
decay. In most natural sounds, evidence shows that higher frequency components
tend to decay more rapidly than the lower frequency ones. But from a
creative compositional perspective he mentioned:
“ Because with additive synthesis one has complete control of decay
rates, one can add interest to the computer timbres by occasionally
violating the principle.”
Inharmonic tones evoke music played on gongs and bells. For a
natural rendition of these sounds some envelopes are changed to non
percussive envelopes, hence producing bell-like tones transformed into
fluid textures while retaining same underlying pattern. In the first
part of a synthesized sound as described above, the listener tends to
perceive individual “sound objects” such as bells whereas in a second
part of the sound, the fusion of partials into individual
sound objects is hindered by asynchronous envelopes, helping hear each
partial in successive patterns. Next is our take on the subject of
synthesizing Inharmonic tones on Snd's s7.
;;; Bell Spectra
(define bell-ratios '(.56 .563 .92 .923 1.19 1.7 2 2.74 3 3.74 4.07))
(define bell-amps '(1 2/3 1 1.8 8/3 1.46 4/3 4/3 1 4/3 1))
;;; Inharmonic Spectra
(define in-ratios '(.56 .92 1.19 1.71 2.0 2.74 3. 3.76 4.07 4.125))
(define in-amps '(2/3 1 .75 .5 .45 .4 .43 .15 .1 .07))
(define* (inharmonic beg dur freq att partials coeffs
(envl '(0 0 .05 1 .85 0.07 1 0)))
(let* ((start (seconds->samples beg))
(len (length partials))
(arr (make-vector len))
(ratios (make-vector len))
(amps (make-vector len))
(envelopes (make-vector len))
(end (seconds->samples (+ beg dur))) )
(set! ratios (list->vector partials))
(set! amps (list->vector coeffs))
(do ((i 0 (1+ i))) ;; oscillator bank
((= i len))
(set! (arr i) (make-oscil :frequency (* freq (ratios i))) ))
(do ((k 0 (1+ k))) ;; amplitude for each partial
((= k len))
(set! (amps k) (/ 1 (1+ k))) )
(do ((k 0 (1+ k))) ;; envelope for each partial
((= k len)) ;; duration shorter on higher partials
(set! (envelopes k) (make-env :envelope envl
:duration (* dur (/ (- len k) len))
:scaler (amps k))))
(do ((i start (1+ i))) ;; Output signal
((= i end))
(let ((sum 0.0))
(do ((j 0 (1+ j)))
((= j len))
(set! sum (+ sum
(* (env (envelopes j)) (oscil (arr j)))))
(outa i (* (* 0.8 att sum ) rev-amt) *reverb*)
(outa i (* 0.8 att sum )))
Copy-and-paste -all-of-the-above- code into a new file and save it as
- Load “inharmonic.cms”into Snd:
- We can try several function calls to listen to Jean Claude
Risset's perennial bell and other inharmonic sounds. But
first notice on the code above that we have four lists, couple
with “ ratios” for each partial above or below a fundamental and
other two with the amplitudes. Duration envelopes are
calculated at “runtime” given that, the higher the partial, the shorter its
duration. On the function definition for “inharmonic”, slot
variables are provided for these lists as well as an overall default
envelope which can also be changed. On the first function call, we
are generating a bell-like tone on the lower end. Second call a
higher bell tone. Third case is inharmonic spectra taken from
Risset's examples and for the purpose of comparison. Sounds might be
similar, though they should be different. Aside from these examples,
try changing overall envelope and other frequencies.
(with-sound () (inharmonic 0 3 500 .4 bell-ratios bell-amps))
(with-sound () (inharmonic 0 6 1000 .4 bell-ratios bell-amps))
(with-sound () (inharmonic 0 3 1000 .4 in-ratios in-amps))
© Copyright 2001-2022 CCRMA, Stanford University. All rights reserved.
Created and Mantained by Juan Reyes