@map-audio/pam-mcp-server 1.22.0 → 1.27.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.
Files changed (52) hide show
  1. package/README.md +33 -6
  2. package/dist/audioAnalysis.d.ts +1 -1
  3. package/dist/audioAnalysis.js +3 -4
  4. package/dist/audioAnalysis.js.map +1 -1
  5. package/dist/bridge.d.ts +4 -0
  6. package/dist/bridge.js +53 -160
  7. package/dist/bridge.js.map +1 -1
  8. package/dist/drumSynth.js +1 -1
  9. package/dist/drumSynth.js.map +1 -1
  10. package/dist/drumSynthEngines.json +1 -1
  11. package/dist/fgemma-runner.js +20 -4
  12. package/dist/fgemma-runner.js.map +1 -1
  13. package/dist/generated/kvWriteOptions.d.ts +20 -0
  14. package/dist/generated/kvWriteOptions.js +45 -0
  15. package/dist/generated/kvWriteOptions.js.map +1 -0
  16. package/dist/generated/variationSnapshot.d.ts +8 -4
  17. package/dist/generated/variationSnapshot.js +6 -23
  18. package/dist/generated/variationSnapshot.js.map +1 -1
  19. package/dist/generativePlayerPresets.json +70 -0
  20. package/dist/generativePlayers.json +134 -0
  21. package/dist/manifest-cell1.json +2 -2
  22. package/dist/manifest-mfx.json +178 -37
  23. package/dist/manifest-msq.json +9564 -0
  24. package/dist/manifest.d.ts +1 -1
  25. package/dist/manifest.js +17 -9
  26. package/dist/manifest.js.map +1 -1
  27. package/dist/manifest.json +11227 -2841
  28. package/dist/mfxCombos.js +1 -1
  29. package/dist/mfxCombos.js.map +1 -1
  30. package/dist/midiFile.d.ts +21 -0
  31. package/dist/midiFile.js +108 -0
  32. package/dist/midiFile.js.map +1 -0
  33. package/dist/mixAssist.d.ts +35 -0
  34. package/dist/mixAssist.js +247 -19
  35. package/dist/mixAssist.js.map +1 -1
  36. package/dist/patternLanes.d.ts +40 -0
  37. package/dist/patternLanes.js +108 -0
  38. package/dist/patternLanes.js.map +1 -0
  39. package/dist/players.d.ts +89 -0
  40. package/dist/players.js +235 -0
  41. package/dist/players.js.map +1 -0
  42. package/dist/presetSave.d.ts +8 -0
  43. package/dist/presetSave.js +35 -0
  44. package/dist/presetSave.js.map +1 -1
  45. package/dist/sampleSlicing.d.ts +12 -0
  46. package/dist/sampleSlicing.js +78 -0
  47. package/dist/sampleSlicing.js.map +1 -0
  48. package/dist/server.js +1828 -525
  49. package/dist/server.js.map +1 -1
  50. package/dist/targetDenylist.json +20 -0
  51. package/dist/variationSessionKeys.json +34 -1
  52. package/package.json +5 -4
