diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index ab1aeb6..93eb823 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -772,63 +772,6 @@ OSCdef(\mat_steps_get, { |msg, time, addr| } }; -// -- ~matSetColorMod : set/clear a color's capture effect; validate; re-source; echo -- -~matSetColorMod = { |vi, color, source, target, depth| - ((vi >= 0 and: { vi < ~matVoices.size }) and: { color >= 1 and: { color <= 6 } }).if({ - var name = ~matVoices[vi]; - var src = ((source == \none) or: { source.isNil }).if({ nil }, { source.asSymbol }); - var tgt = ((target == \none) or: { target.isNil }).if({ nil }, { target.asSymbol }); - var d = (depth ? 0).asFloat.clip(0, 1); - var ok = (src.isNil or: tgt.isNil) or: { - ~matModSources.includes(src) and: { (~matModTargets[name] ? []).includes(tgt) } }; - ok.if({ - ~matColorDefs[vi][color][\mod] = (src.isNil or: tgt.isNil).if({ nil }, - { (source: src, target: tgt, depth: d) }); - ~matLastColor[vi] = -1; - (~lp[\matPlaying] and: { ~matApplyBar.notNil }).if({ ~matApplyBar.(~lp[\matBar]) }); - ~matColorModPush.(vi, color) - }) - }) -}; - -// -- ~matSetColorPose : add/replace a pose binding in a color (dedup poseId; empty clears) -- -~matSetColorPose = { |vi, color, poseId, action| - ((vi >= 0 and: { vi < ~matVoices.size }) and: { color >= 1 and: { color <= 6 } }).if({ - var pid = poseId.asSymbol; - ((pid == '') or: { pid == \none }).if({ - ~matColorDefs[vi][color][\pose] = [] - }, { - ~matColorDefs[vi][color][\pose] = (~matColorDefs[vi][color][\pose] ? []) - .reject({ |b| b[\poseId] == pid }) ++ [ (poseId: pid, action: (action ? \trigger).asSymbol) ]; - }); - ~matColorPosePush.(vi, color) - }) -}; - -// -- ~matColorModPush : send one color's mod binding to surfaces -- -~matColorModPush = { |vi, color| - ((vi >= 0 and: { vi < ~matVoices.size }) and: { color >= 1 and: { color <= 6 } }).if({ - ~toscSend !? { - var m = ~matColorDefs[vi][color][\mod]; - ~toscSend.("/matrix/colormod", vi, color, - (m.isNil).if({ "none" }, { m[\source].asString }), - (m.isNil).if({ "none" }, { m[\target].asString }), - (m.isNil).if({ 0 }, { m[\depth] })) - } - }) -}; - -// -- ~matColorPosePush : send one color's pose bindings to surfaces -- -~matColorPosePush = { |vi, color| - ((vi >= 0 and: { vi < ~matVoices.size }) and: { color >= 1 and: { color <= 6 } }).if({ - ~toscSend !? { - var list = ~matColorDefs[vi][color][\pose] ? []; - var flat = list.collect({ |b| [b[\poseId].asString, b[\action].asString] }).flatten; - ~toscSend.valueArray(["/matrix/colorpose", vi, color, list.size] ++ flat) - } - }) -}; - OSCdef(\mat_voicemod, { |msg, time, addr| ~toscTouch !? { ~toscTouch.(addr) }; ~matSetVoiceMod.((msg[1] ? 0).asInteger, (msg[2] ? 0).asInteger, msg.copyToEnd(3)) diff --git a/sound_algo/data_only/test/test_matrix.scd b/sound_algo/data_only/test/test_matrix.scd index d41e0a8..b92ab9d 100644 --- a/sound_algo/data_only/test/test_matrix.scd +++ b/sound_algo/data_only/test/test_matrix.scd @@ -412,37 +412,6 @@ pass = pass and: { ~ev[\freq].isNil }; // --- Per-color mod + pose state (Task 1) --- pass = pass and: { ~matColorDefs[5][2][\mod].isNil }; // default no effect pass = pass and: { ~matColorDefs[5][2][\pose].isArray and: { ~matColorDefs[5][2][\pose].isEmpty } }; -pass = pass and: { ~matSetColorMod.notNil and: { ~matSetColorPose.notNil } }; -~trigLog = nil; ~toscSend = { |path ...args| ~trigLog = ([path] ++ args) }; -~matSetColorMod.(5, 2, \rHandY, \cutoff, 0.7); // acid supports cutoff -pass = pass and: { ~matColorDefs[5][2][\mod][\target] == \cutoff }; -pass = pass and: { ~trigLog[0] == "/matrix/colormod" and: { ~trigLog[1] == 5 } }; -~matSetColorMod.(0, 1, \rHandY, \cutoff, 0.7); // kick has no cutoff -> reject -pass = pass and: { ~matColorDefs[0][1][\mod].isNil }; -~matSetColorMod.(5, 2, \none, \none, 0); // clears -pass = pass and: { ~matColorDefs[5][2][\mod].isNil }; -~matSetColorPose.(5, 2, \poseA, \trigger); -pass = pass and: { ~matColorDefs[5][2][\pose][0][\poseId] == \poseA }; -~matColorDefs[5][2][\pose] = []; - -// dedup: setting the same poseId twice keeps one entry -~matColorDefs[5][2][\pose] = []; -~matSetColorPose.(5, 2, \poseD, \trigger); -~matSetColorPose.(5, 2, \poseD, \gate); -pass = pass and: { ~matColorDefs[5][2][\pose].size == 1 }; -pass = pass and: { ~matColorDefs[5][2][\pose][0][\action] == \gate }; -~matColorDefs[5][2][\pose] = []; - -// colorpose push echo -~trigLog = nil; -~matSetColorPose.(5, 2, \poseE, \trigger); -pass = pass and: { ~trigLog[0] == "/matrix/colorpose" and: { ~trigLog[1] == 5 } }; -~matColorDefs[5][2][\pose] = []; - -// out-of-bounds set must not raise / not corrupt -~matSetColorMod.(-1, 1, \rHandY, \cutoff, 0.5); -~matSetColorMod.(5, 7, \rHandY, \cutoff, 0.5); -pass = pass and: { true }; // Fix 1: fresh color pose arrays and distinct per color pass = pass and: { (~matColorDefs[5][1][\pose] === ~matColorDefs[5][2][\pose]).not }; @@ -498,8 +467,8 @@ try { ~matPoseFire.(\unknown) } { |e| pass = false }; ~matColorDefs[5][3][\pose] = []; // --- Per-color mod/pose persistence + migration (Task 3) --- -~matSetColorMod.(4, 3, \rHandY, \amp, 0.5); -~matSetColorPose.(4, 3, \poseM, \gate); +~matColorDefs[4][3][\mod] = (source: \rHandY, target: \amp, depth: 0.5); +~matColorDefs[4][3][\pose] = [ (poseId: \poseM, action: \gate) ]; ~matSave.("cp grid"); ~matColorDefs = Array.fill(~matVoices.size, { ~matDefaultColorDefs.value }); pass = pass and: { ~matLoad.("cp grid") }; @@ -518,16 +487,6 @@ pass = pass and: { ~matColorDefs[4][1][\mod][\target] == \cutoff }; // voice m pass = pass and: { ~matColorDefs[4][3][\pose][0][\poseId] == \poseL }; // pose -> its color File.delete(~matDir +/+ "legc.matrix"); -// colorpose OSCdef list-format parse (web sends vi color n pairs) -~cpMsg = ["/matrix/colorpose", 5, 2, 2, "poseA", "trigger", "poseB", "gate"]; -~matColorDefs[5][2][\pose] = Array.fill((~cpMsg[3]).asInteger, { |k| - (poseId: (~cpMsg[4 + (k*2)]).asSymbol, action: (~cpMsg[5 + (k*2)]).asSymbol) }); -pass = pass and: { ~matColorDefs[5][2][\pose].size == 2 }; -pass = pass and: { ~matColorDefs[5][2][\pose][1][\poseId] == \poseB }; -pass = pass and: { ~matColorDefs[5][2][\pose][1][\action] == \gate }; -// n=0 clears -~matColorDefs[5][2][\pose] = Array.fill(0, { nil }); -pass = pass and: { ~matColorDefs[5][2][\pose].isEmpty }; // --- New iPhone mod sources (Task 1) --- // ~matModOrder must have 19 entries diff --git a/web_realart/public/control/js/voice-editor.js b/web_realart/public/control/js/voice-editor.js index 87d1a1a..3034963 100644 --- a/web_realart/public/control/js/voice-editor.js +++ b/web_realart/public/control/js/voice-editor.js @@ -530,26 +530,6 @@ on("/matrix/steps", (args) => { } }); -on("/matrix/colormod", (args) => { - const vi=Math.round(Number(args[0])), c=Math.round(Number(args[1])); - if (vi>=0&&vi=1&&c<=6&&matColorDefs[vi][c]) { - const src=String(args[2]??"none"); - matColorDefs[vi][c].mod = (src==="none") ? null : {source:src, target:String(args[3]??"none"), depth:Number(args[4])||0}; - saveMatState(); - if (isOpenFor(vi) && cdColor === c) renderPattern(vi); - } -}); - -on("/matrix/colorpose", (args) => { - const vi=Math.round(Number(args[0])), c=Math.round(Number(args[1])), n=Math.round(Number(args[2])); - if (vi>=0&&vi=1&&c<=6&&matColorDefs[vi][c]) { - matColorDefs[vi][c].pose = []; - for (let k=0;k { const { vi, list } = parseVoiceMod(args); if (vi >= 0 && vi < MATRIX_VOICES.length) {