<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
;------------------------------------------------------------------------
; Tone Wheel Organ with Rotating Speaker
; Originally by Hans Mikelson
; with Two Manuals, Vibrato, Percussion, and other mods by Pete Goodeve
; v6.2 -- 07/11/26 (Better Percussion)(8/26 Reverb added to Instr 10)
; v7.0 -- 08/1/22  'real' tonewheel emulation, and keyclick compensation
;      -- 08/2/27  revised Leslie with side reflections (and general cleanup)
;      -- 08/3/4 ...discovered 'pset' opcode... (:-/)
; v7.1 -- 08/11/30 scaled amplitude with frequency; Instr 11 for Csound5 needs
;      -- 08/12/2  added phasing and better key-click
;------------------------------------------------------------------------

; Use lower audio sampling rate than usual:
; (This is for my older. slower machine, but it probably matches a real Hammond!)
sr     = 22050
;; Using a lower K-rate too gives me more simultaneous notes
;ksmps  = 7
;; ... but this may be too low -- has a little more latency (?):
ksmps  = 10

nchnls = 2

; Midi Channel Assignments -- you can switch the channels used here 
; [I understand that these only relate to *live* MIDI, not midifile input...]
; They do *not* affect Score Instrument numbers!
giChanLeslie = 3	; leslie speed control by MIDI
giChanSwell = 1		; Upper Manual MIDI channel
giChanGreat = 2		; Lower Manual MIDI channel

; These are needed for ctrlinit, even if channels match intruments:
massign giChanLeslie,3
massign giChanSwell,4
massign giChanGreat,5

;---------- Score Function Table Defaults: ---------
; (i.e. they can be supplied by the score, with function-table numbers as below,
; but these defaults will apply otherwise)

;Distortion Characteristic [table 1] (Default: slight):
giDist ftgen 1, 0, 8192, 8, \
         -.8, 336, -.78,  800, -.7, 5920, .7,  800, .78, 336, .8

; Swell Pedal Characteristic [table 2]:
giSwell ftgen 2, 0, 129, 7, \
          0.001, 3, 0.01, 30, 0.5, 37, 0.8, 58, 1, 1, 1,

; Leslie Speeds (Revs/sec) [Tables 5,6]:
; ... Values gleaned and extrapolated from statements on the web...
;  Adjust to taste
; Horn should spin slightly faster than the Bass

giLeslieHorn ftgen 5, 0, 8, -17, \
	0, 0, \
	1, 0.8, \
	2, 0.85, \
	3, 1.4, \
	4, 6.7, \
	5, 6.8, \
	6, 7.5, \
	7, 9,
	
giLeslieBass ftgen 6, 0, 8, -17, \
	0, 0, \
	1, 0.7, \
	2, 0.8, \
	3, 1.2, \
	4, 5.7, \
	5, 6.6, \
	6, 7.0, \
	7, 8,
	
;---------- Misc. Adjustable Parameters: ---------

;Percussion decay times -- change to taste
;; From the circuit, these values look plausible:
gipercfast = 0.37
gipercslow = 1.5

; Keyclick  -- adjust to taste (default value seems good)
; (The main cause of the click is picking up the contimuous sinewaves
;  at a random point -- mimimized by a slower rise-time.  A white-noise
;  click sound can also be added if desired.)
giClickRise = 0.001	; set to zero for maximum contact click -- 0.01 to minimize
giClickNoise = 0	; "Hash" amplitude:  <1.0 if you want it...

; Swell Pedal Initial position (70%)
ctrlinit giChanSwell, 11, 88
ctrlinit giChanGreat, 11, 88

; Drawbar MIDI block starts from Controller number:
giDBControlBase = 20

; Leslie Characteristics:
giLeslieBase = 21	; note number (instr 3) that will stop Leslie
                 	; Leslie speed controlled by following 7 (via table)
giRampTimeHigh = 1	; Time (secs) for Leslie top rotor to come to speed
giRampTimeLow = 2	; Time (secs) for Leslie lower rotor to come to speed

giPowScale = 0.002	; Scaling for harmonic power adjustment (by experiment)
					; -- may depend on power/freq table (giScaling)

;---------- Fixed Parameters: ---------

; Fixed Organ manual keyboard range (0 == 2 octaves below middle-C)
gikeylo = 0
gikeyhi = 61

gkone init 1	;; literal constants seem to have a bug in many ops...
gkmin init 1.0/kr	;; so does v.short delay

; These instruments must not have more than one instance:
maxalloc 3,1	;Leslie speed
maxalloc 6,1	; Vibrato
maxalloc 8,1	; Leslie A
maxalloc 9,1	; Leslie B
maxalloc 10,1	; Audio Out/Chain Terminator

; Vibrato Scanner Delay Line Length:
giVibrLine = 1.1	;millisec

