From cadbced9589a71c5b1de67a47a1dc878d4a6abf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:19:14 +0200 Subject: [PATCH] fix(matrix): no baseGrid leak in evolve one-shot When the evolve toggle is OFF, ~matRelanceEvolve now snapshots ~matBaseGrid, mutates once, then restores it to nil. When ON it keeps the persistent base and re-mutates from it. Fixes stale- snapshot corruption across preset loads. Case I added to harness. --- sound_algo/data_only/matrix.scd | 9 +++++++-- .../matrix_presets/test_global_actions.scd | 13 +++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index 2bab630..beef03c 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -407,10 +407,15 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); }); }; -// one mutation from a base snapshot + re-source (the evolve one-shot) +// one mutation + re-source (the evolve one-shot). When the evolve toggle is +// OFF, snapshot/mutate/discard so ~matBaseGrid (owned by the toggle: non-nil +// iff evolve active) is never leaked across a preset load. When ON, keep the +// persistent base and just re-mutate from it. ~matRelanceEvolve = { - ~matBaseGrid.isNil.if({ ~matBaseGrid = ~lp[\matrix].collect({ |row| row.copy }) }); + var hadBase = ~matBaseGrid.notNil; + hadBase.not.if({ ~matBaseGrid = ~lp[\matrix].collect({ |row| row.copy }) }); ~matEvolveStep.(); + hadBase.not.if({ ~matBaseGrid = nil }); ~matVoices.size.do { |i| ~matLastColor[i] = -1 }; (~lp[\matPlaying] == true).if({ ~matApplyBar.(~lp[\matBar] ? 0) }); }; diff --git a/sound_algo/data_only/matrix_presets/test_global_actions.scd b/sound_algo/data_only/matrix_presets/test_global_actions.scd index 6d1278c..193d816 100644 --- a/sound_algo/data_only/matrix_presets/test_global_actions.scd +++ b/sound_algo/data_only/matrix_presets/test_global_actions.scd @@ -67,6 +67,19 @@ feat.load; (~matGlobalActions == [\evolve, \breakdown, \fill, \drop]).not.if({ pass = false; "FAIL: globalActions not round-tripped".postln }); ("rm -f '" ++ (~matDir +/+ "zz_gact_test.matrix") ++ "'").systemCmd; +// -- I: evolve one-shot must not leak ~matBaseGrid when the toggle is off, +// and must mutate from the CURRENT grid (not a stale snapshot) -- +~matEvolve = false; ~matBaseGrid = nil; +~lp[\matrix] = Array.fill(~matVoices.size, { Array.fill(~matBars, 0) }); +~lp[\matrix][0][0] = 3; // gridA: kick bar0 active +~matRelanceEvolve.(); +(~matBaseGrid.isNil).not.if({ pass = false; "FAIL: evolve one-shot leaked baseGrid".postln }); +~lp[\matrix] = Array.fill(~matVoices.size, { Array.fill(~matBars, 0) }); +~lp[\matrix][1][5] = 2; // gridB: hats bar5 active +~matRelanceEvolve.(); +(~lp[\matrix][0][0] == 0).not.if({ pass = false; "FAIL: stale gridA cell resurrected by evolve".postln }); +(~lp[\matrix][1][5] > 0).not.if({ pass = false; "FAIL: gridB active cell lost by evolve".postln }); + pass.if({ "GLOBALACT PASS".postln }, { "GLOBALACT FAIL".postln }); 0.exit; )