fractal-midi 0.1.0-alpha.3 → 0.3.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 (156) hide show
  1. package/NOTICE +17 -0
  2. package/README.md +28 -28
  3. package/dist/am4/blockLayout.d.ts +48 -0
  4. package/dist/am4/blockLayout.d.ts.map +1 -0
  5. package/dist/am4/blockLayout.js +39 -0
  6. package/dist/am4/blockTypes.js +2 -2
  7. package/dist/am4/cacheEnums.d.ts +1 -1
  8. package/dist/am4/cacheEnums.js +1 -1
  9. package/dist/am4/cacheOracleParams.generated.d.ts +1247 -0
  10. package/dist/am4/cacheOracleParams.generated.d.ts.map +1 -0
  11. package/dist/am4/cacheOracleParams.generated.js +783 -0
  12. package/dist/am4/cacheParams.d.ts +88 -24
  13. package/dist/am4/cacheParams.d.ts.map +1 -1
  14. package/dist/am4/cacheParams.js +81 -17
  15. package/dist/am4/index.d.ts +5 -2
  16. package/dist/am4/index.d.ts.map +1 -1
  17. package/dist/am4/index.js +6 -2
  18. package/dist/am4/paramNames.d.ts +3 -3
  19. package/dist/am4/paramNames.js +56 -56
  20. package/dist/am4/params.d.ts +1360 -290
  21. package/dist/am4/params.d.ts.map +1 -1
  22. package/dist/am4/params.js +826 -433
  23. package/dist/am4/presetBinary.d.ts +72 -0
  24. package/dist/am4/presetBinary.d.ts.map +1 -0
  25. package/dist/am4/presetBinary.js +104 -0
  26. package/dist/am4/setParam.d.ts +64 -26
  27. package/dist/am4/setParam.d.ts.map +1 -1
  28. package/dist/am4/setParam.js +92 -29
  29. package/dist/am4/shared/paramHelpers.d.ts +3 -3
  30. package/dist/am4/shared/paramHelpers.js +4 -4
  31. package/dist/am4/symbolicIds.d.ts +1 -1
  32. package/dist/am4/symbolicIds.js +1 -1
  33. package/dist/am4/typeApplicability.d.ts +3 -3
  34. package/dist/am4/typeApplicability.d.ts.map +1 -1
  35. package/dist/am4/typeApplicability.js +3 -4
  36. package/dist/axe-fx-gen1/blockTypes.d.ts +6 -0
  37. package/dist/axe-fx-gen1/blockTypes.d.ts.map +1 -0
  38. package/dist/axe-fx-gen1/blockTypes.js +48 -0
  39. package/dist/axe-fx-gen1/index.d.ts +7 -0
  40. package/dist/axe-fx-gen1/index.d.ts.map +1 -0
  41. package/dist/axe-fx-gen1/index.js +15 -0
  42. package/dist/axe-fx-gen1/nibble.d.ts +5 -0
  43. package/dist/axe-fx-gen1/nibble.d.ts.map +1 -0
  44. package/dist/axe-fx-gen1/nibble.js +22 -0
  45. package/dist/axe-fx-gen1/params.d.ts +8 -0
  46. package/dist/axe-fx-gen1/params.d.ts.map +1 -0
  47. package/dist/axe-fx-gen1/params.js +935 -0
  48. package/dist/axe-fx-gen1/readParam.d.ts +37 -0
  49. package/dist/axe-fx-gen1/readParam.d.ts.map +1 -0
  50. package/dist/axe-fx-gen1/readParam.js +140 -0
  51. package/dist/axe-fx-gen1/setParam.d.ts +23 -0
  52. package/dist/axe-fx-gen1/setParam.d.ts.map +1 -0
  53. package/dist/axe-fx-gen1/setParam.js +76 -0
  54. package/dist/axe-fx-gen1/types.d.ts +51 -0
  55. package/dist/axe-fx-gen1/types.d.ts.map +1 -0
  56. package/dist/axe-fx-gen1/types.js +14 -0
  57. package/dist/axe-fx-ii/applicability.d.ts +63 -0
  58. package/dist/axe-fx-ii/applicability.d.ts.map +1 -0
  59. package/dist/axe-fx-ii/applicability.js +121 -0
  60. package/dist/axe-fx-ii/blockTypes.d.ts +3 -3
  61. package/dist/axe-fx-ii/blockTypes.js +3 -3
  62. package/dist/axe-fx-ii/index.d.ts +2 -0
  63. package/dist/axe-fx-ii/index.d.ts.map +1 -1
  64. package/dist/axe-fx-ii/index.js +2 -0
  65. package/dist/axe-fx-ii/opcodes.d.ts +5 -5
  66. package/dist/axe-fx-ii/opcodes.d.ts.map +1 -1
  67. package/dist/axe-fx-ii/opcodes.js +9 -10
  68. package/dist/axe-fx-ii/paramAliases.d.ts.map +1 -1
  69. package/dist/axe-fx-ii/paramAliases.js +16 -1
  70. package/dist/axe-fx-ii/params.d.ts +461 -35
  71. package/dist/axe-fx-ii/params.d.ts.map +1 -1
  72. package/dist/axe-fx-ii/params.js +416 -254
  73. package/dist/axe-fx-ii/setParam.d.ts +164 -43
  74. package/dist/axe-fx-ii/setParam.d.ts.map +1 -1
  75. package/dist/axe-fx-ii/setParam.js +213 -35
  76. package/dist/axe-fx-ii/typeApplicability.d.ts +41 -0
  77. package/dist/axe-fx-ii/typeApplicability.d.ts.map +1 -0
  78. package/dist/axe-fx-ii/typeApplicability.js +905 -0
  79. package/dist/axe-fx-iii/blockTypes.d.ts +16 -11
  80. package/dist/axe-fx-iii/blockTypes.d.ts.map +1 -1
  81. package/dist/axe-fx-iii/blockTypes.js +27 -20
  82. package/dist/axe-fx-iii/enumOverlay.d.ts +14 -0
  83. package/dist/axe-fx-iii/enumOverlay.d.ts.map +1 -1
  84. package/dist/axe-fx-iii/enumOverlay.js +72 -1
  85. package/dist/axe-fx-iii/enumRawId.d.ts +57 -0
  86. package/dist/axe-fx-iii/enumRawId.d.ts.map +1 -0
  87. package/dist/axe-fx-iii/enumRawId.js +102 -0
  88. package/dist/axe-fx-iii/gen3ReadRosters.d.ts +37 -0
  89. package/dist/axe-fx-iii/gen3ReadRosters.d.ts.map +1 -0
  90. package/dist/axe-fx-iii/gen3ReadRosters.js +595 -0
  91. package/dist/axe-fx-iii/index.d.ts +5 -3
  92. package/dist/axe-fx-iii/index.d.ts.map +1 -1
  93. package/dist/axe-fx-iii/index.js +8 -4
  94. package/dist/axe-fx-iii/params.d.ts +4 -4
  95. package/dist/axe-fx-iii/params.js +6 -6
  96. package/dist/axe-fx-iii/setParam.d.ts +412 -62
  97. package/dist/axe-fx-iii/setParam.d.ts.map +1 -1
  98. package/dist/axe-fx-iii/setParam.js +1065 -163
  99. package/dist/fm3/index.d.ts +2 -0
  100. package/dist/fm3/index.d.ts.map +1 -0
  101. package/dist/fm3/index.js +1 -0
  102. package/dist/fm3/params.d.ts +29 -0
  103. package/dist/fm3/params.d.ts.map +1 -0
  104. package/dist/fm3/params.js +2033 -0
  105. package/dist/fm9/enumOverrides.d.ts +2 -0
  106. package/dist/fm9/enumOverrides.d.ts.map +1 -0
  107. package/dist/fm9/enumOverrides.js +64 -0
  108. package/dist/fm9/index.d.ts +4 -0
  109. package/dist/fm9/index.d.ts.map +1 -0
  110. package/dist/fm9/index.js +3 -0
  111. package/dist/fm9/params.d.ts +29 -0
  112. package/dist/fm9/params.d.ts.map +1 -0
  113. package/dist/fm9/params.js +2064 -0
  114. package/dist/fm9/ranges.generated.d.ts +46 -0
  115. package/dist/fm9/ranges.generated.d.ts.map +1 -0
  116. package/dist/fm9/ranges.generated.js +2106 -0
  117. package/dist/fm9/rosters.generated.d.ts +7 -0
  118. package/dist/fm9/rosters.generated.d.ts.map +1 -0
  119. package/dist/fm9/rosters.generated.js +512 -0
  120. package/dist/index.d.ts +1 -1
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +9 -2
  123. package/dist/shared/device.d.ts +4 -4
  124. package/dist/shared/device.js +1 -1
  125. package/dist/shared/effectId.d.ts +56 -0
  126. package/dist/shared/effectId.d.ts.map +1 -0
  127. package/dist/shared/effectId.js +117 -0
  128. package/dist/shared/index.d.ts +1 -0
  129. package/dist/shared/index.d.ts.map +1 -1
  130. package/dist/shared/index.js +1 -0
  131. package/dist/shared/lineage/amp-lineage.json +270 -292
  132. package/dist/shared/lineage/axefx2-amp-lineage.json +343 -147
  133. package/dist/shared/lineage/cab-lineage.json +10777 -10777
  134. package/dist/shared/lineage/chorus-lineage.json +173 -173
  135. package/dist/shared/lineage/compressor-lineage.json +338 -338
  136. package/dist/shared/lineage/delay-lineage.json +313 -313
  137. package/dist/shared/lineage/drive-lineage.json +217 -39
  138. package/dist/shared/lineage/flanger-lineage.json +313 -313
  139. package/dist/shared/lineage/phaser-lineage.json +208 -208
  140. package/dist/shared/lineage/reverb-lineage.json +793 -793
  141. package/dist/shared/lineage/wah-lineage.json +117 -117
  142. package/dist/shared/lineageLookup.d.ts +1 -0
  143. package/dist/shared/lineageLookup.d.ts.map +1 -1
  144. package/dist/shared/lineageLookup.js +4 -0
  145. package/dist/shared/packValue.d.ts +2 -2
  146. package/dist/shared/packValue.js +2 -2
  147. package/dist/vp4/index.d.ts +3 -0
  148. package/dist/vp4/index.d.ts.map +1 -0
  149. package/dist/vp4/index.js +2 -0
  150. package/dist/vp4/params.d.ts +27 -0
  151. package/dist/vp4/params.d.ts.map +1 -0
  152. package/dist/vp4/params.js +1702 -0
  153. package/dist/vp4/setParam.d.ts +59 -0
  154. package/dist/vp4/setParam.d.ts.map +1 -0
  155. package/dist/vp4/setParam.js +161 -0
  156. package/package.json +20 -3
