diff --git a/README.md b/README.md index 341f2867..4bd9ceea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,21 @@ -# SuperDirt +# SuperTweak +This is a fork of superdirt that is intended to play well with Strudel.cc +The intention of the fork is to be temporary, as features are planned to be merged back into superdirt over time. Features: +- note scaling is the same as Strudel +- Shimmer Reverb effect ".shimmer(1)" +- new oscillator types: supersaw, superpulse, sawtooth, triangle, pulse +- z parameters AKA oscillator macros z/z1,z2,z3,z4 +- pwm modulation ".s("pulse").z(.5).z2(3).z3(.8)" +- better delay effect with cycle relative timing ".delaytime(3/16)" +- filter envelopes for each filter type +- distort +- FX bus gain behavior is improved to work like a mixing console +- gain modules: ".gain" is pre effect ".postgain" is pre orbit effect +- ".dry" and ".wet" control the relative levels of effect bus so you can get a totally "wet" sound for example with ".room(1).dry(0)" +- relative gain of synths to samples is improved and normalized +- better sounding filters +- improved gaincurve x^2 (as opposed to x^4 in superdirt or x in Strudel ) +- Juno 60 Chorus emulation ".chorus(.5)" SuperCollider implementation of the Dirt sampler, originally designed for the [TidalCycles](https://github.com/tidalcycles/tidal) @@ -32,7 +49,7 @@ along with this library. If not, see . ## Installation from SuperCollider ``` -include("SuperDirt"); +in interpreter options in supercollider, include the path to this repo ``` Note: this also automatically installs the DirtSamples quark, which contains a large collection of sound files. It downloads them as a zip file. Sometimes, git fails to unpack these samples and they don't get listed. In this case, you have to unpack them "manually". diff --git a/classes/DirtEvent.sc b/classes/DirtEvent.sc index 03f07524..1f10015b 100644 --- a/classes/DirtEvent.sc +++ b/classes/DirtEvent.sc @@ -8,10 +8,14 @@ DirtEvent { } play { + + event.parent = orbit.defaultParentEvent; event.use { + // s and n stand for synth/sample and note/number ~s ?? { this.splitName }; + // unless orbit wide diversion returns something, we proceed ~diversion.(this) ?? { if(~s != \) { // backslash stands for do nothing @@ -35,15 +39,27 @@ DirtEvent { } splitName { + var s, n; + + + #s, n = ~sound.asString.split($:); if(~bank.notNil) { s = ~bank ++ s }; ~s = s.asSymbol; + + + + ~n = if(n.notNil) { n.asFloat } { 0.0 }; } mergeSoundEvent { - var soundEvent = orbit.dirt.soundLibrary.getEvent(~s, ~n); + var soundEvent; + + + soundEvent = orbit.dirt.soundLibrary.getEvent(~s, ~n); + if(soundEvent.isNil) { // only call ~notFound if no ~diversion is given that anyhow redirects control if(~diversion.isNil) { ~notFound.value } @@ -67,6 +83,7 @@ DirtEvent { var accelerate = ~accelerate.value; var avgSpeed, endSpeed; var useUnit; + ~release = ~release.value ? 0.01; ~freq = ~freq.value; unitDuration = ~unitDuration.value; @@ -102,24 +119,38 @@ DirtEvent { }; sustain = ~sustain.value; + sustain = sustain ?? { delta = ~delta.value; - if(~legato.notNil) { - delta * ~legato.value - } { + if (useUnit and: ~clip.isNil) { unitDuration = unitDuration ? delta; loop !? { unitDuration = unitDuration * loop.abs }; - } + } { + (delta / ~cps) * (~clip.value ? 1) + }; + + // if(~clip.notNil) { + // (delta / ~cps) * ~clip.value + // } { + // unitDuration = unitDuration ? delta; + // loop !? { unitDuration = unitDuration * loop.abs }; + // } }; - + + // end samples if sustain exceeds buffer duration // for every buffer, unitDuration is (and should be) defined. - if(useUnit) { sustain = min(unitDuration, sustain) }; - - ~fadeTime = min(~fadeTime.value, sustain * 0.19098); - ~fadeInTime = if(~begin != 0) { ~fadeTime } { 0.0 }; + // if(useUnit) { sustain = min(unitDuration, sustain) }; + + + // ~fadeTime = min(~fadeTime.value, sustain * 0.19098); + // ~fadeTime = ~fadeTime.value ? .001; + // ~fadeInTime = if(~begin != 0) { ~fadeTime } { 0.0 }; if (~timescale.notNil) {sustain = sustain * ~timescale }; - ~sustain = sustain - (~fadeTime + ~fadeInTime); + ~totalDuration = if (useUnit) {min(unitDuration, sustain + ~release)} {sustain + ~release}; + // ~sustain = sustain - (~fadeTime + ~fadeInTime); + ~sustain = sustain; + ~speed = speed; ~endSpeed = endSpeed; @@ -129,6 +160,7 @@ DirtEvent { ~channel !? { ~pan = ~pan.value + (~channel.value / ~numChannels) }; ~pan = ~pan * 2 - 1; // convert unipolar (0..1) range into bipolar one (-1...1) ~delayAmp = ~delay ? 0.0; // for clarity + ~z1 = ~z1 ? ~n; ~latency = ~latency + ~lag.value + (~offset.value * ~speed.value.abs); } @@ -140,14 +172,15 @@ DirtEvent { sendSynth { |instrument, args| var group = ~synthGroup; args = args ?? { this.getMsgFunc(instrument).valueEnvir }; + args.asControlInput.flop.do { |each| - server.sendMsg(\s_new, + server.sendMsg(\s_new, instrument, -1, // no id 1, // add action: addToTail group, // send to group *each.asOSCArgArray // append all other args - ) + ) } } @@ -160,11 +193,12 @@ DirtEvent { *[ in: orbit.synthBus.index, // read from synth bus, which is reused out: orbit.dryBus.index, // write to orbital dry bus - amp: ~amp, gain: ~gain, overgain: ~overgain, sample: ~hash, // required for the cutgroup mechanism cut: ~cut.abs, + release: ~release, + totalDuration: ~totalDuration, sustain: ~sustain, // after sustain, free all synths and group fadeInTime: ~fadeInTime, // fade in fadeTime: ~fadeTime // fade out diff --git a/classes/DirtEventTypes.sc b/classes/DirtEventTypes.sc index 3830b726..22f0bc89 100644 --- a/classes/DirtEventTypes.sc +++ b/classes/DirtEventTypes.sc @@ -44,7 +44,8 @@ DirtEventTypes { var freq, lag, sustain; var args, midiout, hasGate, midicmd, latency, chan; var sendNRPN, schedmidi, schedmidicmd, donecmd; - var hasNote = (~n != \none or: {~note.notNil}); + // var hasNote = (~n != \none or: {~note.notNil}); + var hasNote = (~n.notNil or: {~note.notNil}); var midiCommandPending = ~midicmd.notNil; var nrpnMSB, nrpnLSB, valMSB, valLSB; var ctlNum, control, num, val, note; @@ -108,7 +109,7 @@ DirtEventTypes { if (hasNote) { freq = ~freq.value; - ~midinote = (freq.cpsmidi).round(1).asInteger; + ~midinote = ((freq.cpsmidi).round(1) ? 0).asInteger; // Assume aftertouch means no noteOn, for now.. if(~polyTouch.notNil) { val = ~polyTouch; @@ -116,7 +117,7 @@ DirtEventTypes { schedmidi.value({ midiout.polyTouch(chan, note, val) }) } { // match dirt_gate SynthDef amplitude scaling - ~amp = ~amp.value * pow(~gain.min(2) + ~overgain, 4); + ~amp = ~amp.value * StrudelUtils.gainCurve(~gain + ~overgain, 4); sustain = ~sustain = ~sustain.value; if(~uid.notNil and: { midiout.notNil }) { diff --git a/classes/DirtOrbit.sc b/classes/DirtOrbit.sc index b69479bf..93a6cc3d 100644 --- a/classes/DirtOrbit.sc +++ b/classes/DirtOrbit.sc @@ -58,11 +58,12 @@ DirtOrbit { initDefaultGlobalEffects { this.globalEffects = [ // all global effects sleep when the input is quiet for long enough and no parameters are set. + GlobalDirtEffect(\dirt_shimmer, [\delaytime, \delayfeedback, \delaySend, \shimmer, \cps]), GlobalDirtEffect(\dirt_delay, [\delaytime, \delayfeedback, \delaySend, \delayAmp, \lock, \cps]), GlobalDirtEffect(\dirt_reverb, [\size, \room, \dry]), GlobalDirtEffect(\dirt_leslie, [\leslie, \lrate, \lsize]), GlobalDirtEffect(\dirt_rms, [\rmsReplyRate, \rmsPeakLag]).alwaysRun_(true), - GlobalDirtEffect(\dirt_monitor, [\limitertype]).alwaysRun_(true), + GlobalDirtEffect(\dirt_monitor, [\limitertype, \outgain, \dry, \wet]).alwaysRun_(true), ] } @@ -163,6 +164,7 @@ DirtOrbit { makeDefaultParentEvent { defaultParentEvent = Event.make { + ~cps = 1.0; ~offset = 0.0; ~begin = 0.0; @@ -173,22 +175,26 @@ DirtOrbit { ~overgain = 0.0; ~cut = 0.0; ~unit = \r; - ~n = \none; // sample number or note - ~octave = 5; - ~midinote = #{ ~note ? ~n + (~octave * 12) }; + ~n = nil; + ~octave = 0; + ~midinote = #{ (~note ? ~n ? StrudelUtils.baseNote()) + (~octave * 12) }; ~freq = #{ ~midinote.value.midicps }; ~dur = 1.0; ~delta = #{ ~dur.value }; - ~latency = 0.0; ~lag = 0.0; ~length = 1.0; ~loop = 1.0; - ~dry = 0.0; + ~dry = 1.0; + ~wet = 1.0; ~lock = 0; // if set to 1, syncs delay times with cps - ~amp = 0.4; + ~amp = 1; ~fadeTime = 0.001; + ~delaytime = 0.1875; + ~delayfeedback = 0.15; + ~lock = 1; + ~outgain = 1; // output gain that drives the final limiter // values from the dirt bus diff --git a/classes/DirtSoundLibrary.sc b/classes/DirtSoundLibrary.sc index fa3739d5..bb11c780 100644 --- a/classes/DirtSoundLibrary.sc +++ b/classes/DirtSoundLibrary.sc @@ -31,6 +31,27 @@ DirtSoundLibrary { synthEvents.clear; this.freeAllSoundFiles; } + // extractParts { |str| + // // Regex to split the string into numeric and non-numeric parts + // str.collect { |part| + // part.isNumber ifTrue: { part.asInteger } ifFalse: { part } + // }; + // } + + // sortStringsAlphanumerically { |stringArray| + // stringArray.sort { |a, b| + // var partsA = this.extractParts.(a); + // var partsB = this.extractParts.(b); + + // partsA.zip(partsB).detect { |pair| + // var (partA, partB) = pair; + // partA < partB ifTrue: { ^-1 }; + // partA > partB ifTrue: { ^1 }; + // }; + + // 0 // They are equal + // }; + // } addBuffer { |name, buffer, appendToExisting = false, metaData| var event, index; @@ -51,6 +72,7 @@ DirtSoundLibrary { } addSynth { |name, event, appendToExisting = false, useSynthDefSustain = false, metaData| + if(bufferEvents[name].notNil) { "a sample buffer with that name already exists: %\nSkipping...".format(name).warn; ^this @@ -107,6 +129,8 @@ DirtSoundLibrary { set { |name, indices ... pairs| var allEvents = this.at(name); + + if(allEvents.isNil) { "set: no events found with this name: %\n".format(name).warn } { @@ -179,7 +203,9 @@ DirtSoundLibrary { }; files = pathMatch(folderPath.standardizePath +/+ "*"); // dependent on operating system - if(sortFiles) { files.sort }; + if(sortFiles) { + files.sort; + }; if(files.notEmpty) { name = name.asSymbol; @@ -195,7 +221,9 @@ DirtSoundLibrary { filePaths.do { |filepath| try { + var buf, metaData; + buf = this.readSoundFile(filepath); if(buf.notNil) { metaData = this.readMetaData(filepath); @@ -283,6 +311,7 @@ DirtSoundLibrary { var allEvents = this.at(name); var event; + if(allEvents.isNil) { // first look up buffers, then synths @@ -298,8 +327,7 @@ DirtSoundLibrary { ^event } { - // the index may be \none (a Symbol), but this converts it to 0 - event = allEvents.wrapAt(index.asInteger); + event = allEvents.wrapAt((index ? 0).asInteger); }; if(doNotReadYet and: { event.notNil and: { event[\notYetRead] ? false } }) { @@ -320,8 +348,9 @@ DirtSoundLibrary { } makeEventForBuffer { |buffer, metaData| - var baseFreq = 60.midicps; + var baseFreq = StrudelUtils.baseNote().midicps; var baseFreqToMetaFreqRatio = metaData !? _[\baseFreqToMetaFreqRatio] ? 1.0; + ^( buffer: buffer.bufnum, bufferObject: buffer, @@ -340,7 +369,7 @@ DirtSoundLibrary { }, unitDuration: { buffer.duration * baseFreq / (~freq.value * ~metaDataTuneRatio.value) }, hash: buffer.identityHash, - note: 0 + note: StrudelUtils.baseNote() ) } diff --git a/classes/GlobalDirtEffect.sc b/classes/GlobalDirtEffect.sc index 60962347..0d234af5 100644 --- a/classes/GlobalDirtEffect.sc +++ b/classes/GlobalDirtEffect.sc @@ -30,7 +30,6 @@ GlobalDirtEffect { ) } - release { |releaseTime = 0.2| if(synth.notNil) { synth.server.sendBundle(nil, diff --git a/classes/StrudelUtils.sc b/classes/StrudelUtils.sc new file mode 100644 index 00000000..97eecff5 --- /dev/null +++ b/classes/StrudelUtils.sc @@ -0,0 +1,50 @@ + +StrudelUtils { + *lerp {|a, b, n| + var result = n * (b - a) + a; + ^result; + } + *getUnisonDetune { | unison, detune, voiceIndex | + var amount = 0; + if (unison > 1){ + amount = StrudelUtils.lerp(detune * -0.5, detune * 0.5, voiceIndex / (unison - 1)); + }; + ^amount; + } + *calculateCutoff {|cutoff=440, anchor=0, envamt=0, hold=0, holdtime, attack, decay, release, cutmin=20, cutmax=20000| + var offset = envamt.abs * anchor; + + var envmin = clip(2 ** (offset * -1) * cutoff, cutmin, cutmax); + var envmax = clip(2 ** (envamt.abs - offset) * cutoff, cutmin, cutmax); + + cutoff = EnvGen.ar( + Env.adsr( + attackTime: attack, + decayTime: decay, + releaseTime: release, + sustainLevel: hold, + peakLevel: envmax - envmin, + bias: envmin, + curve: -4 + ), + gate: Trig.ar(1, holdtime) + ); + ^cutoff; + } + *baseNote { + ^36; + } + //makeup gain for sample buffer + *sampleGain { + ^1; + } + *synthGain { + ^0.27; + } + *gainCurve {|gain=1| + // ^gain + ^pow(gain, 2) + } + +} + diff --git a/classes/SuperDirt.sc b/classes/SuperDirt.sc index 0f13700e..eb5d3ceb 100644 --- a/classes/SuperDirt.sc +++ b/classes/SuperDirt.sc @@ -33,6 +33,7 @@ SuperDirt { var <>controlBusses; var receiveAction, <>warnOutOfOrbit = true, <>maxLatency = 42; @@ -53,10 +54,14 @@ SuperDirt { init { soundLibrary = DirtSoundLibrary(server, numChannels); + outputvolume = server.volume; + outputvolume.setVolumeRange(-90, 6); modules = []; this.loadSynthDefs; this.initVowels(\counterTenor); this.initRoutingBusses; + + group = server.nextPermNodeID; flotsam = IdentityDictionary.new; } @@ -281,7 +286,7 @@ SuperDirt { playFunc = { |msg, time, tidalAddr| var latency = time - thisThread.seconds; - var event = (), orbit, index; + var event = (), orbit, index; if(dropWhen.value.not) { if(latency > maxLatency) { "The scheduling delay is too long. Your networks clocks may not be in sync".warn; diff --git a/classes/SuperDirtUGens.sc b/classes/SuperDirtUGens.sc index a18d1e9b..c6c0e6c6 100644 --- a/classes/SuperDirtUGens.sc +++ b/classes/SuperDirtUGens.sc @@ -183,9 +183,7 @@ DirtGateCutGroup { } } - DirtPause { - *ar { | signal, graceTime = 1, pauseImmediately = 0 | // immediately pause when started PauseSelf.kr(Impulse.kr(0) * pauseImmediately); @@ -193,7 +191,6 @@ DirtPause { signal = signal.abs + Trig1.ar(\resumed.tr(0), graceTime); DetectSilence.ar(signal, time:graceTime, doneAction:1); } - } diff --git a/hacks/adding-a-compressor.scd b/hacks/adding-a-compressor.scd index 963ed9c3..b40f699d 100644 --- a/hacks/adding-a-compressor.scd +++ b/hacks/adding-a-compressor.scd @@ -7,7 +7,7 @@ GlobalDirtEffect(\dirt_reverb, [\size, \room, \dry]), GlobalDirtEffect(\dirt_leslie, [\leslie, \lrate, \lsize]), GlobalDirtEffect(\dirt_rms, [\rmsReplyRate, \rmsPeakLag]).alwaysRun_(true), - GlobalDirtEffect(\dirt_monitor, [\limitertype]).alwaysRun_(true), + GlobalDirtEffect(\dirt_monitor, [\limitertype, \outgain]).alwaysRun_(true), ] }; ) diff --git a/hacks/external-interfacing.scd b/hacks/external-interfacing.scd index 5a2e0c93..3714118f 100644 --- a/hacks/external-interfacing.scd +++ b/hacks/external-interfacing.scd @@ -15,7 +15,7 @@ SynthDef(\gendy, { |out, sustain = 1, freq = 440, pan, fratio = 0| ); // play it in tidal: -// d1 $ s "gendy" # legato "1.2" +// d1 $ s "gendy" # clip "1.2" ~dirt.set(\fratio, Ndef(\ctrl1)); diff --git a/hacks/jitlib-hacks.scd b/hacks/jitlib-hacks.scd index db27357e..faff890a 100644 --- a/hacks/jitlib-hacks.scd +++ b/hacks/jitlib-hacks.scd @@ -63,6 +63,7 @@ Event.addEventType(\dirt, { ~latency = s.latency; ~delta = ~dur.value; ~s = ~s ? ~instrument; + d.value(currentEnvironment) }) ) @@ -74,7 +75,7 @@ Pdef(\x, \s, Pn(Pshuf([\bd, \hh, \cp, \imp], 5)), \begin, Pn(Pseries(0, 0.002, 20)), \dur, 0.1, - \legato, Pwhite(0.01, 0.4) + \clip, Pwhite(0.01, 0.4) ) ).play; ) @@ -88,7 +89,7 @@ Pdef(\x, \begin, Pn(Pseries(0, 0.002, 20)), \bandf, Pfunc { exprand(130, 10000) }, \dur, 0.1, - \legato, Pwhite(0.01, 0.4) + \clip, Pwhite(0.01, 0.4) ) ).play; ) @@ -104,7 +105,7 @@ Pdef(\x, \instrument, Pn(Pshuf([\bd, \hh, \cp, \imp], 5)), \begin, Pn(Pseries(0, 0.002, 20)), \dur, 0.1, - \legato, Pwhite(0.01, 0.4) + \clip, Pwhite(0.01, 0.4) ) ).play; ) @@ -118,7 +119,7 @@ Pdef(\x, \dur, 0.11, \room, Pseq([0, 0, 0.5, 0, 0], inf), \pan, Pseq([0, 1], inf), - \legato, Pwhite(0.01, 1.4) + Pwrand([0, 16], [0.9, 0.1], inf) + \clip, Pwhite(0.01, 1.4) + Pwrand([0, 16], [0.9, 0.1], inf) ) ).play; ) @@ -132,7 +133,7 @@ Pdef(\x, \dur, Prand((3..5).collect{ |x| Pn(2 ** neg(x), x) }, inf), \room, Pseq([0, 0, 0.5, 0, 0], inf), \pan, Pseq([0, 1], inf), - \legato, Pwhite(0.01, 1.4) + Pwrand([0, 16], [0.9, 0.1], inf) + \clip, Pwhite(0.01, 1.4) + Pwrand([0, 16], [0.9, 0.1], inf) ) ).play; ) diff --git a/hacks/pitch-model-from-tidal.scd b/hacks/pitch-model-from-tidal.scd index 60564dd3..ce796812 100644 --- a/hacks/pitch-model-from-tidal.scd +++ b/hacks/pitch-model-from-tidal.scd @@ -47,7 +47,8 @@ let degree = pF "degree" var scale, tuning; pitchEvent.use { ~freq = { - if(~n != 0) { ~note = ~n }; // interpret n as note (might be also degree) + if(~n.notNil) { ~note = ~n }; // interpret n as note (might be also degree) + // if(~n != 0) { ~note = ~n }; // interpret n as note (might be also degree) ~scaleName !? { scale = Scale.at(~scaleName); scale !? { diff --git a/hacks/sclang-dirt.scd b/hacks/sclang-dirt.scd index af9fde5f..8e04da82 100644 --- a/hacks/sclang-dirt.scd +++ b/hacks/sclang-dirt.scd @@ -39,7 +39,7 @@ Pdef(\x, \n, Pwhite(0, 20, inf), \speed, Pbrown(1, 1.2, 0.01), \amp, Pwhite().linexp(0, 1, 0.001, 0.3), - \legato, 2, + \clip, 2, \dur, 1 / 32 * Pshuf([1, 1/2, 1, 2, 2, 1/2], inf), \room, Pwrand([0, 0.8], [0.9, 0.1], inf), ) diff --git a/library/default-effects-extra.scd b/library/default-effects-extra.scd index 52c315a9..6925fdb0 100644 --- a/library/default-effects-extra.scd +++ b/library/default-effects-extra.scd @@ -152,14 +152,14 @@ DEFAULT EFFECTS EXTRA }, [\ir]).add; // A crunchy distortion with a lot of high harmonics, the only parameter is `distort` - ~dirt.addModule('distort', { |dirtEvent| + ~dirt.addModule('distort2', { |dirtEvent| dirtEvent.sendSynth("dirt_distort" ++ ~dirt.numChannels, [ - distort: ~distort, + distort: ~distort2, out: ~out ] ) - }, { ~distort.notNil }); + }, { ~distort2.notNil }); SynthDef("dirt_distort" ++ ~dirt.numChannels, { |out, distort = 0| var signal, mod; diff --git a/library/default-synths-extra.scd b/library/default-synths-extra.scd index df139191..c987dad9 100644 --- a/library/default-synths-extra.scd +++ b/library/default-synths-extra.scd @@ -101,6 +101,7 @@ env = EnvGen.ar(Env.linen(0.01, 0, 0.3, 1, -3), timeScale:sustain, doneAction:2); freq = 2000 * DirtFreqScale.kr(speed, accelerate, sustain) * (n/5 + 1).wrap(0.5,2); sound = HPF.ar(LPF.ar(WhiteNoise.ar(1), 3*freq), freq); + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)) }).add ); @@ -116,6 +117,7 @@ var freq = 100 * DirtFreqScale.kr(speed, accelerate, sustain) * (n/5+1).wrap(0.5,2); var sound = LPF.ar(Pulse.ar(freq), Line.ar(1030, 30, 0.2*sustain)) + (BPF.ar(HPF.ar(WhiteNoise.ar(1), 500), 1500) * Line.ar(1, 0, 0.2*decay)); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)) }).add ); @@ -179,6 +181,7 @@ SinOsc.ar(basefreq/64*rate, 0).range(lfof1,lfof2), resonance*4); sound = sound.tanh * 2; + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add ); @@ -187,17 +190,19 @@ // a moog-inspired sawtooth synth; slightly detuned saws with triangle harmonics, filter frequency modulated by LFO // "voice" controls a relative phase and detune amount ( - SynthDef(\supersaw, {|out, rate=1, decay=0, sustain=1, pan, accelerate, freq, + SynthDef(\supersawold, {|out, rate=1, decay=0, sustain=1, pan, accelerate, freq, voice=0.5, semitone=12, resonance=0.2, lfo=1, pitch1=1, speed=1| var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2); var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); var basefreq2 = basefreq * (2**(semitone/12)); var lfof1 = min(basefreq*10*pitch1, 22000); var lfof2 = min(lfof1 * (lfo + 1), 22000); - var sound = MoogFF.ar( - (0.5 * Mix.arFill(3, {|i| SawDPW.ar(basefreq * ((i-1)*voice/50+1), 0)})) + (0.5 * LFTri.ar(basefreq2, voice)), - LFTri.ar(basefreq/64*rate, 0.5).range(lfof1,lfof2), - resonance*4); + var sound = Mix.arFill(3, {|n| SawDPW.ar(basefreq * ((n-1)*voice/50+1), 0)}); + // var sound = MoogFF.ar( + // (0.5 * Mix.arFill(3, {|i| SawDPW.ar(basefreq * ((i-1)*voice/50+1), 0)})) + (0.5 * LFTri.ar(basefreq2, voice)), + // LFTri.ar(basefreq/64*rate, 0.5).range(lfof1,lfof2), + // resonance*4); + sound = sound.tanh*2; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add @@ -220,6 +225,7 @@ sound = MoogFF.ar(sound, SinOsc.ar(basefreq/32*rate, 0).range(lfof1,lfof2), resonance*4); sound = MoogFF.ar(sound, min(env2*lfof2*1.1, 22000), 3); sound = sound.tanh*5; + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add ); @@ -239,6 +245,7 @@ sound, pitch1 * 4 * basefreq + SinOsc.ar(basefreq/64*rate, 0, lfo*basefreq/2) + LFNoise2.ar(1,lfo*basefreq), LFNoise2.ar(0,0.1,4*resonance)); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(0.5*sound, ~dirt.numChannels, pan, env)); }).add ); @@ -261,6 +268,7 @@ sound= AY.ar( AY.freqtotone(basefreq), AY.freqtotone(pitch2*basefreq), AY.freqtotone(pitch3*basefreq), vola:va, volb:vb, volc:vc)/2; sound = tanh(sound)*2; + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add ); @@ -285,6 +293,7 @@ 2*voice-1); sound = HPF.ar(BMoog.ar(sound, ffreq, resonance, 3), 20); sound = clip(sound, -1,1) * 0.3; + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add ); @@ -340,6 +349,7 @@ SynthDef(\superhammond, {|out, sustain=1, decay=0, pan, freq, vibrato=0.5, vrate sound = 0.5 * Mix.ar( SinOsc.ar(freqs*(2*click+1), (2pi ! 9).rand, amps/amps.sum) ); sound = perc * 0.5 * SinOsc.ar(freq*percf, 2pi.rand) * XLine.ar(1,1e-6,2*decay+1) + sound; sound = sound + BAllPass.ar(sound, 1000*LFTri.kr(vrate,0,vibrato/2,1)); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add ); @@ -391,6 +401,7 @@ SynthDef(\superhoover, {|out, sustain=1, decay=0, pan, freq, accelerate=0, slide mix = BPeakEQ.ar(mix, 6000, 1, 3); mix = BPeakEQ.ar(mix, 3500, 1, 6); mix = mix.dup + CombC.ar(mix.dup, 1/200, SinOsc.kr(3, [0.5pi, 1.5pi]).range(1/300, 1/200), 0); + mix = mix * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(1.4*mix, ~dirt.numChannels, pan, env)); }).add ); @@ -409,6 +420,7 @@ SynthDef(\superzow, {|out, sustain=1, pan, accelerate, freq, decay=0, slide=1, d var sound3 = VarSaw.ar(basefreq*(-1*detune/100+1), 0, Line.ar(0,0.5,sustain*20/slide)); sound = sound - DelayN.ar(sound2,0.2, Line.ar(0,1,5*sustain/slide)/basefreq) + DelayN.ar(sound3,0.2, Line.ar(0,1,20*sustain/slide)/basefreq); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound/2, ~dirt.numChannels, pan, env)); }).add ); @@ -422,6 +434,7 @@ SynthDef(\superstatic, {|out, sustain=1, pan, freq, accelerate=0, speed=1 | freq = freq * DirtFreqScale.kr(speed, accelerate, sustain); sound = Dust.ar(freq*40) > 0.5; sound = Pulse.ar(freq*sound*4,0.5,0.5); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)) }).add ); @@ -445,6 +458,8 @@ SynthDef(\supergrind, {|out, pan, freq, sustain, accelerate, detune=0, voice=0, LocalOut.ar(LeakDC.ar(loop).tanh); loop = loop + DelayC.ar(loop, 0.2, SinOsc.ar(1, 0, 1e-3, 0.1)); loop = GVerb.ar(sin(loop + (8*trig)*4)).sin + loop; + loop = loop * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(0.3*loop, ~dirt.numChannels, pan, env)); }).add; ); @@ -467,6 +482,7 @@ SynthDef(\superprimes, {|out, pan, freq, sustain, accelerate, rate=1, detune=0, * LPF.ar(Decay.ar(trig, (primes+3)*sustain/10), voice.linexp(0,2,30,18000)); sound = GVerb.ar(sound.softclip, 10*voice.linexp(0,5,1,0.01), 10).tanh; sound = SplayAz.ar(primes.size, sound.flat, center:LFNoise2.kr(sustain).range(0,primes.size-1)); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add; ); @@ -488,6 +504,7 @@ SynthDef(\superwavemechanics, {|out, pan, freq, sustain, accelerate, detune=0, v d = Rand(1.6*i - detune, 1.7*i + detune).round(0.25); sound = Resonz.ar(WhiteNoise.ar(0.5), freq * r * d, 0.01 + voice.linexp(0,1,1e-3,1)); sound = HPF.ar(Limiter.ar(55 * GVerb.ar(sound, resonance.linexp(0,1,99,0.1),10) ), 30).sanitize; + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound.flat, ~dirt.numChannels, pan, env)); }).add; ); @@ -503,6 +520,7 @@ SynthDef(\supertron, {|out, pan, freq, sustain, voice, detune, accelerate, speed sound = LocalIn.ar(1); sound = Mix.ar( Pulse.ar(freq+[1+detune,-1-detune], RLPF.ar(sound, freq/6.1, 1.5).range(0,1-(voice/1.5))) ); sound = LeakDC.ar(sound); + sound = sound * StrudelUtils.synthGain; LocalOut.ar(sound); Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, aenv)) }).add; @@ -521,6 +539,7 @@ SynthDef(\superreese, {|out, pan, freq, sustain, accelerate, detune=0, voice=0, sound = RLPF.ar(sound, freq*10, 1.0/q1); sound = sound.clip2(1.0/5.0)* 5.0; sound = 0.35*RLPF.ar(sound, freq*20, 1.0/q2); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add; ); @@ -634,6 +653,7 @@ SynthDef(\superfm, { var sound = FM7.ar(ctls, presets[5]) * amps; sound = Mix.ar(sound) * (-15.dbamp); + sound = sound * StrudelUtils.synthGain; Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env)); }).add; ); diff --git a/library/strudel-synths.scd b/library/strudel-synths.scd new file mode 100644 index 00000000..1ec6e496 --- /dev/null +++ b/library/strudel-synths.scd @@ -0,0 +1,451 @@ +( + var sawfunc, supersawfunc, pulsefunc, superpulsefunc, calculateCutoff; + var numChannels = ~dirt.numChannels; + + supersawfunc = {|voices| + {|out = 0, rate=1, decay=0, sustain=1, pan= 0, accelerate=0, freq =130.8, speed=1, spread = 0.5, detune = 0.15| + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var sound; + var panspread = spread; + var freqspread = detune; + + if (voices < 2) { + panspread = 0; + }; + + sound = Splay.arFill(voices, {|i| + SawDPW.ar(basefreq * pow(2, StrudelUtils.getUnisonDetune(voices, freqspread, i) / 12), + iphase: TRand.kr(-1, 1, Impulse.kr(0)) + ) + },spread: panspread, level: 1, center: 0); + sound = sound * 1.24; + sound = sound * StrudelUtils.synthGain; + + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + } + }; + + (1..10).do{|voices| + var name = "supersaw" ++ voices; + SynthDef.new(name, supersawfunc.value(voices)).add; + }; + + ~dirt.soundLibrary.addSynth(\supersaw, + (playInside: { |e| + ( + instrument: "supersaw" ++ clip(~unison.value ? 3, 1, 10), + out: ~out, + freq: ~freq, + speed: ~speed, + accelerate: ~accelerate, + amp: ~amp, + detune: ~detune.value ? ~n.value ? 0.18, + spread: ~spread ? 0.6, + group: ~synthGroup + ).play + }) + ); + + superpulsefunc = {|voices| + {|out = 0, rate=1, decay=0, sustain=1, pan= 0, accelerate=0, freq =130.8, speed=1, spread = 0.5, detune = 0.15, z1=0.5, z2=0, z3=0.65, cycle, cps| + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var sound; + var panspread = spread; + var freqspread = detune; + var width = z1; + var modspeed = z2; + var moddepth = z3; + var phaseoffset = (((cycle / cps) * modspeed) % 1); + var mod = LFTri.ar(modspeed, iphase: phaseoffset).range(-0.5,0.5) * moddepth; + width = clip(mod + width,0.01, 0.99); + + if (voices < 2) { + panspread = 0; + }; + sound = Splay.arFill(voices, {|i| + LFPulse.ar( + basefreq * pow(2, StrudelUtils.getUnisonDetune(voices, freqspread, i) / 12), + iphase: TRand.kr(0, 1, Impulse.kr(0)), + width:width; + ) + },spread: panspread, level: 1, center: 0); + sound = HPF.ar(sound, 20); + sound = sound * StrudelUtils.synthGain; + + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + } + }; + + + (1..10).do{|voices| + var name = "superpulse" ++ voices; + SynthDef.new(name, superpulsefunc.value(voices)).add; + }; + + ~dirt.soundLibrary.addSynth(\superpulse, + (playInside: { |e| + ( + instrument: "superpulse" ++ clip(~unison.value ? 5, 1, 10), + out: ~out, + freq: ~freq, + speed: ~speed, + accelerate: ~accelerate, + amp: ~amp, + cycle: ~cycle, + cps: ~cps, + z1: ~z1 ? ~n ? 0.5, + z2: ~z2, + z3: ~z3 ? 0.65, + detune: ~detune.value ? ~n.value ? 0.12, + spread: ~spread ? 1, + group: ~synthGroup + ).play + }) + ); + + sawfunc = { + {|out, rate=1, decay=0, sustain=1, pan, accelerate, freq = 130.8, speed=1| + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var sound = SawDPW.ar(freq: basefreq) * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + } + }; + + SynthDef(\sawtooth, sawfunc.value()).add; + + + + SynthDef(\pulse, {|out, sustain=1, pan, accelerate, freq=130.8, speed=1, z1=0.5, z2=0, z3=0.65, cycle, cps| + var sound; + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var width = z1; + var modspeed = z2; + var moddepth = z3; + var phaseoffset = (((cycle / cps) * modspeed) % 1) * 4; + var mod = LFTri.ar(modspeed, iphase: phaseoffset).range(-0.5,0.5) * moddepth; + width = clip(mod + width,0.01,0.99); + sound = Pulse.ar(basefreq, width: width) * 0.8; + sound = sound * StrudelUtils.synthGain; + + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + + + + + SynthDef(\sine, {|out, rate=1, sustain=1, pan, accelerate, freq=130.8, speed=1| + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var sound = SinOsc.ar(basefreq); + sound = sound * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + + SynthDef(\triangle, {|out, rate=1, sustain=1, pan, accelerate, freq = 130.8, speed=1| + var basefreq = freq * DirtFreqScale.kr(speed, accelerate, sustain); + var sound = LFTri.ar(basefreq); + sound = sound * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + + SynthDef(\white, {|out, pan| + var sound = WhiteNoise.ar(mul:0.5); + sound = sound * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + SynthDef(\brown, {|out, pan| + var sound = BrownNoise.ar(mul:0.5); + sound = sound * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + SynthDef(\pink, {|out, pan| + var sound = PinkNoise.ar(mul:0.5); + sound = sound * StrudelUtils.synthGain; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + + + // PERCUSSION + // gabber kick + SynthDef(\sbd2, { |out, pan, freq = 440, z1 = 0, z2 = 0, z3 = 0, z4 = 0| + var sound; + var dec = 0.15 + z1; + var pitchenv = Env.perc(0.001, dec, curve: -3).ar; + var volenv = Env.perc(0.001, dec, curve: 2).ar; + var volratio = clip(z2 + 0.2, 0, 1); + var knockdecay = 0.01 + (z3 * 0.1); + var knockenv = Env.perc(0.001, knockdecay, -4).ar; + var fmosc = SinOsc.ar(freq *3, 0, freq *3) ; + var knock = SinOsc.ar(freq + fmosc)* knockenv; + + volenv = (volenv * volratio) + (1 - volratio); + freq = freq * (pitchenv * clip(48 - (z4 * 48), 1, 60)).midiratio; + sound = Saw.ar(freq); + sound = sound + knock; + sound = (sound * 100).tanh + ((sound.sign - sound) * -8.dbamp); + sound = sound * volenv * 0.3; + + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan)); + }).add; + + + //EFFECTS + + SynthDef("gain" ++ numChannels, { |out, gain=1.0 | + var signal = In.ar(out, numChannels) * StrudelUtils.gainCurve(gain); + ReplaceOut.ar(out, signal) + }, [\ir, \kr, \kr]).add; + + ~dirt.addModule('postgain', + { |dirtEvent| + dirtEvent.sendSynth("gain" ++ ~numChannels, + [ + gain: ~postgain, + out: ~out + ]) + + }, { ~postgain.notNil }); + + SynthDef("strudel_lpf" ++ numChannels, { |out, cutoff = 440, resonance = 0, attack, hold, decay, envamt = 0, anchor = 0, release, holdtime | + var signal = In.ar(out, numChannels); + cutoff = StrudelUtils.calculateCutoff(cutoff,anchor, envamt, hold, holdtime, attack, decay, release, cutmax: SampleRate.ir / 2); + signal = SVF.ar(signal, cutoff: cutoff, res: resonance); + ReplaceOut.ar(out, signal) + }, [\ir, \kr, \kr]).add; + + ~dirt.addModule('lpf', + { |dirtEvent| + dirtEvent.sendSynth("strudel_lpf" ++ ~numChannels, + [ + cutoff: ~cutoff, + anchor: ~anchor, + resonance: ~resonance, + envamt: ~lpenv, + attack: {~lpattack.value ? ~attack.value}, + decay: {~lpdecay.value ? ~decay.value}, + hold: { ~lpsustain.value ? ~hold.value ? ~lpdecay.isNil}, + release: {~lprelease.value ? ~release.value}, + holdtime: ~sustain, + out: ~out + ]) + + }, { ~cutoff.notNil }); + + SynthDef("strudel_hpf" ++ numChannels, { |out, cutoff = 440, resonance = 0, attack, hold, decay, envamt = 0, anchor = 0, release, holdtime| + var signal = In.ar(out, numChannels); + cutoff = StrudelUtils.calculateCutoff(cutoff,anchor, envamt, hold, holdtime, attack, decay, release, cutmax: SampleRate.ir / 2); + signal = RHPF.ar(signal, cutoff.abs.clip(20, SampleRate.ir / 2), 1 - resonance); + ReplaceOut.ar(out, signal) + }, [\ir, \kr, \kr]).add; + + ~dirt.addModule('hpf', + { |dirtEvent| + dirtEvent.sendSynth("strudel_hpf" ++ ~numChannels, + [ + cutoff: ~hcutoff, + anchor: ~anchor, + resonance: ~hresonance, + envamt: ~hpenv, + attack: {~hpattack.value ? ~attack.value}, + decay: {~hpdecay.value ? ~decay.value}, + hold: { ~hpsustain.value ? ~hold.value ? ~hpdecay.isNil}, + release: {~hprelease.value ? ~release.value}, + holdtime: ~sustain, + out: ~out + ]) + + }, { ~hcutoff.notNil }); + + SynthDef("strudel_bpf" ++ numChannels, { |out, cutoff=440, resonance=0, attack, hold, decay, envamt=0, anchor=0, release, holdtime| + var signal = In.ar(out, numChannels); + cutoff = StrudelUtils.calculateCutoff(cutoff,anchor, envamt, hold, holdtime, attack, decay, release, cutmax: SampleRate.ir / 2); + signal = BPF.ar(signal, cutoff.abs.clip(20, SampleRate.ir / 2), resonance.abs.clip(0.05, 1)); + ReplaceOut.ar(out, signal) + }, [\ir, \kr, \kr]).add; + + ~dirt.addModule('bpf', + { |dirtEvent| + dirtEvent.sendSynth("strudel_bpf" ++ ~numChannels, + [ + cutoff: ~bandf, + anchor: ~anchor, + resonance: ~bandq, + envamt: ~bpenv, + attack: {~bpattack.value ? ~attack.value}, + decay: {~bpdecay.value ? ~decay.value}, + hold: { ~bpsustain.value ? ~hold.value ? ~bpdecay.isNil}, + release: {~bprelease.value ? ~release.value}, + holdtime: ~sustain, + out: ~out + ]) + + }, { ~bandf.notNil }); + //emulation of juno 60 chorus + SynthDef("strudel_chorus" ++ numChannels, { |out, mix, depth, speed| + var input = In.ar(out, numChannels); + var l = input[0]; + var r = input[1] ? l; + var signal; + var d = depth * 0.01; + var minD = 0.00166; + var mod = LFTri.kr(speed).range(-1, 1) * d; + var rmod = mod * -1; + + mix = (mix * 2) - 1; + l = DelayC.ar(l, maxDelayTime: 1, delaytime: minD + d + mod ); + r = DelayC.ar(r, maxDelayTime: 1, delaytime: minD + d + rmod ); + + signal = Splay.ar([l, r],spread: 1, level: 1, center: 0); + signal = LPF.ar(signal, 18000); + + signal = XFade2.ar(input, signal, mix); + ReplaceOut.ar(out, signal); + }, [\ir, \kr, \kr]).add; + + ~dirt.addModule('chorus', + { |dirtEvent| + dirtEvent.sendSynth("strudel_chorus" ++ ~numChannels, + [ + mix: ~chorus, + depth: {~chorusdepth.value ? 0.1845}, + speed: {~chorusspeed.value ? 0.863}, + out: ~out + ]) + + }, { ~chorus.notNil }); + + + SynthDef("strudel_distort" ++ numChannels, { |out, shape = 0, postgain = 1| + + var signal = In.ar(out, numChannels), amp = 1; + + shape = exp(shape) - 1; + + // shape = min(shape, 1.0 - 4e-10); // avoid division by zero + postgain = clip(postgain, 0.001, 1); + postgain = StrudelUtils.gainCurve(postgain); + + signal = ((1 + shape) * signal / (1 + (shape * abs(signal)))) * postgain; + ReplaceOut.ar(out, signal * amp) + }, [\ir, \kr]).add; + + ~dirt.addModule('distort', + { |dirtEvent| + dirtEvent.sendSynth('strudel_distort' ++ ~numChannels, + [ + shape: ~distort, + postgain: ~distortvol ? 1, + out: ~out + ]) + }, { ~distort.notNil }); + + SynthDef("strudel_phaser" ++ numChannels, { |out, phaserrate, phaserdepth = 0.5, phasercenter, phasersweep, phaserstages, phaseoffset| + var signal = In.ar(out, numChannels); + var modgain = phasersweep; + var fOffset = 0; + var cutoff; + var mod = LFTri.kr(phaserrate, iphase: phaseoffset).range(-1, 1); + var modsignal = signal; + // var fade = (2 * phaserdepth) -1; + + mod = (mod * modgain) + phasercenter; + + + + (1..3).do{|i| + // if (i <= phaserstages){ + cutoff = clip(mod + fOffset, 20, SampleRate.ir / 2 ); + modsignal = SVF.ar( + modsignal, + cutoff: cutoff, + lowpass:0, + res: 1 - phaserdepth, + notch: 1, + ); + fOffset = fOffset + 282; + // }; + + }; + + ReplaceOut.ar(out, modsignal); + }, [\ir, \kr]).add; + + + + ~dirt.addModule('phaser', + { |dirtEvent| + dirtEvent.sendSynth('strudel_phaser' ++ ~numChannels, + [ + phaserrate: ~phaserrate, + phaserdepth: ~phaserdepth ? 0.75, + phasercenter: ~phasercenter ? 2700, + phasersweep: ~phasersweep ? 2000, + phaserstages: ~phaserstages ? 2, + phaseoffset: (((~cycle ? 1 / ~cps ? 0.5) * ~phaserrate) % 1) * 4, + out: ~out + ]) + }, { ~phaserrate.notNil }); + + + SynthDef("strudel_compressor" ++ numChannels, { |out, threshold = 0, ratio = 0.25, knee = 8, attack = 0.1, release = 0.1| + var signal = In.ar(out, numChannels), amp = 1; + threshold = clip(threshold, 0.01, 100); + + signal = Compander.ar(signal, signal, + thresh: threshold, + slopeBelow: knee, + slopeAbove: ratio, + clampTime: attack, + relaxTime: release + ); + ReplaceOut.ar(out, signal * amp) + }, [\ir, \kr]).add; + + ~dirt.addModule('compressor', + { |dirtEvent| + dirtEvent.sendSynth('strudel_compressor' ++ ~numChannels, + [ + threshold: ~compressor ? -3, + ratio: ~compressorRatio ? 0.25, + knee: ~compressorKnee ? 0.8, + attack: ~compressorAttack ? 0.01, + release: ~compressorRelease ? 0.01, + out: ~out + ]) + }, { ~compressor.notNil }); + + SynthDef("strudel_envelope" ++ numChannels, { |out, attack, decay, hold, holdtime = 0, release, amp=0.3, curve | + var signal = In.ar(out, numChannels); + var volenv = EnvGen.ar( + Env.adsr( + attackTime: attack.max(0.001), + decayTime: decay, + releaseTime: release, + sustainLevel: hold, + peakLevel: 1, + curve: curve + ), + gate: Trig.ar(1, holdtime) + ); + signal = signal * volenv * amp; + ReplaceOut.ar(out, signal); + }, [\ir, \ir, \ir, \ir, \ir]).add; + + ~dirt.addModule('envelope', + { |dirtEvent| + dirtEvent.sendSynth('strudel_envelope' ++ ~numChannels, + [ + attack: ~attack, + decay: ~decay, + hold: { ~hold.value ? ~decay.isNil }, + holdtime: ~sustain, + amp: ~amp, + release: ~release, + curve: {~curve.value ? -2}, + out: ~out + ]) + }, { ~attack.notNil or: { ~release.notNil } or: { ~decay.notNil } or: { ~hold.notNil }}); + + ~dirt.orderModules(['sound','supersaw','superpulse','dirt_gate','lpf','bpf','hpf','shape','crush','coarse','phaser','compressor','chorus','distort','envelope','postgain']); + +) + diff --git a/scripts/internal-routing-test.scd b/scripts/internal-routing-test.scd index 53c6de98..eefb2c97 100644 --- a/scripts/internal-routing-test.scd +++ b/scripts/internal-routing-test.scd @@ -43,7 +43,7 @@ Pdef(\x, \modfreq, Pseq([2, Prand([3, 7], 1), 0.3, 0.4], inf), \rq, Pwhite().linexp(0, 1, 0.05, 0.3), \dur, 1, //1/Pseq([1, 3, 2, 1], inf), - \legato, 2, + \clip, 2, \pan, 0, //Pseq([0, 1], inf) ) ]) diff --git a/scripts/tidal-midi.scd b/scripts/tidal-midi.scd index 3edc3890..8a7e807e 100644 --- a/scripts/tidal-midi.scd +++ b/scripts/tidal-midi.scd @@ -45,7 +45,7 @@ d1 $ ccn "28*16" # ccv 127 # s "midi" # midichan 9 // note: parameter names may change in the future! // In supercollider terms, the following midicmds and their parameters are supported -// (the usual note/freq and legato/sustain parameters are taken into account) +// (the usual note/freq and clip/sustain parameters are taken into account) polyTouch: midichan, midinote, polyTouch program: midichan, progNum diff --git a/synths/core-modules.scd b/synths/core-modules.scd index add1139a..9e05fc4c 100644 --- a/synths/core-modules.scd +++ b/synths/core-modules.scd @@ -45,6 +45,7 @@ this may be refacored later. speed: ~speed, freq: ~freq * ~metaDataTuneRatio.value, endSpeed: ~endSpeed, + totalDuration: ~totalDuration, begin: ~begin, end: ~end, pan: ~pan, @@ -104,27 +105,27 @@ this may be refacored later. }, { ~shape.notNil }); -~dirt.addModule('hpf', - { |dirtEvent| - dirtEvent.sendSynth("dirt_hpf" ++ ~numChannels, - [ - hcutoff: ~hcutoff, - hresonance: ~hresonance, - out: ~out - ]) +// ~dirt.addModule('hpf', +// { |dirtEvent| +// dirtEvent.sendSynth("dirt_hpf" ++ ~numChannels, +// [ +// hcutoff: ~hcutoff, +// hresonance: ~hresonance, +// out: ~out +// ]) -}, { ~hcutoff.notNil }); +// }, { ~hcutoff.notNil }); -~dirt.addModule('bpf', - { |dirtEvent| - dirtEvent.sendSynth("dirt_bpf" ++ ~numChannels, - [ - bandqf: ~bandf, - bandq: ~bandq, - out: ~out - ]) +// ~dirt.addModule('bpf', +// { |dirtEvent| +// dirtEvent.sendSynth("dirt_bpf" ++ ~numChannels, +// [ +// bandqf: ~bandf, +// bandq: ~bandq, +// out: ~out +// ]) -}, { ~bandf.notNil }); +// }, { ~bandf.notNil }); ~dirt.addModule('crush', { |dirtEvent| @@ -147,16 +148,22 @@ this may be refacored later. }, { ~coarse.notNil and: { ~coarse > 1 } }); // coarse == 1 => full rate -~dirt.addModule('lpf', - { |dirtEvent| - dirtEvent.sendSynth("dirt_lpf" ++ ~numChannels, - [ - cutoff: ~cutoff, - resonance: ~resonance, - out: ~out - ]) - -}, { ~cutoff.notNil }); +// ~dirt.addModule('lpf', +// { |dirtEvent| +// dirtEvent.sendSynth("dirt_lpf" ++ ~numChannels, +// [ +// cutoff: ~cutoff, +// resonance: ~resonance, +// envamt: ~lpenv, +// attack: {~lpattack.value ? ~attack.value}, +// decay: {~lpdecay.value ? ~decay.value}, +// hold: { ~lpsustain.value ? ~hold.value ? ~lpdecay.isNil}, +// release: {~lprelease.value ? ~release.value}, +// holdtime: ~sustain, +// out: ~out +// ]) + +// }, { ~cutoff.notNil }); ~dirt.addModule('pshift', { |dirtEvent| @@ -169,17 +176,19 @@ this may be refacored later. ]) }, { ~psrate.notNil }); -~dirt.addModule('envelope', - { |dirtEvent| - dirtEvent.sendSynth('dirt_envelope' ++ ~numChannels, - [ - attack: ~attack, - hold: ~hold, - release: ~release, - curve: ~curve, - out: ~out - ]) -}, { ~attack.notNil or: { ~release.notNil }}); +// ~dirt.addModule('envelope', +// { |dirtEvent| +// dirtEvent.sendSynth('dirt_envelope' ++ ~numChannels, +// [ +// attack: ~attack, +// decay: ~decay, +// hold: { ~hold.value ? ~decay.isNil }, +// holdtime: ~sustain, +// release: ~release, +// curve: {~curve.value ? -2}, +// out: ~out +// ]) +// }, { ~attack.notNil or: { ~release.notNil } or: { ~decay.notNil } or: { ~hold.notNil }}); ~dirt.addModule('grenvelo', { |dirtEvent| @@ -205,14 +214,14 @@ this may be refacored later. }, { ~tremolorate.notNil }); // Phaser audio DSP effect declaration -~dirt.addModule('phaser', - { |dirtEvent| - dirtEvent.sendSynth('dirt_phaser' ++ ~numChannels, - [ - phaserrate: ~phaserrate, - phaserdepth: ~phaserdepth, - out: ~out - ]) -}, { ~phaserrate.notNil }); +// ~dirt.addModule('phaser', +// { |dirtEvent| +// dirtEvent.sendSynth('dirt_phaser' ++ ~numChannels, +// [ +// phaserrate: ~phaserrate, +// phaserdepth: ~phaserdepth, +// out: ~out +// ]) +// }, { ~phaserrate.notNil }); ); diff --git a/synths/core-synths-global.scd b/synths/core-synths-global.scd index bc32075c..762ffe97 100644 --- a/synths/core-synths-global.scd +++ b/synths/core-synths-global.scd @@ -23,19 +23,20 @@ CORE SYNTHDEFS FOR DIRT */ - SynthDef("dirt_monitor" ++ numChannels, { |dryBus, effectBus, outBus, gate = 1, limitertype = 1| - var drySignal = In.ar(dryBus, numChannels); - var wetSignal = In.ar(effectBus, numChannels); + SynthDef("dirt_monitor" ++ numChannels, { |dryBus, effectBus, outBus, gate = 1, limitertype = 1, outgain = 1, dry = 1, wet = 1| + var drySignal = In.ar(dryBus, numChannels) * StrudelUtils.gainCurve(dry); + var wetSignal = In.ar(effectBus, numChannels) * StrudelUtils.gainCurve(wet); //var signal = XFade2.ar(wetSignal, drySignal, dry * 2 - 1); var signal = wetSignal + drySignal; var post = if(SuperDirt.postBadValues) { 2 } { 0 }; - signal = Select.ar(CheckBadValues.ar(signal, post: post) > 0, [signal, DC.ar(0)]); + //remove any low frequency artifacts that can slam the limiter + signal = HPF.ar(signal, 16) * StrudelUtils.gainCurve(outgain); signal = Select.ar(limitertype, [ signal, - Limiter.ar(signal), + Limiter.ar(signal, 1.0, 0.01), softclip(signal * 0.5) * 2 ] ); @@ -43,6 +44,7 @@ CORE SYNTHDEFS FOR DIRT DirtPause.ar(signal, graceTime:4); signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2); + Out.ar(outBus, signal) }, [\ir, \ir, \kr, \kr, \kr]).add; @@ -71,62 +73,45 @@ CORE SYNTHDEFS FOR DIRT dryBus and effectBus have \ir as rates (they shouldn't change at runtime) */ - - - - if(\SwitchDelay.asClass.notNil) { - - SynthDef("dirt_delay" ++ numChannels, { |dryBus, effectBus, gate = 1, delaytime, delayfeedback, delaySend = 1, delayAmp = 1, lock = 0, cps = 1| + SynthDef("dirt_shimmer" ++ numChannels, { |dryBus, effectBus, gate = 1, delaytime, delayfeedback, shimmer = 0, lock = 1, cps = 1| var signal; - var input = In.ar(dryBus, numChannels); + var input = In.ar(dryBus, numChannels) * StrudelUtils.gainCurve(shimmer.lag(0.01)); var maxDelayTime = 4; - - input = input * delaySend.lag(LFNoise1.kr(1).range(0.01, 0.02)); // regulate input - - delayfeedback = delayfeedback.max(0); + var delta = 0.375 * 2; delaytime = delaytime * if(lock, reciprocal(cps), 1); - delaytime = delaytime.clip(0, maxDelayTime); // just to be sure - // from sc3-plugins - signal = \SwitchDelay.asClass.ar(input, 1, 1, delaytime, delayfeedback, maxDelayTime); - + signal = input + (LocalIn.ar(2) * delayfeedback); + signal = PitchShift.ar(signal, windowSize: delta, pitchRatio: 2, timeDispersion: delta / 2); + signal = LPF.ar(signal, 10000); + signal = HPF.ar(signal, 120); + signal = DelayC.ar(signal, maxDelayTime, delaytime ); + LocalOut.ar(signal); + + signal = Limiter.ar(signal, 0.5, 0.001); signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2); - signal = signal * delayAmp.lag(0.01); - DirtPause.ar(signal, graceTime:4); - Out.ar(effectBus, signal); + }, [\ir, \ir]).add; - }, [\ir, \ir]).add; - } { - "\n\n ---- SC3-Plugins not found. This is not a problem." - "Note that we are using a comb delay, which may not sound the same as SwitchDelay from the plugins".postln; - SynthDef("dirt_delay" ++ numChannels, { |dryBus, effectBus, gate = 1, delaytime, delayfeedback, delayAmp = 1, lock = 0, cps = 1| - var signal = In.ar(dryBus, numChannels); - var maxDelayTime = 4; - var decayTime; - delayfeedback = delayfeedback.clip(0, 0.99); + SynthDef("dirt_delay" ++ numChannels, { |dryBus, effectBus, gate = 1, delaytime, delayfeedback, delaySend = 1, delayAmp = 1, lock = 1, cps = 1| + var signal; + var input = In.ar(dryBus, numChannels) * StrudelUtils.gainCurve(delayAmp.lag(0.01)); + var maxDelayTime = 4; delaytime = delaytime * if(lock, reciprocal(cps), 1); - delaytime = delaytime.clip(0, maxDelayTime); // just to be sure - decayTime = log2(-60.dbamp) / log2(delayfeedback) * delaytime; - decayTime = decayTime.clip(0, 20); - - signal = CombL.ar(signal, maxDelayTime, delaytime.lag(1), decayTime); - - signal = LeakDC.ar(signal) * delayAmp.lag(0.01) * EnvGen.kr(Env.asr, gate, doneAction:2); - + signal = input + (LocalIn.ar(2) * delayfeedback); + signal = DelayC.ar(LPF.ar(signal, 10000), maxDelayTime, delaytime ); + LocalOut.ar(signal); + signal = Limiter.ar(signal, 0.5, 0.001); + signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2); DirtPause.ar(signal, graceTime:4); - Out.ar(effectBus, signal); - }, [\ir, \ir]).add; - }; - + }, [\ir, \ir]).add; // thanks to Jost Muxfeld and James McCartney // note that "size" is not room size, just the feed level into the room - SynthDef("dirt_reverb" ++ numChannels, { |dryBus, effectBus, gate = 1, room = 0, size = 0.1, dry = 0| + SynthDef("dirt_reverb" ++ numChannels, { |dryBus, effectBus, gate = 1, room = 0, size = 0.1| var in, snd, loop, depth; in = In.ar(dryBus, numChannels).asArray.sum; @@ -136,7 +121,7 @@ CORE SYNTHDEFS FOR DIRT 4.do { in = AllpassN.ar(in, 0.03, { Rand(0.005, 0.02) }.dup(numChannels), 1) }; depth = size.lag(0.02).linexp(0, 1, 0.01, 0.98); // change depth between 0.1 and 0.98 - loop = LocalIn.ar(numChannels) * { depth + Rand(0, 0.05) }.dup(numChannels); + loop = in + LocalIn.ar(numChannels) * { depth + Rand(0, 0.05) }.dup(numChannels); loop = OnePole.ar(loop, 0.5); // 0-1 loop = AllpassN.ar(loop, 0.05, { Rand(0.01, 0.05) }.dup(numChannels), 2); @@ -144,13 +129,13 @@ CORE SYNTHDEFS FOR DIRT loop = DelayN.ar(loop, 0.3, [0.19, 0.26] + { Rand(-0.003, 0.003) }.dup(2)); loop = AllpassN.ar(loop, 0.05, { Rand(0.03, 0.15) }.dup(numChannels), 2); - loop = loop + in; + // loop = loop + in; loop = LeakDC.ar(loop); LocalOut.ar(loop); snd = loop; - snd = snd * (1 - dry).lag(LFNoise1.kr(1).range(0.01, 0.02)); + snd = snd * (1).lag(LFNoise1.kr(1).range(0.01, 0.02)); DirtPause.ar(snd, graceTime:4); diff --git a/synths/core-synths.scd b/synths/core-synths.scd index 3f37799a..67bad174 100644 --- a/synths/core-synths.scd +++ b/synths/core-synths.scd @@ -11,25 +11,27 @@ Their name and parameter names shouldn't be changed. Parameter names can be adde live coding them requires that you have your SuperDirt instance in an environment variable called ~dirt. */ + ( { var numChannels = ~dirt.numChannels; - - - + // write variants for different sample buffer sizes (1..SuperDirt.maxSampleNumChannels).do { |sampleNumChannels| var name = format("dirt_sample_%_%", sampleNumChannels, numChannels); - SynthDef(name, { |out, bufnum, sustain = 1, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0| + SynthDef(name, { |out, bufnum, totalDuration = 0, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0| var sound, rate, phase, sawrate, numFrames; + // playback speed - rate = Line.kr(speed, endSpeed, sustain) * (freq / 60.midicps); + + rate = Line.kr(speed, endSpeed, totalDuration) * (freq / StrudelUtils.baseNote().midicps); + // sample phase // BufSampleRate adjusts the rate if the sound file doesn't have the same rate as the soundcard @@ -46,6 +48,7 @@ live coding them requires that you have your SuperDirt instance in an environmen loop: 0, interpolation: 4 // cubic interpolation ); + sound = sound * StrudelUtils.sampleGain(); sound = DirtPan.ar(sound, numChannels, pan); @@ -62,13 +65,15 @@ live coding them requires that you have your SuperDirt instance in an environmen var name = format("dirt_sample_long_%_%", sampleNumChannels, numChannels); - SynthDef(name, { |out, bufnum, sustain = 1, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0| + SynthDef(name, { |out, bufnum, totalDuration = 1, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0| var sound, rate, env, startPos, numFrames; // playback speed - rate = Line.kr(speed, endSpeed, sustain) * (freq / 60.midicps); + rate = Line.kr(speed, endSpeed, totalDuration) * (freq / StrudelUtils.baseNote().midicps); + + // sample phase // BufSampleRate adjusts the rate if the sound file doesn't have the same rate as the soundcard //phase = Sweep.ar(1, rate * BufSampleRate.ir(bufnum)) + (BufFrames.ir(bufnum) * begin); @@ -88,9 +93,10 @@ live coding them requires that you have your SuperDirt instance in an environmen loop: 0 ); - env = EnvGen.kr(Env.linen(0, sustain, 0)); // todo: check if control rate smoothens (shouldn't) + env = EnvGen.kr(Env.linen(0, totalDuration, 0)); // todo: check if control rate smoothens (shouldn't) sound = sound * env; + sound = sound * StrudelUtils.sampleGain(); sound = DirtPan.ar(sound, numChannels, pan); @@ -105,13 +111,15 @@ live coding them requires that you have your SuperDirt instance in an environmen var name = format("dirt_stretchsample_%_%", sampleNumChannels, numChannels); - SynthDef(name, { |out, bufnum, sustain = 1, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0, timescale = 1, timescalewin = 1| + SynthDef(name, { |out, bufnum, totalDuration, begin = 0, end = 1, speed = 1, endSpeed = 1, freq = 440, pan = 0, timescale = 1, timescalewin = 1| var sound, rate, phase, sawrate, numFrames, index, windowIndex, window, timescaleStep; var sound0, sound1, windowSize, nSteps; // playback speed - rate = Line.kr(speed, endSpeed, sustain) * (freq / 60.midicps); + rate = Line.kr(speed, endSpeed, totalDuration) * (freq / StrudelUtils.baseNote().midicps); + + // sample phase // BufSampleRate adjusts the rate if the sound file doesn't have the same rate as the soundcard @@ -155,6 +163,7 @@ live coding them requires that you have your SuperDirt instance in an environmen interpolation: 4 // cubic interpolation ); sound = (sound0 + sound1) / window.sum; + sound = sound * StrudelUtils.sampleGain(); sound = DirtPan.ar(sound, numChannels, pan); @@ -174,12 +183,16 @@ live coding them requires that you have your SuperDirt instance in an environmen // the monitor does the mixing and zeroing of the busses for each sample grain // so that they can all play in one bus - SynthDef("dirt_gate" ++ numChannels, { |out, in, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, amp = 1, gain = 1, overgain = 0| + SynthDef("dirt_gate" ++ numChannels, { |out, in, totalDuration = 0, fadeInTime = 0.001, fadeTime = 0.001, gain = 1, overgain = 0| var signal = In.ar(in, numChannels); // doneAction: 14: free surrounding group and all nodes - var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \sin), doneAction: 14); - amp = amp * pow(gain.min(2) + overgain, 4); - signal = signal * env * amp * DirtGateCutGroup.ar(fadeTime, doneAction: 14); + var holdtime = totalDuration - (fadeInTime + fadeTime); + + var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, holdtime, fadeTime], \sin), doneAction: 14); + + // var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain + release, fadeTime], \sin), doneAction: 14); + gain = StrudelUtils.gainCurve(gain + overgain); + signal = signal * env * gain * DirtGateCutGroup.ar(fadeTime, doneAction: 14); // this takes the signal and offsets it so it matches precisely onto the sample // as scheduled within one block (a synth is always started on the block bondary) OffsetOut.ar(out, signal); @@ -193,9 +206,9 @@ live coding them requires that you have your SuperDirt instance in an environmen */ - SynthDef("dirt_out" ++ numChannels, { |out, to, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, through = 0, amp = 1| + SynthDef("dirt_out" ++ numChannels, { |out, to, totalDuration, fadeInTime = 0.001, fadeTime = 0.001, through = 0, amp = 1| var signal = In.ar(out, numChannels); - var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \sin)); + var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, totalDuration - (fadeInTime + fadeTime), fadeTime], \sin)); Out.ar(to, signal * env * amp); ReplaceOut.ar(out, signal * through); }, [\ir, \ir, \ir, \ir, \ir, \ir, \kr]).add; // amp can be modulated @@ -264,15 +277,27 @@ live coding them requires that you have your SuperDirt instance in an environmen ReplaceOut.ar(out, signal * amp) }, [\ir, \kr]).add; - SynthDef("dirt_lpf" ++ numChannels, { |out, cutoff = 440, resonance = 0| + SynthDef("dirt_lpf" ++ numChannels, { |out, cutoff = 440, resonance = 0, attack, hold, decay, envamt = 0, anchor = 0, release, holdtime | var signal = In.ar(out, numChannels); - signal = RLPF.ar(signal, cutoff.abs.clip(20, SampleRate.ir / 2), resonance.linexp(0, 1, 1, 0.001)); + cutoff = StrudelUtils.calculateCutoff(cutoff,anchor, envamt, hold, holdtime, attack, decay, release, cutmax: SampleRate.ir / 2); + signal = IIRFilter.ar(signal, cutoff, resonance); ReplaceOut.ar(out, signal) }, [\ir, \kr, \kr]).add; - SynthDef("dirt_envelope" ++ numChannels, { |out, attack = 0, hold = 0, release = inf, curve = -3 | + SynthDef("dirt_envelope" ++ numChannels, { |out, attack, decay, hold, holdtime = 0, release, curve | var signal = In.ar(out, numChannels); - signal = signal * EnvGen.ar(Env.linen(attack, hold, release, 1, curve: curve)); + var volenv = EnvGen.ar( + Env.adsr( + attackTime: attack, + decayTime: decay, + releaseTime: release, + sustainLevel: hold, + peakLevel: 1, + curve: curve + ), + gate: Trig.ar(1, holdtime) + ); + signal = signal * volenv; ReplaceOut.ar(out, signal); }, [\ir, \ir, \ir, \ir, \ir]).add; diff --git a/synths/default-synths.scd b/synths/default-synths.scd index ba96d122..ecfaaee4 100644 --- a/synths/default-synths.scd +++ b/synths/default-synths.scd @@ -39,6 +39,22 @@ SynthDef(\psin, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, phase = Line.ar(begin, end, sustain); rate = speed + Sweep.kr(1, accelerate); sound = SinOsc.ar(freq, SinOsc.ar(modfreq * (1..5), 0, 1 - phase * 10 * env / (1..5), 0.5pi)).sum; + + Out.ar(out, + DirtPan.ar(sound, ~dirt.numChannels, pan, env) + ) +}).add +); + +( +SynthDef(\psin, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, accelerate, offset, modfreq = 40| + var env, sound, rate, phase, amp; + amp = AmpCompA.kr(freq); + env = EnvGen.ar(Env.perc(0.002, sustain, 1, -1), doneAction:2); + phase = Line.ar(begin, end, sustain); + rate = speed + Sweep.kr(1, accelerate); + sound = SinOsc.ar(freq, SinOsc.ar(modfreq * (1..5), 0, 1 - phase * 10 * env / (1..5), 0.5pi)).sum; + Out.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env) ) diff --git a/synths/try-load-extra-synths.scd b/synths/try-load-extra-synths.scd index f80743de..7fb18b2d 100644 --- a/synths/try-load-extra-synths.scd +++ b/synths/try-load-extra-synths.scd @@ -2,5 +2,6 @@ if(\MembraneHexagon.asClass.isNil) { "Dirt could not load some synths from default-synths.scd, because sc3plugins are necessary and missing.".warn } { loadRelative("../library/default-synths-extra.scd"); + loadRelative("../library/strudel-synths.scd"); loadRelative("../library/default-effects-extra.scd"); }; diff --git a/used-parameters.scd b/used-parameters.scd index 19be9417..cc5be305 100644 --- a/used-parameters.scd +++ b/used-parameters.scd @@ -30,10 +30,11 @@ cps unit loop delta -legato +clip sustain amp gain +postgain channel pan note @@ -81,13 +82,29 @@ bandq crush coarse cutoff +lpattack +lpdecay +lpsustain +lprelease +lpenv attack +decay release hold +spread +unison +detune tremolorate tremolodepth phaserrate phaserdepth +distort +distortvol +compressor +compressorRatio +compressorKnee +compressorAttack +compressorRelease tilt plat