livepilot 1.27.1 → 1.27.3
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.
- package/CHANGELOG.md +86 -0
- package/README.md +10 -7
- package/bin/livepilot.js +156 -37
- package/livepilot/.Codex-plugin/plugin.json +1 -1
- package/livepilot/.claude-plugin/plugin.json +1 -1
- package/livepilot/skills/livepilot-core/SKILL.md +33 -1
- package/livepilot/skills/livepilot-core/references/atlas-tool-notes.md +69 -0
- package/livepilot/skills/livepilot-core/references/overview.md +18 -11
- package/livepilot/skills/livepilot-core/references/perception.md +125 -0
- package/livepilot/skills/livepilot-devices/references/device-parameter-units.md +66 -0
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +8 -0
- package/livepilot/skills/livepilot-release/SKILL.md +1 -1
- package/livepilot/skills/livepilot-sample-engine/references/splice-tools-notes.md +56 -0
- package/livepilot/skills/livepilot-wonder/SKILL.md +6 -0
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +48 -11
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/__init__.py +181 -40
- package/mcp_server/atlas/overlays.py +46 -3
- package/mcp_server/atlas/tools.py +226 -86
- package/mcp_server/audit/checks.py +50 -22
- package/mcp_server/audit/state.py +10 -2
- package/mcp_server/audit/tools.py +27 -6
- package/mcp_server/composer/develop/apply.py +7 -7
- package/mcp_server/composer/fast/apply.py +29 -23
- package/mcp_server/composer/fast/brief_builder.py +6 -2
- package/mcp_server/composer/framework/atlas_resolver.py +16 -1
- package/mcp_server/composer/full/apply.py +40 -34
- package/mcp_server/composer/full/engine.py +66 -32
- package/mcp_server/composer/tools.py +16 -9
- package/mcp_server/connection.py +69 -10
- package/mcp_server/creative_constraints/engine.py +10 -2
- package/mcp_server/creative_constraints/tools.py +24 -7
- package/mcp_server/curves.py +30 -7
- package/mcp_server/device_forge/builder.py +40 -11
- package/mcp_server/device_forge/models.py +9 -0
- package/mcp_server/device_forge/tools.py +30 -11
- package/mcp_server/experiment/engine.py +29 -22
- package/mcp_server/experiment/tools.py +15 -5
- package/mcp_server/m4l_bridge.py +217 -62
- package/mcp_server/memory/taste_graph.py +43 -0
- package/mcp_server/memory/technique_store.py +26 -3
- package/mcp_server/memory/tools.py +62 -4
- package/mcp_server/mix_engine/critics.py +187 -30
- package/mcp_server/mix_engine/models.py +21 -1
- package/mcp_server/mix_engine/state_builder.py +87 -8
- package/mcp_server/mix_engine/tools.py +16 -4
- package/mcp_server/performance_engine/tools.py +56 -8
- package/mcp_server/persistence/base_store.py +11 -0
- package/mcp_server/persistence/project_store.py +132 -8
- package/mcp_server/persistence/taste_store.py +90 -7
- package/mcp_server/preview_studio/engine.py +40 -10
- package/mcp_server/preview_studio/models.py +40 -0
- package/mcp_server/preview_studio/tools.py +56 -12
- package/mcp_server/project_brain/arrangement_graph.py +4 -0
- package/mcp_server/project_brain/models.py +2 -0
- package/mcp_server/project_brain/role_graph.py +13 -7
- package/mcp_server/reference_engine/gap_analyzer.py +58 -3
- package/mcp_server/reference_engine/profile_builder.py +47 -4
- package/mcp_server/reference_engine/tools.py +6 -0
- package/mcp_server/runtime/execution_router.py +57 -1
- package/mcp_server/runtime/mcp_dispatch.py +22 -0
- package/mcp_server/runtime/remote_commands.py +9 -4
- package/mcp_server/runtime/tools.py +0 -1
- package/mcp_server/sample_engine/sources.py +0 -2
- package/mcp_server/sample_engine/tools.py +19 -38
- package/mcp_server/semantic_moves/mix_compilers.py +276 -51
- package/mcp_server/semantic_moves/performance_compilers.py +51 -17
- package/mcp_server/semantic_moves/resolvers.py +45 -0
- package/mcp_server/semantic_moves/sound_design_compilers.py +14 -6
- package/mcp_server/semantic_moves/tools.py +80 -2
- package/mcp_server/semantic_moves/transition_compilers.py +26 -9
- package/mcp_server/server.py +27 -25
- package/mcp_server/session_continuity/tracker.py +51 -3
- package/mcp_server/song_brain/builder.py +47 -5
- package/mcp_server/song_brain/tools.py +21 -7
- package/mcp_server/sound_design/critics.py +1 -0
- package/mcp_server/splice_client/client.py +117 -33
- package/mcp_server/splice_client/http_bridge.py +15 -3
- package/mcp_server/splice_client/quota.py +28 -0
- package/mcp_server/stuckness_detector/detector.py +8 -5
- package/mcp_server/synthesis_brain/adapters/drift.py +13 -0
- package/mcp_server/synthesis_brain/adapters/meld.py +13 -0
- package/mcp_server/tools/_analyzer_engine/sample.py +36 -10
- package/mcp_server/tools/_perception_engine.py +6 -0
- package/mcp_server/tools/agent_os.py +4 -1
- package/mcp_server/tools/analyzer.py +198 -209
- package/mcp_server/tools/arrangement.py +7 -4
- package/mcp_server/tools/automation.py +24 -4
- package/mcp_server/tools/browser.py +25 -11
- package/mcp_server/tools/clips.py +6 -0
- package/mcp_server/tools/composition.py +33 -2
- package/mcp_server/tools/devices.py +53 -53
- package/mcp_server/tools/generative.py +14 -14
- package/mcp_server/tools/harmony.py +7 -7
- package/mcp_server/tools/mixing.py +4 -4
- package/mcp_server/tools/planner.py +68 -6
- package/mcp_server/tools/research.py +20 -2
- package/mcp_server/tools/theory.py +10 -10
- package/mcp_server/tools/transport.py +7 -2
- package/mcp_server/transition_engine/critics.py +13 -1
- package/mcp_server/user_corpus/tools.py +30 -1
- package/mcp_server/wonder_mode/engine.py +82 -9
- package/mcp_server/wonder_mode/session.py +32 -10
- package/mcp_server/wonder_mode/tools.py +14 -1
- package/package.json +1 -1
- package/remote_script/LivePilot/__init__.py +21 -8
- package/remote_script/LivePilot/arrangement.py +93 -33
- package/remote_script/LivePilot/browser.py +60 -4
- package/remote_script/LivePilot/devices.py +132 -62
- package/remote_script/LivePilot/mixing.py +31 -5
- package/remote_script/LivePilot/server.py +94 -22
- package/remote_script/LivePilot/tracks.py +11 -5
- package/remote_script/LivePilot/transport.py +11 -0
- package/requirements.txt +5 -5
- package/server.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# LivePilot v1.27.
|
|
1
|
+
# LivePilot v1.27.3 — Architecture & Tool Reference
|
|
2
2
|
|
|
3
3
|
Agentic production system for Ableton Live 12. 467 tools across 56 domains. Device atlas (5264 devices, 120 enriched, 47 with aesthetic-tagged `signature_techniques`), spectral perception (M4L analyzer with 9-band FFT — sub_low / sub / low / low_mid / mid / high_mid / high / presence / air), technique memory, automation intelligence (16 curve types, 15 recipes), music theory (Krumhansl-Schmuckler, species counterpoint), generative algorithms (Euclidean rhythm, tintinnabuli, phase shift, additive process), neo-Riemannian harmony (PRL transforms, Tonnetz), MIDI file I/O, **LIVE Splice describe-a-sound + variations via captured GraphQL endpoints (v1.17)**, drum-rack pad-by-pad construction, live dead-device detection via meter sampling, role-aware Simpler defaults, session-record arrangement-automation workaround.
|
|
4
4
|
|
|
@@ -44,9 +44,16 @@ A flat tool list lets the AI press buttons. LivePilot's three layers give it con
|
|
|
44
44
|
|
|
45
45
|
This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spectrum to confirm the mud is actually reduced."
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Core-Domain Reference (~228 tools, 13 of 56 domains)
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
This section documents the 13 highest-traffic domains in prose (what each
|
|
50
|
+
tool does, when to reach for it). It is intentionally NOT exhaustive — the
|
|
51
|
+
remaining domains (sample_engine, atlas, agent_os, wonder_mode, and the rest
|
|
52
|
+
of the Creative Intelligence layer) are covered by their own domain skills
|
|
53
|
+
and by the auto-generated **[Tool Catalog](../../../../docs/manual/tool-catalog.md)**,
|
|
54
|
+
which lists all 467 tools across all 56 domains.
|
|
55
|
+
|
|
56
|
+
### Transport (showing 12 of 21) — Playback, tempo, global state, diagnostics
|
|
50
57
|
|
|
51
58
|
| Tool | What it does | Key params |
|
|
52
59
|
|------|-------------|------------|
|
|
@@ -63,7 +70,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
63
70
|
| `get_recent_actions` | Returns log of recent commands sent to Ableton (newest first) | `limit` (1-50, default 20) |
|
|
64
71
|
| `get_session_diagnostics` | Analyzes session for issues: armed tracks, solo leftovers, unnamed tracks, empty clips | — |
|
|
65
72
|
|
|
66
|
-
### Tracks (14) — Create, delete, configure, group tracks
|
|
73
|
+
### Tracks (showing 14 of 21) — Create, delete, configure, group tracks
|
|
67
74
|
|
|
68
75
|
| Tool | What it does | Key params |
|
|
69
76
|
|------|-------------|------------|
|
|
@@ -82,7 +89,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
82
89
|
| `set_group_fold` | Folds/unfolds a group track | `track_index`, `folded` (bool) |
|
|
83
90
|
| `set_track_input_monitoring` | Sets input monitoring state | `track_index`, `state` (0=In, 1=Auto, 2=Off) |
|
|
84
91
|
|
|
85
|
-
### Clips (11) — Clip lifecycle, properties, warp
|
|
92
|
+
### Clips (showing 11 of 16) — Clip lifecycle, properties, warp
|
|
86
93
|
|
|
87
94
|
| Tool | What it does | Key params |
|
|
88
95
|
|------|-------------|------------|
|
|
@@ -122,7 +129,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
122
129
|
- `velocity_deviation` — -127.0 to 127.0
|
|
123
130
|
- `release_velocity` — 0.0-127.0
|
|
124
131
|
|
|
125
|
-
### Devices (15) — Instruments, effects, racks, 12.3+ device insertion
|
|
132
|
+
### Devices (showing 15 of 42) — Instruments, effects, racks, 12.3+ device insertion
|
|
126
133
|
|
|
127
134
|
| Tool | What it does | Key params |
|
|
128
135
|
|------|-------------|------------|
|
|
@@ -142,7 +149,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
142
149
|
| `set_chain_volume` | Sets volume of a rack chain | `track_index`, `device_index`, `chain_index`, `volume` |
|
|
143
150
|
| `get_device_presets` | Lists presets for a device (audio effects, instruments, MIDI effects) | `device_name` |
|
|
144
151
|
|
|
145
|
-
### Scenes (8) — Scene management
|
|
152
|
+
### Scenes (showing 8 of 12) — Scene management
|
|
146
153
|
|
|
147
154
|
| Tool | What it does | Key params |
|
|
148
155
|
|------|-------------|------------|
|
|
@@ -180,7 +187,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
180
187
|
| `search_browser` | Searches the browser | `query` |
|
|
181
188
|
| `load_browser_item` | Loads a browser item onto a track — **`uri` MUST come from `search_browser` results, NEVER invented** | `track_index`, `uri` |
|
|
182
189
|
|
|
183
|
-
### Arrangement (20) — Timeline, recording, cue points, arrangement notes
|
|
190
|
+
### Arrangement (showing 20 of 21) — Timeline, recording, cue points, arrangement notes
|
|
184
191
|
|
|
185
192
|
| Tool | What it does | Key params |
|
|
186
193
|
|------|-------------|------------|
|
|
@@ -205,7 +212,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
205
212
|
| `jump_to_cue` | Jumps to a cue point by index | `cue_index` |
|
|
206
213
|
| `toggle_cue_point` | Creates/removes cue point at current position | — |
|
|
207
214
|
|
|
208
|
-
### Memory (8) — Technique library persistence
|
|
215
|
+
### Memory (showing 8 of 18) — Technique library persistence
|
|
209
216
|
|
|
210
217
|
| Tool | What it does | Key params |
|
|
211
218
|
|------|-------------|------------|
|
|
@@ -218,7 +225,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
218
225
|
| `memory_update` | Updates name, tags, or qualities | `technique_id`, `name`, `tags`, `qualities` |
|
|
219
226
|
| `memory_delete` | Removes technique (backs up first) | `technique_id` |
|
|
220
227
|
|
|
221
|
-
### Analyzer (38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
|
|
228
|
+
### Analyzer (showing 20 of 38) — Real-time DSP analysis (requires LivePilot Analyzer M4L device on master track)
|
|
222
229
|
|
|
223
230
|
| Tool | What it does | Key params |
|
|
224
231
|
|------|-------------|------------|
|
|
@@ -243,7 +250,7 @@ This turns "set EQ band 3 to -4 dB" into "cut 400 Hz by 4 dB, then read the spec
|
|
|
243
250
|
| `stop_scrub` | Stop preview | `track_index`, `clip_index` |
|
|
244
251
|
| `get_display_values` | Human-readable parameter values ("440 Hz", "-6 dB") | `track_index`, `device_index` |
|
|
245
252
|
|
|
246
|
-
### Automation (8) — Clip automation CRUD + intelligent curve generation
|
|
253
|
+
### Automation (showing 8 of 9) — Clip automation CRUD + intelligent curve generation
|
|
247
254
|
|
|
248
255
|
| Tool | What it does | Key params |
|
|
249
256
|
|------|-------------|------------|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Perception (Analyzer) Reference
|
|
2
|
+
|
|
3
|
+
Deep-dive detail for `mcp_server/tools/analyzer.py` tools. The tool
|
|
4
|
+
docstrings carry a trimmed operational contract (params, ranges,
|
|
5
|
+
gotchas); this file carries the full band tables, classification
|
|
6
|
+
thresholds, and historical bug context that motivated each behavior.
|
|
7
|
+
Read this before deep spectral/health-check work — the tool docstrings
|
|
8
|
+
point back here for the parts that don't change from call to call.
|
|
9
|
+
|
|
10
|
+
## `get_master_spectrum` — 9-band table
|
|
11
|
+
|
|
12
|
+
Band energies (fffb~ center frequencies shown in parens), values 0.0-1.0:
|
|
13
|
+
|
|
14
|
+
| Band | Range | Center | Use |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| sub_low | 20-60 Hz | ~35 Hz | kick fundamentals, deep sub-bass |
|
|
17
|
+
| sub | 60-120 Hz | ~85 Hz | 808s, sub-bass body |
|
|
18
|
+
| low | 120-250 Hz | ~175 Hz | bass body, warmth |
|
|
19
|
+
| low_mid | 250-500 Hz | ~350 Hz | mud zone, male vocal lows |
|
|
20
|
+
| mid | 500 Hz-1 kHz | ~700 Hz | vocal presence, snare body |
|
|
21
|
+
| high_mid | 1-2 kHz | ~1.4 kHz | consonants, pick attack |
|
|
22
|
+
| high | 2-4 kHz | ~2.8 kHz | presence, vocal intelligibility |
|
|
23
|
+
| presence | 4-8 kHz | ~5.6 kHz | cymbal definition, air of breath |
|
|
24
|
+
| air | 8-20 kHz | ~12 kHz | shimmer, sparkle |
|
|
25
|
+
|
|
26
|
+
Older `.amxd` builds (pre-v1.16) emit the legacy 8-band layout without
|
|
27
|
+
the explicit `sub_low` split — the server auto-detects band count from
|
|
28
|
+
the OSC payload and picks the right name set. Re-freeze the Max device
|
|
29
|
+
to get the 9-band resolution.
|
|
30
|
+
|
|
31
|
+
**BUG-2026-04-22#6 fix — windowed averaging.** Kick transients make
|
|
32
|
+
single snapshots swing wildly (0.45 → 0.05 → 0.16 within a bar). The
|
|
33
|
+
`window_ms` param samples the cache over a time window and mean-pools
|
|
34
|
+
instead of returning one instantaneous frame.
|
|
35
|
+
|
|
36
|
+
**BUG-2026-04-22#15 fix — sub-band resolution.** `sub_detail=True`
|
|
37
|
+
derives three finer buckets from the FluCoMa 40-band mel spectrum
|
|
38
|
+
(band 0-1 ≈ sub_deep 0-45 Hz — kick fundamental, band 2 ≈ sub_mid
|
|
39
|
+
45-60 Hz — 808 body/kick upper, band 3 ≈ sub_high 60-80 Hz — bass
|
|
40
|
+
guitar low/sub-bass crossover). Mel band edges are perceptual, not
|
|
41
|
+
linear Hz, so these are approximations tight enough for mixing
|
|
42
|
+
decisions ("is energy in the 30 Hz or 60 Hz range?"). Requires FluCoMa
|
|
43
|
+
active — omitted with `sub_detail_warning` otherwise.
|
|
44
|
+
|
|
45
|
+
## `verify_device_health` / `verify_all_devices_health`
|
|
46
|
+
|
|
47
|
+
**BUG-2026-04-22#19 fix.** `parameter_count` alone can't tell you
|
|
48
|
+
whether an AU/VST is alive — plenty of "loaded" plugins return N
|
|
49
|
+
params and silence. These tools fire a real test MIDI note and read
|
|
50
|
+
the track meter across a window (`get_track_meters(samples=N)` to
|
|
51
|
+
dodge the BUG-#7 "left=right=0 while level>0" artifact).
|
|
52
|
+
|
|
53
|
+
Common dead-device causes (surfaced in the `hint` field when
|
|
54
|
+
`alive=False`): (1) plugin waiting for preset/bank selection, (2)
|
|
55
|
+
algorithm/envelope configured for zero output, (3) wrong MIDI channel
|
|
56
|
+
or velocity curve, (4) dead VST (reinstall). Try opening the device UI
|
|
57
|
+
and auditioning manually.
|
|
58
|
+
|
|
59
|
+
`verify_all_devices_health` (BUG-2026-04-26#1 fix): audio-track
|
|
60
|
+
detection uses `has_midi_input`/`has_audio_input` from
|
|
61
|
+
`get_session_info` (earlier code checked nonexistent `is_audio_track`/
|
|
62
|
+
`type` fields, so detection silently always evaluated False).
|
|
63
|
+
Empty-track detection requires a `get_track_info` round-trip per track
|
|
64
|
+
because `get_session_info` doesn't embed per-track `devices` arrays.
|
|
65
|
+
|
|
66
|
+
## `classify_simpler_slices` — classification thresholds
|
|
67
|
+
|
|
68
|
+
Validated on "Break Ghosts 90 bpm" reference material:
|
|
69
|
+
- KICK: sub+low >= 45%, high < 40%
|
|
70
|
+
- HAT: high >= 70% AND mid < 25% (thin metal disc = no drum body)
|
|
71
|
+
- SNARE: mid >= 25% AND high >= 40% AND peak >= 0.6 (broadband loud)
|
|
72
|
+
- ghost: peak < 0.35
|
|
73
|
+
|
|
74
|
+
**Always run this before programming drum patterns on a sliced break.**
|
|
75
|
+
Slice content depends on transient detection order in the source
|
|
76
|
+
audio — slice 0 is NOT guaranteed to be a kick. Assuming drum-rack
|
|
77
|
+
convention produces wrong grooves that take iterations to diagnose.
|
|
78
|
+
|
|
79
|
+
File-path resolution order: explicit `file_path` param, then Remote
|
|
80
|
+
Script TCP (`get_simpler_file_path` via direct LOM read — most
|
|
81
|
+
reliable), then M4L bridge UDP fallback (kept registered for
|
|
82
|
+
environments where Remote Script is stale/unavailable; call
|
|
83
|
+
`reload_handlers` to refresh without a full restart).
|
|
84
|
+
|
|
85
|
+
## `add_drum_rack_pad`
|
|
86
|
+
|
|
87
|
+
**BUG-2026-04-22#1 fix** — this tool closes a gap where
|
|
88
|
+
`load_browser_item` replaced the existing chain on repeat calls and
|
|
89
|
+
`load_sample_to_simpler` couldn't address nested rack paths. It chains
|
|
90
|
+
six steps atomically: locate/auto-detect the Drum Rack, insert a chain,
|
|
91
|
+
assign the trigger note, insert an empty Simpler into the chain, native
|
|
92
|
+
`replace_sample_native` with nested addressing, Snap=0 hygiene.
|
|
93
|
+
|
|
94
|
+
## `replace_simpler_sample` / `load_sample_to_simpler`
|
|
95
|
+
|
|
96
|
+
Prefer `load_browser_item(track, uri)` when the file is browser-indexed
|
|
97
|
+
— the M4L bridge's replace path can silently keep the bootstrap
|
|
98
|
+
placeholder in some conditions (this is why both tools verify by
|
|
99
|
+
reading back the device name post-load and error if the replace didn't
|
|
100
|
+
actually take effect).
|
|
101
|
+
|
|
102
|
+
Nested addressing (`chain_index` + `nested_device_index`) is Live
|
|
103
|
+
12.4+ only (BUG-#1, 2026-04-22) — resolves at
|
|
104
|
+
`track.devices[device_index].chains[chain_index].devices[nested_device_index or 0]`,
|
|
105
|
+
which is how Drum Rack pad-by-pad construction works. The M4L bridge
|
|
106
|
+
fallback cannot resolve nested paths; only the native 12.4 path honors
|
|
107
|
+
`chain_index`.
|
|
108
|
+
|
|
109
|
+
`load_sample_to_simpler`'s bootstrap flow (used pre-12.4 or when no
|
|
110
|
+
Simpler exists yet): loads a dummy sample via the browser to force
|
|
111
|
+
Ableton to create a Simpler, replaces it with the target file, then
|
|
112
|
+
runs the same post-load hygiene/verification as `replace_simpler_sample`.
|
|
113
|
+
|
|
114
|
+
## `simpler_set_warp` / `compressor_set_sidechain` — LOM gap tools
|
|
115
|
+
|
|
116
|
+
**BUG-A2**: Python's Remote Script ControlSurface API can't reach
|
|
117
|
+
Simpler's `warping`/`warp_mode` — they live on the sample child object
|
|
118
|
+
(`SimplerDevice.sample.*`) that only Max for Live's JavaScript LiveAPI
|
|
119
|
+
can step into. Hence the M4L bridge round-trip.
|
|
120
|
+
|
|
121
|
+
**BUG-A3**: `compressor_set_sidechain`'s routing properties
|
|
122
|
+
(`sidechain_input_routing_type`/`_channel`) aren't in Compressor's
|
|
123
|
+
automatable parameter list, but Python's Remote Script reaches them
|
|
124
|
+
directly as device properties (same LOM pattern as `set_track_routing`)
|
|
125
|
+
— no M4L bridge needed here, unlike the warp case above.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Device Parameter Units Reference
|
|
2
|
+
|
|
3
|
+
Full per-device unit table for `set_device_parameter` / `batch_set_parameters`
|
|
4
|
+
(`mcp_server/tools/devices.py`). The tool docstrings carry the most
|
|
5
|
+
commonly-hit gotchas inline; this file is the complete list plus the
|
|
6
|
+
bug history that motivated the error-enrichment behavior.
|
|
7
|
+
|
|
8
|
+
## Parameter ranges are NOT always 0-1 (BUG-B4 / B9 / 2026-04-26#2)
|
|
9
|
+
|
|
10
|
+
Ableton devices use MIXED units depending on the parameter. Always read
|
|
11
|
+
the `value_string` in the response (and `min`/`max` from
|
|
12
|
+
`get_device_parameters`) before assuming 0-1 semantics:
|
|
13
|
+
|
|
14
|
+
- Auto Filter `Frequency`: 20-135 index (NOT normalized)
|
|
15
|
+
- Auto Filter Legacy `LFO Amount`: 0-30 absolute (displays as %)
|
|
16
|
+
- Auto Filter `Resonance`: 0-1.25 on legacy, 0-1 on AutoFilter2
|
|
17
|
+
- Auto Filter `Env. Modulation`: -127..+127 on legacy
|
|
18
|
+
- Compressor I (legacy): pre-2010 units (Threshold dB direct)
|
|
19
|
+
- **Compressor 2 (modern, default)**: 0-1 NORMALIZED. `Threshold 0.85 ≈
|
|
20
|
+
0 dB`, `Ratio 0.75 = 4:1`, `Release 0.16 = 30 ms`. Setting Threshold
|
|
21
|
+
to a dB value like -22 will fail. Compute normalized: `(dB + 50) / 50`
|
|
22
|
+
for typical dB→0-1 mapping, OR read the param's `value_string` after
|
|
23
|
+
a probe write.
|
|
24
|
+
- **Saturator** `Drive`, `Output`, `Threshold`, `Color *`: 0-1
|
|
25
|
+
NORMALIZED (Drive 0.5 ≈ 0 dB, Drive 0.6 ≈ +7 dB).
|
|
26
|
+
- Dynamic Tube, Vocoder: pre-2010 units
|
|
27
|
+
- EQ Three `Frequency Hi/Lo`: 50Hz-15kHz absolute
|
|
28
|
+
- Wavetable `Osc 1 Pos`: 0-1 normalized ✓
|
|
29
|
+
- Drift / Analog / Operator macros: 0-1 normalized ✓
|
|
30
|
+
- Pedal `Output`: -20..+20 dB direct
|
|
31
|
+
- Pedal `Bass / Mid / Treble`: -1..+1 direct
|
|
32
|
+
|
|
33
|
+
## Error enrichment (BUG-2026-04-26#2)
|
|
34
|
+
|
|
35
|
+
If the Remote Script rejects the value as out-of-range,
|
|
36
|
+
`set_device_parameter` fetches the parameter's actual
|
|
37
|
+
min/max/value_string and re-raises with that context inline — saves a
|
|
38
|
+
follow-up `get_device_parameters` round-trip in the agent loop after
|
|
39
|
+
every miss.
|
|
40
|
+
|
|
41
|
+
## Silent snapping (BUG #4, v1.20.2)
|
|
42
|
+
|
|
43
|
+
Quantized-enum params (e.g. Beat Repeat's "Gate" at an integer enum)
|
|
44
|
+
silently snap a caller's float request to the nearest step. Both
|
|
45
|
+
`set_device_parameter` (via the `snapped` field) and
|
|
46
|
+
`batch_set_parameters` (via `snapped_params`, tolerance 1e-5) surface
|
|
47
|
+
this so callers driving deterministic state don't mistake a snap for
|
|
48
|
+
success. `batch_set_parameters` accepts any of `parameter_index`,
|
|
49
|
+
`parameter_name`, `name`, `index`, or the legacy `name_or_index` per
|
|
50
|
+
entry (BUG-F4 / BUG-2026-04-22#3 — the sibling tools originally had
|
|
51
|
+
inconsistent schemas, so all shapes are now normalized so
|
|
52
|
+
`get_device_parameters`'s output can be fed straight back in).
|
|
53
|
+
|
|
54
|
+
## Drum Rack construction workflow (12.3+)
|
|
55
|
+
|
|
56
|
+
Shared by `insert_device`, `insert_rack_chain`, and the atomic
|
|
57
|
+
`add_drum_rack_pad` (see `perception.md` for that one's full history):
|
|
58
|
+
|
|
59
|
+
1. `insert_device(track_index, 'Drum Rack')` — create empty rack
|
|
60
|
+
2. `insert_rack_chain(track_index, device_index)` — add a chain
|
|
61
|
+
3. `set_drum_chain_note(chain_index, note=36)` — assign C1 (kick)
|
|
62
|
+
4. `insert_device(track_index, 'Simpler', device_index=rack_idx,
|
|
63
|
+
chain_index=0)` — add the instrument into that chain
|
|
64
|
+
|
|
65
|
+
On Live < 12.3, `insert_device`/`insert_rack_chain` return an error
|
|
66
|
+
suggesting `find_and_load_device` instead.
|
|
@@ -173,7 +173,7 @@ Live 12.4 introduces a new capability tier that unlocks native LOM access for sa
|
|
|
173
173
|
**Tool signatures:** unchanged. Callers do not need to detect the tier —
|
|
174
174
|
routing is transparent.
|
|
175
175
|
|
|
176
|
-
**Probe-first 12.4 surfaces in v1.27.
|
|
176
|
+
**Probe-first 12.4 surfaces in v1.27.3:**
|
|
177
177
|
- `probe_link_audio()` reports observed peer/input/routing visibility and
|
|
178
178
|
returns `manual_only`, `readable`, `routable`, or `unavailable`.
|
|
179
179
|
- `probe_stem_workflow()` reports observed callable paths and returns
|
|
@@ -27,6 +27,14 @@ If the M4L analyzer bridge is absent, critics fall back to role-based heuristics
|
|
|
27
27
|
|
|
28
28
|
For detailed frequency collision data, call `get_masking_report`. For a quick status overview without the full critic pass, call `get_mix_summary`.
|
|
29
29
|
|
|
30
|
+
Each masking entry carries `measured` and `severity_basis`: `measured=True` /
|
|
31
|
+
`severity_basis="spectral_overlap"` means `severity` came from real per-track
|
|
32
|
+
spectral data; `measured=False` / `severity_basis="role_heuristic"` means it's
|
|
33
|
+
a role-pair prior with no per-track measurement behind it. Treat
|
|
34
|
+
`measured=False` entries as low-confidence hypotheses, not verified problems —
|
|
35
|
+
solo the pair and read `get_master_spectrum` before acting on them. See
|
|
36
|
+
`livepilot-core` SKILL.md → "Response Fields You Must Check".
|
|
37
|
+
|
|
30
38
|
### Step 2 — Plan
|
|
31
39
|
|
|
32
40
|
Pick the highest-severity issue from the `issues` array. Call `plan_mix_move` with the issue data. The planner returns the smallest intervention that addresses the problem — a single parameter change, not a chain of edits.
|
|
@@ -31,7 +31,7 @@ Run this checklist EVERY time the user says "update everything", "push", "releas
|
|
|
31
31
|
Current: **467 tools across 56 domains**.
|
|
32
32
|
Spectral/analyzer (bridge-only): **38**. The remaining tool surface works without the bridge or degrades gracefully. Backed by 32 bridge commands.
|
|
33
33
|
|
|
34
|
-
Verify: `
|
|
34
|
+
Verify: `python3 scripts/sync_metadata.py --check`
|
|
35
35
|
|
|
36
36
|
Files that reference tool count:
|
|
37
37
|
- [ ] `README.md` — header ("467 tools. 56 domains"), bridge section ("38 spectral/analyzer tools require bridge")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Splice Tool Notes
|
|
2
|
+
|
|
3
|
+
Implementation history and worked examples for the Splice-facing tools
|
|
4
|
+
in `mcp_server/sample_engine/tools.py`. The tool docstrings carry the
|
|
5
|
+
operational contract (params, return shape, gating rules); this file
|
|
6
|
+
carries endpoint-capture history and full response examples.
|
|
7
|
+
|
|
8
|
+
## `get_splice_credits` — full response example (Ableton Live plan)
|
|
9
|
+
|
|
10
|
+
```json
|
|
11
|
+
{
|
|
12
|
+
"connected": true,
|
|
13
|
+
"username": "user-1367453956",
|
|
14
|
+
"plan_raw": "subscribed",
|
|
15
|
+
"plan_kind": "ableton_live",
|
|
16
|
+
"sounds_plan_id": 12,
|
|
17
|
+
"features": {"ableton_unmetered": true},
|
|
18
|
+
"credits_remaining": 80,
|
|
19
|
+
"credit_floor": 5,
|
|
20
|
+
"daily_quota": {
|
|
21
|
+
"used_today": 3, "remaining_today": 97, "daily_limit": 100,
|
|
22
|
+
"near_limit": false, "at_limit": false
|
|
23
|
+
},
|
|
24
|
+
"can_download_sample": true,
|
|
25
|
+
"download_gating": "daily_quota"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`download_gating` is `"daily_quota"` on the Ableton Live plan (the
|
|
30
|
+
100/day unmetered quota) or `"credit_floor"` on Sounds+/Creator/
|
|
31
|
+
Creator+ plans (the `CREDIT_HARD_FLOOR` protects the last 5 credits).
|
|
32
|
+
`connected: false` with zero credits means the Splice desktop app isn't
|
|
33
|
+
running or `grpcio` isn't installed.
|
|
34
|
+
|
|
35
|
+
## `splice_describe_sound` / `splice_generate_variation` — endpoint history
|
|
36
|
+
|
|
37
|
+
Both hit GraphQL operations on `surfaces-graphql.splice.com`, captured
|
|
38
|
+
via mitmproxy against Splice desktop 5.4.9 + the Sounds Plugin
|
|
39
|
+
(status: LIVE as of 2026-04-22):
|
|
40
|
+
|
|
41
|
+
- `splice_describe_sound` → `SamplesSearch` with `semantic=1` +
|
|
42
|
+
`rephrase=true`. This is the Sounds Plugin's "Describe a Sound"
|
|
43
|
+
feature — Splice's AI matches free-form descriptions like "dark
|
|
44
|
+
ambient pad with shimmer" to catalog samples.
|
|
45
|
+
- `splice_generate_variation` → `AssetSimilarSoundsQuery` (the
|
|
46
|
+
right-click "Variations" menu item). Up to 10 results, no credit
|
|
47
|
+
cost — despite the tool name, this is a similarity-recommender
|
|
48
|
+
lookup, not AI audio synthesis (the "generate" naming in the original
|
|
49
|
+
handoff spec was aspirational).
|
|
50
|
+
|
|
51
|
+
Both tools strip the raw GraphQL response before returning (~270KB of
|
|
52
|
+
noise per call) — only the flattened sample list ships back.
|
|
53
|
+
|
|
54
|
+
`splice_search_with_sound` was removed 2026-04-22 — the user does this
|
|
55
|
+
in-Splice manually. The capture recipe for resurrecting it is at
|
|
56
|
+
`docs/2026-04-22-splice-https-capture-recipe.md`.
|
|
@@ -111,6 +111,12 @@ Wonder Mode now serves two callers:
|
|
|
111
111
|
references/move-family-diversity-rule.md)
|
|
112
112
|
- 1 executable + 2 analytical is an honest, useful result
|
|
113
113
|
- The `variant_count_actual` field tells you how many are real
|
|
114
|
+
- **Check `degraded_reason`** on every `enter_wonder_mode` response — when
|
|
115
|
+
non-empty, fewer than 3 variants are actually executable (or none matched
|
|
116
|
+
and the set is cold-start fallback). Do not present a degraded set as
|
|
117
|
+
"three genuinely different options"; surface the degradation to the user
|
|
118
|
+
in the same terms the field describes. See `livepilot-core` SKILL.md →
|
|
119
|
+
"Response Fields You Must Check".
|
|
114
120
|
|
|
115
121
|
## Presenting Results
|
|
116
122
|
|
|
Binary file
|
|
@@ -34,7 +34,7 @@ outlets = 2; // 0: to udpsend (responses), 1: to buffer~/status
|
|
|
34
34
|
// Single source of truth for the bridge version — bumped alongside the
|
|
35
35
|
// rest of the release manifest. Surfaced in the UI via messnamed("livepilot_version", ...)
|
|
36
36
|
// so the frozen .amxd visibly reports which build it was last exported from.
|
|
37
|
-
var VERSION = "1.27.
|
|
37
|
+
var VERSION = "1.27.3";
|
|
38
38
|
|
|
39
39
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
40
40
|
|
|
@@ -45,6 +45,7 @@ var pitch_history = []; // Rolling buffer for key detection
|
|
|
45
45
|
var MAX_PITCH_HISTORY = 128;
|
|
46
46
|
var detected_key = "";
|
|
47
47
|
var detected_scale = "";
|
|
48
|
+
var current_response_request_id = "";
|
|
48
49
|
|
|
49
50
|
// Capture state
|
|
50
51
|
var capture_active = false;
|
|
@@ -85,9 +86,19 @@ function anything() {
|
|
|
85
86
|
var cmd = messagename;
|
|
86
87
|
if (cmd.charAt(0) === "/") cmd = cmd.substring(1);
|
|
87
88
|
var args = _decode_arg_strings(arrayfromargs(arguments));
|
|
89
|
+
var request_id = "";
|
|
90
|
+
if (args.length > 0 && typeof args[args.length - 1] === "string") {
|
|
91
|
+
var last_arg = args[args.length - 1];
|
|
92
|
+
var request_prefix = "__livepilot_request_id:";
|
|
93
|
+
if (last_arg.indexOf(request_prefix) === 0) {
|
|
94
|
+
request_id = last_arg.substring(request_prefix.length);
|
|
95
|
+
args.pop();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
88
98
|
|
|
89
99
|
// Defer to low-priority thread for LiveAPI safety
|
|
90
100
|
var task = new Task(function() {
|
|
101
|
+
current_response_request_id = request_id;
|
|
91
102
|
try {
|
|
92
103
|
dispatch(cmd, args);
|
|
93
104
|
} catch(e) {
|
|
@@ -223,6 +234,11 @@ function cmd_get_params(args) {
|
|
|
223
234
|
|
|
224
235
|
var batch_size = 8;
|
|
225
236
|
var current = 0;
|
|
237
|
+
// Capture the request id now: read_batch reschedules itself via
|
|
238
|
+
// Task.schedule(20), and an interleaved command arriving in that gap can
|
|
239
|
+
// overwrite the module-level current_response_request_id before the final
|
|
240
|
+
// send_response fires. The closure keeps OUR id stable across batches.
|
|
241
|
+
var captured_request_id = current_response_request_id;
|
|
226
242
|
|
|
227
243
|
function read_batch() {
|
|
228
244
|
try {
|
|
@@ -246,7 +262,7 @@ function cmd_get_params(args) {
|
|
|
246
262
|
var next_task = new Task(read_batch);
|
|
247
263
|
next_task.schedule(20);
|
|
248
264
|
} else {
|
|
249
|
-
send_response({"track": track_idx, "device": device_idx, "params": params});
|
|
265
|
+
send_response({"track": track_idx, "device": device_idx, "params": params}, captured_request_id);
|
|
250
266
|
}
|
|
251
267
|
} catch (e) {
|
|
252
268
|
send_response({
|
|
@@ -254,7 +270,7 @@ function cmd_get_params(args) {
|
|
|
254
270
|
"track": track_idx,
|
|
255
271
|
"device": device_idx,
|
|
256
272
|
"partial_params": params
|
|
257
|
-
});
|
|
273
|
+
}, captured_request_id);
|
|
258
274
|
}
|
|
259
275
|
}
|
|
260
276
|
|
|
@@ -275,6 +291,9 @@ function cmd_get_hidden_params(args) {
|
|
|
275
291
|
var params = [];
|
|
276
292
|
var current = 0;
|
|
277
293
|
var batch_size = 8;
|
|
294
|
+
// See cmd_get_params: capture the request id so the closure survives the
|
|
295
|
+
// Task.schedule(20) gaps without being clobbered by an interleaved command.
|
|
296
|
+
var captured_request_id = current_response_request_id;
|
|
278
297
|
|
|
279
298
|
function read_batch() {
|
|
280
299
|
try {
|
|
@@ -307,7 +326,7 @@ function cmd_get_hidden_params(args) {
|
|
|
307
326
|
"device_name": device_name,
|
|
308
327
|
"total_params": param_count,
|
|
309
328
|
"params": params
|
|
310
|
-
});
|
|
329
|
+
}, captured_request_id);
|
|
311
330
|
}
|
|
312
331
|
} catch (e) {
|
|
313
332
|
send_response({
|
|
@@ -316,7 +335,7 @@ function cmd_get_hidden_params(args) {
|
|
|
316
335
|
"device": device_idx,
|
|
317
336
|
"device_name": device_name,
|
|
318
337
|
"partial_params": params
|
|
319
|
-
});
|
|
338
|
+
}, captured_request_id);
|
|
320
339
|
}
|
|
321
340
|
}
|
|
322
341
|
|
|
@@ -334,6 +353,9 @@ function cmd_get_auto_state(args) {
|
|
|
334
353
|
var results = [];
|
|
335
354
|
var current = 0;
|
|
336
355
|
var batch_size = 8;
|
|
356
|
+
// See cmd_get_params: capture the request id so the closure survives the
|
|
357
|
+
// Task.schedule(20) gaps without being clobbered by an interleaved command.
|
|
358
|
+
var captured_request_id = current_response_request_id;
|
|
337
359
|
|
|
338
360
|
function read_batch() {
|
|
339
361
|
try {
|
|
@@ -362,7 +384,7 @@ function cmd_get_auto_state(args) {
|
|
|
362
384
|
"total_params": param_count,
|
|
363
385
|
"automated_params": results,
|
|
364
386
|
"automated_count": results.length
|
|
365
|
-
});
|
|
387
|
+
}, captured_request_id);
|
|
366
388
|
}
|
|
367
389
|
} catch (e) {
|
|
368
390
|
send_response({
|
|
@@ -372,7 +394,7 @@ function cmd_get_auto_state(args) {
|
|
|
372
394
|
"total_params": param_count,
|
|
373
395
|
"automated_params": results,
|
|
374
396
|
"automated_count": results.length
|
|
375
|
-
});
|
|
397
|
+
}, captured_request_id);
|
|
376
398
|
}
|
|
377
399
|
}
|
|
378
400
|
|
|
@@ -689,22 +711,37 @@ function correlate(a, b) {
|
|
|
689
711
|
|
|
690
712
|
// ── Response Encoding ──────────────────────────────────────────────────────
|
|
691
713
|
|
|
692
|
-
function send_response(obj) {
|
|
693
|
-
var
|
|
714
|
+
function send_response(obj, explicit_id) {
|
|
715
|
+
var response = obj || {};
|
|
716
|
+
// Async/batched handlers (cmd_get_params et al.) capture the request id in
|
|
717
|
+
// a closure and pass it explicitly here, because the module-level
|
|
718
|
+
// current_response_request_id can be clobbered by an interleaved command
|
|
719
|
+
// that arrives during a Task.schedule() gap between batches.
|
|
720
|
+
var rid = (typeof explicit_id === "string" && explicit_id !== "")
|
|
721
|
+
? explicit_id
|
|
722
|
+
: current_response_request_id;
|
|
723
|
+
if (rid) {
|
|
724
|
+
response._livepilot_request_id = rid;
|
|
725
|
+
}
|
|
726
|
+
var json = JSON.stringify(response);
|
|
694
727
|
var encoded = base64_encode(json);
|
|
695
728
|
|
|
696
729
|
// Check if chunking needed (Max OSC packet limit ~8KB)
|
|
697
730
|
if (encoded.length < 1400) {
|
|
698
731
|
outlet(0, "/response", encoded);
|
|
699
732
|
} else {
|
|
700
|
-
// Split into chunks
|
|
733
|
+
// Split into chunks. The request id rides the chunk header (first arg)
|
|
734
|
+
// so the Python side buckets chunks per-response and never mixes two
|
|
735
|
+
// commands' chunks — the id inside the JSON can't be read until the
|
|
736
|
+
// chunks are reassembled.
|
|
701
737
|
var chunk_size = 1400;
|
|
702
738
|
var total = Math.ceil(encoded.length / chunk_size);
|
|
703
739
|
for (var i = 0; i < total; i++) {
|
|
704
740
|
var piece = encoded.substring(i * chunk_size, (i + 1) * chunk_size);
|
|
705
|
-
outlet(0, "/response_chunk", i, total, piece);
|
|
741
|
+
outlet(0, "/response_chunk", (rid || ""), i, total, piece);
|
|
706
742
|
}
|
|
707
743
|
}
|
|
744
|
+
current_response_request_id = "";
|
|
708
745
|
}
|
|
709
746
|
|
|
710
747
|
function base64_encode(str) {
|
package/mcp_server/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""LivePilot MCP Server — bridges MCP protocol to Ableton Live."""
|
|
2
|
-
__version__ = "1.27.
|
|
2
|
+
__version__ = "1.27.3"
|