@mthines/reaper-mcp 0.19.0 → 0.70.2
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/README.md +19 -570
- package/bridge-ui/mcp_bridge.html +129 -0
- package/bridge-ui/mcp_bridge.webmanifest +16 -0
- package/bridge-ui/mcp_bridge_icon_192.png +0 -0
- package/bridge-ui/mcp_bridge_icon_512.png +0 -0
- package/bridge-ui/mcp_bridge_sw.js +35 -0
- package/claude/agents/plugin-researcher.md +188 -0
- package/claude/knowledge/reference/aesthetics-scoring.md +48 -0
- package/{knowledge → claude/knowledge}/reference/common-mistakes.md +1 -1
- package/claude/knowledge/reference/lorekit-setup.md +36 -0
- package/claude/knowledge/reference/memory-protocol.md +377 -0
- package/{knowledge → claude/knowledge}/reference/metering.md +5 -5
- package/claude/knowledge/reference/perceived-loudness.md +182 -0
- package/{knowledge → claude/knowledge}/workflows/editing.md +4 -0
- package/{knowledge → claude/knowledge}/workflows/gain-staging.md +21 -23
- package/{knowledge → claude/knowledge}/workflows/learn-plugin.md +15 -48
- package/{knowledge → claude/knowledge}/workflows/master-bus.md +13 -1
- package/claude/knowledge/workflows/section-levels.md +138 -0
- package/{knowledge → claude/knowledge}/workflows/session-prep.md +4 -0
- package/claude/knowledge/workflows/transient-lighting.md +52 -0
- package/claude/skills/critique/SKILL.md +131 -0
- package/claude/skills/editing/SKILL.md +281 -0
- package/claude/skills/learn-plugin/SKILL.md +210 -0
- package/claude/skills/mastering/SKILL.md +151 -0
- package/claude/skills/mix-memory/SKILL.md +140 -0
- package/claude/skills/mixer/SKILL.md +253 -0
- package/claude/skills/new-extension/SKILL.md +324 -0
- package/main.js +7843 -1940
- package/package.json +17 -15
- package/reaper/CLAUDE.md +22 -4
- package/reaper/mcp_actions_lib.lua +375 -0
- package/reaper/mcp_analyzer.jsfx +27 -12
- package/reaper/mcp_arrange_lib.lua +949 -0
- package/reaper/mcp_bridge.lua +2321 -758
- package/reaper/mcp_edit_views_lib.lua +1378 -0
- package/reaper/mcp_envelopes_lib.lua +748 -0
- package/reaper/mcp_extensions_lib.lua +55 -0
- package/reaper/mcp_fxstate_lib.lua +144 -0
- package/reaper/mcp_gain_trace.jsfx +126 -0
- package/reaper/mcp_items_lib.lua +877 -0
- package/reaper/mcp_lufs_meter.jsfx +16 -13
- package/reaper/mcp_midi_lib.lua +555 -0
- package/reaper/mcp_mixing_lib.lua +1021 -0
- package/reaper/mcp_plan_lib.lua +801 -0
- package/reaper/mcp_prefs_lib.lua +127 -0
- package/reaper/mcp_project_lib.lua +1088 -0
- package/reaper/mcp_recording_lib.lua +595 -0
- package/reaper/mcp_render_lib.lua +492 -0
- package/reaper/mcp_snapshot_lib.lua +547 -120
- package/reaper/mcp_snapshot_next.lua +10 -4
- package/reaper/mcp_snapshot_prev.lua +11 -4
- package/reaper/mcp_snapshot_quick_save.lua +7 -32
- package/reaper/mcp_snapshots_ui_lib.lua +258 -0
- package/reaper/mcp_tracks_lib.lua +409 -0
- package/sidecar/analysis.py +661 -0
- package/sidecar/chords.py +96 -0
- package/sidecar/mixcheck.py +295 -0
- package/sidecar/requirements-chords.txt +6 -0
- package/sidecar/requirements-separation.txt +3 -0
- package/sidecar/requirements.txt +17 -0
- package/sidecar/separation.py +142 -0
- package/sidecar/server.py +622 -0
- package/sidecar/tests/test_analysis.py +249 -0
- package/sidecar/tests/test_chords.py +117 -0
- package/sidecar/tests/test_mixcheck.py +163 -0
- package/sidecar/tests/test_separation.py +73 -0
- package/sidecar/tests/test_server.py +464 -0
- package/sidecar/tests/test_verify.py +243 -0
- package/sidecar/tests/test_voice_render.py +268 -0
- package/sidecar/tests/test_voice_sketch.py +140 -0
- package/sidecar/verify.py +224 -0
- package/sidecar/voice_render.py +295 -0
- package/sidecar/voice_sketch.py +280 -0
- package/claude-agents/critique.md +0 -147
- package/claude-agents/editor.md +0 -184
- package/claude-agents/levels.md +0 -107
- package/claude-agents/mastering.md +0 -129
- package/claude-agents/mixer.md +0 -248
- package/claude-agents/preflight.md +0 -149
- package/claude-agents/producer.md +0 -159
- package/claude-agents/setup.md +0 -150
- package/claude-agents/stems.md +0 -135
- package/claude-rules/architecture.md +0 -39
- package/claude-rules/development.md +0 -54
- package/claude-rules/lua-bridge.md +0 -50
- package/claude-rules/testing.md +0 -42
- package/claude-skills/learn-plugin.md +0 -123
- package/knowledge/CLAUDE.md +0 -71
- package/knowledge/plugins/_template.md +0 -82
- package/knowledge/plugins/fabfilter/pro-c-2.md +0 -117
- package/knowledge/plugins/fabfilter/pro-l-2.md +0 -95
- package/knowledge/plugins/fabfilter/pro-q-3.md +0 -112
- package/knowledge/plugins/neural-dsp/helix-native.md +0 -104
- package/knowledge/plugins/stock-reaper/js-1175-compressor.md +0 -94
- package/knowledge/plugins/stock-reaper/rea-comp.md +0 -100
- package/knowledge/plugins/stock-reaper/rea-delay.md +0 -95
- package/knowledge/plugins/stock-reaper/rea-eq.md +0 -103
- package/knowledge/plugins/stock-reaper/rea-gate.md +0 -99
- package/knowledge/plugins/stock-reaper/rea-limit.md +0 -75
- package/knowledge/plugins/stock-reaper/rea-verb.md +0 -76
- package/knowledge/reference/perceived-loudness.md +0 -122
- package/reaper/mcp_snapshot_manager.lua +0 -1001
- /package/{knowledge → claude/knowledge}/genres/_template.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/electronic.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/hip-hop.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/metal.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/orchestral.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/pop.md +0 -0
- /package/{knowledge → claude/knowledge}/genres/rock.md +0 -0
- /package/{knowledge → claude/knowledge}/reference/compression.md +0 -0
- /package/{knowledge → claude/knowledge}/reference/frequencies.md +0 -0
- /package/{knowledge → claude/knowledge}/workflows/delivery.md +0 -0
- /package/{knowledge → claude/knowledge}/workflows/drum-bus.md +0 -0
- /package/{knowledge → claude/knowledge}/workflows/low-end.md +0 -0
- /package/{knowledge → claude/knowledge}/workflows/stem-prep.md +0 -0
- /package/{knowledge → claude/knowledge}/workflows/vocal-chain.md +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: editing
|
|
3
|
+
description: >
|
|
4
|
+
Edits a live REAPER session through the reaper MCP tools: MIDI parts (writing,
|
|
5
|
+
rewriting, quantizing, importing), arrangement (split, move, copy, insert or
|
|
6
|
+
remove time), timing and phase, crossfades and comping, voice recordings into
|
|
7
|
+
arrangements, audio stem separation, and A/B-testing variations in fixed lanes.
|
|
8
|
+
Changes notes and items, not levels or FX; use /mixer for those. Use when asked
|
|
9
|
+
to edit, rewrite, tighten, comp, change the groove, compare parts, turn humming
|
|
10
|
+
or beatboxing into music, or split a recording into stems. Triggers on "edit
|
|
11
|
+
the drums", "change the chorus", "make a variation", "A/B these takes",
|
|
12
|
+
"comp this", "tighten the timing", "compose from this recording", "turn my
|
|
13
|
+
humming into a song", "split stems", "/editing".
|
|
14
|
+
argument-hint: '[what to edit, voice recording, stems, or versions to compare]'
|
|
15
|
+
license: MIT
|
|
16
|
+
metadata:
|
|
17
|
+
author: mthines
|
|
18
|
+
version: '1.0.0'
|
|
19
|
+
workflow_type: applied
|
|
20
|
+
tags:
|
|
21
|
+
- editing
|
|
22
|
+
- midi
|
|
23
|
+
- arrangement
|
|
24
|
+
- comping
|
|
25
|
+
- reaper
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Editing
|
|
29
|
+
|
|
30
|
+
Edit the notes, items and structure of a **live** REAPER session through the
|
|
31
|
+
`reaper` MCP tools. This skill changes what plays and when. Levels, EQ,
|
|
32
|
+
compression and the master belong to `/mixer` and `/mastering`; what a sampled
|
|
33
|
+
instrument expects (note map, keyswitches) comes from `/learn-plugin`'s LoreKit
|
|
34
|
+
record. After an edit, hand the balance question to `/mixer`.
|
|
35
|
+
|
|
36
|
+
The step-by-step procedures (crossfades, phase, stretch markers, head and tail
|
|
37
|
+
cleanup, arrangement edits) are in `knowledge/workflows/editing.md`; load it for
|
|
38
|
+
audio cleanup. Voice sketches and stem separation use the workflows below, not
|
|
39
|
+
the recorded-track cleanup procedure.
|
|
40
|
+
|
|
41
|
+
## Rules that save sessions
|
|
42
|
+
|
|
43
|
+
1. **Re-list before every index-based write.** The user edits the session while
|
|
44
|
+
you work: a deleted or added track moves every index after it (this once put
|
|
45
|
+
an EQ on the wrong tracks). `list_tracks` (filtered by `parent`) or
|
|
46
|
+
`get_track_lanes` right before each batch, and target by name where it is
|
|
47
|
+
unique. Item indexes also change after every move, import or delete.
|
|
48
|
+
2. **Snapshots do not store items.** `snapshot_save` keeps faders and FX
|
|
49
|
+
parameters, so it cannot undo a MIDI or arrangement edit. Before changing
|
|
50
|
+
items, keep the original as a **take** of the item it replaces (see "Keeping
|
|
51
|
+
the original" below), or as the A lane of a lane pair. **Never mute an
|
|
52
|
+
original and leave it under or beside the new item**: overlapping muted items
|
|
53
|
+
clutter the timeline and are easy to leave muted. Delete the original only
|
|
54
|
+
when the user says the new version won.
|
|
55
|
+
3. **Keep the user's selection in mind.** `set_selected_items` and item actions
|
|
56
|
+
replace it; say so when it ends up changed.
|
|
57
|
+
4. **Validate, then write.** Check pitch range, track and item before the first
|
|
58
|
+
write. A MIDI write that fails halfway is undone by the server; a bad import
|
|
59
|
+
can still leave an item you did not want, so list items after.
|
|
60
|
+
5. **Check the instrument before writing MIDI.** A sampled instrument has note
|
|
61
|
+
ranges and keyswitch zones (Odin x Ari Lite: notes below 36 are keyswitches,
|
|
62
|
+
so music written there is silent or switches articulation). Read the plugin's
|
|
63
|
+
record (`get_builtin_knowledge`, `memory.read` of `user::plugins::…`) before
|
|
64
|
+
writing a part, and probe one note if it is unverified.
|
|
65
|
+
6. **Plugin gate — no plugin is touched before its memory is read.** Before the
|
|
66
|
+
first call that adds, sets, loads a preset for, writes MIDI to, or reads parameters
|
|
67
|
+
of a plugin (`add_fx`, `setup_fx_chain`, `set_fx_parameter`,
|
|
68
|
+
`set_multiple_fx_parameters`, `set_fx_preset`, `load_fx_chain`, MIDI for an
|
|
69
|
+
instrument track, take FX), look it up — every plugin, every time it is new to this
|
|
70
|
+
session, including ones the user named, ones already in the project and ones you
|
|
71
|
+
only meet while listing a chain. Never skip it because the plugin looks familiar.
|
|
72
|
+
Look up both layers: `list_builtin_knowledge { query: "<plugin name>" }` (or `tags:
|
|
73
|
+
["fx::<FX name>"]`) / `get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }`,
|
|
74
|
+
and `memory.search` / `memory.read` of `user::plugins::{vendor}/{plugin}` (the user's
|
|
75
|
+
record wins). Then **follow the record**: its MIDI map and note ranges, parameter
|
|
76
|
+
scaling, recommended settings and gotchas decide what you do, and a setting you were
|
|
77
|
+
about to use that the record warns against is not used. Say it in one chat line
|
|
78
|
+
("Recalled Odin x Ari Lite: notes <36 are keyswitches → transposing"). Keep a running
|
|
79
|
+
list of recalled plugins and don't re-read those. No record in either layer: say so
|
|
80
|
+
and carry on (or bootstrap it when the user asked for the plugin by name). LoreKit
|
|
81
|
+
not connected: say so once and use the built-in read only.
|
|
82
|
+
|
|
83
|
+
## Writing and rewriting MIDI
|
|
84
|
+
|
|
85
|
+
- **Fast path for a whole part:** generate one `.mid` per instrument with a node
|
|
86
|
+
script (480 PPQ, a tempo and 4/4 meta event, an end-of-track at the last bar
|
|
87
|
+
line), then `import_midi_file { path, trackIndex, position }`. Thousands of
|
|
88
|
+
`insert_midi_note` calls are far slower. The file's tempo is **not** applied:
|
|
89
|
+
set the project tempo first.
|
|
90
|
+
- **Drum maps are not General MIDI.** Check the kit's record (GGD Invasion: kick
|
|
91
|
+
R24/L23, snare 26, toms 33-38, hats 43/45, crash L52, china 65). Alternate kick
|
|
92
|
+
feet when two hits are a 16th apart.
|
|
93
|
+
- **Small changes:** `edit_midi_notes` / `insert_midi_notes` (batch),
|
|
94
|
+
`transform_midi` (transpose, velocity, humanize, length) and `quantize_midi`
|
|
95
|
+
(grid, strength, swing). Positions are in beats, velocity 1-127.
|
|
96
|
+
- **Replacing a section:** import the new section at its start time on the same
|
|
97
|
+
track, then fold old and new into one item of takes (below) until approved.
|
|
98
|
+
Imported items never overwrite existing ones.
|
|
99
|
+
- **Keeping the original (takes, never mute).** For one section replaced:
|
|
100
|
+
1. `set_selected_items` on exactly the old and new item of **one** section,
|
|
101
|
+
then `run_action 40543` ("Take: Implode items on same track into takes").
|
|
102
|
+
Do one section per call: selecting several sections at once merges them
|
|
103
|
+
all into a single item (seen live; `undo_project` reverts it). Work from
|
|
104
|
+
the highest item index down, since indexes shift after each implode.
|
|
105
|
+
2. The takes keep the lower-indexed item first. `list_takes` the item, then
|
|
106
|
+
`set_active_take` the version that should play (`takeIndex` 1 when the
|
|
107
|
+
new item came after the old one).
|
|
108
|
+
3. The imploded item can inherit the mute: `get_media_item_properties`, and if
|
|
109
|
+
`muted`, `set_media_item_properties { mute: 0 }` (the parameter is `mute`,
|
|
110
|
+
a number 0/1, not a boolean).
|
|
111
|
+
4. Switch versions later with `set_active_take`; when the user decides, delete
|
|
112
|
+
the losing take (or keep it). Take names are blank for imported items; say
|
|
113
|
+
which take is which in chat.
|
|
114
|
+
Use fixed lanes below instead when whole-song versions are compared.
|
|
115
|
+
- **Big MIDI calls can hit the 10 s bridge timeout** (seen on a 400-note
|
|
116
|
+
`transform_midi` while the user was in the session). Prefer re-importing a
|
|
117
|
+
generated file over editing hundreds of notes in place.
|
|
118
|
+
|
|
119
|
+
## Voice recordings to a playable arrangement
|
|
120
|
+
|
|
121
|
+
For "make music from this humming/beatboxing", use `transcribe_voice_sketch`.
|
|
122
|
+
Do not substitute a hand-written melody or a generic MIDI script for analyzing
|
|
123
|
+
the recording. File analysis/export does not require REAPER; importing and
|
|
124
|
+
playing the result requires a live bridge.
|
|
125
|
+
|
|
126
|
+
1. **Locate and protect the source.** Use an absolute path on the machine running
|
|
127
|
+
the MCP server. Download an attachment there first; a cloud attachment or an
|
|
128
|
+
orb path is not automatically accessible to a local server. Keep the original
|
|
129
|
+
file unchanged. Select the musical range with `startTime`/`endTime` to exclude
|
|
130
|
+
speech, count-ins and long silence, at most 120 seconds per call.
|
|
131
|
+
2. **Analyze before importing.** Start with `limit: 0` and no `outputPath` for
|
|
132
|
+
summaries, warnings, tempo and key. Use `mode: auto` for mixed humming and
|
|
133
|
+
beatboxing, `melody` for humming alone, `drums` for beatboxing alone. The core
|
|
134
|
+
sidecar is sufficient; no pitch model or Demucs install is needed. If the
|
|
135
|
+
tool is missing, check the server build/connection rather than inventing an
|
|
136
|
+
alternative implementation. Missing core setup:
|
|
137
|
+
`reaper-mcp setup-sidecar --without-aesthetics`.
|
|
138
|
+
3. **Resolve musical uncertainty.** Ordinary timing drift becomes one rounded
|
|
139
|
+
tempo. Automatic changes need two adjacent four-second windows and at least
|
|
140
|
+
20% difference by default; exact half/double-time changes remain ambiguous.
|
|
141
|
+
If the pulse is uncertain, use the user's BPM or offer short auditions of
|
|
142
|
+
plausible pulses, then rerun with `bpm` to fix the chosen tempo. Never reuse
|
|
143
|
+
a previous recording's BPM as a default. Meter is assumed 4/4 and the first
|
|
144
|
+
onset is beat zero, not a detected downbeat. Report weak key confidence or a
|
|
145
|
+
fallback key; do not force the melody into it. `key` overrides accompaniment
|
|
146
|
+
only. For missed low/short syllables, try a lower `pitchMin` or `minNoteMs`
|
|
147
|
+
down to 40, explaining the increased false-note risk. If recognition remains
|
|
148
|
+
poor, ask for a cleaner take or separate humming and beatboxing takes.
|
|
149
|
+
4. **Export the requested draft.** Use `arrange: true` for generated drums, bass,
|
|
150
|
+
chords and repeated detected melody, default 16 bars. Use `arrange: false`
|
|
151
|
+
for detected melody/percussion only. `mode` limits extraction, not the
|
|
152
|
+
generated backing parts. Backbeats, fills, chords and song
|
|
153
|
+
sections are proposals, not recovered performances. Choose a new absolute
|
|
154
|
+
`.mid` `outputPath` under an existing folder. Export includes every note
|
|
155
|
+
regardless of response pagination. With separate takes, extract each in its
|
|
156
|
+
own mode with a shared BPM/grid and combine once; do not stack two complete
|
|
157
|
+
generated backing bands. Align takes using a known cue or ask for their
|
|
158
|
+
offset; each take's first onset becomes its own beat zero.
|
|
159
|
+
5. **Set tempo before MIDI import.** Inspect `get_tempo_map` and existing items.
|
|
160
|
+
In an empty project starting at zero, apply `arrangement.tempos` for the full
|
|
161
|
+
generated score, or `tempo.segments` for transcription-only output. Use
|
|
162
|
+
`set_project_tempo` for the first BPM and `add_tempo_marker` with
|
|
163
|
+
`timeSigNumerator: 4`, `timeSigDenominator: 4`, `linear: false` at zero to
|
|
164
|
+
establish 4/4; use `linear: false` for later changes too. Convert segment
|
|
165
|
+
beats to project seconds by integrating the preceding BPM segments, not by
|
|
166
|
+
using the initial BPM throughout. Source `time`/`originSeconds` are original file times, not marker
|
|
167
|
+
positions for the exported score. Preserve an existing project's tempo map
|
|
168
|
+
by default; resolve a mismatch with the user before changing it. Then
|
|
169
|
+
`import_midi_file { path, newTracks: true, trackIndex, position }` creates one
|
|
170
|
+
named track per part. Re-list immediately before choosing `trackIndex`.
|
|
171
|
+
The importer applies neither the file tempo map nor GM program changes.
|
|
172
|
+
6. **Make it audible.** Hand instrument/FX setup to `/mixer`: choose installed
|
|
173
|
+
drum, bass, chord and lead instruments and check their knowledge records.
|
|
174
|
+
The exported drum part is GM on MIDI channel 10; verify the kit's channel
|
|
175
|
+
handling and map, then remap notes when necessary. Do not transpose all drum
|
|
176
|
+
notes as a melodic part. Check melody/bass ranges and keyswitches too. A
|
|
177
|
+
successful MIDI import is not proof of audible playback.
|
|
178
|
+
7. **Verify a short section first.** Read back the imported notes, tempo map and
|
|
179
|
+
track placement, then play a representative groove and melody for the user.
|
|
180
|
+
Check audible output through `/mixer` and ask whether the pulse, melody and
|
|
181
|
+
drum roles match the idea. Fix octaves, false notes and drum mapping before
|
|
182
|
+
polishing or extending. Keep variants in fixed lanes and compare them at a
|
|
183
|
+
shared project tempo; use separate projects or rendered WAVs for different
|
|
184
|
+
tempo maps. Report what was detected, what was generated and what is unsure.
|
|
185
|
+
|
|
186
|
+
## Stem splitting: choose the right operation
|
|
187
|
+
|
|
188
|
+
- **Mixed voice sketch:** start with `transcribe_voice_sketch` directly. Pitch
|
|
189
|
+
and percussion are analyzed independently, including overlapping events.
|
|
190
|
+
Do not run Demucs first by default. Its accuracy on humming plus beatboxing
|
|
191
|
+
is unverified; if explicitly tried, keep a direct-transcription baseline and
|
|
192
|
+
audition both before discarding anything.
|
|
193
|
+
- **Recorded band or song:** use `separate_stems` for audio source separation.
|
|
194
|
+
`htdemucs` gives drums, bass, other and vocals; `htdemucs_6s` also gives guitar
|
|
195
|
+
and piano. Neither splits kick/snare/hat. Requires the opt-in
|
|
196
|
+
`reaper-mcp setup-sidecar --with-separation`; the six-source model downloads
|
|
197
|
+
weights on first use. Explain missing dependencies/downloads before setup.
|
|
198
|
+
Choose an explicit range, at most 600 seconds, and a fresh `outDir`. A track
|
|
199
|
+
input is rendered post-FX; use its original file only when that is the wanted
|
|
200
|
+
source. Leave the source untouched and listen for bleed and artifacts before
|
|
201
|
+
relying on a separated stem.
|
|
202
|
+
- **Generated instrument WAVs:** `transcribe_voice_sketch` with `outputPath`
|
|
203
|
+
plus `soundfontPath` renders a mix and instrument stems. These are
|
|
204
|
+
resynthesized instruments, not isolated original voice audio. This optional
|
|
205
|
+
route needs local FluidSynth and the user's GM `.sf2`, with at most 240
|
|
206
|
+
seconds including release tail. Prefer MIDI plus installed instruments when
|
|
207
|
+
those dependencies are absent. A `preview.error` can accompany a successful
|
|
208
|
+
MIDI export; keep that file and do not retry the same existing output path.
|
|
209
|
+
- **Individual generated drum parts:** the tool exports one drum MIDI part and
|
|
210
|
+
one `drums.wav`, not separate kit-piece WAVs. If requested, split the generated
|
|
211
|
+
GM drum notes by pitch into kick, snare, hat and other MIDI parts before
|
|
212
|
+
instrument-specific remapping. Keep a shared origin and tempo, preserve
|
|
213
|
+
velocities, and mute the unsplit copy when playing the split parts. Separate
|
|
214
|
+
audio outputs need a verified kit-output setup or separate renders; delegate
|
|
215
|
+
that routing/render setup to `/mixer`. Never label these as isolated beatbox
|
|
216
|
+
audio.
|
|
217
|
+
|
|
218
|
+
For Demucs insertion, `insertTracks: true` creates a **muted folder**. A track's
|
|
219
|
+
stems start at `startTime`; a file's start at `filePosition + startTime`, where
|
|
220
|
+
`filePosition` is the project position of the source file's second zero. Inspect
|
|
221
|
+
returned `inserted`/`warning` and re-list tracks before retrying; files can exist
|
|
222
|
+
even if insertion failed. For generated WAVs, use `insert_audio_file` to place
|
|
223
|
+
every instrument stem at the same chosen project position. Play either the
|
|
224
|
+
source/mix or the stem set, not both. Check parent mute and solo states when a
|
|
225
|
+
stem seems silent; preserve the source and make A/B switching explicit.
|
|
226
|
+
|
|
227
|
+
## A/B-testing MIDI or arrangement variants (fixed lanes)
|
|
228
|
+
|
|
229
|
+
Use this to compare alternatives that change notes or arrangement: a drum
|
|
230
|
+
groove, a bass line, a different chorus. A snapshot cannot switch them (rule 2),
|
|
231
|
+
and a muted duplicate is easy to leave muted (so never use one; one section
|
|
232
|
+
replaced is a take, see "Keeping the original").
|
|
233
|
+
|
|
234
|
+
**One lane per complete version.** Each lane holds the whole song, so one switch
|
|
235
|
+
plays a whole version and nothing is left silent. A lane with only a changed
|
|
236
|
+
section forces the unchanged sections into another lane, and playing one lane
|
|
237
|
+
alone then silences them.
|
|
238
|
+
|
|
239
|
+
1. `set_track_lanes { track, fixedLanes: true }`: every item goes on lane 0
|
|
240
|
+
(version A). `laneCount` needs `fixedLanes: true`.
|
|
241
|
+
2. With only lane 0 playing, run action 42505 ("Track lanes: Duplicate items from
|
|
242
|
+
playing lanes to new lanes"): lane 1 starts as a full copy.
|
|
243
|
+
3. Make the change in lane 1. To bring a newly imported item in, `set_selected_items`
|
|
244
|
+
then 40068 (up one lane), 40107 (down one lane) or 42588 (bottom lane), and
|
|
245
|
+
delete the copy it replaces. Run `get_track_lanes` after each move.
|
|
246
|
+
4. Name the lanes: `names: [{ lane: 0, name: "A original" }, { lane: 1, name: "B half-time chorus" }]`
|
|
247
|
+
(objects, not strings).
|
|
248
|
+
5. **Switch:** `set_track_lanes { track, play: 1 }` plays lane 1 alone, `play: 0`
|
|
249
|
+
lane 0. A number is exclusive, an array (`play: [0, 2]`) is layered.
|
|
250
|
+
6. **Decide:** `comp_lanes` takes sections from either lane onto a new comp lane
|
|
251
|
+
(a committed copy, not a switch). Delete the losers afterwards (action 42691
|
|
252
|
+
removes lanes that are not playing, with their items).
|
|
253
|
+
|
|
254
|
+
Gotchas:
|
|
255
|
+
- Unchanged sections exist in every lane, so an edit in one lane does not reach
|
|
256
|
+
the others. Finish shared edits first, or make them in each lane.
|
|
257
|
+
- `get_track_lanes` / `set_track_lanes` take `track`, not `trackIndex`.
|
|
258
|
+
- Turning lanes off puts every item on one lane, all playing (`undo_project`
|
|
259
|
+
restores).
|
|
260
|
+
- A full A/B is a lane choice plus a mix snapshot: lanes for notes and
|
|
261
|
+
arrangement, snapshots (`/mixer`) for faders, EQ and the master.
|
|
262
|
+
- For a few-note tweak, edit in place; lanes are for whole alternatives.
|
|
263
|
+
|
|
264
|
+
## Workflow
|
|
265
|
+
|
|
266
|
+
1. **Understand** the edit and the song structure (`list_regions`, `list_markers`,
|
|
267
|
+
`get_tempo_map`). Load `workflows/editing.md` for audio editing.
|
|
268
|
+
2. **Protect:** `snapshot_save { name: "before-{task}" }` for the mix, and keep
|
|
269
|
+
the original items (rule 2).
|
|
270
|
+
3. **Re-list**, then edit (rule 1), explaining the musical reason for each change.
|
|
271
|
+
4. **Verify:** list the items and lanes again, play the changed range for the user
|
|
272
|
+
(`set_cursor_position` + `play`), and check the result with the meters through
|
|
273
|
+
`/mixer` when level or tone may have moved. Ask the user to listen: their ear
|
|
274
|
+
decides.
|
|
275
|
+
5. **Report** what changed, where the originals are, and how to switch back.
|
|
276
|
+
|
|
277
|
+
## Interpreting vague requests
|
|
278
|
+
|
|
279
|
+
"Slows down", "bigger", "less busy" can mean several things. State the reading you
|
|
280
|
+
chose (for "the groove slows down": half-time at the same tempo, not a tempo
|
|
281
|
+
change, since the other parts would have to follow) and offer the other.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: learn-plugin
|
|
3
|
+
description: Teach the mixing skills one plugin or a list of them (researched in parallel): researches each on the web, tests it live in REAPER and writes its plugin knowledge record to LoreKit, asking the user only what it couldn't work out
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /learn-plugin
|
|
7
|
+
|
|
8
|
+
This skill teaches the mixing skills a plugin. It writes the plugin's **plugin
|
|
9
|
+
knowledge record** to the user's own LoreKit layer: scope `project::reaper-mcp`,
|
|
10
|
+
key `user::plugins::{vendor}/{plugin}`, following
|
|
11
|
+
`knowledge/reference/memory-protocol.md`.
|
|
12
|
+
|
|
13
|
+
It does the work itself before asking anything. The **`plugin-researcher`**
|
|
14
|
+
agent researches the plugin on the web, loads it on a scratch track, probes its
|
|
15
|
+
parameters, and writes the record. Then this skill asks the user **only** the
|
|
16
|
+
questions the agent couldn't answer, and folds the answers in.
|
|
17
|
+
|
|
18
|
+
If an opt-in extension drives the plugin (a `list_tool_categories` category named
|
|
19
|
+
after it, e.g. `vital`), the agent reads its internals through it and tags the record
|
|
20
|
+
`extension::<name>`, so `/mixer` and `/mastering` know to use it. A plugin that hides
|
|
21
|
+
its sound in internal state and has no extension gets a one-line offer to build one
|
|
22
|
+
(`reaper-mcp extension new <name>`, see `docs/EXTENSIONS.md`).
|
|
23
|
+
|
|
24
|
+
The mixing skills use the same agent to bootstrap plugins they don't know. To
|
|
25
|
+
recall or tidy memory, use `/mix-memory`. If the `memory.*` tools are not
|
|
26
|
+
connected, do not stop at an error: read `~/.claude/knowledge/reference/lorekit-setup.md` (in a clone: `knowledge/reference/lorekit-setup.md`) and walk
|
|
27
|
+
the user through connecting LoreKit (free, a few minutes), then carry on once it is.
|
|
28
|
+
If they decline, say there is nowhere to save the record and stop.
|
|
29
|
+
|
|
30
|
+
Every learned plugin should end up in the **built-in plugin list**
|
|
31
|
+
(`docs/PLUGINS.md`). A **publisher** (writing member of the `reaper-mcp` LoreKit
|
|
32
|
+
org, e.g. the maintainer) publishes the record and updates the list in their
|
|
33
|
+
clone (Step 5). Everyone else gets it there through a contribution PR, and the
|
|
34
|
+
list updates when the maintainer publishes it.
|
|
35
|
+
|
|
36
|
+
## Trigger
|
|
37
|
+
|
|
38
|
+
The user types `/learn-plugin [plugin]`, or asks Claude to "learn about a
|
|
39
|
+
plugin", "research this plugin" or "add plugin knowledge".
|
|
40
|
+
|
|
41
|
+
## Instructions
|
|
42
|
+
|
|
43
|
+
### Step 1: Get the plugin name(s)
|
|
44
|
+
|
|
45
|
+
Take them from the arguments: one plugin, or a list (one per line, or comma
|
|
46
|
+
separated). If there are none, ask a single question:
|
|
47
|
+
|
|
48
|
+
> "Which plugin should I learn?"
|
|
49
|
+
|
|
50
|
+
If the user already said something about one (what they use it for, how they
|
|
51
|
+
set it up), keep it as caller context for that plugin in Step 2. Don't ask for
|
|
52
|
+
anything else yet.
|
|
53
|
+
|
|
54
|
+
Also check, once, whether the user is a **publisher**: `org.list`, and look for
|
|
55
|
+
the `reaper-mcp` org with a writing role (member, admin or owner). Remember the
|
|
56
|
+
answer for Steps 3 and 5. No `org.list` tool, or no such membership: not a
|
|
57
|
+
publisher.
|
|
58
|
+
|
|
59
|
+
### Step 2: Dispatch the researchers, all at once
|
|
60
|
+
|
|
61
|
+
One `plugin-researcher` per plugin, **all in the same message** so they run in
|
|
62
|
+
parallel. Even when the user says "one at a time", run them in parallel: the
|
|
63
|
+
agents are built for it, and only the questions are asked plugin by plugin.
|
|
64
|
+
Give each one a short, unique uppercase tag for its scratch track:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Agent(subagent_type: "plugin-researcher",
|
|
68
|
+
prompt: "Plugin: <exact name>\nScratch track tag: <TAG, e.g. PROQ4>\nCaller context: <anything the user said, or 'none'>")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Tell the user what is happening, in one line: each researcher looks the plugin
|
|
72
|
+
up on the web and briefly adds a scratch track `[MCP] plugin-research <TAG>` to
|
|
73
|
+
their project, which it removes afterwards. Several at once can make REAPER lag
|
|
74
|
+
for a moment while heavy plugins load. Then wait for the reports. As each one
|
|
75
|
+
arrives, give a one-line status (key, proposed preference, what was verified
|
|
76
|
+
live, number of open questions). Don't ask yet.
|
|
77
|
+
|
|
78
|
+
**No `plugin-researcher` agent available** (the Agent tool is missing, or the
|
|
79
|
+
agent isn't installed)? Do its steps here instead. Read
|
|
80
|
+
`~/.claude/agents/plugin-researcher.md` (in the repo:
|
|
81
|
+
`.claude/agents/plugin-researcher.md`) and follow it.
|
|
82
|
+
|
|
83
|
+
### Step 3: Ask only the open questions
|
|
84
|
+
|
|
85
|
+
Show the report's summary lines: the key written, FX names, category/style,
|
|
86
|
+
what was verified live, sources.
|
|
87
|
+
|
|
88
|
+
Then ask **only** the report's open questions, all at once in one
|
|
89
|
+
`AskUserQuestion` call (up to 4). Each question offers the value the agent
|
|
90
|
+
already wrote as the first option, labelled "(keep)":
|
|
91
|
+
|
|
92
|
+
- **Preference:** offer the proposed number plus the neighbouring bands from
|
|
93
|
+
the field guide (e.g. "65 — good third-party (keep)", "80 — go-to",
|
|
94
|
+
"45 — fallback only").
|
|
95
|
+
- **Habit or settings questions:** offer "Use the researched defaults (keep)"
|
|
96
|
+
and let the user type their own in "Other".
|
|
97
|
+
|
|
98
|
+
More than 4 open questions? Ask the 4 that change the record the most. List the
|
|
99
|
+
rest as already filled in from research, and say the user can change them with
|
|
100
|
+
another `/learn-plugin`.
|
|
101
|
+
|
|
102
|
+
No open questions besides preference? Ask only the preference confirmation.
|
|
103
|
+
|
|
104
|
+
**Publishers only:** add one question per plugin, in the same call: "Publish
|
|
105
|
+
**[Plugin]** to built-in for every reaper-mcp user?" with "Publish (adds it to
|
|
106
|
+
the built-in plugin list)" first and "Keep it in my layer" second. It counts
|
|
107
|
+
toward the 4; with several plugins, one question "Publish all N to built-in?"
|
|
108
|
+
is enough.
|
|
109
|
+
|
|
110
|
+
**Several plugins:** start asking once most reports are in, without waiting for
|
|
111
|
+
a slow last one. `AskUserQuestion` takes 4 questions per call, so batch across
|
|
112
|
+
plugins and name the plugin in every question:
|
|
113
|
+
|
|
114
|
+
1. Preferences first, 4 plugins per call. Two utilities with the same kind of
|
|
115
|
+
question can share one question.
|
|
116
|
+
2. Then the facts about the user's setup that change the records the most,
|
|
117
|
+
e.g. what an offline instance or a hardware-control track is for.
|
|
118
|
+
3. Then habits, settings and naming questions, which matter less.
|
|
119
|
+
|
|
120
|
+
Stop after about 3–4 calls. Anything still unasked keeps the researched value;
|
|
121
|
+
list those questions at the end, and say the user can change any of them with
|
|
122
|
+
another `/learn-plugin`. When an answer can be checked in REAPER (e.g. "it was
|
|
123
|
+
offline, check again"), check it read-only and fold in what you find.
|
|
124
|
+
|
|
125
|
+
### Step 4: Fold the answers in
|
|
126
|
+
|
|
127
|
+
Answers that only kept the agent's values change nothing; skip the write.
|
|
128
|
+
Otherwise `memory.read` the `user::` key and change only what the user answered:
|
|
129
|
+
|
|
130
|
+
- preference → the header line **and** the `preference::<n>` tag
|
|
131
|
+
- when they pick it → `## When to prefer this`
|
|
132
|
+
- their own settings → a `###` use case under `## Recommended settings`,
|
|
133
|
+
marked as the user's own
|
|
134
|
+
|
|
135
|
+
Then `memory.write` the full record and full tag list (a write replaces both),
|
|
136
|
+
with `source_agent: "learn-plugin"` and no `ttl_days`. Keep everything else the
|
|
137
|
+
agent wrote, `## Learned notes` included.
|
|
138
|
+
|
|
139
|
+
**Several plugins:** make the writes in parallel, one subagent per record, or a
|
|
140
|
+
single subagent for several records that only change the preference. Give each
|
|
141
|
+
one the key, the exact changes, and the rule to keep everything else word for
|
|
142
|
+
word.
|
|
143
|
+
|
|
144
|
+
### Step 5: Add it to the built-in plugin list
|
|
145
|
+
|
|
146
|
+
**Publisher who chose Publish:** run `/mix-memory publish` for each plugin's
|
|
147
|
+
`user::plugins::…` key (it merges with any built-in record, checks privacy,
|
|
148
|
+
writes the built-in key and removes the `user::` copy). Its last step rebuilds
|
|
149
|
+
`docs/PLUGINS.md` in the clone with `scripts/plugin-list.mjs`; with several
|
|
150
|
+
plugins, run the script once at the end. Say which rows were added and that
|
|
151
|
+
`docs/PLUGINS.md` needs a commit.
|
|
152
|
+
|
|
153
|
+
**Everyone else (or "Keep it in my layer"):** don't edit `docs/PLUGINS.md`; it
|
|
154
|
+
lists only built-in records, and a local edit blocks the bridge's one-click
|
|
155
|
+
Update. Tell the user, in two lines, how to get it listed:
|
|
156
|
+
|
|
157
|
+
> To share **[Plugin]** with every reaper-mcp user: open the bridge window's
|
|
158
|
+
> **Plugins** tab and press **Contribute**. That opens a pull request with your
|
|
159
|
+
> record; once the maintainer publishes it, it's added to the built-in plugin
|
|
160
|
+
> list (`docs/PLUGINS.md`).
|
|
161
|
+
|
|
162
|
+
### Step 6: Confirm
|
|
163
|
+
|
|
164
|
+
> "Done! **[Plugin Name]** is saved to LoreKit as
|
|
165
|
+
> `user::plugins::{vendor}/{plugin}` (preference n/100, [category]).
|
|
166
|
+
> [Verified live: N params, the scaling of K of them. | Not tested live: reason.]
|
|
167
|
+
>
|
|
168
|
+
> The mixing skills will use it for **[category]** jobs when it's your
|
|
169
|
+
> highest-preference installed plugin, and will add to its learned notes as they
|
|
170
|
+
> work with it."
|
|
171
|
+
|
|
172
|
+
Published in Step 5? Say "is now built in as `plugins::{vendor}/{plugin}`"
|
|
173
|
+
instead, and add the `docs/PLUGINS.md` row to commit.
|
|
174
|
+
|
|
175
|
+
If the report said the scratch track couldn't be removed, say that first and
|
|
176
|
+
name the track.
|
|
177
|
+
|
|
178
|
+
**Several plugins:** one table instead (plugin, key, preference, category,
|
|
179
|
+
verified live, published or how to contribute), then the Step 7 overviews,
|
|
180
|
+
shortened to a few lines each.
|
|
181
|
+
|
|
182
|
+
### Step 7: Show how it works
|
|
183
|
+
|
|
184
|
+
Always end with the overview from the report's **How it works** section, under
|
|
185
|
+
the heading **"How [Plugin Name] works"**. Update it with the user's answers
|
|
186
|
+
from Step 3 first: fill in or correct **Your setup**, and adjust **In practice**
|
|
187
|
+
where an answer changes what the mixer can do. Keep the agent's structure (what
|
|
188
|
+
it is, the key point, the control table, presets, your setup, in practice). Keep
|
|
189
|
+
it plain, not fancy.
|
|
190
|
+
|
|
191
|
+
The report has no overview (an older agent, or you did the steps inline)?
|
|
192
|
+
Write one in that structure from the final record.
|
|
193
|
+
|
|
194
|
+
## Notes
|
|
195
|
+
|
|
196
|
+
- **Ask little.** Anything the web or REAPER can answer (exact FX name, vendor,
|
|
197
|
+
category, parameters, ranges, presets, typical settings) is never asked.
|
|
198
|
+
The user is asked about their taste and habits, or a fact the sources disagree
|
|
199
|
+
on and testing couldn't settle.
|
|
200
|
+
- **Self-improvement loop (per `memory-protocol.md`).** The main output is the
|
|
201
|
+
plugin record. If a run shows a recurring process lesson (e.g. a vendor whose
|
|
202
|
+
FX names don't match its marketing name, a category that's often mis-picked,
|
|
203
|
+
a plugin type whose params can't be probed), dedup-search and write or update
|
|
204
|
+
a `user::mixing-lessons::<slug>` lesson (`source_agent: "learn-plugin"`) and
|
|
205
|
+
mention it.
|
|
206
|
+
- The `fx::` tags must be the **exact** FX-browser names. They're matched as
|
|
207
|
+
case-insensitive substrings of installed FX names. The agent takes them from
|
|
208
|
+
`search_fx`, so they always match this machine.
|
|
209
|
+
- The header line and the tags must stay in step: lookups filter on the tags,
|
|
210
|
+
people read the header.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastering
|
|
3
|
+
description: >
|
|
4
|
+
Masters the mix bus in a live REAPER session — gentle corrective EQ, glue
|
|
5
|
+
compression, and a true-peak limiter targeting a platform LUFS standard — while
|
|
6
|
+
verifying against metering and preserving the mix's character. Use when the user
|
|
7
|
+
asks to master, finalize, or prepare a track for Spotify/Apple/streaming or a
|
|
8
|
+
specific loudness target. Triggers on "master this", "prepare for Spotify",
|
|
9
|
+
"final master", "hit -14 LUFS", "/mastering".
|
|
10
|
+
argument-hint: '[platform or LUFS target]'
|
|
11
|
+
license: MIT
|
|
12
|
+
metadata:
|
|
13
|
+
author: mthines
|
|
14
|
+
version: '1.0.0'
|
|
15
|
+
workflow_type: applied
|
|
16
|
+
tags:
|
|
17
|
+
- mastering
|
|
18
|
+
- loudness
|
|
19
|
+
- lufs
|
|
20
|
+
- limiter
|
|
21
|
+
- reaper
|
|
22
|
+
- audio
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Mastering
|
|
26
|
+
|
|
27
|
+
Act as a mastering engineer working the mix bus in a **live** REAPER session via
|
|
28
|
+
the `reaper` MCP tools. Apply a transparent chain that hits a loudness standard
|
|
29
|
+
while preserving the mix's character.
|
|
30
|
+
|
|
31
|
+
**Mastering is subtle** — moves are fractions of a dB. If large corrections are
|
|
32
|
+
needed, tell the user the mix needs work first and consider `/mixer`.
|
|
33
|
+
|
|
34
|
+
## Targets
|
|
35
|
+
|
|
36
|
+
Default to **-14 LUFS, -1.0 dBTP** (safe for all streaming) unless the user names
|
|
37
|
+
a platform. Full target table: `reference/metering.md`.
|
|
38
|
+
|
|
39
|
+
## Memory
|
|
40
|
+
|
|
41
|
+
Per `reference/memory-protocol.md` — plugin knowledge and lessons in LoreKit
|
|
42
|
+
(scope `project::reaper-mcp`), in two layers: the read-only **built-in** layer and
|
|
43
|
+
the user's own `user::` layer on top. Reads combine both; writes go to `user::` keys only.
|
|
44
|
+
- **Before:** read the `loop::mixing-lessons` bucket (capped at 5 + one search on
|
|
45
|
+
"mastering limiter loudness …") and, for your limiter/EQ/comp plugins, both
|
|
46
|
+
`get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }` and `memory.read`
|
|
47
|
+
of `user::plugins::{vendor}/{plugin}` — past
|
|
48
|
+
targets the user preferred and known gotchas (the user record wins).
|
|
49
|
+
- **Plugin gate — no plugin is touched before its memory is read.** Before the
|
|
50
|
+
first call that adds, sets, loads a preset for, writes MIDI to, or reads parameters
|
|
51
|
+
of a plugin (`add_fx`, `setup_fx_chain`, `set_fx_parameter`,
|
|
52
|
+
`set_multiple_fx_parameters`, `set_fx_preset`, `load_fx_chain`, MIDI for an
|
|
53
|
+
instrument track, take FX), look it up — every plugin, every time it is new to this
|
|
54
|
+
session, including ones the user named, ones already in the project and ones you
|
|
55
|
+
only meet while listing a chain. Never skip it because the plugin looks familiar.
|
|
56
|
+
Look up both layers: `list_builtin_knowledge { query: "<plugin name>" }` (or `tags:
|
|
57
|
+
["fx::<FX name>"]`) / `get_builtin_knowledge { key: "plugins::{vendor}/{plugin}" }`,
|
|
58
|
+
and `memory.search` / `memory.read` of `user::plugins::{vendor}/{plugin}` (the user's
|
|
59
|
+
record wins). Then **follow the record**: its MIDI map and note ranges, parameter
|
|
60
|
+
scaling, recommended settings and gotchas decide what you do, and a setting you were
|
|
61
|
+
about to use that the record warns against is not used. Say it in one chat line
|
|
62
|
+
("Recalled Odin x Ari Lite: notes <36 are keyswitches → transposing"). Keep a running
|
|
63
|
+
list of recalled plugins and don't re-read those. No record in either layer: say so
|
|
64
|
+
and carry on (or bootstrap it when the user asked for the plugin by name). LoreKit
|
|
65
|
+
not connected: say so once and use the built-in read only.
|
|
66
|
+
- **Unknown plugin?** Bootstrap it first (see protocol): dispatch the
|
|
67
|
+
`plugin-researcher` agent (or follow its steps yourself), then read its
|
|
68
|
+
`user::plugins::` record and use it.
|
|
69
|
+
- **At a correction point — write the lesson immediately, before your next
|
|
70
|
+
action** (the user found your master too loud and you backed off; a re-measure
|
|
71
|
+
missed the LUFS/true-peak target; you over-limited and lost crest). Non-
|
|
72
|
+
negotiable (see Hard Rules); **say in chat that you captured it** (key +
|
|
73
|
+
takeaway). A silent skip is a bug.
|
|
74
|
+
- **End-of-session retrospective (always, even on a clean master).** Before the
|
|
75
|
+
final report, ask: did the user override a target/ceiling, did a measurement
|
|
76
|
+
surprise me, did a lesson I had fail to fire? If anything surfaced, write or
|
|
77
|
+
UPDATE a lesson (rewriting the same key bumps the store's `seen_count`). A
|
|
78
|
+
lesson seen `>= 3×` is promotable to a Hard Rule via `/mix-memory promote`.
|
|
79
|
+
- **Durable facts:** also capture a verified limiter param map or a ceiling the
|
|
80
|
+
user kept under the `user::plugins::` record's `## Learned notes`
|
|
81
|
+
(read-merge-write; never write a built-in key). Name the key you wrote.
|
|
82
|
+
|
|
83
|
+
## Workflow
|
|
84
|
+
|
|
85
|
+
1. **Snapshot** — `snapshot_save { name: "pre-master" }`.
|
|
86
|
+
2. **Discover plugins** — `list_available_fx`; prefer limiter Pro-L 2 > ReaLimit,
|
|
87
|
+
EQ Pro-Q 3 > ReaEQ (linear phase for mastering), comp Pro-C 2 > ReaComp. Check
|
|
88
|
+
the LoreKit plugin records (built-in + `user::`) for settings; bootstrap any
|
|
89
|
+
unknown plugin first.
|
|
90
|
+
3. **Assess the bus** — `analyze_track_offline { trackIndex: -1, startTime: 0,
|
|
91
|
+
endTime: <song end>, sectionSeconds: 10 }`: integrated LUFS over the whole
|
|
92
|
+
song (not a few seconds of meter), LRA, true peak, crest, loudest/quietest
|
|
93
|
+
sections and band balance. With a reference song, add `referencePath` for the
|
|
94
|
+
loudness and tonal-balance delta. Peak should be -6 to -3 dBFS (reduce the
|
|
95
|
+
mix fader first if hotter); note distance from target LUFS and the dynamics.
|
|
96
|
+
Pass the target as `targetLufs` on every `read_track_lufs` / `measure_tracks`
|
|
97
|
+
call, so the bridge page shows each reading against it.
|
|
98
|
+
4. **Corrective EQ** — gentle only. Typical: steep HPF 20–30 Hz; low shelf -0.5 to
|
|
99
|
+
-1 dB @ 80 Hz; low-mid dip -0.5 to -1 dB @ 250–350 Hz; +0.5 dB presence @
|
|
100
|
+
2–4 kHz only if needed; air shelf +0.5 to +1 dB @ 10–12 kHz. The 2–5 kHz range
|
|
101
|
+
has outsized perceptual impact (`reference/perceived-loudness.md`). Judge the
|
|
102
|
+
bus spectrum on K-weighted `kDb`, never raw `db`, against a level-matched
|
|
103
|
+
reference band by band, and read it 3+ times (each read is a ~0.5 s snapshot). **If you're
|
|
104
|
+
EQing more than ±2 dB, the mix has a problem — go back.**
|
|
105
|
+
5. **Glue compression** (optional) — only for cohesion: 1.5:1–2:1, slow attack
|
|
106
|
+
30–80 ms, auto/200–500 ms release, **1–2 dB GR max**. More GR → fix the mix.
|
|
107
|
+
6. **Limiter** (last in chain) — ceiling -1.0 dBTP (streaming) or -0.3 (CD); raise
|
|
108
|
+
input until integrated LUFS hits target; keep limiter GR under ~3 dB.
|
|
109
|
+
If the limiter pumps (guitars/bass dip on every drum hit), **clip before
|
|
110
|
+
it** rather than lowering drive or limiting harder. Put a clipper (e.g.
|
|
111
|
+
Free Clip 2) just before the limiter, with a ceiling ~1–1.5 dB under the
|
|
112
|
+
level that *arrives at it* (an upstream limiter's ceiling, not 0 dBFS).
|
|
113
|
+
The clipper only alters the peak samples, while the limiter's gain change
|
|
114
|
+
pulls the whole mix down for its release time. Seen live: master pumping
|
|
115
|
+
std 1.35 → 1.06 dB at +0.25 LU. Keep it to ≤1.5 dB (lesson
|
|
116
|
+
drum-bus-clip-buries-attack).
|
|
117
|
+
**Dynamics over loudness:** streaming turns everything down to about -14
|
|
118
|
+
LUFS, so a hotter master only loses punch there. Don't chase a loud
|
|
119
|
+
reference's LUFS. Offer louder as an option the user picks by ear.
|
|
120
|
+
7. **Verify** — `analyze_track_offline` on the master over the whole song:
|
|
121
|
+
integrated LUFS within 0.5 of target, true peak below the ceiling, LRA and
|
|
122
|
+
crest genre-appropriate; `read_track_correlation` healthy (>0.3). To compare
|
|
123
|
+
chain versions, `analyze_track_aesthetics` on the same 30 s range keeps the
|
|
124
|
+
default level match (-18 LUFS), so the louder master does not win by level;
|
|
125
|
+
PQ moves under ~0.1 are noise (`reference/aesthetics-scoring.md`).
|
|
126
|
+
While the user is working in REAPER, verify during playback instead of
|
|
127
|
+
rendering (a render window takes focus). Use `measure_tracks` on the bus for
|
|
128
|
+
LUFS + true peak over the loud section, or the stock Loudness Meter in
|
|
129
|
+
true-peak mode. For a final choice, build 2–3 variants and switch them live
|
|
130
|
+
with `run_plan` (mixer skill, step 7). Render the deliverable once, when the
|
|
131
|
+
user asks.
|
|
132
|
+
8. **Report** — first run the **end-of-session retrospective** (Memory) and write
|
|
133
|
+
any lesson it surfaces; then `snapshot_save { name: "master-v1" }` and report
|
|
134
|
+
target vs achieved LUFS, true peak, crest, the chain + settings, any
|
|
135
|
+
compromises, and **what you captured to memory (or that nothing was)**.
|
|
136
|
+
|
|
137
|
+
## Hard Rules
|
|
138
|
+
|
|
139
|
+
<!-- Promotion target: recurring mastering lessons graduate here via /mix-memory promote. -->
|
|
140
|
+
|
|
141
|
+
- **No plugin without its memory.** Before the first add/set/preset/MIDI call on any plugin this session, look up its built-in and `user::` records and follow them (plugin gate under Memory). Skipping the lookup because the plugin looks familiar is a bug.
|
|
142
|
+
|
|
143
|
+
- **Capture the lesson at the correction point** — if the user overrides a
|
|
144
|
+
target/ceiling or a re-measure misses, write the lesson before your next action
|
|
145
|
+
and say you did. Never end a session that had a correction without a written
|
|
146
|
+
lesson. (Invariant.)
|
|
147
|
+
- **Mastering is the final stage** — the mix should already be finished.
|
|
148
|
+
- **If the bus clips before you start, reduce it first** — don't just add a limiter.
|
|
149
|
+
- **Linear-phase EQ if available** — avoids phase shift on the master.
|
|
150
|
+
- **Always A/B with `snapshot_restore`** — mastering is subtle enough to fool you.
|
|
151
|
+
- **A balanced master slopes gently down** from lows to highs on the analyzer.
|