fix: matrix re-source only on color change
CI build oscope-of / build-check (push) Has been cancelled

Track last-applied color per voice in ~matLastColor; ~matApplyBar
skips Pdef re-source and re-play when color is unchanged and non-zero,
eliminating envelope re-attacks on sustaining pads/subs/reese/sweeps.
~matStop resets ~matLastColor to -1 so subsequent play re-applies all.
~matVariation now returns nil for color 0 instead of the base pattern.
loadMatState validates each cell is an integer 0..6.
This commit is contained in:
L'électron rare
2026-06-28 17:07:04 +02:00
parent 2d927107f1
commit 6843e5aafc
2 changed files with 44 additions and 31 deletions
+42 -30
View File
@@ -4,6 +4,8 @@
// A playhead Routine advances bar-by-bar on the launchpad clock, applying cells.
// Colors 1-6 map to Pchain overlays (\stretch / \octave / \amp). 0 = Pdef.stop.
// Loaded after sections.scd (boot step 6i). Idempotent reload, nil-guarded.
// NOTE: the \amp variation override bypasses ~lpVol per-voice volume; web vol sliders
// have no effect while a matrix variation plays — deferred to v2.
(
// -- Env init (nil-guarded; idempotent reload) --
@@ -20,6 +22,7 @@
~lp[\matPlaying] = ~lp[\matPlaying] ? false;
~matBase = ~matBase ? IdentityDictionary.new;
~matBeatsPerBar = ~matBeatsPerBar ? 4;
~matLastColor = ~matLastColor ? Array.fill(~matVoices.size, -1);
// -- ~matBaseFor : capture base Pdef source once (lazy, per voice name symbol) --
// Returns nil when the Pdef is missing (safe for partial environments).
@@ -42,28 +45,30 @@
// to the octave variation — acceptable for v1; tune the palette at the live gate.
// Single function so all variation logic lives in one place.
~matVariation = { |name, color|
var base = ~matBaseFor.(name);
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)
][color];
spec.notNil.if({
Pchain(
Pbind(
\stretch, spec[\stretch],
\octave, spec[\octave],
\amp, spec[\amp]
),
base
)
}, { base })
}, { nil })
(color == 0).if({ nil }, {
var base = ~matBaseFor.(name);
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)
][color];
spec.notNil.if({
Pchain(
Pbind(
\stretch, spec[\stretch],
\octave, spec[\octave],
\amp, spec[\amp]
),
base
)
}, { base })
}, { nil })
})
};
// -- ~matApplyBar : set each voice's Pdef to its cell color and (re)play or stop --
@@ -74,15 +79,21 @@
var key = ("lp_" ++ name).asSymbol;
Pdef.all.includesKey(key).if({
(color == 0).if(
{ Pdef(key).stop },
{
var pat = ~matVariation.(name, color);
pat.notNil.if({
Pdef(key, pat);
Pdef(key).play(
~lp[\clock] ? TempoClock.default,
quant: ~matBeatsPerBar
)
Pdef(key).stop;
~matLastColor[vi] = 0
},
{
(color != ~matLastColor[vi]).if({
var pat = ~matVariation.(name, color);
pat.notNil.if({
~matLastColor[vi] = color;
Pdef(key, pat);
Pdef(key).play(
~lp[\clock] ? TempoClock.default,
quant: ~matBeatsPerBar
)
})
})
}
)
@@ -103,6 +114,7 @@
var k = ("lp_" ++ name).asSymbol;
Pdef.all.includesKey(k).if({ Pdef(k).stop })
};
~matVoices.size.do { |i| ~matLastColor[i] = -1 };
~matPush.()
};
+2 -1
View File
@@ -182,7 +182,8 @@ function loadMatState() {
const parsed = JSON.parse(raw);
if (
Array.isArray(parsed) && parsed.length === 16 &&
parsed.every(row => Array.isArray(row) && row.length === 32)
parsed.every(row => Array.isArray(row) && row.length === 32 &&
row.every(v => Number.isInteger(v) && v >= 0 && v <= 6))
) {
matGrid = parsed;
return;