- Leslie and Moving Sound Sources -

The Leslie effect heard on the Leslie Speaker, has spatial motion properties while listening to a sound source. In particular Hammond B-3 organs add expressive cues to a tone which is static on its duration envelope. Great organ performers like Jimmy Smith, Lonnie Smith and the Deep Blue Organ Trio, make clever use of this effect. Because of frequency shifts due to moving speakers, this effect effect gives the illusion of not only one sound source but several. At slow rotating speeds, there is the effect of a moving source, while at fast rotating rates, there is the effect of a chorale with multiple sound sources. Time varying delay lines are used for various effects and simulation of moving sound sources. Below is ChucK code for modeling the Leslie speaker cabinet as an example for applications of dynamics from moving sound sources.

The "Leslie" speaker cabinet, nowadays an intrinsic part of the Hammond organ system, is an example of a moving sound source. Perception of moving sources and localization cues depend on static variables such as amplitude or intensity of a sound, further function of distance from source to the listener. Timbre or spectral cues, pitch and reverberation of the environment are also static. Dynamic variables consist of changing distances from sound sources to the listener and velocities of this motion [Kronland-Martinet et al, 2008]. These parameters in addition to velocity of sound dispersion are the factors for Doppler shifts. More about the Leslie cabinet: [here].

Doppler effect models have been used to add realism of simulated moving sources on composition contexts in a variety of computer music pieces and electroacoustic composition [Chowning, 1971], [Lopez-Lezcano, 2008]. Immersive environments with invisible objects use sound motion to delineate possible images and locations for perception of sources. Bill Fontana's [Sonic Shadows] is an example of real and physical dynamic sound sources inside an acoustical environment.

A Doppler simulator can be used to model sound source motion. For a reasonable application such as the Leslie effect, a simulator with delay lines as building-blocks has been proposed on [Smith et al., 2002]. It is a well known fact that a time varying delay line results in a frequency shift see [here]. Since Doppler effects give the illusion of a pitched sound rising or falling, given the motion of the source or the listener in relation to each other, a delay line mimics this effect[ibid]. In the case of the Leslie speaker delay lines cast a Doppler simulator by modeling motion of the rotating horn. In this, the listener hears multiple reflections at different Doppler shifts, giving the illusion of a multiple voice chorale. More on time-varying delay effects [here].

Delay lines are part of major software synthesis packages. STK and therfore ChucK implement [DelayL] providing continous and linearly interpolated variable delay lengths. For reference, a technical despcrition on modeling Doppler and the Leslie is found [here]. Operation of the Leslie is described on [Wikipedia]. Note that to implement a continuously varying delay, a "delay growth parameter" 'g' needs to added to the delay line. When g is 0, there is a fixed delay line. When g>0, delay increments g samples per sample, and thus seconds per second.

To calculate a growing factor for the rotating horn in the Leslie speaker we need its geometrical factors. Therefore, using Doppler shift equation (14) on [Smith et al., 2002], a growing factor for frequency shift is obtained by the product of the trace of the circumference of the horn, its angular velocity and cosine (or sine) of the angle of the horn at time 't', over the speed of sound. See equation (16) on [ibid]. In modeling the cabinet four delay lines are needed for the system to get shifts from the four sides of the cabinet. Similarly, motion of lower baffle speaker is achieved by a set of four low pass filters. Their center frequency is also obtained by a growing factor, this time describing the circular motion of the lower Leslie bass rotor (see code listing).

//* *************************************************************************
//*  Leslie.ck
//*                    Leslie rotating horn
//*  Dopplers for Leslie algorithm in ChucK 
//*  Using DelayL or DelayP (not documented)
//*  NOTES:
//*  This is ChucK code testing STK's DelayL(P) on ChucK.
//*  Max delay time in samples and delay read position (in samples) are function
//*  of sampling rate.
//*  This program models the upper and lower parts of the Leslie cabinet
//*  Doppler using DelayL lines changing with a growing factor (Hi part)
//*  Low pass filter with changing cutoff frequicies (Lo part).
//*  Use really short decay time for reverb(small room) Nverb.
//*  Needs reverb on lower port.
//*  Tested on ChucK v1.34 
//*  Juanig_at_ccrma_Stanford_EDU
//*  (c) 2007-14