package/NOTICE CHANGED
@@ -26,3 +26,20 @@ descriptively (nominative fair use) to identify the hardware family
26
26
  this library targets. The library does not embed Fractal Audio
27
27
  firmware, factory presets, branding assets, or any other Fractal-
28
28
  copyrighted material.
29
+
30
+ ---
31
+
32
+ THIRD-PARTY SOFTWARE
33
+
34
+ This library includes gen-3 (Axe-Fx III / FM3 / FM9) protocol data
35
+ derived from:
36
+
37
+ - fractal-syx-codec (Apache License, Version 2.0)
38
+ Copyright 2026 Andrew Mercurio ("BoodieTraps")
39
+ https://github.com/drewmerc302/fractal-syx-codec
40
+ The gen-3 preset-file format spec (FORMAT.md) and the read-ordinal
41
+ effect-type roster tables (shipped as the gen-3 read rosters /
42
+ body-decode tables). The Huffman/CRC codec is a clean-room
43
+ reimplementation from that spec; the roster name tables are derived
44
+ from its data, independently cross-validated against our own
45
+ hardware captures.
package/README.md CHANGED
@@ -4,14 +4,11 @@ Pure-TypeScript codec and parameter dictionaries for Fractal Audio
4
4
  guitar processors. Build and parse the SysEx wire bytes a Fractal
