musalce-server 0.5.1 → 0.8.1
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 +4 -4
- data/.github/workflows/notify-plugin.yml +17 -0
- data/.gitignore +3 -0
- data/.version +6 -0
- data/.yardopts +6 -0
- data/README.md +307 -10
- data/docs/architecture.md +178 -0
- data/lib/bitwig/bitwig.rb +32 -0
- data/lib/bitwig/controllers.rb +93 -0
- data/lib/bitwig/handler.rb +30 -0
- data/lib/bitwig/tracks.rb +46 -0
- data/lib/daw.rb +193 -4
- data/lib/live/handler.rb +14 -0
- data/lib/live/live.rb +36 -0
- data/lib/live/tracks.rb +67 -2
- data/lib/midi-devices.rb +58 -1
- data/lib/musalce-server.rb +33 -0
- data/lib/surface-bridge.rb +171 -0
- data/lib/surface.rb +369 -0
- data/lib/version.rb +13 -1
- data/musalce-server.gemspec +20 -13
- metadata +90 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f29e5cc377ccb9096005b401ae7a65f434d4d2f7793771f2c0cdf8672d649e0f
|
|
4
|
+
data.tar.gz: 3580f96bdbec2b71115b3017e415cfa0cb9dea5a9edb035d86861732a6cd7e65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '01695aeb27c2c3731c474c8a2c610a6d9f7957e203d7dc38b09063aaebb2f899e211fb090c7674619bd7e195ff11c8acae788208bb313603d5907dbd82a9cecd'
|
|
7
|
+
data.tar.gz: 0ee19cbbc2347b90dcf811362e2c01b76eda7a2824ecc35116ab3be09a465f6f9328262fb6b9648a27d914a080115bc298ae446bdb27c0fea9d9622ed6f983ba
|
|
@@ -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
data/.version
ADDED
data/.yardopts
ADDED
data/README.md
CHANGED
|
@@ -1,17 +1,314 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MusaLCE Server Suite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.ruby-lang.org/)
|
|
4
|
+
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
|
4
5
|
|
|
5
|
-
**
|
|
6
|
+
**Musa-DSL Live Coding Environment Server Suite for Ableton Live 11+ and Bitwig Studio 5+**
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
##
|
|
11
|
-
**TODO**
|
|
10
|
+
## Overview
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
The MusaLCE Server Suite system allows you to write Ruby code in your editor (Visual Studio Code) 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 Suite with/inside your DAW choice (Bitwig Studio or Ableton Live)
|
|
15
|
+
2. Open your VS Code editor with the MusaLCE extension (MusaLCEforVSCode)
|
|
16
|
+
3. Write and execute Musa-DSL code interactively
|
|
17
|
+
4. The code controls MIDI instruments and transport 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) (not recommended because 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 (for Bitwig: [MusaLCE for Bitwig](https://github.com/javier-sy/MusaLCEforBitwig), for Ableton Live: [MusaLCE for Live](https://github.com/javier-sy/MusaLCEforLive))
|
|
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 and configured
|
|
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 (Ctrl+Alt+Return, Ctrl+Alt+M)
|
|
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 Server Suite 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 Musa-DSL MIDI clock
|
|
137
|
+
daw.transport # Access the Musa-DSL transport
|
|
138
|
+
daw.tracks # Access all tracks on the daw by name
|
|
139
|
+
daw.surface # Access the control surface (currently elgato Stream Deck)
|
|
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 controller doesn't support transport control by now).
|
|
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
|
+
### File Require
|
|
264
|
+
|
|
265
|
+
```ruby
|
|
266
|
+
# Require files relative to your editor's current file
|
|
267
|
+
require_relative 'my_patterns'
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Module Import
|
|
271
|
+
|
|
272
|
+
```ruby
|
|
273
|
+
# Import additional modules into the REPL context
|
|
274
|
+
import(MyHelperModule)
|
|
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 should be 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** by now
|
|
293
|
+
- Multiple tracks can have the same name
|
|
294
|
+
- Use `daw.midi_sync('MIDI 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 |
|
|
311
|
+
| [MusaLCE Client for Atom](https://github.com/javier-sy/MusaLCEClientForAtom) | Atom plugin (discontinued) |
|
|
15
312
|
|
|
16
313
|
## Author
|
|
17
314
|
|
|
@@ -19,4 +316,4 @@ Musa-DSL Live Coding Environment for Ableton Live and Bitwig Studio (Server part
|
|
|
19
316
|
|
|
20
317
|
## License
|
|
21
318
|
|
|
22
|
-
[MusaLCE
|
|
319
|
+
[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,178 @@
|
|
|
1
|
+
# MusaLCE Server Suite Architecture
|
|
2
|
+
|
|
3
|
+
This document is the canonical reference for the **musalce-server suite** — running [musalce-server](https://github.com/javier-sy/musalce-server) together with the per-DAW extension to drive Bitwig Studio ([MusaLCEforBitwig](https://github.com/javier-sy/MusaLCEforBitwig)) or Ableton Live ([MusaLCEforLive](https://github.com/javier-sy/MusaLCEforLive)) from a code editor (VSCode + [MusaLCEClientForVSCode](https://github.com/javier-sy/MusaLCEClientForVSCode)) in real time, optionally with **elgato Stream Deck** integration via **Pulso** — [yeste.studio](https://yeste.studio)'s upcoming Stream Deck workflow system for DAWs.
|
|
4
|
+
|
|
5
|
+
It is a companion to (not a replacement for) the lower-level [musa-dsl REPL component](https://github.com/javier-sy/musa-dsl/blob/master/docs/subsystems/repl.md), which covers the **standalone REPL** workflow. The **musalce-server suite** documented here is **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. It also adds the connection to the DAW (Bitwig or Ableton Live) through **MusaLCEforBitwig**/**MusaLCEforLive** and exposes a `daw.*` object to access and to control the DAW from your editor.
|
|
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 a Stream Deck wired into your score via Pulso's MusaLCE Surface integration (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 VS Code as editor and the same [MusaLCEClientForVSCode](https://github.com/javier-sy/MusaLCEClientForVSCode) editor extension. The editor extension connects to the server via TCP socket on port 1327.
|
|
17
|
+
|
|
18
|
+
## The big picture
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌────────────────────────────┐
|
|
22
|
+
│ Stream Deck plugin │
|
|
23
|
+
│ (Pulso Workflow .sdPlugin) │
|
|
24
|
+
└────────────────────────────┘
|
|
25
|
+
^
|
|
26
|
+
│ OSC over UDP (Pulso wire)
|
|
27
|
+
▼
|
|
28
|
+
┌────────────────────┐ TCP 1327 ┌──────────────────┐ ┌─────────────────────────┐ ┌──────────────────┐
|
|
29
|
+
│ VSCode + │ ◀──────────▶ │ musalce-server │ ◀────▶ │ MusaLCEforBitwig │ ◀────▶ │ Bitwig Studio │
|
|
30
|
+
│ MusaLCEClient │ (REPL) │ (Ruby gem) │ │ + Pulso Bridge relay │ └──────────────────┘
|
|
31
|
+
│ ForVSCode │ │ │ UDP └─────────────────────────┘
|
|
32
|
+
└────────────────────┘ │ • REPL │ OSC OR
|
|
33
|
+
│ • Sequencer │
|
|
34
|
+
│ • DAW handler │ ◀────▶ ┌─────────────────────────┐ ┌──────────────────┐
|
|
35
|
+
│ • Surface │ │ MusaLCEforLive │ ◀────▶ │ Ableton Live │
|
|
36
|
+
│ • MIDI out │ │ (Python) │ └──────────────────┘
|
|
37
|
+
└──────────────────┘ └─────────────────────────┘
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Two parallel OSC contracts cross the server ↔ extension boundary:
|
|
41
|
+
|
|
42
|
+
- **Handler protocol** — `/musalce4bitwig/*` or `/musalce4live/*` plus a common `/hello`, `/version`, `/reload`. Carries DAW control (transport, track sync, channels). Documented [below](#osc-handler-protocol).
|
|
43
|
+
- **Surface protocol** — `/musalce/surface/*`. Carries elgato Stream Deck control state (inventory, triggers, state propagation). The canonical Pulso-side spec will be linked here once Pulso publishes.
|
|
44
|
+
|
|
45
|
+
## Component responsibilities
|
|
46
|
+
|
|
47
|
+
| Component | Repo | Role | Language |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| **musa-dsl** | [musa-dsl](https://github.com/javier-sy/musa-dsl) | The composition framework: series, sequencer, neumas, transport, REPL primitive. | Ruby |
|
|
50
|
+
| **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 |
|
|
51
|
+
| **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) |
|
|
52
|
+
| **MusaLCEforLive** | [MusaLCEforLive](https://github.com/javier-sy/MusaLCEforLive) | Ableton Live MIDI Remote Script; bridges Live and musalce-server over OSC. | Python |
|
|
53
|
+
| **MusaLCEClientForVSCode** | [MusaLCEClientForVSCode](https://github.com/javier-sy/MusaLCEClientForVSCode) | VSCode extension that is a REPL client over TCP/1327. | TypeScript |
|
|
54
|
+
| **Pulso Bridge** *(optional)* | *public release pending* | The DAW-side component of [yeste.studio](https://yeste.studio)'s upcoming Pulso, a Stream Deck workflow system for DAWs (Bitwig today; Ableton planned). Pulso's primary scope is generic DAW control (transport, tracks, devices, browser, parameter encoders); Pulso Bridge can also relay user actions and feedback data to/from the Stream Deck through the MusaLCE Surface protocol in MusaLCEforBitwig/Live — that's the integration described in this doc. | --- |
|
|
55
|
+
|
|
56
|
+
## Accessing the DAW (`daw.*`)
|
|
57
|
+
|
|
58
|
+
**musalce-server** exposes to the user access to the daw through a `daw.*` accessor. Quick reference:
|
|
59
|
+
|
|
60
|
+
| Accessor | Returns | What it's for |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `daw` | `Daw` (Bitwig or Live subclass) | Root entry point |
|
|
63
|
+
| `daw.sequencer` | `Musa::Sequencer::Sequencer` | The sequencer, also the implicit DSL host |
|
|
64
|
+
| `daw.clock` | `Musa::Clock::InputMidiClock` | The MIDI clock |
|
|
65
|
+
| `daw.transport` | `Musa::Transport::Transport` | The transport. Exposes `on_start`/`after_stop`/`before_begin` for callbacks that survive Stop/Play (since v0.7.2). |
|
|
66
|
+
| `daw.tracks` | DAW-specific | Track collection (`daw.track('Name')`) |
|
|
67
|
+
| `daw.surface` | `Surface` | Stream Deck / hardware surface object — `surface[:event]` (see below) |
|
|
68
|
+
| `daw.play`, `daw.stop`, `daw.continue`, `daw.goto(bar)`, `daw.record` | — | Transport remote control. **Bitwig only** (Live API limitation). |
|
|
69
|
+
| `daw.panic!` | — | All-notes-off to every track |
|
|
70
|
+
|
|
71
|
+
## Stop/Play semantics
|
|
72
|
+
|
|
73
|
+
The server registers exactly one built-in callback on the transport:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
transport.after_stop { sequencer.reset }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`sequencer.reset` (`musa-dsl/sequencer/base-sequencer.rb`) wipes:
|
|
80
|
+
|
|
81
|
+
- `@timeslots` — all `at`-scheduled events
|
|
82
|
+
- `@everying` — all `every` loops
|
|
83
|
+
- `@playing` — all `play` operations
|
|
84
|
+
- `@moving` — all `move` operations
|
|
85
|
+
- `@event_handlers` — **all `on :event` handlers**
|
|
86
|
+
|
|
87
|
+
What survives a Stop/Play cycle:
|
|
88
|
+
|
|
89
|
+
| | Survives Stop? |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Top-level Ruby (`def`, constants, modules) | ✅ (Ruby process is alive) |
|
|
92
|
+
| `daw.*` (sequencer, transport, tracks, surface) | ✅ (instance state of `Daw`) |
|
|
93
|
+
| `surface[:event]` **control declarations** | ✅ (live on `@surface`) |
|
|
94
|
+
| `surface[:event]` **handler blocks** (`on :event do … end`) | ❌ (wiped with `@event_handlers`) |
|
|
95
|
+
| `at`, `every`, `play`, `move` | ❌ |
|
|
96
|
+
|
|
97
|
+
### Rehydration pattern
|
|
98
|
+
|
|
99
|
+
Use `daw.transport.on_start` to re-install handlers and schedules on every Play:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
daw.transport.on_start do
|
|
103
|
+
load 'persistent_actions.rb' # re-establishes on :event, every, at, …
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`on_start` callbacks accumulate (it's an 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`).
|
|
108
|
+
|
|
109
|
+
## Accessing the Stream Deck (`on :event` and `surface[:event]`)
|
|
110
|
+
|
|
111
|
+
In Stream Deck Pulso Workflow plugin the user has several kinds of buttons and encoders that can trigger events on the user MusaDSL code (as MusaDSL Sequencer Events with parameters). This allows the user to control the behaviour of his MusaDSL code in realtime using an elgato Stream Deck device.
|
|
112
|
+
|
|
113
|
+
The buttons and encoders are identified with a `event` name. This `event` name is the one launched on the `musalce-server` **Sequencer** and the one the user can subscribe from his code with `on :event |parameters| do ... end` commands.
|
|
114
|
+
|
|
115
|
+
Also, the user can update the visible content on the buttons and encoders on the Stream Deck device using the `surface[:event].set parameter: value, parameter: value` commands.
|
|
116
|
+
|
|
117
|
+
Pulso Bridge is aware of MusaLCEforBitwig/Live through a pair of configurable OSC ports and both coordinate the bidirectional communication between Stream Deck and MusaDSL code in the user session.
|
|
118
|
+
|
|
119
|
+
## OSC handler protocol
|
|
120
|
+
|
|
121
|
+
Two unidirectional channels, both UDP:
|
|
122
|
+
|
|
123
|
+
- **server listens** on `127.0.0.1:11011` (extension → server)
|
|
124
|
+
- **server sends** to `127.0.0.1:10001` (server → extension)
|
|
125
|
+
|
|
126
|
+
Both ports are **hardcoded** on the server side (`musalce-server/lib/daw.rb`). The DAW extensions match these defaults.
|
|
127
|
+
|
|
128
|
+
### Common addresses (both DAWs)
|
|
129
|
+
|
|
130
|
+
| Direction | Address | Args | Purpose |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| ext → server | `/hello` | — | Extension announces itself on init. Server replies with `/version` + a per-DAW sync request. |
|
|
133
|
+
| server → ext | `/version` | `s` (VERSION) | Server announces its gem version. Extension can refuse to talk to incompatible versions. |
|
|
134
|
+
| server → ext | `/reload` | — | Asks the extension to reset and re-sync (used by `reload` REPL command). |
|
|
135
|
+
|
|
136
|
+
### Bitwig-specific (`/musalce4bitwig/*`)
|
|
137
|
+
|
|
138
|
+
| Direction | Address | Args | Purpose |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| server → ext | `/musalce4bitwig/sync` | — | Ask the extension to re-emit controllers + channels. |
|
|
141
|
+
| server → ext | `/musalce4bitwig/play` | — | Bitwig transport play. |
|
|
142
|
+
| server → ext | `/musalce4bitwig/stop` | — | Bitwig transport stop. |
|
|
143
|
+
| server → ext | `/musalce4bitwig/continue` | — | Bitwig transport continue. |
|
|
144
|
+
| server → ext | `/musalce4bitwig/goto` | `d` (position in beats from bar 1) | Move playhead. |
|
|
145
|
+
| server → ext | `/musalce4bitwig/record` | — | Toggle record. |
|
|
146
|
+
| ext → server | `/musalce4bitwig/controllers` | `s s s …` (names) | Register all controllers in Bitwig. |
|
|
147
|
+
| ext → server | `/musalce4bitwig/controller` | `s s i` (name, port_name, is_clock 0/1) | Register a single controller. |
|
|
148
|
+
| ext → server | `/musalce4bitwig/controller/update` | `s s s i` (old_name, new_name, port_name, is_clock) | Rename / update a controller. |
|
|
149
|
+
| ext → server | `/musalce4bitwig/channels` | `s i i …` (controller_name, channels…) | Register channels for a controller. |
|
|
150
|
+
|
|
151
|
+
### Live-specific (`/musalce4live/*`)
|
|
152
|
+
|
|
153
|
+
| Direction | Address | Args | Purpose |
|
|
154
|
+
|---|---|---|---|
|
|
155
|
+
| server → ext | `/musalce4live/tracks` | — | Ask the script to re-emit the track registry. |
|
|
156
|
+
| ext → server | `/musalce4live/tracks` | bulk (sliced 10) | Bulk track registry dump. |
|
|
157
|
+
| ext → server | `/musalce4live/track/name` | bulk (sliced 2) | Track names. |
|
|
158
|
+
| ext → server | `/musalce4live/track/midi` | bulk (sliced 3) | MIDI track metadata. |
|
|
159
|
+
| ext → server | `/musalce4live/track/audio` | bulk (sliced 3) | Audio track metadata. |
|
|
160
|
+
| ext → server | `/musalce4live/track/routings` | bulk (sliced 5) | Routing metadata. |
|
|
161
|
+
|
|
162
|
+
## MusaLCE Surface protocol — elgato Stream Deck via Pulso's MusaLCE integration (Bitwig only)
|
|
163
|
+
|
|
164
|
+
The MusaLCE Surface protocol carries surface inventory, triggers and state between **musalce-server**, **MusaLCEforBitwig** and **Pulso Bridge**.
|
|
165
|
+
|
|
166
|
+
- `/musalce/surface/inventory/{begin,add,remove,end}` — surface inventory (Pulso → server)
|
|
167
|
+
- `/musalce/surface/trigger event payload` — Pulso → server, dispatched to `on :event` via `@sequencer.launch`
|
|
168
|
+
- `/musalce/surface/state/{message,enabled,value,range} event …` — server → Pulso, repaints the Stream Deck
|
|
169
|
+
- `/musalce/surface/sync_request`, `/musalce/surface/state_request` — handshake messages
|
|
170
|
+
|
|
171
|
+
## Where to go next
|
|
172
|
+
|
|
173
|
+
- Reference the **standalone REPL** workflow: [musa-dsl/docs/subsystems/repl.md](https://github.com/javier-sy/musa-dsl/blob/master/docs/subsystems/repl.md).
|
|
174
|
+
- Reference the **REPL commands** (`daw.*`, transport controls, sequencer DSL) of the suite: [musalce-server README](https://github.com/javier-sy/musalce-server#readme).
|
|
175
|
+
- Configure the **DAW extensions**: [MusaLCEforBitwig README](https://github.com/javier-sy/MusaLCEforBitwig#readme), [MusaLCEforLive README](https://github.com/javier-sy/MusaLCEforLive#readme).
|
|
176
|
+
- Wire the **VSCode editor**: [MusaLCEClientForVSCode README](https://github.com/javier-sy/MusaLCEClientForVSCode#readme).
|
|
177
|
+
- Wire the **Stream Deck** (Bitwig only): pending Pulso's public release.
|
|
178
|
+
|
data/lib/bitwig/bitwig.rb
CHANGED
|
@@ -4,8 +4,24 @@ require_relative 'handler'
|
|
|
4
4
|
require_relative 'controllers'
|
|
5
5
|
|
|
6
6
|
module MusaLCEServer
|
|
7
|
+
# Bitwig Studio integration module.
|
|
8
|
+
#
|
|
9
|
+
# Provides support for live coding with Bitwig Studio 5+ through
|
|
10
|
+
# the MusaLCE for Bitwig controller extension.
|
|
11
|
+
#
|
|
12
|
+
# @see https://github.com/javier-sy/MusaLCEforBitwig Controller extension
|
|
7
13
|
module Bitwig
|
|
14
|
+
# DAW controller for Bitwig Studio.
|
|
15
|
+
#
|
|
16
|
+
# Implements the {Daw} interface for Bitwig Studio, providing
|
|
17
|
+
# transport control, track management, and MIDI routing through
|
|
18
|
+
# the MusaLCE for Bitwig controller extension.
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# # Started via MusaLCEServer.run('bitwig')
|
|
22
|
+
# daw.track('Bass').out.note(60, velocity: 100, duration: 1)
|
|
8
23
|
class Bitwig < Daw
|
|
24
|
+
# @api private
|
|
9
25
|
def daw_initialize(midi_devices:, clock:, osc_server:, osc_client:, logger:)
|
|
10
26
|
super
|
|
11
27
|
|
|
@@ -17,6 +33,11 @@ module MusaLCEServer
|
|
|
17
33
|
return controllers.tracks, handler
|
|
18
34
|
end
|
|
19
35
|
|
|
36
|
+
# Retrieves a track by name.
|
|
37
|
+
#
|
|
38
|
+
# @param name [String] the track name as configured in Bitwig
|
|
39
|
+
# @param all [Boolean] if true, returns array; otherwise returns single track
|
|
40
|
+
# @return [Track, Array<Track>] the track or array containing the track
|
|
20
41
|
def track(name, all: false)
|
|
21
42
|
if all
|
|
22
43
|
[@tracks[name]]
|
|
@@ -25,26 +46,37 @@ module MusaLCEServer
|
|
|
25
46
|
end
|
|
26
47
|
end
|
|
27
48
|
|
|
49
|
+
# Starts playback in Bitwig.
|
|
50
|
+
# @return [void]
|
|
28
51
|
def play
|
|
29
52
|
@handler.play
|
|
30
53
|
super
|
|
31
54
|
end
|
|
32
55
|
|
|
56
|
+
# Stops playback in Bitwig.
|
|
57
|
+
# @return [void]
|
|
33
58
|
def stop
|
|
34
59
|
@handler.stop
|
|
35
60
|
super
|
|
36
61
|
end
|
|
37
62
|
|
|
63
|
+
# Continues playback from current position.
|
|
64
|
+
# @return [void]
|
|
38
65
|
def continue
|
|
39
66
|
@handler.continue
|
|
40
67
|
super
|
|
41
68
|
end
|
|
42
69
|
|
|
70
|
+
# Moves playhead to specified bar position.
|
|
71
|
+
# @param position [Numeric] the bar number (1-based)
|
|
72
|
+
# @return [void]
|
|
43
73
|
def goto(position)
|
|
44
74
|
@handler.goto(position)
|
|
45
75
|
super
|
|
46
76
|
end
|
|
47
77
|
|
|
78
|
+
# Starts recording in Bitwig.
|
|
79
|
+
# @return [void]
|
|
48
80
|
def record
|
|
49
81
|
@handler.record
|
|
50
82
|
super
|