From 47fe6a46afbcdb76bcc167fcfb3e3236e766a341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Mon, 29 Jun 2026 20:31:32 +0200 Subject: [PATCH] feat(matrix): evolve edit/save/load + OSC routes --- sound_algo/data_only/matrix.scd | 15 ++++++++++++++- sound_algo/data_only/test/test_matrix.scd | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index 95c7477..c97f852 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -438,6 +438,7 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); ~matSetCell = { |vi, bar, color| (vi >= 0 and: { vi < ~matVoices.size and: { bar >= 0 and: { bar < ~matBars } } }).if({ ~lp[\matrix][vi][bar] = color.clip(0, 6).asInteger; + (~matEvolve and: { ~matBaseGrid.notNil }).if({ ~matBaseGrid[vi][bar] = ~lp[\matrix][vi][bar] }); (~lp[\matPlaying] and: { bar == ~lp[\matBar] }).if({ ~matApplyBar.(bar) }); ~toscSend !? { ~toscSend.("/matrix/cell", vi, bar, ~lp[\matrix][vi][bar]) } }) @@ -640,7 +641,7 @@ OSCdef(\mat_steps_get, { |msg, time, addr| var safe = ~matSafeName.(name); var path = ~matDir +/+ (safe ++ ".matrix"); var payload = ( - grid: ~lp[\matrix], + grid: (~matEvolve.if({ ~matBaseGrid ? ~lp[\matrix] }, { ~lp[\matrix] })), instruments: ~matInstruments.collect({ |x| (x ? \default) }), colorDefs: ~matColorDefs.collect({ |defs| (1..6).collect({ |c| defs[c] }) }), voiceMods: ~matVoices.collect({ |name| ~matVoiceMods[name] ? [] }), @@ -664,6 +665,7 @@ OSCdef(\mat_steps_get, { |msg, time, addr| grid = grid.isArray.if({ ~matMigrateGrid.(grid) }, { grid }); // pad/tile to current dims ~matGridValid.(grid).if({ ~lp[\matrix] = grid; + (~matEvolve).if({ ~matBaseGrid = ~lp[\matrix].collect({ |row| row.copy }) }); // restore instruments (default nil; validate against choices) ~matVoices.do { |name, vi| var sym = (insts.notNil).if({ insts[vi] }, { \default }); @@ -916,6 +918,17 @@ OSCdef(\mat_play, { |msg, time, addr| ~matPlay.() }, '/matrix/play'); +OSCdef(\mat_evolve, { |msg, time, addr| + ~toscTouch !? { ~toscTouch.(addr) }; + ~matSetEvolve.((msg[1] ? 0).asInteger > 0) +}, '/matrix/evolve'); + +OSCdef(\mat_evolverate, { |msg, time, addr| + ~toscTouch !? { ~toscTouch.(addr) }; + ~matEvolveRate = (msg[1] ? 0.15).asFloat.clip(0, 1); + ~matEvolvePush.() +}, '/matrix/evolverate'); + OSCdef(\mat_stop, { |msg, time, addr| ~toscTouch !? { ~toscTouch.(addr) }; ~matStop.() diff --git a/sound_algo/data_only/test/test_matrix.scd b/sound_algo/data_only/test/test_matrix.scd index c99b150..39043ca 100644 --- a/sound_algo/data_only/test/test_matrix.scd +++ b/sound_algo/data_only/test/test_matrix.scd @@ -848,6 +848,28 @@ pass = pass and: { ~matBaseGrid == ~evSnap }; // base unchanged by steps ~matSetEvolve.(false); // restore pass = pass and: { ~lp[\matrix] == ~evSnap }; // working grid back to base +// -- Task 2: persistence integration + OSC routes -- +// edit during evolve writes through to the base (survives next cycle) +~lp[\matrix] = Array.fill(~matVoices.size, { Array.fill(~matBars, 0) }); +~lp[\matrix][0][0] = 1; +~matSetEvolve.(true); // base = current grid +~matSetCell.(0, 0, 4); // edit while evolving +pass = pass and: { ~matBaseGrid[0][0] == 4 }; // base updated, not just working grid +// save serializes the base, not the mutated working grid +~matEvolveRate = 1.0; ~matEvolveStep.(); // working grid now mutated +~matSave.("ev_tmp"); +~evRaw = File.use(~matDir +/+ "ev_tmp.matrix", "r", { |f| f.readAllString }).interpret; +pass = pass and: { ~evRaw[\grid][0][0] == 4 }; // saved = base value, not the mutated one +File.delete(~matDir +/+ "ev_tmp.matrix"); +~matSetEvolve.(false); +// OSCdefs route through to the setters +OSCdef(\mat_evolverate).func.value(['/matrix/evolverate', 0.42]); +pass = pass and: { (~matEvolveRate - 0.42).abs < 0.001 }; +OSCdef(\mat_evolve).func.value(['/matrix/evolve', 1]); +pass = pass and: { ~matEvolve == true and: { ~matBaseGrid.notNil } }; +OSCdef(\mat_evolve).func.value(['/matrix/evolve', 0]); +pass = pass and: { ~matEvolve == false }; + pass.if( { "TEST PASS".postln }, { "TEST FAIL".postln }