Class: MusaLCEServer::Daw Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/daw.rb

Overview

This class is abstract.

Subclass and implement #daw_initialize and #track

Base class for DAW (Digital Audio Workstation) controllers.

This class provides the common infrastructure for communicating with DAWs like Ableton Live and Bitwig Studio. It manages:

  • OSC server/client for communication with DAW controller extensions
  • MIDI clock synchronization
  • Musa-DSL sequencer integration
  • MIDI device management
  • Transport controls (play, stop, record, etc.)

Subclasses must implement #daw_initialize to set up DAW-specific handlers and track management.

Direct Known Subclasses

Bitwig::Bitwig, Live::Live

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDaw

Creates a new DAW controller instance.

Sets up OSC server (port 11011) and client (port 10001), initializes the Musa-DSL sequencer, MIDI clock, and transport. Calls #daw_initialize for DAW-specific setup.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
103
104
105
106
# File 'lib/daw.rb', line 59

def initialize
  osc_server = OSC::EMServer.new(11_011)
  osc_client = OSC::Client.new('localhost', 10_001)

  Thread.new { osc_server.run }

  @sequencer = Musa::Sequencer::Sequencer.new 4, 24, dsl_context_class: MusaLCE_Context, do_log: true

  @clock = Musa::Clock::InputMidiClock.new do_log: true, logger: @sequencer.logger
  @transport = Musa::Transport::Transport.new @clock, sequencer: @sequencer

  @transport.after_stop do
    sequencer.reset
  end

  @midi_devices = MIDIDevices.new(@sequencer)

  # Build the surface side: inbound +/musalce/surface/*+
  # messages land on the EM reactor thread, are enqueued by the
  # bridge, then drained on the sequencer tick thread via
  # +before_tick+ — guaranteeing that inventory mutations and
  # user-defined trigger handlers can safely use any DSL method
  # (+play+, +at+, +launch+, …). Drainer latency is one tick
  # (≈20 ms at 120 BPM / 24 PPQN).
  surface_bridge = SurfaceBridge.new(osc_client, @sequencer, logger: @sequencer.logger)
  @surface = Surface.new(bridge: surface_bridge, logger: @sequencer.logger)
  surface_bridge.surface = @surface
  surface_bridge.register_inbound(osc_server)
  MusaLCEServer.surface = @surface

  @sequencer.before_tick do |_position|
    surface_bridge.drain
  end

  @tracks, @handler = daw_initialize(midi_devices: @midi_devices, clock: @clock, osc_server: osc_server, osc_client: osc_client, logger: @sequencer.logger)

  @handler.version
  @handler.sync

  # Ask Pulso Bridge (through the DAW extension) to dump its
  # current inventory. The reply re-establishes
  # +@surface.controls+ from scratch and triggers a full state
  # re-emit. Sent after +@handler.sync+ so the DAW extension is
  # known to be alive.
  surface_bridge.request_sync

  Thread.new { @transport.start }
end

Instance Attribute Details

#clockMusa::Clock::InputMidiClock (readonly)

Returns the MIDI clock for synchronization.

Returns:

  • (Musa::Clock::InputMidiClock)

    the MIDI clock for synchronization



125
126
127
# File 'lib/daw.rb', line 125

def clock
  @clock
end

#sequencerMusa::Sequencer::Sequencer (readonly)

Returns the Musa-DSL sequencer instance.

Returns:

  • (Musa::Sequencer::Sequencer)

    the Musa-DSL sequencer instance



125
# File 'lib/daw.rb', line 125

attr_reader :clock, :sequencer, :transport, :tracks, :surface

#surfaceObject (readonly)

Returns the value of attribute surface.



125
# File 'lib/daw.rb', line 125

attr_reader :clock, :sequencer, :transport, :tracks, :surface

#tracksObject (readonly)

Returns the DAW-specific tracks collection.

Returns:

  • (Object)

    the DAW-specific tracks collection



125
# File 'lib/daw.rb', line 125

