feat: multicast tosc feedback to clients
Replace single ~tosc NetAddr with ~toscClients Dictionary (keyed by ip) so feedback OSC reaches all connected clients (web bridge + iPad) simultaneously. ~toscTouch deduplicates by IP and logs only on first connection. ~toscSend iterates the dictionary; no-op when empty. Test: add assertion that two distinct IPs produce size==2. Balance: P:0 B:0 on both files. Headless TEST PASS.
This commit is contained in:
@@ -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 };
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user