@map-audio/pam-mcp-server 1.12.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/bridge.d.ts +17 -3
- package/dist/bridge.js +81 -20
- package/dist/bridge.js.map +1 -1
- package/dist/drumSynth.d.ts +96 -0
- package/dist/drumSynth.js +193 -0
- package/dist/drumSynth.js.map +1 -0
- package/dist/drumSynthEngines.json +1360 -0
- package/dist/fgemma-format.d.ts +119 -0
- package/dist/fgemma-format.js +292 -0
- package/dist/fgemma-format.js.map +1 -0
- package/dist/fgemma-runner.d.ts +27 -0
- package/dist/fgemma-runner.js +475 -0
- package/dist/fgemma-runner.js.map +1 -0
- package/dist/generated/variationSnapshot.d.ts +31 -0
- package/dist/generated/variationSnapshot.js +62 -0
- package/dist/generated/variationSnapshot.js.map +1 -0
- package/dist/manifest-cell1.json +8245 -0
- package/dist/manifest-mfx.json +14060 -0
- package/dist/manifest.d.ts +14 -1
- package/dist/manifest.js +133 -34
- package/dist/manifest.js.map +1 -1
- package/dist/manifest.json +2322 -157
- package/dist/mixAssist.d.ts +155 -0
- package/dist/mixAssist.js +652 -0
- package/dist/mixAssist.js.map +1 -0
- package/dist/presetSave.d.ts +10 -0
- package/dist/presetSave.js +22 -0
- package/dist/presetSave.js.map +1 -0
- package/dist/server.js +2667 -236
- package/dist/server.js.map +1 -1
- package/dist/variationSessionKeys.json +110 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -77,11 +77,29 @@ Use the same `mcpServers` block in the client's MCP config. Any stdio-compatible
|
|
|
77
77
|
|
|
78
78
|
## What's in the box
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
~145 tools. The high-value entry points:
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
- **Read first**: `design_context` (curated parameter cheat sheet, works offline) and `get_design_overview` (compact live snapshot). Prefer these over full `get_state` dumps or broad `get_parameter_info` sweeps.
|
|
83
|
+
- **Sound design**: `set_parameters`, `update_pattern`, `add_modulation` / `add_param_seq`, `update_effect_config`, `set_master_effects`, `set_drum_synth`, `randomize` / `randomize_samples` / `randomize_patterns`.
|
|
84
|
+
- **Samples**: `get_default_locations` → `list_samples` → `load_sample`, plus `trim/reverse/gain/normalize_sample`, `analyze_sample_tempo`, `resample_sample_to_bpm`, `build_sample_chain`.
|
|
85
|
+
- **Transport, MIDI & devices**: `start_transport` / `stop_transport` / `full_stop_transport`, `set_bpm`, `trigger_midi` (+ CC / program change), `midi_recording`; `get_audio_device_setup` / `set_audio_device` / `set_midi_io` (standalone).
|
|
86
|
+
- **Presets, variations & songs**: `load_preset` / `save_preset` / `new_preset`, `save_variation` / `load_variation` / `queue_variation`, `song_mode`, `export_song` (full-track bounce), `export_audio` (incl. per-cell stems).
|
|
87
|
+
- **Looper**: full 8-track control — arm/record/capture, `load_audio_to_looper_track`, warp, looper variations, `live_resample`.
|
|
88
|
+
- **Plugin host** (PAM builds with hosting): `scan_plugins` → `get_plugin_scan_status` → `list_plugins` → `load_plugin` → `list_loaded_plugins` → `set_plugin_param` / `set_plugin_bypass`.
|
|
89
|
+
- **AI models & generation** (experimental flags required): `download_model` / `load_model` / `get_model_status` / `list_models` (engines: aigen, magenta, notochord), `generate_sample`, `generate_kit`.
|
|
90
|
+
- **Video (VX) & UI** — require PAM's window to be open: `get_video_state`, `add_video_layer`, `bind_video_param`, `video_command`, …, and `capture_ui` (deterministic UI screenshot).
|
|
91
|
+
- **Offline (manifest-only)**: `get_parameter_info`, `design_context`, `list_presets`, `read_preset`, `get_manifest_summary`.
|
|
83
92
|
|
|
84
|
-
|
|
93
|
+
- **MFX**: `set_mfx_routing` reads and replaces the cable patch (`input` / `sidechain` → `cellN` → `output`). MFX-only; it errors on PAM and CELL1.
|
|
94
|
+
|
|
95
|
+
All three product manifests (PAM / CELL1 / MFX) are bundled; the server auto-selects by the connected instance's product, so one config entry drives all three products. Preset listing follows that product too — each has its own tree under `MAP Audio`.
|
|
96
|
+
|
|
97
|
+
## Agent ergonomics
|
|
98
|
+
|
|
99
|
+
- **Tool annotations.** Every tool carries MCP annotations. Tools with `readOnlyHint: true` never change plugin state, so clients can approve them freely. `destructiveHint: true` marks tools that discard user state (`delete_preset`, `reset_cell`, `load_preset` over unsaved edits). `openWorldHint` is `false` on every tool; the server only talks to the local plugin.
|
|
100
|
+
- **Structured output.** The status tools (`connection_status`, `select_instance`, `get_transport`, `get_manifest_summary`, `get_model_status`, `get_plugin_scan_status`, `workbench_sidecar_status`) return `structuredContent` with a declared output schema, alongside the same JSON as text.
|
|
101
|
+
- **Prompts.** Five guided workflows ship as MCP prompts: `build-a-beat`, `make-a-song`, `design-a-preset`, `mix-and-master`, `troubleshoot-bridge`. In Claude Code they appear as slash commands (e.g. `/pam:build-a-beat`).
|
|
102
|
+
- **Multiple instances.** When several products run at once (say PAM and MFX), `select_instance` picks which one the live tools drive, matched by product name, instanceId, or port. Setting `PAM_BRIDGE_PRODUCT=MFX` in the server's `env` block pins the choice at launch. Offline parameter validation follows the selected product's manifest.
|
|
85
103
|
|
|
86
104
|
## License
|
|
87
105
|
|
package/dist/bridge.d.ts
CHANGED
|
@@ -1,23 +1,37 @@
|
|
|
1
|
-
interface BridgeInfo {
|
|
1
|
+
export interface BridgeInfo {
|
|
2
2
|
port: number;
|
|
3
3
|
instanceId: string;
|
|
4
4
|
product: string;
|
|
5
5
|
pid: number;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Instance selector for connect(). `instanceId` matches exactly, `product`
|
|
9
|
+
* case-insensitively ("PAM" / "CELL1" / "MFX"), `port` directly. When a
|
|
10
|
+
* selector is given and nothing matches, connect() fails rather than silently
|
|
11
|
+
* driving a different instance. PAM_BRIDGE_PRODUCT env pins the default.
|
|
12
|
+
*/
|
|
13
|
+
export interface ConnectTarget {
|
|
14
|
+
port?: number;
|
|
15
|
+
product?: string;
|
|
16
|
+
instanceId?: string;
|
|
17
|
+
}
|
|
7
18
|
export declare class PluginBridge {
|
|
8
19
|
private socket;
|
|
9
20
|
private buffer;
|
|
10
21
|
private nextId;
|
|
11
22
|
private pending;
|
|
12
23
|
private connected;
|
|
24
|
+
private connectedInstance;
|
|
13
25
|
discover(): Promise<BridgeInfo[]>;
|
|
14
|
-
|
|
26
|
+
private static matchesTarget;
|
|
27
|
+
connect(target?: ConnectTarget): Promise<boolean>;
|
|
15
28
|
disconnect(): void;
|
|
16
29
|
isConnected(): boolean;
|
|
30
|
+
/** The discovery entry of the instance this bridge is connected to, if known. */
|
|
31
|
+
getConnectedInstance(): BridgeInfo | null;
|
|
17
32
|
private static readonly SLOW_ACTIONS;
|
|
18
33
|
private static readonly VERY_SLOW_ACTIONS;
|
|
19
34
|
send(action: string, ...args: unknown[]): Promise<unknown>;
|
|
20
35
|
private translateBridgeError;
|
|
21
36
|
private processBuffer;
|
|
22
37
|
}
|
|
23
|
-
export {};
|
package/dist/bridge.js
CHANGED
|
@@ -98,11 +98,29 @@ const NEW_ACTIONS_ADDED_IN_1_8_0 = new Set([
|
|
|
98
98
|
"videoCommand",
|
|
99
99
|
"getVideoState",
|
|
100
100
|
]);
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
// Actions added in MCP server 1.13.0 — drum-synth control routed through the WebView
|
|
102
|
+
// (the engine-aware randomizer + the drawable-wave LUT). Require a PAM build whose
|
|
103
|
+
// MCPBridge forwards them via postToUI; older builds return "unknown action 'X'".
|
|
104
|
+
const NEW_ACTIONS_ADDED_IN_1_13_0 = new Set([
|
|
105
|
+
"randomizeDrumSynth",
|
|
106
|
+
"setDrumSynthWaveCurve",
|
|
107
|
+
]);
|
|
108
|
+
// Actions added in MCP server 1.15.0 — the assistant-surface UI forwards
|
|
109
|
+
// (set_view navigation + the lfos/mods modulation randomizer), routed through
|
|
110
|
+
// the WebView like randomizeDrumSynth. Older builds return "unknown action 'X'".
|
|
111
|
+
const NEW_ACTIONS_ADDED_IN_1_15_0 = new Set([
|
|
112
|
+
"setView",
|
|
113
|
+
"randomizeModulations",
|
|
114
|
+
]);
|
|
115
|
+
const NEW_ACTIONS_ADDED_IN_1_17_0 = new Set([
|
|
116
|
+
"analyzeMix",
|
|
117
|
+
"getMixAnalysis",
|
|
118
|
+
]);
|
|
119
|
+
// Plugin-host actions ship on builds with PAM_PLUGIN_HOST=1. Older builds or
|
|
120
|
+
// non-host SKUs like Cell1 won't recognize them and will return
|
|
121
|
+
// "unknown action 'X'". MFX can compile FX-side hosting, but these shared MCP
|
|
122
|
+
// actions are still PAM-manager-shaped until product-aware FX-host tooling lands.
|
|
123
|
+
// The bridge handler translates unknown actions into an actionable tool error.
|
|
106
124
|
const PLUGIN_HOST_ACTIONS = new Set([
|
|
107
125
|
"listPlugins",
|
|
108
126
|
"scanPlugins",
|
|
@@ -135,6 +153,7 @@ export class PluginBridge {
|
|
|
135
153
|
nextId = 1;
|
|
136
154
|
pending = new Map();
|
|
137
155
|
connected = false;
|
|
156
|
+
connectedInstance = null;
|
|
138
157
|
async discover() {
|
|
139
158
|
try {
|
|
140
159
|
const raw = await readFile(DISCOVERY_FILE, "utf-8");
|
|
@@ -160,14 +179,44 @@ export class PluginBridge {
|
|
|
160
179
|
return [];
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
return
|
|
166
|
-
if (
|
|
167
|
-
|
|
182
|
+
static matchesTarget(instance, target) {
|
|
183
|
+
if (target.instanceId !== undefined && instance.instanceId !== target.instanceId)
|
|
184
|
+
return false;
|
|
185
|
+
if (target.port !== undefined && instance.port !== target.port)
|
|
186
|
+
return false;
|
|
187
|
+
if (target.product !== undefined &&
|
|
188
|
+
instance.product?.toLowerCase() !== target.product.toLowerCase())
|
|
189
|
+
return false;
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
async connect(target) {
|
|
193
|
+
// Default target: the PAM_BRIDGE_PRODUCT env pin, if set. The pin is hard —
|
|
194
|
+
// silently connecting to a different product would mutate the wrong plugin.
|
|
195
|
+
if (!target && process.env.PAM_BRIDGE_PRODUCT) {
|
|
196
|
+
target = { product: process.env.PAM_BRIDGE_PRODUCT };
|
|
197
|
+
}
|
|
198
|
+
if (this.connected) {
|
|
199
|
+
if (!target || (this.connectedInstance && PluginBridge.matchesTarget(this.connectedInstance, target)))
|
|
200
|
+
return true;
|
|
201
|
+
this.disconnect();
|
|
202
|
+
}
|
|
203
|
+
let port = target?.port;
|
|
204
|
+
let instance = null;
|
|
205
|
+
const instances = await this.discover();
|
|
206
|
+
if (target && (target.product !== undefined || target.instanceId !== undefined)) {
|
|
207
|
+
instance = instances.find((i) => PluginBridge.matchesTarget(i, target)) ?? null;
|
|
208
|
+
if (!instance)
|
|
209
|
+
return false;
|
|
210
|
+
port = instance.port;
|
|
211
|
+
}
|
|
212
|
+
else if (!port) {
|
|
168
213
|
if (instances.length === 0)
|
|
169
214
|
return false;
|
|
170
|
-
|
|
215
|
+
instance = instances[0];
|
|
216
|
+
port = instance.port;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
instance = instances.find((i) => i.port === port) ?? null;
|
|
171
220
|
}
|
|
172
221
|
return new Promise((resolve) => {
|
|
173
222
|
const timer = setTimeout(() => {
|
|
@@ -179,6 +228,7 @@ export class PluginBridge {
|
|
|
179
228
|
this.socket = createConnection({ host: "127.0.0.1", port }, () => {
|
|
180
229
|
clearTimeout(timer);
|
|
181
230
|
this.connected = true;
|
|
231
|
+
this.connectedInstance = instance;
|
|
182
232
|
resolve(true);
|
|
183
233
|
});
|
|
184
234
|
this.socket.setEncoding("utf-8");
|
|
@@ -205,10 +255,15 @@ export class PluginBridge {
|
|
|
205
255
|
this.socket?.destroy();
|
|
206
256
|
this.socket = null;
|
|
207
257
|
this.connected = false;
|
|
258
|
+
this.connectedInstance = null;
|
|
208
259
|
}
|
|
209
260
|
isConnected() {
|
|
210
261
|
return this.connected;
|
|
211
262
|
}
|
|
263
|
+
/** The discovery entry of the instance this bridge is connected to, if known. */
|
|
264
|
+
getConnectedInstance() {
|
|
265
|
+
return this.connected ? this.connectedInstance : null;
|
|
266
|
+
}
|
|
212
267
|
// Actions that block the message thread for disk I/O + graph rebuild
|
|
213
268
|
static SLOW_ACTIONS = new Set([
|
|
214
269
|
"loadPreset",
|
|
@@ -267,21 +322,27 @@ export class PluginBridge {
|
|
|
267
322
|
if (message.startsWith("unknown action '")) {
|
|
268
323
|
if (PLUGIN_HOST_ACTIONS.has(action)) {
|
|
269
324
|
return (`PAM build does not include the plugin host ('${action}' not recognized). ` +
|
|
270
|
-
`Plugin-host tools require a
|
|
271
|
-
`Cell1
|
|
325
|
+
`Plugin-host tools require a build with PAM_PLUGIN_HOST=1. ` +
|
|
326
|
+
`Cell1 does not host third-party plugins; MFX only exposes FX-side hosting and needs product-aware FX-host MCP support.`);
|
|
272
327
|
}
|
|
273
328
|
if (MODEL_ACTIONS.has(action)) {
|
|
274
329
|
return (`PAM build does not include the AI model managers ('${action}' not recognized). ` +
|
|
275
330
|
`Model-management tools require PAM ≥ 1.9.0 with the AIGen/Magenta/Notochord managers; ` +
|
|
276
331
|
`they are not available on standalone MFX builds.`);
|
|
277
332
|
}
|
|
278
|
-
const requiredVersion =
|
|
279
|
-
? "1.
|
|
280
|
-
:
|
|
281
|
-
? "1.
|
|
282
|
-
:
|
|
283
|
-
?
|
|
284
|
-
:
|
|
333
|
+
const requiredVersion = NEW_ACTIONS_ADDED_IN_1_17_0.has(action)
|
|
334
|
+
? "1.17.0"
|
|
335
|
+
: NEW_ACTIONS_ADDED_IN_1_15_0.has(action)
|
|
336
|
+
? "1.15.0"
|
|
337
|
+
: NEW_ACTIONS_ADDED_IN_1_13_0.has(action)
|
|
338
|
+
? "1.13.0"
|
|
339
|
+
: NEW_ACTIONS_ADDED_IN_1_8_0.has(action)
|
|
340
|
+
? "1.8.0"
|
|
341
|
+
: NEW_ACTIONS_ADDED_IN_1_7_0.has(action)
|
|
342
|
+
? "1.7.0"
|
|
343
|
+
: NEW_ACTIONS_ADDED_IN_1_1_0.has(action) || NEW_ACTIONS_ADDED_IN_1_5_0.has(action)
|
|
344
|
+
? MIN_PAM_VERSION_FOR_NEW_ACTIONS
|
|
345
|
+
: null;
|
|
285
346
|
if (requiredVersion) {
|
|
286
347
|
return (`PAM build does not support '${action}'. ` +
|
|
287
348
|
`This action requires PAM ≥ ${requiredVersion} ` +
|
package/dist/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAe,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export type DrumDispKind = "freq" | "time" | "note" | "st" | "ratio" | "pct" | "num";
|
|
2
|
+
export interface DrumParamDisplay {
|
|
3
|
+
kind: DrumDispKind;
|
|
4
|
+
lo?: number;
|
|
5
|
+
hi?: number;
|
|
6
|
+
/** Exact engine-unit anchor at norm 0.5; each half maps separately. */
|
|
7
|
+
center?: number;
|
|
8
|
+
curve?: "exp" | "lin";
|
|
9
|
+
digits?: number;
|
|
10
|
+
suffix?: string;
|
|
11
|
+
direction?: "pitchSweep";
|
|
12
|
+
}
|
|
13
|
+
export interface DrumRegistrySlot extends DrumParamDisplay {
|
|
14
|
+
label: string;
|
|
15
|
+
default: number;
|
|
16
|
+
bipolar?: boolean;
|
|
17
|
+
rand?: [number, number];
|
|
18
|
+
group: "pitch" | "gen" | "amp";
|
|
19
|
+
groupOrder: number;
|
|
20
|
+
}
|
|
21
|
+
export interface DrumSynthRegistry {
|
|
22
|
+
engines: Record<string, {
|
|
23
|
+
name: string;
|
|
24
|
+
slots: DrumRegistrySlot[];
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface DrumSynthEngineDescriptor {
|
|
28
|
+
/** Engine enum value (1..N); 0 is Off and has no descriptor. */
|
|
29
|
+
id: number;
|
|
30
|
+
name: string;
|
|
31
|
+
params: {
|
|
32
|
+
label: string;
|
|
33
|
+
default: number;
|
|
34
|
+
bipolar?: boolean;
|
|
35
|
+
rand?: [number, number];
|
|
36
|
+
}[];
|
|
37
|
+
}
|
|
38
|
+
/** Breakpoint shape of cell{N}_synthAmpCurve — structurally the UI's CurvePoint. */
|
|
39
|
+
export interface DrumCurvePoint {
|
|
40
|
+
t: number;
|
|
41
|
+
v: number;
|
|
42
|
+
tension: number;
|
|
43
|
+
}
|
|
44
|
+
export type DrumSynthDelta = Record<string, number | DrumCurvePoint[]>;
|
|
45
|
+
export declare const DRUM_SYNTH_PARAMS_PER_CELL = 8;
|
|
46
|
+
/**
|
|
47
|
+
* Half the 0.001 manifest step for cell{N}_synth_pN, which also absorbs the
|
|
48
|
+
* float32 round-trip a normalized value takes through the host parameter. A slot
|
|
49
|
+
* within this of its engine's curated default was never touched, so an engine
|
|
50
|
+
* switch reseeds it instead of carrying it.
|
|
51
|
+
*/
|
|
52
|
+
export declare const DRUM_SLOT_EDIT_EPSILON = 0.0005;
|
|
53
|
+
/** Must match DrumSynthCore::prepare (0.25 s) and the UI selector fallback. */
|
|
54
|
+
export declare const DEFAULT_DRUM_AMP_TIME_MS = 250;
|
|
55
|
+
/** Flat-at-unity: the no-op gain contour the C++ default seed renders. */
|
|
56
|
+
export declare const DEFAULT_DRUM_AMP_CURVE: DrumCurvePoint[];
|
|
57
|
+
/** normalized 0..1 → real engine-unit value (mirrors mapParamValue in C++). */
|
|
58
|
+
export declare function drumParamToReal(d: DrumParamDisplay, x: number): number;
|
|
59
|
+
/** real engine-unit value → normalized 0..1 (the inverse). */
|
|
60
|
+
export declare function drumParamFromReal(d: DrumParamDisplay, v: number): number;
|
|
61
|
+
export declare const isDrumSlotEdited: (value: unknown, curatedDefault: number) => boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Move an edited value from one engine's slot to another's. `pct` slots carry the
|
|
64
|
+
* knob POSITION because their display IS the position; every unit-bearing family
|
|
65
|
+
* carries the engine value, re-normalized through the destination's own map and
|
|
66
|
+
* clamped into its range. Returns undefined when the two slots are not the same
|
|
67
|
+
* quantity.
|
|
68
|
+
*/
|
|
69
|
+
export declare const carryDrumSlotValue: (src: DrumParamDisplay | undefined, dst: DrumParamDisplay | undefined, value: number) => number | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* A drawn amp envelope shapes EVERY engine and its C++ latch is one-way, so an
|
|
72
|
+
* untouched (absent, or flat-at-unity over the default window) contour is cleared
|
|
73
|
+
* when the engine changes. Anything the user actually drew survives.
|
|
74
|
+
*/
|
|
75
|
+
export declare const isDrumAmpEnvUntouched: (curve: unknown, timeMs: unknown) => boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Empty array, not the flat curve: sampler.ts omits the ampEnvCurveLUT prop for an
|
|
78
|
+
* empty array and emits ampEnvActive: 0, which clears the node's one-way latch on
|
|
79
|
+
* the rebuild an engine change always triggers.
|
|
80
|
+
*/
|
|
81
|
+
export declare const drumAmpEnvResetDelta: (cellId: number) => DrumSynthDelta;
|
|
82
|
+
export declare const drumSynthParamKey: (cellId: number | string, slot: number) => string;
|
|
83
|
+
export interface DrumSynthCatalog {
|
|
84
|
+
/** Index matches drumsynth::Engine — element 0 is 'Off'. */
|
|
85
|
+
engineNames: readonly string[];
|
|
86
|
+
engines: DrumSynthEngineDescriptor[];
|
|
87
|
+
getEngine(engineId: number): DrumSynthEngineDescriptor | undefined;
|
|
88
|
+
getDisplay(engineId: number, slot: number): DrumParamDisplay | undefined;
|
|
89
|
+
buildEngineSwitchDelta(cellId: number, nextEngineId: number, state: Record<string, unknown>): DrumSynthDelta;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Project the registry into the roster + switch rule. Taking the parsed JSON as an
|
|
93
|
+
* argument (rather than importing it) is what lets the published package read the
|
|
94
|
+
* copy vendored into dist/ while the repo checkout reads shared/.
|
|
95
|
+
*/
|
|
96
|
+
export declare function createDrumSynthCatalog(registry: DrumSynthRegistry): DrumSynthCatalog;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Drum-synth engine roster + engine-switch delta, built from
|
|
2
|
+
// shared/drumSynthEngines.json.
|
|
3
|
+
//
|
|
4
|
+
// The server used to carry its own copy of the roster (labels + normalized
|
|
5
|
+
// defaults) and its own engine-switch rule. Both drifted: Kick, Cowbell and 808
|
|
6
|
+
// kept their pre-anchor Tune defaults after the registry re-centred them, and
|
|
7
|
+
// the switch rule carried knob positions where the plugin carries engine units.
|
|
8
|
+
// A call over the bridge therefore landed somewhere the same call in the plugin
|
|
9
|
+
// does not (issue #999).
|
|
10
|
+
//
|
|
11
|
+
// Everything here mirrors interface/src/dsp/modules/drumSynth.ts, which is the
|
|
12
|
+
// implementation the UI hook and the in-plugin assistant executor both call.
|
|
13
|
+
// The published package cannot import across workspaces, so this is a vendored
|
|
14
|
+
// twin — interface/test/mcpDrumSynthParity.test.ts drives both over the same
|
|
15
|
+
// inputs and fails on any divergence.
|
|
16
|
+
export const DRUM_SYNTH_PARAMS_PER_CELL = 8;
|
|
17
|
+
/**
|
|
18
|
+
* Half the 0.001 manifest step for cell{N}_synth_pN, which also absorbs the
|
|
19
|
+
* float32 round-trip a normalized value takes through the host parameter. A slot
|
|
20
|
+
* within this of its engine's curated default was never touched, so an engine
|
|
21
|
+
* switch reseeds it instead of carrying it.
|
|
22
|
+
*/
|
|
23
|
+
export const DRUM_SLOT_EDIT_EPSILON = 5e-4;
|
|
24
|
+
/** Must match DrumSynthCore::prepare (0.25 s) and the UI selector fallback. */
|
|
25
|
+
export const DEFAULT_DRUM_AMP_TIME_MS = 250;
|
|
26
|
+
/** Flat-at-unity: the no-op gain contour the C++ default seed renders. */
|
|
27
|
+
export const DEFAULT_DRUM_AMP_CURVE = [
|
|
28
|
+
{ t: 0, v: 1, tension: 0 },
|
|
29
|
+
{ t: 1, v: 1, tension: 0 },
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Unit families for the engine-switch carry. `kind` is display-only and is never
|
|
33
|
+
* read by the cook, so 'note' and 'freq' are the same physical quantity in Hz and
|
|
34
|
+
* share a family — they differ only in whether the UI renders "A1" or "55 Hz".
|
|
35
|
+
*/
|
|
36
|
+
const DRUM_CARRY_FAMILY = {
|
|
37
|
+
note: "hz",
|
|
38
|
+
freq: "hz",
|
|
39
|
+
time: "s",
|
|
40
|
+
st: "st",
|
|
41
|
+
ratio: "ratio",
|
|
42
|
+
num: "num",
|
|
43
|
+
pct: "pct",
|
|
44
|
+
};
|
|
45
|
+
const clamp01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
|
|
46
|
+
/** normalized 0..1 → real engine-unit value (mirrors mapParamValue in C++). */
|
|
47
|
+
export function drumParamToReal(d, x) {
|
|
48
|
+
const lo = d.lo ?? 0;
|
|
49
|
+
const hi = d.hi ?? 1;
|
|
50
|
+
const t = clamp01(x);
|
|
51
|
+
const mapSegment = (segmentLo, segmentHi, segmentT) => d.curve === "exp"
|
|
52
|
+
? segmentLo * Math.pow(segmentHi / segmentLo, segmentT)
|
|
53
|
+
: segmentLo + (segmentHi - segmentLo) * segmentT;
|
|
54
|
+
if (d.center === undefined)
|
|
55
|
+
return mapSegment(lo, hi, t);
|
|
56
|
+
if (t === 0.5)
|
|
57
|
+
return d.center;
|
|
58
|
+
return t < 0.5 ? mapSegment(lo, d.center, t * 2) : mapSegment(d.center, hi, (t - 0.5) * 2);
|
|
59
|
+
}
|
|
60
|
+
/** real engine-unit value → normalized 0..1 (the inverse). */
|
|
61
|
+
export function drumParamFromReal(d, v) {
|
|
62
|
+
const lo = d.lo ?? 0;
|
|
63
|
+
const hi = d.hi ?? 1;
|
|
64
|
+
const unmapSegment = (segmentLo, segmentHi) => {
|
|
65
|
+
if (d.curve === "exp") {
|
|
66
|
+
return clamp01(Math.log(Math.max(v, 1e-9) / segmentLo) / Math.log(segmentHi / segmentLo));
|
|
67
|
+
}
|
|
68
|
+
return segmentHi === segmentLo ? 0 : clamp01((v - segmentLo) / (segmentHi - segmentLo));
|
|
69
|
+
};
|
|
70
|
+
if (d.center === undefined)
|
|
71
|
+
return unmapSegment(lo, hi);
|
|
72
|
+
if (v === d.center)
|
|
73
|
+
return 0.5;
|
|
74
|
+
return v < d.center ? unmapSegment(lo, d.center) * 0.5 : 0.5 + unmapSegment(d.center, hi) * 0.5;
|
|
75
|
+
}
|
|
76
|
+
export const isDrumSlotEdited = (value, curatedDefault) => {
|
|
77
|
+
const numeric = Number(value);
|
|
78
|
+
if (!Number.isFinite(numeric))
|
|
79
|
+
return false;
|
|
80
|
+
return Math.abs(numeric - curatedDefault) > DRUM_SLOT_EDIT_EPSILON;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Move an edited value from one engine's slot to another's. `pct` slots carry the
|
|
84
|
+
* knob POSITION because their display IS the position; every unit-bearing family
|
|
85
|
+
* carries the engine value, re-normalized through the destination's own map and
|
|
86
|
+
* clamped into its range. Returns undefined when the two slots are not the same
|
|
87
|
+
* quantity.
|
|
88
|
+
*/
|
|
89
|
+
export const carryDrumSlotValue = (src, dst, value) => {
|
|
90
|
+
if (!src || !dst)
|
|
91
|
+
return undefined;
|
|
92
|
+
const family = DRUM_CARRY_FAMILY[src.kind];
|
|
93
|
+
if (family === undefined || family !== DRUM_CARRY_FAMILY[dst.kind])
|
|
94
|
+
return undefined;
|
|
95
|
+
if (family === "pct")
|
|
96
|
+
return clamp01(value);
|
|
97
|
+
const real = drumParamToReal(src, value);
|
|
98
|
+
const lo = dst.lo ?? 0;
|
|
99
|
+
const hi = dst.hi ?? 1;
|
|
100
|
+
const bounded = Math.min(Math.max(real, Math.min(lo, hi)), Math.max(lo, hi));
|
|
101
|
+
return clamp01(drumParamFromReal(dst, bounded));
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* A drawn amp envelope shapes EVERY engine and its C++ latch is one-way, so an
|
|
105
|
+
* untouched (absent, or flat-at-unity over the default window) contour is cleared
|
|
106
|
+
* when the engine changes. Anything the user actually drew survives.
|
|
107
|
+
*/
|
|
108
|
+
export const isDrumAmpEnvUntouched = (curve, timeMs) => {
|
|
109
|
+
const time = Number(timeMs ?? DEFAULT_DRUM_AMP_TIME_MS);
|
|
110
|
+
if (Number.isFinite(time) && Math.abs(time - DEFAULT_DRUM_AMP_TIME_MS) > 1e-6)
|
|
111
|
+
return false;
|
|
112
|
+
if (!Array.isArray(curve) || curve.length === 0)
|
|
113
|
+
return true;
|
|
114
|
+
if (curve.length !== DEFAULT_DRUM_AMP_CURVE.length)
|
|
115
|
+
return false;
|
|
116
|
+
return curve.every((point, i) => {
|
|
117
|
+
const ref = DEFAULT_DRUM_AMP_CURVE[i];
|
|
118
|
+
return (Math.abs(Number(point?.t) - ref.t) < 1e-6
|
|
119
|
+
&& Math.abs(Number(point?.v) - ref.v) < 1e-6
|
|
120
|
+
&& Math.abs(Number(point?.tension ?? 0) - (ref.tension ?? 0)) < 1e-6);
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Empty array, not the flat curve: sampler.ts omits the ampEnvCurveLUT prop for an
|
|
125
|
+
* empty array and emits ampEnvActive: 0, which clears the node's one-way latch on
|
|
126
|
+
* the rebuild an engine change always triggers.
|
|
127
|
+
*/
|
|
128
|
+
export const drumAmpEnvResetDelta = (cellId) => ({
|
|
129
|
+
[`cell${cellId}_synthAmpCurve`]: [],
|
|
130
|
+
[`cell${cellId}_synthAmpTime`]: DEFAULT_DRUM_AMP_TIME_MS,
|
|
131
|
+
});
|
|
132
|
+
export const drumSynthParamKey = (cellId, slot) => `cell${cellId}_synth_p${slot}`; // slot is 1-based
|
|
133
|
+
/**
|
|
134
|
+
* Project the registry into the roster + switch rule. Taking the parsed JSON as an
|
|
135
|
+
* argument (rather than importing it) is what lets the published package read the
|
|
136
|
+
* copy vendored into dist/ while the repo checkout reads shared/.
|
|
137
|
+
*/
|
|
138
|
+
export function createDrumSynthCatalog(registry) {
|
|
139
|
+
const bySlot = registry.engines;
|
|
140
|
+
const ids = Object.keys(bySlot)
|
|
141
|
+
.map(Number)
|
|
142
|
+
.sort((a, b) => a - b);
|
|
143
|
+
const engineNames = ["Off", ...ids.map((id) => bySlot[String(id)].name)];
|
|
144
|
+
const engines = ids.map((id) => ({
|
|
145
|
+
id,
|
|
146
|
+
name: bySlot[String(id)].name,
|
|
147
|
+
params: bySlot[String(id)].slots.map((s) => ({
|
|
148
|
+
label: s.label,
|
|
149
|
+
default: s.default,
|
|
150
|
+
...(s.bipolar ? { bipolar: true } : {}),
|
|
151
|
+
...(s.rand ? { rand: s.rand } : {}),
|
|
152
|
+
})),
|
|
153
|
+
}));
|
|
154
|
+
const display = Object.fromEntries(ids.map((id) => [id, bySlot[String(id)].slots]));
|
|
155
|
+
const getEngine = (engineId) => engines.find((e) => e.id === engineId);
|
|
156
|
+
const getDisplay = (engineId, slot) => display[engineId]?.[slot - 1];
|
|
157
|
+
const buildEngineSwitchDelta = (cellId, nextEngineId, state) => {
|
|
158
|
+
const delta = { [`cell${cellId}_synthEngine`]: nextEngineId };
|
|
159
|
+
const nextEngine = getEngine(nextEngineId);
|
|
160
|
+
if (!nextEngine)
|
|
161
|
+
return delta;
|
|
162
|
+
const currentEngineId = Math.round(Number(state[`cell${cellId}_synthEngine`] ?? 0));
|
|
163
|
+
const currentEngine = getEngine(currentEngineId);
|
|
164
|
+
// Only slots the user MOVED off their curated default travel. An untouched
|
|
165
|
+
// cell therefore lands on the destination's factory voice exactly.
|
|
166
|
+
const editedByLabel = new Map();
|
|
167
|
+
currentEngine?.params.forEach((param, index) => {
|
|
168
|
+
const value = Number(state[drumSynthParamKey(cellId, index + 1)]);
|
|
169
|
+
if (isDrumSlotEdited(value, param.default)) {
|
|
170
|
+
editedByLabel.set(param.label, { slot: index + 1, value });
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
for (let i = 0; i < DRUM_SYNTH_PARAMS_PER_CELL; i++) {
|
|
174
|
+
const nextParam = nextEngine.params[i];
|
|
175
|
+
const paramId = drumSynthParamKey(cellId, i + 1);
|
|
176
|
+
if (!nextParam) {
|
|
177
|
+
delta[paramId] = 0.5; // manifest default for an unused slot
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const edited = editedByLabel.get(nextParam.label);
|
|
181
|
+
const carried = edited
|
|
182
|
+
? carryDrumSlotValue(getDisplay(currentEngineId, edited.slot), getDisplay(nextEngineId, i + 1), edited.value)
|
|
183
|
+
: undefined;
|
|
184
|
+
delta[paramId] = carried ?? nextParam.default;
|
|
185
|
+
}
|
|
186
|
+
if (isDrumAmpEnvUntouched(state[`cell${cellId}_synthAmpCurve`], state[`cell${cellId}_synthAmpTime`])) {
|
|
187
|
+
Object.assign(delta, drumAmpEnvResetDelta(cellId));
|
|
188
|
+
}
|
|
189
|
+
return delta;
|
|
190
|
+
};
|
|
191
|
+
return { engineNames, engines, getEngine, getDisplay, buildEngineSwitchDelta };
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=drumSynth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drumSynth.js","sourceRoot":"","sources":["../src/drumSynth.ts"],"names":[],"mappings":"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"}
|