@map-audio/pam-mcp-server 1.21.0 → 1.25.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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -7
  3. package/dist/audioAnalysis.d.ts +35 -0
  4. package/dist/audioAnalysis.js +277 -0
  5. package/dist/audioAnalysis.js.map +1 -0
  6. package/dist/bridge.d.ts +6 -0
  7. package/dist/bridge.js +151 -168
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/corpusFingerprints.d.ts +17 -0
  10. package/dist/corpusFingerprints.js +10 -0
  11. package/dist/corpusFingerprints.js.map +1 -0
  12. package/dist/corpusRanges.d.ts +28 -0
  13. package/dist/corpusRanges.js +1029 -0
  14. package/dist/corpusRanges.js.map +1 -0
  15. package/dist/drumSynthEngines.json +376 -0
  16. package/dist/fingerprint.d.ts +70 -0
  17. package/dist/fingerprint.js +240 -0
  18. package/dist/fingerprint.js.map +1 -0
  19. package/dist/generated/variationSnapshot.d.ts +8 -4
  20. package/dist/generated/variationSnapshot.js +6 -4
  21. package/dist/generated/variationSnapshot.js.map +1 -1
  22. package/dist/generativePlayerPresets.json +70 -0
  23. package/dist/generativePlayers.json +134 -0
  24. package/dist/manifest-cell1.json +4972 -249
  25. package/dist/manifest-mfx.json +11571 -1800
  26. package/dist/manifest.d.ts +15 -3
  27. package/dist/manifest.js +24 -15
  28. package/dist/manifest.js.map +1 -1
  29. package/dist/manifest.json +25034 -499
  30. package/dist/mfxCombos.d.ts +45 -0
  31. package/dist/mfxCombos.js +499 -0
  32. package/dist/mfxCombos.js.map +1 -0
  33. package/dist/midiFile.d.ts +21 -0
  34. package/dist/midiFile.js +108 -0
  35. package/dist/midiFile.js.map +1 -0
  36. package/dist/mixAssist.d.ts +6 -0
  37. package/dist/mixAssist.js +96 -11
  38. package/dist/mixAssist.js.map +1 -1
  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 +5 -0
  43. package/dist/presetSave.js +22 -0
  44. package/dist/presetSave.js.map +1 -1
  45. package/dist/productProfile.d.ts +9 -0
  46. package/dist/productProfile.js +20 -0
  47. package/dist/productProfile.js.map +1 -0
  48. package/dist/sampleSlicing.d.ts +12 -0
  49. package/dist/sampleSlicing.js +78 -0
  50. package/dist/sampleSlicing.js.map +1 -0
  51. package/dist/server.js +2536 -483
  52. package/dist/server.js.map +1 -1
  53. package/dist/variationSessionKeys.json +34 -1
  54. package/package.json +11 -5