attr_reader :clock, :sequencer, :transport, :tracks, :surface

#transportMusa::Transport::Transport (readonly)

Returns the transport driving the sequencer. Exposed so REPL users can register callbacks (Musa::Transport::Transport#on_start, Musa::Transport::Transport#after_stop, Musa::Transport::Transport#before_begin) that survive across DAW Stop/Play cycles — useful for re-installing +on :event+ handlers, +every+ loops or +at+ schedules that are wiped by the built-in +after_stop { sequencer.reset }+ callback.

Returns:

  • (Musa::Transport::Transport)

    the transport driving the sequencer. Exposed so REPL users can register callbacks (Musa::Transport::Transport#on_start, Musa::Transport::Transport#after_stop, Musa::Transport::Transport#before_begin) that survive across DAW Stop/Play cycles — useful for re-installing +on :event+ handlers, +every+ loops or +at+ schedules that are wiped by the built-in +after_stop { sequencer.reset }+ callback.



125
# File 'lib/daw.rb', line 125

attr_reader :clock, :sequencer, :transport, :tracks, :surface

Class Method Details

.daw_controller_for(daw_id) ⇒ Daw

Creates and returns a new DAW controller instance for the given identifier.

Parameters:

  • daw_id (Symbol)

    the DAW identifier (:bitwig or :live)

Returns:

  • (Daw)

    a new instance of the registered DAW controller



50
51
52
# File 'lib/daw.rb', line 50

def self.daw_controller_for(daw_id)
  @@daws[daw_id].new
end

.register(daw_id, daw_class) ⇒ void

This method returns an undefined value.

Registers a DAW driver class for a given identifier.

Examples:

Daw.register(:bitwig, Bitwig::Bitwig)

Parameters:

  • daw_id (Symbol)

    the DAW identifier (:bitwig or :live)

  • daw_class (Class)

    the DAW controller class to register



41
42
43
44
# File 'lib/daw.rb', line 41

def self.register(daw_id, daw_class)
  @@daws ||= {}
  @@daws[daw_id] = daw_class
end

Instance Method Details

#continuevoid

This method returns an undefined value.

Continues playback from current position.



162
# File 'lib/daw.rb', line 162

def continue; end

#goto(position) ⇒ void

This method returns an undefined value.

Moves playhead to specified position.

Parameters:

  • position (Numeric)

    the bar position to go to



167
# File 'lib/daw.rb', line 167

def goto(position); end

#panic!void

This method returns an undefined value.

Sends All Notes Off to all tracks.

Use this to stop stuck notes after errors or interruptions.



177
178
179
180
181
# File 'lib/daw.rb', line 177

def panic!
  @tracks.each do |track|
    track.out.all_notes_off
  end
end

#playvoid

This method returns an undefined value.

Starts playback in the DAW.



154
# File 'lib/daw.rb', line 154

def play; end

#recordvoid

This method returns an undefined value.

Starts recording in the DAW.



171
# File 'lib/daw.rb', line 171

def record; end

#reloadvoid

This method returns an undefined value.

Requests the DAW controller extension to reload.



191
192
193
# File 'lib/daw.rb', line 191

def reload
  @handler.reload
end

#stopvoid

This method returns an undefined value.

Stops playback in the DAW.



158
# File 'lib/daw.rb', line 158

def stop; end

#syncvoid

This method returns an undefined value.

Requests track synchronization from the DAW.



185
186
187
# File 'lib/daw.rb', line 185

def sync
  @handler.sync
end

#track(name, all: false) ⇒ Object+

This method is abstract.

Retrieves a track by name.

Parameters:

  • name (String)

    the track name

  • all (Boolean) (defaults to: false)

    if true, returns all matching tracks; otherwise returns first match

Returns:

  • (Object, Array<Object>)

    the track(s) matching the name

Raises:

  • (NotImplementedError)

    must be implemented by subclasses



148
149
150
# File 'lib/daw.rb', line 148

def track(name, all: false)
  raise NotImplementedError
end