SqrOsc sqr =>  Gain gains => blackhole;
gains => DelayL dline1 => blackhole;
gains => DelayL dline2 => blackhole;
gains => DelayL dline3 => blackhole;
gains => DelayL dline4 => blackhole;

dline1 => DelayL reflPath0 => NRev reva => Gain g1 => dac.left;
dline2 => DelayL reflPath1 => NRev revb => Gain g2 => dac.right;
dline3 => DelayL reflPath2 => NRev revc => Gain g3 => dac.left;
dline4 => DelayL reflPath3 => NRev revd => Gain g4 => dac.right;

gains => LPF filtera => Gain gf1 => dac.left;
gains => LPF filterb => Gain gf2 => dac.right; 
gains => LPF filterc => Gain gf3 => dac.left;
gains => LPF filterd => Gain gf4 => dac.right; 

// sample rate
1::second / 1::samp => float srate;

Math.PI => float myPi;
Math.PI*2 => float my2Pi;

// Leslie dimensions
0.18 => float hornRadius;          // radius(mts) 0.18
0.19050 => float baffleRadius;     // lower baffle radius(mts) 15in wooffer
0.71 => float cabinetLen;          // cabinet length
0.52 => float cabinetWid;          // cabinet width

0.125 => gains.gain;               // Overall input gain

0.1250 => g1.gain;                 // Doppler gain outputs 
0.1250 => g2.gain;
0.1250 => g3.gain;
0.1250 => g4.gain;

0.250 => gf1.gain;                 // LP Filter gain
0.250 => gf2.gain;
0.250 => gf3.gain;
0.250 => gf4.gain;

// ======
0.2 => float T60;

// gain
.75 => reva.gain;
.75 => revb.gain;
.75 => revc.gain;
.75 => revd.gain;

// Mix
0.0125 => reva.mix;
0.0125 => revb.mix;
0.0125 => revc.mix;
0.0125 => revd.mix;

// speed
345.12 => float sspeedmts;         // speed of sound mts/s
4.0 => float speedsl;              // speed of source mt/s (50KPH) => 50000/3600 m/s
//0.3333 => float speedsl;         // Between 0.3333 and 4.0

// Meters to samples
srate / sspeedmts => float m2samp;

// delay lengths:
float maxDopDelay;                 // Maximum delay line length
float startDopDelay;               // starting length of delay line

if (srate == 44100) {
	96 => maxDopDelay;
	48 => startDopDelay;}
if (srate == 48000) {
	104 => maxDopDelay;
	52 => startDopDelay;}

10.0 => float startFreqShift;     // Frequency shift in Hz (for Lo baffle)

maxDopDelay::samp => dline1.max;
maxDopDelay::samp => dline2.max;
maxDopDelay::samp => dline3.max;
maxDopDelay::samp => dline4.max;

startDopDelay => float dshift1;
startDopDelay => float dshift2;
startDopDelay => float dshift3;
startDopDelay => float dshift4;

float fshift1,fshift2,fshift3,fshift4;

startFreqShift*my2Pi => fshift1;  // Frequency shift in radians
startFreqShift*my2Pi => fshift2,fshift3,fshift4;

float hornAngVel, baffleAngVel;
float hornAngle, baffleAngle;
0.0 => hornAngle, baffleAngle;       // initial phases of angular motion

// Doppler DelayLine incrment

float incr0, incr1, incra,incrb;
0.0 =>  incr0, incr1;
0.0 =>  incra, incrb;

// Reflection variables and array

float xDev, yDev;
float reflectLen[4];	

// Speed
speedsl => hornAngVel;
0.98*speedsl => baffleAngVel;