; ------- (Fixed) Function Tables: ---------
; (Table numbers 3, 4, 9, 11, 12, 13, 14, 20
;  -- only modify these if you're REALLY feeling experimental...)

; Tone Wheel Frequencies [Table 20]:
; (from wheel teeth and gearing on actual Hammond -- 1200 RPM main shaft)
giTones ftgen 20, 0, 128, -17, \
	0, 32.69230768, \
	1, 34.63414636, \
	2, 36.71232876, \
	3, 38.88888888, \
	4, 41.2, \
	5, 43.63636364, \
	6, 46.25, \
	7, 49, \
	8, 51.89189188, \
	9, 55, \
	10, 58.26086956, \
	11, 61.71428572, \
	12, 65.38461536, \
	13, 69.26829272, \
	14, 73.42465752, \
	15, 77.77777776, \
	16, 82.4, \
	17, 87.27272728, \
	18, 92.5, \
	19, 98, \
	20, 103.78378376, \
	21, 110, \
	22, 116.52173912, \
	23, 123.42857144, \
	24, 130.76923072, \
	25, 138.53658544, \
	26, 146.84931504, \
	27, 155.55555552, \
	28, 164.8, \
	29, 174.54545456, \
	30, 185, \
	31, 196, \
	32, 207.56756752, \
	33, 220, \
	34, 233.04347824, \
	35, 246.85714288, \
	36, 261.53846144, \
	37, 277.07317088, \
	38, 293.69863008, \
	39, 311.11111104, \
	40, 329.6, \
	41, 349.09090912, \
	42, 370, \
	43, 392, \
	44, 415.13513504, \
	45, 440, \
	46, 466.08695648, \
	47, 493.71428576, \
	48, 523.07692288, \
	49, 554.14634176, \
	50, 587.39726016, \
	51, 622.22222208, \
	52, 659.2, \
	53, 698.18181824, \
	54, 740, \
	55, 784, \
	56, 830.27027008, \
	57, 880, \
	58, 932.17391296, \
	59, 987.42857152, \
	60, 1046.15384576, \
	61, 1108.29268352, \
	62, 1174.79452032, \
	63, 1244.44444416, \
	64, 1318.4, \
	65, 1396.36363648, \
	66, 1480, \
	67, 1568, \
	68, 1660.54054016, \
	69, 1760, \
	70, 1864.34782592, \
	71, 1974.85714304, \
	72, 2092.30769152, \
	73, 2216.58536704, \
	74, 2349.58904064, \
	75, 2488.88888832, \
	76, 2636.8, \
	77, 2792.72727296, \
	78, 2960, \
	79, 3136, \
	80, 3321.08108032, \
	81, 3520, \
	82, 3728.69565184, \
	83, 3949.71428608, \
	84, 4189.09090944, \
	85, 4440, \
	86, 4704, \
	87, 4981.62162048, \
	88, 5280, \
	89, 5593.04347776, \
	90, 5924.57142912

; Amplitude scaling of frequencies -- arbitrarily exponential
giScaling ftgen 21, 0, 128, 5, 5.0, 90, 1.0, 38, 0.3   ;faster fall-off when folded...


; Tone Wheel waveforms [Tables 11,12]:
giSine1  ftgen 11, 0, 16384, 10, 1, .02, .01	; -- also Low freq Leslie
giSine2  ftgen 12, 0, 16384, 10, 1, 0, .2, 0, .1, 0, .05, 0, .02


;Triangular Scanner Sweep [Table 9]:
;; Scan is not actually quite triangular!:
giScanner ftgen 9, 0, 16, 7,  \
  0, 1,1,  1,3,  1,6,  1, 9,  1,12,  1,15,  1,17,  1,18,\
  1,17,  1,15,  1,12,  1,9,  1,6,  1,3,  1,1,  1,0 

; Leslie Horn Characteristics [Tables 3,4,13,14]:
giLhidef  ftgen 3, 0, 1024, 8, .95, 24, .85, 24, 1, 24, .85, 24, 1, 24, .85, 248, .9, 72, .8, 72, 1, 72, .8, 72, .9, 248, .85, 24, 1, 24, .85, 24, 1, 24, .85, 24, .95
giLmiddef  ftgen 4, 0, 1024, 8, .95, 48, .85, 96, .75, 240, .8, 64, 1, 128, 1, 64, .8, 240, .75, 96, .85, 48, .95
giLhinodef  ftgen 13, 0, 1024, 8, .2, 440, .4, 72, 1, 72, .4, 440, .2
giLmidnodef  ftgen 14, 0, 1024, 8, .4, 320, .6, 64, 1, 256, 1, 64, .6, 320, .4


;--------------------------------

; Leslie stationary by default:
gispeedhorn   init 0
gispeedbass   init 0

; To avoid blast at start...:
gipow = giPowScale/72
gipowG = giPowScale/72


;------------------------------------------------------------------------
; Drawbar Initialization for Upper ("Swell") Manual (keyboard = Instr 4)
;------------------------------------------------------------------------

           instr 1

gksubfund  init p4
gksub3rd   init p5
gkfund     init p6
gk2nd      init p7
gk3rd      init p8
gk4th      init p9
gk5th      init p10
gk6th      init p11
gk8th      init p12
givibrS    init p13
giperc2    init p14
giperc3    init p15

ctrlinit giChanSwell, \
	giDBControlBase, i(gksubfund), \
	giDBControlBase+1, i(gksub3rd), \
	giDBControlBase+2, i(gkfund), \
	giDBControlBase+3, i(gk2nd), \
	giDBControlBase+4, i(gk3rd), \
	giDBControlBase+5, i(gk4th), \
	giDBControlBase+6, i(gk5th), \
	giDBControlBase+7, i(gk6th), \
	giDBControlBase+8, i(gk8th)

; Volume compensation:
gipow      init giPowScale/(p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + 8)
;;;;            ^^^ suck&see  -- must be low enough to avoid overrange
; print gipow*10000
; Click volume must depend on drawbars in use:
giclkpow init giClickNoise/(gipow*10000)

         endin
        
;------------------------------------------------------------------------
; Drawbar Initialization for Lower ("Great") Manual (keyboard = Instr 5)
;------------------------------------------------------------------------

           instr 2

gksubfundG  init p4
gksub3rdG   init p5
gkfundG     init p6
gk2ndG      init p7
gk3rdG      init p8
gk4thG      init p9
gk5thG      init p10
gk6thG      init p11
gk8thG      init p12
givibrG    init p13
;; No Percussion...

ctrlinit giChanGreat, \
	giDBControlBase, i(gksubfundG), \
	giDBControlBase+1, i(gksub3rdG), \
	giDBControlBase+2, i(gkfundG), \
	giDBControlBase+3, i(gk2ndG), \
	giDBControlBase+4, i(gk3rdG), \
	giDBControlBase+5, i(gk4thG), \
	giDBControlBase+6, i(gk5thG), \
	giDBControlBase+7, i(gk6thG), \
	giDBControlBase+8, i(gk8thG)


; Volume compensation:
gipowG      init giPowScale/(p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + 8)
;;;;            ^^^ suck&see -- must be low enough to avoid overrange
; print gipowG*10000
; Click volume must depend on drawbars in use:
giclkpowG init giClickNoise/(gipowG*10000)

         endin

        
;------------------------------------------------------------------------
; This instrument acts as the "foot switch" controlling rotor speeds.
; Hacked to handle MIDI ch.3 from lowest 8 of 88-keys (A..E) or Score input
; Note -- you need to hold it on for 2 secs to get full speed change!
;------------------------------------------------------------------------
         instr 3
pset 0, 0, 0, 0, 0	; avoid "illegal p..." warning
ishorn = gispeedhorn
isbass = gispeedbass
ichn midichn
if (ichn == 0) goto iscore	; not from midi
ikey 		notnum
indx init (ikey - giLeslieBase)     ; new speed from K/B
                                      ;(default: lowest of 88 keys -- MIDI 21-28)
gispeedhorn table indx, giLeslieHorn
gispeedbass table indx, giLeslieBass
	goto change

iscore:
;indx init   p4          ; new speed from score
gispeedhorn init   p4
gispeedbass init   p5

change:

gkenv    linseg ishorn,giRampTimeHigh,gispeedhorn,.01,gispeedhorn ;High freq. rotor acceleration
gkenvlow linseg isbass,giRampTimeLow,gispeedbass,.01,gispeedbass ;Low freq. rotor acceleration

         endin


;------------------------------------------------------------------------
; Tone Wheel Organ ("Upper") Manual (MIDI input ch. 4)
;------------------------------------------------------------------------
         instr 4

  inn  notnum
  iamp veloc
  kswell midic7 11, 0, iamp, giSwell

gaorgan  init  0                       ;Global send to speaker
gabypass init 0							; Bypass Vibrato
galeft init 0							;Leslie Outputs
garight init 0
gkpercenv init 0

ikey     init  inn-36	; key '0' is lowest on organ manual
if ikey < gikeylo || ikey > gikeyhi then
	turnoff
	endif

iks3 init ikey+19	;  Sub3rd
ikf init ikey+12	; Fund
ik2 init ikey+24	; Octv
ik3 init (ikey > 59? ikey+19 : ikey+31)	; 3rd
ik4 init (ikey > 54? ikey+24 : ikey+36)	; 4th
ik5 init (ikey > 50? ikey+28 : ikey+40)	; 5th
ik6 init (ikey>47? ik3 : ikey+43)	; 6th
ik8 init (ikey>42? ik4 : ikey+48)	; 8th

ifsf table ikey, giTones	; SubFund
ifs3 table iks3, giTones	;  Sub3rd
iff table  ikf, giTones	; Fund
if2 table  ik2, giTones	; Octv
if3 table  ik3, giTones	; 3rd
if4 table  ik4, giTones	; 4th
if5 table  ik5, giTones	; 5th
if6 table  ik6, giTones	; 6th
if8 table  ik8, giTones	; 8th
; print ifsf, ifs3, iff, if2, if3, if4, if5, if6, if8

issf table ikey, giScaling	; SubFund
iss3 table iks3, giScaling	;  Sub3rd
isf table  ikf, giScaling	; Fund
is2 table  ik2, giScaling	; Octv
; For the higher keys, we ignore folding
is3 table  ikey+31, giScaling	; 3rd
is4 table  ikey+36, giScaling	; 4th
is5 table  ikey+40, giScaling	; 5th
is6 table  ikey+43, giScaling	; 6th
is8 table  ikey+48, giScaling	; 8th
; print issf, iss3, isf, is2, is3, is4, is5, is6, is8

iwheel1  init  ((ikey-12) > 12 ? giSine1:giSine2)  ;The lower 12 tone wheels have
iwheel2  init  ((ikey+7)  > 12 ? giSine1:giSine2)  ;increased odd harmonic content.
iwheel3  init  (ikey      > 12 ? giSine1:giSine2)
iwheel4  init  giSine1                       
  
;------------------------------------------------------------------------
midicontrolchange giDBControlBase, gksubfund
midicontrolchange giDBControlBase+1, gksub3rd
midicontrolchange giDBControlBase+2, gkfund
midicontrolchange giDBControlBase+3, gk2nd
midicontrolchange giDBControlBase+4, gk3rd
midicontrolchange giDBControlBase+5, gk4th
midicontrolchange giDBControlBase+6, gk5th
midicontrolchange giDBControlBase+7, gk6th
midicontrolchange giDBControlBase+8, gk8th

gipow init giPowScale/(i(gksubfund) + i(gksub3rd) \
	+ i(gkfund) + i(gk2nd) \
	+ i(gk3rd) + i(gk4th) \
	+ i(gk5th) + i(gk6th) \
	+ i(gk8th) + 8)
giclkpow init giClickNoise/(gipow*10000)
;------------------------------------------------------------------------
; Phase Management
; we use performance time and frequency to set the initial phase of
; each harmonic.
; This should both keep multiple uses of the same 'wheel' in sync,
; and provide a more realistic 'key-click' (if enabled)

iT times

;------------------------------------------------------------------------

amp linenr kswell, giClickRise, .01, .01

; Percussion
instcount active 4
; ... only one of giperc2 or giperc3 should be non-zero:
ipercamp = giperc2+giperc3
iperctime = gipercfast
if ipercamp >= 0 goto fastperc
	iperctime = gipercslow
	ipercamp = -ipercamp
fastperc:
if (instcount > 1) goto skiperc	; comment out this line if you want multi-triggering
; Decay is exponential:
 gkpercenv expseg 0.001, .01, ipercamp+0.001, iperctime, 0.001, .01, 0.001
skiperc:
; Actual Hammond percussion is "Single triggered" and seems to retain the harmonic:
;(actual organ hardware usurps the 9th harmonic busbar to trigger percussion, so
; that frequency is not available.  The simulation doesn't bother; for realism, just
; make sure that drawbar is set to zero.)
k2nd = (giperc2 != 0 ? gkpercenv : 0) + gk2nd  ; If percussion is on envelope the second.
k3rd = (giperc3 != 0 ? gkpercenv : 0) + gk3rd   ; If percussion is on envelope the third.
;------------------------------------------------------------------------
asubfund oscil  gksubfund*issf, ifsf,  iwheel1, frac(iT*ifsf)   ;The organ tone is
asub3rd  oscil  gksub3rd*iss3,  ifs3,  iwheel2, frac(iT*ifs3)   ;made from adding
afund    oscil  gkfund*isf,    iff,   iwheel3, frac(iT*iff)   ;the weighted output
a2nd     oscil  k2nd*is2,      if2,   iwheel4, frac(iT*if2)   ;of 9 tone wheels
a3rd     oscil  k3rd*is3,      if3,   iwheel4, frac(iT*if3)  
a4th     oscil  gk4th*is4,     if4,   iwheel4, frac(iT*if4)
a5th     oscil  gk5th*is5,     if6,   iwheel4, frac(iT*if6)
a6th     oscil  gk6th*is6,     if6,   iwheel4, frac(iT*if6)
a8th     oscil  gk8th*is8,     if8,   iwheel4, frac(iT*if8)

; Key Click 'hash noise'
kclickenv linseg 0, .005, giclkpow, .01, 0, .01, 0
aclick   noise   kclickenv, 0.6	;adjust last param for low-pass

aorgan sum  asubfund,asub3rd,afund,a2nd,a3rd,a4th,a5th,a6th,a8th,aclick
aorgan   =      amp*aorgan*gipow
gaorgan  =      gaorgan+givibrS*aorgan
gabypass =      gabypass+(gkone-givibrS)*aorgan

         endin


;------------------------------------------------------------------------
;------------------------------------------------------------------------
; Tone Wheel Organ Second ("Lower") Manual (MIDI input ch. 5)
;------------------------------------------------------------------------
         instr 5

  inn  notnum
  iamp veloc
  kswell midic7 11, 0, iamp, giSwell

gaorgan  init  0                       ;Global send to speaker
gabypass init 0							; Bypass Vibrato
galeft init 0							;Leslie Outputs
garight init 0

ikey     init  inn-36
; print inn, ipch, ikey
if ikey < gikeylo || ikey > gikeyhi then
	turnoff
	endif
iks3 init ikey+19	;  Sub3rd
ikf init ikey+12	; Fund
ik2 init ikey+24	; Octv
ik3 init (ikey > 59? ikey+19 : ikey+31)	; 3rd
ik4 init (ikey > 54? ikey+24 : ikey+36)	; 4th
ik5 init (ikey > 50? ikey+28 : ikey+40)	; 5th
ik6 init (ikey>47? ik3 : ikey+43)	; 6th
ik8 init (ikey>42? ik4 : ikey+48)	; 8th

ifsf table ikey, giTones	; SubFund
ifs3 table iks3, giTones	;  Sub3rd
iff table  ikf, giTones	; Fund
if2 table  ik2, giTones	; Octv
if3 table  ik3, giTones	; 3rd
if4 table  ik4, giTones	; 4th
if5 table  ik5, giTones	; 5th
if6 table  ik6, giTones	; 6th
if8 table  ik8, giTones	; 8th
; print ifsf, ifs3, iff, if2, if3, if4, if5, if6, if8

issf table ikey, giScaling	; SubFund
iss3 table iks3, giScaling	;  Sub3rd
isf table  ikf, giScaling	; Fund
is2 table  ik2, giScaling	; Octv
; For the higher keys, we ignore folding
is3 table  ikey+31, giScaling	; 3rd
is4 table  ikey+36, giScaling	; 4th
is5 table  ikey+40, giScaling	; 5th
is6 table  ikey+43, giScaling	; 6th
is8 table  ikey+48, giScaling	; 8th
; print issf, iss3, isf, is2, is3, is4, is5, is6, is8

iwheel1  init  ((ikey-12) > 12 ? giSine1:giSine2)  ;The lower 12 tone wheels have
iwheel2  init  ((ikey+7)  > 12 ? giSine1:giSine2)  ;increased odd harmonic content.
iwheel3  init  (ikey      > 12 ? giSine1:giSine2)
iwheel4  init  giSine1                       

;------------------------------------------------------------------------
midicontrolchange giDBControlBase, gksubfundG
midicontrolchange giDBControlBase+1, gksub3rdG
midicontrolchange giDBControlBase+2, gkfundG
midicontrolchange giDBControlBase+3, gk2ndG
midicontrolchange giDBControlBase+4, gk3rdG
midicontrolchange giDBControlBase+5, gk4thG
midicontrolchange giDBControlBase+6, gk5thG
midicontrolchange giDBControlBase+7, gk6thG
midicontrolchange giDBControlBase+8, gk8thG

gipowG init giPowScale/(i(gksubfundG) + i(gksub3rdG) \
	+ i(gkfundG) + i(gk2ndG) \
	+ i(gk3rdG) + i(gk4thG) \
	+ i(gk5thG) + i(gk6thG) \
	+ i(gk8thG) + 8)
giclkpowG init giClickNoise/(gipowG*10000)
;------------------------------------------------------------------------

iT times

;------------------------------------------------------------------------
amp linenr kswell, giClickRise, .01, .01

; Percussion not available on lower manual
;------------------------------------------------------------------------
asubfund oscil  gksubfundG*issf, ifsf,  iwheel1, frac(iT*ifsf)
asub3rd  oscil  gksub3rdG*iss3,  ifs3,  iwheel2, frac(iT*ifs3)
afund    oscil  gkfundG*isf,    iff,   iwheel3, frac(iT*iff) 
a2nd     oscil  gk2ndG*is2,     if2,   iwheel4, frac(iT*if2) 
a3rd     oscil  gk3rdG*is3,     if3,   iwheel4, frac(iT*if3) 
a4th     oscil  gk4thG*is4,     if4,   iwheel4, frac(iT*if4)
a5th     oscil  gk5thG*is5,     if5,   iwheel4, frac(iT*if6)
a6th     oscil  gk6thG*is6,     if6,   iwheel4, frac(iT*if6)
a8th     oscil  gk8thG*is8,     if8,   iwheel4, frac(iT*if8)

; Key Click 'hash noise'
kclickenv linseg 0, .005, giclkpowG, .01, 0, .01, 0
aclick   noise   kclickenv, 0.6	;adjust last param for low-pass

aorgan sum  asubfund,asub3rd,afund,a2nd,a3rd,a4th,a5th,a6th,a8th,aclick
aorgan   =      amp*aorgan*gipowG
gaorgan  =      gaorgan+givibrG*aorgan
gabypass =      gabypass+(gkone-givibrG)*aorgan

         endin


;------------------------------------------------------------------------
; This instrument sets Vibrato
;	p4 = effect  (O=off, 1=Vibrato, 0.5=Chorus)  -- 0 turns intrument off
;	p5 = depth -- i.e fraction of delay-line scanned
;		 (Hammond values V/C1=0.45, V/C2=0.66, V/C3=1.0)
; These parameters are fairly experimental -- adjust to taste:
;	p6 = delay-zero max cutoff freq
;	p7 = delay freq adjustment factor (multiplier to DL scan)
;	p8 = lowpass filter Q
;------------------------------------------------------------------------
         instr 6
         p3 = p3+0.1	; so ihold will never see a zero p3
         ihold
; These initializations don't work under C5 if vibrato is already running
; Use Instr 11 to alter them
	givibchor	init (p4 > 1? 1 : p4)	; 0..1
	giscanfrac	init (p5 > 1? 1 : p5)	; 0..1 
	giftopfrq	init p6					; ~10000
	gifscale	init p7					; ~2??
	giQ			init p8					;~2
	givrchor 	init 1 - givibchor
  krun = givibchor	; so we see any change by instr 11
  if (krun == 0) then
   ; Turn Vibrato off now.
   printks "stopping Vibrato\\n", 0
   turnoff
  endif

	; scanner shaft speed =  412 RPM => 6.87 Hz
	kscan oscili giscanfrac, 6.87, giScanner	;triangle wave
	ascan interp kscan*giVibrLine
	avibrout vdelay gaorgan, ascan, giVibrLine*2
	; delay line attenuates higher frequencies
	afiltout lowpass2 avibrout, giftopfrq/(1+kscan*gifscale), giQ
;	kvchor init givibchor
;	gaorgan mac (gkone-kvchor),gaorgan, kvchor,afiltout, gkone, gabypass
;	kvchor init 1-givibchor
;	kvchor = 1-givibchor
;	gaorgan mac kvchor,gaorgan, givibchor,afiltout, gkone, gabypass
	gaorgan mac givrchor,gaorgan, givibchor,afiltout, gkone, gabypass
	gabypass = 0	;zeroed after first use

         endin

;------------------------------------------------------------------------
;Rotating Leslie Speaker
; Revised algorithm using 90 deg "wall reflections"
;------------------------------------------------------------------------
         instr 8
  p3 = p3+0.1	; so ihold will never see a zero p3
  ihold
	gkleslieA init 1

  if (p4 == 0 || gkleslieA == 0) then	; p4 only works in Csound4
    ; Turn the Leslie off now.
    printks "stopping Leslie\\n", 0
    gkleslieA = 0
    turnoff
  endif

; p4 is <=1 to use deflectors, >1 for no deflectors:
itaba    init   (p4 <= 1 ? giLhidef : giLhinodef)
itabb    init   (p4 <= 1 ? giLmiddef : giLmidnodef)
irefl     init   p5             ;Quadrature (sideways) mix amount
ilag     init   p6/1000             ;p6 is reflection delay in *millisecs*
iradius  init   .00025         ;Radius of the rotating horn.
iradlow  init   .00035         ;Radius of the rotating scoop.
ideleng  init   .1            ;Length of delay line (longer to allow for reflections).
if (ilag+2*iradius > ideleng) then
	ilag = ideleng - 2*iradius
	endif

;------------------------------------------------------------------------
 ;Distortion effect using waveshaping.
aclip    tablei gaorgan+gabypass,giDist,1,.5    ;A lazy "S" curve, use other table
aclip    =      aclip*16000    ;  for increased distortion.
gabypass = 0	;zeroed after first use

;------------------------------------------------------------------------
adiscard delayr  ideleng,1      ;Put "clipped" signal into a delay line.

;------------------------------------------------------------------------
; Higher frequencies are assumed to reflect from walls so Doppler
; will be shifted by +-90 degrees

;kosc   oscil   1,gkenv,giSine1 
;koscql   oscil   1,gkenv,giSine1, 0.25 
kosc   oscil   iradius,gkenv,giSine1 
koscql   oscil   iradius,gkenv,giSine1, 0.25 
;koscqr   oscil   1,gkenv,giSine1, 0.75 
kdopl   =       gkmin+(iradius-kosc)
kdoplql   =       gkmin+(iradius-koscql)+ilag
;kdoplqr   =       gkmin+(1-koscqr)*iradius+ilag
kdoplqr   =       gkmin+koscql+ilag
adopl   deltapi kdopl
adoplql  deltapi kdoplql
adoplqr  deltapi kdoplqr

;aleft = adopl + irefl*adoplql
;aright = adopl + irefl*adoplqr

;------------------------------------------------------------------------
; Lower speaker is mostly Amplitude Modulation, so Doppler isn't split

kosclow  oscil   1,gkenvlow,giSine1
kdopllow  =       gkmin+(1-kosclow)*iradlow
adopllow  deltapi kdopllow

        delayw  aclip

;------------------------------------------------------------------------
adfhi     butterbp adopl,5000,4000     ;Divide the frequency into three
alfhi     butterbp adoplql,5000,4000     ;groups and modulate each with a
arfhi     butterbp adoplqr,5000,4000    ;different width pulse to account
adfmid    butterbp adopl,2000,3000    
alfmid    butterbp adoplql,2000,3000     ;for different  dispersion
arfmid    butterbp adoplqr,2000,3000    
adflow    butterlp adopllow,500        ;of different frequencies.

;adfmid    butterbp adopl,2000,1500    
;alfmid    butterbp adoplql,2000,1500     ;different width pulse to account
;arfmid    butterbp adoplqr,2000,1500    ;for different  dispersion

kfdohi    oscil    1,gkenv,itaba
kflohi    oscil    irefl,gkenv,itaba,0.25
;kfrohi    oscil    irefl,gkenv,itaba,0.75
kfrohi = irefl - kflohi
kfdomid   oscil    1,gkenv,itabb
kflomid   oscil    irefl,gkenv,itabb,0.25
;kfromid   oscil    irefl,gkenv,itabb,0.75
kfromid = irefl - kflomid
  
  
;------------------------------------------------------------------------
; Amplitude Effect on Lower Speaker
kalosc    = kosclow*.4+1

; Add all frequency ranges and output the result.
;galeft mac gkone,galeft, kflohi,alfhi, 2*kflomid,alfmid, kalosc,alflow
;garight mac gkone,garight, kflohi,arfhi, 2*kflomid,arfmid, kalosc,alflow
galeft mac gkone,galeft, kfdohi,adfhi, kflohi,alfhi, 2*kfdomid,adfmid, 2*kflomid,alfmid, kalosc,adflow
garight mac gkone,garight, kfdohi,adfhi, kfrohi,arfhi, 2*kfdomid,adfmid, 2*kfromid,arfmid, kalosc,adflow

	endin

;------------------------------------------------------------------------
;Rotating Leslie Speaker
; Instr 9 is Hans Mikelson's algorithm
; (with irrelevant 'offset' removed)
;------------------------------------------------------------------------
         instr  9
  p3 = p3+0.1	; so ihold will never see a zero p3
  ihold

	gkleslieB init 1

  if (p4 == 0 || gkleslieB == 0) then	; p4 only works in Csound4
    ; Turn the Leslie off now.
    printks "stopping Leslie\\n", 0
    gkleslieB = 0
    turnoff
  endif

; p4 is <=1 to use deflectors, >1 for no deflectors:
itaba    init   (p4 <= 1 ? giLhidef : giLhinodef)
itabb    init   (p4 <= 1 ? giLmiddef : giLmidnodef)
isep     init   p5             ;Phase separation between right and left
iradius  init   .00025         ;Radius of the rotating horn.
iradlow  init   .00035         ;Radius of the rotating scoop.
ideleng  init   .02            ;Length of delay line.

;------------------------------------------------------------------------
 ;Distortion effect using waveshaping.
aclip    tablei gaorgan+gabypass,giDist,1,.5    ;A lazy "S" curve, use other table
aclip    =      aclip*16000    ;  for increased distortion.
gabypass = 0	;zeroed after first use

;------------------------------------------------------------------------
adiscard delayr  ideleng,1      ;Put "clipped" signal into a delay line.

;------------------------------------------------------------------------
koscl   oscil   1,gkenv,giSine1            ;Doppler effect is the result
koscr   oscil   1,gkenv,giSine1,isep       ;of delay taps oscillating
kdopl   =       ideleng/2-koscl*iradius   ;through the delay line.  Left
kdopr   =       ideleng/2-koscr*iradius   ;and right are slightly out of phase
aleft   deltapi kdopl                     ;to simulate separation between ears
aright  deltapi kdopr                     ;or microphones

;------------------------------------------------------------------------
koscllow  oscil   1,gkenvlow,giSine1           ;Doppler effect for the
koscrlow  oscil   1,gkenvlow,giSine1,isep      ;lower frequencies.
kdopllow  =       ideleng/2-koscllow*iradlow
kdoprlow  =       ideleng/2-koscrlow*iradlow
aleftlow  deltapi kdopllow
arightlow deltapi kdoprlow

        delayw  aclip

;------------------------------------------------------------------------
alfhi     butterbp aleft,5000,4000     ;Divide the frequency into three
arfhi     butterbp aright,5000,4000    ;groups and modulate each with a
alfmid    butterbp aleft,2000,1500     ;different width pulse to account
arfmid    butterbp aright,2000,1500    ;for different  dispersion
alflow    butterlp aleftlow,500        ;of different frequencies.
arflow    butterlp arightlow,500

kflohi    oscil    1,gkenv,itaba
kfrohi    oscil    1,gkenv,itaba,isep
kflomid   oscil    1,gkenv,itabb
kfromid   oscil    1,gkenv,itabb,isep
  
  
;------------------------------------------------------------------------
; Amplitude Effect on Lower Speaker
kalosc    = koscllow*.4+1
karosc    = koscrlow*.4+1

; Add all frequency ranges and output the result.
galeft mac gkone,galeft, kflohi,alfhi, 2*kflomid,alfmid, kalosc,alflow
garight mac gkone,garight, kfrohi,arfhi, 2*kfromid,arfmid, karosc,arflow

	endin


;---------------------------------------------------
; Used to end the audio chain
; -- must be running continuously for audio output
; 'Reverb' (p4) can be adjusted by another 'i10' command at any time (C4 only)
;---------------------------------------------------

	instr 10
    p3 = p3+0.1	; so ihold will never see a zero p3
	ihold
	
	gireverb init p4	; may be reset by Instr 11


;	gkleslieA  active 8
;	gkleslieB  active 9
	
	if (gkleslieA + gkleslieB == 0) then
		galeft = (gaorgan+gabypass)*40000
		garight = galeft
	endif

	krvb = gireverb
	if (krvb > 0) then
		arvbl reverb galeft, gireverb 
		arvbr reverb garight, gireverb
	else
		arvbl = galeft
		arvbr = garight
	endif
	
	outs (galeft+arvbl)/2, (garight+arvbr)/2
	; display gaorgan, 1,1
    gaorgan = 0
	gabypass = 0
    galeft = 0
    garight = 0

    endin

;---------------------------------------------------
; Used to reset parameters of running instruments in Csound5
;  -- also can alter key-click amount here
;	p3 = instrument number to be affected (NOT duration! -- never sustained)
;	p4... = parameters appropriate to instrument
;---------------------------------------------------

	instr 11
	
	pset 0, 0, 0, 0, 0, 0, 0	; 
	if p3 == 6 then	; Vibrato
		givibchor	init (p4 > 1? 1 : p4)	; 0..1
		giscanfrac	init (p5 > 1? 1 : p5)	; 0..1 
		giftopfrq	init p6					; ~10000
		gifscale	init p7					; ~2??
		giQ			init p8					;~2
		givrchor 	init 1 - givibchor
	elseif p3 == 8 then	; LeslieA -- can only turn off at the moment
		gkleslieA = 0
	elseif p3 == 9 then	; LeslieB -- can only turn off at the moment
		gkleslieB = 0
	elseif p3 == 10 then	; Reverb
		gireverb = p4
	elseif p3 == 11 then	; Key Click
		giClickRise = p4
		giClickNoise = p5
	endif
	
	turnoff	; always
    endin
</CsInstruments>
<CsScore>
;-------------------------------------------------------------------
; Tone Wheel Organ with Rotating Speaker rev. 7
; Original by Hans Mikelson
; mods by Pete Goodeve
; this score matches the new Leslie (instr 8)
; (Hans' version is Instr 9)
;-------------------------------------------------------------------
; GEN functions
;-------------------------------------------------------------------
f0  5000         ; Continue running a long time for midi data input.

; The default versions of these tables are set in the .orc file
; Override if you want...

; Distortion Tables
; Slight Distortion (default)
;f1 0 8192   8 -.8 336 -.78  800 -.7 5920 .7  800 .78 336 .8
; Heavy Distortion
;f1 0 8192   8 -.8 336 -.76 3000 -.7 1520 .7 3000 .76 336 .8
; ...Matched to Slight Dist level:
;f1 0 8192   -8 -.4 336 -.38 3000 -.35 1520 .35 3000 .38 336 .4


; Default Swell Pedal Characteristic Curve
;f2 0 129 7 0.1 3 0.2 30 0.7 37 0.9 58 1 1 1



; Instr 1 is drawbars/vibrato on-off/percussion
i1 0 0     8   8   5   3   2   4   5   8   8     1      0    0

; Instr 2 is drawbars/keyclick/percussion Lower Manual (no perc needed)
i2 0 0     8   8   8   0   0   0   0   0   0     1

; Instr 3 is Leslie speed (Horn and Bass Rotor speeds are different)
;  -- note 2 sec 'ramp' to speed
; changes can also be made via MIDI ch.3 (see orc for details)
; It is reported that actual Fast Leslie is close to:
;                Horn   Bass
i3    0    2     6.8    6.6

;"Chorus 2" Vibrato -- (Instr 6): (now turned on by default as "C2")
;        FX      Scan    FiltTop    Filt Scale:    Q
i6 0 0  .5       .67       10000         1         1


; Instr 8, 9 are Leslies with/without deflectors
; p4=1 for deflectors, p4=2 for none (0 for off)
; i8 is a new algorithm:
;     p5=fraction of wall reflection to mix
;     p6 = reflection delay in millisec
i8  0  .1    1   .6 15
; Instr 9 off by default.  Start with, e.g.:  (p5=stereo phase)
;i9 0  .1    1   .12

; Instr 10 is Audio-Out-End-of_Chain (always runs)
; now also has reverb setting (p4 = "reverb time" -- off by default)
; may be changed at any time by another 'i10' command
i10 0 .1    0

s
</CsScore>
</CsoundSynthesizer>