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