CCRMA

Substractive Synthesis and Filters, Granular Synthesis


Lecture Slides

A series of gif images of the lecture slides (filters)...

A series of gif images of the lecture slides (granular synthesis)...


Note: the fm-violin and dlocsig
Here's a mutated version of v.ins (dv.ins) that uses dlocsig instead of locsig to localize the samples in space. You'll have to compile and load dlocsig to be able to use this version of the fm-violin...

Substractive Synthesis

Basic concepts.


Filters

Definition
input -> operation -> output; anything is a filter... usually applied to devices that boost or attenuate regions of the spectrum.
Characterization
amplitude versus frequency response curve
Cutoff Frequency
half power point (0.707 or -3dB)
Center Frequency
[maximum|minimum] amplitude in a [bandpass|bandreject]
Stopband vs Passband
Bandwidth
Slope
Q and Gain
Comb and Allpass Filters

Examples

Here is a bunch of very simple instruments that use the stock filters that come with the clm distribution ("/usr/ccrma/lisp/src/clm").


onepole.ins

A simple One Pole filter (filtering white noise)...

(definstrument onepole(start-time duration amplitude
				  &key
				  (b1 '(0 0.5 1 0.5)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* ((noise (make-randh :frequency (* 0.49 sampling-rate) 
			      :amplitude amplitude))
	   (b1-env (make-env :envelope b1))
	   (opfilt (make-one-pole :a0 1.0 :b1 0.5)))
      (Run
       (loop for i from beg to end do
	     (setf (smpflt-b1 opfilt) (env b1-env))
	     (outa i (one-pole opfilt (randh noise))))))))

onezero.ins

A simple One Zero filter (filtering white noise)...

(definstrument onezero(start-time duration amplitude
				  &key
				  (a1 '(0 0.5 1 0.5)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* ((noise (make-randh :frequency (* 0.49 sampling-rate) 
			      :amplitude amplitude))
	   (a1-env (make-env :envelope a1))
	   (ozfilt (make-one-zero :a0 1.0 :a1 0.5)))
      (Run
       (loop for i from beg to end do
	     (setf (smpflt-a1 ozfilt) (env a1-env))
	     (outa i (one-zero ozfilt (randh noise))))))))

ppolar.ins

A simple Two Pole filter with resonance based on the ppolar clm ug (filtering white noise)...

(defmacro b1-from-r-freq (r freq) `(- (* 2.0 ,r (cos (in-hz ,freq)))))
(defmacro b2-from-r (r) `(* ,r ,r))

(definstrument twopole(start-time duration amplitude
				  &key
				  (freq '(0 20 1 10000))
				  (r '(0 0.5 1 0.5)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* ((noise (make-randh :frequency (* 0.49 sampling-rate) 
			      :amplitude amplitude))
	   (freq-env (make-env :envelope freq))
	   (r-env (make-env :envelope r))
	   (ppfilt (make-ppolar :r 0.5 :frequency 440.0)))
      (Run
       (loop for i from beg to end do
	     (let* ((freq0 (env freq-env))
		    (r0 (env r-env)))
	       (setf (smpflt-b1 ppfilt) (b1-from-r-freq r0 freq0))
	       (setf (smpflt-b2 ppfilt) (b2-from-r r0))
	       (outa i (ppolar ppfilt (randh noise)))))))))

formnt.ins

A simple Two Pole / Two Zero formant filter (filtering white noise)...