5
5
  device speaks, without pulling in a MIDI transport library.
6
6
 
7
- > **Status pre-release.** The first published version (`0.1.0`)
8
- > covers AM4 and Axe-Fx II at hardware-verified parity, plus the
9
- > Axe-Fx III at codec + calibration via public-capture
10
- > verification and JUCE-BinaryData mining (hardware-verification
11
- > stays community-driven see the III notes in the coverage table).
12
- > FM3 / FM9 ship next via mechanical ports of the III pipeline.
13
- > Don't depend on this package from production code yet — APIs may
14
- > shift before `0.1.0`.
7
+ > Covers AM4 and Axe-Fx II at hardware-verified parity, the modern Fractal
8
+ > family (Axe-Fx III / FM3 / FM9) at codec and calibration via public-capture
9
+ > verification and editor-binary mining, and the Axe-Fx Standard/Ultra (gen-1)
10
+ > as a SET-only descriptor. The gen-3 family stays community-driven for
11
+ > hardware verification; see the per-device notes in the coverage table.
15
12
 
16
13
  > **Unaffiliated community library.** "Fractal Audio", "AM4",
17
14
  > "Axe-Fx", "Axe-Fx II", "Axe-Fx III", "FM3", and "FM9" are
@@ -24,16 +21,16 @@ device speaks, without pulling in a MIDI transport library.
24
21
 
