From 68fa3c4e3b00fed35b7df2774edd2d61c4d9e519 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 09:13:23 +0200 Subject: [PATCH] feat(matrix): queued load at loop wrap --- sound_algo/data_only/matrix.scd | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index 01dcb58..ecbfbba 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -64,6 +64,7 @@ ~matDir = ~matDir ? "~/.config/av-live/matrices".standardizePath; ~matPresetDir = ~matPresetDir ? (PathName(thisProcess.nowExecutingPath).pathOnly ++ "matrix_presets"); ~matSavedNames = ~matSavedNames ? Set.new; +~matQueuedLoad = ~matQueuedLoad ? nil; // armed preset name for /matrix/loadnext (nil = none) File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); // -- ~matBaseFor : capture base Pdef source once (lazy, per voice name symbol) -- @@ -404,6 +405,19 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); ~matPush.() }; +// -- ~matWrapStep : runs once per loop wrap. A queued load (/matrix/loadnext) +// wins over evolve so a freshly loaded preset plays one clean cycle before +// ÉVOLUE mutates it; otherwise evolve mutates as before. -- +~matWrapStep = { + ~matQueuedLoad.notNil.if({ + ~matLoad.(~matQueuedLoad); + ~matQueuedLoad = nil; + ~toscSend !? { ~toscSend.("/matrix/queued", "") }; + }, { + ~matEvolve.if({ ~matEvolveStep.() }); + }); +}; + // -- ~matPlay : start the playhead Routine from bar 0, looping over ~matBars -- ~matPlay = { var clock = ~lp[\clock] ? TempoClock.default; @@ -418,8 +432,8 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); ~matBeatsPerBar.wait; ~matPrevBar = ~lp[\matBar]; ~lp[\matBar] = ~matNextBar.value; - // loop wrapped (playhead jumped backward) -> mutate one cycle - (~matEvolve and: { ~lp[\matBar] < ~matPrevBar }).if({ ~matEvolveStep.() }); + // loop wrapped (playhead jumped backward) -> queued load wins, else mutate + (~lp[\matBar] < ~matPrevBar).if({ ~matWrapStep.() }); } }).play(clock, quant: ~matBeatsPerBar); // -- per-step playhead: emits /matrix/stephead s (0..15) every 16th note -- @@ -951,6 +965,18 @@ OSCdef(\mat_load, { |msg, time, addr| ~matLoad.(msg[1].asString) }, '/matrix/load'); +OSCdef(\mat_loadnext, { |msg, time, addr| + var name = msg[1].asString; + ~toscTouch !? { ~toscTouch.(addr) }; + ~lp[\matPlaying].if({ + ~matQueuedLoad = name; // armed: swaps at next wrap + ~toscSend !? { ~toscSend.("/matrix/queued", name) }; + }, { + ~matLoad.(name); // not playing -> load now + ~toscSend !? { ~toscSend.("/matrix/queued", "") }; + }); +}, '/matrix/loadnext'); + OSCdef(\mat_list, { |msg, time, addr| ~toscTouch !? { ~toscTouch.(addr) }; ~matListPush.()