diff --git a/sound_algo/data_only/test/test_touchosc_feedback.scd b/sound_algo/data_only/test/test_touchosc_feedback.scd index f27ba7c..a219443 100644 --- a/sound_algo/data_only/test/test_touchosc_feedback.scd +++ b/sound_algo/data_only/test/test_touchosc_feedback.scd @@ -30,13 +30,18 @@ pass = pass and: { ~toscSend.notNil }; pass = pass and: { ~toscTouch.notNil }; pass = pass and: { ~toscArmedPush.notNil }; -// Calling ~toscArmedPush.() with ~tosc nil must not raise -// (~toscSend nil-guards via !? so no OSC is actually sent) +// Calling ~toscArmedPush.() with no clients must not raise +// (~toscSend iterates an empty dictionary -> no-op, no OSC sent) try { ~toscArmedPush.() } { |e| pass = false; ("EXCEPTION in ~toscArmedPush: " ++ e.messageString).postln; }; +// Assert multicast set grows with distinct IPs +~toscTouch.(NetAddr("127.0.0.1", 0)); +~toscTouch.(NetAddr("10.0.0.9", 0)); +pass = pass and: { ~toscClients.size == 2 }; + // Stop the background Routine so the process can exit cleanly ~toscFeedbackRoutine !? { ~toscFeedbackRoutine.stop }; diff --git a/sound_algo/data_only/touchosc_feedback.scd b/sound_algo/data_only/touchosc_feedback.scd index 39da293..4e8252a 100644 --- a/sound_algo/data_only/touchosc_feedback.scd +++ b/sound_algo/data_only/touchosc_feedback.scd @@ -20,21 +20,23 @@ ( // -- Port + address init -- -~toscPort = ~toscPort ? 9000; -~tosc = ~tosc; // nil on first load, preserved on reload +~toscPort = ~toscPort ? 9000; +~toscClients = ~toscClients ? Dictionary.new; -// Refresh the target NetAddr when a control message arrives from the surface +// Add / refresh a client entry when a control message arrives from the surface. +// Keyed by ip String so the same host always maps to one NetAddr (dedup). +// Logs only when a NEW ip is first seen. ~toscTouch = { |addr| var ip = addr.ip; - (~tosc.isNil or: { ~tosc.ip != ip }).if({ - ~tosc = NetAddr(ip, ~toscPort); + ~toscClients[ip].isNil.if({ + ~toscClients[ip] = NetAddr(ip, ~toscPort); ("[touchosc] client -> " ++ ip ++ ":" ++ ~toscPort.asString).postln; }); }; -// Send an OSC message to the surface, silently if ~tosc not yet known +// Send an OSC message to all known clients; no-op when none connected ~toscSend = { |path ...args| - ~tosc !? { ~tosc.sendMsg(path, *args) }; + ~toscClients.values.do { |dest| dest.sendMsg(path, *args) }; }; // Canonical pad name order (16 pads in grid order, matches the surface layout)