Class: MusaLCEServer::SurfaceBridge
- Inherits:
-
Object
- Object
- MusaLCEServer::SurfaceBridge
- Defined in:
- lib/surface-bridge.rb
Overview
OSC bridge between the server-side Surface and the physical control surface (Stream Deck, …) reached through the chain MusaLCEServer ↔ MusaLCEforXXX ↔ Pulso Bridge ↔ plugin.
Two responsibilities:
Outbound emission — translates Surface state changes and sync requests into +/musalce/surface/*+ OSC messages sent on the existing UDP client (port 10001, shared with Daw).
Inbound dispatch — receives +/musalce/surface/*+ messages on the OSC server (EM reactor thread), enqueues them, and drains the queue on the sequencer tick thread via #drain. This is critical: inventory mutations and trigger dispatch may invoke arbitrary user DSL code (+play+, +at+, +launch+, …) which must run on the sequencer thread.
Wired up by Daw#initialize; expected to be the sole emitter of +/musalce/surface/*+ on the server side.
Instance Attribute Summary collapse
-
#surface ⇒ Surface
The surface this bridge dispatches inbound messages to; set during Daw initialization after both instances exist.
Instance Method Summary collapse
-
#drain ⇒ void
private
Drains the inbound queue.
-
#initialize(osc_client, sequencer, logger:) ⇒ SurfaceBridge
constructor
A new instance of SurfaceBridge.
-
#register_inbound(osc_server) ⇒ void
Registers all inbound +/musalce/surface/*+ handlers on the given OSC server.
-
#request_sync ⇒ void
Sends +/musalce/surface/sync_request+ outbound.
-
#send_state(event:, prop:, value:) ⇒ void
Sends +/musalce/surface/state/
+ for a property change.
Constructor Details
#initialize(osc_client, sequencer, logger:) ⇒ SurfaceBridge
Returns a new instance of SurfaceBridge.
35 36 37 38 39 40 |
# File 'lib/surface-bridge.rb', line 35 def initialize(osc_client, sequencer, logger:) @client = osc_client @sequencer = sequencer @logger = logger @inbox = Queue.new end |
Instance Attribute Details
Instance Method Details
#drain ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Drains the inbound queue. Called from the sequencer tick thread (via +before_tick+) so every dispatched action runs in a context where DSL methods like +launch+, +play+, +at+ are safe to invoke.
110 111 112 113 114 115 116 117 |
# File 'lib/surface-bridge.rb', line 110 def drain loop do msg = @inbox.pop(true) dispatch(msg) end rescue ThreadError # Queue empty — done draining. end |
#register_inbound(osc_server) ⇒ void
This method returns an undefined value.
Registers all inbound +/musalce/surface/*+ handlers on the given OSC server. Each handler enqueues the message; actual processing happens on #drain.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/surface-bridge.rb', line 76 def register_inbound(osc_server) osc_server.add_method('/musalce/surface/inventory/begin') do |_msg| @inbox << [:inventory_begin] end osc_server.add_method('/musalce/surface/inventory/add') do |msg| args = msg.to_a @inbox << [:inventory_add, args[0], args[1]] end osc_server.add_method('/musalce/surface/inventory/remove') do |msg| @inbox << [:inventory_remove, msg.to_a[0]] end osc_server.add_method('/musalce/surface/inventory/end') do |_msg| @inbox << [:inventory_end] end osc_server.add_method('/musalce/surface/state_request') do |_msg| @inbox << [:state_request] end osc_server.add_method('/musalce/surface/trigger') do |msg| args = msg.to_a @inbox << [:trigger, args[0], (args[1] || '').to_s] end end |
#request_sync ⇒ void
This method returns an undefined value.
Sends +/musalce/surface/sync_request+ outbound. Used on server startup to ask Pulso Bridge (via the DAW extension) to dump its current inventory. The reply arrives as a sequence of +inventory/begin+, +inventory/add+ ..., +inventory/end+.
47 48 49 |
# File 'lib/surface-bridge.rb', line 47 def request_sync send_osc '/musalce/surface/sync_request' end |
#send_state(event:, prop:, value:) ⇒ void
This method returns an undefined value.
Sends +/musalce/surface/state/
One address per property so the Java relay and the surface plugin can dispatch on a fixed argument layout per address (event + N typed args). All values are serialized to strings on the wire — receivers parse them based on the address. Keeps the Java forwarder generic without inspecting typetags.
65 66 67 68 |
# File 'lib/surface-bridge.rb', line 65 def send_state(event:, prop:, value:) args = value.map { |v| serialize_arg(v) } send_osc "/musalce/surface/state/#{prop}", event.to_s, *args end |