Class: MusaLCEServer::SurfaceBridge

Inherits:
Object
  • Object
show all
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:

  1. 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).

  2. 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

Instance Method Summary collapse

Constructor Details

#initialize(osc_client, sequencer, logger:) ⇒ SurfaceBridge

Returns a new instance of SurfaceBridge.

Parameters:

  • osc_client (OSC::Client)

    outbound OSC client (shared with the active Handler)

  • sequencer (Musa::Sequencer::Sequencer)

    used to launch user-defined event handlers in response to surface triggers

  • logger (Logger)

    the logger



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

#surfaceSurface

Returns the surface this bridge dispatches inbound messages to; set during Daw initialization after both instances exist.

Returns:

  • (Surface)

    the surface this bridge dispatches inbound messages to; set during Daw initialization after both instances exist.



28
29
30
# File 'lib/surface-bridge.rb', line 28

def surface
  @surface
end

Instance Method Details

#drainvoid

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.

Parameters:

  • osc_server (OSC::EMServer)


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_syncvoid

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/+ for a property change.

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.

Parameters:

  • event (Symbol)

    the event the control is bound to

  • prop (Symbol)

    the property name (+:message+, +:enabled+, +:value+, +:range+, …)

  • value (Array<Object>)

    one or more values for the property (e.g. one for +:message+, two for +:range+)



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