;------------------------------------------------------------------------ ; 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... (:-/) ;------------------------------------------------------------------------ ; 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 is 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 = 4 ; Upper Manual MIDI channel giChanGreat = 5 ; 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.1, 3, 0.2, 30, 0.7, 37, 0.9, 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 silent by default -- adjust to taste giclick = 0 ; 5=soft 20=heavy ; 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 ;---------- 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 ; 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 = 0.001/72 gipowG = 0.001/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 0.001/(p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + 8) ;;;; ^^^ suck&see (=40/40000) -- must be low enough to avoid overrange ; print gipow*10000 ; Click volume must depend on drawbars in use: giclkpow init giclick/(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 0.001/(p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + 8) ;;;; ^^^ suck&see (=40/40000) -- must be low enough to avoid overrange ; print gipowG*10000 ; Click volume must depend on drawbars in use: giclkpowG init giclick/(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 ifsf table ikey, giTones ; SubFund ifs3 table (ikey+19), giTones ; Sub3rd iff table (ikey+12), giTones ; Fund if2 table (ikey+24), giTones ; Octv if3 table (ikey > 59? ikey+19 : ikey+31), giTones ; 3rd if4 table (ikey > 54? ikey+24 : ikey+36), giTones ; 4th if5 table (ikey > 50? ikey+28 : ikey+40), giTones ; 5th if6 table (ikey > 59? ikey+19 : (ikey>47? ikey+31 : ikey+43)), giTones; 5th if8 table (ikey > 54? ikey+24 : (ikey>42? ikey+36 : ikey+48)), giTones ; 5th ; print ifsf, ifs3, iff, if2, if3, if4, if5, if6, if8 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 0.001/(i(gksubfund) + i(gksub3rd) \ + i(gkfund) + i(gk2nd) \ + i(gk3rd) + i(gk4th) \ + i(gk5th) + i(gk6th) \ + i(gk8th) + 8) giclkpow init giclick/(gipow*10000) ;------------------------------------------------------------------------ ;kamp linenr kswell, .01, .01, .01 ;; This suppresses click from slow K-rate amp linenr kswell, .01, .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 ; Lokks like decay should be 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, ifsf, iwheel1 ;The organ tone is asub3rd oscil gksub3rd, ifs3, iwheel2 ;made from adding afund oscil gkfund, iff, iwheel3 ;the weighted output a2nd oscil k2nd, if2, iwheel4 ;of 9 tone wheels a3rd oscil k3rd, if3, iwheel4 a4th oscil gk4th, if4, iwheel4 a5th oscil gk5th, if5, iwheel4 a6th oscil gk6th, if6, iwheel4 a8th oscil gk8th, if8, iwheel4 ; Key Click 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 ifsf table ikey, giTones ; SubFund ifs3 table (ikey+19), giTones ; Sub3rd iff table (ikey+12), giTones ; Fund if2 table (ikey+24), giTones ; Octv if3 table (ikey > 59? ikey+19 : ikey+31), giTones ; 3rd if4 table (ikey > 54? ikey+24 : ikey+36), giTones ; 4th if5 table (ikey > 50? ikey+28 : ikey+40), giTones ; 5th if6 table (ikey > 59? ikey+19 : (ikey>47? ikey+31 : ikey+43)), giTones; 5th if8 table (ikey > 54? ikey+24 : (ikey>42? ikey+36 : ikey+48)), giTones ; 5th ; print ifsf, ifs3, iff, if2, if3, if4, if5, if6, if8 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 0.001/(i(gksubfundG) + i(gksub3rdG) \ + i(gkfundG) + i(gk2ndG) \ + i(gk3rdG) + i(gk4thG) \ + i(gk5thG) + i(gk6thG) \ + i(gk8thG) + 8) giclkpowG init giclick/(gipowG*10000) ;------------------------------------------------------------------------ amp linenr kswell, .01, .01, .01 ; Percussion not available on lower manual ;------------------------------------------------------------------------ asubfund oscil gksubfundG, ifsf, iwheel1 asub3rd oscil gksub3rdG, ifs3, iwheel2 afund oscil gkfundG, iff, iwheel3 a2nd oscil gk2ndG, if2, iwheel4 a3rd oscil gk3rdG, if3, iwheel4 a4th oscil gk4thG, if4, iwheel4 a5th oscil gk5thG, if5, iwheel4 a6th oscil gk6thG, if6, iwheel4 a8th oscil gk8thG, if8, iwheel4 ; Key Click 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 still 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 if (p4 == 0) then ; Turn Vibrato off now. printks "stopping Vibrato\\n", 0 turnoff endif givibchor init (p4 > 1? 1 : p4) ; 0..1 giscanfrac init (p5 > 1? 1 : p5) ; 0..1 giftopfrq init p6 ; ~10000 gifscale init p7 ; ~2?? iQ init p8 ;~2 ; 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), iQ kvchor init givibchor gaorgan mac (gkone-kvchor),gaorgan, kvchor,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 if (p4 == 0) then ; Turn the Leslie off now. printks "stopping Leslie\\n", 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 koscqr oscil 1,gkenv,giSine1, 0.75 kdopl = gkmin+(1-kosc)*iradius kdoplql = gkmin+(1-koscql)*iradius+ilag kdoplqr = gkmin+(1-koscqr)*iradius+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 kfdomid oscil 1,gkenv,itabb kflomid oscil irefl,gkenv,itabb,0.25 kfromid oscil irefl,gkenv,itabb,0.75 ;------------------------------------------------------------------------ ; 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 if (p4 == 0) then ; Turn the Leslie off now. printks "stopping Leslie\\n", 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 ;--------------------------------------------------- instr 10 p3 = p3+0.1 ; so ihold will never see a zero p3 ihold kleslieA active 8 kleslieB active 9 if (kleslieA + kleslieB == 0) then galeft = (gaorgan+gabypass)*40000 garight = galeft endif leslie: if (p4 > 0) goto reverbit arvbl = galeft arvbr = garight goto output reverbit: arvbl reverb galeft, p4 arvbr reverb garight, p4 output: outs (galeft+arvbl)/2, (garight+arvbr)/2 ;display gaorgan, 1,1 gaorgan = 0 gabypass = 0 galeft = 0 garight = 0 endin