25
22
  ## What this is
26
23
 
27
- - **JSON-shaped parameter dictionaries** every block-and-param the
24
+ - **JSON-shaped parameter dictionaries.** Every block-and-param the
28
25
  device understands, with display unit, value range, and the
29
26
  paramId that goes on the wire. Reverse-engineered against real
30
27
  hardware and Fractal's own published 3rd-party MIDI specs.
31
- - **Pure-TypeScript codec** display value in (`gain: 7.5`,
28
+ - **Pure-TypeScript codec.** Display value in (`gain: 7.5`,
32
29
  `'Plexi 100W High'`), SysEx bytes out (`Uint8Array`). No MIDI
33
30
  library required.
34
- - **Parsers / validators** given captured bytes, parse back to
31
+ - **Parsers and validators.** Given captured bytes, parse back to
35
32
  display values for round-trip equality testing.
36
- - **Reference data** Fractal's amp / cab / drive lineage tables
33
+ - **Reference data.** Fractal's amp / cab / drive lineage tables
37
34
  (the "the JC-120 model is based on this real-world amp" data),
38
35
  factory bank metadata, applicability tables.
39
36
 
@@ -41,7 +38,7 @@ device speaks, without pulling in a MIDI transport library.
41
38
 
42
39
  - **Not a MIDI library.** Routing bytes to and from your hardware
43
40
  is your responsibility. Use `node-midi`, `webmidi`,
44
- `easymidi`, JUCE, RtMidi, CoreMIDI, ALSA whatever fits.
41
+ `easymidi`, JUCE, RtMidi, CoreMIDI, ALSA, whatever fits.
45
42
  - **Not a preset editor.** This package gives you the wire-level
46
43
  primitives a preset editor would be built on top of.
47
44
  - **Not affiliated with Fractal Audio Systems.** See the trademark
@@ -57,9 +54,6 @@ Node >= 18. ESM-only.
57
54
 
58
55
  ## Usage
59
56
 
60
- > The shape below is the target API. Until `0.1.0` ships, the
61
- > module surface may differ.
62
-
63
57
  ```ts
64
58
  import { buildSetParam, parseSetParam } from 'fractal-midi/am4/codec';
65
59
  import { params, blocks } from 'fractal-midi/am4';
@@ -90,9 +84,10 @@ import { params } from 'fractal-midi/axe-fx-iii';
90
84
  |---|---|---|---|---|
91
85
  | AM4 | ✅ | ✅ | ✅ | ✅ |
92
86
  | Axe-Fx II | ✅ | ✅ | ✅ | ✅ |
93
- | Axe-Fx III | ✅ (2216 params) | ✅ ([see note](#axe-fx-iii-codec-note)) | ✅ ([see note](#axe-fx-iii-calibration-note)) | 🟡 community beta ([see note](#axe-fx-iii-hardware-note)) |
94
- | FM3 | | | | ❌ |
95
- | FM9 | | | | ❌ |
87
+ | Axe-Fx III | ✅ (full catalog) | ✅ ([see note](#axe-fx-iii-codec-note)) | ✅ ([see note](#axe-fx-iii-calibration-note)) | 🟡 community beta ([see note](#axe-fx-iii-hardware-note)) |
88
+ | FM3 | (device-true, mined from FM3-Edit) | (shared gen-3) | 🟡 (linear; some non-linear pending) | ❌ community beta |
89
+ | FM9 | (device-true, mined from FM9-Edit) | (shared gen-3) | 🟡 (linear; some non-linear pending) | ❌ community beta |
90
+ | Axe-Fx Standard/Ultra (gen-1) | ✅ (922 params) | ✅ (nibble-split, SET-only) | 🟡 (linear; 171 non-linear pending) | ❌ community beta (no gen-1 hardware) |
96
91
 
97
92
  ### Coverage notes
98
93
 
@@ -100,9 +95,9 @@ import { params } from 'fractal-midi/axe-fx-iii';
100
95
 
101
96
  The III's SET_PARAMETER wire envelope (fn=0x01, sub-action `09 00`,
102
97
  23-byte frame) is byte-verified against 10 public community captures
103
- spanning two effect blocks and two sub-action codes see the
104
- `axe-fx-iii/setparam` test goldens (302 cases: 36 envelope vectors +
105
- 264 round-trip `build parse equality` cases + 2
98
+ spanning two effect blocks and two sub-action codes. See the
99
+ `axe-fx-iii/setparam` test goldens (302 cases: 36 envelope vectors,
100
+ 264 round-trip `build` to `parse` to equality cases, and 2
106
101
  `parseStateBroadcast` assertions). The GET-response shape is
107
102
  hypothesis-only (no public capture exists); the parser handles both
108
103
  the `09 00` / `52 00` set-echo shape and the async `04 01`
@@ -113,14 +108,14 @@ STATE_BROADCAST shape via `parseSetGetParameterResponse` /
113
108
 
114
109
  III calibration = 100% of catalog entries carry a non-`'unverified'`
115
110
  unit tag (16 string-typed `_NAME` / `_LABEL` / `_MSG` entries are
116
- exempted by the calibration gate they have no `'string'` unit in
111
+ exempted by the calibration gate, since they have no `'string'` unit in
117
112
  the `Param` type). Enum vocabularies are resolved at runtime via
118
113
  `resolveEnumValues(name)` from `enumOverlay.ts`, which carries a
119
- `provenance` field on every entry `'am4-shared'` (AM4-verified,
114
+ `provenance` field on every entry: `'am4-shared'` (AM4-verified,
120
115
  shared with III), `'fractal-convention'` (universal Fractal-family
121
116
  convention like OFF/ON / channel pickers), or `'iii-spec'` (hand-
122
117
  curated for III-only params). Coverage of enum vocabularies and
123
- numeric display ranges is partial `resolveEnumValues` returns
118
+ numeric display ranges is partial: `resolveEnumValues` returns
124
119
  `undefined` for params not yet mapped, and many XML-derived numeric
125
120
  entries carry a unit tag but no `displayMin` / `displayMax`. Treat
126
121
  the catalog as the wire-level truth; treat the calibration overlay
@@ -137,9 +132,14 @@ that disagrees with their hardware.
137
132
 
138
133
  FM3 and FM9 share the III protocol family (model bytes `0x11` /
139
134
  `0x12` vs III's `0x10`, identical envelope per Fractal's v1.4 MIDI
140
- spec). Catalog + codec + calibration for those devices are planned as
141
- mechanical ports of the III pipeline once the FM3-Edit / FM9-Edit
142
- JUCE binaries are mined for parameterName + dispatcher tables.
135
+ spec). Both ship device-true param catalogs mined from their own
136
+ FM3-Edit / FM9-Edit JUCE binaries (paramIds are device-specific and are
137
+ never reused from the III) on the shared gen-3 codec. Calibration
138
+ covers the linear params; some non-linear display formulas are still
139
+ pending. Neither has been hardware-verified by the maintainer, so they
140
+ remain community beta: FM9 has real community captures confirming the
141
+ shared read and preset-dump paths, while FM3 confirmation is still
142
+ open.
143
143
 
144
144
  ## License
145
145
 
@@ -0,0 +1,48 @@
1
+ /**
2
+ * AM4 working-buffer block-layout snapshot — pure helpers.
3
+ *
4
+ * The AM4 holds 4 signal-chain slots. Each slot register reports the
5
+ * pidLow of the block currently placed there (or `BLOCK_TYPE_VALUES.none`
6
+ * for empty). Reading the four slot registers produces a `BlockLayoutSnapshot`
7
+ * — the union of placed block types in the active working buffer.
8
+ *
9
+ * Used by phantom-param pre-flight: a `set_param` write against a
10
+ * block that isn't placed in any slot wire-acks but silently no-ops on
11
+ * the device. The dispatcher consults the cached snapshot before each
12
+ * write and surfaces a `validation_info[]` warning when the target block
13
+ * is absent.
14
+ *
15
+ * The codec layer is wire-bytes agnostic — the consumer reads the four
16
+ * slots however its transport prefers, then constructs a snapshot from
17
+ * the (slot-index → block-type) pairs.
18
+ */
19
+ import type { BlockTypeName } from './blockTypes.js';
20
+ /**
21
+ * Working-buffer block layout. One entry per slot (1..4); each entry is
22
+ * the canonical block-type name placed there, or 'none' for an empty
23
+ * slot. `placedBlocks` is a derived Set of unique placed block names for
24
+ * fast `isBlockPlaced` lookup.
25
+ *
26
+ * AM4 enforces single-instance-per-type (no two slots hold the same
27
+ * block type), so a Set is sufficient. Grid devices (II/III) need a
28
+ * different snapshot shape — they ship their own helper.
29
+ */
30
+ export interface BlockLayoutSnapshot {
31
+ /** Slot 1..4 block-type name, 'none' for empty. */
32
+ slots: readonly [BlockTypeName, BlockTypeName, BlockTypeName, BlockTypeName];
33
+ /** Unique non-'none' block names from `slots`, for O(1) `isBlockPlaced` lookup. */
34
+ placedBlocks: ReadonlySet<BlockTypeName>;
35
+ }
36
+ /**
37
+ * Build a snapshot from a 4-element block-type array. Filters 'none'
38
+ * out of `placedBlocks` so callers don't accidentally match an empty
39
+ * slot when checking placement.
40
+ */
41
+ export declare function buildBlockLayoutSnapshot(slots: readonly [BlockTypeName, BlockTypeName, BlockTypeName, BlockTypeName]): BlockLayoutSnapshot;
42
+ /**
43
+ * True when `block` is placed in any slot of the snapshot. Case-sensitive
44
+ * (the snapshot uses canonical block names); the dispatcher resolves the
45
+ * block name to canonical before calling this helper.
46
+ */
47
+ export declare function isBlockPlaced(snapshot: BlockLayoutSnapshot, block: string): boolean;
48
+ //# sourceMappingURL=blockLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockLayout.d.ts","sourceRoot":"","sources":["../../src/am4/blockLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,KAAK,EAAE,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAC7E,mFAAmF;IACnF,YAAY,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;CAC1C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,GAC3E,mBAAmB,CAMrB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,MAAM,GACZ,OAAO,CAET"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AM4 working-buffer block-layout snapshot — pure helpers.
3
+ *
4
+ * The AM4 holds 4 signal-chain slots. Each slot register reports the
5
+ * pidLow of the block currently placed there (or `BLOCK_TYPE_VALUES.none`
6
+ * for empty). Reading the four slot registers produces a `BlockLayoutSnapshot`
7
+ * — the union of placed block types in the active working buffer.
8
+ *
9
+ * Used by phantom-param pre-flight: a `set_param` write against a
10
+ * block that isn't placed in any slot wire-acks but silently no-ops on
11
+ * the device. The dispatcher consults the cached snapshot before each
12
+ * write and surfaces a `validation_info[]` warning when the target block
13
+ * is absent.
14
+ *
15
+ * The codec layer is wire-bytes agnostic — the consumer reads the four
16
+ * slots however its transport prefers, then constructs a snapshot from
17
+ * the (slot-index → block-type) pairs.
18
+ */
19
+ /**
20
+ * Build a snapshot from a 4-element block-type array. Filters 'none'
21
+ * out of `placedBlocks` so callers don't accidentally match an empty
22
+ * slot when checking placement.
23
+ */
24
+ export function buildBlockLayoutSnapshot(slots) {
25
+ const placed = new Set();
26
+ for (const s of slots) {
27
+ if (s !== 'none')
28
+ placed.add(s);
29
+ }
30
+ return { slots, placedBlocks: placed };
31
+ }
32
+ /**
33
+ * True when `block` is placed in any slot of the snapshot. Case-sensitive
34
+ * (the snapshot uses canonical block names); the dispatcher resolves the
35
+ * block name to canonical before calling this helper.
36
+ */
37
+ export function isBlockPlaced(snapshot, block) {
38
+ return snapshot.placedBlocks.has(block);
39
+ }
@@ -16,12 +16,12 @@ export const BLOCK_TYPE_VALUES = {
16
16
  amp: 0x003a,
17
17
  compressor: 0x002e,
18
18
  geq: 0x0032,
19
- peq: 0x0036, // pidLow pinned Session 18; no Type enum known
19
+ peq: 0x0036, // pidLow pinned ; no Type enum known
20
20
  reverb: 0x0042,
21
21
  delay: 0x0046,
22
22
  chorus: 0x004e,
23
23
  flanger: 0x0052,
24
- rotary: 0x0056, // pidLow pinned Session 18; no Type enum known
24
+ rotary: 0x0056, // pidLow pinned ; no Type enum known
25
25
  phaser: 0x005a,
26
26
  wah: 0x005e,
27
27
  volpan: 0x0066,
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Source: AM4-Edit metadata cache (effectDefinitions_15_2p0.cache),
5
5
  * parsed by scripts/parse-cache.ts, verified against wire captures
6
- * by scripts/map-cache-params.ts (Session 15).
6
+ * by scripts/map-cache-params.ts.
7
7
  *
8
8
  * Each array lists the firmware's effect-type dictionary in wire
9
9
  * order. The wire value sent in SET_PARAM (at pidHigh=0x000A of the
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Source: AM4-Edit metadata cache (effectDefinitions_15_2p0.cache),
5
5
  * parsed by scripts/parse-cache.ts, verified against wire captures
6
- * by scripts/map-cache-params.ts (Session 15).
6
+ * by scripts/map-cache-params.ts.
7
7
  *
8
8
  * Each array lists the firmware's effect-type dictionary in wire
9
9
  * order. The wire value sent in SET_PARAM (at pidHigh=0x000A of the