while( true ) {

	// Frequency
	500 => sqr.freq;

	my2Pi * hornAngVel/srate +=> hornAngle;
	my2Pi * baffleAngVel/srate +=> baffleAngle;
	if (hornAngle > my2Pi) my2Pi -=> hornAngle;
	if (baffleAngle > my2Pi) my2Pi -=> baffleAngle;
	-my2Pi*hornRadius*hornAngVel*Math.cos(hornAngle)/sspeedmts => incr0;
	-my2Pi*hornRadius*hornAngVel*Math.sin(hornAngle)/sspeedmts => incr1;

	incr0 -=> dshift1;
	incr1 -=> dshift2;
	-incr0 -=> dshift3;
	-incr1 -=> dshift4;
	dshift1::samp => dline1.delay;
	dshift2::samp => dline2.delay;
	dshift3::samp => dline3.delay;
	dshift4::samp => dline4.delay;

	// Reflections
	hornRadius* Math.cos(hornAngle) => xDev;         
	hornRadius* Math.sin(hornAngle) => yDev;         
	(cabinetWid/2 + yDev)*m2samp => reflectLen[0];           // direct path length
	(cabinetLen - xDev)*m2samp => reflectLen[1];             // right wall reflection
	(1.5*(cabinetWid)-yDev)*m2samp => reflectLen[2];         // back wall reflection
	(cabinetLen + xDev)*m2samp => reflectLen[3];             // left wall reflection

	reflectLen[0]::samp => reflPath0.delay;
	reflectLen[1]::samp => reflPath1.delay;
	reflectLen[2]::samp => reflPath2.delay;
	reflectLen[3]::samp => reflPath3.delay;

	// Baffle low port section
	-my2Pi*baffleRadius*baffleAngVel*Math.cos(baffleAngle)/sspeedmts => incra;
	-my2Pi*baffleRadius*baffleAngVel*Math.sin(baffleAngle)/sspeedmts => incrb;
	incra -=> fshift1;
	incrb -=> fshift2;
	-incra -=> fshift3;
	-incrb -=> fshift4;

	// fshift1*100 => filtera.freq;
	// fshift2*100 => filterb.freq;

	fshift1*10+50*my2Pi => filtera.freq;
	fshift2*10+50*my2Pi => filterb.freq;
	fshift3*10+50*my2Pi => filterc.freq;
	fshift4*10+100*my2Pi => filterd.freq;

	// advance "1" sample.
	1.0::samp => now;



Listing: Chuck code for a Leslie rotating speaker

On this code a square wave ugen oscillator 'SqrOsc' enters the signal path of the Leslie model. By modularity on software synthesis packages, this input can be swapped with other unit generators in [ChucK]. Frequency can also be a variable. Worth mentioning are the effects of accelerating and decelerating the speeds of the horn and lower baffle. This factor can also be added by means of triggering an envelope for changing the angular speed of the rotors. Code can be downloaded [here].

Jorge Herrera and others have a more complete and accurate model using time varying FIR filters [Herrera et al, 2009]. Richard Kronland-Martinet and others have also approached the subject using an image method for simulating small-room acoustics by computing the values of radiating sources and reflecting planes [Kronland-Martinet et al, 2008]. From this research there is a Max-MSP patch and a Leslie simulation page [here]. Other implementations on Scheme and Lisp by Juan Reyes are found on tarball distributions of [Snd] and [CLM] respectively.

Musical references of the Hammond-Leslie sound, mostly on 'blues' and part the Jazz genre, are heard on recordings of Jimmy Smith, Dr. Lonnie Smith, Deep Blue Organ Trio, Charles Earland, Joey DeFrancesco, Mike LeDonne, Billy Preston, Tom Coster, among others. Enabling the Leslie effect, in addition to changing its rotating speed are trademark gestures on Jazz organ performances from the above mentioned virtuosi.


My gratitude to Patty Huang and Julius Smith for explanations on time varying delay lines while doing research with Stefania Serafin on the Leslie. Also to Jonathan Abel for his clues and for pointing out new research on this subject matter.