fix: matrix octave colors and sustained lead
CI build oscope-of / build-check (push) Has been cancelled
CI build oscope-of / build-check (push) Has been cancelled
Matrix colors 3/5 pushed a dead \octave key; every pitched Pdef sets \freq directly so the transposition was inaudible. Replace with a base-\freq multiplier (x2/x0.5) over the Pchain, gated to pitched voices so drums and instrument overrides keep their pitch. Add a dedicated sustained \lp_lead SynthDef (gated ASR) and point Pdef(\lp_lead) at it with \legato so lead notes hold; arp and stab stay on \lp_pluck.
This commit is contained in:
@@ -39,6 +39,13 @@ SynthDef(\lp_pluck, { |out=0, freq=220, amp=0.3, cutoff=2500, pan=0|
|
||||
var sig = RLPF.ar(Saw.ar(freq.clip(40,2000) * [1, 1.005]), cutoff.clip(200,8000), 0.4);
|
||||
Out.ar(out, Pan2.ar(Mix(sig) * env, pan.clip(-1,1)) * amp);
|
||||
}).add;
|
||||
// sustained lead: gated ASR so notes hold for their full \dur (needs \legato).
|
||||
SynthDef(\lp_lead, { |out=0, freq=220, amp=0.3, cutoff=3000, gate=1, pan=0|
|
||||
var env = EnvGen.kr(Env.asr(0.01, 1, 0.3), gate, doneAction: 2);
|
||||
var sig = Mix(Saw.ar(freq.clip(40, 3000) * [0.997, 1.0, 1.005]));
|
||||
sig = RLPF.ar(sig, (cutoff.clip(300, 9000) * (1 + (env * 0.4))).clip(300, 12000), 0.28);
|
||||
Out.ar(out, Pan2.ar(sig * env, pan.clip(-1, 1)) * amp * 0.45);
|
||||
}).add;
|
||||
SynthDef(\lp_pad, { |out=0, freq=220, amp=0.0, cutoff=1500, gate=1|
|
||||
var sig = Mix(Saw.ar(freq.clip(40,1000) * [0.99, 1.0, 1.008, 2.0]));
|
||||
sig = RLPF.ar(sig, cutoff.clip(200,6000), 0.4);
|
||||
@@ -164,10 +171,10 @@ Pdef(\lp_arp, Pbind(\instrument, \lp_pluck, \dur, 0.25,
|
||||
\degree, Pseq([0,2,4,7,4,2], inf),
|
||||
\freq, Pfunc { |e| ~lpNote.(e[\degree], 1).midicps },
|
||||
\cutoff, 3000, \amp, Pfunc { 0.2 * ~lpVol.(\arp) }, \pan, Pwhite(-0.3,0.3)));
|
||||
Pdef(\lp_lead, Pbind(\instrument, \lp_pluck, \dur, Pseq([1, 0.5, 0.5, 2], inf),
|
||||
Pdef(\lp_lead, Pbind(\instrument, \lp_lead, \dur, Pseq([1, 0.5, 0.5, 2], inf),
|
||||
\degree, Pseq([7,5,4,0,2,4], inf),
|
||||
\freq, Pfunc { |e| ~lpNote.(e[\degree], 1).midicps },
|
||||
\cutoff, 4000, \amp, Pfunc { 0.24 * ~lpVol.(\lead) }));
|
||||
\cutoff, 4000, \amp, Pfunc { 0.24 * ~lpVol.(\lead) }, \legato, 1));
|
||||
Pdef(\lp_stab, Pbind(\instrument, \lp_pluck, \dur, Pseq([Rest(0.5), 0.5], inf),
|
||||
\freq, Pfunc { [0,2,4].collect { |d| ~lpNote.(d, 0).midicps } },
|
||||
\cutoff, 2200, \amp, Pfunc { 0.2 * ~lpVol.(\stab) }));
|
||||
|
||||
@@ -142,9 +142,10 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
// -- ~matVariation : map color 1-6 to a Pchain overlay on the captured base --
|
||||
// color 1 = base as-is, 2 = double-time, 3 = octave up, 4 = half-time,
|
||||
// 5 = octave down + slight accent, 6 = accent roll (denser + louder).
|
||||
// \stretch multiplies event duration; \octave shifts degree-based pitch.
|
||||
// NOTE: voices that compute \freq via Pfunc (ignoring \octave) will not respond
|
||||
// to the octave variation — acceptable for v1; tune the palette at the live gate.
|
||||
// \stretch multiplies event duration; octave colors multiply the base \freq
|
||||
// (x2 up, x0.5 down) over the base event, so they transpose even voices that set
|
||||
// \freq directly via Pfunc (which bypass SC's \octave). Only pitched voices get
|
||||
// the \freq multiply — drums keep their pitch (and any instrument override).
|
||||
// Single function so all variation logic lives in one place.
|
||||
~matVariation = { |name, color, vi = 0|
|
||||
(color == 0).if({ nil }, {
|
||||
@@ -152,18 +153,26 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
base.notNil.if({
|
||||
var spec = [
|
||||
nil,
|
||||
(stretch: 1.0, octave: 0, amp: 1.0),
|
||||
(stretch: 0.5, octave: 0, amp: 1.0),
|
||||
(stretch: 1.0, octave: 1, amp: 1.0),
|
||||
(stretch: 2.0, octave: 0, amp: 1.0),
|
||||
(stretch: 1.0, octave: -1, amp: 1.05),
|
||||
(stretch: 0.5, octave: 0, amp: 1.2)
|
||||
(stretch: 1.0, freqRatio: 1.0, amp: 1.0),
|
||||
(stretch: 0.5, freqRatio: 1.0, amp: 1.0),
|
||||
(stretch: 1.0, freqRatio: 2.0, amp: 1.0),
|
||||
(stretch: 2.0, freqRatio: 1.0, amp: 1.0),
|
||||
(stretch: 1.0, freqRatio: 0.5, amp: 1.05),
|
||||
(stretch: 0.5, freqRatio: 1.0, amp: 1.2)
|
||||
][color];
|
||||
spec.notNil.if({
|
||||
var inst = ~matInstruments[vi];
|
||||
// per-voice volume (mixer fix from main): read live, default 0.8
|
||||
var volOf = { (~lp[\vol].notNil).if({ ~lp[\vol][name.asSymbol] ? 0.8 }, { 0.8 }) };
|
||||
var instPair = inst.notNil.if({ [\instrument, inst] }, { [] });
|
||||
// octave colors: multiply the base \freq, pitched voices only.
|
||||
// gating avoids forcing a pitch onto drums (incl. drum voices
|
||||
// remapped to a pitched instrument override).
|
||||
var pitched = [\sub, \acid, \arp, \lead, \stab, \pad, \reese, \bells, \perc, \tom];
|
||||
var freqRatio = spec[\freqRatio] ? 1.0;
|
||||
var freqPair = (pitched.includes(name) and: { freqRatio != 1.0 }).if({
|
||||
[\freq, Pfunc({ |e| (e[\freq] ? 440) * freqRatio })]
|
||||
}, { [] });
|
||||
var mod = ~matMod[vi];
|
||||
var modPairs = mod.isNil.if({ [] }, {
|
||||
var src = mod[\source], tgt = mod[\target], d = mod[\depth];
|
||||
@@ -186,9 +195,8 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
0
|
||||
},
|
||||
\stretch, spec[\stretch],
|
||||
\octave, spec[\octave],
|
||||
\amp, Pfunc({ (spec[\amp] ? 1.0) * volOf.value })
|
||||
] ++ instPair ++ modPairs)),
|
||||
] ++ freqPair ++ instPair ++ modPairs)),
|
||||
base
|
||||
)
|
||||
}, { base })
|
||||
|
||||
Reference in New Issue
Block a user