Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
393 lines (334 sloc) 14.4 KB
(
e = 2.71828;
~delayDivisions = [25, 8, 6, 4, 3, e, 2, e/2, 1, 0.5];
/*
* DISTORTION
*/
// # 1209 Valve saturation
// > k: Distortion level (0 to 1)
// > k: Distortion character (0 to 1)
// > a: Input
// < a: Output
// Mix controls both bypass and total distortion amount, Elektron style.
SynthDef(\valvesat,
{
arg output = 0, input, mix = 0.5, crunch = 0.1;
var in = In.ar(input, 2);
var distortion = mix;
var character = mix;
var effect = LADSPA.ar(2, 1209, distortion, character, in);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}
).add;
// Custom soft-clip based distortion/overdrive with compression on input and output.
// Mix controls both bypass and total distortion amount, Elektron style.
// Todo:
// - Tune mapping of offset, and wetdry for proper feeling across input range.
// - Combine with a compressor of some sort to even out distortion?
// - Add harmonics, tube-style, as you crank it.
// - Add some hard clipping towards the top of the range.
// - Some sort of volume/overall loudness compensation (re-map based on input envelope again to track dynamics?)
// - Add an EQ/Filter, Analog-heat style?
SynthDef(\digitalheat,
{
arg output = 0, input, mix = 0, ratio = 1/3, attack = 0.01, release = 0.1;
var in = In.ar(input, 2);
var asymmetry = ControlSpec(0, 0.1).map(mix);
var pregain = Lag.kr(ControlSpec(1, 10).map(mix));
var threshold = ControlSpec(1, 0.4).map(mix);
// Processing
var comp = CompanderD.ar(in: in, thresh: threshold, slopeBelow: 1, slopeAbove: ratio, clampTime: attack, relaxTime: release, mul: 1, add: 0);
var effect = SoftClipAmp4.ar(comp.madd(add: asymmetry), pregain: pregain, add: -1 * pregain * asymmetry);
var outcomp = CompanderD.ar(in: effect, thresh: 0.7, slopeBelow: 1, slopeAbove: ratio, clampTime: attack, relaxTime: release, mul: 1, add: 0);
Out.ar(output, LinXFade2.ar(in, outcomp, mix * 2 - 1));
}
).add;
// # 1196 Fast overdrive
// > k: Drive level (0..1) => (1 to 3)
// > a: Input
// < a: Output
SynthDef(\fastoverdrive,
{
arg output = 0, input, mix = 0;
var in = In.ar(input, 2),
drive = ControlSpec(1, 3).map(mix);
var effect = LADSPA.ar(2, 1196, drive, in);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}
).add;
// # 1771 C* Saturate - Various static nonlinearities, 8x oversampled
// > k: mode (0 to 11)
// > k: gain (dB) (-24 to 72)
// > k: bias (0 to 1)
// > a: in (0 to 0)
// < a: out
SynthDef(\c_saturate,
{
arg output = 0, input, mix = 1, mode = 1, gain = 0.25, bias = 0.5;
var in = In.ar(input, 2),
m_mode = ControlSpec(0, 11, step: 1).map(mode),
m_gain = ControlSpec(-24, 72).map(gain);
var effect = LADSPA.ar(2, 1771, m_mode, m_gain, bias, in);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}
).add;
/*
* Pitch effects: CHORUS, FLANGER, PHASER, etc...
*/
// # 1201 Multivoice Chorus
// > k: Number of voices (1 to 8)
// > k: Delay base (ms) (10 to 40)
// > k: Voice separation (ms) (0 to 2)
// > k: Detune (%) (0 to 5)
// > k: LFO frequency (Hz) (2 to 30)
// > k: Output attenuation (dB) (-20 to 0)
// > a: Input
// < a: Output
SynthDef(\chorus,
{
arg output = 0, input, mix = 0,
numVoices = 8, predelay = 15, separation = 0.5,
detune = 1, lfoFreq = e, vol = -9;
var in = In.ar(input, 2);
var effect = LADSPA.ar(2, 1201, numVoices, predelay, separation, detune, lfoFreq, vol, in);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}
).add;
/*
* DELAYS
*/
// # 2588 C* Scape - Stereo delay with chromatic resonances
// > k: bpm (30 to 164)
// > k: divider (2 to 4) // (0..1) is mapped to a pleasant range of divisions.
// > k: feedback (0 to 1)
// > k: dry (0 to 1)
// > k: blend (0 to 1)
// > k: tune (Hz) (415 to 467) (modulation param mod)
// > a: in (0 to 0)
// < a: out.l
// < a: out.r
SynthDef(\c_scape,
{
arg output = 0, input, mix = 0.5, bpm = 120,
divider = 0.5, feedback = 0.3, dry = 0, mod = 0.5;
var in = In.ar(input, 2),
tune = ControlSpec(415, 467).map(mod),
division = Select.kr(ControlSpec(0, ~delayDivisions.size).map(divider), ~delayDivisions);
var effect = LADSPA.ar(2, 2588, bpm, division, feedback, dry, mix, tune, in);
Out.ar(output, effect);
}).add;
// a modified stereo ping-pong delay
SynthDef(\delay_ppong,
{
arg output = 0, input, mix = 1, bpm = 120,
division = 0.5, feedback = 0.3, mod = 0;
// flows
var in = In.ar(input, 2);
var divider = Select.kr(ControlSpec(0, ~delayDivisions.size, step: 1).map(division), ~delayDivisions);
// calcs
var tempo = 60.0 / bpm;
var dlyTime = Lag2.kr(tempo / divider, 0.75);
var rt60 = ControlSpec(0, 60, \amp).map(feedback);
var fbratio = 0.001 ** (dlyTime / rt60.abs) * rt60.sign; // permits negative feedback which changes harmonics
var effect = PingPong.ar(Buffer.alloc(s, s.sampleRate * 2, 2).bufnum, [in[0],in[1]], dlyTime, fbratio, 1);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}
).add;
/*
* REVERBS
*/
// # 1795 C* PlateX2 - Versatile plate reverb, stereo inputs
// > k: bandwidth (0 to 1) (size)
// > k: tail (0 to 1)
// > k: damping (0 to 1) (hfdecay)
// > k: blend (0 to 1) (mix)
// > a: in.l (0 to 0)
// > a: in.r (0 to 0)
// < a: out.l
// < a: out.r
// NOTE: diffusion is added here for compatibility but it does nothing in this reverb algorithm.
SynthDef(\c_plate_x2,
{
arg output = 0, input, mix = 0.5,
size = 0.9, tail = 0.5, hfdecay = 0.25, diffusion = 0;
var in = In.ar(input, 2);
var effect = LADSPA.ar(2, 1795, size, tail, hfdecay, mix, in[0], in[1], output, output + 1);
}).add;
// in: input to the reverb. Either an array of two audio signals (stereo), or a mono audiosignal.
// t60: (tail) (0..1) => (0.1..60) approximate reverberation time in seconds (0.1..60 sec) (T60 - the time for the reverb to decay by 60db when damp == 0 ). Does not affect early reflections.
// damp: (hfdecay) (0..1) controls damping of high-frequencies as the reverb decays. 0 is no damping, 1 is very strong damping. Values should be between (0..1). argumentsize scales size of delay-lines within the reverberator, producing the impression of a larger or smaller space. Values below 1 can sound metallic. Values should be between (0.5..5).
// size: -- undocumented --
// earlyDiff: (0..1) controls shape of early reflections. Values of 0.707 or more produce smooth exponential decay. Lower values produce a slower build-up of echoes. Values should be between (0..1).
// modDepth: depth (0..1) of delay-line modulation. Use in combination with modFreq to set amount of chorusing within the structure.
// modFreq: frequency (0..10 Hz) of delay-line modulation. Use in combination with modDepth to set amount of chorusing within the structure.
// low: multiplier (0..1) for the reverberation time within the low band.
// mid: multiplier (0..1) for the reverberation time within the mid band.
// high: multiplier (0..1) for the reverberation time within the high band.
// lowcut: frequency (100..6000 Hz) at which the crossover between the low and mid bands of the reverb occurs.
// highcut: frequency (1000..10000 Hz) at which the crossover between the mid and high bands of the reverb occurs.
SynthDef(\jpverb,
{
arg output = 0, input, mix = 0.5,
tail = 0.1, hfdecay = 0, size = 0.8, diffusion = 0.707,
modDepth = 5, modFreq = 2,
lowMult = 1, midMult = 1, highMult = 1,
lowcut = 500, highcut = 4000;
var in = In.ar(input, 2);
var rt60 = ControlSpec.new(0.1, 60).map(tail);
var effect = JPverb.ar(
in, rt60, hfdecay, size, diffusion,
modDepth, modFreq,
lowMult, midMult, highMult,
lowcut, highcut
);
Out.ar(output, LinXFade2.ar(in, effect, mix * 2 - 1));
}).add;
// in: either an array of two audio signals (stereo), or a mono audiosignal.
// delayTime: (tail) (0..1) => (0.1..60) approximate reverberation time in seconds (0.1..60 sec).
// damp: (hfdecay) (0..1) controls damping of high-frequencies as the reverb decays. 0 is no damping, 1 is very strong damping. Values should be between (0..1). argumentsize scales size of delay-lines within the diffusion unit, producing the impression of a larger or smaller space. Values below 1 can sound metallic. Values should be between (0.5..5).
// size: -- undocumented --
// diff: (0..1) controls pattern of echoes produced by the diffuser. At very low values, the diffuser acts like a delay-line whose length is controlled by the 'size' parameter. Medium values produce a slow build-up of echoes, giving the sound a reversed-like quality. Values of 0.707 or greater than produce smooth exponentially decaying echoes. Values should be in the range (0..1).
// feedback: (0..1) amount of feedback through the system. Sets the number of repeating echoes. A setting of 1.0 produces infinite sustain. Values should be in the range (0..1).
// modDepth: (0..1) depth of delay-line modulation. Use in combination with modFreq to produce chorus and pitch-variations in the echoes.
// modFreq: (0..10 Hz) frequency of delay-line modulation. Use in combination with modDepth to produce chorus and pitch-variations in the echoes.
SynthDef(\greyhole,
{
arg output = 0, input, mix = 0.5,
tail = 1, hfdecay = 0, size = 1, diffusion = 1,
feedback = 0.1, modDepth = 0.5, modFreq = 5;
var in = In.ar(input, 2);
var rt60 = ControlSpec.new(0.1, 60).map(tail);
var effect = Greyhole.ar([in[0], in[1]], rt60, hfdecay, size, diffusion, feedback, modDepth, modFreq);
Out.ar(output, LinXFade2.ar(in, [effect[0], effect[1]], mix * 2 - 1));
}).add;
// mix: (0..1) dry/wet balance
// room: (0..1) room size
// damp: (0..1) hfdecay
SynthDef(\freeverb,
{
arg output = 0, input, mix = 0.5, size = 1, hfdecay = 0, level = 1;
var in = In.ar(input, 2);
var effect = FreeVerb2.ar(in[0], in[1], mix:1, room: size, damp: hfdecay, mul: level);
Out.ar(output, LinXFade2.ar(in, [effect[0], effect[1]], mix * 2 - 1));
}).add;
/*
* AMP, CABINET, AND SPEAKER EMULATIONS
*/
// # 2592 C* AmpVTS - Idealised guitar amplification
// > k: over (0 to 2)
// > k: gain (0 to 1)
// > k: bright (0 to 1)
// > k: power (0 to 1)
// > k: tonestack (0 to 8)
// > k: bass (0 to 1)
// > k: mid (0 to 1)
// > k: treble (0 to 1)
// > k: attack (0 to 1)
// > k: squash (0 to 1)
// > k: lowcut (0 to 1)
// > a: in (0 to 0)
// < a: out
// ====================
// tonestack
// 0 basswoman
// 1 stanford
// 2 wookie
// 3 DC 30
// 4 juice 800
// 5 twin
// 6 AK 20
// 7 nihon ace
// 8 porky
// TODO : Create composite controls for compression (blend attack and squash), tone (blend brightness, bass, mid, treble), and crunch (blend gain and power, maybe tweak brightness).
// Possible TODO: Map some of the controls against an envelope follower to turn down the crunch when it's really loud?
//
// Custom controls:
// tonestack => passthrough to the plugin
// crunch => A synthesis of gain, power, and other controls for overdrive
// punch => compression as a single control
// tone => eq and brightness as a single control
SynthDef(\c_ampsim,
{
arg output = 0, input, mix = 1,
tonestack = 3, crunch = 0.1, punch = 0.1, tone = 0.5;
var in = In.ar(input, 2),
oversampling = 1,
gain = ControlSpec(0, 1).map(crunch),
brightness = ControlSpec(0.4, 1, 4).map(tone),
power = 0.5, // ControlSpec(0.2, 0.9).map(crunch),
bass = ControlSpec(0.7, 0.3).map(tone),
mid = 0.5,
treble = ControlSpec(0.3, 0.7).map(tone),
attack = ControlSpec(0.1, 0.3).map(punch),
squash = ControlSpec(0, 1).map(punch),
lowcut = 0.05,
outlevel = ControlSpec(1, 0.3, \amp).map(crunch)
;
var effect = LADSPA.ar(2, 2592,
oversampling, gain, brightness, power, tonestack, bass, mid, treble,
attack, squash, lowcut,
in);
Out.ar(output, LinXFade2.ar(in, effect * outlevel, mix * 2 - 1));
}).add;
/*
* EQ AND COMPRESSION
*/
// DJ style HP and LP filters from MZero
SynthDef(\paraeq,
{
arg output = 0, input, hpFreq, lpFreq;
var in = In.ar(input, 2);
var hpfkr = Lag2UD.kr(hpFreq, 0.05, 0.01);
var lpfkr = Lag2UD.kr(lpFreq, 0.05, 0.01);
Out.ar(output, BLowPass.ar(BHiPass.ar(in, hpfkr), lpfkr));
}
).add;
/*
* MIXERS AND SIGNAL UTILITIES
*/
// Simple stereo routing mixer with input gain and stereo send
// Routes two stereo signals (usually a dry signal and an effected signal)
// between two stereo outputs (usually a through and an effect)
// inOne = the first input
// inTwo = the second input
// inGain = a gainstage control to adjust the overall input level of both inputs before thru and send.
// outThru = the default output if send values are 0;
// outSend = secondary output - send values > 0 increase the amount of that input at this output.
// sendOne / sendTwo = respective sends for each input. 0 = 100% thru, 0% send, 1 = 100% send, 0% thru.
SynthDef(\fxMixer,
{
arg inOne, inTwo, inGain = 1, outThru, outSend, sendOne = 0, sendTwo = 0;
var inA = In.ar(inOne, 2),
inB = In.ar(inTwo, 2),
thruA = (1 - sendOne) * inGain,
thruB = (1 - sendTwo) * inGain,
sendA = sendOne * inGain,
sendB = sendTwo * inGain
;
Out.ar(outThru, Mix([[inA[0] * thruA, inA[1] * thruA], [inB[0] * thruB, inB[1] * thruB]]));
Out.ar(outSend, Mix([[inA[0] * sendA, inA[1] * sendA], [inB[0] * sendB, inB[1] * sendB]]));
}
).add;
// Simple stereo->stereo panning mixer with input gain and mono summing
// Mono summing (0..1) is linear sum from 0 (full stereo) to 1 (both inputs summed to both outputs)
SynthDef(\m2sMixer,
{
arg input, output, mono = 0, gain = 1;
var in = In.ar(input, 2) * gain;
Out.ar(output, Mix.ar([Balance2.ar(in[0], in[0], mono - 1), Balance2.ar(in[1], in[1], 1 - mono)]));
}
).add;
// MZero's gate algo
// rate is a control rate signal containing the clock division of the gate, e.g. 8, 4, 2, 0.5. 0 turns the gate effect off.
// beat is a phasor or other control rate signal from 0 to the number of beats per bar, used to sync the gate.
// ex: Phasor.ar(InTrig.kr(~beatSyncBus.index), tempo / s.sampleRate, 0, beatsPerBar);
SynthDef(\gate,
{
arg output = 0, input, rate, beat;
var k_rate = In.kr(rate);
var gateOn = Lag2UD.kr(k_rate > 0, 0.05, 0.05);
var gate = Lag2UD.ar((In.ar(beat) * k_rate).frac < 0.5, 0.005, 0.010);
Out.ar(output, input * (gate * gateOn + (1 - gateOn)));
}
).add;
)