musalce-server 0.5.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 362aa81c7054d8726ba7f2c76c7a6053235872dd5a01e996ad81ff4356a329af
4
- data.tar.gz: 20c096e30e76eeadecd875ac6eed534ce299a99644150a04f5a3aed1a5592855
3
+ metadata.gz: 2230cb912aab835e98533a65b0a8b0ae44c5b815bce0555ecfe1433807048502
4
+ data.tar.gz: 4b3323bdc75f6a1e54f9ec75a42ccb649aaa82ed20fb150bf84258c098e9b908
5
5
  SHA512:
6
- metadata.gz: 7f495fb6fef34ed22b950b0ff4cbef22212b8a4112f23781df2856b760b011110be40bb26e5ba650867af201d5645bc0460985593fbfe78bbcbc61cc501294d5
7
- data.tar.gz: c93cda068c6a8f58797d7b2348c83dbfb2b819c2d0664f16c998ce9870dfe283fb785dbb6881fafcffaab3f0689bb60b6036558cb28389041b20e5f392d8dc6b
6
+ metadata.gz: cfbc543f1927cf246604d5d0c25390fbba0f932a81c43232e5ae31e6020e06dc5995b8bd5eec44f251f76e40a22f8eccc13c6fadc1c1d5bcbeed6373d4ea80de
7
+ data.tar.gz: 0bacccdb81eaea73d307b3667871ed4a092e791ba5822c10870ac5bf56ecc3ec3e815946634c5e9035f2ff658745fb1f60f21cd652c1df5b14d2928e35b37c08
@@ -0,0 +1,17 @@
1
+ name: Notify Plugin Rebuild
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ jobs:
8
+ notify:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Trigger nota-plugin-for-claude rebuild
12
+ uses: peter-evans/repository-dispatch@v3
13
+ with:
14
+ token: ${{ secrets.PLUGIN_REBUILD_PAT }}
15
+ repository: javier-sy/nota-plugin-for-claude
16
+ event-type: source-updated
17
+ client-payload: '{"repo": "${{ github.repository }}", "sha": "${{ github.sha }}"}'
data/.gitignore CHANGED
@@ -6,5 +6,8 @@
6
6
  .ruby-gemset
7
7
  .ruby-version
8
8
  Gemfile.lock
9
+ doc/
10
+ .yardoc/
11
+
9
12
 
10
13
 
data/.version ADDED
@@ -0,0 +1,6 @@
1
+ # Configuración de versión para musalce-server
2
+ GEM_NAME="musalce-server"
3
+ MODULE_NAME="MusaLCEServer"
4
+ VERSION_FILE="lib/version.rb"
5
+ GEMSPEC_FILE="musalce-server.gemspec"
6
+ TEST_COMMAND="bundle exec rspec"
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --markup markdown
2
+ --title "MusaLCE Server API"
3
+ --readme README.md
4
+ --no-private
5
+ --embed-mixins
6
+ lib/**/*.rb
data/README.md CHANGED
@@ -1,17 +1,325 @@
1
- # Musa Live Coding Environment (Server for Ableton Live and Bitwig)
1
+ # MusaLCE Server
2
2
 
