feat: classic-machine instrument emulations
CI build oscope-of / build-check (push) Has been cancelled
CI build oscope-of / build-check (push) Has been cancelled
Add faithful-ish TR-909 (kick/clap/hat/ride), TR-808 (kick/clap/ hat/cowbell), TB-303 (acid), Korg MS-20 and Roland SH-101 as extra matrix instrument choices. All note-terminating (perc+doneAction or gated ASR), Pbind-safe, with pan + reverb send; standard UGens only. Wired into ~matInstChoices and the web mirror per voice.
This commit is contained in:
@@ -133,6 +133,116 @@ SynthDef(\lp_sweep, { |out=0, amp=0.0, gate=1, pan=0, rev=0|
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
|
||||
// ===================================================================
|
||||
// Classic-machine emulations — extra matrix instrument choices.
|
||||
// All note-terminating (perc env + doneAction, or gated ASR) so they
|
||||
// are Pbind-safe; all take \pan + \rev like the lp_ voices. Standard
|
||||
// UGens only (no sc3-plugins). Tune by ear at the live gate.
|
||||
// ===================================================================
|
||||
// --- Roland TR-909 ---
|
||||
SynthDef(\tr909_kick, { |out=0, amp=0.9, pan=0, rev=0|
|
||||
var fenv = EnvGen.kr(Env([300, 54], [0.045], \exp));
|
||||
var aenv = EnvGen.kr(Env.perc(0.001, 0.42, 1, -4), doneAction: 2);
|
||||
var click = HPF.ar(WhiteNoise.ar, 700) * EnvGen.kr(Env.perc(0.0003, 0.008)) * 0.5;
|
||||
var body = SinOsc.ar(fenv) * aenv;
|
||||
var sig = Pan2.ar(((body * 1.3) + click).tanh, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr909_clap, { |out=0, amp=0.5, pan=0, rev=0|
|
||||
var env = EnvGen.ar(Env([0, 1, 0.4, 1, 0.3, 1, 0, 0.7, 0],
|
||||
[0.001, 0.009, 0.001, 0.009, 0.001, 0.009, 0.001, 0.16]), doneAction: 2);
|
||||
var sig = BPF.ar(WhiteNoise.ar, 1050, 0.75) * env * 2.2;
|
||||
sig = Pan2.ar(sig.tanh, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr909_hat, { |out=0, amp=0.3, pan=0, rev=0, dur=0.06|
|
||||
var env = EnvGen.kr(Env.perc(0.001, dur, 1, -8), doneAction: 2);
|
||||
var osc = Mix(Pulse.ar([2003, 3079, 4111, 5519, 6883, 8087] * 0.5)) * 0.15;
|
||||
var sig = HPF.ar(osc, 7000) * env;
|
||||
sig = Pan2.ar(sig, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr909_ride, { |out=0, amp=0.3, pan=0, rev=0|
|
||||
var env = EnvGen.kr(Env.perc(0.001, 0.7, 1, -5), doneAction: 2);
|
||||
var osc = Mix(Pulse.ar([1047, 1571, 2003, 3079, 4111])) * 0.1;
|
||||
var ring = Ringz.ar(Impulse.ar(0), 4200, 0.1) * 0.3;
|
||||
var sig = (HPF.ar(osc, 3000) + ring) * env;
|
||||
sig = Pan2.ar(sig, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
// --- Roland TR-808 ---
|
||||
SynthDef(\tr808_kick, { |out=0, amp=0.9, freq=52, pan=0, rev=0|
|
||||
var fenv = EnvGen.kr(Env([freq * 2.6, freq], [0.06], \exp));
|
||||
var aenv = EnvGen.kr(Env.perc(0.001, 0.95, 1, -5), doneAction: 2);
|
||||
var click = SinOsc.ar(1800) * EnvGen.kr(Env.perc(0.0003, 0.006)) * 0.25;
|
||||
var body = SinOsc.ar(fenv.clip(20, 400)) * aenv;
|
||||
var sig = Pan2.ar((body + click).tanh, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr808_clap, { |out=0, amp=0.5, pan=0, rev=0|
|
||||
var env = EnvGen.ar(Env([0, 1, 0.3, 1, 0.2, 1, 0, 0.5, 0],
|
||||
[0.001, 0.011, 0.001, 0.011, 0.001, 0.011, 0.001, 0.22]), doneAction: 2);
|
||||
var sig = BPF.ar(WhiteNoise.ar, 980, 0.9) * env * 2;
|
||||
sig = Pan2.ar(sig.tanh, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr808_hat, { |out=0, amp=0.3, pan=0, rev=0, dur=0.05|
|
||||
var env = EnvGen.kr(Env.perc(0.001, dur, 1, -8), doneAction: 2);
|
||||
var osc = Mix(Pulse.ar([2063, 3013, 4759, 5503, 6817, 8243] * 0.5)) * 0.14;
|
||||
var sig = HPF.ar(osc, 8000) * env;
|
||||
sig = Pan2.ar(sig, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
SynthDef(\tr808_cowbell, { |out=0, amp=0.4, pan=0, rev=0|
|
||||
var env = EnvGen.kr(Env.perc(0.001, 0.32, 1, -4), doneAction: 2);
|
||||
var osc = (Pulse.ar(540, 0.5) + Pulse.ar(800, 0.5)) * 0.5;
|
||||
var sig = BPF.ar(osc, 2640, 0.6) * env * 3;
|
||||
sig = Pan2.ar(sig.tanh, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
// --- Roland TB-303 (acid) : saw -> env-swept resonant LPF + drive ---
|
||||
SynthDef(\tb303, { |out=0, freq=110, amp=0.32, cutoff=500, res=0.82, fenvamt=2.6, pan=0, rev=0|
|
||||
var aenv = EnvGen.kr(Env.perc(0.004, 0.45, 1, -3), doneAction: 2);
|
||||
var fenv = EnvGen.kr(Env.perc(0.004, 0.32, 1, -4)) * fenvamt;
|
||||
var rq = res.clip(0, 1).linexp(0, 1, 1.0, 0.04);
|
||||
var cut = (cutoff * (1 + fenv)).clip(60, 6500);
|
||||
var sig = RLPF.ar(Saw.ar(freq.clip(20, 2000)), cut, rq);
|
||||
sig = (sig * 1.6).tanh * aenv;
|
||||
sig = Pan2.ar(sig, pan.clip(-1,1)) * amp;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
// --- Korg MS-20 (screaming resonant, gated lead/bass) ---
|
||||
SynthDef(\ms20, { |out=0, freq=110, amp=0.3, cutoff=1200, res=0.8, gate=1, pan=0, rev=0|
|
||||
var env = EnvGen.kr(Env.asr(0.005, 1, 0.14), gate, doneAction: 2);
|
||||
var osc = Saw.ar(freq.clip(20, 3000)) + Pulse.ar(freq.clip(20, 3000) * 1.004, 0.35);
|
||||
var rq = res.clip(0, 1).linexp(0, 1, 1.0, 0.05);
|
||||
var sig = RLPF.ar(osc, cutoff.clip(60, 8000), rq);
|
||||
sig = (sig * 2.2).tanh;
|
||||
sig = Pan2.ar(sig * env, pan.clip(-1, 1)) * amp * 0.5;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
// --- Roland SH-101 (mono saw+pulse+sub bass/lead, gated) ---
|
||||
SynthDef(\sh101, { |out=0, freq=55, amp=0.3, cutoff=1500, res=0.3, gate=1, pan=0, rev=0|
|
||||
var env = EnvGen.kr(Env.asr(0.006, 1, 0.2), gate, doneAction: 2);
|
||||
var sub = Pulse.ar((freq * 0.5).clip(10, 1000), 0.5) * 0.5;
|
||||
var osc = Saw.ar(freq.clip(20, 2000)) + (Pulse.ar(freq.clip(20, 2000), 0.45) * 0.5) + sub;
|
||||
var rq = res.clip(0, 1).linexp(0, 1, 1.0, 0.1);
|
||||
var sig = RLPF.ar(osc, cutoff.clip(60, 7000), rq);
|
||||
sig = Pan2.ar(sig * env, pan.clip(-1, 1)) * amp * 0.4;
|
||||
Out.ar(out, sig);
|
||||
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
|
||||
}).add;
|
||||
|
||||
s.sync;
|
||||
|
||||
~lp = ~lp ? ();
|
||||
|
||||
@@ -81,20 +81,20 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
// they never free and pile up forever, so they are NOT offered. The gated \lp_
|
||||
// sustained voices (lp_sub/lp_reese/lp_pad/lp_sweep) cover the drone textures.
|
||||
~matInstChoices = ~matInstChoices ? IdentityDictionary[
|
||||
\kick -> [\lp_kick, \do_kick, \do_quake_sub],
|
||||
\hats -> [\lp_hat, \do_hat],
|
||||
\clap -> [\lp_clap, \lp_rim, \do_hat],
|
||||
\perc -> [\lp_perc, \do_strike, \lp_tom],
|
||||
\sub -> [\lp_sub, \lp_reese, \do_quake_sub],
|
||||
\acid -> [\lp_acid, \lp_pluck],
|
||||
\arp -> [\lp_pluck, \do_strike, \lp_bells],
|
||||
\lead -> [\lp_pluck, \do_plane, \do_strike, \lp_bells],
|
||||
\stab -> [\lp_pluck, \lp_acid],
|
||||
\pad -> [\lp_pad, \lp_reese, \lp_sub],
|
||||
\ride -> [\lp_ride, \lp_hat, \do_hat],
|
||||
\rim -> [\lp_rim, \lp_clap, \do_hat],
|
||||
\kick -> [\lp_kick, \tr909_kick, \tr808_kick, \do_kick, \do_quake_sub],
|
||||
\hats -> [\lp_hat, \tr909_hat, \tr808_hat, \do_hat],
|
||||
\clap -> [\lp_clap, \tr909_clap, \tr808_clap, \lp_rim, \do_hat],
|
||||
\perc -> [\lp_perc, \tr808_cowbell, \do_strike, \lp_tom],
|
||||
\sub -> [\lp_sub, \sh101, \tr808_kick, \lp_reese, \do_quake_sub],
|
||||
\acid -> [\lp_acid, \tb303, \ms20, \lp_pluck],
|
||||
\arp -> [\lp_pluck, \tb303, \do_strike, \lp_bells],
|
||||
\lead -> [\lp_pluck, \ms20, \sh101, \do_plane, \do_strike],
|
||||
\stab -> [\lp_pluck, \ms20, \tb303, \lp_acid],
|
||||
\pad -> [\lp_pad, \ms20, \lp_reese, \lp_sub],
|
||||
\ride -> [\lp_ride, \tr909_ride, \lp_hat, \do_hat],
|
||||
\rim -> [\lp_rim, \tr808_cowbell, \tr909_clap, \do_hat],
|
||||
\tom -> [\lp_tom, \do_strike, \do_quake_sub],
|
||||
\reese -> [\lp_reese, \lp_sub, \lp_pad],
|
||||
\reese -> [\lp_reese, \ms20, \sh101, \lp_sub],
|
||||
\bells -> [\lp_bells, \do_strike, \do_plane],
|
||||
\sweep -> [\lp_sweep, \lp_pad, \lp_reese]
|
||||
];
|
||||
|
||||
@@ -312,14 +312,14 @@ const MATRIX_VOICES = [
|
||||
// per-voice curated instrument options (must mirror SC ~matInstChoices)
|
||||
// note-terminating synths only — the continuous do_ drones never free per-note.
|
||||
const MATRIX_INST_CHOICES = {
|
||||
kick:["lp_kick","do_kick","do_quake_sub"], hats:["lp_hat","do_hat"],
|
||||
clap:["lp_clap","lp_rim","do_hat"], perc:["lp_perc","do_strike","lp_tom"],
|
||||
sub:["lp_sub","lp_reese","do_quake_sub"],
|
||||
acid:["lp_acid","lp_pluck"], arp:["lp_pluck","do_strike","lp_bells"],
|
||||
lead:["lp_pluck","do_plane","do_strike","lp_bells"], stab:["lp_pluck","lp_acid"],
|
||||
pad:["lp_pad","lp_reese","lp_sub"], ride:["lp_ride","lp_hat","do_hat"],
|
||||
rim:["lp_rim","lp_clap","do_hat"], tom:["lp_tom","do_strike","do_quake_sub"],
|
||||
reese:["lp_reese","lp_sub","lp_pad"],
|
||||
kick:["lp_kick","tr909_kick","tr808_kick","do_kick","do_quake_sub"], hats:["lp_hat","tr909_hat","tr808_hat","do_hat"],
|
||||
clap:["lp_clap","tr909_clap","tr808_clap","lp_rim","do_hat"], perc:["lp_perc","tr808_cowbell","do_strike","lp_tom"],
|
||||
sub:["lp_sub","sh101","tr808_kick","lp_reese","do_quake_sub"],
|
||||
acid:["lp_acid","tb303","ms20","lp_pluck"], arp:["lp_pluck","tb303","do_strike","lp_bells"],
|
||||
lead:["lp_pluck","ms20","sh101","do_plane","do_strike"], stab:["lp_pluck","ms20","tb303","lp_acid"],
|
||||
pad:["lp_pad","ms20","lp_reese","lp_sub"], ride:["lp_ride","tr909_ride","lp_hat","do_hat"],
|
||||
rim:["lp_rim","tr808_cowbell","tr909_clap","do_hat"], tom:["lp_tom","do_strike","do_quake_sub"],
|
||||
reese:["lp_reese","ms20","sh101","lp_sub"],
|
||||
bells:["lp_bells","do_strike","do_plane"], sweep:["lp_sweep","lp_pad","lp_reese"]
|
||||
};
|
||||
let matInst = new Array(16).fill("default"); // per-voice selection (persisted)
|
||||
|
||||
Reference in New Issue
Block a user