(defmacro set-formnt(filter freq r)
  `(let* ((freq ,freq)
	  (r ,r))
     (setf (smpflt-a2 (frmnt-tz ,filter)) (- r)
	   (smpflt-b1 (frmnt-tp ,filter)) (- (* 2.0 r (cos (in-hz freq))))
	   (smpflt-b2 (frmnt-tp ,filter)) (* r r))))

(definstrument simp-formnt(start-time duration amplitude
				  &key
				  (freq '(0 20 1 10000))
				  (r '(0 0.707 1 0.707)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* ((noise (make-randh :frequency (* 0.5 sampling-rate) :amplitude amplitude))
	   (freq-env (make-env :envelope freq
			       :start-time start-time
			       :duration duration))
	   (r-env (make-env :envelope r
			    :start-time start-time
			    :duration duration))
	   (fmfilt (make-formnt :frequency 440 :r 0.99)))
      (Run
       (loop for i from beg to end do
	     (set-formnt fmfilt (env freq-env) (env r-env))
	     (outa i (formnt fmfilt (randh noise))))))))
All of these example instrument do some internal contortions to move through envelopes the center frequency, resonance and or assorted internal coefficients. Hope you can figure things out. Believe it or not everything that's being done is documented in the clm manual... :-)

butterworth.cl

A pair of quite good low pass, high pass, band pass and reject filters from the clm distribution. Just copy the file butterworth.cl. Take a look at the docs. Here's an example instrument (butter.ins), courtesy of Juan.

moog.ins

Tim Stilson's implementation of a 24db/octave Moog low pass filter, with variable resonance... back to that warm analog sound! Find the source in moog.ins. There's also a simple example instrument (moog-test.clm) that can filter white noise. If you really want to read all the gory details on how the magic works go to Tim Stilson's Home Page and follow the link that points to his papers.

addflt.ins

Take a look at a more sophisticated example that is included in the clm distribution, a multiple resonante filter instrument called addflt.ins

onezero-forever.ins

A real-time version of a simple one zero filter.

onepole-forever.ins

A real-time version of a simple one pole filter.

vowels.cl

Juan's real time implementation of a three formant filter, just the right approach to simulate the resonances of a human voice.

Adding filtering to instruments

Two approaches to adding filtering to instruments.

In the first one we modified the code of the original v.ins (Bill's fm-violin) and added a moog filter based of Tim Stilson's moog filter. Needless to say, for this to work we have to first compile and load the moog filter code moog.ins. After that, compiling and loading the modified vmoog.ins fm violin file will generate a mutant fm-violin that understands two additional parameters, freq-env: the frequency envelope for the cutoff frequency of the moog filter and res-env: an envelope that controls the resonance of the filter.

We can also create a general purpose moog filter instrument that processes a soundfile. The code can be found in moog-filter.ins. One way to use this instrument to process arbitrary clm instrument output is to use a sound-let to create a temporary soundfile that holds the notes that are to be filtered. Better still, we can create a custom macro that adds some syntactic sugar and makes things look better. See the "with-moog" macro in the previous file plus an example on how to use it.



Granular Synthesis

Overview of granular synthesis techniques.


Examples

Here's a fairly comprehensive granular synthesis instrument written in clm (grani.ins) and geared towards granulation of soundfiles.

Here is the header of the instrument and a short description of its parameters (see the source code for the parameter defaults):

(definstrument grani 
    (start-time duration amplitude file
		&key
		(grains grani-grains)
		(amp-envelope grani-amp-envelope)
		(grain-envelope grani-grain-envelope)
		(grain-envelope-end grani-grain-envelope-end)
		(grain-envelope-transition grani-grain-envelope-transition)
		(grain-duration grani-grain-duration)
		(grain-duration-spread grani-grain-duration-spread)
		(grain-duration-limit grani-grain-duration-limit)
		(srate grani-srate)
		(srate-spread grani-srate-spread)
		(srate-linear grani-srate-linear)
		(srate-base grani-srate-base)
		(srate-error grani-srate-error)
		(grain-start grani-grain-start)
		(grain-start-spread grani-grain-start-spread)
		(grain-density grani-grain-density)
		(grain-density-spread grani-grain-density-spread)
		(reverb-amount grani-reverb-amount)
		(reverse grani-reverse)
		(where-to grani-where-to)
		(where-bins grani-where-bins)
		(grain-distance grani-grain-distance)
		(grain-distance-spread grani-grain-distance-spread)
		(grain-degree grani-grain-degree)
		(grain-degree-spread grani-grain-degree-spread))

Mandatory parameters

start-time
starting time in seconds
duration
duration of the note in seconds
amplitude
amplitude of the note
file
the complete pathname of the soundfile you want to use as source material for the grains

Some of the optional parameters

After the name of the parameter I specify the type of parameter. Most of the key parameters can be either numbers (for a constant value) or an envelope.

amp-envelope [envelope]
amplitude envelope for the whole note
grain-envelope [envelope]
amplitude envelope for each individual grain
grain-envelope-end [envelope or nil]
a second amplitude envelope for each individual grain. If specified, grain-envelope-transition can be used to interpolate between both envelopes over the duration of the note.
grain-envelope-transition [envelope]
interpolation envelope for the grain envelope (used only if grain-envelope-end has been specified).
grain-duration [number or envelope]
duration in seconds of each individual grain
grain-duration-spread [number or envelope]
random deviation from grain-duration
grain-duration-limit [number]
minimum duration in seconds of a grain
srate [number or envelope]
sample rate conversion factor. The value for each grain is either a constant if the parameter is a number or is determined by the value of the envelope at the point in time where the grain starts. The sample rate conversion factor is a constant within the grain. If not overriden by the sampling rate conversion factor is specified in semitones (positive values transpose the sound up and negative values transpose down).
srate-spread [number or envelope]
random deviation the value of srate
srate-linear [t or nil]
defines the type of envelope used for the sampling rate conversion factor:
nil (the default): "srate" is expressed in fractional semitones above or below the original sampling rate (0 = no change in sampling rate conversion). The exponential envelope is approximated by a linear segment representation. The error bounds of the approximation can be set by srate-error. The base of the exponential curve can be changed by srate-base.
t: "srate" is the linear sampling rate conversion factor (1 = no change in sampling rate).
srate-error [number]
error bound for the exponential conversion
srate-base [number]
base for the exponential conversion. "2" will express the envelope in octaves. "(expt 2 (/ 12)" will express the envelope in semitones.
grain-start [number or envelope]
point in the input file where the samples are going to be read from. "0" represents the start of the input soundfile, "1" represents the end. An envelope can be used to produce arbitrary mappings over time.
grain-start-spread [number or envelope]
random deviation from the value of grain-start.
grain-density [number or envelope]
number of grains per second that will be created.
grain-density-spread [number or envelope]
random deviation from the value of grain-density.
reverse [t or nil]
"t" means the input soundfile will be read backwards (each grain will read backwards but of course this is independent from grain-start, for example we could be advancing forwards in the file but reading the samples backwards).
reverb-amount [number]
amount of sound to be sent to the reverb output stream.
grain-distance [number or envelope]
distance to the listener position (for locsig)
grain-distance-spread [number or envelope]
random deviation from the value of grain-distance
grain-degree [number or envelope]
angular position (for locsig)
grain-degree-spread [number or envelope]
random deviation from the value of grain-degree
Some examples...


Here's the "one-cut" instrument, a soundfile mangling machine... (cut.ins). Here are some parameter examples you can paste into a with-sound.


Assignment #4

Use dlocsig and/or the hrtf instrument to locate in space a musical phrase built notes rendered with the grani instrument (hint: for grani you will have to use move-sound to wrap the notes you want to spatialize - can you figure out why it's not possible to use dlocsig inside grani?). Submit, as usual, to unjung@ccrma...

This assignment is due by March 7th 2000.


©2000 Fernando Lopez-Lezcano. All Rights Reserved.
nando@ccrma.stanford.edu