feat: more classic machine emulations
CI build oscope-of / build-check (push) Has been cancelled

Web-researched the iconic machines per style and added 7 more:
Minimoog (ladder bass/lead), Roland JP-8000 supersaw (trance/
progressive), Juno-106 (chorus pad), Yamaha DX7 (FM), E-mu
SP-1200 (12-bit drum crunch), Akai sampler (lo-fi grit) and
Roland System-100. Standard UGens only (MoogFF/Latch/DelayC).
Wired per voice into the choices + web mirror; all kit/test
instrument targets kept in the choice lists.
This commit is contained in:
L'électron rare
2026-06-29 00:20:34 +02:00
parent 25ce6e0139
commit dc766fe896
3 changed files with 97 additions and 24 deletions
+73
View File
@@ -242,6 +242,79 @@ SynthDef(\sh101, { |out=0, freq=55, amp=0.3, cutoff=1500, res=0.3, gate=1, pan=0
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- Minimoog : 3-osc fat bass/lead, Moog ladder LPF (gated) ---
SynthDef(\minimoog, { |out=0, freq=55, amp=0.3, cutoff=1200, res=0.5, gate=1, pan=0, rev=0|
var env = EnvGen.kr(Env.asr(0.005, 1, 0.22), gate, doneAction: 2);
var osc = Mix([Saw.ar(freq.clip(20,3000)), Saw.ar(freq.clip(20,3000) * 1.005),
Pulse.ar((freq * 0.5).clip(10, 1500), 0.5)]) * 0.4;
var sig = MoogFF.ar(osc, cutoff.clip(60, 8000), res.clip(0, 1) * 3.8);
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 JP-8000 supersaw : 7 detuned saws (trance/progressive lead) ---
SynthDef(\supersaw, { |out=0, freq=220, amp=0.3, cutoff=6000, res=0.2, detune=0.05, gate=1, pan=0, rev=0|
var env = EnvGen.kr(Env.asr(0.01, 1, 0.3), gate, doneAction: 2);
var dets = [-3, -2, -1, 0, 1, 2, 3] * (detune / 3);
var osc = Mix(Saw.ar((freq.clip(20, 4000)) * (1 + dets))) * (1/7) * 2;
var sig = RLPF.ar(osc, cutoff.clip(200, 12000), (1 - res).clip(0.2, 1));
sig = Pan2.ar(sig * env, pan.clip(-1, 1)) * amp * 0.7;
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- Roland Juno-106 : saw+pulse+sub -> LPF + signature chorus (gated pad) ---
SynthDef(\juno, { |out=0, freq=110, amp=0.3, cutoff=2500, res=0.2, gate=1, pan=0, rev=0|
var env = EnvGen.kr(Env.asr(0.02, 1, 0.4), gate, doneAction: 2);
var osc = Saw.ar(freq.clip(20, 3000))
+ (Pulse.ar(freq.clip(20, 3000), SinOsc.kr(0.3).range(0.3, 0.7)) * 0.6)
+ (Pulse.ar((freq * 0.5).clip(10, 1500), 0.5) * 0.4);
var flt = RLPF.ar(osc * 0.3, cutoff.clip(200, 9000), (1 - res).clip(0.2, 1));
var ch = flt
+ DelayC.ar(flt, 0.03, SinOsc.kr(0.6, 0, 0.003, 0.008))
+ DelayC.ar(flt, 0.03, SinOsc.kr(0.5, pi, 0.003, 0.008));
var sig = Pan2.ar(ch * 0.5 * env, pan.clip(-1, 1)) * amp * 0.5;
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- Yamaha DX7 : 2-operator FM (bass / bell / e-piano) ---
SynthDef(\dx7, { |out=0, freq=110, amp=0.3, ratio=2.0, index=3, pan=0, rev=0|
var env = EnvGen.kr(Env.perc(0.004, 0.6, 1, -4), doneAction: 2);
var menv = EnvGen.kr(Env.perc(0.001, 0.3, 1, -3));
var mod = SinOsc.ar(freq.clip(20, 4000) * ratio) * freq.clip(20, 4000) * ratio * index * menv;
var sig = SinOsc.ar(freq.clip(20, 4000) + mod) * env;
sig = Pan2.ar(sig, pan.clip(-1, 1)) * amp * 0.5;
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- E-mu SP-1200 : 12-bit / ~26 kHz crunchy drum character ---
SynthDef(\sp1200, { |out=0, freq=120, amp=0.5, pan=0, rev=0|
var env = EnvGen.kr(Env.perc(0.001, 0.3, 1, -4), doneAction: 2);
var src = (SinOsc.ar(freq.clip(30, 400)) + (WhiteNoise.ar * 0.5)) * env;
var crushed = (Latch.ar(src, Impulse.ar(26040)) * 2048).round / 2048;
var sig = Pan2.ar(crushed.tanh, pan.clip(-1, 1)) * amp;
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- Akai sampler (S950/S1100-ish) : 12-bit / 22 kHz lo-fi tonal grit ---
SynthDef(\akai_s, { |out=0, freq=220, amp=0.3, pan=0, rev=0|
var env = EnvGen.kr(Env.perc(0.002, 0.5, 1, -3), doneAction: 2);
var src = (Saw.ar(freq.clip(20, 3000)) + (Pulse.ar(freq.clip(20, 3000) * 1.5, 0.4) * 0.5)) * 0.4;
var crushed = (Latch.ar(src, Impulse.ar(22050)) * 4096).round / 4096;
var sig = RLPF.ar(crushed, 6000, 0.6) * env;
sig = Pan2.ar(sig, pan.clip(-1, 1)) * amp * 0.6;
Out.ar(out, sig);
~doReverbBus.notNil.if({ Out.ar(~doReverbBus, sig * rev) });
}).add;
// --- Roland System-100 : semi-modular saw/pulse + Moog-ish LPF (bass/lead) ---
SynthDef(\system100, { |out=0, freq=110, amp=0.3, cutoff=1500, res=0.4, gate=1, pan=0, rev=0|
var env = EnvGen.kr(Env.asr(0.006, 1, 0.2), gate, doneAction: 2);
var osc = (Saw.ar(freq.clip(20, 3000)) + Pulse.ar(freq.clip(20, 3000) * 0.999, 0.45)
+ (Pulse.ar((freq * 0.5).clip(10, 1500), 0.5) * 0.4)) * 0.3;
var sig = MoogFF.ar(osc, cutoff.clip(60, 8000), res.clip(0, 1) * 3.6);
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;
s.sync;
+15 -15
View File
@@ -81,22 +81,22 @@ 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, \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],
\kick -> [\lp_kick, \tr909_kick, \tr808_kick, \sp1200, \do_kick, \do_quake_sub],
\hats -> [\lp_hat, \tr909_hat, \tr808_hat, \sp1200, \do_hat],
\clap -> [\lp_clap, \tr909_clap, \tr808_clap, \sp1200, \lp_rim],
\perc -> [\lp_perc, \tr808_cowbell, \sp1200, \akai_s, \do_strike],
\sub -> [\lp_sub, \sh101, \minimoog, \system100, \lp_reese],
\acid -> [\lp_acid, \tb303, \ms20, \system100, \lp_pluck],
\arp -> [\lp_pluck, \tb303, \supersaw, \juno, \do_strike],
\lead -> [\lp_pluck, \ms20, \supersaw, \do_plane, \sh101],
\stab -> [\lp_pluck, \ms20, \supersaw, \tb303, \lp_acid],
\pad -> [\lp_pad, \juno, \supersaw, \ms20, \lp_reese],
\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]
\rim -> [\lp_rim, \tr808_cowbell, \tr909_clap, \sp1200],
\tom -> [\lp_tom, \sp1200, \do_strike, \do_quake_sub],
\reese -> [\lp_reese, \ms20, \minimoog, \system100, \supersaw],
\bells -> [\lp_bells, \dx7, \akai_s, \do_plane],
\sweep -> [\lp_sweep, \akai_s, \lp_pad, \lp_reese]
];
// -- fixed kits: kitName -> (voiceName -> instrument). Unlisted voices = default --
+9 -9
View File
@@ -312,15 +312,15 @@ 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","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"]
kick:["lp_kick","tr909_kick","tr808_kick","sp1200","do_kick","do_quake_sub"], hats:["lp_hat","tr909_hat","tr808_hat","sp1200","do_hat"],
clap:["lp_clap","tr909_clap","tr808_clap","sp1200","lp_rim"], perc:["lp_perc","tr808_cowbell","sp1200","akai_s","do_strike"],
sub:["lp_sub","sh101","minimoog","system100","lp_reese"],
acid:["lp_acid","tb303","ms20","system100","lp_pluck"], arp:["lp_pluck","tb303","supersaw","juno","do_strike"],
lead:["lp_pluck","ms20","supersaw","do_plane","sh101"], stab:["lp_pluck","ms20","supersaw","tb303","lp_acid"],
pad:["lp_pad","juno","supersaw","ms20","lp_reese"], ride:["lp_ride","tr909_ride","lp_hat","do_hat"],
rim:["lp_rim","tr808_cowbell","tr909_clap","sp1200"], tom:["lp_tom","sp1200","do_strike","do_quake_sub"],
reese:["lp_reese","ms20","minimoog","system100","supersaw"],
bells:["lp_bells","dx7","akai_s","do_plane"], sweep:["lp_sweep","akai_s","lp_pad","lp_reese"]
};
let matInst = new Array(16).fill("default"); // per-voice selection (persisted)
const MATRIX_MOD_SOURCES = ["none","lHandY","rHandY","lHandX","rHandX","lOpen","rOpen","handSpeed","handDist","bodyX","bodyY","depth"];