3
- Musa-DSL Live Coding Environment for Ableton Live and Bitwig Studio (Server part)
3
+ [![Ruby Version](https://img.shields.io/badge/ruby-2.7+-red.svg)](https://www.ruby-lang.org/)
4
+ [![License](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)
4
5
 
5
- **TODO: complete README**
6
+ **Musa-DSL Live Coding Environment Server for Ableton Live 11+ and Bitwig Studio 5+**
6
7
 
7
- ## Install
8
- **TODO**
8
+ This server enables live coding music composition using [Musa-DSL](https://github.com/javier-sy/musa-dsl) with your favorite DAW and code editor.
9
9
 
10
- ## Usage
11
- **TODO**
10
+ ## Overview
11
+
12
+ The MusaLCE system allows you to write Ruby code in your editor (Visual Studio Code recommended) and have it executed in real-time, sending MIDI to tracks in your DAW. The typical workflow is:
13
+
14
+ 1. Start the MusaLCE Server with your DAW choice
15
+ 2. Open your code editor with the MusaLCE extension
16
+ 3. Write and execute Musa-DSL code interactively
17
+ 4. The code controls MIDI instruments in your DAW
18
+
19
+ ## Requirements
20
+
21
+ - Ruby 2.7+
22
+ - [Musa-DSL](https://github.com/javier-sy/musa-dsl) (installed automatically as dependency)
23
+ - A supported DAW with its controller extension:
24
+ - **Bitwig Studio 5+** with [MusaLCE for Bitwig](https://github.com/javier-sy/MusaLCEforBitwig) Controller Extension
25
+ - **Ableton Live 11+** with [MusaLCE for Live](https://github.com/javier-sy/MusaLCEforLive) MIDI Remote Script
26
+ - A code editor with MusaLCE client extension:
27
+ - **Visual Studio Code** (recommended) with [MusaLCE Client for VSCode](https://github.com/javier-sy/MusaLCEClientForVSCode)
28
+ - Atom with [MusaLCE Client for Atom](https://github.com/javier-sy/MusaLCEClientForAtom) (Atom is discontinued)
29
+
30
+ ## Installation
31
+
32
+ If you're using Bundler, add this line to your application's Gemfile:
33
+
34
+ ```ruby
35
+ gem 'musalce-server'
36
+ ```
37
+
38
+ Otherwise:
39
+
40
+ ```bash
41
+ gem install musalce-server
42
+ ```
43
+
44
+ ## Quick Start
45
+
46
+ 1. **Install the DAW controller extension** for your DAW (Bitwig or Live)
47
+ 2. **Install the VSCode extension** [MusaLCE Client for VSCode](https://github.com/javier-sy/MusaLCEClientForVSCode)
48
+ 3. **Start your DAW** and ensure the MusaLCE controller is loaded
49
+ 4. **Start the server** (see below)
50
+ 5. **Open VSCode** and create a `.rb` file
51
+ 6. **Execute code** using the MusaLCE extension commands
52
+
53
+ ## Starting the Server
54
+
55
+ The `musalce-server` command starts the live coding server:
56
+
57
+ ```bash
58
+ musalce-server <daw>
59
+ ```
60
+
61
+ Where `<daw>` is one of:
62
+ - `bitwig` - for Bitwig Studio
63
+ - `live` - for Ableton Live
64
+
65
+ Examples:
66
+
67
+ ```bash
68
+ musalce-server bitwig # Start server for Bitwig Studio
69
+ musalce-server live # Start server for Ableton Live
70
+ ```
71
+
72
+ The server runs in the foreground and logs activity to the console. Use `Ctrl+C` or the `shutdown` command from the editor to stop it.
73
+
74
+ ## Running Environment
75
+
76
+ A complete MusaLCE live coding session requires **three components running simultaneously**:
77
+
78
+ 1. **Code Editor** (Visual Studio Code with MusaLCE extension)
79
+ - Where you write and execute Ruby/Musa-DSL code
80
+ - Connects to musalce-server via TCP port 1327
81
+
82
+ 2. **MusaLCE Server** (`musalce-server` command)
83
+ - Receives code from the editor and executes it
84
+ - Communicates with the DAW via OSC
85
+ - Manages MIDI routing and the Musa-DSL sequencer
86
+
87
+ 3. **DAW** (Bitwig Studio or Ableton Live)
88
+ - With the corresponding MusaLCE controller extension loaded
89
+ - Receives transport and sync commands from the server
90
+ - Routes MIDI from the server to instruments/tracks
91
+
92
+ ## Architecture
93
+
94
+ The MusaLCE system connects three components:
95
+
96
+ ```
97
+ ┌─────────────────────┐ TCP ┌─────────────────────┐
98
+ │ Code Editor │◄──────────────────►│ MusaLCE Server │
99
+ │ (VSCode + Plugin) │ port 1327 │ (Ruby + REPL) │
100
+ └─────────────────────┘ └─────────────────────┘
101
+ │ ▲
102
+ OSC │ │ OSC
103
+ port 10001 │ │ port 11011
104
+ ▼ │
105
+ ┌─────────────────────┐
106
+ │ DAW Controller │
107
+ │ Extension │
108
+ │ (Bitwig or Live) │
109
+ └─────────────────────┘
110
+
111
+ │ MIDI
112
+
113
+ ┌─────────────────────┐
114
+ │ DAW Tracks & │
115
+ │ Instruments │
116
+ └─────────────────────┘
117
+ ```
118
+
119
+ ### Communication Ports
120
+
121
+ | Port | Protocol | Direction | Purpose |
122
+ |------|----------|-----------|---------|
123
+ | 1327 | TCP | Editor ↔ Server | REPL code execution |
124
+ | 10001 | OSC/UDP | Server → DAW | Transport commands, sync requests |
125
+ | 11011 | OSC/UDP | DAW → Server | Track info, controller registration |
126
+
127
+ ## REPL Commands Reference
128
+
129
+ The following commands are available in the REPL context (executed from your editor):
130
+
131
+ ### DAW Access
132
+
133
+ ```ruby
134
+ daw # Access the DAW controller object
135
+ daw.sequencer # Access the Musa-DSL sequencer
136
+ daw.clock # Access the MIDI clock
137
+ daw.transport # Access the transport (callbacks survive Stop/Play)
138
+ daw.tracks # Access all tracks
139
+ daw.surface # Access the control surface (Stream Deck, etc.)
140
+ ```
141
+
142
+ #### Persistent actions across DAW Stop/Play
143
+
144
+ Every DAW Stop wipes the sequencer (`at`, `every`, `play`, `on :event`
145
+ handlers are all cleared by the built-in `transport.after_stop { sequencer.reset }`).
146
+ Top-level Ruby state (methods, modules, constants) survives, but
147
+ anything you scheduled or subscribed to via the sequencer DSL does
148
+ not. To re-install those on every Play, register an `on_start`
149
+ callback on the transport:
150
+
151
+ ```ruby
152
+ daw.transport.on_start do
153
+ load 'persistent_actions.rb' # rehydrate on :event, every, at, …
154
+ end
155
+ ```
156
+
157
+ `on_start` callbacks accumulate (they're an append-only list), so you
158
+ can register more from the REPL at any time. They run on every Start,
159
+ after the built-in `before_begin`. Use `before_begin` instead if you
160
+ want a callback that runs **only on the very first Start** of the
161
+ session.
162
+
163
+
164
+ ### Track Operations
165
+
166
+ ```ruby
167
+ # Get a track by name
168
+ bass = daw.track('Bass')
169
+
170
+ # Get all tracks with a name (Live only, can have duplicates)
171
+ drums = daw.track('Drums', all: true)
172
+
173
+ # Send MIDI to a track
174
+ bass.out.note(60, velocity: 100, duration: 1)
175
+ bass.out.note_on(60, 100)
176
+ bass.out.note_off(60)
177
+ bass.out.control_change(1, 64)
178
+ bass.out.program_change(5)
179
+ bass.out.all_notes_off
180
+ ```
181
+
182
+ ### Transport Controls
183
+
184
+ Transport controls send commands to the DAW. **Only available for Bitwig Studio** (Live's MIDI Remote Script API doesn't support transport control).
185
+
186
+ ```ruby
187
+ daw.play # Start playback
188
+ daw.stop # Stop playback
189
+ daw.continue # Continue from current position
190
+ daw.goto(5) # Go to bar 5
191
+ daw.record # Start recording
192
+ ```
193
+
194
+ ### Sequencer (Musa-DSL)
195
+
196
+ All [Musa-DSL](https://github.com/javier-sy/musa-dsl) sequencer methods are available:
197
+
198
+ ```ruby
199
+ # Schedule events at specific positions
200
+ at 1 do
201
+ bass.out.note(48, velocity: 80, duration: 0.5)
202
+ end
203
+
204
+ # Wait relative to current position
205
+ wait 2 do
206
+ bass.out.note(52, velocity: 80, duration: 0.5)
207
+ end
208
+
209
+ # Schedule repeating patterns (returns EveryControl)
210
+ pattern = every 4 do
211
+ drums.out.note(36, velocity: 100, duration: 0.25)
212
+ end
213
+
214
+ # Play a series (returns PlayControl)
215
+ serie = S(60, 62, 64, 65, 67)
216
+ melody = play serie do |note|
217
+ bass.out.note(note, velocity: 80, duration: 1)
218
+ end
219
+
220
+ # Animate values over time (returns MoveControl)
221
+ sweep = move from: 0, to: 127, duration: 4 do |value|
222
+ bass.out.control_change(1, value.to_i)
223
+ end
224
+ ```
225
+
226
+ ### Controlling Playback
227
+
228
+ The `play`, `every`, and `move` methods return control objects that allow you to stop, pause, and monitor playback:
229
+
230
+ ```ruby
231
+ # Stop a pattern or playback
232
+ pattern.stop
233
+ melody.stop
234
+
235
+ # Check status
236
+ pattern.stopped? # true if stopped
237
+ melody.paused? # true if paused
238
+
239
+ # Pause and continue (for play)
240
+ melody.pause
241
+ melody.continue
242
+
243
+ # Callback when stopped
244
+ pattern.on_stop do
245
+ puts "Pattern stopped"
246
+ end
247
+
248
+ # Callback after play completes
249
+ melody.after(2) do
250
+ puts "2 bars after melody finished"
251
+ end
252
+ ```
253
+
254
+ ### Utility Commands
255
+
256
+ ```ruby
257
+ reload # Reload DAW controller extension
258
+ daw.sync # Re-synchronize track information
259
+ daw.panic! # Send All Notes Off to all tracks
260
+ shutdown # Stop the server
261
+ ```
262
+
263
+ ### Module Import
264
+
265
+ ```ruby
266
+ # Import additional modules into the REPL context
267
+ import(MyHelperModule)
268
+ ```
269
+
270
+ ### File Require
271
+
272
+ ```ruby
273
+ # Require files relative to your editor's current file
274
+ require_relative 'my_patterns'
275
+ ```
276
+
277
+ ## DAW-Specific Notes
278
+
279
+ ### Bitwig Studio
280
+
281
+ Requires [MusaLCE for Bitwig](https://github.com/javier-sy/MusaLCEforBitwig) controller extension.
282
+
283
+ - Full transport control support (play, stop, continue, goto, record)
284
+ - Track names must be unique
285
+ - MIDI clock sync from any controller marked as clock source
286
+ - Controllers and channels configured in the Bitwig extension
287
+
288
+ ### Ableton Live
289
+
290
+ Requires [MusaLCE for Live](https://github.com/javier-sy/MusaLCEforLive) MIDI Remote Script.
291
+
292
+ - **No transport control** (Live's MIDI Remote Script API limitation)
293
+ - Multiple tracks can have the same name
294
+ - Use `daw.midi_sync('Device Name')` to set MIDI clock source
295
+ - Track routing configured in Live's preferences
296
+
297
+ ```ruby
298
+ # Set MIDI clock source for Live
299
+ daw.midi_sync('IAC Driver Bus 1')
300
+ ```
301
+
302
+ ## Related Projects
303
+
304
+ | Component | Description |
305
+ | --- | --- |
306
+ | [Musa-DSL](https://github.com/javier-sy/musa-dsl) | Core music composition DSL |
307
+ | [MusaLCE Server](https://github.com/javier-sy/musalce-server) | Live coding server (this gem) |
308
+ | [MusaLCE for Bitwig](https://github.com/javier-sy/MusaLCEforBitwig) | Bitwig Studio controller extension |
309
+ | [MusaLCE for Live](https://github.com/javier-sy/MusaLCEforLive) | Ableton Live MIDI Remote Script |
310
+ | [MusaLCE Client for VSCode](https://github.com/javier-sy/MusaLCEClientForVSCode) | VSCode extension (recommended) |
311
+ | [MusaLCE Client for Atom](https://github.com/javier-sy/MusaLCEClientForAtom) | Atom plugin (discontinued) |
12
312
 
13
313
  ## Documentation
14
- **TODO**
314
+
315
+ API documentation is available via YARD:
316
+
317
+ ```bash
318
+ bundle exec yard doc
319
+ bundle exec yard server
320
+ ```
321
+
322
+ Then open http://localhost:8808 in your browser.
15
323
 
16
324
  ## Author
17
325
 
@@ -19,4 +327,4 @@ Musa-DSL Live Coding Environment for Ableton Live and Bitwig Studio (Server part
19
327
 
20
328
  ## License
21
329
 
22
- [MusaLCE-Server](https://github.com/javier-sy/MusaLCE-Server) Copyright (c) 2021-2023 [Javier Sánchez Yeste](https://yeste.studio), licensed under GPL 3.0 License
330
+ [MusaLCE Server](https://github.com/javier-sy/musalce-server) Copyright (c) 2021-2026 [Javier Sánchez Yeste](https://yeste.studio), licensed under GPL 3.0 License
@@ -0,0 +1,242 @@
1
+ # MusaLCE Suite Architecture
2
+
3
+ This document is the canonical reference for the **suite workflow** of MusaLCE — running [musalce-server](https://github.com/javier-sy/musalce-server) together with the per-DAW extension to drive Bitwig Studio or Ableton Live from a code editor in real time, optionally with Stream Deck integration through [Pulso](https://github.com/javier-sy/pulso).
4
+
5
+ It is a companion to (not a replacement for) the lower-level [musa-dsl REPL subsystem doc](https://github.com/javier-sy/musa-dsl/blob/master/docs/subsystems/repl.md), which covers the **standalone REPL** workflow (case 1). The suite documented here is **internally a specialization** of that case — `musalce-server` opens `Musa::REPL::REPL.new(binding)` after pre-building the sequencer, clock, transport, DAW handler and surface, so you don't have to.
6
+
7
+ ## When to use this (vs the standalone REPL)
8
+
9
+ | Use this (suite) | Use the standalone REPL |
10
+ |---|---|
11
+ | Target is Bitwig Studio or Ableton Live | Target is SuperCollider, Max/MSP, OSC apps, custom hardware |
12
+ | You want `daw.*`, `surface[:event]` and DAW transport out of the box | You want full control over the wiring |
13
+ | You want Stream Deck integration via Pulso (Bitwig only today) | You're prototyping a personal live-coding DSL |
14
+ | Worked example: `_demo-13b-live-coding-suite` (planned) | Worked example: [`_demo-13-live-coding`](https://github.com/javier-sy/musadsl-demo) |
15
+
16
+ Both workflows use the same [MusaLCEClientForVSCode](https://github.com/javier-sy/MusaLCEClientForVSCode) extension; the extension does not know or care which server is on the other end of TCP/1327.
17
+
18
+ ## The big picture
19
+
20
+ ```
21
+ ┌────────────────────────────┐
22
+ │ Stream Deck plugin │
23
+ │ (Pulso Workflow .sdPlugin) │
24
+ └─────────────┬──────────────┘
25
+ │ OSC over UDP (Pulso wire)
26
+
27
+ ┌────────────────────┐ TCP 1327 ┌──────────────────┐ ┌─────────────────────────┐ ┌──────────────────┐
28
+ │ VSCode + │ ◀──────────▶ │ musalce-server │ ─────▶ │ MusaLCEforBitwig │ ◀────▶ │ Bitwig Studio │
29
+ │ MusaLCEClient │ (REPL) │ (Ruby gem) │ │ + Pulso Bridge relay │ └──────────────────┘
30
+ │ ForVSCode │ │ │ UDP └─────────────────────────┘
31
+ └────────────────────┘ │ • REPL │ OSC OR
32
+ │ • Sequencer │
33
+ │ • DAW handler │ ─────▶ ┌─────────────────────────┐ ┌──────────────────┐
34
+ │ • Surface │ │ MusaLCEforLive │ ◀────▶ │ Ableton Live │
35
+ │ • MIDI out │ │ (Python) │ └──────────────────┘
36
+ └──────────────────┘ └─────────────────────────┘
37
+ ```
38
+
39
+ Two parallel OSC contracts cross the server ↔ extension boundary:
40
+
41
+ - **Handler protocol** — `/musalce4bitwig/*` or `/musalce4live/*` plus a common `/hello`, `/version`, `/reload`. Carries DAW control (transport, track sync, channels). Documented [below](#osc-handler-protocol).
42
+ - **Surface protocol** — `/musalce/surface/*`. Carries Stream Deck control state (inventory, triggers, state propagation). [Single source of truth in pulso/docs/osc-protocol.md](https://github.com/javier-sy/pulso/blob/main/docs/osc-protocol.md). Bitwig only today; Live side not implemented.
43
+
44
+ ## Component responsibilities
45
+
46
+ | Component | Repo | Role | Language |
47
+ |---|---|---|---|
48
+ | **musa-dsl** | [musa-dsl](https://github.com/javier-sy/musa-dsl) | The composition framework: series, sequencer, neumas, transport, REPL primitive. | Ruby |
49
+ | **musalce-server** | [musalce-server](https://github.com/javier-sy/musalce-server) | Packages the REPL + sequencer + per-DAW handler + surface into a single command (`musalce-server bitwig\|live`). | Ruby |
50
+ | **MusaLCEforBitwig** | [MusaLCEforBitwig](https://github.com/javier-sy/MusaLCEforBitwig) | Bitwig controller extension; bridges Bitwig and musalce-server over OSC, includes the `MusaLCESurfaceRelay` for Pulso. | Java (Bitwig Extension API 18) |
51
+ | **MusaLCEforLive** | [MusaLCEforLive](https://github.com/javier-sy/MusaLCEforLive) | Ableton Live MIDI Remote Script; bridges Live and musalce-server over OSC. Inherits `/live/*` from AbletonOSC. | Python |
52
+ | **MusaLCEClientForVSCode** | [MusaLCEClientForVSCode](https://github.com/javier-sy/MusaLCEClientForVSCode) | VSCode extension that is a REPL client over TCP/1327. | TypeScript |
53
+ | **Pulso Bridge** *(optional)* | [pulso](https://github.com/javier-sy/pulso) | Bitwig controller that bridges between MusaLCEforBitwig (Surface relay side) and the Stream Deck plugin. | Java |
54
+
55
+ ## REPL DSL surface (`daw.*`)
56
+
57
+ The DSL context exposed in the REPL of the suite workflow extends what's available in the standalone REPL with a `daw` accessor. Quick reference (full reference: [musalce-server README → REPL Commands Reference](https://github.com/javier-sy/musalce-server#readme)):
58
+
59
+ | Accessor | Returns | What it's for |
60
+ |---|---|---|
61
+ | `daw` | `Daw` (Bitwig or Live subclass) | Root entry point |
62
+ | `daw.sequencer` | `Musa::Sequencer::Sequencer` | The sequencer, also the implicit DSL host |
63
+ | `daw.clock` | `Musa::Clock::InputMidiClock` | The MIDI clock |
64
+ | `daw.transport` | `Musa::Transport::Transport` | The transport. Exposes `on_start`/`after_stop`/`before_begin` for callbacks that survive Stop/Play (since v0.7.2). |
65
+ | `daw.tracks` | DAW-specific | Track collection (`daw.track('Name')`) |
66
+ | `daw.surface` | `Surface` | Stream Deck / hardware surface object — `surface[:event]` (see below) |
67
+ | `daw.play`, `daw.stop`, `daw.continue`, `daw.goto(bar)`, `daw.record` | — | Transport remote control. **Bitwig only** (Live API limitation). |
68
+ | `daw.panic!` | — | All-notes-off to every track |
69
+
70
+ ## `surface[:event]` DSL — Stream Deck integration
71
+
72
+ A *Surface* control is named by an **event Symbol** that doubles as the identifier the sequencer uses when dispatching from a physical control. The surface is registered by the Pulso Bridge (via the inventory protocol — see [pulso/docs/osc-protocol.md](https://github.com/javier-sy/pulso/blob/main/docs/osc-protocol.md)); the server **owns the state** (message, enabled, value, range) and propagates changes outbound.
73
+
74
+ There are three control types: **Toggle**, **Trigger** and **Encoder**.
75
+
76
+ ### Trigger — momentary
77
+
78
+ ```ruby
79
+ # In score code:
80
+ surface[:launch_chorus].set(message: "Chorus")
81
+
82
+ on :launch_chorus do |payload|
83
+ puts "Stream Deck button fired (#{payload.inspect})"
84
+ # ... schedule the chorus section ...
85
+ end
86
+ ```
87
+
88
+ A Trigger has no persistent state beyond an optional `message`. Pressing the Stream Deck button reaches the `on :launch_chorus do |payload| … end` handler through the sequencer's event dispatch.
89
+
90
+ ### Toggle — three-state (Action / Ready / Idle)
91
+
92
+ ```ruby
93
+ surface[:mode].set(message: "Verse", enabled: true)
94
+
95
+ on :mode do |payload|
96
+ if surface[:mode].enabled
97
+ surface[:mode].enabled = false
98
+ # ... toggle off behaviour ...
99
+ else
100
+ surface[:mode].enabled = true
101
+ # ... toggle on behaviour ...
102
+ end
103
+ end
104
+ ```
105
+
106
+ `enabled` accepts `true` / `false` / `:inactive` — Pulso paints the three states with distinct palettes (Action / Ready / Idle).
107
+
108
+ ### Encoder — integer with range
109
+
110
+ ```ruby
111
+ surface[:tempo].set(value: 120, range: [60, 200], message: "BPM")
112
+
113
+ on :tempo do |payload|
114
+ new_value = payload[:value].to_i
115
+ surface[:tempo].value = new_value
116
+ # ... apply tempo change ...
117
+ end
118
+ ```
119
+
120
+ The encoder owns its `value` (an integer) and its `range` (min, max integers). State propagates back to the Stream Deck plugin so the key/dial repaints.
121
+
122
+ ## Stop/Play semantics
123
+
124
+ The server registers exactly one built-in callback on the transport:
125
+
126
+ ```ruby
127
+ transport.after_stop { sequencer.reset }
128
+ ```
129
+
130
+ `sequencer.reset` (`musa-dsl/sequencer/base-sequencer.rb`) wipes:
131
+
132
+ - `@timeslots` — all `at`-scheduled events
133
+ - `@everying` — all `every` loops
134
+ - `@playing` — all `play` operations
135
+ - `@moving` — all `move` operations
136
+ - `@event_handlers` — **all `on :event` handlers**
137
+
138
+ What survives a Stop/Play cycle:
139
+
140
+ | | Survives Stop? |
141
+ |---|---|
142
+ | Top-level Ruby (`def`, constants, modules) | ✅ (Ruby process is alive) |
143
+ | `daw.*` (sequencer, transport, tracks, surface) | ✅ (instance state of `Daw`) |
144
+ | `surface[:event]` **control declarations** | ✅ (live on `@surface`) |
145
+ | `surface[:event]` **handler blocks** (`on :event do … end`) | ❌ (wiped with `@event_handlers`) |
146
+ | `at`, `every`, `play`, `move` | ❌ |
147
+
148
+ **Asymmetry warning**: the Stream Deck button keeps painting after a Stop, but pressing it dispatches to a handler that is no longer registered — silence.
149
+
150
+ ### Rehydration pattern
151
+
152
+ Use `daw.transport.on_start` (exposed since v0.7.2 — see [musalce-server commit `fb8480f`](https://github.com/javier-sy/musalce-server/commit/fb8480f)) to re-install handlers and schedules on every Play:
153
+
154
+ ```ruby
155
+ daw.transport.on_start do
156
+ load 'persistent_actions.rb' # re-establishes on :event, every, at, …
157
+ end
158
+ ```
159
+
160
+ `on_start` callbacks accumulate (append-only list), so you can register more from the REPL at any time. Use `before_begin` for callbacks that should run **only on the first Start of the session**, and `after_stop` for cleanup (e.g. `voices.panic`).
161
+
162
+ ## OSC handler protocol
163
+
164
+ Two unidirectional channels, both UDP:
165
+
166
+ - **server listens** on `127.0.0.1:11011` (extension → server)
167
+ - **server sends** to `127.0.0.1:10001` (server → extension)
168
+
169
+ Both ports are **hardcoded** on the server side (`musalce-server/lib/daw.rb`). The DAW extensions match these defaults.
170
+
171
+ ### Common addresses (both DAWs)
172
+
173
+ | Direction | Address | Args | Purpose |
174
+ |---|---|---|---|
175
+ | ext → server | `/hello` | — | Extension announces itself on init. Server replies with `/version` + a per-DAW sync request. |
176
+ | server → ext | `/version` | `s` (VERSION) | Server announces its gem version. Extension can refuse to talk to incompatible versions. |
177
+ | server → ext | `/reload` | — | Asks the extension to reset and re-sync (used by `reload` REPL command). |
178
+
179
+ ### Bitwig-specific (`/musalce4bitwig/*`)
180
+
181
+ | Direction | Address | Args | Purpose |
182
+ |---|---|---|---|
183
+ | server → ext | `/musalce4bitwig/sync` | — | Ask the extension to re-emit controllers + channels. |
184
+ | server → ext | `/musalce4bitwig/play` | — | Bitwig transport play. |
185
+ | server → ext | `/musalce4bitwig/stop` | — | Bitwig transport stop. |
186
+ | server → ext | `/musalce4bitwig/continue` | — | Bitwig transport continue. |
187
+ | server → ext | `/musalce4bitwig/goto` | `d` (position in beats from bar 1) | Move playhead. |
188
+ | server → ext | `/musalce4bitwig/record` | — | Toggle record. |
189
+ | ext → server | `/musalce4bitwig/controllers` | `s s s …` (names) | Register all controllers in Bitwig. |
190
+ | ext → server | `/musalce4bitwig/controller` | `s s i` (name, port_name, is_clock 0/1) | Register a single controller. |
191
+ | ext → server | `/musalce4bitwig/controller/update` | `s s s i` (old_name, new_name, port_name, is_clock) | Rename / update a controller. |
192
+ | ext → server | `/musalce4bitwig/channels` | `s i i …` (controller_name, channels…) | Register channels for a controller. |
193
+
194
+ ### Live-specific (`/musalce4live/*`)
195
+
196
+ | Direction | Address | Args | Purpose |
197
+ |---|---|---|---|
198
+ | server → ext | `/musalce4live/tracks` | — | Ask the script to re-emit the track registry. |
199
+ | ext → server | `/musalce4live/tracks` | bulk (sliced 10) | Bulk track registry dump. |
200
+ | ext → server | `/musalce4live/track/name` | bulk (sliced 2) | Track names. |
201
+ | ext → server | `/musalce4live/track/midi` | bulk (sliced 3) | MIDI track metadata. |
202
+ | ext → server | `/musalce4live/track/audio` | bulk (sliced 3) | Audio track metadata. |
203
+ | ext → server | `/musalce4live/track/routings` | bulk (sliced 5) | Routing metadata. |
204
+
205
+ ### `/live/*` — inherited from AbletonOSC (Live only)
206
+
207
+ MusaLCEforLive inherits the full `/live/*` surface from [ideoforms/AbletonOSC](https://github.com/ideoforms/AbletonOSC) — dozens of endpoints covering volume, pan, send, clip control, devices, etc. These are not MusaLCE-specific and are not documented here; see the upstream README for the full address list.
208
+
209
+ ## Surface protocol — Stream Deck via Pulso (Bitwig only)
210
+
211
+ The protocol carrying surface inventory, triggers and state between musalce-server, MusaLCEforBitwig (`MusaLCESurfaceRelay`) and the Pulso Bridge is documented end-to-end in [pulso/docs/osc-protocol.md → MusaLCE surface relay](https://github.com/javier-sy/pulso/blob/main/docs/osc-protocol.md#musalce-surface-relay).
212
+
213
+ Quick summary of address space:
214
+
215
+ - `/musalce/surface/inventory/{begin,add,remove,end}` — surface inventory (Pulso → server)
216
+ - `/musalce/surface/trigger event payload` — Pulso → server, dispatched to `on :event` via `@sequencer.launch`
217
+ - `/musalce/surface/state/{message,enabled,value,range} event …` — server → Pulso, repaints the Stream Deck
218
+ - `/musalce/surface/sync_request`, `/musalce/surface/state_request` — handshake messages
219
+
220
+ In the suite the relay is implemented on the Bitwig side only (`MusaLCEforBitwig/.../MusaLCESurfaceRelay.java`). **There is no Live-side relay yet** — Stream Deck integration is Bitwig-only at the time of writing.
221
+
222
+ ## Current versions
223
+
224
+ | Component | Version |
225
+ |---|---|
226
+ | musa-dsl | 0.42.7+ |
227
+ | musalce-server | 0.7.2 |
228
+ | MusaLCEforBitwig | from `git describe` (typically `0.x`) |
229
+ | MusaLCEforLive | (no semver published) |
230
+ | MusaLCEClientForVSCode | 0.1.0 |
231
+ | Pulso Bridge | 0.x (see pulso/docs/osc-protocol.md changelog) |
232
+ | Pulso Workflow (Stream Deck plugin) | matches Bridge |
233
+
234
+ Stay on the same release branch across components — pin musalce-server in your `Gemfile.lock`, build the matching `.bwextension`/Remote Script from the same point in time. There's no semantic compatibility matrix today; protocol changes are coordinated across components by commit (see e.g. the simultaneous `id → event` rename in musalce-server `346fe51` ↔ pulso `0c6536f` ↔ MusaLCEforBitwig `33e4d7c`).
235
+
236
+ ## Where to go next
237
+
238
+ - Reference the **standalone REPL** workflow: [musa-dsl/docs/subsystems/repl.md](https://github.com/javier-sy/musa-dsl/blob/master/docs/subsystems/repl.md).
239
+ - Reference the **REPL commands** (`daw.*`, transport controls, sequencer DSL) of the suite: [musalce-server README](https://github.com/javier-sy/musalce-server#readme).
240
+ - Configure the **DAW extensions**: [MusaLCEforBitwig README](https://github.com/javier-sy/MusaLCEforBitwig#readme), [MusaLCEforLive README](https://github.com/javier-sy/MusaLCEforLive#readme).
241
+ - Wire the **VSCode editor**: [MusaLCEClientForVSCode README](https://github.com/javier-sy/MusaLCEClientForVSCode#readme).
242
+ - Wire the **Stream Deck** (Bitwig only): [Pulso README](https://github.com/javier-sy/pulso#readme) + [OSC protocol](https://github.com/javier-sy/pulso/blob/main/docs/osc-protocol.md).