1import("stdfaust.lib"); 2 3// These are now in a separate file ./effects.dsp 4// echo = echog(component("echo.dsp")); // ./echo.dsp 5// flanger = flg(component("flanger.dsp")); // ./flanger.dsp 6// chorus = chg(component("chorus.dsp")); // ./chorus.dsp 7// reverb = rg(component("freeverb.dsp")); 8 9process = main <: _,_; // Now separate: : echo : flanger : chorus : reverb; 10main = (signal + attach(extInput,amp) : filters : *(ampScaling)) ~ _; 11signal = oscs + noise * noiseOff * namp; 12 13ampScaling = envelopeAmp * masterVolume; // masterVolume is redundant but easier to find 14oscs = par(i,3,(oscamp(i+1)*osc(i+1))) :> _; 15 16controlSelect(1) = osc1(vrockerred); // ("[0] use as LFO")); 17octaveSelect(1) = osc1(vslider("[1] Octave1 [midi:ctrl 23] [style:knob]",1,0,5,1):int); // LO, 32', 16', 8', 4', 2' 18// Osc1 detunes like Osc2 and Osc3 (unlike in the Minimoog where it would be an expensive extra knob): 19detuneOctaves(1) = osc1(vslider("[2] DeTuning1 [units:Octaves] [midi:ctrl 24] [style:knob]",0.0,-1.0,1.0,0.001)); 20waveSelect(1) = osc1(vslider("[3] Waveform1 [midi:ctrl 25] [style:knob]",5,0,5,1):int); 21amp1Enable = mr1(vslider("[1] On [midi:ctrl 12] [style:knob] [color:blue]",1,0,1,1)); 22oscamp(1) = mr1(vslider("[0] Osc1 Amp [midi:ctrl 26] [style:knob]",0.5,0.0,1.0,0.001)) * amp1Enable; 23 24eei = mr2(vslider("[1] On [midi:ctrl 13] [style:knob] [color:blue]",0,0,1,1)); // External input = MAIN OUTPUT when "off" 25sei = mr2(vslider("[0] Ext Input [midi:ctrl 27] [style: knob]",0,0,1.0,0.001)); 26extInput(fb,extSig) = fb,extSig : select2(eei) : *(sei) : extClipLED; 27extClipLED = _ <: _, (abs : >(0.95) : mr2(vbargraph("[2] Ext Input Clip [style:led]",0,1)):!); 28keycLED = attach(mr2(vbargraph("[3] Keyboard Ctl [style:led]",0,1))); 29 30controlSelect(2) = osc2(vrockerred); // ("[0] use as LFO")); 31octaveSelect(2) = osc2(vslider("[1] Octave2 [midi:ctrl 28] [style:knob]",1,0,5,1):int); // LO, 32', 16', 8', 4', 2' 32detuneOctaves(2) = osc2(vslider("[2] DeTuning2 [units:Octaves] [midi:ctrl 29] [style:knob]",0.41667,-1.0,1.0,0.001)); 33waveSelect(2) = osc2(vslider("[3] Waveform2 [midi:ctrl 30] [style:knob]",5,0,5,1):int); 34amp2Enable = mr3(vslider("[1] On [midi:ctrl 14] [style:knob] [color:blue]",1,0,1,1)); 35oscamp(2) = mr3(vslider("[0] Osc2 Amp [midi:ctrl 31] [style:knob]",0.5,0.0,1.0,0.001)) * amp2Enable; 36 37noise = select2(ntype,no.noise,10.0*no.pink_noise); // pink noise needs some "make-up gain" 38namp = mr4(vslider("[0] Noise Amp [midi:ctrl 32] [style: knob]",0.0,0.0,1.0,0.001)); 39noiseOff = mr4cbg(vslider("[0] On [midi:ctrl 15] [style:knob] [color:blue]",0,0,1,1)); 40ntype = mr4cbg(vslider("[1] White/Pink [midi:ctrl 16] [tooltip: Choose either White or Pink Noise] [style: knob] [color:blue]",1,0,1,1)); 41 42controlSelect(3) = osc3(vrockerred); // ("[0] use as LFO")); 43octaveSelect(3) = osc3(vslider("[1] Octave3 [midi:ctrl 33] [style:knob]",0,0,5,1):int); // LO, 32', 16', 8', 4', 2' 44detuneOctaves(3) = osc3(vslider("[2] DeTuning3 [units:Octaves] [midi:ctrl 34] [style:knob]",0.3,-1.0,1.0,0.001)); 45waveSelect(3) = osc3(vslider("[3] Waveform3 [midi:ctrl 35] [style:knob]",0,0,5,1):int); 46amp3Enable = mr5(vslider("[1] On [midi:ctrl 17] [style:knob] [color:blue]",0,0,1,1)); 47oscamp(3) = mr5(vslider("[0] Osc3 Amp [midi:ctrl 36] [style:knob]",0.5,0.0,1.0,0.001)) * amp3Enable; 48 49waveforms(i) = (tri(i), bent(i), saw(i), sq(i), ptm(i), ptn(i)); 50 51// compute oscillator frequency scale factor, staying in lg(Hz) as much as possible: 52modWheelShift = 1.5*modWheel; // Manual says 0 to 1.5 octaves 53modulationCenterShift = 0; // Leave this off until triangle-wave modulation is debugged 54modulationShift = select2(oscModEnable, 0.0, 55 modWheelShift * ( modulationCenterShift + (1.0-modulationCenterShift) * oscNoiseModulation )); 56octaveShift(i) = -2+int(octaveSelect(i)); 57osc3FixedFreq = 369.994; // F# a tritone above middle C 58keyFreqGlidedMaybe = select2(osc3Control,osc3FixedFreq,keyFreqGlided); 59keyFreqModulatedShifted(3) = keyFreqGlidedMaybe; // osc3 not allowed to FM itself 60keyFreqModulatedShifted(i) = keyFreqGlided * pow(2.0, modulationShift); // i=1,2 61 62// When disconnected from the keyboard, Osc3 can detune 3 octaves up or down (Pat video): 63detuneBoost(3) = select2(osc3Control,3.0,1.0); 64detuneBoost(i) = 1.0; // i=1,2 65detuneOctavesFinal(i) = detuneOctaves(i)*detuneBoost(i); 66 67fBase(i) = keyFreqModulatedShifted(i) * pow(2.0, (masterTuneOctaves+octaveShift(i)+detuneOctavesFinal(i))) 68 : si.smooth(ba.tau2pole(0.016)); 69fLFOBase(i) = 3.0 * pow(2.0, detuneOctavesFinal(i)); // used when osc3 (only) is in LFO mode 70lfoMode(i) = (octaveSelect(i) == 0); 71f(i) = select2(lfoMode(i), fBase(i), fLFOBase(i)); // lowest range setting is LFO mode for any osc 72 73// i is 1-based: 74osc(i) = ba.selectn(6, int(waveSelect(i)), tri(i), bent(i), saw(i), sq(i), ptm(i), ptn(i)); 75tri(i) = select2(lfoMode(i), 76 os.triangle(f(i)), 77 os.lf_triangle(f(i))); 78bent(i) = 0.5*tri(i) + 0.5*saw(i); // from Minimoog manual 79saw(i) = select2(lfoMode(i), 80 os.sawtooth(f(i)), 81 os.lf_saw(f(i))); 82sq(i) = select2(lfoMode(i), 83 os.square(f(i)), 84 os.lf_squarewave(f(i))); 85ptm(i) = select2(lfoMode(i), // Note: a Duty knob would be better than these two, or in addition 86 os.pulsetrain(f(i),0.25), 87 lf_pulsetrain(f(i),0.25)); 88ptn(i) = select2(lfoMode(i), 89 os.pulsetrain(f(i),0.125), 90 lf_pulsetrain(f(i),0.125)); 91 92// Soon to appear in oscillators.lib: 93lf_pulsetrain(freq,duty) = 2.0*os.lf_pulsetrainpos(freq,duty) - 1.0; 94 95filters = ba.bypass1(bp,vcf); // BYPASS WILL GO AWAY (I think you just open it up all the way to bypass): 96bp = 0; // VCF is always on 97fcLgHz = vcf1(vslider("[1] Corner Freq [unit:Log2(Hz)] 98 [tooltip: Corner resonance frequency in Log2(Hertz)] 99 [style: knob] 100 [midi:ctrl 74]", // Frequency Cutoff (aka Brightness ) 101 10.6, log(40.0)/log(2), log(20000.0)/log(2), 0.000001)) // 9 octaves (from Minimoog manual) 102 //p: 40, 30, 80, 0.01)) 103 //p: : ba.pianokey2hz 104 : si.smooth(ba.tau2pole(0.016)); 105res = vcf1(vslider("[2] Corner Resonance [midi:ctrl 37] [tooltip: Resonance Q at VCF corner frequency (0 to 1)] 106 [style: knob]", 107 0.7, 0, 1, 0.01)); 108 109vcfKeyRange = vcf1cbg(vslider("[2] Kbd Ctl [midi:ctrl 38] [tooltip: Keyboard tracking of VCF corner-frequency (0=none, 1=full)] 110 [style: knob]", 111 1, 0, 1, 0.001)); // was in mr2 112vcfModEnable = vcf1cbg(vslider("[1] Filter Mod. [midi:ctrl 19] [color:red] [style:knob] [tooltip: Filter Modulation => Route Modulation Mix output to VCF frequency]",1,0,1,1)); 113// Note that VCF has three sources of corner-frequency setting that are added together: 114// - Corner Freq knob (40 Hz to 20 kHz) 115// - VCF Contour envelope (0 to 4 octaves) 116// - Injection 32 of Modulation Mix (0 to 1.5 octaves) 117// Manual says maximum vcf sweep spans 0 to 4 octaves: 118// Original Knob went to 10, but we're going to 4 so we can say the knob is in "octaves" units: 119vcfContourAmountOctaves = vcf1(vslider("[3] Amount of Contour (octaves) [midi:ctrl 39] [style: knob]", 1.2, 0, 4.0, 0.001)); 120vcfContourOctaves = vcfContourAmountOctaves * envelopeVCF; // in octaves 121// We are assuming that the modulation-mix range for the VCF freq is 1.5 octaves like it is for oscs 1 and 2: 122vcfModMixModulationOctaves = select2(vcfModEnable, 0, (1.5 * oscNoiseModulation * modWheel)); // octaves 123vcfModulationOctaves = vcfModMixModulationOctaves + vcfContourOctaves; 124keyFreqLogHzGlided = log(keyFreqGlided)/log(2.0); // FIXME: Start w freqLogHz not freq so we don't need exp(log()) here 125keyShiftOctaves = keyFreqLogHzGlided - log(261.625565)/log(2.0); // FIXME: ARBITRARILY centering on middle C - check device 126vcfKeyShiftOctaves = vcfKeyRange * keyShiftOctaves; 127modulatedFcLgHz = fcLgHz + vcfModulationOctaves + vcfKeyShiftOctaves; 128 129fc = min((0.5*ma.SR), pow(2.0,modulatedFcLgHz)); 130vcf = ve.moog_vcf_2bn(res,fc); 131 132// Attack, Decay, and Sustain ranges are set according to the Minimoog manual: 133attT60VCF = 0.001 * vcf2(vslider("[0] AttackF [midi:ctrl 40] [tooltip: Attack Time] [unit:ms] [style: knob]",1400,10,10000,1)); 134decT60VCF = 0.001 * vcf2(vslider("[0] DecayF [midi:ctrl 41] [tooltip: Decay-to-Sustain Time] [unit:ms] [style: knob]",10,10,10000,1)); 135susLvlVCF = 0.01 * vcf2(vslider("[0] SustainF [midi:ctrl 42] [tooltip: Sustain level as percent of max] [style: knob]",80,0,100,0.1)); 136decayButton = wg(vslider("Decay [midi:ctrl 20] [tooltip:Envelope Release either Decay value or 0][style:knob]",1,0,1,1):int); // was Staccato 137legatoButton = wg(vslider("Glide [midi:ctrl 65] [tooltip: Glide from note to note][style:knob]",1,0,1,1)); // was Legato 138relT60VCF = select2(decayButton,0.010,decT60VCF); 139envelopeVCF = en.adsre(attT60VCF,decT60VCF,susLvlVCF,relT60VCF,gate); 140 141// --- Smart Keyboard interface --- 142 143declare interface "SmartKeyboard{ 144 'Number of Keyboards':'2', 145 'Keyboard 0 - Number of Keys':'13', 146 'Keyboard 1 - Number of Keys':'13', 147 'Keyboard 0 - Lowest Key':'72', 148 'Keyboard 1 - Lowest Key':'60' 149}"; 150 151// --- functions --- 152 153// Signal controls: 154 155keyDownHold = gg(vslider("[0] gateHold [tooltip: lock sustain pedal on (hold gate set at 1)][style:knob]",0,0,1,1)); 156 157keyDown = gg(button("[1] gate [tooltip: The gate signal is 1 during a 158 note and 0 otherwise. For MIDI, NoteOn occurs when the gate 159 transitions from 0 to 1, and NoteOff is an event corresponding 160 to the gate transition from 1 to 0. The name of this Faust 161 button must be 'gate'.]")); 162 163sustain = gg(button("[1] sustain [midi:ctrl 64] 164 [tooltip: extends the gate (keeps it set to 1)]")); // MIDI only (see smartkeyb doc) 165 166gate = keyDown + keyDownHold + sustain : min(1); 167 168attT60 = 0.001 * ng(vslider("[0] AttackA [midi:ctrl 43] [tooltip: Attack Time] [unit:ms] [style: knob]",2,0,5000,0.1)); 169decT60 = 0.001 * ng(vslider("[0] DecayA [midi:ctrl 44] [tooltip: Decay-to-Sustain Time] [unit:ms] [style: knob]",10,0,10000,0.1)); 170susLvl = 0.01 * ng(vslider("[0] SustainA [midi:ctrl 45] [tooltip: Sustain level as percent of max] [style: knob]",80,0,100,0.1)); 171relT60 = select2(decayButton,0.010,decT60); // right? 172envelopeAmpNoAM = en.adsre(attT60,decT60,susLvl,relT60,gate); 173AMDepth = 0.5; 174envelopeAmp = select2(oscModEnable, envelopeAmpNoAM, 175 envelopeAmpNoAM * (1.0 + AMDepth*modWheel * 0.5 * (1.0+oscNoiseModulation))); 176 177// Signal Parameters 178ampL = volg(vslider("[1] gain [style:knob] [tooltip: Amplitude]",0.2,0,1.0,0.001)); 179amp = ampL : si.smoo; // envelopeAmp is multiplied once on entire signal sum 180//elecGuitar.dsp values used: 181bend = wg(ba.semi2ratio(hslider("[0] bend [style:knob] [midi:pitchwheel]",0,-2,2,0.01))) : si.polySmooth(gate,0.999,1); 182//Previous guess: 183modWheel = wg(vslider("[1] mod [midi:ctrl 1] [style:knob] [tooltip: PitchModulation amplitude in octaves]", 184 0,0,1.0,0.01)) : si.polySmooth(gate,0.999,1); 185//p: MIDI requires frequency in Hz, not piano-keys as we had before 186// Frequency Range is 0.1 Hz to 20 kHz according to the Minimoog manual: 187// MIDI REQUIRES THE FOLLOWING PARAMETER TO BE NAMED 'freq': 188keyFreqBent = bend * kg(hslider("[2] freq [unit:Hz] [style:knob]",220,0.1,20000,0.1)); 189masterVolume = vg(vslider("MasterVolume [style:knob] [midi:ctrl 7] [tooltip: master volume, MIDI controlled]", 190 0.7,0,1,0.001)) 191 : si.smooth(ba.tau2pole(0.16)); 192masterTuneOctaves = dg(vslider("[0] Tune [midi:ctrl 47] [unit:Octaves] [style:knob] 193 [tooltip: Frequency-shift up or down for all oscillators in Octaves]", 0.0,-1.0,1.0,0.001)); 194 // Oscillator Modulation HrockerRed => apply Modulation Mix output osc1&2 pitches 195glide = gmmg(vslider("[0] Glide [midi:ctrl 5] [unit:sec/octave] [style:knob] [scale:log] 196 [tooltip: Portamento (frequency-glide) in seconds per octave]", 197 0.008,0.001,1.0,0.001)); 198legatoPole = select2(legatoButton,0.5,ba.tau2pole(glide*exp(1.0f)/2.0f)); // convert 1/e to 1/2 by slowing down exp 199keyFreqGlided = keyFreqBent : si.smooth(legatoPole); 200 201mmix = gmmg(vslider("[1] Mod. Mix [midi:ctrl 48] [style:knob] [tooltip: Modulation Mix: Osc3 (0) to Noise (1)]", 202 0.0,0.0,1.0,0.001)); 203oscNoiseModulation = (mmix * noise) + ((1.0-mmix) * osc(3)); // noise amplitude and off-switch ignored here 204oscModEnable = dsg(vslider("[0] Osc. Mod. [midi:ctrl 22] [color:red] [style:knob] [tooltip:Oscillator Modulation adds Modulation Mix output to osc1&2 frequencies",1,0,1,1)); // any offset? 205osc3Control = dsg(vslider("[1] Osc. 3 Ctl [midi:ctrl 9] [color:red] [style:knob] [tooltip:Oscillator 3 frequency tracks the keyboard if on, else not",0,0,1,1):int); 206 207effect = _,_ : + 208: component_echo 209: component_flanger 210: component_chorus 211: component_freeverb; 212 213component_echo = environment { 214 215echo_group(x) = x; // Let layout2.dsp lay us out 216knobs_group(x) = ekg(x); 217switches_group(x) = esg(x); 218 219dmax = 32768; // one and done 220dmaxs = float(dmax)/44100.0; 221 222Nnines = 1.8; // Increase until you get the desired maximum amount of smoothing when fbs==1 223//fastpow2 = ffunction(float fastpow2(float), "fast_pow2.h", ""); 224fbspr(fbs) = 1.0 - pow(2.0, -3.33219*Nnines*fbs); // pole radius of feedback smoother 225inputSelect(gi) = _,0 : select2(gi); 226echo_mono(dmax,curdel,tapdel,fb,fbspr,gi) = inputSelect(gi) : (+:si.smooth(fbspr) 227<: de.fdelay(dmax,curdel), 228de.fdelay(dmax,tapdel)) 229~(*(fb),!) : !,_; 230 231tau2pole(tau) = ba.if(tau>0, exp(-1.0/(tau*ma.SR)), 0.0); 232t60smoother(dEchoT60) = si.smooth(tau2pole(dEchoT60/6.91)); 233 234dEchoT60 = knobs_group(vslider("[1] DelayT60 [midi:ctrl 60] [style:knob]", 0.5, 0, 100, 0.001)); 235dEchoSamplesRaw = knobs_group(vslider("[0] Delay [midi:ctrl 61] [style:knob]", 0.5, 0.001, (dmaxs-0.001), 0.001)) * ma.SR; 236dEchoSamples = dEchoSamplesRaw : t60smoother(dEchoT60); 237warpRaw = knobs_group(vslider("[0] Warp [midi:ctrl 62] [style:knob]", 0, -1.0, 1.0, 0.001)); 238 239scrubAmpRaw = 0; 240 241scrubPhaseRaw = 0; 242fb = knobs_group(vslider("[2] Feedback [midi:ctrl 2] [style:knob]", .3, 0.0, 1.0, 0.0001)); 243amp = knobs_group(vslider("[3] Amp [midi:ctrl 75] [style:knob]", .5, 0, 1, 0.001)) : si.smooth(ba.tau2pole(ampT60/6.91)); 244 245ampT60 = 0.15661; 246fbs = knobs_group(vslider("[5] [midi:ctrl 76] FeedbackSm [style:knob]", 0, 0, 1, 0.00001)); 247gi = switches_group(1-vslider("[7] [midi:ctrl 105] EnableEcho[style:knob]",0,0,1,1)); // "ground input" switches input to zeros 248 249// Warp and Scrubber stuff: 250enableEcho = (scrubAmpRaw > 0.00001); 251triggerScrubOn = (enableEcho - enableEcho') > 0; // enableEcho went 0 to 1 252triggerScrubOff = (enableEcho - enableEcho') < 0; // enableEcho went 1 to 0 253// Ramps up only during scrub "hold" time and is otherwise zero: 254counter = (enableEcho * (triggerScrubOn : + ~ +(1) * enableEcho : -(2))) & (dmax-1); 255// implementation that continues scrubbing where it left off: 256 257scrubPhase = scrubPhaseRaw : t60smoother(dEchoT60*(1-triggerScrubOff)); 258scrubAmp = scrubAmpRaw : t60smoother(dEchoT60*(1-triggerScrubOff)); 259warp = warpRaw : t60smoother(dEchoT60); 260dTapSamplesRaw = dEchoSamplesRaw * (1.0 + warp + scrubPhase * scrubAmp) + float(counter); 261dTapSamples = dTapSamplesRaw : t60smoother(dEchoT60*(1-triggerScrubOff)); 262 263echo_process = _ <: _, amp * echo_mono(dmax,dEchoSamples,dTapSamples,fb,fbspr(fbs),gi) : +; 264 265}.echo_process; 266 267component_flanger = environment { 268 269// Created from flange.dsp 2015/06/21 270 271flanger_mono(dmax,curdel,depth,fb,invert,lfoshape) = _ <: _, (-:de.fdelay(dmax,curdel)) ~ *(fb) : _,*(select2(invert,depth,0-depth)) : + : *(1/(1+depth)); // ideal for dc and reinforced sinusoids (in-phase summed signals) 272 273flanger_process = ba.bypass1(fbp,flanger_mono_gui); 274 275// Kill the groups to save vertical space: 276meter_group(x) = flsg(x); 277ctl_group(x) = flkg(x); 278del_group(x) = flkg(x); 279lvl_group(x) = flkf(x); 280 281flangeview = lfo(freq); 282 283flanger_mono_gui = attach(flangeview) : flanger_mono(dmax,curdel,depth,fb,invert,lfoshape); 284 285sinlfo(freq) = (1 + os.oscrs(freq))/2; 286trilfo(freq) = 1.0-abs(os.saw1(freq)); 287lfo(f) = (lfoshape * trilfo(f)) + ((1-lfoshape) * sinlfo(f)); 288 289dmax = 2048; 290odflange = 44; // ~1 ms at 44.1 kHz = min delay 291dflange = ((dmax-1)-odflange)*del_group(vslider("[1] Delay [midi:ctrl 50][style:knob]", 0.22, 0, 1, 1)); 292freq = ctl_group(vslider("[1] Rate [midi:ctrl 51] [unit:Hz] [style:knob]", 0.5, 0, 10, 0.01)) : si.smooth(ba.tau2pole(freqT60/6.91)); 293 294freqT60 = 0.15661; 295depth = ctl_group(vslider("[3] Depth [midi:ctrl 52] [style:knob]", .75, 0, 1, 0.001)) : si.smooth(ba.tau2pole(depthT60/6.91)); 296 297depthT60 = 0.15661; 298fb = ctl_group(vslider("[5] Feedback [midi:ctrl 53] [style:knob]", 0, -0.995, 0.99, 0.001)) : si.smooth(ba.tau2pole(fbT60/6.91)); 299 300fbT60 = 0.15661; 301lfoshape = ctl_group(vslider("[7] Waveshape [midi:ctrl 54] [style:knob]", 0, 0, 1, 0.001)); 302curdel = odflange+dflange*lfo(freq); 303 304fbp = 1-int(flsg(vslider("[0] Enable [midi:ctrl 102][style:knob]",0,0,1,1))); 305 306invert = flsg(vslider("[1] Invert [midi:ctrl 49][style:knob]",0,0,1,1):int); 307 308}.flanger_process; 309 310component_chorus = environment { 311 312voices = 8; // MUST BE EVEN 313chorus_process = ba.bypass1to2(cbp,chorus_mono(dmax,curdel,rate,sigma,do2,voices)); 314 315dmax = 8192; 316curdel = dmax * ckg(vslider("[0] Delay [midi:ctrl 55] [style:knob]", 0.5, 0, 1, 1)) : si.smooth(0.999); 317rateMax = 7.0; // Hz 318rateMin = 0.01; 319rateT60 = 0.15661; 320rate = ckg(vslider("[1] Rate [midi:ctrl 56] [unit:Hz] [style:knob]", 0.5, rateMin, rateMax, 0.0001)) 321 : si.smooth(ba.tau2pole(rateT60/6.91)); 322 323depth = ckg(vslider("[4] Depth [midi:ctrl 57] [style:knob]", 0.5, 0, 1, 0.001)) : si.smooth(ba.tau2pole(depthT60/6.91)); 324 325depthT60 = 0.15661; 326delayPerVoice = 0.5*curdel/voices; 327sigma = delayPerVoice * ckg(vslider("[6] Deviation [midi:ctrl 58] [style:knob]",0.5,0,1,0.001)) : si.smooth(0.999); 328 329periodic = 1; 330 331do2 = depth; // use when depth=1 means "multivibrato" effect (no original => all are modulated) 332cbp = 1-int(csg(vslider("[0] Enable [midi:ctrl 103][style:knob]",0,0,1,1))); 333 334chorus_mono(dmax,curdel,rate,sigma,do2,voices) 335 = _ <: (*(1-do2)<:_,_),(*(do2) <: par(i,voices,voice(i)) :> _,_) : ro.interleave(2,2) : +,+ 336 with { 337 angle(i) = 2*ma.PI*(i/2)/voices + (i%2)*ma.PI/2; 338 voice(i) = de.fdelay(dmax,min(dmax,del(i))) * cos(angle(i)); 339 del(i) = curdel*(i+1)/voices + dev(i); 340 rates(i) = rate/float(i+1); 341 dev(i) = sigma * os.oscp(rates(i),i*2*ma.PI/voices); 342 }; 343 344}.chorus_process; 345 346component_freeverb = environment { 347 348import("stdfaust.lib"); 349 350declare name "freeverb"; 351declare version "1.0"; 352declare author "Grame"; 353declare license "BSD"; 354declare copyright "(c) GRAME 2006 and MoForte Inc. 2017"; 355declare reference "https://ccrma.stanford.edu/~jos/pasp/Freeverb.html"; 356 357//====================================================== 358// 359// Freeverb 360// Faster version using fixed delays (20% gain) 361// 362//====================================================== 363 364// Constant Parameters 365//-------------------- 366 367fixedgain = 0.015; //value of the gain of fxctrl 368scalewet = 3.0; 369scaledry = 2.0; 370scaledamp = 0.4; 371scaleroom = 0.28; 372offsetroom = 0.7; 373initialroom = 0.5; 374initialdamp = 0.5; 375initialwet = 1.0/scalewet; 376initialdry = 0; 377initialwidth= 1.0; 378initialmode = 0.0; 379freezemode = 0.5; 380stereospread= 23; 381allpassfeed = 0.5; //feedback of the delays used in allpass filters 382 383// Filter Parameters 384//------------------ 385 386combtuningL1 = 1116; 387combtuningL2 = 1188; 388combtuningL3 = 1277; 389combtuningL4 = 1356; 390combtuningL5 = 1422; 391combtuningL6 = 1491; 392combtuningL7 = 1557; 393combtuningL8 = 1617; 394 395allpasstuningL1 = 556; 396allpasstuningL2 = 441; 397allpasstuningL3 = 341; 398allpasstuningL4 = 225; 399 400// Control Sliders 401//-------------------- 402// Damp : filters the high frequencies of the echoes (especially active for great values of RoomSize) 403// RoomSize : size of the reverberation room 404// Dry : original signal 405// Wet : reverberated signal 406 407dampSlider = rkg(vslider("Damp [midi:ctrl 3] [style:knob]",0.5, 0, 1, 0.025))*scaledamp; 408roomsizeSlider = rkg(vslider("RoomSize [midi:ctrl 4] [style:knob]", 0.5, 0, 1, 0.025))*scaleroom + offsetroom; 409wetSlider = rkg(vslider("Wet [midi:ctrl 79] [style:knob]", 0.3333, 0, 1, 0.025)); 410combfeed = roomsizeSlider; 411 412// Comb and Allpass filters 413//------------------------- 414 415allpass(dt,fb) = (_,_ <: (*(fb),_:+:@(dt)), -) ~ _ : (!,_); 416 417comb(dt, fb, damp) = (+:@(dt)) ~ (*(1-damp) : (+ ~ *(damp)) : *(fb)); 418 419// Reverb components 420//------------------ 421 422monoReverb(fb1, fb2, damp, spread) 423= _ <: comb(combtuningL1+spread, fb1, damp), 424comb(combtuningL2+spread, fb1, damp), 425comb(combtuningL3+spread, fb1, damp), 426comb(combtuningL4+spread, fb1, damp), 427comb(combtuningL5+spread, fb1, damp), 428comb(combtuningL6+spread, fb1, damp), 429comb(combtuningL7+spread, fb1, damp), 430comb(combtuningL8+spread, fb1, damp) 431+> 432allpass (allpasstuningL1+spread, fb2) 433: allpass (allpasstuningL2+spread, fb2) 434: allpass (allpasstuningL3+spread, fb2) 435: allpass (allpasstuningL4+spread, fb2) 436; 437 438monoReverbToStereo(fb1, fb2, damp, spread) 439= + <: monoReverb(fb1, fb2, damp, 0) <: _,_; 440stereoReverb(fb1, fb2, damp, spread) 441= + <: monoReverb(fb1, fb2, damp, 0), monoReverb(fb1, fb2, damp, spread); 442monoToStereoReverb(fb1, fb2, damp, spread) 443= _ <: monoReverb(fb1, fb2, damp, 0), monoReverb(fb1, fb2, damp, spread); 444 445// fxctrl : add an input gain and a wet-dry control to a stereo FX 446//---------------------------------------------------------------- 447 448fxctrl(g,w,Fx) = _,_ <: (*(g),*(g) : Fx : *(w),*(w)), *(1-w), *(1-w) +> _,_; 449 450rbp = 1-int(rsg(vslider("[0] Enable [midi:ctrl 104][style:knob]",0,0,1,1))); 451 452// Freeverb 453//--------- 454 455//JOS:freeverb = fxctrl(fixedgain, wetSlider, stereoReverb(combfeed, allpassfeed, dampSlider, stereospread)); 456freeverb = fxctrl(fixedgain, wetSlider, monoReverbToStereo(combfeed, allpassfeed, dampSlider, stereospread)); 457 458freeverb_process = ba.bypass2(rbp,freeverb); 459 460}.freeverb_process; 461 462 463// This layout loosely follows the MiniMoog-V 464// Arturia-only features are labeled 465// Original versions also added where different 466 467// Need vrocker and hrocker toggle switches in Faust! 468// Need orange and blue color choices 469// Orange => Connect modulation sources to their destinations 470// Blue => Turn audio sources On and Off 471// - and later - 472// White => Turn performance features On and Off 473// Black => Select between modulation sources 474// Julius Smith for Analog Devices 3/1/2017 475 476vrocker(x) = checkbox("%%x [style:vrocker]"); 477hrocker(x) = checkbox("%%x [style:hrocker]"); 478vrockerblue(x) = checkbox("%x [style:vrocker] [color:blue]"); 479vrockerblue(x) = checkbox("%x [style:vrocker] [color:blue]"); 480 // USAGE: vrockerorange("[0] ModulationEnable"); 481 482hrockerblue(x) = checkbox("%%x [style:hrocker] [color:blue]"); 483vrockerred(x) = checkbox("%%x [style:vrocker] [color:red]"); 484hrockerred(x) = checkbox("%%x [style:hrocker] [color:red]"); 485 486declare designer "Robert A. Moog"; 487 488mmg(x) = hgroup("",x); // Minimoog + Effects 489 synthg(x) = mmg(vgroup("[0] Minimoog",x)); 490 fxg(x) = mmg(hgroup("[1] Effects",x)); 491 mg(x) = synthg(hgroup("[0]",x)); 492 cg(x) = mg(vgroup("[0] Controllers",x)); // Formerly named "Modules" but "Minimoog" group-title is enough 493 vg(x) = cg(hgroup("[0] Master Volume", x)); 494 dg(x) = cg(hgroup("[1] Oscillator Tuning & Switching", x)); 495 // Tune knob = master tune 496 dsg(x) = dg(vgroup("[1] Switches", x)); 497 // Oscillator Modulation HrockerRed => apply Modulation Mix output to osc1&2 pitches 498 // [MOVED here from osc3 group] Osc 3 Control VrockerRed => use osc3 as LFO instead of osc3 499 gmmg(x) = cg(hgroup("[2] Glide and ModMix", x)); 500 // Glide knob [0:10] = portamento speed 501 // Modulation Mix knob [0:10] (between Osc3 and Noise) = mix of noise and osc3 modulating osc1&2 pitch and/or VCF freq 502 og(x) = mg(vgroup("[1] Oscillator Bank", x)); 503 osc1(x) = og(hgroup("[1] Oscillator 1", x)); 504 // UNUSED Control switch (for alignment) - Could put Oscillator Modulation switch there 505 // Range rotary switch: LO (slow pulses or rhythm), 32', 16', 8', 4', 2' 506 // Frequency <something> switch: LED to right 507 // Waveform rotary switch: tri, impulse/bent-triangle, saw, pulseWide, pulseMed, pulseNarrow 508 osc2(x) = og(hgroup("[2] Oscillator 2", x)); 509 // UNUSED (originall) or Osc 2 Control VrockerRed 510 // Range rotary switch: LO, 32', 16', 8', 4', 2' 511 // Detuning knob: -7 to 7 [NO SWITCH] 512 // Waveform rotary switch: tri, impulse(?), saw, pulseWide, pulseMed, pulseNarrow 513 osc3(x) = og(hgroup("[3] Oscillator 3", x)); 514 // Osc 3 Control VrockerRed => use osc3 as LFO instead of osc3 515 // Range rotary switch: LO, 32', 16', 8', 4', 2' 516 // Detuning knob: -7 to 7 [NO SWITCH] 517 // Waveform rotary switch: tri, impulse(?), saw, pulseWide, pulseMed, pulseNarrow 518 mixg(x) = mg(vgroup("[2] Mixer", x)); 519 // Each row 5 slots to maintain alignment and include red rockers joining VCF area: 520 mr1(x) = mixg(hgroup("[0] Osc1", x)); // mixer row 1 = 521 // Osc1 Volume and Osc1 HrockerBlue & _ & _ & Filter Modulation HrockerRed 522 // Filter Modulation => Modulation Mix output to VCF freq 523 mr2(x) = mixg(hgroup("[1] Ext In, KeyCtl", x)); // row 2 = Ext In HrockerBlue and Vol and Overload LED and Keyboard Ctl HrockerRed 1 524 mr3(x) = mixg(hgroup("[2] Osc2", x)); // = Osc2 Volume and Osc2 HrockerBlue and Keyboard Ctl HrockerRed 2 525 // Keyboard Control Modulation 1&2 => 0, 1/3, 2/3, all of Keyboard Control Signal ("gate?") applied to VCF freq 526 mr4(x) = mixg(hgroup("[3] Noise", x)); // = Noise HrockerBlue and Volume and Noise Type VrockerBlue 527 mr4cbg(x) = mr4(vgroup("[1]", x)); // = Noise Off and White/Pink selection 528 // two rockers 529 mr5(x) = mixg(hgroup("[4] Osc3", x)); // Osc3 Volume and Osc3 HrockerBlue 530 modg(x) = mg(vgroup("[3] Modifiers", x)); 531 vcfg(x) = modg(vgroup("[0] Filter", x)); 532 vcf1(x) = vcfg(hgroup("[0] [tooltip:freq, Q, ContourScale]", x)); 533 vcf1cbg(x) = vcf1(vgroup("[0] [tooltip:two checkboxes]", x)); 534 // Filter Modulation switch 535 // VCF Off switch 536 // Corner Frequency knob 537 // Filter Emphasis knob 538 // Amount of Contour knob 539 vcf2(x) = vcfg(hgroup("[1] Filter Contour [tooltip:AttFilt, DecFilt, Sustain Level for Filter Contour]", x)); 540 // Attack Time knob 541 // Decay Time knob 542 // Sustain Level knob 543 ng(x) = modg(hgroup("[1] Loudness Contour", x)); 544 // Attack Time knob 545 // Decay Time knob 546 // Sustain Level knob 547 echog(x) = fxg(hgroup("[4] Echo",x)); 548 ekg(x) = echog(vgroup("[0] Knobs",x)); 549 esg(x) = echog(vgroup("[1] Switches",x)); 550 flg(x) = fxg(hgroup("[5] Flanger",x)); 551 flkg(x) = flg(vgroup("[0] Knobs",x)); 552 flsg(x) = flg(vgroup("[1] Switches",x)); 553 chg(x) = fxg(hgroup("[6] Chorus",x)); 554 ckg(x) = chg(vgroup("[0] Knobs",x)); 555 csg(x) = chg(vgroup("[1] Switches",x)); 556 rg(x) = fxg(hgroup("[7] Reverb",x)); 557 rkg(x) = rg(vgroup("[0] Knobs",x)); 558 rsg(x) = rg(vgroup("[1] Switches",x)); 559 outg(x) = fxg(vgroup("[8] Output", x)); 560 volg(x) = outg(hgroup("[0] Volume Main Output", x)); 561 // Volume knob [0-10] 562 // Unison switch (Arturia) or Output connect/disconnect switch (original) 563 // When set, all voices are stacked and instrument is in mono mode 564 tunerg(x) = outg(hgroup("[1] A-440 Switch", x)); 565 vdtpolyg(x) = outg(hgroup("[2] Voice Detune / Poly", x)); 566 // Voice Detune knob [0-10] (Arturia) or 567 // Polyphonic switch [red LED below] (Arturia) 568 // When set, instrument is in polyphonic mode with one oscillator per key 569 clipg(x) = fxg(vgroup("[9] Soft Clip", x)); 570 // Soft Clipping switch [red LED above] 571 kg(x) = synthg(hgroup("[1] Keyboard Group", x)); // Keyboard was 3 1/2 octaves 572 ws(x) = kg(vgroup("[0] Wheels and Switches", x)); 573 s1g(x) = ws(hgroup("[0] Jacks and Rockers", x)); 574 jg(x) = s1g(vgroup("[0] MiniJacks",x)); 575 gdlg(x) = s1g(vgroup("[1] Glide/Decay/Legato Enables",x)); // Arturia 576 // Glide Hrocker (see original Button version below) 577 // Decay Hrocker (see original Button version below) => Sets Release (R) of ADSR to either 0 or Decay (R) 578 // Legato Hrocker (not in original) 579 s2g(x) = ws(hgroup("[1] [tooltip:Wheels+]", x)); 580 bg(x) = s2g(vgroup("[0] [tooltip:Bend Enable and Range]", x)); 581 wg(x) = s2g(hgroup("[1] [tooltip:Bend and Mod Wheels]", x)); 582 // Using Glide/Decay/Legato enables above following Arturia: 583 // dg(x) = s2g(hgroup("[2] Glide and Decay momentary pushbuttons", x)); 584 // Glide Button injects portamento as set by Glide knob 585 // Decay Button uses decay of Loudness Contour (else 0) 586 keys(x) = kg(hgroup("[1] [tooltip:Keys]", x)); 587 gg(x) = keys(hgroup("[0] [tooltip: Gates]",x)); 588 // leave slot 1 open for sustain (below) 589