;------------------------------------------------------------------------ ; 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 ; v7.2 -- 09/4/8 improved drawbar relation, added buzz to vibrato, simpler volume ; v7.3 -- 09/5/19 percussion now bypasses vibrato (as in real organ) ; -- and is *properly* single-triggered ; -- 09/5/23 run-time adjustment of Leslie freq response added ; -- 09/7/27 typo fix!! 5th harmonic was actually 6th in upper manual! ;------------------------------------------------------------------------ ; 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 (?) [seems OK...]: ksmps = 15 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, \ ; -1.0, 336, -.96, 800, -.9, 5920, .9, 800, .96, 336, 1.0 giDist ftgen 1, 0, 8192, 8, \ -1.0, 672, -.96, 800, -.9, 5248, .9, 800, .96, 672, 1.0 ; Straight Line: ;giDist ftgen 1, 0, 8192, 7, -1, 8192, 1 ; 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) for control via MIDI [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: --------- giVolume = 2 ; adjustment for optimum output (should never reach giDistMax) giDistMax = 20000; maximum output peak from distortion stage -- divides input too ;Percussion decay ("RC") time constants -- change to taste ; (the exponential hold time is computed from these according to amplitude) ;; 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.002 ; set to zero for maximum contact click -- 0.01 to minimize giClickNoise = 0 ; "Hash" amplitude: <1.0 if you want it... giClickBeta = 0.9 ; low-pass -- the closer to 1 the lower... ; 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 ;Leslie Freq Range scaling: ; (now adjusted to be a bit mellower -- but see instr 11 p3=12) giHiDirect = 0.1 giHiRefl = 0.1 giMidDirect = 0.7 giMidRefl = 0.7 giLowAll = 1.0 ;---------- 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 giBuzzAmp = 0.1 ; scanner vane wobble (adjust to taste) ; ------- (Fixed) Function Tables: --------- ; (Table numbers 3, 4, 9, 11, 12, 13, 14, 20, 21, 22 ; -- 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 [Table 21] giScaling ftgen 21, 0, 128, 5, 5.0, 90, 1.0, 38, 0.3 ;faster fall-off when folded... ; Relation of DrawBar position to harmonic amplitude [Table 22] giDBresp = 3 ; 0 is straight line, ~5 is x2/step ; Csound bug -- table has to be *longer* than 9...!) giDrawbar ftgen 22, 0, 16, -16, 0.0, 8, giDBresp, 8.0 ; (8 segs 1..9) ; 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 ;-------------------------------- ; ------- Global Initialization: --------- ; Leslie stationary by default: gispeedhorn init 0 gispeedbass init 0 gkpercenv init 0 ; no percussion unless triggered gaorgan init 0 ;Global send to speaker gabypass init 0 ; Bypass Vibrato galeft init 0 ;Leslie Outputs garight init 0 ;------------------------------------------------------------------------ ; 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) 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) 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) ;------------------------------------------------------------------------ ;------- A local sub-instrument is used for percussion control ----- instr percussion_envelope ;prints "percussion entered\\n" ihold kount active 4 if (kount == 0) then ;printks "percussion switching off\\n", 1 gkpercenv = 0 turnoff endif ipercamp init 0 if (giperc2 != 0) then ipercamp init giperc2 elseif (giperc3 != 0) then ipercamp init giperc3 endif iperctime init giPercFast if (ipercamp < 0) then ipercamp init -ipercamp iperctime init giPercSlow endif if (ipercamp > 0) then ; adjust decay time (from exp time const) iperctime init iperctime*(6.9+log(ipercamp)) endif gkpercenv init ipercamp ; Decay is exponential: gkpercenv expon ipercamp+0.001, iperctime, 0.001 endin ;-------- The organ voices -------- instr 4 ; Start percussion if needed: instcount init 0 if (giperc2 + giperc3) != 0 then instcount active 4 ; only first key-down should trigger envelope ;(multi-triggering now needs a few changes -- you can probably figure them out...) endif konce init instcount ; yes.. this is all necessary (:-/) [Conditionals -- Ughh!] if (konce == 1) then event "i", "percussion_envelope", 0, 0.001 konce = 0 endif inn notnum iamp veloc kswell midic7 11, 0, iamp, giSwell ikey init inn-36 ; key '0' is lowest on organ manual if ikey < gikeylo || ikey > gikeyhi then iamp=0 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 ksubfund table gksubfund, giDrawbar ksub3rd table gksub3rd, giDrawbar kfund table gkfund, giDrawbar k2nd table gk2nd, giDrawbar k3rd table gk3rd, giDrawbar k4th table gk4th, giDrawbar k5th table gk5th, giDrawbar k6th table gk6th, giDrawbar k8th table gk8th, giDrawbar ;------------------------------------------------------------------------ ; 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 ;------------------------------------------------------------------------ asubfund oscil ksubfund*issf, ifsf, iwheel1, frac(iT*ifsf) ;The organ tone is asub3rd oscil ksub3rd*iss3, ifs3, iwheel2, frac(iT*ifs3) ;made from adding afund oscil kfund*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 k4th*is4, if4, iwheel4, frac(iT*if4) a5th oscil k5th*is5, if5, iwheel4, frac(iT*if5) a6th oscil k6th*is6, if6, iwheel4, frac(iT*if6) a8th oscil k8th*is8, if8, iwheel4, frac(iT*if8) ; Key Click 'hash noise' kclickenv linseg 0, .005, giClickNoise, .01, 0, .01, 0 aclick noise kclickenv, giClickBeta ;adjust last param for low-pass ; (Revised) Percussion: ; Actual Hammond percussion is "Single triggered". ; The harmonic used for the 'percussion' sound is also available to drawbars. ; The percussion signal bypasses vibrato (as in the real circuitry) ;(In the hardware, the 9th harmonic busbar is diverted 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.) ; ... only one of giperc2 or giperc3 should be non-zero: ifperc = (giperc2 != 0) ? if2 : if3 isperc init 0 ;; because 'else' dun' work in Csound4!! if (giperc2 != 0) then isperc init is2*giVolume elseif (giperc3 != 0) then isperc init is3*giVolume endif aperc oscil gkpercenv*isperc, ifperc, iwheel4, frac(iT*ifperc) aorgan sum asubfund,asub3rd,afund,a2nd,a3rd,a4th,a5th,a6th,a8th,aclick aorgan = amp*aorgan*giVolume gaorgan = gaorgan+givibrS*aorgan gabypass = gabypass+(gkone-givibrS)*aorgan+aperc*amp endin ;------------------------------------------------------------------------ ;------------------------------------------------------------------------ ; Tone Wheel Organ Second ("Lower") Manual (MIDI input ch. 5) ;------------------------------------------------------------------------ instr 5 inn notnum iamp veloc kswell midic7 11, 0, iamp, giSwell ikey init inn-36 ; print inn, ipch, ikey if ikey < gikeylo || ikey > gikeyhi then iamp=0 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 ksubfund table gksubfundG, giDrawbar ksub3rd table gksub3rdG, giDrawbar kfund table gkfundG, giDrawbar k2nd table gk2ndG, giDrawbar k3rd table gk3rdG, giDrawbar k4th table gk4thG, giDrawbar k5th table gk5thG, giDrawbar k6th table gk6thG, giDrawbar k8th table gk8thG, giDrawbar ;------------------------------------------------------------------------ iT times ;------------------------------------------------------------------------ amp linenr kswell, giClickRise, .01, .01 ; Percussion not available on lower manual ;------------------------------------------------------------------------ asubfund oscil ksubfund*issf, ifsf, iwheel1, frac(iT*ifsf) asub3rd oscil ksub3rd*iss3, ifs3, iwheel2, frac(iT*ifs3) afund oscil kfund*isf, iff, iwheel3, frac(iT*iff) a2nd oscil k2nd*is2, if2, iwheel4, frac(iT*if2) a3rd oscil k3rd*is3, if3, iwheel4, frac(iT*if3) a4th oscil k4th*is4, if4, iwheel4, frac(iT*if4) a5th oscil k5th*is5, if5, iwheel4, frac(iT*if5) a6th oscil k6th*is6, if6, iwheel4, frac(iT*if6) a8th oscil k8th*is8, if8, iwheel4, frac(iT*if8) ; Key Click 'hash noise' kclickenv linseg 0, .005, giClickNoise, .01, 0, .01, 0 aclick noise kclickenv, giClickBeta ;adjust last param for low-pass aorgan sum asubfund,asub3rd,afund,a2nd,a3rd,a4th,a5th,a6th,a8th,aclick aorgan = amp*aorgan*giVolume gaorgan = gaorgan+givibrG*aorgan gabypass = gabypass+(gkone-givibrG)*aorgan endin ;------------------------------------------------------------------------ ; This instrument adds 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 giBuzzAmp init p9 ; maybe 0.1 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 abuzz oscils giBuzzAmp, 109.92, 0 ; stator vane wobble abuzz = abuzz + 1.0 avibrout vdelay gaorgan, ascan, giVibrLine*2 ; delay line attenuates higher frequencies afiltout lowpass2 avibrout*abuzz, giftopfrq/(1+kscan*gifscale), giQ gaorgan mac givrchor,gaorgan, givibchor,afiltout, gkone, gabypass gabypass = 0 ;zeroed after first use ; kp peak gaorgan ; uncomment these if you want to check peak outputs... ; printk 4,kp 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. ; (input -0.5..+0.5, output -1.0..+1.0) aclip tablei (gaorgan+gabypass)*4096/giDistMax, giDist,0,4096 aclip = aclip*giDistMax ; Distortion bypass if desired (and comment out the above): ; aclip = gaorgan+gabypass 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 iradius,gkenv,giSine1 koscq oscil iradius,gkenv,giSine1, 0.25 kdopl = gkmin+(iradius-kosc) kdoplql = gkmin+(iradius-koscq)+ilag kdoplqr = gkmin+koscq+ilag adopl deltapi kdopl adoplql deltapi kdoplql adoplqr deltapi kdoplqr ;------------------------------------------------------------------------ ; 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. kfdohi oscil giHiDirect,gkenv,itaba kflohi oscil irefl*giHiRefl,gkenv,itaba,0.25 kfrohi = irefl*giHiRefl - kflohi kfdomid oscil giMidDirect,gkenv,itabb kflomid oscil irefl*giMidRefl,gkenv,itabb,0.25 kfromid = irefl*giMidRefl - kflomid ;------------------------------------------------------------------------ ; Amplitude Effect on Lower Speaker kalosc = (kosclow*.4+1)*giLowAll ; Add all frequency ranges and output the result. galeft mac gkone,galeft, kfdohi,adfhi, kflohi,alfhi, kfdomid,adfmid, kflomid,alfmid, kalosc,adflow garight mac gkone,garight, kfdohi,adfhi, kfrohi,arfhi, kfdomid,adfmid, 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)*4096/giDistMax, giDist,0,4096 aclip = aclip*giDistMax/2 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 giHiDirect,gkenv,itaba kfrohi oscil giHiDirect,gkenv,itaba,isep kflomid oscil giMidDirect,gkenv,itabb kfromid oscil giMidDirect,gkenv,itabb,isep ;------------------------------------------------------------------------ ; Amplitude Effect on Lower Speaker kalosc = (koscllow*.4+1)*giLowAll karosc = (koscrlow*.4+1)*giLowAll ; Add all frequency ranges and output the result. galeft mac gkone,galeft, kflohi,alfhi, kflomid,alfmid, kalosc,alflow garight mac gkone,garight, kfrohi,arfhi, 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 if (gkleslieA + gkleslieB == 0) then galeft = (gaorgan+gabypass) garight = galeft endif ; kpl peak galeft ; uncomment for peak checking ; printk 4, kpl, 5 ; kpr peak garight ; printk 4, kpr, 6 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 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 giBuzzAmp init p9 ; maybe 0.1 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 if p6 > 0 then giClickBeta = p6 endif elseif p3 == 12 then ; Leslie freq resp. giHiDirect = p4 giHiRefl = p5 giMidDirect = p6 giMidRefl = p7 giLowAll = p8 endif turnoff ; always endin