@@ -0,0 +1,108 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export const VALUE_LANES = ["pitch", "slice", "stretch"];
5
+ export const CC_LANES = ["ccOut1", "ccOut2", "ccOut3", "ccOut4"];
6
+ export const PARAM_LANES = ["paramLane1", "paramLane2", "paramLane3", "paramLane4"];
7
+ export const PATTERN_LANE_IDS = ["note", ...VALUE_LANES, ...CC_LANES, ...PARAM_LANES];
8
+ /** State-key suffix per lane: `cell{N}_<suffix>`. */
9
+ export const PATTERN_LANE_SUFFIX = {
10
+ note: "midiSequence",
11
+ pitch: "pitchSequence",
12
+ slice: "sliceSequence",
13
+ stretch: "stretchSequence",
14
+ ccOut1: "ccOut1Sequence",
15
+ ccOut2: "ccOut2Sequence",
16
+ ccOut3: "ccOut3Sequence",
17
+ ccOut4: "ccOut4Sequence",
18
+ paramLane1: "paramLane1Sequence",
19
+ paramLane2: "paramLane2Sequence",
20
+ paramLane3: "paramLane3Sequence",
21
+ paramLane4: "paramLane4Sequence",
22
+ };
23
+ /** The cells-object field holding a param lane's target suffix ("" = none). */
24
+ export const LANE_TARGET_FIELD = {
25
+ paramLane1: "paramLaneTarget1",
26
+ paramLane2: "paramLaneTarget2",
27
+ paramLane3: "paramLaneTarget3",
28
+ paramLane4: "paramLaneTarget4",
29
+ };
30
+ export const isCcLane = (lane) => CC_LANES.includes(lane);
31
+ export const isParamLane = (lane) => PARAM_LANES.includes(lane);
32
+ export const ccLaneIndex = (lane) => Number(lane.slice("ccOut".length));
33
+ /** Sixteen CC out slots per cell (cell config ccOutCc{K}); each CC lane locks one (ccLaneSlot{L}, 0 = none). */
34
+ export const CC_OUT_SLOTS = Array.from({ length: 16 }, (_, index) => index + 1);
35
+ export const CC_OUT_CONFIG_KEYS = CC_OUT_SLOTS.map((slot) => `ccOutCc${slot}`);
36
+ export const isCcOutValueSuffix = (suffix) => /^ccOut\d{1,2}$/.test(suffix);
37
+ export const ccLaneSlotField = (lane) => `ccLaneSlot${ccLaneIndex(lane)}`;
38
+ /** The slot a CC lane locks in `cell`, as the engine reads it: lane L's default is slot L. */
39
+ export function ccLaneSlotOf(cell, lane) {
40
+ const raw = cell[ccLaneSlotField(lane)];
41
+ const slot = Math.round(Number(raw ?? ccLaneIndex(lane)));
42
+ return Number.isInteger(slot) && slot >= 1 && slot <= CC_OUT_SLOTS.length ? slot : 0;
43
+ }
44
+ // shared/patternLanes/targetDenylist.json is the one list the UI, this server and the engine read.
45
+ const TARGET_DENYLIST = (() => {
46
+ const here = dirname(fileURLToPath(import.meta.url));
47
+ const candidates = [
48
+ resolve(here, "..", "..", "..", "shared", "patternLanes", "targetDenylist.json"),
49
+ resolve(here, "targetDenylist.json"),
50
+ ];
51
+ for (const file of candidates) {
52
+ if (!existsSync(file))
53
+ continue;
54
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
55
+ return { exact: parsed.exact ?? [], prefixes: parsed.prefixes ?? [], unreachable: parsed.unreachable ?? [] };
56
+ }
57
+ throw new Error("pam-mcp: shared/patternLanes/targetDenylist.json not found; rebuild the package.");
58
+ })();
59
+ function isDeniedLaneTarget(suffix) {
60
+ return (TARGET_DENYLIST.exact.includes(suffix) ||
61
+ TARGET_DENYLIST.unreachable.includes(suffix) ||
62
+ TARGET_DENYLIST.prefixes.some((prefix) => suffix.startsWith(prefix)));
63
+ }
64
+ /** The manifest parameter a param lane may be pointed at, or a reason it may not. */
65
+ export function resolveLaneTarget(cellId, suffix, parameters) {
66
+ if (isDeniedLaneTarget(suffix))
67
+ return { reason: `${suffix} cannot be a lane target` };
68
+ const param = parameters.find((p) => p.paramId === `cell${cellId}_${suffix}`);
69
+ if (!param)
70
+ return { reason: `cell${cellId}_${suffix} is not a parameter of this product` };
71
+ if (param.isModulatable !== true)
72
+ return { reason: `cell${cellId}_${suffix} is not modulatable` };
73
+ return { param };
74
+ }
75
+ export function productHasLane(cellId, lane, stateVariables) {
76
+ const key = `cell${cellId}_${PATTERN_LANE_SUFFIX[lane]}`;
77
+ return (stateVariables ?? []).some((entry) => entry.paramId === key);
78
+ }
79
+ const finiteOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
80
+ /** CC lane events: integer 0..127 values, bar height equal to the value (a CC bar floors at 0), no pitch fields. */
81
+ export function normalizeCcLaneEvents(events) {
82
+ return events.map((event) => {
83
+ const { pitch: _pitch, pitchRnd: _pitchRnd, ...rest } = event;
84
+ const value = Math.max(0, Math.min(127, Math.round(finiteOr(event.value, 64))));
85
+ return { time: 0, duration: 0.25, prob: 1, ...rest, value, velocity: value };
86
+ });
87
+ }
88
+ // Steps a value like its knob (interface/src/utils/paramScale.ts), so the lane holds what the knob could.
89
+ function stepLikeKnob(value, param) {
90
+ return param.step > 0 && param.step < param.max - param.min ? Math.round(value / param.step) * param.step : value;
91
+ }
92
+ /** A param lane's events, clamped to its target's range and stepped like its knob. */
93
+ export function normalizeTargetLaneEvents(events, param) {
94
+ const span = param.max - param.min;
95
+ return events.map((event) => {
96
+ const { pitch: _pitch, pitchRnd: _pitchRnd, ...rest } = event;
97
+ const clamp = (v) => Math.max(param.min, Math.min(param.max, v));
98
+ const value = clamp(stepLikeKnob(clamp(finiteOr(event.value, param.defaultValue)), param));
99
+ const normalized = span > 0 ? Math.pow((value - param.min) / span, param.skew) : 0;
100
+ return { time: 0, duration: 0.25, prob: 1, ...rest, value, velocity: Math.round(normalized * 127) };
101
+ });
102
+ }
103
+ /** A CC lane may land on a destination slot only when that slot is Off or wired to the same controller. */
104
+ export function ccLaneMayLand(sourceController, destinationController) {
105
+ const dst = typeof destinationController === "number" ? destinationController : -1;
106
+ return dst < 0 || dst === sourceController;
107
+ }
108
+ //# sourceMappingURL=patternLanes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patternLanes.js","sourceRoot":"","sources":["../src/patternLanes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ export interface PlayerSlotSpec {
2
+ label: string;
3
+ default: number;
4
+ steps?: number;
5
+ stepLabels?: string[];
6
+ hint?: string;
7
+ center?: boolean;
8
+ }
9
+ export interface PlayerSpec {
10
+ id: number;
11
+ name: string;
12
+ tag: "drum" | "melodic" | "both";
13
+ replay: boolean;
14
+ blurb: string;
15
+ defaults: {
16
+ density: number;
17
+ mutate: number;
18
+ };
19
+ slots: PlayerSlotSpec[];
20
+ }
21
+ export interface PlayerPreset {
22
+ name: string;
23
+ density: number;
24
+ mutate: number;
25
+ p: number[];
26
+ }
27
+ export declare const PLAYER_SLOT_FIELDS: readonly ["playerP1", "playerP2", "playerP3", "playerP4", "playerP5"];
28
+ export type PlayerSlotField = (typeof PLAYER_SLOT_FIELDS)[number];
29
+ export type PlayerField = "playerDensity" | "playerMutate" | PlayerSlotField;
30
+ /** The seven fields that are ALSO manifest params: every write must reach both. */
31
+ export declare const MODULATABLE_PLAYER_FIELDS: readonly PlayerField[];
32
+ export declare const LISTEN_MODES: readonly ["off", "complement", "answer", "harmonic"];
33
+ export type ListenModeName = (typeof LISTEN_MODES)[number];
34
+ export declare const PATTERN_MODES: readonly ["mask", "keep"];
35
+ export type PatternModeName = (typeof PATTERN_MODES)[number];
36
+ /** "No arm on record" in the persisted poly ledger (interface/src/utils/playerPolyArm.ts). */
37
+ export declare const NO_POLY_ARM = -1;
38
+ export declare const PLAYER_GENRES: readonly ["boom_bap", "trap", "drill", "house", "techno", "dnb", "idm"];
39
+ export type PlayerGenre = (typeof PLAYER_GENRES)[number];
40
+ export declare const GENERATIVE_PLAYERS: PlayerSpec[];
41
+ export declare const PLAYER_NAMES: string[];
42
+ export declare const getPlayerSpec: (type: number) => PlayerSpec | undefined;
43
+ /** A roster name (any case) or a numeric id; undefined for anything else. */
44
+ export declare function resolvePlayerSpec(ref: string | number): PlayerSpec | undefined;
45
+ export declare const playerPresetsFor: (type: number) => PlayerPreset[];
46
+ export declare function resolvePlayerPreset(spec: PlayerSpec, name: string): PlayerPreset | undefined;
47
+ /** The roster's own voicing for a type pick — what setCellPlayer seeds before the caller's fields. */
48
+ export declare function playerDefaultsFor(type: number): Record<string, number>;
49
+ export declare function presetConfig(preset: PlayerPreset): Record<string, number>;
50
+ /** A detented field writes exactly i/(steps-1); continuous is the clamped identity. */
51
+ export declare function snapPlayerValue(steps: number | undefined, value: number): number;
52
+ export declare function playerSlotStepIndex(slot: PlayerSlotSpec, value: number): number;
53
+ export declare function playerSlotDisplay(slot: PlayerSlotSpec, value: number): string;
54
+ export declare const playerDensityDisplay: (value: number) => string;
55
+ export declare const playerMutateDisplay: (value: number) => string;
56
+ /**
57
+ * A slot write from an agent: a 0..1 position (snapped to the slot's detents) or,
58
+ * on a labelled slot, one of its step labels. Returns an error string on a miss.
59
+ */
60
+ export declare function resolveSlotValue(slot: PlayerSlotSpec, input: number | string): number | string;
61
+ export interface PlayerGenreSlot {
62
+ index: number;
63
+ genres: PlayerGenre[];
64
+ }
65
+ /** The slot whose detents all name randomizer genres — found from the registry, never hardcoded. */
66
+ export declare function playerGenreSlot(spec: PlayerSpec | undefined): PlayerGenreSlot | undefined;
67
+ export declare function playerGenreConfig(spec: PlayerSpec | undefined, genre: string | undefined): Record<string, number>;
68
+ export interface RolePlayerConfig {
69
+ playerType: number;
70
+ playerP1?: number;
71
+ playerP5?: number;
72
+ isPoly?: number;
73
+ }
74
+ export declare const DEFAULT_PLAYER_TYPE = 2;
75
+ export declare const rolePlayerConfigFor: (cellId: number) => RolePlayerConfig;
76
+ export declare const roleSpreadSummary: () => Record<number, string>;
77
+ export declare const isMelodicPlayer: (spec: PlayerSpec | undefined) => boolean;
78
+ /** uint31 so the seed round-trips through every JSON/number layer intact. */
79
+ export declare const randomPlayerSeed: () => number;
80
+ export declare const cellPlayerType: (cell: Record<string, unknown> | undefined) => number;
81
+ /**
82
+ * Human-readable summary of a cell's running player. The seven modulatable
83
+ * fields are read from the PARAMS (`cell{N}_player*`) with the config as the
84
+ * fallback, because only a UI write mirrors the two and an automated move
85
+ * leaves the config behind.
86
+ */
87
+ export declare function describeCellPlayer(cellId: number, cell: Record<string, unknown> | undefined, state: Record<string, unknown>): Record<string, unknown> | undefined;
88
+ /** The roster as an agent-facing catalogue: one entry per player, presets attached. */
89
+ export declare function describePlayerSpec(spec: PlayerSpec, includePresets: boolean): Record<string, unknown>;
@@ -0,0 +1,235 @@
1
+ // Generative Players (per-cell PLAYER mode) for the MCP server, read from the
2
+ // two shared registries build.js and the UI consume; vendored into dist/ by
3
+ // scripts/build-postprocess.mjs.
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { dirname, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ export const PLAYER_SLOT_FIELDS = ["playerP1", "playerP2", "playerP3", "playerP4", "playerP5"];
8
+ /** The seven fields that are ALSO manifest params: every write must reach both. */
9
+ export const MODULATABLE_PLAYER_FIELDS = ["playerDensity", "playerMutate", ...PLAYER_SLOT_FIELDS];
10
+ export const LISTEN_MODES = ["off", "complement", "answer", "harmonic"];
11
+ export const PATTERN_MODES = ["mask", "keep"];
12
+ /** "No arm on record" in the persisted poly ledger (interface/src/utils/playerPolyArm.ts). */
13
+ export const NO_POLY_ARM = -1;
14
+ export const PLAYER_GENRES = ["boom_bap", "trap", "drill", "house", "techno", "dnb", "idm"];
15
+ function readRegistry(fileName, valid) {
16
+ const here = dirname(fileURLToPath(import.meta.url));
17
+ const candidates = [
18
+ resolve(here, "..", "..", "..", "shared", fileName), // repo checkout
19
+ resolve(here, fileName), // published dist/
20
+ ];
21
+ for (const file of candidates) {
22
+ if (!existsSync(file))
23
+ continue;
24
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
25
+ if (valid(parsed))
26
+ return parsed;
27
+ }
28
+ throw new Error(`pam-mcp: ${fileName} not found. Rebuild the package (scripts/build-postprocess.mjs vendors it into dist/) — ` +
29
+ "arming a player without it would write values that disagree with the plugin.");
30
+ }
31
+ const REGISTRY = readRegistry("generativePlayers.json", (parsed) => !!parsed.players && Object.keys(parsed.players).length > 0);
32
+ const PRESETS = readRegistry("generativePlayerPresets.json", (parsed) => !!parsed.presets);
33
+ export const GENERATIVE_PLAYERS = Object.keys(REGISTRY.players)
34
+ .map(Number)
35
+ .sort((a, b) => a - b)
36
+ .map((id) => ({ id, ...REGISTRY.players[String(id)] }));
37
+ const BY_ID = new Map(GENERATIVE_PLAYERS.map((spec) => [spec.id, spec]));
38
+ const BY_NAME = new Map(GENERATIVE_PLAYERS.map((spec) => [spec.name.toLowerCase(), spec]));
39
+ export const PLAYER_NAMES = GENERATIVE_PLAYERS.map((spec) => spec.name);
40
+ export const getPlayerSpec = (type) => BY_ID.get(Math.round(type));
41
+ /** A roster name (any case) or a numeric id; undefined for anything else. */
42
+ export function resolvePlayerSpec(ref) {
43
+ if (typeof ref === "number")
44
+ return getPlayerSpec(ref);
45
+ const trimmed = ref.trim();
46
+ if (/^\d+$/.test(trimmed))
47
+ return getPlayerSpec(Number(trimmed));
48
+ return BY_NAME.get(trimmed.toLowerCase());
49
+ }
50
+ export const playerPresetsFor = (type) => PRESETS.presets[String(Math.round(type))] ?? [];
51
+ export function resolvePlayerPreset(spec, name) {
52
+ const wanted = name.trim().toLowerCase();
53
+ return playerPresetsFor(spec.id).find((preset) => preset.name.toLowerCase() === wanted);
54
+ }
55
+ /** The roster's own voicing for a type pick — what setCellPlayer seeds before the caller's fields. */
56
+ export function playerDefaultsFor(type) {
57
+ const spec = getPlayerSpec(type);
58
+ const out = {
59
+ playerType: type,
60
+ playerDensity: spec?.defaults.density ?? 0.5,
61
+ playerMutate: spec?.defaults.mutate ?? 0.25,
62
+ };
63
+ PLAYER_SLOT_FIELDS.forEach((field, i) => {
64
+ out[field] = spec?.slots[i]?.default ?? 0.5;
65
+ });
66
+ return out;
67
+ }
68
+ export function presetConfig(preset) {
69
+ const out = { playerDensity: preset.density, playerMutate: preset.mutate };
70
+ preset.p.forEach((value, i) => {
71
+ const field = PLAYER_SLOT_FIELDS[i];
72
+ if (field)
73
+ out[field] = value;
74
+ });
75
+ return out;
76
+ }
77
+ /** A detented field writes exactly i/(steps-1); continuous is the clamped identity. */
78
+ export function snapPlayerValue(steps, value) {
79
+ const clamped = Math.max(0, Math.min(1, value));
80
+ if (!steps || steps < 2)
81
+ return clamped;
82
+ return Math.round(clamped * (steps - 1)) / (steps - 1);
83
+ }
84
+ export function playerSlotStepIndex(slot, value) {
85
+ if (!slot.steps || slot.steps < 2)
86
+ return 0;
87
+ const clamped = Math.max(0, Math.min(1, value));
88
+ return Math.max(0, Math.min(slot.steps - 1, Math.round(clamped * (slot.steps - 1))));
89
+ }
90
+ export function playerSlotDisplay(slot, value) {
91
+ if (slot.steps && slot.stepLabels)
92
+ return slot.stepLabels[playerSlotStepIndex(slot, value)] ?? "";
93
+ if (slot.steps && slot.steps >= 2)
94
+ return String(playerSlotStepIndex(slot, value));
95
+ const clamped = Math.max(0, Math.min(1, value));
96
+ if (slot.center) {
97
+ const signed = Math.round((clamped - 0.5) * 200);
98
+ return signed > 0 ? `+${signed}%` : `${signed}%`;
99
+ }
100
+ return `${Math.round(clamped * 100)}%`;
101
+ }
102
+ export const playerDensityDisplay = (value) => `${Math.round(value * 100)}%`;
103
+ export const playerMutateDisplay = (value) => (value < 0.02 ? "Lock" : `${Math.round(value * 100)}%`);
104
+ /**
105
+ * A slot write from an agent: a 0..1 position (snapped to the slot's detents) or,
106
+ * on a labelled slot, one of its step labels. Returns an error string on a miss.
107
+ */
108
+ export function resolveSlotValue(slot, input) {
109
+ if (typeof input === "number")
110
+ return snapPlayerValue(slot.steps, input);
111
+ const wanted = input.trim().toLowerCase();
112
+ if (slot.stepLabels && slot.steps) {
113
+ const index = slot.stepLabels.findIndex((label) => label.toLowerCase() === wanted);
114
+ if (index >= 0)
115
+ return index / (slot.steps - 1);
116
+ return `'${input}' is not a ${slot.label} position — one of: ${slot.stepLabels.join(", ")}.`;
117
+ }
118
+ const numeric = Number(wanted.replace(/%$/, ""));
119
+ if (Number.isFinite(numeric))
120
+ return snapPlayerValue(slot.steps, wanted.endsWith("%") ? numeric / 100 : numeric);
121
+ return `${slot.label} takes a 0..1 value${slot.steps ? ` (${slot.steps} detents)` : ""}, not '${input}'.`;
122
+ }
123
+ const normalizeGenre = (label) => {
124
+ const lowered = label.toLowerCase().trim().replace(/-/g, "_").replace(/\s+/g, "_");
125
+ return PLAYER_GENRES.includes(lowered) ? lowered : undefined;
126
+ };
127
+ /** The slot whose detents all name randomizer genres — found from the registry, never hardcoded. */
128
+ export function playerGenreSlot(spec) {
129
+ if (!spec)
130
+ return undefined;
131
+ for (let index = 0; index < spec.slots.length; index++) {
132
+ const labels = spec.slots[index].stepLabels;
133
+ if (!labels || labels.length === 0)
134
+ continue;
135
+ const genres = labels.map(normalizeGenre);
136
+ if (genres.every((genre) => genre !== undefined))
137
+ return { index, genres };
138
+ }
139
+ return undefined;
140
+ }
141
+ export function playerGenreConfig(spec, genre) {
142
+ const slot = spec ? playerGenreSlot(spec) : undefined;
143
+ const wanted = genre ? normalizeGenre(genre) : undefined;
144
+ if (!spec || !slot || !wanted)
145
+ return {};
146
+ const position = slot.genres.indexOf(wanted);
147
+ if (position < 0)
148
+ return {};
149
+ const steps = spec.slots[slot.index].steps ?? 1;
150
+ return { [PLAYER_SLOT_FIELDS[slot.index]]: position / (steps - 1) };
151
+ }
152
+ // Twin of ROLE_PLAYER_CONFIGS in interface/src/utils/generativePlayers.ts
153
+ // (KIT's positional cellId → role table); scripts/check-parity.mjs diffs them.
154
+ const ROLE_PLAYER_CONFIGS = {
155
+ 1: { playerType: 2 },
156
+ 2: { playerType: 6, playerP1: 1 / 3 },
157
+ 3: { playerType: 1 },
158
+ 4: { playerType: 7 },
159
+ 5: { playerType: 4, isPoly: 1 },
160
+ 6: { playerType: 3 },
161
+ 7: { playerType: 5, playerP5: 2 / 5, isPoly: 1 },
162
+ 8: { playerType: 8, playerP5: 3 / 5, isPoly: 1 },
163
+ };
164
+ export const DEFAULT_PLAYER_TYPE = 2;
165
+ export const rolePlayerConfigFor = (cellId) => ROLE_PLAYER_CONFIGS[cellId] ?? { playerType: DEFAULT_PLAYER_TYPE };
166
+ export const roleSpreadSummary = () => Object.fromEntries(Object.entries(ROLE_PLAYER_CONFIGS).map(([cellId, config]) => [
167
+ Number(cellId),
168
+ getPlayerSpec(config.playerType)?.name ?? String(config.playerType),
169
+ ]));
170
+ export const isMelodicPlayer = (spec) => spec?.tag === "melodic";
171
+ /** uint31 so the seed round-trips through every JSON/number layer intact. */
172
+ export const randomPlayerSeed = () => Math.floor(Math.random() * 0x7fffffff);
173
+ export const cellPlayerType = (cell) => Math.round(Number(cell?.playerType ?? 0));
174
+ const numberOr = (value, fallback) => {
175
+ const n = Number(value);
176
+ return Number.isFinite(n) ? n : fallback;
177
+ };
178
+ /**
179
+ * Human-readable summary of a cell's running player. The seven modulatable
180
+ * fields are read from the PARAMS (`cell{N}_player*`) with the config as the
181
+ * fallback, because only a UI write mirrors the two and an automated move
182
+ * leaves the config behind.
183
+ */
184
+ export function describeCellPlayer(cellId, cell, state) {
185
+ const type = cellPlayerType(cell);
186
+ const spec = getPlayerSpec(type);
187
+ if (!spec)
188
+ return undefined;
189
+ const readField = (field, fallback) => numberOr(state[`cell${cellId}_${field}`], numberOr(cell?.[field], fallback));
190
+ const slots = {};
191
+ spec.slots.forEach((slot, i) => {
192
+ const field = PLAYER_SLOT_FIELDS[i];
193
+ slots[slot.label] = playerSlotDisplay(slot, readField(field, slot.default));
194
+ });
195
+ const density = readField("playerDensity", spec.defaults.density);
196
+ const mutate = readField("playerMutate", spec.defaults.mutate);
197
+ const listenMode = Math.round(numberOr(cell?.playerListenMode, 0));
198
+ return {
199
+ id: spec.id,
200
+ name: spec.name,
201
+ density: playerDensityDisplay(density),
202
+ mutate: playerMutateDisplay(mutate),
203
+ slots,
204
+ seed: Math.round(numberOr(cell?.playerSeed, 0)),
205
+ patternMode: PATTERN_MODES[Math.round(numberOr(cell?.playerPatternMode, 0))] ?? "mask",
206
+ listen: listenMode > 0
207
+ ? {
208
+ mode: LISTEN_MODES[listenMode] ?? "off",
209
+ source: Math.round(numberOr(cell?.playerListenSource, 0)),
210
+ amount: numberOr(cell?.playerListenAmount, 0.5),
211
+ }
212
+ : undefined,
213
+ };
214
+ }
215
+ /** The roster as an agent-facing catalogue: one entry per player, presets attached. */
216
+ export function describePlayerSpec(spec, includePresets) {
217
+ return {
218
+ id: spec.id,
219
+ name: spec.name,
220
+ tag: spec.tag,
221
+ blurb: spec.blurb,
222
+ defaults: spec.defaults,
223
+ slots: spec.slots.map((slot, i) => ({
224
+ arg: `p${i + 1}`,
225
+ label: slot.label,
226
+ default: slot.default,
227
+ ...(slot.steps && slot.steps >= 2
228
+ ? { detents: slot.steps, ...(slot.stepLabels ? { positions: slot.stepLabels } : {}) }
229
+ : { range: slot.center ? "bipolar 0..1, centre 0.5" : "0..1" }),
230
+ ...(slot.hint ? { hint: slot.hint } : {}),
231
+ })),
232
+ ...(includePresets ? { presets: playerPresetsFor(spec.id).map((preset) => preset.name) } : {}),
233
+ };
234
+ }
235
+ //# sourceMappingURL=players.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"players.js","sourceRoot":"","sources":["../src/players.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,9 @@
1
+ import { Buffer } from "node:buffer";
1
2
  /** Strip the library prefix accepted by MCP tools before resolving a preset on disk. */
2
3
  export declare function normalizePresetLookupPath(presetPath: string): string;
4
+ /** Native resolves relative preset paths against the product base folder, which holds Presets/. */
5
+ export declare function nativePresetPath(presetPath: string): string;
6
+ export declare function isFactoryPresetPath(presetPath: string): boolean;
3
7
  /**
4
8
  * Select the preset whose variation bank a save operation should preserve.
5
9
  *
@@ -8,3 +12,7 @@ export declare function normalizePresetLookupPath(presetPath: string): string;
8
12
  * destination remains the only useful source (for explicit-path overwrites).
9
13
  */
10
14
  export declare function selectSaveVariationSourcePath(activePresetPath: unknown, destinationPath: string): string;
15
+ export declare function parsePresetFile(raw: string | Buffer): {
16
+ metadata: Record<string, unknown>;
17
+ data: Record<string, unknown>;
18
+ };
@@ -1,9 +1,23 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { isAbsolute, posix } from "node:path";
1
3
  /** Strip the library prefix accepted by MCP tools before resolving a preset on disk. */
2
4
  export function normalizePresetLookupPath(presetPath) {
3
5
  return presetPath.startsWith("Presets/")
4
6
  ? presetPath.slice("Presets/".length)
5
7
  : presetPath;
6
8
  }
9
+ /** Native resolves relative preset paths against the product base folder, which holds Presets/. */
10
+ export function nativePresetPath(presetPath) {
11
+ if (isAbsolute(presetPath))
12
+ return presetPath;
13
+ const normalized = presetPath.replaceAll("\\", "/");
14
+ return /^presets\//i.test(normalized) ? normalized : `Presets/${normalized}`;
15
+ }
16
+ // Native collapses "." / ".." / "//" and the macOS volume is case-insensitive, so match that form.
17
+ export function isFactoryPresetPath(presetPath) {
18
+ const resolved = posix.normalize(nativePresetPath(presetPath).replaceAll("\\", "/")).toLowerCase();
19
+ return /(^|\/)presets\/(factory|default)\//.test(resolved);
20
+ }
7
21
  /**
8
22
  * Select the preset whose variation bank a save operation should preserve.
9
23
  *
@@ -19,4 +33,25 @@ export function selectSaveVariationSourcePath(activePresetPath, destinationPath)
19
33
  }
20
34
  return normalizePresetLookupPath(destinationPath);
21
35
  }
36
+ export function parsePresetFile(raw) {
37
+ const bytes = typeof raw === "string" ? Buffer.from(raw, "utf8") : raw;
38
+ let prefixLength = 0;
39
+ while (bytes[prefixLength] >= 48 && bytes[prefixLength] <= 57)
40
+ prefixLength++;
41
+ if (prefixLength === 0)
42
+ throw new Error("invalid format (no metadata size prefix)");
43
+ const metadataSize = Number(bytes.toString("ascii", 0, prefixLength));
44
+ const dataOffset = prefixLength + metadataSize;
45
+ if (!Number.isSafeInteger(metadataSize) || metadataSize <= 0 || dataOffset >= bytes.length) {
46
+ throw new Error("invalid format (metadata size out of bounds)");
47
+ }
48
+ const metadata = JSON.parse(bytes.toString("utf8", prefixLength, dataOffset));
49
+ const data = JSON.parse(bytes.toString("utf8", dataOffset));
50
+ for (const value of [metadata, data]) {
51
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
52
+ throw new Error("invalid format (metadata and data must be objects)");
53
+ }
54
+ }
55
+ return { metadata, data };
56
+ }
22
57
  //# sourceMappingURL=presetSave.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"presetSave.js","sourceRoot":"","sources":["../src/presetSave.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC1D,OAAO,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC;QACtC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QACrC,CAAC,CAAC,UAAU,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CAC3C,gBAAyB,EACzB,eAAuB;IAEvB,IACE,OAAO,gBAAgB,KAAK,QAAQ;QACpC,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAC3B,gBAAgB,KAAK,MAAM,EAC3B,CAAC;QACD,OAAO,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,yBAAyB,CAAC,eAAe,CAAC,CAAC;AACpD,CAAC"}
1
+ {"version":3,"file":"presetSave.js","sourceRoot":"","sources":["../src/presetSave.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { WavData } from "./audioAnalysis.js";
2
+ /** interface/src/stores/SliceProperties.ts MAX_SLICES */
3
+ export declare const MAX_SLICES = 64;
4
+ /** Sorted, clamped, deduplicated 0..1 boundaries that always start at 0 and end at 1. */
5
+ export declare function normalizeBoundaries(input: number[]): number[];
6
+ export declare function equalBoundaries(count: number): number[];
7
+ /**
8
+ * Onset positions (0..1 of the file) from half-wave-rectified log-energy
9
+ * flux, peak-picked with a 40 ms refractory window. `sensitivity` 0..1 lowers
10
+ * the threshold; at most `maxSlices - 1` onsets survive, strongest first.
11
+ */
12
+ export declare function detectOnsetBoundaries(wav: WavData, sensitivity?: number, maxSlices?: number): number[];
@@ -0,0 +1,78 @@
1
+ // Slice-boundary helpers for set_slices: boundary normalisation, equal division
2
+ // and a plain energy-onset detector over a decoded WAV (no plugin round trip).
3
+ /** interface/src/stores/SliceProperties.ts MAX_SLICES */
4
+ export const MAX_SLICES = 64;
5
+ /** Sorted, clamped, deduplicated 0..1 boundaries that always start at 0 and end at 1. */
6
+ export function normalizeBoundaries(input) {
7
+ const points = input
8
+ .map((v) => Math.max(0, Math.min(1, Number(v))))
9
+ .filter((v) => Number.isFinite(v))
10
+ .sort((a, b) => a - b);
11
+ const out = [0];
12
+ for (const p of points) {
13
+ if (p - out[out.length - 1] > 1e-4 && p < 1 - 1e-4)
14
+ out.push(p);
15
+ }
16
+ out.push(1);
17
+ return out;
18
+ }
19
+ export function equalBoundaries(count) {
20
+ const n = Math.max(1, Math.min(MAX_SLICES, Math.round(count)));
21
+ return Array.from({ length: n + 1 }, (_, i) => i / n);
22
+ }
23
+ /**
24
+ * Onset positions (0..1 of the file) from half-wave-rectified log-energy
25
+ * flux, peak-picked with a 40 ms refractory window. `sensitivity` 0..1 lowers
26
+ * the threshold; at most `maxSlices - 1` onsets survive, strongest first.
27
+ */
28
+ export function detectOnsetBoundaries(wav, sensitivity = 0.5, maxSlices = 32) {
29
+ const { samples, sampleRate } = wav;
30
+ const hop = Math.max(64, Math.round(sampleRate * 0.0058));
31
+ const frames = Math.floor(samples.length / hop);
32
+ if (frames < 4)
33
+ return [0, 1];
34
+ const energy = new Float64Array(frames);
35
+ for (let f = 0; f < frames; f++) {
36
+ let sum = 0;
37
+ const start = f * hop;
38
+ for (let i = 0; i < hop; i++) {
39
+ const s = samples[start + i];
40
+ sum += s * s;
41
+ }
42
+ energy[f] = 10 * Math.log10(sum / hop + 1e-10);
43
+ }
44
+ const flux = new Float64Array(frames);
45
+ let mean = 0;
46
+ for (let f = 1; f < frames; f++) {
47
+ flux[f] = Math.max(0, energy[f] - energy[f - 1]);
48
+ mean += flux[f];
49
+ }
50
+ mean /= frames - 1;
51
+ let variance = 0;
52
+ for (let f = 1; f < frames; f++)
53
+ variance += (flux[f] - mean) ** 2;
54
+ const std = Math.sqrt(variance / Math.max(1, frames - 2));
55
+ const clampedSensitivity = Math.max(0, Math.min(1, sensitivity));
56
+ const threshold = mean + (2.5 - 2.0 * clampedSensitivity) * std;
57
+ const floorDb = -60;
58
+ const refractory = Math.max(1, Math.round((sampleRate * 0.04) / hop));
59
+ const peaks = [];
60
+ let lastPeak = -refractory;
61
+ for (let f = 2; f < frames - 1; f++) {
62
+ if (flux[f] < threshold || energy[f] < floorDb)
63
+ continue;
64
+ if (flux[f] < flux[f - 1] || flux[f] < flux[f + 1])
65
+ continue;
66
+ if (f - lastPeak < refractory)
67
+ continue;
68
+ peaks.push({ frame: f - 1, strength: flux[f] });
69
+ lastPeak = f;
70
+ }
71
+ const keep = Math.max(0, Math.min(MAX_SLICES, Math.round(maxSlices)) - 1);
72
+ const chosen = peaks
73
+ .sort((a, b) => b.strength - a.strength)
74
+ .slice(0, keep)
75
+ .map((p) => (p.frame * hop) / samples.length);
76
+ return normalizeBoundaries(chosen);
77
+ }
78
+ //# sourceMappingURL=sampleSlicing.js.map