Digital Sound, Additive and Wavetable Synthesis
Transducers change one type of energy into another...
A basic limitation on how things work is that we need to sample a given signal at least twice as fast as the highest frequency present in the signal. Otherwise we won't be able to reconstruct the signal from the samples.
Here we see how sampling at less than 1/2 the highest frequency gives rise to "aliasing", where frequencies "reflect" around zero and create components in the reconstructed output that were not there to begin with...
How do we express a sine wave in the discrete digital domain?
With these pair of formulas we can move back and forth between a time represetation of our signal and a frequency domain representation. Pure magic...
Same thing but in the discrete digital domain...
N samples in time give us N samples in frequency and viceversa.
And this is how we view both a time domain representation (waveform) and a frequency domain representation (fft) of a particular sound (a bell).
We can also view things tridimensionally, that is, show fft slices of the sound at different times in a waterfall representation. This gives us an idea on how the sound changes over time.
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 clm instrument that implements additive synthesis by using the table-lookup unit generator
And the text version for it:
(definstrument dowave (startime duration frequency amplitude harmonics) (multiple-value-bind (beg end) (get-beg-end startime duration) (let* ((waveform (load-synthesis-table harmonics (make-table))) (s (make-table-lookup :frequency frequency :wave-table waveform)) (amp-env (make-env :envelope '(0 0 0.5 1 1 0) :scaler amplitude))) (run (loop for i from beg to end do (outa i (* (env amp-env) (table-lookup s))))))))In Partial Synthesis the overtones are not integer multiples of a fundamental frequency. Thus we cannot resort to the shortcut of a table and have to really implement all oscillators (and thus use a lot of resources).
Here's a very simple instrument that implements additive synthesis with three partials.
And the text version:
(definstrument doadd (start-time duration frequency amplitude &key (partial1 1.0)(amp1 0.3) (partial2 2.0)(amp2 0.3) (partial3 3.0)(amp3 0.3) (env '(0 0 0.5 1 1 0))) (multiple-value-bind (beg end) (get-beg-end start-time duration) (let* ((sine1 (make-oscil :frequency (* partial1 frequency))) (sine2 (make-oscil :frequency (* partial2 frequency))) (sine3 (make-oscil :frequency (* partial3 frequency))) (amp-env (make-env :envelope env :scaler amplitude :start-time start-time :duration duration))) (Run (loop for i from beg to end do (outa i (* (env amp-env) (+ (* amp1 (oscil sine1)) (* amp2 (oscil sine2)) (* amp3 (oscil sine3))))))))))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.
The problem is: "how do we create ot generate the enormous amount of data that we need to accurately represent hundreds of points in the envelopes or all partials?"
|©1998 Fernando Lopez-Lezcano. All Rights Reserved.|