@@ -0,0 +1,240 @@
1
+ // Preset fingerprinting — the shared algorithm behind the corpus index
2
+ // (scripts/derive-corpus-fingerprints.ts) and the preset_novelty tool.
3
+ //
4
+ // WHY: nothing in the design pipeline ever compared a new preset against the
5
+ // ones already shipped, so every session started from the same prior and landed
6
+ // on the same centroid preset. A fingerprint plus a distance makes "does this
7
+ // already exist?" a number instead of a judgement call.
8
+ //
9
+ // The dimensions are deliberately structural rather than acoustic — they read
10
+ // straight off preset state, so novelty can be scored with no render, no audio
11
+ // and no plugin connection.
12
+ const asArray = (v) => {
13
+ if (Array.isArray(v))
14
+ return v;
15
+ if (typeof v === "string") {
16
+ try {
17
+ const p = JSON.parse(v);
18
+ return Array.isArray(p) ? p : [];
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ }
24
+ return [];
25
+ };
26
+ const asRecord = (v) => {
27
+ if (typeof v === "string") {
28
+ try {
29
+ const p = JSON.parse(v);
30
+ return p && typeof p === "object" ? p : {};
31
+ }
32
+ catch {
33
+ return {};
34
+ }
35
+ }
36
+ return v && typeof v === "object" ? v : {};
37
+ };
38
+ /** Strip take numbers, bpm tags and separators so "Kick_03_120bpm" and
39
+ * "kick-05" read as the same source. Two presets built from the same folder
40
+ * should look similar even when the exact files differ. */
41
+ const normalizeSource = (path) => path
42
+ .split(/[\\/]/)
43
+ .pop()
44
+ .replace(/\.[a-z0-9]+$/i, "")
45
+ .toLowerCase()
46
+ .replace(/\d+\s*bpm/g, "")
47
+ .replace(/[\d_\-\s]+/g, "")
48
+ .slice(0, 24);
49
+ /** Param suffix from a modulation link's target, so cell3_filterCutoff and
50
+ * cell7_filterCutoff count as the same kind of move. */
51
+ const targetFamily = (paramId) => typeof paramId === "string" ? paramId.replace(/^cell\d+_/, "").replace(/^macro_/, "macro:") : null;
52
+ export function buildFingerprint(state, defaults, effectNames, name = "candidate") {
53
+ const params = new Set();
54
+ const fx = new Set();
55
+ const chains = new Set();
56
+ const groove = [];
57
+ const pitch = new Set();
58
+ const engines = new Set();
59
+ let cells = 0;
60
+ for (let c = 1; c <= 8; c += 1) {
61
+ const seq = asArray(state[`cell${c}_midiSequence`]);
62
+ if (seq.length === 0)
63
+ continue;
64
+ cells += 1;
65
+ // The per-effect enable flags are state-only — they are NOT manifest
66
+ // parameters, so they never reach the defaults map below and have to be
67
+ // read directly. Missing this silently produced an empty fx set on every
68
+ // preset in the corpus index.
69
+ for (const slug of effectNames) {
70
+ if (state[`cell${c}_${slug}Enabled`])
71
+ fx.add(slug);
72
+ }
73
+ for (const [key, value] of Object.entries(state)) {
74
+ if (!key.startsWith(`cell${c}_`) || typeof value !== "number")
75
+ continue;
76
+ const suffix = key.slice(`cell${c}_`.length);
77
+ const def = defaults[suffix];
78
+ // A param at its default was never a decision. Only moved params
79
+ // describe the preset.
80
+ if (def === undefined || value === def)
81
+ continue;
82
+ params.add(suffix);
83
+ }
84
+ const order = asArray(state[`cell${c}_effectOrder`]).filter((s) => typeof s === "string");
85
+ if (order.length)
86
+ chains.add(order.join(">"));
87
+ // Onsets quantized to 16ths of a bar. `time` is in beats, so ×4 is a 16th
88
+ // grid; folding mod 16 compares the groove rather than the bar count.
89
+ const steps = new Set();
90
+ for (const ev of seq) {
91
+ const t = ev.time;
92
+ if (typeof t === "number")
93
+ steps.add(Math.round(t * 4) % 16);
94
+ }
95
+ if (steps.size)
96
+ groove.push(`c${c}:${[...steps].sort((a, b) => a - b).join(",")}`);
97
+ const ps = state[`cell${c}_pitchShift`];
98
+ if (typeof ps === "number" && ps !== 0)
99
+ pitch.add(ps);
100
+ const ar = state[`cell${c}_arpeg`];
101
+ if (typeof ar === "number" && ar !== 0)
102
+ pitch.add(ar);
103
+ for (const ev of asArray(state[`cell${c}_pitchSequence`])) {
104
+ const v = ev.value;
105
+ if (typeof v === "number" && v !== 0)
106
+ pitch.add(v);
107
+ }
108
+ const eng = state[`cell${c}_synthEngine`];
109
+ if (typeof eng === "number" && eng > 0)
110
+ engines.add(eng);
111
+ }
112
+ const modTargets = new Set();
113
+ const countLinks = (key) => {
114
+ const links = asArray(state[key]);
115
+ for (const l of links) {
116
+ const fam = targetFamily(l.paramId);
117
+ if (fam)
118
+ modTargets.add(fam);
119
+ }
120
+ return links.length;
121
+ };
122
+ const sources = new Set();
123
+ const cellMap = asRecord(state.cells);
124
+ for (const entry of Object.values(cellMap)) {
125
+ const fp = entry.filePath;
126
+ if (typeof fp === "string" && fp.length > 2)
127
+ sources.add(normalizeSource(fp));
128
+ }
129
+ const bpmRaw = asRecord(state.transport).bpm ?? state.bpm;
130
+ return {
131
+ name,
132
+ bpm: typeof bpmRaw === "number" ? bpmRaw : 0,
133
+ cells,
134
+ params: [...params].sort(),
135
+ fx: [...fx].sort(),
136
+ chains: [...chains].sort(),
137
+ mod: {
138
+ lfo: countLinks("lfos"),
139
+ env: countLinks("envelopes"),
140
+ vary: countLinks("vary"),
141
+ seq: countLinks("paramSeqs"),
142
+ targets: [...modTargets].sort(),
143
+ },
144
+ groove: groove.sort(),
145
+ pitch: [...pitch].sort((a, b) => a - b),
146
+ sources: [...sources].sort(),
147
+ engines: [...engines].sort((a, b) => a - b),
148
+ };
149
+ }
150
+ const jaccard = (a, b) => {
151
+ if (a.length === 0 && b.length === 0)
152
+ return 1;
153
+ const setB = new Set(b);
154
+ let shared = 0;
155
+ for (const x of new Set(a))
156
+ if (setB.has(x))
157
+ shared += 1;
158
+ const union = new Set([...a, ...b]).size;
159
+ return union === 0 ? 1 : shared / union;
160
+ };
161
+ /** Groove similarity ignores which cell a rhythm sat on — the same pattern
162
+ * moved from cell 3 to cell 5 is still the same pattern. */
163
+ const grooveSimilarity = (a, b) => jaccard(a.map((g) => g.split(":")[1] ?? ""), b.map((g) => g.split(":")[1] ?? ""));
164
+ const modSimilarity = (a, b) => {
165
+ const density = (m) => m.lfo + m.env + m.vary + m.seq;
166
+ const da = density(a);
167
+ const db = density(b);
168
+ const scale = Math.max(da, db) || 1;
169
+ const densityMatch = 1 - Math.abs(da - db) / scale;
170
+ // What is modulated matters more than how much of it there is.
171
+ return 0.35 * densityMatch + 0.65 * jaccard(a.targets, b.targets);
172
+ };
173
+ /** Dimension weights. Groove and params dominate because they are what a
174
+ * listener names first when two presets "sound the same". */
175
+ const WEIGHTS = { params: 0.24, groove: 0.24, mod: 0.18, sources: 0.16, fx: 0.08, chains: 0.05, pitch: 0.05 };
176
+ export function similarity(a, b) {
177
+ const byDimension = {
178
+ params: jaccard(a.params, b.params),
179
+ groove: grooveSimilarity(a.groove, b.groove),
180
+ mod: modSimilarity(a.mod, b.mod),
181
+ sources: jaccard(a.sources, b.sources),
182
+ fx: jaccard(a.fx, b.fx),
183
+ chains: jaccard(a.chains, b.chains),
184
+ pitch: jaccard(a.pitch.map(String), b.pitch.map(String)),
185
+ };
186
+ let overall = 0;
187
+ for (const [dim, w] of Object.entries(WEIGHTS)) {
188
+ overall += w * byDimension[dim];
189
+ }
190
+ return { overall, byDimension };
191
+ }
192
+ /** Score a candidate against a corpus. novelty = 1 - closest match, so 0 means
193
+ * "this already exists" and 1 means "nothing like it has shipped". */
194
+ export function scoreNovelty(candidate, corpus, topN = 5, baseline) {
195
+ const scored = corpus
196
+ .map((other) => ({ other, sim: similarity(candidate, other) }))
197
+ .sort((x, y) => y.sim.overall - x.sim.overall)
198
+ .slice(0, topN);
199
+ const nearest = scored.map(({ other, sim }) => ({
200
+ name: other.name,
201
+ similarity: Math.round(sim.overall * 1000) / 1000,
202
+ // Dimensions where the candidate is essentially a copy. These are the
203
+ // actionable part of the report — they name what to change.
204
+ duplicatedDimensions: Object.entries(sim.byDimension)
205
+ .filter(([, v]) => v >= 0.7)
206
+ .sort((a, b) => b[1] - a[1])
207
+ .map(([k, v]) => `${k} ${Math.round(v * 100)}%`),
208
+ }));
209
+ const top = scored[0]?.sim.overall ?? 0;
210
+ const novelty = Math.round((1 - top) * 1000) / 1000;
211
+ let verdict;
212
+ let percentileVsCorpus = null;
213
+ if (baseline) {
214
+ // Linear interpolation across the three known percentiles is enough for a
215
+ // verdict — this is a calibration aid, not a statistic.
216
+ if (novelty <= baseline.p10)
217
+ percentileVsCorpus = Math.max(0, Math.round((10 * novelty) / baseline.p10));
218
+ else if (novelty <= baseline.p50)
219
+ percentileVsCorpus = Math.round(10 + (40 * (novelty - baseline.p10)) / (baseline.p50 - baseline.p10));
220
+ else if (novelty <= baseline.p90)
221
+ percentileVsCorpus = Math.round(50 + (40 * (novelty - baseline.p50)) / (baseline.p90 - baseline.p50));
222
+ else
223
+ percentileVsCorpus = Math.min(100, Math.round(90 + (10 * (novelty - baseline.p90)) / (1 - baseline.p90)));
224
+ verdict =
225
+ novelty < baseline.floor
226
+ ? `More derivative than ANY pair in the shipped corpus (the closest shipped pair scores ${baseline.floor}). Redesign the duplicated dimensions before saving.`
227
+ : novelty < baseline.p10
228
+ ? "More derivative than 90% of shipped presets. Change at least one duplicated dimension."
229
+ : novelty < baseline.p50
230
+ ? "Below the corpus median for distinctness. Acceptable, but the duplicated dimensions are where it blends in."
231
+ : novelty < baseline.p90
232
+ ? "Distinct at or above the corpus median."
233
+ : "More distinct than 90% of shipped presets.";
234
+ }
235
+ else {
236
+ verdict = `Nearest-neighbour similarity ${Math.round(top * 100)}%. No corpus baseline supplied, so this number is only comparable against other runs.`;
237
+ }
238
+ return { novelty, percentileVsCorpus, nearest, verdict };
239
+ }
240
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,10 @@
1
1
  export interface VariationSnapshotContract {
2
2
  /** Session keys a variation must not carry (shared/variationSessionKeys.json). */
3
3
  sessionKeys: readonly string[];
4
+ /** The in-flight dispatch flags (StateShape's Transient group). A stored one
5
+ * is read back as an instruction — a slot carrying `__fadeMs__` crossfades
6
+ * the next load at the fade the FILE holds, not the one the loader asked for. */
7
+ transientKeys: readonly string[];
4
8
  /** Visual audio-react paramIds — they persist ACROSS variations, so they are
5
9
  * stripped from every snapshot rather than captured per slot. */
6
10
  visualParamIds: readonly string[];
@@ -23,9 +27,9 @@ export declare function reconcileLfoGeneratorEnabledState(snapshot: Record<strin
23
27
  /**
24
28
  * Shape a variation snapshot from plugin state.
25
29
  *
26
- * Order matters and is part of the contract: strip session keys, drop the
27
- * active-preset path, strip visual params, narrow for FX products, then
28
- * reconcile the LFO generator flags LAST — the reconcile reads `lfos`, which
29
- * the earlier steps may have removed.
30
+ * Order matters and is part of the contract: strip session keys and the
31
+ * transient dispatch flags, drop the active-preset path, strip visual params,
32
+ * narrow for FX products, then reconcile the LFO generator flags LAST — the
33
+ * reconcile reads `lfos`, which the earlier steps may have removed.
30
34
  */
31
35
  export declare function buildVariationSnapshotBase(state: Record<string, unknown>, contract: VariationSnapshotContract, options?: VariationSnapshotOptions): Record<string, unknown>;
@@ -42,15 +42,17 @@ export function reconcileLfoGeneratorEnabledState(snapshot, lfoGeneratorCount) {
42
42
  /**
43
43
  * Shape a variation snapshot from plugin state.
44
44
  *
45
- * Order matters and is part of the contract: strip session keys, drop the
46
- * active-preset path, strip visual params, narrow for FX products, then
47
- * reconcile the LFO generator flags LAST — the reconcile reads `lfos`, which
48
- * the earlier steps may have removed.
45
+ * Order matters and is part of the contract: strip session keys and the
46
+ * transient dispatch flags, drop the active-preset path, strip visual params,
47
+ * narrow for FX products, then reconcile the LFO generator flags LAST — the
48
+ * reconcile reads `lfos`, which the earlier steps may have removed.
49
49
  */
50
50
  export function buildVariationSnapshotBase(state, contract, options = {}) {
51
51
  const snapshot = { ...state };
52
52
  for (const key of contract.sessionKeys)
53
53
  delete snapshot[key];
54
+ for (const key of contract.transientKeys)
55
+ delete snapshot[key];
54
56
  delete snapshot.activePresetPath;
55
57
  for (const paramId of contract.visualParamIds)
56
58
  delete snapshot[paramId];
@@ -1 +1 @@
1
- {"version":3,"file":"variationSnapshot.js","sourceRoot":"","sources":["../../src/generated/variationSnapshot.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,+DAA+D;AAC/D,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,iFAAiF;AACjF,wDAAwD;AACxD,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,8DAA8D;AAuB9D;;;;;;;GAOG;AACH,MAAM,UAAU,iCAAiC,CAC/C,QAAiC,EACjC,iBAAyB;IAEzB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAM;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAiB,CAAA;IAEvC,KAAK,IAAI,cAAc,GAAG,CAAC,EAAE,cAAc,IAAI,iBAAiB,EAAE,cAAc,EAAE,EAAE,CAAC;QACnF,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAC/B,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,EAAE,iBAAiB,KAAK,cAAc;YACzC,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC;YACzB,OAAO,GAAG,EAAE,OAAO,KAAK,QAAQ;YAChC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CACzB,CAAA;QACD,QAAQ,CAAC,MAAM,cAAc,UAAU,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACpE,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAA8B,EAC9B,QAAmC,EACnC,UAAoC,EAAE;IAEtC,MAAM,QAAQ,GAA4B,EAAE,GAAG,KAAK,EAAE,CAAA;IAEtD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC5D,OAAO,QAAQ,CAAC,gBAAgB,CAAA;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,cAAc;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvE,IAAI,OAAO,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAA;IAE7C,iCAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAA;IACvE,OAAO,QAAQ,CAAA;AACjB,CAAC"}
1
+ {"version":3,"file":"variationSnapshot.js","sourceRoot":"","sources":["../../src/generated/variationSnapshot.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,+DAA+D;AAC/D,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,iFAAiF;AACjF,wDAAwD;AACxD,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,8DAA8D;AA2B9D;;;;;;;GAOG;AACH,MAAM,UAAU,iCAAiC,CAC/C,QAAiC,EACjC,iBAAyB;IAEzB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAM;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAiB,CAAA;IAEvC,KAAK,IAAI,cAAc,GAAG,CAAC,EAAE,cAAc,IAAI,iBAAiB,EAAE,cAAc,EAAE,EAAE,CAAC;QACnF,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAC/B,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,EAAE,iBAAiB,KAAK,cAAc;YACzC,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC;YACzB,OAAO,GAAG,EAAE,OAAO,KAAK,QAAQ;YAChC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CACzB,CAAA;QACD,QAAQ,CAAC,MAAM,cAAc,UAAU,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACpE,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAA8B,EAC9B,QAAmC,EACnC,UAAoC,EAAE;IAEtC,MAAM,QAAQ,GAA4B,EAAE,GAAG,KAAK,EAAE,CAAA;IAEtD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC5D,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,aAAa;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC9D,OAAO,QAAQ,CAAC,gBAAgB,CAAA;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,cAAc;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvE,IAAI,OAAO,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAA;IAE7C,iCAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAA;IACvE,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,70 @@
1
+ {
2
+ "_doc": "Curated per-player starting points for the generative Players — the 'one-click start' rung of the type -> preset -> dice -> knobs ladder (docs/research/2026-08-05_generative-players-research.md §16, transferable principles 3 and 6). Keyed by the player id in shared/generativePlayers.json; each entry is a complete snapshot of that player's performance axes and character slots: `density` and `mutate` are raw 0..1, and `p` holds one value per slot in P1..Pn order. UI-ONLY — the C++ core never reads this file, and no preset id is persisted anywhere: applying one writes plain cell-config values through setCellPlayer, so a preset may be renamed, re-voiced or dropped without touching a single saved project. What IS frozen is the meaning of what it writes: `p[i]` is that player's slot i in shared/generativePlayers.json, so re-voicing a preset is free while pointing it at a different slot is not. A DETENTED slot's value must be exactly i/(steps-1) — the long decimals here are that quotient, not a rounded taste; type 0.667 for a 4-position slot and the knob, the menu and the C++ stepIndex helper stop agreeing on which position it is (interface/test/generativePlayerPresets.test.ts pins it). A player may carry fewer `p` entries than it has slots (the rest fall back to the roster default), never more.",
3
+ "version": 1,
4
+ "presets": {
5
+ "1": [
6
+ { "name": "Bossa Five", "density": 0.3125, "mutate": 0, "p": [0, 0.3, 0.4, 0] },
7
+ { "name": "Offbeats", "density": 0.5, "mutate": 0, "p": [0.06666666666666667, 0.5, 0.5, 0] },
8
+ { "name": "Rolling Hat", "density": 0.6875, "mutate": 0, "p": [0, 0.18, 0.25, 0] },
9
+ { "name": "XOR Weave", "density": 0.4375, "mutate": 0, "p": [0, 0.45, 0.6, 0.6666666666666666] },
10
+ { "name": "Punch Gaps", "density": 0.75, "mutate": 0, "p": [0.26666666666666666, 0.15, 0.8, 1] }
11
+ ],
12
+ "2": [
13
+ { "name": "Sparse Trap", "density": 0.38, "mutate": 0, "p": [0, 0.15, 0.35, 0.5] },
14
+ { "name": "Rolling Drill", "density": 0.62, "mutate": 0.08, "p": [0.16666666666666666, 0.45, 0.55, 0.6] },
15
+ { "name": "Busy Boom Bap", "density": 0.58, "mutate": 0.12, "p": [0.3333333333333333, 0.7, 0.1, 0.6] },
16
+ { "name": "DnB Break", "density": 0.66, "mutate": 0.15, "p": [0.5, 0.55, 0.2, 0.5] },
17
+ { "name": "Techno Lock", "density": 0.55, "mutate": 0, "p": [0.8333333333333334, 0, 0, 0.5] },
18
+ { "name": "IDM Skitter", "density": 0.72, "mutate": 0.35, "p": [1, 0.75, 0.5, 0.25] }
19
+ ],
20
+ "3": [
21
+ { "name": "Short Loop", "density": 0.7, "mutate": 0, "p": [0.2222222222222222, 0.15, 0.5, 0, 0] },
22
+ { "name": "Long Drift", "density": 0.6, "mutate": 0.22, "p": [0.7777777777777778, 0.45, 0.5, 0.2, 0] },
23
+ { "name": "Inverted Loop", "density": 0.65, "mutate": 1, "p": [0.5555555555555556, 0.3, 0.55, 0.1, 0] },
24
+ { "name": "Acid Slide", "density": 0.85, "mutate": 0.08, "p": [0.3333333333333333, 0.2, 0.35, 0.75, 0] },
25
+ { "name": "Quartal Pad", "density": 0.4, "mutate": 0.12, "p": [0.6666666666666666, 0.7, 0.85, 0.6, 1] }
26
+ ],
27
+ "4": [
28
+ { "name": "Tiny Steps", "density": 0.75, "mutate": 0.3, "p": [0.1, 0.7, 0.15, 0.15, 0] },
29
+ { "name": "Wide Wander", "density": 0.6, "mutate": 0.3, "p": [0.85, 0.2, 0.2, 0.8, 0] },
30
+ { "name": "Root Anchor", "density": 0.8, "mutate": 0, "p": [0.35, 1, 0.1, 0.25, 0] },
31
+ { "name": "Sparse Triads", "density": 0.7, "mutate": 0.3, "p": [0.3, 0.55, 0.6, 0.35, 0.6] },
32
+ { "name": "Fifths Roam", "density": 0.55, "mutate": 0.3, "p": [0.55, 0.35, 0.3, 0.55, 0.4] }
33
+ ],
34
+ "5": [
35
+ { "name": "Echo the Clip", "density": 0.7, "mutate": 0, "p": [0.95, 0, 0.2, 0.2, 0] },
36
+ { "name": "Loose Jam", "density": 0.65, "mutate": 0.3, "p": [0.6, 0.75, 0.25, 0.4, 0] },
37
+ { "name": "Free Improv", "density": 0.6, "mutate": 0.3, "p": [0.25, 1, 0.3, 0.7, 0] },
38
+ { "name": "Wide Sevenths", "density": 0.5, "mutate": 0.3, "p": [0.75, 0.5, 0.35, 1, 0.8] },
39
+ { "name": "Tight Comp", "density": 0.85, "mutate": 0.3, "p": [0.85, 0.25, 0.1, 0, 0.2] }
40
+ ],
41
+ "6": [
42
+ { "name": "Bare Bones", "density": 0.3, "mutate": 0, "p": [0, 0, 0, 0.5] },
43
+ { "name": "Backbeat Fills", "density": 0.45, "mutate": 0.1, "p": [0.3333333333333333, 0.6, 0.35, 0.5] },
44
+ { "name": "Offbeat Buzz", "density": 0.4, "mutate": 0.15, "p": [0.6666666666666666, 0.3, 0.8, 0.15] },
45
+ { "name": "Machine Gun", "density": 0.7, "mutate": 0.2, "p": [1, 0.85, 0.9, 0.85] },
46
+ { "name": "Drag Flams", "density": 0.55, "mutate": 0.25, "p": [0, 0.2, 0.45, 0.95] }
47
+ ],
48
+ "7": [
49
+ { "name": "Five Slide", "density": 0.6, "mutate": 0, "p": [0.25, 0.25, 1, 0] },
50
+ { "name": "Static Seven", "density": 0.43, "mutate": 0, "p": [0.75, 0, 0, 0] },
51
+ { "name": "Nine Drift", "density": 0.55, "mutate": 0, "p": [1, 0.75, 0.3333333333333333, 1] },
52
+ { "name": "Triple Pulse", "density": 0.67, "mutate": 0, "p": [0, 0.25, 0.6666666666666666, 0] },
53
+ { "name": "Six Interlock", "density": 0.5, "mutate": 0, "p": [0.5, 0.5, 0.3333333333333333, 1] }
54
+ ],
55
+ "8": [
56
+ { "name": "Up Two Oct", "density": 0.9, "mutate": 0, "p": [0, 0, 0.3333333333333333, 0.3, 0] },
57
+ { "name": "Andalusian", "density": 0.75, "mutate": 0.15, "p": [0.6666666666666666, 1, 0.6666666666666666, 0.45, 0] },
58
+ { "name": "Converge Slow", "density": 0.45, "mutate": 0.15, "p": [1, 0.6666666666666666, 0.3333333333333333, 0.8, 0] },
59
+ { "name": "Wide Descent", "density": 0.85, "mutate": 0, "p": [0.3333333333333333, 0.3333333333333333, 1, 0.25, 0] },
60
+ { "name": "Chord Stabs", "density": 0.35, "mutate": 0.15, "p": [0, 0.6666666666666666, 0, 0.15, 0.8] }
61
+ ],
62
+ "9": [
63
+ { "name": "As Written", "density": 0.5, "mutate": 0, "p": [0.5, 0.35] },
64
+ { "name": "Thinned", "density": 0.3, "mutate": 0, "p": [0.75, 0.2] },
65
+ { "name": "Filled In", "density": 0.72, "mutate": 0, "p": [0.35, 0.5] },
66
+ { "name": "Breathing", "density": 0.5, "mutate": 0.35, "p": [0.5, 0.4] },
67
+ { "name": "Skeleton", "density": 0.16, "mutate": 0.12, "p": [0.9, 0.85] }
68
+ ]
69
+ }
70
+ }
@@ -0,0 +1,134 @@
1
+ {
2
+ "_doc": "SINGLE REGISTRY for the generative Players (docs/plans/GENERATIVE_PLAYERS.md §8). One entry per player id; id 0 is Off and has no entry. Consumed by build.js (codegens modules/player/GenerativePlayerSpec.generated.h and gates manifest.generativePatterns) and by interface/src/utils/generativePlayers.ts via the @shared import. IDS ARE APPEND-ONLY and a shipped id's P-slot meanings are frozen: cells[id].playerType persists in every preset and variation, and playerP1..P5 are raw 0..1 knob positions whose meaning comes from this file alone. A player may GROW a slot (the melodic four grew Chord): a new slot's default must be the value that reproduces the pre-slot output, since a preset saved before it existed carries no field. `tag` (drum|melodic|both) drives the UI grouping and the mono-cell hint; `replay` marks the three players whose state is derived by bounded deterministic replay (GenerativePlayerCore::chainStateAtCycle) rather than a closed form. `slots` holds 1..5 P-knob descriptors in P1..P5 order — a player with fewer slots leaves the remaining playerP* fields inert. `steps`/`stepLabels` turn a slot into a detented selector (stepLabels.length must equal steps); everything else is a continuous 0..1 knob. A continuous slot may carry `hint` (one plain sentence the knob's tooltip prints — detented slots self-describe through their labels) and `center: true` (the value is bipolar around 0.5 and prints signed, like KIT's Feel). `defaults.mutate` is 0 for the players where a repeating loop is the point and small where evolution is. `doc` is the ENGINEERING note (algorithm, prior art, hardware lineage) and never reaches the UI; `blurb` is the user-facing one-liner the roster prints, so it carries no filenames, no maths notation and no third-party product names.",
3
+ "version": 1,
4
+ "players": {
5
+ "1": {
6
+ "name": "EUCLID",
7
+ "tag": "drum",
8
+ "replay": false,
9
+ "doc": "Clough-Douthett closed-form maximally-even E(k,n) with rotation; k from DENSITY over the pattern's 16ths. P4 layers a second pulse generator combined by a boolean op (the Digitakt II dual-Euclid trick). Closed-form and seed-independent while MUTATE is locked, so ROTATION stays absolute and the named repertoire is reachable at known positions. The default density is E(7,16) - the Samba necklace - rather than the k=8 midpoint, which is periodic (gcd 8) and degenerates to a plain straight-eighths grid.",
10
+ "blurb": "Spreads hits as evenly as it can across the bar. Density sets how many, Rotate slides them, Layer adds a second pulse.",
11
+ "defaults": { "density": 0.44, "mutate": 0.0 },
12
+ "slots": [
13
+ { "label": "Rotate", "default": 0.0, "steps": 16 },
14
+ { "label": "Gate", "default": 0.35, "hint": "Note length, as a share of the step" },
15
+ { "label": "Accent", "default": 0.5, "hint": "How many of the hits play accented" },
16
+ { "label": "Layer", "default": 0.0, "steps": 4, "stepLabels": ["Off", "OR", "XOR", "SUB"] }
17
+ ]
18
+ },
19
+ "2": {
20
+ "name": "KIT",
21
+ "tag": "drum",
22
+ "replay": false,
23
+ "doc": "Genre-prior threshold masking from RandomizerPatternPriors.h for the cell's default role, played live: onset probability x metric weight, velocity from the prior's mean, ghosts as low-velocity prob steps, ratchets on the retrigger fields.",
24
+ "blurb": "Plays this cell's drum role in the feel of a genre. Ghost notes and ratchets fill the gaps between the main hits.",
25
+ "defaults": { "density": 0.5, "mutate": 0.0 },
26
+ "slots": [
27
+ { "label": "Genre", "default": 0.0, "steps": 7, "stepLabels": ["Trap", "Drill", "Boom Bap", "DnB", "House", "Techno", "IDM"] },
28
+ { "label": "Ghosts", "default": 0.3, "hint": "How many quiet extra hits fill the gaps" },
29
+ { "label": "Ratchet", "default": 0.15, "hint": "How often a hit becomes a short double burst" },
30
+ { "label": "Feel", "default": 0.5, "center": true, "hint": "Drag behind or push ahead of the beat — the centre is straight" }
31
+ ]
32
+ },
33
+ "3": {
34
+ "name": "TURING",
35
+ "tag": "melodic",
36
+ "replay": true,
37
+ "doc": "Looping shift register over the hardware's musical length set, one full rotation per cycle; MUTATE is the bit-flip probability (full mutate = the Mobius double-length inverted loop). Pitch comes from LSB-in/MSB-out bit weighting mapped into the cell scale.",
38
+ "blurb": "A looping bit pattern read out as a melody. Mutate flips bits, so the loop drifts a little further every time round.",
39
+ "defaults": { "density": 0.6, "mutate": 0.15 },
40
+ "slots": [
41
+ { "label": "Length", "default": 0.4444444444444444, "steps": 10, "stepLabels": ["2", "3", "4", "5", "6", "8", "12", "16", "24", "32"] },
42
+ { "label": "Range", "default": 0.35, "hint": "Pitch range, up to four octaves" },
43
+ { "label": "Gate", "default": 0.5, "hint": "Which notes survive low density — full favours the strong beats" },
44
+ { "label": "Slide", "default": 0.0, "hint": "How often a note holds legato into the next" },
45
+ { "label": "Chord", "default": 0.0, "steps": 6, "stepLabels": ["Off", "Oct", "5th", "Triad", "7th", "Quartal"] }
46
+ ]
47
+ },
48
+ "4": {
49
+ "name": "WALK",
50
+ "tag": "melodic",
51
+ "replay": true,
52
+ "doc": "Bounded drunk walk over scale degrees: weighted interval table (seconds/thirds dominant), gravity toward the root, leap-then-step-back voice leading, rests from (1-DENSITY).",
53
+ "blurb": "Wanders up and down the scale in small steps. Gravity pulls it back toward the root, and low density turns steps into rests.",
54
+ "defaults": { "density": 0.6, "mutate": 0.3 },
55
+ "slots": [
56
+ { "label": "Step", "default": 0.4, "hint": "Interval size, small steps to wide leaps" },
57
+ { "label": "Gravity", "default": 0.5, "hint": "Pull toward the root; high keeps it close to home" },
58
+ { "label": "Rests", "default": 0.25, "hint": "How often a step becomes a rest" },
59
+ { "label": "Range", "default": 0.4, "hint": "How far above and below the root it can wander" },
60
+ { "label": "Chord", "default": 0.0, "steps": 6, "stepLabels": ["Off", "Oct", "5th", "Triad", "7th", "Quartal"] }
61
+ ]
62
+ },
63
+ "5": {
64
+ "name": "MARKOV",
65
+ "tag": "melodic",
66
+ "replay": true,
67
+ "doc": "Order-1 chain over scale-degree intervals learned from the cell's own drawn pattern, blended toward the metric-hierarchy prior when the clip is thin. P2 is the temperature (argmax replay to uniform).",
68
+ "blurb": "Learns from the pattern you drew and improvises around it. Fidelity holds the line, Temp loosens it.",
69
+ "defaults": { "density": 0.6, "mutate": 0.3 },
70
+ "slots": [
71
+ { "label": "Fidelity", "default": 0.7, "hint": "How closely it follows the pattern it learnt" },
72
+ { "label": "Freedom", "default": 0.5, "steps": 5, "stepLabels": ["Lock", "Tight", "As Learnt", "Loose", "Free"] },
73
+ { "label": "Rests", "default": 0.25, "hint": "How often a step becomes a rest" },
74
+ { "label": "Range", "default": 0.4, "hint": "Octave span of the improvisation" },
75
+ { "label": "Chord", "default": 0.0, "steps": 6, "stepLabels": ["Off", "Oct", "5th", "Triad", "7th", "Quartal"] }
76
+ ]
77
+ },
78
+ "6": {
79
+ "name": "RATCHET",
80
+ "tag": "drum",
81
+ "replay": false,
82
+ "doc": "Sparse archetype skeleton grown by threshold masking, plus per-cycle fills and retrigger bursts baked from the cycle hash. Emits the grid an Elektron-style player freezes into.",
83
+ "blurb": "A sparse skeleton with fills and retrigger bursts. Every cycle puts them somewhere new.",
84
+ "defaults": { "density": 0.45, "mutate": 0.1 },
85
+ "slots": [
86
+ { "label": "Skeleton", "default": 0.0, "steps": 4, "stepLabels": ["Downbeat", "Backbeat", "Offbeat", "Rolling"] },
87
+ { "label": "Fills", "default": 0.25, "hint": "How often a cycle grows a fill" },
88
+ { "label": "Ratchet", "default": 0.3, "hint": "How often a hit becomes a retrigger burst" },
89
+ { "label": "Ramp", "default": 0.5, "hint": "Burst speed, and how hard the repeats hit" }
90
+ ]
91
+ },
92
+ "7": {
93
+ "name": "PHASE",
94
+ "tag": "both",
95
+ "replay": false,
96
+ "doc": "A sub-loop of L steps tiled against the pattern window and rotated by a fixed number of steps per cycle (discrete Reich phasing - loop-safe and bounce-exact, unlike continuous drift).",
97
+ "blurb": "A short loop of odd length that slides against the bar. The two pull apart, then meet up again.",
98
+ "defaults": { "density": 0.5, "mutate": 0.0 },
99
+ "slots": [
100
+ { "label": "Loop", "default": 0.0, "steps": 5, "stepLabels": ["3", "5", "6", "7", "9"] },
101
+ { "label": "Drift", "default": 0.25, "steps": 5, "stepLabels": ["0", "1", "2", "3", "4"] },
102
+ { "label": "Accent", "default": 0.3333333333333333, "steps": 4, "stepLabels": ["1", "2", "3", "4"] },
103
+ { "label": "Alternate", "default": 0.0, "steps": 2, "stepLabels": ["Off", "On"] }
104
+ ]
105
+ },
106
+ "8": {
107
+ "name": "RIFF",
108
+ "tag": "melodic",
109
+ "replay": false,
110
+ "doc": "Scale-degree arp automaton: a chord-tone pool cycling through a short progression per cycle, traversed by shape over an octave span, with skips from (1-DENSITY).",
111
+ "blurb": "Arpeggios over a short chord progression. Shape picks the path up and down, Octaves sets the range.",
112
+ "defaults": { "density": 0.7, "mutate": 0.15 },
113
+ "slots": [
114
+ { "label": "Shape", "default": 0.0, "steps": 4, "stepLabels": ["Up", "Down", "Orbit", "Converge"] },
115
+ { "label": "Prog", "default": 0.0, "steps": 4, "stepLabels": ["Static", "i-VI", "i-iv-V", "i-VII-VI-V"] },
116
+ { "label": "Octaves", "default": 0.3333333333333333, "steps": 4, "stepLabels": ["1", "2", "3", "4"] },
117
+ { "label": "Gate", "default": 0.4, "hint": "Note length, as a share of the step" },
118
+ { "label": "Chord", "default": 0.0, "steps": 6, "stepLabels": ["Off", "Oct", "5th", "Triad", "7th", "Quartal"] }
119
+ ]
120
+ },
121
+ "9": {
122
+ "name": "MASK",
123
+ "tag": "both",
124
+ "replay": false,
125
+ "doc": "The cell's own drawn pattern, morphed. Per-step weights seeded from the clip (velocity on their notes, metric hierarchy on their rests) under one monotone threshold whose CENTER DETENT reproduces the clip exactly; MUTATE is a per-cycle latched perturbation depth.",
126
+ "blurb": "Your drawn pattern, thinned out or filled in. The centre of Density plays it back exactly as written.",
127
+ "defaults": { "density": 0.5, "mutate": 0.0 },
128
+ "slots": [
129
+ { "label": "Accent", "default": 0.5, "hint": "How far the off-beats duck under the strong beats" },
130
+ { "label": "Gate", "default": 0.35, "hint": "Note length, as a share of the step" }
131
+ ]
132
+ }
133
+ }
134
+ }