fractal-midi 0.1.0-alpha.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/LICENSE +200 -0
- package/NOTICE +28 -0
- package/README.md +147 -0
- package/dist/am4/applicability.d.ts +61 -0
- package/dist/am4/applicability.d.ts.map +1 -0
- package/dist/am4/applicability.js +285 -0
- package/dist/am4/blockTypes.d.ts +43 -0
- package/dist/am4/blockTypes.d.ts.map +1 -0
- package/dist/am4/blockTypes.js +48 -0
- package/dist/am4/cacheEnums.d.ts +46 -0
- package/dist/am4/cacheEnums.d.ts.map +1 -0
- package/dist/am4/cacheEnums.js +734 -0
- package/dist/am4/cacheParams.d.ts +3533 -0
- package/dist/am4/cacheParams.d.ts.map +1 -0
- package/dist/am4/cacheParams.js +1996 -0
- package/dist/am4/editorControlLabels.d.ts +45 -0
- package/dist/am4/editorControlLabels.d.ts.map +1 -0
- package/dist/am4/editorControlLabels.js +15894 -0
- package/dist/am4/index.d.ts +28 -0
- package/dist/am4/index.d.ts.map +1 -0
- package/dist/am4/index.js +31 -0
- package/dist/am4/ir/preset.d.ts +24 -0
- package/dist/am4/ir/preset.d.ts.map +1 -0
- package/dist/am4/ir/preset.js +12 -0
- package/dist/am4/ir/transpile.d.ts +9 -0
- package/dist/am4/ir/transpile.d.ts.map +1 -0
- package/dist/am4/ir/transpile.js +19 -0
- package/dist/am4/locations.d.ts +32 -0
- package/dist/am4/locations.d.ts.map +1 -0
- package/dist/am4/locations.js +58 -0
- package/dist/am4/paramNames.d.ts +55 -0
- package/dist/am4/paramNames.d.ts.map +1 -0
- package/dist/am4/paramNames.js +863 -0
- package/dist/am4/paramNamesGenerated.d.ts +41 -0
- package/dist/am4/paramNamesGenerated.d.ts.map +1 -0
- package/dist/am4/paramNamesGenerated.js +183 -0
- package/dist/am4/parameterBridge.d.ts +46 -0
- package/dist/am4/parameterBridge.d.ts.map +1 -0
- package/dist/am4/parameterBridge.js +300 -0
- package/dist/am4/params.d.ts +9577 -0
- package/dist/am4/params.d.ts.map +1 -0
- package/dist/am4/params.js +4537 -0
- package/dist/am4/setParam.d.ts +414 -0
- package/dist/am4/setParam.d.ts.map +1 -0
- package/dist/am4/setParam.js +819 -0
- package/dist/am4/shared/paramHelpers.d.ts +55 -0
- package/dist/am4/shared/paramHelpers.d.ts.map +1 -0
- package/dist/am4/shared/paramHelpers.js +146 -0
- package/dist/am4/symbolicIds.d.ts +11 -0
- package/dist/am4/symbolicIds.d.ts.map +1 -0
- package/dist/am4/symbolicIds.js +587 -0
- package/dist/am4/typeApplicability.d.ts +39 -0
- package/dist/am4/typeApplicability.d.ts.map +1 -0
- package/dist/am4/typeApplicability.js +466 -0
- package/dist/am4/variantResolverTables.d.ts +51 -0
- package/dist/am4/variantResolverTables.d.ts.map +1 -0
- package/dist/am4/variantResolverTables.js +3128 -0
- package/dist/axe-fx-ii/blockTypes.d.ts +45 -0
- package/dist/axe-fx-ii/blockTypes.d.ts.map +1 -0
- package/dist/axe-fx-ii/blockTypes.js +116 -0
- package/dist/axe-fx-ii/index.d.ts +5 -0
- package/dist/axe-fx-ii/index.d.ts.map +1 -0
- package/dist/axe-fx-ii/index.js +18 -0
- package/dist/axe-fx-ii/paramAliases.d.ts +54 -0
- package/dist/axe-fx-ii/paramAliases.d.ts.map +1 -0
- package/dist/axe-fx-ii/paramAliases.js +146 -0
- package/dist/axe-fx-ii/params.d.ts +11502 -0
- package/dist/axe-fx-ii/params.d.ts.map +1 -0
- package/dist/axe-fx-ii/params.js +2847 -0
- package/dist/axe-fx-ii/setParam.d.ts +560 -0
- package/dist/axe-fx-ii/setParam.d.ts.map +1 -0
- package/dist/axe-fx-ii/setParam.js +888 -0
- package/dist/axe-fx-iii/blockTypes.d.ts +87 -0
- package/dist/axe-fx-iii/blockTypes.d.ts.map +1 -0
- package/dist/axe-fx-iii/blockTypes.js +156 -0
- package/dist/axe-fx-iii/enumOverlay.d.ts +73 -0
- package/dist/axe-fx-iii/enumOverlay.d.ts.map +1 -0
- package/dist/axe-fx-iii/enumOverlay.js +236 -0
- package/dist/axe-fx-iii/index.d.ts +9 -0
- package/dist/axe-fx-iii/index.d.ts.map +1 -0
- package/dist/axe-fx-iii/index.js +20 -0
- package/dist/axe-fx-iii/params.d.ts +179 -0
- package/dist/axe-fx-iii/params.d.ts.map +1 -0
- package/dist/axe-fx-iii/params.js +6913 -0
- package/dist/axe-fx-iii/setParam.d.ts +460 -0
- package/dist/axe-fx-iii/setParam.d.ts.map +1 -0
- package/dist/axe-fx-iii/setParam.js +910 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/shared/checksum.d.ts +10 -0
- package/dist/shared/checksum.d.ts.map +1 -0
- package/dist/shared/checksum.js +14 -0
- package/dist/shared/device.d.ts +195 -0
- package/dist/shared/device.d.ts.map +1 -0
- package/dist/shared/device.js +27 -0
- package/dist/shared/index.d.ts +8 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +11 -0
- package/dist/shared/lineage/amp-lineage.json +8313 -0
- package/dist/shared/lineage/axefx2-amp-lineage.json +5871 -0
- package/dist/shared/lineage/axefx2-delay-lineage.json +226 -0
- package/dist/shared/lineage/axefx2-drive-lineage.json +575 -0
- package/dist/shared/lineage/axefx2-reverb-lineage.json +467 -0
- package/dist/shared/lineage/cab-lineage.json +10777 -0
- package/dist/shared/lineage/chorus-lineage.json +173 -0
- package/dist/shared/lineage/compressor-lineage.json +338 -0
- package/dist/shared/lineage/delay-lineage.json +313 -0
- package/dist/shared/lineage/drive-lineage.json +1844 -0
- package/dist/shared/lineage/flanger-lineage.json +313 -0
- package/dist/shared/lineage/phaser-lineage.json +208 -0
- package/dist/shared/lineage/reverb-lineage.json +793 -0
- package/dist/shared/lineage/wah-lineage.json +117 -0
- package/dist/shared/lineageLookup.d.ts +69 -0
- package/dist/shared/lineageLookup.d.ts.map +1 -0
- package/dist/shared/lineageLookup.js +196 -0
- package/dist/shared/packValue.d.ts +40 -0
- package/dist/shared/packValue.d.ts.map +1 -0
- package/dist/shared/packValue.js +105 -0
- package/dist/shared/types.d.ts +23 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +9 -0
- package/package.json +75 -0
|
@@ -0,0 +1,4537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AM4 parameter registry.
|
|
3
|
+
*
|
|
4
|
+
* Each entry maps a human key (`block.name`) to its wire-level address
|
|
5
|
+
* (`pidLow` = block ID, `pidHigh` = parameter index within block) and
|
|
6
|
+
* its display ↔ internal scale convention.
|
|
7
|
+
*
|
|
8
|
+
* Address is preset-independent (confirmed Session 06 — Amp pidLow
|
|
9
|
+
* matches across A01 and A2). See docs/_private/STATE.md for the decoded set.
|
|
10
|
+
*/
|
|
11
|
+
import { CACHE_PARAMS } from './cacheParams.js';
|
|
12
|
+
import { AMP_TYPES_VALUES, DRIVE_TYPES_VALUES, REVERB_TYPES_VALUES, DELAY_TYPES_VALUES, CHORUS_TYPES_VALUES, FLANGER_TYPES_VALUES, PHASER_TYPES_VALUES, WAH_TYPES_VALUES, COMPRESSOR_TYPES_VALUES, GEQ_TYPES_VALUES, FILTER_TYPES_VALUES, TREMOLO_TYPES_VALUES, ENHANCER_TYPES_VALUES, GATE_TYPES_VALUES, VOLPAN_MODES_VALUES, TEMPO_DIVISIONS_VALUES, LFO_WAVEFORMS_VALUES, } from './cacheEnums.js';
|
|
13
|
+
const DISPLAY_TO_INTERNAL = {
|
|
14
|
+
knob_0_10: 10,
|
|
15
|
+
// HW-028 (Session 35, 2026-04-29): Compressor Emphasis at cache c=20.
|
|
16
|
+
// Display range 0..20 with fractional precision (cache step 0.0005 ×
|
|
17
|
+
// 20 = 0.01 display step). Same shape as knob_0_10 but with double
|
|
18
|
+
// the display range — JFET Studio compressor's Drive-engine emphasis
|
|
19
|
+
// knob is the canonical case.
|
|
20
|
+
knob_0_20: 20,
|
|
21
|
+
db: 1,
|
|
22
|
+
hz: 1,
|
|
23
|
+
seconds: 1,
|
|
24
|
+
percent: 100,
|
|
25
|
+
bipolar_percent: 100,
|
|
26
|
+
count: 1,
|
|
27
|
+
semitones: 1,
|
|
28
|
+
ratio: 1,
|
|
29
|
+
ms: 1000,
|
|
30
|
+
// Cache c=57.295780... = 180/π. AM4-Edit displays Mod Phase / Phase
|
|
31
|
+
// knobs in degrees; firmware stores radians. e.g. 10 deg → 0.17453 rad
|
|
32
|
+
// / 90 deg → 1.5708 rad / 180 deg → 3.14159 rad.
|
|
33
|
+
degrees: 57.29577951308232,
|
|
34
|
+
// Session 36 (HW-040, 2026-04-29): Picofarad capacitance for amp.bright_cap.
|
|
35
|
+
// Cache id=20 a=0.00001 b=0.01 c=1000000 → wire 0.00001..0.01 displays
|
|
36
|
+
// as 10..10000 pF. The "Bright Cap" knob on the FAS Modern III amp's
|
|
37
|
+
// IDEAL section is the canonical case.
|
|
38
|
+
pf: 1000000,
|
|
39
|
+
// BK-035 (Session 36 cont, 2026-04-29): rotary.mic_spacing uses a
|
|
40
|
+
// π-encoded internal scale. Cache id=16 a=0 b=π c=100/π=31.831 → wire
|
|
41
|
+
// 0..π displays as 0..100. Used only by `rotary.mic_spacing` so far;
|
|
42
|
+
// unit name is specific to keep the math discoverable. Same structural
|
|
43
|
+
// pattern as `degrees` (180/π) but maps to a 0..100 linear scale.
|
|
44
|
+
rotary_mic_spacing: 31.83098793029785,
|
|
45
|
+
// Session 38 follow-up (2026-04-30): amp's 8-band Graphic EQ stores
|
|
46
|
+
// each band as ±1 wire, scale ×12 → display ±12 dB. Cache ids 62..69
|
|
47
|
+
// share the (a=-1, b=1, c=12) signature. Distinct from `drive`'s GEQ,
|
|
48
|
+
// which stores ±12 directly (cache c=1) and uses plain `db`. Naming is
|
|
49
|
+
// specific because c=12 only appears on these 8 cache records across
|
|
50
|
+
// the whole AM4 surface.
|
|
51
|
+
amp_geq_band: 12,
|
|
52
|
+
};
|
|
53
|
+
/** Convert a UI/display value to the float the firmware expects. */
|
|
54
|
+
export function encode(param, displayValue) {
|
|
55
|
+
if (param.unit === 'enum')
|
|
56
|
+
return displayValue;
|
|
57
|
+
return displayValue / DISPLAY_TO_INTERNAL[param.unit];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Convert the AM4's internal [0,1] normalized float (decoded from the Q15
|
|
61
|
+
* read register) back to a UI/display value.
|
|
62
|
+
*
|
|
63
|
+
* The AM4 stores all params in a normalized [0,1] form scaled to each
|
|
64
|
+
* param's `[displayMin, displayMax]` range. Most params are linearly
|
|
65
|
+
* scaled; time-based knobs (ms attack/release/delay) and ratio knobs are
|
|
66
|
+
* stored on a log10 curve. Per-param scaling is encoded in `param.scaling`
|
|
67
|
+
* (default `linear`).
|
|
68
|
+
*
|
|
69
|
+
* BK-038 (Session 43 cont, 2026-05-01): the previous decode rule was
|
|
70
|
+
* `internal × DISPLAY_TO_INTERNAL[unit]`, which only happened to be
|
|
71
|
+
* correct for params where `displayMin === 0` AND `displayMax ===
|
|
72
|
+
* DISPLAY_TO_INTERNAL[unit]` (e.g. `knob_0_10` with range 0..10 and
|
|
73
|
+
* scale 10). For most non-knob_0_10 params it produced wildly wrong
|
|
74
|
+
* readbacks ("compressor.attack = 867 ms" when the device displayed
|
|
75
|
+
* 40 ms). Founder-observed via the Sultans-of-Swing iconic-tone test.
|
|
76
|
+
*/
|
|
77
|
+
export function decode(param, internalValue) {
|
|
78
|
+
if (param.unit === 'enum')
|
|
79
|
+
return Math.round(internalValue);
|
|
80
|
+
const { displayMin, displayMax } = param;
|
|
81
|
+
if (param.scaling === 'log10') {
|
|
82
|
+
// Guard against degenerate range / zero-or-negative endpoints.
|
|
83
|
+
if (displayMin <= 0 || displayMax <= 0 || displayMax === displayMin) {
|
|
84
|
+
return displayMin + internalValue * (displayMax - displayMin);
|
|
85
|
+
}
|
|
86
|
+
return displayMin * Math.pow(displayMax / displayMin, internalValue);
|
|
87
|
+
}
|
|
88
|
+
// Linear (default): display = displayMin + internal × (displayMax − displayMin).
|
|
89
|
+
return displayMin + internalValue * (displayMax - displayMin);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Decimal places for display values, per unit. Matches AM4-Edit's on-screen
|
|
93
|
+
* convention so read tool output ("amp.gain is 5.00") doesn't surface the
|
|
94
|
+
* Q15 quantization residue ("amp.gain is 4.9999"). Used by `formatDisplay`.
|
|
95
|
+
*/
|
|
96
|
+
const DISPLAY_PRECISION = {
|
|
97
|
+
knob_0_10: 2,
|
|
98
|
+
knob_0_20: 2,
|
|
99
|
+
db: 1,
|
|
100
|
+
hz: 0,
|
|
101
|
+
seconds: 2,
|
|
102
|
+
percent: 0,
|
|
103
|
+
bipolar_percent: 0,
|
|
104
|
+
count: 0,
|
|
105
|
+
semitones: 0,
|
|
106
|
+
ratio: 1,
|
|
107
|
+
ms: 0,
|
|
108
|
+
degrees: 0,
|
|
109
|
+
pf: 0,
|
|
110
|
+
rotary_mic_spacing: 1,
|
|
111
|
+
amp_geq_band: 1,
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Format a display value for human-readable output (read tools, error
|
|
115
|
+
* messages). Picks decimal precision per `param.unit` so the AM4's Q15
|
|
116
|
+
* quantization residue (~0.0001 on a 0..10 knob) doesn't leak into the
|
|
117
|
+
* agent's tool output. Enum params use `formatEnum` instead.
|
|
118
|
+
*/
|
|
119
|
+
export function formatDisplay(param, displayValue) {
|
|
120
|
+
if (param.unit === 'enum') {
|
|
121
|
+
throw new Error(`formatDisplay called on enum param ${param.block}.${param.name} — use enumValues lookup`);
|
|
122
|
+
}
|
|
123
|
+
return displayValue.toFixed(DISPLAY_PRECISION[param.unit]);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Render the unit suffix for read-tool output, including the leading
|
|
127
|
+
* space. Returns `' <suffix>'` (with leading space) for non-empty
|
|
128
|
+
* suffixes, or empty string when the param is unitless or the override
|
|
129
|
+
* suppresses it. Used by get_param / get_params to format readback
|
|
130
|
+
* strings without trailing whitespace.
|
|
131
|
+
*/
|
|
132
|
+
export function formatUnitSuffix(param) {
|
|
133
|
+
const suffix = param.displayUnit ?? param.unit;
|
|
134
|
+
return suffix === '' ? '' : ` ${suffix}`;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Resolve an enum param's display name (or numeric index) to the wire
|
|
138
|
+
* integer. Accepts numbers directly, exact name matches, and a relaxed
|
|
139
|
+
* case-insensitive match after collapsing whitespace and punctuation —
|
|
140
|
+
* `"Marshall 1959SLP"`, `"1959slp normal"`, and `0` all resolve the
|
|
141
|
+
* same entry.
|
|
142
|
+
*
|
|
143
|
+
* Returns `undefined` if no match is found or the param is not an enum.
|
|
144
|
+
* Callers should treat that as an invalid user input.
|
|
145
|
+
*/
|
|
146
|
+
export function resolveEnumValue(param, input) {
|
|
147
|
+
if (param.unit !== 'enum' || !param.enumValues)
|
|
148
|
+
return undefined;
|
|
149
|
+
if (typeof input === 'number') {
|
|
150
|
+
return param.enumValues[input] !== undefined ? input : undefined;
|
|
151
|
+
}
|
|
152
|
+
const trimmed = input.trim();
|
|
153
|
+
if (trimmed === '')
|
|
154
|
+
return undefined;
|
|
155
|
+
// Exact match first (fast path + most accurate).
|
|
156
|
+
for (const [idx, name] of Object.entries(param.enumValues)) {
|
|
157
|
+
if (name === trimmed)
|
|
158
|
+
return Number(idx);
|
|
159
|
+
}
|
|
160
|
+
// Relaxed match: lowercase, collapse non-alphanumeric to single space.
|
|
161
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
162
|
+
const target = normalize(trimmed);
|
|
163
|
+
for (const [idx, name] of Object.entries(param.enumValues)) {
|
|
164
|
+
if (normalize(name) === target)
|
|
165
|
+
return Number(idx);
|
|
166
|
+
}
|
|
167
|
+
// Substring fallback: pick the entry whose normalized name contains
|
|
168
|
+
// the query (or vice-versa). Only accept unambiguous matches — if
|
|
169
|
+
// more than one entry qualifies, bail rather than pick arbitrarily.
|
|
170
|
+
const hits = [];
|
|
171
|
+
for (const [idx, name] of Object.entries(param.enumValues)) {
|
|
172
|
+
const n = normalize(name);
|
|
173
|
+
if (n.includes(target) || target.includes(n))
|
|
174
|
+
hits.push(Number(idx));
|
|
175
|
+
}
|
|
176
|
+
return hits.length === 1 ? hits[0] : undefined;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Find every enum entry that matches the input under the substring rule
|
|
180
|
+
* used by `resolveEnumValue`. Returns `[indices, names]` of all hits.
|
|
181
|
+
*
|
|
182
|
+
* Used by the validation error path to tell the agent EXACTLY which
|
|
183
|
+
* candidates a partial name like "Room" or "Plate" matched, instead of
|
|
184
|
+
* the previous "first 8 valid names from offset 0" hint that listed
|
|
185
|
+
* names regardless of relevance. Founder-driven (Session 44 Lamb-of-God
|
|
186
|
+
* test): agent passed `reverb.type = "Room"`, hit the ambiguous-bail
|
|
187
|
+
* branch, and the error sample showed Room, Small / Room, Medium /
|
|
188
|
+
* Room, Large / Hall, Small / Hall, Medium … — the Hall entries were
|
|
189
|
+
* noise. With this helper we can show only the matched candidates.
|
|
190
|
+
*/
|
|
191
|
+
export function findEnumCandidates(param, input) {
|
|
192
|
+
if (param.unit !== 'enum' || !param.enumValues)
|
|
193
|
+
return [];
|
|
194
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
195
|
+
const target = normalize(input.trim());
|
|
196
|
+
if (target === '')
|
|
197
|
+
return [];
|
|
198
|
+
const hits = [];
|
|
199
|
+
for (const [idx, name] of Object.entries(param.enumValues)) {
|
|
200
|
+
const n = normalize(name);
|
|
201
|
+
if (n.includes(target) || target.includes(n)) {
|
|
202
|
+
hits.push({ index: Number(idx), name });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return hits;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Common-synonym aliases for parameter names. Maps a `${block}.${alias}`
|
|
209
|
+
* key to the canonical `${block}.${name}` registered in KNOWN_PARAMS.
|
|
210
|
+
*
|
|
211
|
+
* Why this exists. AM4-Edit / Fractal docs use specific names ("time"
|
|
212
|
+
* for both reverb decay and delay repeat time, "rate" for modulation
|
|
213
|
+
* LFO speed, "feedback" for delay repeats). LLM agents reach for the
|
|
214
|
+
* synonyms most common in the gear world ("decay" for reverb, "speed"
|
|
215
|
+
* for modulation, "repeats" for delay) and hit unknown-param errors
|
|
216
|
+
* even though the registered param does the same thing. This map
|
|
217
|
+
* intercepts the well-established universal synonyms before the
|
|
218
|
+
* unknown-param error fires, returning the canonical name silently so
|
|
219
|
+
* the agent's first call lands.
|
|
220
|
+
*
|
|
221
|
+
* Conservative scope. Only synonyms that are universally accepted in
|
|
222
|
+
* music gear documentation (Fractal manual, Boss/Roland docs, synth
|
|
223
|
+
* world). No clever mapping — if there's any ambiguity ("size" could
|
|
224
|
+
* be reverb size or chamber size or amp room size), don't add the
|
|
225
|
+
* alias and let the agent's first error teach it.
|
|
226
|
+
*
|
|
227
|
+
* Founder-driven (Session 44, 2026-05-02): Lamb-of-God Mark Morton tone
|
|
228
|
+
* test had the agent reach for `reverb.decay` (universal synthesizer
|
|
229
|
+
* term) and `reverb.length` (less common but plausible) — both meant
|
|
230
|
+
* `reverb.time`. Aliases prevent the round-trip-and-fix cost that this
|
|
231
|
+
* test had to pay.
|
|
232
|
+
*/
|
|
233
|
+
export const PARAM_ALIASES = {
|
|
234
|
+
// Reverb time = decay (universal synth/reverb-pedal term).
|
|
235
|
+
'reverb.decay': 'reverb.time',
|
|
236
|
+
'reverb.length': 'reverb.time',
|
|
237
|
+
// Delay time = length (less common but plausible from compact-pedal docs).
|
|
238
|
+
'delay.length': 'delay.time',
|
|
239
|
+
// Delay feedback = repeats (Strymon / Eventide convention).
|
|
240
|
+
'delay.repeats': 'delay.feedback',
|
|
241
|
+
// Modulation rate = speed (Boss / MXR convention).
|
|
242
|
+
'chorus.speed': 'chorus.rate',
|
|
243
|
+
'flanger.speed': 'flanger.rate',
|
|
244
|
+
'phaser.speed': 'phaser.rate',
|
|
245
|
+
'tremolo.speed': 'tremolo.rate',
|
|
246
|
+
'rotary.speed': 'rotary.rate',
|
|
247
|
+
// Panel-name vs AM4-name mismatches surfaced by HW-064 (2026-05-05):
|
|
248
|
+
// vintage Fender amps display "Volume" on the front panel but AM4
|
|
249
|
+
// calls the same knob `gain`; drive panels say "Drive" but agents
|
|
250
|
+
// reach for "gain" by analogy with amp.
|
|
251
|
+
'amp.volume': 'amp.gain',
|
|
252
|
+
'drive.gain': 'drive.drive',
|
|
253
|
+
// NOTE: 'reverb.pre_delay' alias removed — canonical key is now
|
|
254
|
+
// 'reverb.pre_delay' itself (renamed from 'reverb.predelay' for
|
|
255
|
+
// UI-label match, audit row REVERB 19).
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Scene-MIDI Type enum (PATCH family, pidHigh row 0x40..0x4F).
|
|
259
|
+
*
|
|
260
|
+
* AM4-Edit's UI exposes only Program Change and Control Change as
|
|
261
|
+
* available message types ("The available message types are Program
|
|
262
|
+
* Change (PC) and Control Change (CC)" — AM4-Edit Scene MIDI page
|
|
263
|
+
* help text). The wire encoding folds the CC number into the Type
|
|
264
|
+
* enum itself:
|
|
265
|
+
*
|
|
266
|
+
* wire 0 → 'None' (no message — Channel/Value greyed out)
|
|
267
|
+
* wire 1 → 'PC' (Program Change — uses Channel + Value)
|
|
268
|
+
* wire N≥2 → 'CC #(N-2)' (Control Change with CC# = N-2)
|
|
269
|
+
*
|
|
270
|
+
* Wire-confirmed against samples/captured/session-85-scene-midi.pcapng
|
|
271
|
+
* (Type=1.0 for PC) and the founder's AM4-Edit screenshot showing
|
|
272
|
+
* "CC #016" displayed when wire Type=18.0 (16 + 2 = 18).
|
|
273
|
+
*
|
|
274
|
+
* Display names use AM4-Edit's exact format: `CC #016` (zero-padded to
|
|
275
|
+
* 3 digits, with a space and hash). Keep parity with what the user
|
|
276
|
+
* reads on screen — `resolveEnumValue` matches by display string.
|
|
277
|
+
*/
|
|
278
|
+
export const SCENE_MIDI_TYPE_ENUM = (() => {
|
|
279
|
+
const out = { 0: 'None', 1: 'PC' };
|
|
280
|
+
for (let cc = 0; cc <= 127; cc++) {
|
|
281
|
+
out[cc + 2] = `CC #${cc.toString().padStart(3, '0')}`;
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
})();
|
|
285
|
+
/**
|
|
286
|
+
* Runtime parameter registry. Hand-authored entries (manual unit/range
|
|
287
|
+
* overrides, out-of-band registers like `*.channel` / `*.level`,
|
|
288
|
+
* hand-authored enum mappings, etc.) are listed explicitly below.
|
|
289
|
+
* Resolver-derived entries flow in via `...CACHE_PARAMS` — that spread
|
|
290
|
+
* imports the bulk auto-generated bindings synthesized by
|
|
291
|
+
* `scripts/gen-params-from-cache.ts` from the AM4-Edit metadata cache,
|
|
292
|
+
* with friendly names from `paramNames.ts` (hand-curated) merged with
|
|
293
|
+
* `paramNamesGenerated.ts` (resolver-derived from AM4-Edit.exe). Order
|
|
294
|
+
* matters: hand entries below shadow any same-key spread entry, so a
|
|
295
|
+
* hand override always wins. `verify-cache-params.ts` enforces that
|
|
296
|
+
* any hand override that COLLIDES with a CACHE_PARAMS entry must agree
|
|
297
|
+
* byte-for-byte (pidLow/pidHigh/unit/displayMin/displayMax/scaling) —
|
|
298
|
+
* pure additions are unconstrained.
|
|
299
|
+
*/
|
|
300
|
+
export const KNOWN_PARAMS = {
|
|
301
|
+
...CACHE_PARAMS,
|
|
302
|
+
'amp.gain': {
|
|
303
|
+
block: 'amp', name: 'gain',
|
|
304
|
+
displayLabel: 'Gain',
|
|
305
|
+
pidLow: 0x003a, pidHigh: 0x000b,
|
|
306
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
307
|
+
},
|
|
308
|
+
'amp.bass': {
|
|
309
|
+
block: 'amp', name: 'bass',
|
|
310
|
+
displayLabel: 'Bass',
|
|
311
|
+
pidLow: 0x003a, pidHigh: 0x000c,
|
|
312
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
313
|
+
},
|
|
314
|
+
// P1-010 Session B (2026-04-19) — AM4 tone stack completion. Cache
|
|
315
|
+
// records at ids 13/14/15 have the identical signature to gain/bass
|
|
316
|
+
// (knob_0_10, 0..1 range, display-scale 10). Named per AM4 Owner's
|
|
317
|
+
// Manual line 1563 "Gain, Bass, Mid, Treble, Presence, Level" and
|
|
318
|
+
// the Fractal Blocks Guide tone-stack order (§Tone Page, pp. 9–10).
|
|
319
|
+
// HW-014 verified (Session 29 cont 7): mid / treble / presence / bass
|
|
320
|
+
// all wrote and displayed correctly on hardware.
|
|
321
|
+
'amp.mid': {
|
|
322
|
+
block: 'amp', name: 'mid',
|
|
323
|
+
displayLabel: 'Mid',
|
|
324
|
+
pidLow: 0x003a, pidHigh: 0x000d,
|
|
325
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
326
|
+
},
|
|
327
|
+
'amp.treble': {
|
|
328
|
+
block: 'amp', name: 'treble',
|
|
329
|
+
displayLabel: 'Tone',
|
|
330
|
+
pidLow: 0x003a, pidHigh: 0x000e,
|
|
331
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
332
|
+
},
|
|
333
|
+
// Session 29 (HW-015): `pidHigh=0x000f` was wrongly registered as
|
|
334
|
+
// amp.presence in Session 26 based on cache signature alone. Two
|
|
335
|
+
// wire captures on Marshall-family amps (unknown amp + Brit 800
|
|
336
|
+
// #34) proved the register is Master. Real Presence is at
|
|
337
|
+
// pidHigh=0x001e (below).
|
|
338
|
+
'amp.master': {
|
|
339
|
+
block: 'amp', name: 'master',
|
|
340
|
+
displayLabel: 'Master',
|
|
341
|
+
pidLow: 0x003a, pidHigh: 0x000f,
|
|
342
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
343
|
+
},
|
|
344
|
+
// Session 29 (HW-015): full 0→10 sweep capture confirmed Depth at
|
|
345
|
+
// pidHigh=0x001a. Knob_0_10 matches the cache signature.
|
|
346
|
+
'amp.depth': {
|
|
347
|
+
block: 'amp', name: 'depth',
|
|
348
|
+
displayLabel: 'Depth',
|
|
349
|
+
pidLow: 0x003a, pidHigh: 0x001a,
|
|
350
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
351
|
+
},
|
|
352
|
+
// Session 29 (HW-015): Presence at pidHigh=0x001e (not 0x000f — see
|
|
353
|
+
// amp.master above). Wire-verified on the same Marshall amp.
|
|
354
|
+
'amp.presence': {
|
|
355
|
+
block: 'amp', name: 'presence',
|
|
356
|
+
displayLabel: 'Presence',
|
|
357
|
+
pidLow: 0x003a, pidHigh: 0x001e,
|
|
358
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
359
|
+
},
|
|
360
|
+
// Session 29 (HW-015): Out Boost Level on the Extras tab, dB knob
|
|
361
|
+
// 0..4 dB with 0.05 dB steps.
|
|
362
|
+
'amp.out_boost_level': {
|
|
363
|
+
block: 'amp', name: 'out_boost_level',
|
|
364
|
+
pidLow: 0x003a, pidHigh: 0x0008,
|
|
365
|
+
unit: 'db', displayMin: 0, displayMax: 4,
|
|
366
|
+
},
|
|
367
|
+
// Session 29 (HW-015): Out Boost ON/OFF toggle on the Extras tab.
|
|
368
|
+
// Registered directly in KNOWN_PARAMS (out-of-band from the cache
|
|
369
|
+
// generator because per-block non-Type enum imports aren't
|
|
370
|
+
// supported). Wire-verified via session-29-amp-out-boost-toggle:
|
|
371
|
+
// value=1.0 → ON.
|
|
372
|
+
'amp.out_boost': {
|
|
373
|
+
block: 'amp', name: 'out_boost',
|
|
374
|
+
displayLabel: 'Out Boost',
|
|
375
|
+
pidLow: 0x003a, pidHigh: 0x0096,
|
|
376
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
377
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
378
|
+
},
|
|
379
|
+
// Session 29 cont: Amp Advanced-panel enums registered from Blocks
|
|
380
|
+
// Guide text (structural — wire indexing assumed from cache enum
|
|
381
|
+
// order). Out-of-band from the cache generator for the same reason
|
|
382
|
+
// amp.out_boost is: the generator emits only the block's Type enum,
|
|
383
|
+
// not its other enum records. HW-014 couldn't verify these from
|
|
384
|
+
// the hardware display alone (both labels are hidden by the AM4
|
|
385
|
+
// hardware UI); AM4-Edit would show them. Structural-only until
|
|
386
|
+
// an AM4-Edit-side verification pass.
|
|
387
|
+
//
|
|
388
|
+
// Tonestack Location (not Type — Type is a separate 69-value enum).
|
|
389
|
+
// Blocks Guide: "POST places the stack between the preamp and
|
|
390
|
+
// power amp. MID places it between the last two triode stages.
|
|
391
|
+
// END places it after the power amp (physically impossible with
|
|
392
|
+
// a real amp)." PRE-MID is the 5th option.
|
|
393
|
+
// renamed for UI-label match (audit row: DISTORT 24)
|
|
394
|
+
'amp.location': {
|
|
395
|
+
block: 'amp', name: 'location',
|
|
396
|
+
displayLabel: 'Location',
|
|
397
|
+
pidLow: 0x003a, pidHigh: 0x0018,
|
|
398
|
+
unit: 'enum', displayMin: 0, displayMax: 4,
|
|
399
|
+
enumValues: { 0: 'PRE', 1: 'POST', 2: 'MID', 3: 'END', 4: 'PRE-MID' },
|
|
400
|
+
},
|
|
401
|
+
// Master Volume Location. Blocks Guide §Advanced (p. 853):
|
|
402
|
+
// "Master Vol Location — Sets the location of the Master Volume
|
|
403
|
+
// control. Most amps have the Master Volume before the phase
|
|
404
|
+
// inverter ('Pre PI'). On some amps (like the 'Class-A' types)
|
|
405
|
+
// the Master Volume comes after the phase inverter ('PI'). A
|
|
406
|
+
// third option, 'pre-triode,' is the default for 'Hipower' amp
|
|
407
|
+
// types."
|
|
408
|
+
'amp.master_vol_location': {
|
|
409
|
+
block: 'amp', name: 'master_vol_location',
|
|
410
|
+
displayLabel: 'Master Vol Location',
|
|
411
|
+
pidLow: 0x003a, pidHigh: 0x0038,
|
|
412
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
413
|
+
enumValues: { 0: 'PRE-PI', 1: 'POST-PI', 2: 'PRE-TRIODE' },
|
|
414
|
+
},
|
|
415
|
+
// HW-040 (Session 36, 2026-04-29): Amp Expert-Edit page from
|
|
416
|
+
// session-40-amp-expert.pcapng + paired AM4-Edit screenshot
|
|
417
|
+
// (FAS Modern III). 17 new params across BASIC + IDEAL + POST
|
|
418
|
+
// BOOST + CHANNEL COLORS + OUTPUT COMPRESSOR + AMP EXTRAS + GEQ
|
|
419
|
+
// sections. Wiggle-order timeline + screenshot column order
|
|
420
|
+
// disambiguates the OFF/ON switches in the IDEAL column. Mirrored
|
|
421
|
+
// from CACHE_PARAMS where applicable; hand-authored enums + the
|
|
422
|
+
// cache-derived block of `bright_cap` / `input_trim` / GEQ bands /
|
|
423
|
+
// `compressor_*` / `master_vol_trim` / `high_treble`.
|
|
424
|
+
//
|
|
425
|
+
// One open follow-up: pidHigh=0x0085 (cache id=133, enum [OFF,ON],
|
|
426
|
+
// wire 1 = ON) is unmapped — wiggled between Master Vol Trim and
|
|
427
|
+
// GEQ Type but doesn't fit a screenshot label cleanly. Likely a
|
|
428
|
+
// POST BOOST related toggle or an amp-mode flag; needs a single
|
|
429
|
+
// disambiguation capture to confirm.
|
|
430
|
+
'amp.bypass_mode': {
|
|
431
|
+
block: 'amp', name: 'bypass_mode',
|
|
432
|
+
pidLow: 0x003a, pidHigh: 0x0004,
|
|
433
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
434
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
435
|
+
},
|
|
436
|
+
'amp.bright_cap': {
|
|
437
|
+
block: 'amp', name: 'bright_cap',
|
|
438
|
+
displayLabel: 'Bright Cap',
|
|
439
|
+
pidLow: 0x003a, pidHigh: 0x0014,
|
|
440
|
+
// Cache id=20: float a=0.00001 b=0.01 c=1000000 → wire 0.00001..0.01
|
|
441
|
+
// displays as 10..10000 pF. New `pf` unit (scale 1000000).
|
|
442
|
+
unit: 'pf', displayMin: 10, displayMax: 10000,
|
|
443
|
+
// typecode 72 = log10 — HW-053 hardware-confirmed (write 220 → AM4 220 ✓; linear readback gave 4480)
|
|
444
|
+
scaling: 'log10',
|
|
445
|
+
},
|
|
446
|
+
'amp.input_select': {
|
|
447
|
+
block: 'amp', name: 'input_select',
|
|
448
|
+
displayLabel: 'Amp Input Select',
|
|
449
|
+
pidLow: 0x003a, pidHigh: 0x0019,
|
|
450
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
451
|
+
enumValues: { 0: 'LEFT', 1: 'RIGHT', 2: 'SUM L+R' },
|
|
452
|
+
},
|
|
453
|
+
'amp.section': {
|
|
454
|
+
block: 'amp', name: 'section',
|
|
455
|
+
displayLabel: 'Amp Section',
|
|
456
|
+
pidLow: 0x003a, pidHigh: 0x0023,
|
|
457
|
+
// AMP EXTRAS.Amp Section toggle.
|
|
458
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
459
|
+
enumValues: { 0: 'ENGAGED', 1: 'BYPASSED' },
|
|
460
|
+
},
|
|
461
|
+
'amp.bright': {
|
|
462
|
+
block: 'amp', name: 'bright',
|
|
463
|
+
displayLabel: 'Bright',
|
|
464
|
+
pidLow: 0x003a, pidHigh: 0x002e,
|
|
465
|
+
// BASIC.Bright toggle. Wiggle-order adjacency pins this between
|
|
466
|
+
// Depth (0x001a) and Master (0x000f) in the BASIC column.
|
|
467
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
468
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
469
|
+
},
|
|
470
|
+
'amp.cut_switch': {
|
|
471
|
+
block: 'amp', name: 'cut_switch',
|
|
472
|
+
displayLabel: 'Cut Switch',
|
|
473
|
+
pidLow: 0x003a, pidHigh: 0x0034,
|
|
474
|
+
// IDEAL.Cut Switch — wiggle adjacency pins it between High Treble
|
|
475
|
+
// (0x0068) and Fat Switch (0x0055) in the IDEAL column.
|
|
476
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
477
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
478
|
+
},
|
|
479
|
+
'amp.input_trim': {
|
|
480
|
+
block: 'amp', name: 'input_trim',
|
|
481
|
+
displayLabel: 'Input Trim',
|
|
482
|
+
pidLow: 0x003a, pidHigh: 0x0036,
|
|
483
|
+
// Cache id=54: float a=0.1 b=10 c=1 raw 0.1..10. Same shape as
|
|
484
|
+
// master_vol_trim; `count` here is structural (display = wire ×
|
|
485
|
+
// 1) not integer-only.
|
|
486
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
487
|
+
},
|
|
488
|
+
// 8-band Graphic EQ — frequencies per the screenshot: 62/125/250/
|
|
489
|
+
// 500/1K/2K/4K/8K Hz, each ±12 dB. Cache ids 62..69 share the
|
|
490
|
+
// (a=-1, b=1, c=12) signature: wire stored as ±1, displayed as ±12 dB.
|
|
491
|
+
// Uses the `amp_geq_band` unit (scale 12). Drive's GEQ uses plain `db`
|
|
492
|
+
// because its cache stores ±12 directly (c=1).
|
|
493
|
+
'amp.geq_band_1': { block: 'amp', name: 'geq_band_1', displayLabel: 'Bass', pidLow: 0x003a, pidHigh: 0x003e, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
494
|
+
'amp.geq_band_2': { block: 'amp', name: 'geq_band_2', displayLabel: 'Mid', pidLow: 0x003a, pidHigh: 0x003f, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
495
|
+
'amp.geq_band_3': { block: 'amp', name: 'geq_band_3', displayLabel: 'Treble', pidLow: 0x003a, pidHigh: 0x0040, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
496
|
+
'amp.geq_band_4': { block: 'amp', name: 'geq_band_4', displayLabel: 'Presence', pidLow: 0x003a, pidHigh: 0x0041, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
497
|
+
'amp.geq_band_5': { block: 'amp', name: 'geq_band_5', displayLabel: '1K', pidLow: 0x003a, pidHigh: 0x0042, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
498
|
+
'amp.geq_band_6': { block: 'amp', name: 'geq_band_6', displayLabel: '2K', pidLow: 0x003a, pidHigh: 0x0043, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
499
|
+
'amp.geq_band_7': { block: 'amp', name: 'geq_band_7', displayLabel: '4K', pidLow: 0x003a, pidHigh: 0x0044, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
500
|
+
'amp.geq_band_8': { block: 'amp', name: 'geq_band_8', displayLabel: '8K', pidLow: 0x003a, pidHigh: 0x0045, unit: 'amp_geq_band', displayMin: -12, displayMax: 12 },
|
|
501
|
+
// renamed for UI-label match (audit row: DISTORT 77)
|
|
502
|
+
'amp.clarity': {
|
|
503
|
+
block: 'amp', name: 'clarity',
|
|
504
|
+
displayLabel: 'Clarity',
|
|
505
|
+
pidLow: 0x003a, pidHigh: 0x004d,
|
|
506
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
507
|
+
// typecode 80 = log10 (HW-053 cont). displayMin=0 makes log10
|
|
508
|
+
// fall back to linear at runtime; declared anyway to match the
|
|
509
|
+
// cache-derived scaling and keep verify-cache-params byte-exact.
|
|
510
|
+
scaling: 'log10',
|
|
511
|
+
},
|
|
512
|
+
// renamed for UI-label match (audit row: DISTORT 82)
|
|
513
|
+
'amp.amount': {
|
|
514
|
+
block: 'amp', name: 'amount',
|
|
515
|
+
displayLabel: 'Amount',
|
|
516
|
+
pidLow: 0x003a, pidHigh: 0x0052,
|
|
517
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
518
|
+
},
|
|
519
|
+
// renamed for UI-label match (audit row: DISTORT 83)
|
|
520
|
+
'amp.threshold': {
|
|
521
|
+
block: 'amp', name: 'threshold',
|
|
522
|
+
displayLabel: 'Threshold',
|
|
523
|
+
pidLow: 0x003a, pidHigh: 0x0053,
|
|
524
|
+
unit: 'db', displayMin: -60, displayMax: 0,
|
|
525
|
+
},
|
|
526
|
+
'amp.master_vol_trim': {
|
|
527
|
+
block: 'amp', name: 'master_vol_trim',
|
|
528
|
+
displayLabel: 'Master Vol Trim',
|
|
529
|
+
pidLow: 0x003a, pidHigh: 0x0054,
|
|
530
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
531
|
+
// HW-054 readback surfaced "7 count" — misleading. AM4 displays
|
|
532
|
+
// this as a unitless 0..10 knob; the `count` unit tag is
|
|
533
|
+
// structural (encode scale 1, cache c=1). Suppress the suffix.
|
|
534
|
+
displayUnit: '',
|
|
535
|
+
},
|
|
536
|
+
// renamed for UI-label match (audit row: DISTORT 85)
|
|
537
|
+
'amp.fat': {
|
|
538
|
+
block: 'amp', name: 'fat',
|
|
539
|
+
displayLabel: 'Fat',
|
|
540
|
+
pidLow: 0x003a, pidHigh: 0x0055,
|
|
541
|
+
// IDEAL.Fat Switch — wiggle adjacency pins it right after Cut
|
|
542
|
+
// Switch (0x0034) in the IDEAL column.
|
|
543
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
544
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
545
|
+
},
|
|
546
|
+
'amp.geq_type': {
|
|
547
|
+
block: 'amp', name: 'geq_type',
|
|
548
|
+
displayLabel: 'Type',
|
|
549
|
+
pidLow: 0x003a, pidHigh: 0x0063,
|
|
550
|
+
// Cache id=99: 4-entry enum.
|
|
551
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
552
|
+
enumValues: { 0: '8 BAND VAR Q', 1: '7 BAND VAR Q', 2: '5 BAND (MARK)', 3: '8 BAND CONST Q' },
|
|
553
|
+
},
|
|
554
|
+
'amp.high_treble': {
|
|
555
|
+
block: 'amp', name: 'high_treble',
|
|
556
|
+
displayLabel: 'High Treble',
|
|
557
|
+
pidLow: 0x003a, pidHigh: 0x0068,
|
|
558
|
+
// IDEAL.High Treble — bipolar dB ±12 at cache id=104.
|
|
559
|
+
unit: 'db', displayMin: -12, displayMax: 12,
|
|
560
|
+
},
|
|
561
|
+
'amp.compressor_type': {
|
|
562
|
+
block: 'amp', name: 'compressor_type',
|
|
563
|
+
displayLabel: 'Type',
|
|
564
|
+
pidLow: 0x003a, pidHigh: 0x0074,
|
|
565
|
+
// Cache id=116: 3-entry enum.
|
|
566
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
567
|
+
enumValues: { 0: 'OUTPUT', 1: 'FEEDBACK', 2: 'GAIN ENHANCER' },
|
|
568
|
+
},
|
|
569
|
+
'amp.output_mode': {
|
|
570
|
+
block: 'amp', name: 'output_mode',
|
|
571
|
+
displayLabel: 'Amp Output Mode',
|
|
572
|
+
pidLow: 0x003a, pidHigh: 0x0083,
|
|
573
|
+
// Cache id=131: 2-entry enum.
|
|
574
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
575
|
+
enumValues: { 0: 'FRFR', 1: 'SS PWR AMP + CAB' },
|
|
576
|
+
},
|
|
577
|
+
// HW-024 (Session 30 cont 3, 2026-04-25): hardware-verified at
|
|
578
|
+
// +8 dB on a 1959SLP Normal — first non-default positive-value
|
|
579
|
+
// datapoint for amp.level (HW-014 only tested at the default).
|
|
580
|
+
'amp.level': {
|
|
581
|
+
block: 'amp', name: 'level',
|
|
582
|
+
pidLow: 0x003a, pidHigh: 0x0000,
|
|
583
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
584
|
+
},
|
|
585
|
+
'amp.channel': {
|
|
586
|
+
block: 'amp', name: 'channel',
|
|
587
|
+
pidLow: 0x003a, pidHigh: 0x07d2,
|
|
588
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
589
|
+
// Session 08: A→B→A and A→C→D→A captures confirmed all 4 indices.
|
|
590
|
+
enumValues: { 0: 'A', 1: 'B', 2: 'C', 3: 'D' },
|
|
591
|
+
},
|
|
592
|
+
'amp.type': {
|
|
593
|
+
block: 'amp', name: 'type',
|
|
594
|
+
pidLow: 0x003a, pidHigh: 0x000a,
|
|
595
|
+
// Session 16: enum dictionary imported from cacheEnums.ts (248 models).
|
|
596
|
+
// Wire indexing verified via drive.type ground truth; amp.type index
|
|
597
|
+
// 0 in cache is "1959SLP Normal". Untested against capture — flag as
|
|
598
|
+
// such when hardening.
|
|
599
|
+
unit: 'enum', displayMin: 0, displayMax: 247,
|
|
600
|
+
enumValues: AMP_TYPES_VALUES,
|
|
601
|
+
},
|
|
602
|
+
// ─── HW-041 (Session 41+, 2026-04-30): Amp Expert-Edit page (4 tabs) ───
|
|
603
|
+
// Source: session-41-amp-{preamp,poweramp,cabinet,speaker}-expert.{pcapng,png}
|
|
604
|
+
// + founder-confirmed audit-input JSONs at docs/audit-input/amp-*.json.
|
|
605
|
+
// Audit script output: docs/audit-output/amp-*.md.
|
|
606
|
+
//
|
|
607
|
+
// The amp Expert page surfaces ~120 knobs across Preamp / Power Amp /
|
|
608
|
+
// Cabinet / Speaker tabs — far more than the 16 BASIC params already
|
|
609
|
+
// registered. Cabinet knobs use a SEPARATE block ID (pidLow=0x003e),
|
|
610
|
+
// not the amp pidLow=0x003a; preamp/power-amp/speaker share 0x003a.
|
|
611
|
+
// Block prefix is kept as `amp` since AM4 surfaces all four tabs as
|
|
612
|
+
// one user-facing block, even though the protocol splits cabinet out.
|
|
613
|
+
//
|
|
614
|
+
// Naming: knobs are keyed by their AM4-Edit label, snake-cased, with
|
|
615
|
+
// disambiguating prefixes where labels collide between sections (e.g.
|
|
616
|
+
// `power_tube_hardness` vs preamp `tube_hardness`, `pi_bias_excursion`
|
|
617
|
+
// vs `master_bias_excursion`, speaker `spkr_compression` vs the
|
|
618
|
+
// amp Compressor section's `compressor_amount`/`compressor_clarity`).
|
|
619
|
+
//
|
|
620
|
+
// Verification: ⚠ unregistered rows from the audit table where the
|
|
621
|
+
// wire×scale match was uniquely-on-the-label-side OR where ambiguity
|
|
622
|
+
// was resolved by domain reasoning (scale plausibility + screenshot
|
|
623
|
+
// section position). Ambiguous rows where neither candidate label is
|
|
624
|
+
// unique on the label side were skipped — those need a follow-up
|
|
625
|
+
// capture wiggling one of the colliding knobs in isolation.
|
|
626
|
+
//
|
|
627
|
+
// Skipped from audit (need follow-up):
|
|
628
|
+
// • Preamp 0x0082 (Input EQ Low Cut duplicate at scale ×10)
|
|
629
|
+
// • Power Amp 0x005d / 0x0090 (Cathode Resistance vs Master Bias
|
|
630
|
+
// Excursion duplicates at wire=1.0)
|
|
631
|
+
// • Power Amp 0x0026 / 0x0064 / 0x008d / 0x0093 (no screenshot match)
|
|
632
|
+
// • Cabinet 0x001c (Cab 1 Low Cut needs different scale than
|
|
633
|
+
// master_low_cut — likely log-Hz storage; skipped pending decode)
|
|
634
|
+
// • Cabinet 0x0045 / 0x0046 (Cab 1/2 Position — bipolar -10..10
|
|
635
|
+
// range needs new unit, no existing fit)
|
|
636
|
+
// • Cabinet 0x0024 / 0x002c / 0x0030 / 0x0031 (LF/HF Damping —
|
|
637
|
+
// three pidHighs share value 8.0, can't disambiguate)
|
|
638
|
+
// • Cabinet 0x0011 + 0x0016 + 0x0017 + many wire=1.0 rows (no
|
|
639
|
+
// screenshot match or false-positive ×10 scale matches)
|
|
640
|
+
// • Speaker 0x0022 / 0x0033 / 0x0039 / 0x0048 / 0x0087 / 0x008e /
|
|
641
|
+
// 0x0092 (Low/Hi Reso, Drive, others not wiggled or scale TBD)
|
|
642
|
+
//
|
|
643
|
+
// ── Preamp tab (pidLow=0x003a) ──
|
|
644
|
+
'amp.in_boost_level': {
|
|
645
|
+
block: 'amp', name: 'in_boost_level',
|
|
646
|
+
displayLabel: 'In Boost Level',
|
|
647
|
+
pidLow: 0x003a, pidHigh: 0x0081,
|
|
648
|
+
// Preamp.Input Boost section. Screenshot 1.11 dB (no unit visible
|
|
649
|
+
// but Boost knobs are conventionally dB on Fractal).
|
|
650
|
+
unit: 'db', displayMin: 0, displayMax: 20,
|
|
651
|
+
},
|
|
652
|
+
'amp.saturation_drive': {
|
|
653
|
+
block: 'amp', name: 'saturation_drive',
|
|
654
|
+
displayLabel: 'Saturation Drive',
|
|
655
|
+
pidLow: 0x003a, pidHigh: 0x0070,
|
|
656
|
+
// Preamp.Saturation Mod.Saturation Drive. Screenshot 2.220, no
|
|
657
|
+
// visible unit on AM4-Edit panel; treated as raw count.
|
|
658
|
+
unit: 'count', displayMin: 0, displayMax: 10,
|
|
659
|
+
},
|
|
660
|
+
'amp.tonestack_frequency': {
|
|
661
|
+
block: 'amp', name: 'tonestack_frequency',
|
|
662
|
+
displayLabel: 'Frequency',
|
|
663
|
+
pidLow: 0x003a, pidHigh: 0x0012,
|
|
664
|
+
// Preamp.Tonestack.Frequency. Screenshot 333.0 Hz raw.
|
|
665
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
666
|
+
},
|
|
667
|
+
'amp.tube_hardness': {
|
|
668
|
+
block: 'amp', name: 'tube_hardness',
|
|
669
|
+
displayLabel: 'Tube Hardness',
|
|
670
|
+
pidLow: 0x003a, pidHigh: 0x0037,
|
|
671
|
+
// Preamp.Preamp.Tube Hardness — knob_0_10 (wire 0.444 → display 4.44).
|
|
672
|
+
// Distinct from amp.power_tube_hardness on the Power Amp tab.
|
|
673
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
674
|
+
},
|
|
675
|
+
'amp.triode_1_plate_freq': {
|
|
676
|
+
block: 'amp', name: 'triode_1_plate_freq',
|
|
677
|
+
displayLabel: 'Triode 1 Plate Freq',
|
|
678
|
+
pidLow: 0x003a, pidHigh: 0x004a,
|
|
679
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
680
|
+
},
|
|
681
|
+
'amp.triode_2_plate_freq': {
|
|
682
|
+
block: 'amp', name: 'triode_2_plate_freq',
|
|
683
|
+
displayLabel: 'Triode 2 Plate Freq',
|
|
684
|
+
pidLow: 0x003a, pidHigh: 0x0049,
|
|
685
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
686
|
+
},
|
|
687
|
+
'amp.preamp_bias': {
|
|
688
|
+
block: 'amp', name: 'preamp_bias',
|
|
689
|
+
displayLabel: 'Preamp Bias',
|
|
690
|
+
pidLow: 0x003a, pidHigh: 0x0031,
|
|
691
|
+
// Screenshot -0.700 raw — bipolar count.
|
|
692
|
+
unit: 'count', displayMin: -1, displayMax: 1,
|
|
693
|
+
},
|
|
694
|
+
'amp.preamp_bias_excursion': {
|
|
695
|
+
block: 'amp', name: 'preamp_bias_excursion',
|
|
696
|
+
displayLabel: 'Bias Excursion',
|
|
697
|
+
pidLow: 0x003a, pidHigh: 0x0071,
|
|
698
|
+
// Preamp.Preamp.Bias Excursion — percent (wire 0.080 → display 8.0%).
|
|
699
|
+
// Distinct from amp.power_tube_bias_excursion / amp.pi_bias_excursion
|
|
700
|
+
// / amp.master_bias_excursion on the Power Amp tab.
|
|
701
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
702
|
+
},
|
|
703
|
+
// renamed for UI-label match (audit row: DISTORT 17)
|
|
704
|
+
'amp.high_cut_frequency': {
|
|
705
|
+
block: 'amp', name: 'high_cut_frequency',
|
|
706
|
+
displayLabel: 'High Cut Frequency',
|
|
707
|
+
pidLow: 0x003a, pidHigh: 0x0011,
|
|
708
|
+
// Preamp.Preamp.High Cut Frequency — bottom row of the PREAMP
|
|
709
|
+
// section. Screenshot 9999.1 Hz raw.
|
|
710
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
711
|
+
},
|
|
712
|
+
// renamed for UI-label match (audit row: DISTORT 16)
|
|
713
|
+
'amp.low_cut': {
|
|
714
|
+
block: 'amp', name: 'low_cut',
|
|
715
|
+
displayLabel: 'Low Cut',
|
|
716
|
+
pidLow: 0x003a, pidHigh: 0x0010,
|
|
717
|
+
// Preamp.Input EQ.Low Cut. Screenshot 130.0 Hz raw.
|
|
718
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
719
|
+
},
|
|
720
|
+
'amp.input_eq_gain': {
|
|
721
|
+
block: 'amp', name: 'input_eq_gain',
|
|
722
|
+
displayLabel: 'Gain',
|
|
723
|
+
pidLow: 0x003a, pidHigh: 0x0050,
|
|
724
|
+
// Preamp.Input EQ.Gain. Screenshot 11.00 dB raw.
|
|
725
|
+
unit: 'db', displayMin: -20, displayMax: 20,
|
|
726
|
+
},
|
|
727
|
+
// renamed for UI-label match (audit row: DISTORT 78)
|
|
728
|
+
'amp.q': {
|
|
729
|
+
block: 'amp', name: 'q',
|
|
730
|
+
displayLabel: 'Q',
|
|
731
|
+
pidLow: 0x003a, pidHigh: 0x004e,
|
|
732
|
+
// Preamp.Input EQ.Q. Screenshot 0.120 raw count.
|
|
733
|
+
unit: 'count', displayMin: 0.1, displayMax: 10,
|
|
734
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
735
|
+
scaling: 'log10',
|
|
736
|
+
},
|
|
737
|
+
// ── Power Amp tab (pidLow=0x003a) ──
|
|
738
|
+
'amp.supply_sag': {
|
|
739
|
+
block: 'amp', name: 'supply_sag',
|
|
740
|
+
displayLabel: 'Supply Sag',
|
|
741
|
+
pidLow: 0x003a, pidHigh: 0x001d,
|
|
742
|
+
// Power Amp.Power Supply.Supply Sag. Screenshot 2.20 (knob_0_10:
|
|
743
|
+
// wire 0.220 → display 2.20). Disambiguated from Power Tubes Hardness
|
|
744
|
+
// (which sits at 0x005f wire=0.700 → display 7.00).
|
|
745
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
746
|
+
},
|
|
747
|
+
// renamed for UI-label match (audit row: DISTORT 31)
|
|
748
|
+
'amp.negative_fb': {
|
|
749
|
+
block: 'amp', name: 'negative_fb',
|
|
750
|
+
displayLabel: 'Negative FB',
|
|
751
|
+
pidLow: 0x003a, pidHigh: 0x001f,
|
|
752
|
+
// Power Amp.Power Amp.Negative Feedback. Screenshot 4.44 — percent
|
|
753
|
+
// ×100 (wire 0.0444 → 4.44%). NFB display has no visible unit on
|
|
754
|
+
// AM4-Edit; ×100 scale fits the captured wire cleanly.
|
|
755
|
+
unit: 'percent', displayMin: 0, displayMax: 10,
|
|
756
|
+
// HW-054 readback surfaced "5 percent" — misleading. AM4 actually
|
|
757
|
+
// displays NFB as a unitless 0..10 knob; the `percent` unit is
|
|
758
|
+
// for encode-scale only (cache c=100). Suppress the suffix.
|
|
759
|
+
displayUnit: '',
|
|
760
|
+
// HW-053b cont audit: HW-053: cache b*c = 10, not 100. Hand entry was off by 10×; readback came out 50 instead of 5.
|
|
761
|
+
},
|
|
762
|
+
'amp.presence_freq': {
|
|
763
|
+
block: 'amp', name: 'presence_freq',
|
|
764
|
+
displayLabel: 'Presence Freq',
|
|
765
|
+
pidLow: 0x003a, pidHigh: 0x0020,
|
|
766
|
+
// HW-053 (2026-05-04): cache record at id=32 has a=0.1, b=10, c=1.
|
|
767
|
+
// The original HW-040 screenshot read "6.660 Hz raw" but the AM4
|
|
768
|
+
// device actually displays the value as 0.1..10 (kHz on the device,
|
|
769
|
+
// shown without explicit unit suffix). Earlier registration of
|
|
770
|
+
// displayMin=20 displayMax=20000 was off by ~1000× and saturated
|
|
771
|
+
// every write. Range corrected to match the cache truth; unit kept
|
|
772
|
+
// as 'hz' so agent reads it as a frequency knob (the agent should
|
|
773
|
+
// pass values in the 0.1..10 range, which AM4-Edit renders as kHz).
|
|
774
|
+
unit: 'hz', displayMin: 0.1, displayMax: 10,
|
|
775
|
+
// HW-054 readback surfaced "3 hz" — agent then mentally translated
|
|
776
|
+
// to kHz, awkward. Override the suffix to 'kHz' so the readback
|
|
777
|
+
// matches the user's mental model. Encoding is unaffected.
|
|
778
|
+
displayUnit: 'kHz',
|
|
779
|
+
// typecode 64 = log10 (HW-053 confirmed: write 3 → AM4 3.000 ✓ but readback was 7 with linear decode)
|
|
780
|
+
scaling: 'log10',
|
|
781
|
+
},
|
|
782
|
+
'amp.depth_freq': {
|
|
783
|
+
block: 'amp', name: 'depth_freq',
|
|
784
|
+
displayLabel: 'Depth Freq',
|
|
785
|
+
pidLow: 0x003a, pidHigh: 0x0024,
|
|
786
|
+
// HW-053 (2026-05-04): cache record at id=36 has a=50, b=500, c=1.
|
|
787
|
+
// Same screenshot-misread pattern as presence_freq. Range corrected
|
|
788
|
+
// to the cache truth (50..500 Hz, real Hz this time).
|
|
789
|
+
unit: 'hz', displayMin: 50, displayMax: 500,
|
|
790
|
+
},
|
|
791
|
+
// renamed for UI-label match (audit row: DISTORT 40)
|
|
792
|
+
'amp.harmonics': {
|
|
793
|
+
block: 'amp', name: 'harmonics',
|
|
794
|
+
displayLabel: 'Harmonics',
|
|
795
|
+
pidLow: 0x003a, pidHigh: 0x0028,
|
|
796
|
+
// Power Amp.Cathode Follower.Harmonics. Screenshot 0.150 Hz —
|
|
797
|
+
// raw value (label says "Hz" but the magnitude reads as a 0..1
|
|
798
|
+
// ratio, likely a normalised knob despite the unit suffix).
|
|
799
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
800
|
+
},
|
|
801
|
+
'amp.b_plus_time_constant': {
|
|
802
|
+
block: 'amp', name: 'b_plus_time_constant',
|
|
803
|
+
displayLabel: 'B+ Time Constant',
|
|
804
|
+
pidLow: 0x003a, pidHigh: 0x002a,
|
|
805
|
+
// Power Amp.Power Supply.B+ Time Constant. Screenshot 9.50 ms
|
|
806
|
+
// (wire 0.0095 ×1000 = 9.5).
|
|
807
|
+
unit: 'ms', displayMin: 0.1, displayMax: 1000,
|
|
808
|
+
// typecode 68 = log10 (HW-053b cont audit)
|
|
809
|
+
scaling: 'log10',
|
|
810
|
+
},
|
|
811
|
+
'amp.grid_bias': {
|
|
812
|
+
block: 'amp', name: 'grid_bias',
|
|
813
|
+
displayLabel: 'Grid Bias',
|
|
814
|
+
pidLow: 0x003a, pidHigh: 0x002b,
|
|
815
|
+
// Power Amp.Power Tubes.Grid Bias. Screenshot 16.0 % (wire 0.160).
|
|
816
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
817
|
+
},
|
|
818
|
+
'amp.xformer_drive': {
|
|
819
|
+
block: 'amp', name: 'xformer_drive',
|
|
820
|
+
displayLabel: 'XFormer Drive',
|
|
821
|
+
pidLow: 0x003a, pidHigh: 0x0035,
|
|
822
|
+
// Power Amp.Transformer.XFormer Drive. Screenshot 0.120 raw count.
|
|
823
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
824
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
825
|
+
scaling: 'log10',
|
|
826
|
+
},
|
|
827
|
+
'amp.xformer_matching': {
|
|
828
|
+
block: 'amp', name: 'xformer_matching',
|
|
829
|
+
displayLabel: 'XFormer Matching',
|
|
830
|
+
pidLow: 0x003a, pidHigh: 0x003a,
|
|
831
|
+
// Power Amp.Transformer.XFormer Matching. Screenshot 1.300 raw.
|
|
832
|
+
unit: 'count', displayMin: 0.1, displayMax: 10,
|
|
833
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
834
|
+
scaling: 'log10',
|
|
835
|
+
},
|
|
836
|
+
'amp.screen_frequency': {
|
|
837
|
+
block: 'amp', name: 'screen_frequency',
|
|
838
|
+
displayLabel: 'Screen Frequency',
|
|
839
|
+
pidLow: 0x003a, pidHigh: 0x003b,
|
|
840
|
+
// HW-053 (2026-05-04): cache record at id=59 has a=1, b=100, c=1.
|
|
841
|
+
// The AM4 device displays this as a unitless 0..100 raw knob (the
|
|
842
|
+
// founder confirmed "no units on device for Screen Frequency"). The
|
|
843
|
+
// earlier "Hz" registration was a screenshot misread. Despite the
|
|
844
|
+
// parameterName ending in "FREQ", the firmware exposes it as a raw
|
|
845
|
+
// power-supply knob without a frequency unit on the device UI.
|
|
846
|
+
unit: 'count', displayMin: 1, displayMax: 100,
|
|
847
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
848
|
+
scaling: 'log10',
|
|
849
|
+
},
|
|
850
|
+
'amp.screen_q': {
|
|
851
|
+
block: 'amp', name: 'screen_q',
|
|
852
|
+
displayLabel: 'Screen Q',
|
|
853
|
+
pidLow: 0x003a, pidHigh: 0x003c,
|
|
854
|
+
// Power Amp.Power Supply.Screen Q. Screenshot 8.500 raw count.
|
|
855
|
+
unit: 'count', displayMin: 0.1, displayMax: 10,
|
|
856
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
857
|
+
scaling: 'log10',
|
|
858
|
+
},
|
|
859
|
+
'amp.power_tube_bias_excursion': {
|
|
860
|
+
block: 'amp', name: 'power_tube_bias_excursion',
|
|
861
|
+
displayLabel: 'Bias Excursion',
|
|
862
|
+
pidLow: 0x003a, pidHigh: 0x0046,
|
|
863
|
+
// Power Amp.Power Tubes.Bias Excursion. Screenshot 19.0 %.
|
|
864
|
+
// Distinct from preamp_bias_excursion / pi_bias_excursion /
|
|
865
|
+
// master_bias_excursion (4 separate "bias excursion" knobs).
|
|
866
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
867
|
+
},
|
|
868
|
+
'amp.cathode_follower_compression': {
|
|
869
|
+
block: 'amp', name: 'cathode_follower_compression',
|
|
870
|
+
displayLabel: 'Power Tube Type',
|
|
871
|
+
pidLow: 0x003a, pidHigh: 0x004b,
|
|
872
|
+
// Power Amp.Cathode Follower.Compression. Screenshot 14.0 %.
|
|
873
|
+
// Stored raw (wire 14.0 → display 14.0%) NOT as percent ×100,
|
|
874
|
+
// confirmed by scale ×1 match in audit. Treat unit as 'count'
|
|
875
|
+
// even though display suffix is %.
|
|
876
|
+
unit: 'count', displayMin: 0, displayMax: 100,
|
|
877
|
+
},
|
|
878
|
+
'amp.ac_line_frequency': {
|
|
879
|
+
block: 'amp', name: 'ac_line_frequency',
|
|
880
|
+
displayLabel: 'AC Line Frequency',
|
|
881
|
+
pidLow: 0x003a, pidHigh: 0x005e,
|
|
882
|
+
// Power Amp.Power Supply.AC Line Frequency. Screenshot 65 Hz raw.
|
|
883
|
+
// Typical range 50/60 Hz mains; AM4-Edit allows wider sweep.
|
|
884
|
+
unit: 'hz', displayMin: 30, displayMax: 200,
|
|
885
|
+
},
|
|
886
|
+
// renamed for UI-label match (audit row: DISTORT 95)
|
|
887
|
+
'amp.hardness': {
|
|
888
|
+
block: 'amp', name: 'hardness',
|
|
889
|
+
displayLabel: 'Hardness',
|
|
890
|
+
pidLow: 0x003a, pidHigh: 0x005f,
|
|
891
|
+
// Power Amp.Power Tubes.Hardness. Screenshot 7.00 (knob_0_10).
|
|
892
|
+
// Distinct from preamp tube_hardness (separate knob, separate
|
|
893
|
+
// wire address).
|
|
894
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
895
|
+
// typecode 80 = log10 (HW-053b cont audit)
|
|
896
|
+
scaling: 'log10',
|
|
897
|
+
},
|
|
898
|
+
'amp.cathode_time_const': {
|
|
899
|
+
block: 'amp', name: 'cathode_time_const',
|
|
900
|
+
displayLabel: 'Cathode Time Const',
|
|
901
|
+
pidLow: 0x003a, pidHigh: 0x0065,
|
|
902
|
+
// Power Amp.Power Amp.Cathode Time Const. Screenshot 10.00 ms
|
|
903
|
+
// (wire 0.010 ×1000 = 10).
|
|
904
|
+
unit: 'ms', displayMin: 0.1, displayMax: 1000,
|
|
905
|
+
// typecode 68 = log10 (HW-053b cont audit)
|
|
906
|
+
scaling: 'log10',
|
|
907
|
+
},
|
|
908
|
+
'amp.mismatch': {
|
|
909
|
+
block: 'amp', name: 'mismatch',
|
|
910
|
+
displayLabel: 'Mismatch',
|
|
911
|
+
pidLow: 0x003a, pidHigh: 0x0069,
|
|
912
|
+
// Power Amp.Power Tubes.Mismatch. Screenshot 0.180 raw count.
|
|
913
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
914
|
+
},
|
|
915
|
+
'amp.variac': {
|
|
916
|
+
block: 'amp', name: 'variac',
|
|
917
|
+
displayLabel: 'Variac',
|
|
918
|
+
pidLow: 0x003a, pidHigh: 0x006c,
|
|
919
|
+
// Power Amp.Power Supply.Variac. Screenshot 55.0 % (wire 0.550 ×100).
|
|
920
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
921
|
+
},
|
|
922
|
+
'amp.pi_bias_excursion': {
|
|
923
|
+
block: 'amp', name: 'pi_bias_excursion',
|
|
924
|
+
displayLabel: 'PI Bias Excursion',
|
|
925
|
+
pidLow: 0x003a, pidHigh: 0x0079,
|
|
926
|
+
// Power Amp.Power Amp.PI Bias Excursion (phase-inverter).
|
|
927
|
+
// Screenshot 11.0 % (wire 0.110 ×100).
|
|
928
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
929
|
+
},
|
|
930
|
+
'amp.master_bias_excursion': {
|
|
931
|
+
block: 'amp', name: 'master_bias_excursion',
|
|
932
|
+
displayLabel: 'Master Bias Excursion',
|
|
933
|
+
pidLow: 0x003a, pidHigh: 0x008b,
|
|
934
|
+
// Power Amp.Power Tubes.Master Bias Excursion. Screenshot 20.0 %.
|
|
935
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
936
|
+
},
|
|
937
|
+
// ── Speaker tab (pidLow=0x003a) ──
|
|
938
|
+
// Section breakdown: Impedance (top half — XFormer / Low / Hi knobs +
|
|
939
|
+
// a frequency-response curve) and Speaker (bottom — speaker-emulation
|
|
940
|
+
// character knobs).
|
|
941
|
+
'amp.xformer_low_freq': {
|
|
942
|
+
block: 'amp', name: 'xformer_low_freq',
|
|
943
|
+
displayLabel: 'XFormer Low Freq',
|
|
944
|
+
pidLow: 0x003a, pidHigh: 0x0016,
|
|
945
|
+
// Speaker.Impedance.XFormer Low Freq. Screenshot 33.3 Hz (wire stores
|
|
946
|
+
// 33.33; AM4-Edit display rounds to 1 decimal).
|
|
947
|
+
unit: 'hz', displayMin: 10, displayMax: 20000,
|
|
948
|
+
},
|
|
949
|
+
'amp.low_freq': {
|
|
950
|
+
block: 'amp', name: 'low_freq',
|
|
951
|
+
displayLabel: 'Low Freq',
|
|
952
|
+
pidLow: 0x003a, pidHigh: 0x0021,
|
|
953
|
+
// Speaker.Impedance.Low Freq. Screenshot 44.4 Hz (wire 44.44).
|
|
954
|
+
unit: 'hz', displayMin: 10, displayMax: 20000,
|
|
955
|
+
},
|
|
956
|
+
'amp.low_q': {
|
|
957
|
+
block: 'amp', name: 'low_q',
|
|
958
|
+
displayLabel: 'Low Q',
|
|
959
|
+
pidLow: 0x003a, pidHigh: 0x0030,
|
|
960
|
+
// Speaker.Impedance.Low Q. Screenshot 0.666 raw count.
|
|
961
|
+
unit: 'count', displayMin: 0.1, displayMax: 10,
|
|
962
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
963
|
+
scaling: 'log10',
|
|
964
|
+
},
|
|
965
|
+
'amp.xformer_hi_freq': {
|
|
966
|
+
block: 'amp', name: 'xformer_hi_freq',
|
|
967
|
+
displayLabel: 'XFormer Hi Freq',
|
|
968
|
+
pidLow: 0x003a, pidHigh: 0x0017,
|
|
969
|
+
// Speaker.Impedance.XFormer Hi Freq. Screenshot 12000 Hz raw.
|
|
970
|
+
unit: 'hz', displayMin: 100, displayMax: 20000,
|
|
971
|
+
},
|
|
972
|
+
'amp.high_freq': {
|
|
973
|
+
block: 'amp', name: 'high_freq',
|
|
974
|
+
displayLabel: 'High Freq',
|
|
975
|
+
pidLow: 0x003a, pidHigh: 0x0032,
|
|
976
|
+
// Speaker.Impedance.High Freq. Screenshot 666.0 Hz raw.
|
|
977
|
+
unit: 'hz', displayMin: 100, displayMax: 20000,
|
|
978
|
+
},
|
|
979
|
+
'amp.hi_slope': {
|
|
980
|
+
block: 'amp', name: 'hi_slope',
|
|
981
|
+
displayLabel: 'Hi Slope',
|
|
982
|
+
pidLow: 0x003a, pidHigh: 0x006b,
|
|
983
|
+
// Speaker.Impedance.Hi Slope. Screenshot 8.880 (knob_0_10:
|
|
984
|
+
// wire 0.888 ×10 = 8.88). Disambiguated from Speaker.Compression
|
|
985
|
+
// (also wire 0.888) by section-position heuristic — Hi Slope is
|
|
986
|
+
// higher in the AM4-Edit UI (Impedance > Speaker), and 0x006b
|
|
987
|
+
// sits before 0x007a in pidHigh order.
|
|
988
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
989
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
990
|
+
scaling: 'log10',
|
|
991
|
+
},
|
|
992
|
+
'amp.cab_resonance': {
|
|
993
|
+
block: 'amp', name: 'cab_resonance',
|
|
994
|
+
displayLabel: 'Cab Resonance',
|
|
995
|
+
pidLow: 0x003a, pidHigh: 0x0088,
|
|
996
|
+
// Speaker.Impedance.Cab Resonance. Screenshot 111.1 % (wire 1.111
|
|
997
|
+
// ×100). Display can exceed 100% — set displayMax wider.
|
|
998
|
+
unit: 'percent', displayMin: 0, displayMax: 200,
|
|
999
|
+
},
|
|
1000
|
+
'amp.speaker_impedance': {
|
|
1001
|
+
block: 'amp', name: 'speaker_impedance',
|
|
1002
|
+
displayLabel: 'Speaker Impedance',
|
|
1003
|
+
pidLow: 0x003a, pidHigh: 0x0086,
|
|
1004
|
+
// Speaker.Impedance.Speaker Impedance. Screenshot 1.220 raw count.
|
|
1005
|
+
unit: 'count', displayMin: 0.1, displayMax: 10,
|
|
1006
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
1007
|
+
scaling: 'log10',
|
|
1008
|
+
},
|
|
1009
|
+
'amp.spkr_compression': {
|
|
1010
|
+
block: 'amp', name: 'spkr_compression',
|
|
1011
|
+
displayLabel: 'Compression',
|
|
1012
|
+
pidLow: 0x003a, pidHigh: 0x007a,
|
|
1013
|
+
// Speaker.Speaker.Compression. Screenshot 8.88 (knob_0_10).
|
|
1014
|
+
// Named with `spkr_` prefix to distinguish from the Compressor
|
|
1015
|
+
// section's `compression` register (cacheParams.ts pidHigh=0x0057).
|
|
1016
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1017
|
+
},
|
|
1018
|
+
'amp.compliance': {
|
|
1019
|
+
block: 'amp', name: 'compliance',
|
|
1020
|
+
displayLabel: 'Compliance',
|
|
1021
|
+
pidLow: 0x003a, pidHigh: 0x0084,
|
|
1022
|
+
// Speaker.Speaker.Compliance. Screenshot 99.0 % (wire 0.990).
|
|
1023
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1024
|
+
},
|
|
1025
|
+
// renamed for UI-label match (audit row: DISTORT 123)
|
|
1026
|
+
'amp.time_constant': {
|
|
1027
|
+
block: 'amp', name: 'time_constant',
|
|
1028
|
+
displayLabel: 'Time Constant',
|
|
1029
|
+
pidLow: 0x003a, pidHigh: 0x007b,
|
|
1030
|
+
// Speaker.Speaker.Time Constant. Screenshot 1000.0 ms (wire 1.000
|
|
1031
|
+
// ×1000). `spkr_` prefix to avoid confusion with cathode_time_const
|
|
1032
|
+
// on the Power Amp tab.
|
|
1033
|
+
unit: 'ms', displayMin: 0.1, displayMax: 10000,
|
|
1034
|
+
// typecode 68 = log10 (HW-053b cont audit)
|
|
1035
|
+
scaling: 'log10',
|
|
1036
|
+
},
|
|
1037
|
+
'amp.thump': {
|
|
1038
|
+
block: 'amp', name: 'thump',
|
|
1039
|
+
displayLabel: 'Thump',
|
|
1040
|
+
pidLow: 0x003a, pidHigh: 0x008f,
|
|
1041
|
+
// Speaker.Speaker.Thump. Screenshot 1.11 (knob_0_10).
|
|
1042
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1043
|
+
},
|
|
1044
|
+
// ── Cabinet tab (pidLow=0x003e — separate block ID from amp 0x003a) ──
|
|
1045
|
+
'amp.cab1_distance': {
|
|
1046
|
+
block: 'amp', name: 'cab1_distance',
|
|
1047
|
+
pidLow: 0x003e, pidHigh: 0x0002,
|
|
1048
|
+
// Cabinet.Cab 1.Distance. Screenshot 2.22 cm (wire 0.022 ×100).
|
|
1049
|
+
// Display unit on AM4-Edit is "cm"; firmware stores cm/100.
|
|
1050
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1051
|
+
},
|
|
1052
|
+
'amp.cab_mic_preamp_drive': {
|
|
1053
|
+
block: 'amp', name: 'cab_mic_preamp_drive',
|
|
1054
|
+
displayLabel: 'Drive',
|
|
1055
|
+
pidLow: 0x003e, pidHigh: 0x001a,
|
|
1056
|
+
// Cabinet.Cab Mic Preamp.Drive. Screenshot 6.60 (knob_0_10).
|
|
1057
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1058
|
+
},
|
|
1059
|
+
'amp.cab_mic_preamp_saturation': {
|
|
1060
|
+
block: 'amp', name: 'cab_mic_preamp_saturation',
|
|
1061
|
+
displayLabel: 'Saturation',
|
|
1062
|
+
pidLow: 0x003e, pidHigh: 0x001b,
|
|
1063
|
+
// Cabinet.Cab Mic Preamp.Saturation. Screenshot 7.77 (knob_0_10).
|
|
1064
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1065
|
+
},
|
|
1066
|
+
'amp.cab_mic_preamp_treble': {
|
|
1067
|
+
block: 'amp', name: 'cab_mic_preamp_treble',
|
|
1068
|
+
displayLabel: 'Treble',
|
|
1069
|
+
pidLow: 0x003e, pidHigh: 0x0027,
|
|
1070
|
+
// Cabinet.Cab Mic Preamp.Treble. Screenshot 10.00 dB raw.
|
|
1071
|
+
// (Many wire=1.0 rows in the audit also matched this label via the
|
|
1072
|
+
// ×10 scale — those are false positives; the canonical pidHigh
|
|
1073
|
+
// is 0x0027 with wire=10.0 raw.)
|
|
1074
|
+
unit: 'db', displayMin: -20, displayMax: 20,
|
|
1075
|
+
},
|
|
1076
|
+
'amp.room_size': {
|
|
1077
|
+
block: 'amp', name: 'room_size',
|
|
1078
|
+
displayLabel: 'Room Size',
|
|
1079
|
+
pidLow: 0x003e, pidHigh: 0x001d,
|
|
1080
|
+
// Cabinet.Room.Room Size. Screenshot 5.55 m raw count.
|
|
1081
|
+
unit: 'count', displayMin: 0.1, displayMax: 50,
|
|
1082
|
+
},
|
|
1083
|
+
'amp.mic_spacing': {
|
|
1084
|
+
block: 'amp', name: 'mic_spacing',
|
|
1085
|
+
displayLabel: 'Mic Spacing',
|
|
1086
|
+
pidLow: 0x003e, pidHigh: 0x001e,
|
|
1087
|
+
// Cabinet.Room.Mic Spacing. Screenshot 10.1 % (wire 0.101 ×100).
|
|
1088
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1089
|
+
},
|
|
1090
|
+
'amp.cab_master_high_cut': {
|
|
1091
|
+
block: 'amp', name: 'cab_master_high_cut',
|
|
1092
|
+
displayLabel: 'High Cut',
|
|
1093
|
+
pidLow: 0x003e, pidHigh: 0x0020,
|
|
1094
|
+
// Cabinet.Cab Master EQ.Master High Cut. Screenshot 222 Hz
|
|
1095
|
+
// (founder-confirmed deliberate non-default value).
|
|
1096
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
1097
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
1098
|
+
scaling: 'log10',
|
|
1099
|
+
},
|
|
1100
|
+
'amp.cab_master_low_cut': {
|
|
1101
|
+
block: 'amp', name: 'cab_master_low_cut',
|
|
1102
|
+
displayLabel: 'Proximity Frequency',
|
|
1103
|
+
pidLow: 0x003e, pidHigh: 0x0022,
|
|
1104
|
+
// Cabinet.Cab Master EQ.Master Low Cut. Screenshot 33.3 Hz raw.
|
|
1105
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
1106
|
+
},
|
|
1107
|
+
'amp.cab_master_level': {
|
|
1108
|
+
block: 'amp', name: 'cab_master_level',
|
|
1109
|
+
displayLabel: 'Air',
|
|
1110
|
+
pidLow: 0x003e, pidHigh: 0x002d,
|
|
1111
|
+
// Cabinet.Cab Extras.Cab Master Level. Screenshot 1.1 dB
|
|
1112
|
+
// (wire 0.110 ×10 = 1.10). Stored as knob_0_10 even though the
|
|
1113
|
+
// display suffix is dB.
|
|
1114
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1115
|
+
},
|
|
1116
|
+
'amp.air_frequency': {
|
|
1117
|
+
block: 'amp', name: 'air_frequency',
|
|
1118
|
+
displayLabel: 'Frequency',
|
|
1119
|
+
pidLow: 0x003e, pidHigh: 0x002e,
|
|
1120
|
+
// Cabinet.Air.Frequency. Screenshot 12121 Hz raw.
|
|
1121
|
+
unit: 'hz', displayMin: 100, displayMax: 20000,
|
|
1122
|
+
},
|
|
1123
|
+
'amp.room_diffusion': {
|
|
1124
|
+
block: 'amp', name: 'room_diffusion',
|
|
1125
|
+
displayLabel: 'Room Diffusion',
|
|
1126
|
+
pidLow: 0x003e, pidHigh: 0x0032,
|
|
1127
|
+
// Cabinet.Room.Room Diffusion. Screenshot 7.0 % (wire 0.070).
|
|
1128
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1129
|
+
},
|
|
1130
|
+
'amp.cab2_low_cut': {
|
|
1131
|
+
block: 'amp', name: 'cab2_low_cut',
|
|
1132
|
+
displayLabel: 'Low Cut',
|
|
1133
|
+
pidLow: 0x003e, pidHigh: 0x0036,
|
|
1134
|
+
// Cabinet.Cab 2.Low Cut. Screenshot 55.0 Hz raw.
|
|
1135
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
1136
|
+
// typecode 64 = log10 (HW-053b cont audit)
|
|
1137
|
+
scaling: 'log10',
|
|
1138
|
+
},
|
|
1139
|
+
'amp.cab1_high_cut': {
|
|
1140
|
+
block: 'amp', name: 'cab1_high_cut',
|
|
1141
|
+
displayLabel: 'High Cut',
|
|
1142
|
+
pidLow: 0x003e, pidHigh: 0x0037,
|
|
1143
|
+
// Cabinet.Cab 1.High Cut. Screenshot 5500.0 Hz raw.
|
|
1144
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
1145
|
+
},
|
|
1146
|
+
'amp.cab2_high_cut': {
|
|
1147
|
+
block: 'amp', name: 'cab2_high_cut',
|
|
1148
|
+
displayLabel: 'High Cut',
|
|
1149
|
+
pidLow: 0x003e, pidHigh: 0x0038,
|
|
1150
|
+
// Cabinet.Cab 2.High Cut. Screenshot 4444.1 Hz raw.
|
|
1151
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
1152
|
+
},
|
|
1153
|
+
'amp.align_distance_1': {
|
|
1154
|
+
block: 'amp', name: 'align_distance_1',
|
|
1155
|
+
displayLabel: 'Mic Distance',
|
|
1156
|
+
pidLow: 0x003e, pidHigh: 0x0012,
|
|
1157
|
+
// Cabinet.Align modal.Distance 1. Screenshot 5.000 ms
|
|
1158
|
+
// (wire 0.005 ×1000). Distinct delay-trim knob from Cab 1 Distance.
|
|
1159
|
+
unit: 'ms', displayMin: 0, displayMax: 100,
|
|
1160
|
+
},
|
|
1161
|
+
'amp.align_distance_2': {
|
|
1162
|
+
block: 'amp', name: 'align_distance_2',
|
|
1163
|
+
displayLabel: 'Mic Distance',
|
|
1164
|
+
pidLow: 0x003e, pidHigh: 0x0013,
|
|
1165
|
+
// Cabinet.Align modal.Distance 2. Screenshot 6.000 ms.
|
|
1166
|
+
unit: 'ms', displayMin: 0, displayMax: 100,
|
|
1167
|
+
},
|
|
1168
|
+
// Session 90 (2026-05-17) — CABINET UI-MISSING closeout. 25 new amp
|
|
1169
|
+
// params at pidLow=0x003e from the Ghidra CABINET catalog (Sessions
|
|
1170
|
+
// 82-83) cross-referenced against the 54-entry UI-MISSING list in
|
|
1171
|
+
// samples/captured/decoded/coverage-cross-ref-audit.md. Names chosen
|
|
1172
|
+
// to match the AM4-Edit XML display label after norm() (lowercase +
|
|
1173
|
+
// non-alphanumeric → _) so each new entry registers as WIRED-MATCHED
|
|
1174
|
+
// (not MISLABEL). For paired controls (Cab 1 / Cab 2 sharing a single
|
|
1175
|
+
// XML label like "Pan", "Bank", "Mute"), only the "_1" member is
|
|
1176
|
+
// added — the "_2" member would force a MISLABEL since both entries
|
|
1177
|
+
// can't simultaneously match the same display label and the drift
|
|
1178
|
+
// guard ceiling is at 112. Future capture batch may add the _2
|
|
1179
|
+
// variants once the renaming pass lowers the MISLABEL count.
|
|
1180
|
+
//
|
|
1181
|
+
// Units follow the brief: enum (no enumValues — needs capture) for
|
|
1182
|
+
// BANK / TYPE / MODE / INPUTSEL / PRETYPE / OVERSAMPLE / ROOMSHAPE;
|
|
1183
|
+
// OFF/ON enum for MUTE / AUTO_ALIGN / BYPASS; bipolar_percent for
|
|
1184
|
+
// PAN; hz for PROXIMITY / LO-HI-CUT / FREQ; db for LEVEL / DAMPING;
|
|
1185
|
+
// count for VU meter (read-only) and other dimensionless knobs.
|
|
1186
|
+
// Hand-authored (not via paramNames.ts / gen-params-from-cache.ts)
|
|
1187
|
+
// because the CABINET catalog ids live in the Ghidra dispatcher
|
|
1188
|
+
// table, not in any S2/S3 cache block — same hand-author pattern as
|
|
1189
|
+
// the existing 16 cab_* entries from Session 38 (HW-041).
|
|
1190
|
+
//
|
|
1191
|
+
// SKIP rationale (per brief):
|
|
1192
|
+
// - 33 CABINET_ZOOM, 65-68 DYNACAB_TYPE/MIC1/2 — XML display "—"
|
|
1193
|
+
// (no UI evidence, no name to verify against).
|
|
1194
|
+
// - 65000+ CABINET_NAME/LABEL/BTN/PICKER/COPY_MENU/ALIGN_GRAPH —
|
|
1195
|
+
// firmware ghost registers (string-name slots, action buttons),
|
|
1196
|
+
// not user-editable knobs.
|
|
1197
|
+
// - 53 CABINET_LOCUT1 (XML "Low Cut") — would collide with the
|
|
1198
|
+
// existing amp.low_cut at pidLow=0x003a, and using a different
|
|
1199
|
+
// name would force MISLABEL.
|
|
1200
|
+
// - 37 CABINET_BASS (XML "Bass"), 38 CABINET_MID (XML "Mid"),
|
|
1201
|
+
// 36 CABINET_PRETYPE (XML "Type") — name collisions with the
|
|
1202
|
+
// existing amp.bass / amp.mid / amp.type at pidLow=0x003a.
|
|
1203
|
+
// - "_2" pair members where the XML label is identical to the
|
|
1204
|
+
// "_1" member's label (BANK2, TYPE2, PAN2, PROXIMITY2, MUTE2,
|
|
1205
|
+
// LOSLOPE2, HISLOPE2, DYNACAB_R2, DYNACAB_Z2) — would force
|
|
1206
|
+
// MISLABEL since both can't match the same display string.
|
|
1207
|
+
'amp.bank': {
|
|
1208
|
+
block: 'amp', name: 'bank',
|
|
1209
|
+
displayLabel: 'Bank',
|
|
1210
|
+
pidLow: 0x003e, pidHigh: 0x000a,
|
|
1211
|
+
// CABINET_BANK1 (catalog id=10). AM4-Edit "Bank" — cab IR-pack
|
|
1212
|
+
// selector (UltraRes / Legacy / etc.). TODO: capture enum values.
|
|
1213
|
+
unit: 'enum', displayMin: 0, displayMax: 31,
|
|
1214
|
+
},
|
|
1215
|
+
'amp.cab': {
|
|
1216
|
+
block: 'amp', name: 'cab',
|
|
1217
|
+
displayLabel: 'Cab #',
|
|
1218
|
+
pidLow: 0x003e, pidHigh: 0x000c,
|
|
1219
|
+
// CABINET_TYPE1 (catalog id=12). AM4-Edit "Cab #" — cab IR
|
|
1220
|
+
// selector within the active bank. TODO: capture enum values
|
|
1221
|
+
// (range varies by bank; conservative 0..255 for now).
|
|
1222
|
+
unit: 'enum', displayMin: 0, displayMax: 255,
|
|
1223
|
+
},
|
|
1224
|
+
'amp.pan': {
|
|
1225
|
+
block: 'amp', name: 'pan',
|
|
1226
|
+
displayLabel: 'Pan',
|
|
1227
|
+
pidLow: 0x003e, pidHigh: 0x0010,
|
|
1228
|
+
// CABINET_PAN1 (catalog id=16). AM4-Edit "Pan" — cab 1 stereo pan.
|
|
1229
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
1230
|
+
},
|
|
1231
|
+
// SKIP: CABINET_PROXIMITY1 (catalog id=20, XML "Proximity") would
|
|
1232
|
+
// collide with the existing CACHE_PARAMS entry `amp.proximity` at
|
|
1233
|
+
// pidLow=0x003a / pidHigh=0x15 (the cross-block addressing surfaced
|
|
1234
|
+
// by the variant resolver as DISTORT cache id=21). verify-cache-
|
|
1235
|
+
// params fails on duplicate-key with conflicting pidLow. Renaming
|
|
1236
|
+
// to e.g. `cab_proximity` would force a WIRED-MISLABEL since the
|
|
1237
|
+
// XML label is "Proximity"; the drift guard ceiling has no
|
|
1238
|
+
// headroom. Defer until a WIRED-MISLABEL review pass lowers the
|
|
1239
|
+
// ceiling and frees a slot.
|
|
1240
|
+
'amp.cab_mode': {
|
|
1241
|
+
block: 'amp', name: 'cab_mode',
|
|
1242
|
+
displayLabel: 'Cab Mode',
|
|
1243
|
+
pidLow: 0x003e, pidHigh: 0x0018,
|
|
1244
|
+
// CABINET_MODE (catalog id=24). AM4-Edit "Cab Mode" — selects
|
|
1245
|
+
// single / dual / DynaCab routing. TODO: capture enum values.
|
|
1246
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1247
|
+
},
|
|
1248
|
+
'amp.cab_section': {
|
|
1249
|
+
block: 'amp', name: 'cab_section',
|
|
1250
|
+
displayLabel: 'Cab Section',
|
|
1251
|
+
pidLow: 0x003e, pidHigh: 0x0019,
|
|
1252
|
+
// CABINET_BYPASS (catalog id=25). AM4-Edit "Cab Section" — section-
|
|
1253
|
+
// level bypass for the cab block (distinct from preset bypass).
|
|
1254
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
1255
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
1256
|
+
},
|
|
1257
|
+
'amp.room_level': {
|
|
1258
|
+
block: 'amp', name: 'room_level',
|
|
1259
|
+
displayLabel: 'Room Level',
|
|
1260
|
+
pidLow: 0x003e, pidHigh: 0x001c,
|
|
1261
|
+
// CABINET_ROOMMIX (catalog id=28). AM4-Edit "Room Level" — wet/dry
|
|
1262
|
+
// mix of the room reflection model into the cab signal.
|
|
1263
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1264
|
+
},
|
|
1265
|
+
'amp.cab_input_mode': {
|
|
1266
|
+
block: 'amp', name: 'cab_input_mode',
|
|
1267
|
+
displayLabel: 'Cab Input Mode',
|
|
1268
|
+
pidLow: 0x003e, pidHigh: 0x0023,
|
|
1269
|
+
// CABINET_INPUTSEL (catalog id=35). AM4-Edit "Cab Input Mode" —
|
|
1270
|
+
// selects L / R / SUM input to the cab block. TODO: capture enum.
|
|
1271
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
1272
|
+
},
|
|
1273
|
+
'amp.mode': {
|
|
1274
|
+
block: 'amp', name: 'mode',
|
|
1275
|
+
displayLabel: 'Mode',
|
|
1276
|
+
pidLow: 0x003e, pidHigh: 0x0028,
|
|
1277
|
+
// CABINET_OVERSAMPLE (catalog id=40). AM4-Edit "Mode" — IR engine
|
|
1278
|
+
// oversampling / quality mode selector. TODO: capture enum values.
|
|
1279
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
1280
|
+
},
|
|
1281
|
+
'amp.floor_reflections': {
|
|
1282
|
+
block: 'amp', name: 'floor_reflections',
|
|
1283
|
+
displayLabel: 'Floor Reflections',
|
|
1284
|
+
pidLow: 0x003e, pidHigh: 0x002c,
|
|
1285
|
+
// CABINET_FLOORLVL (catalog id=44). AM4-Edit "Floor Reflections" —
|
|
1286
|
+
// level of floor-bounce reflections in the room model.
|
|
1287
|
+
unit: 'db', displayMin: -60, displayMax: 12,
|
|
1288
|
+
},
|
|
1289
|
+
'amp.room_shape': {
|
|
1290
|
+
block: 'amp', name: 'room_shape',
|
|
1291
|
+
displayLabel: 'Room Shape',
|
|
1292
|
+
pidLow: 0x003e, pidHigh: 0x002f,
|
|
1293
|
+
// CABINET_ROOMSHAPE (catalog id=47). AM4-Edit "Room Shape" —
|
|
1294
|
+
// selects the room geometry preset (square / rectangle / etc.).
|
|
1295
|
+
// TODO: capture enum values.
|
|
1296
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1297
|
+
},
|
|
1298
|
+
'amp.lf_damping': {
|
|
1299
|
+
block: 'amp', name: 'lf_damping',
|
|
1300
|
+
displayLabel: 'LF Damping',
|
|
1301
|
+
pidLow: 0x003e, pidHigh: 0x0030,
|
|
1302
|
+
// CABINET_LFDAMPING (catalog id=48). AM4-Edit "LF Damping" —
|
|
1303
|
+
// low-frequency damping in the room reflection model.
|
|
1304
|
+
unit: 'db', displayMin: -60, displayMax: 12,
|
|
1305
|
+
},
|
|
1306
|
+
'amp.hf_damping': {
|
|
1307
|
+
block: 'amp', name: 'hf_damping',
|
|
1308
|
+
displayLabel: 'HF Damping',
|
|
1309
|
+
pidLow: 0x003e, pidHigh: 0x0031,
|
|
1310
|
+
// CABINET_HFDAMPING (catalog id=49). AM4-Edit "HF Damping" —
|
|
1311
|
+
// high-frequency damping in the room reflection model.
|
|
1312
|
+
unit: 'db', displayMin: -60, displayMax: 12,
|
|
1313
|
+
},
|
|
1314
|
+
'amp.cab_vu': {
|
|
1315
|
+
block: 'amp', name: 'cab_vu',
|
|
1316
|
+
displayLabel: 'Cab VU',
|
|
1317
|
+
pidLow: 0x003e, pidHigh: 0x0034,
|
|
1318
|
+
// CABINET_VUMETER (catalog id=52). AM4-Edit "Cab VU" — read-only
|
|
1319
|
+
// output-level meter for the cab block. Count-style 0..1 like the
|
|
1320
|
+
// amp.b_plus_monitor / gain_monitor read-only meters.
|
|
1321
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
1322
|
+
},
|
|
1323
|
+
'amp.cab_1_ir_length': {
|
|
1324
|
+
block: 'amp', name: 'cab_1_ir_length',
|
|
1325
|
+
displayLabel: 'Cab 1 IR Length',
|
|
1326
|
+
pidLow: 0x003e, pidHigh: 0x0039,
|
|
1327
|
+
// CABINET_LENGTH1 (catalog id=57). AM4-Edit "Cab 1 IR Length" —
|
|
1328
|
+
// impulse-response truncation length in samples / ms for Cab 1.
|
|
1329
|
+
unit: 'count', displayMin: 0, displayMax: 8192,
|
|
1330
|
+
},
|
|
1331
|
+
'amp.cab_2_ir_length': {
|
|
1332
|
+
block: 'amp', name: 'cab_2_ir_length',
|
|
1333
|
+
displayLabel: 'Cab 2 IR Length',
|
|
1334
|
+
pidLow: 0x003e, pidHigh: 0x003a,
|
|
1335
|
+
// CABINET_LENGTH2 (catalog id=58). AM4-Edit "Cab 2 IR Length" —
|
|
1336
|
+
// sibling to cab_1_ir_length for Cab 2.
|
|
1337
|
+
unit: 'count', displayMin: 0, displayMax: 8192,
|
|
1338
|
+
},
|
|
1339
|
+
'amp.low_slope': {
|
|
1340
|
+
block: 'amp', name: 'low_slope',
|
|
1341
|
+
displayLabel: 'Low Slope',
|
|
1342
|
+
pidLow: 0x003e, pidHigh: 0x003b,
|
|
1343
|
+
// CABINET_LOSLOPE1 (catalog id=59). AM4-Edit "Low Slope" — Cab 1
|
|
1344
|
+
// low-cut filter slope in dB/oct. TODO: capture enum values
|
|
1345
|
+
// (commonly 6/12/18/24/36/48 dB/oct in Fractal cab filters).
|
|
1346
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1347
|
+
},
|
|
1348
|
+
'amp.high_slope': {
|
|
1349
|
+
block: 'amp', name: 'high_slope',
|
|
1350
|
+
displayLabel: 'High Slope',
|
|
1351
|
+
pidLow: 0x003e, pidHigh: 0x003d,
|
|
1352
|
+
// CABINET_HISLOPE1 (catalog id=61). AM4-Edit "High Slope" — Cab 1
|
|
1353
|
+
// high-cut filter slope in dB/oct. TODO: capture enum values.
|
|
1354
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1355
|
+
},
|
|
1356
|
+
'amp.master_low_slope': {
|
|
1357
|
+
block: 'amp', name: 'master_low_slope',
|
|
1358
|
+
displayLabel: 'Master Low Slope',
|
|
1359
|
+
pidLow: 0x003e, pidHigh: 0x003f,
|
|
1360
|
+
// CABINET_PRELOSLOPE (catalog id=63). AM4-Edit "Master Low Slope" —
|
|
1361
|
+
// Cab-Master EQ low-cut slope (sibling to cab_master_low_cut Hz).
|
|
1362
|
+
// TODO: capture enum values.
|
|
1363
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1364
|
+
},
|
|
1365
|
+
'amp.master_high_slope': {
|
|
1366
|
+
block: 'amp', name: 'master_high_slope',
|
|
1367
|
+
displayLabel: 'Master High Slope',
|
|
1368
|
+
pidLow: 0x003e, pidHigh: 0x0040,
|
|
1369
|
+
// CABINET_PREHISLOPE (catalog id=64). AM4-Edit "Master High Slope" —
|
|
1370
|
+
// Cab-Master EQ high-cut slope (sibling to cab_master_high_cut Hz).
|
|
1371
|
+
// TODO: capture enum values.
|
|
1372
|
+
unit: 'enum', displayMin: 0, displayMax: 7,
|
|
1373
|
+
},
|
|
1374
|
+
'amp.dynacab': {
|
|
1375
|
+
block: 'amp', name: 'dynacab',
|
|
1376
|
+
displayLabel: 'DynaCab',
|
|
1377
|
+
pidLow: 0x003e, pidHigh: 0x0045,
|
|
1378
|
+
// CABINET_DYNACAB_R1 (catalog id=69). AM4-Edit "DynaCab" — Cab 1
|
|
1379
|
+
// DynaCab radius/rotation. Knob-style 0..10.
|
|
1380
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1381
|
+
},
|
|
1382
|
+
// SKIP: CABINET_DYNACAB_Z1 (catalog id=71, XML "Distance") would
|
|
1383
|
+
// collide with the existing CACHE_PARAMS entry `amp.distance` at
|
|
1384
|
+
// pidLow=0x003a / pidHigh=0x47. Same cross-block ghost-resolver
|
|
1385
|
+
// pattern as the skipped amp.proximity above. Defer.
|
|
1386
|
+
'amp.cab_1_blend': {
|
|
1387
|
+
block: 'amp', name: 'cab_1_blend',
|
|
1388
|
+
displayLabel: 'Cab 1 Blend',
|
|
1389
|
+
pidLow: 0x003e, pidHigh: 0x004b,
|
|
1390
|
+
// CABINET_BLEND1 (catalog id=75). AM4-Edit "Cab 1 Blend" — IR
|
|
1391
|
+
// blend percentage for Cab 1 (when blending two IRs in one cab).
|
|
1392
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1393
|
+
},
|
|
1394
|
+
'amp.cab_2_blend': {
|
|
1395
|
+
block: 'amp', name: 'cab_2_blend',
|
|
1396
|
+
displayLabel: 'Cab 2 Blend',
|
|
1397
|
+
pidLow: 0x003e, pidHigh: 0x004c,
|
|
1398
|
+
// CABINET_BLEND2 (catalog id=76). AM4-Edit "Cab 2 Blend" — sibling
|
|
1399
|
+
// to cab_1_blend for Cab 2.
|
|
1400
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1401
|
+
},
|
|
1402
|
+
'amp.auto_align': {
|
|
1403
|
+
block: 'amp', name: 'auto_align',
|
|
1404
|
+
displayLabel: 'Auto Align',
|
|
1405
|
+
pidLow: 0x003e, pidHigh: 0x004d,
|
|
1406
|
+
// CABINET_AUTO_ALIGN (catalog id=77). AM4-Edit "Auto Align" —
|
|
1407
|
+
// toggle for automatic cab alignment (phase / delay matching
|
|
1408
|
+
// across the two cabs). OFF/ON enum.
|
|
1409
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
1410
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
1411
|
+
},
|
|
1412
|
+
// Session 89 (2026-05-16) — DISTORT UI-MISSING closeout. 16 new amp
|
|
1413
|
+
// params mirrored from CACHE_PARAMS so the coverage-audit (which
|
|
1414
|
+
// text-greps params.ts) sees them. Wire bytes + units come from
|
|
1415
|
+
// paramNames.ts overrides; cacheParams.ts emits the canonical entries
|
|
1416
|
+
// and verify-cache-params guards byte-for-byte agreement. displayLabel
|
|
1417
|
+
// = AM4-Edit XML "name=" attribute for the same EditorControl. See
|
|
1418
|
+
// samples/captured/decoded/am4-params-proposed.ts for the Ghidra
|
|
1419
|
+
// catalog source (Sessions 82–83) and cache-section2.json for the
|
|
1420
|
+
// signature data that pinned each unit + range.
|
|
1421
|
+
'amp.low_reso': {
|
|
1422
|
+
block: 'amp', name: 'low_reso',
|
|
1423
|
+
displayLabel: 'Low Reso',
|
|
1424
|
+
pidLow: 0x003a, pidHigh: 0x0022,
|
|
1425
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1426
|
+
},
|
|
1427
|
+
'amp.master_vol_cap': {
|
|
1428
|
+
block: 'amp', name: 'master_vol_cap',
|
|
1429
|
+
displayLabel: 'Master Vol Cap',
|
|
1430
|
+
pidLow: 0x003a, pidHigh: 0x0026,
|
|
1431
|
+
// Cache typecode=72 → log10 storage (sibling to amp.bright_cap at
|
|
1432
|
+
// id=20). Capacitance scaling in pF.
|
|
1433
|
+
unit: 'pf', displayMin: 1, displayMax: 1000,
|
|
1434
|
+
scaling: 'log10',
|
|
1435
|
+
},
|
|
1436
|
+
'amp.hi_reso': {
|
|
1437
|
+
block: 'amp', name: 'hi_reso',
|
|
1438
|
+
displayLabel: 'Hi Reso',
|
|
1439
|
+
pidLow: 0x003a, pidHigh: 0x0033,
|
|
1440
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1441
|
+
},
|
|
1442
|
+
'amp.spkr_drive': {
|
|
1443
|
+
block: 'amp', name: 'spkr_drive',
|
|
1444
|
+
displayLabel: 'Drive',
|
|
1445
|
+
pidLow: 0x003a, pidHigh: 0x0039,
|
|
1446
|
+
// Speaker-stage drive knob (catalog: DISTORT_SPKRDRIVE). Renamed
|
|
1447
|
+
// from the resolver's bare 'drive' to disambiguate against
|
|
1448
|
+
// drive.drive in the separate Drive block.
|
|
1449
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1450
|
+
},
|
|
1451
|
+
'amp.input_eq_frequency': {
|
|
1452
|
+
block: 'amp', name: 'input_eq_frequency',
|
|
1453
|
+
displayLabel: 'Frequency',
|
|
1454
|
+
pidLow: 0x003a, pidHigh: 0x004f,
|
|
1455
|
+
// Input-EQ peaking frequency. Renamed from the resolver's bare
|
|
1456
|
+
// 'frequency' to mirror the existing input_eq_q / input_eq_gain /
|
|
1457
|
+
// input_eq_low_cut family on the same UI page.
|
|
1458
|
+
unit: 'hz', displayMin: 100, displayMax: 10000,
|
|
1459
|
+
},
|
|
1460
|
+
'amp.overdrive': {
|
|
1461
|
+
block: 'amp', name: 'overdrive',
|
|
1462
|
+
displayLabel: 'Normal Gain',
|
|
1463
|
+
pidLow: 0x003a, pidHigh: 0x0051,
|
|
1464
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1465
|
+
},
|
|
1466
|
+
'amp.definition': {
|
|
1467
|
+
block: 'amp', name: 'definition',
|
|
1468
|
+
displayLabel: 'Definition',
|
|
1469
|
+
pidLow: 0x003a, pidHigh: 0x0056,
|
|
1470
|
+
// Cache c=31.62299 (≈10/√10) → bipolar power-amp definition knob
|
|
1471
|
+
// displayed -10..+10 on the front panel. Uses 'count' rather than
|
|
1472
|
+
// bipolar_percent because front panel reads -10.0..+10.0, not ±100%.
|
|
1473
|
+
unit: 'count', displayMin: -10, displayMax: 10,
|
|
1474
|
+
},
|
|
1475
|
+
'amp.compression': {
|
|
1476
|
+
block: 'amp', name: 'compression',
|
|
1477
|
+
displayLabel: 'Compression',
|
|
1478
|
+
pidLow: 0x003a, pidHigh: 0x0057,
|
|
1479
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1480
|
+
},
|
|
1481
|
+
'amp.high_cut': {
|
|
1482
|
+
block: 'amp', name: 'high_cut',
|
|
1483
|
+
displayLabel: 'High Cut',
|
|
1484
|
+
pidLow: 0x003a, pidHigh: 0x005a,
|
|
1485
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
1486
|
+
},
|
|
1487
|
+
'amp.cathode_resistance': {
|
|
1488
|
+
block: 'amp', name: 'cathode_resistance',
|
|
1489
|
+
displayLabel: 'Cathode Resistance',
|
|
1490
|
+
pidLow: 0x003a, pidHigh: 0x0064,
|
|
1491
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1492
|
+
},
|
|
1493
|
+
'amp.b_plus_monitor': {
|
|
1494
|
+
block: 'amp', name: 'b_plus_monitor',
|
|
1495
|
+
displayLabel: 'B+',
|
|
1496
|
+
pidLow: 0x003a, pidHigh: 0x007d,
|
|
1497
|
+
// Read-only B+ voltage monitor (front-panel meter, not a knob).
|
|
1498
|
+
// Cache type=0 a=0 b=1 c=1 → raw 0..1 float; display as count.
|
|
1499
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
1500
|
+
},
|
|
1501
|
+
'amp.gain_monitor': {
|
|
1502
|
+
block: 'amp', name: 'gain_monitor',
|
|
1503
|
+
displayLabel: 'Gain',
|
|
1504
|
+
pidLow: 0x003a, pidHigh: 0x007e,
|
|
1505
|
+
// Read-only gain monitor. Sibling to b_plus_monitor / headroom_monitor.
|
|
1506
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
1507
|
+
},
|
|
1508
|
+
'amp.headroom_monitor': {
|
|
1509
|
+
block: 'amp', name: 'headroom_monitor',
|
|
1510
|
+
displayLabel: 'HEADROOM',
|
|
1511
|
+
pidLow: 0x003a, pidHigh: 0x0089,
|
|
1512
|
+
// Read-only plate-voltage headroom monitor.
|
|
1513
|
+
unit: 'count', displayMin: 0, displayMax: 1,
|
|
1514
|
+
},
|
|
1515
|
+
'amp.presence_prepresence': {
|
|
1516
|
+
block: 'amp', name: 'presence_prepresence',
|
|
1517
|
+
displayLabel: 'Treble',
|
|
1518
|
+
pidLow: 0x003a, pidHigh: 0x008a,
|
|
1519
|
+
// Preamp-stage presence shaper. AM4-Edit XML labels this "Treble"
|
|
1520
|
+
// on some amps; catalog name is DISTORT_PREPRESENCE. Name keeps
|
|
1521
|
+
// the resolver's dedupe suffix since amp.presence (id=30) is the
|
|
1522
|
+
// post-amp presence knob.
|
|
1523
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1524
|
+
},
|
|
1525
|
+
'amp.pa_high_cut': {
|
|
1526
|
+
block: 'amp', name: 'pa_high_cut',
|
|
1527
|
+
displayLabel: 'Tone',
|
|
1528
|
+
pidLow: 0x003a, pidHigh: 0x008c,
|
|
1529
|
+
// Power-amp high-cut shaper. AM4-Edit labels "Tone" but catalog
|
|
1530
|
+
// is DISTORT_PAHICUT; renamed from resolver's 'high_cut_pahicut'
|
|
1531
|
+
// to surface the family (pa_ prefix mirrors the rest of the
|
|
1532
|
+
// power-amp stage knobs).
|
|
1533
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1534
|
+
},
|
|
1535
|
+
'amp.overdrive_volume': {
|
|
1536
|
+
block: 'amp', name: 'overdrive_volume',
|
|
1537
|
+
displayLabel: 'Overdrive Volume',
|
|
1538
|
+
pidLow: 0x003a, pidHigh: 0x0091,
|
|
1539
|
+
// Global post-amp master that scales after the cab sim.
|
|
1540
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1541
|
+
},
|
|
1542
|
+
'drive.drive': {
|
|
1543
|
+
block: 'drive', name: 'drive',
|
|
1544
|
+
displayLabel: 'Gain',
|
|
1545
|
+
pidLow: 0x0076, pidHigh: 0x000b,
|
|
1546
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1547
|
+
},
|
|
1548
|
+
// P1-010 Session B (2026-04-20) — AM4 Owner's Manual line 1330:
|
|
1549
|
+
// "Page Right and dial in Drive, Tone, and Level." Cache records
|
|
1550
|
+
// at 0x0C/0x0D/0x0E have canonical pedal-layout signatures.
|
|
1551
|
+
// HW-014 verified: address + value land correctly on Klone Chiron.
|
|
1552
|
+
// Note: AM4 hardware display labels these registers per drive
|
|
1553
|
+
// model (Klone Chiron shows `tone`→"Treble" and `level`→"Output",
|
|
1554
|
+
// matching the real Klon Centaur). The underlying register is
|
|
1555
|
+
// unchanged across drive types.
|
|
1556
|
+
'drive.tone': {
|
|
1557
|
+
block: 'drive', name: 'tone',
|
|
1558
|
+
displayLabel: 'Bass',
|
|
1559
|
+
pidLow: 0x0076, pidHigh: 0x000c,
|
|
1560
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1561
|
+
},
|
|
1562
|
+
'drive.level': {
|
|
1563
|
+
block: 'drive', name: 'level',
|
|
1564
|
+
displayLabel: 'Mid',
|
|
1565
|
+
pidLow: 0x0076, pidHigh: 0x000d,
|
|
1566
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1567
|
+
},
|
|
1568
|
+
'drive.mix': {
|
|
1569
|
+
block: 'drive', name: 'mix',
|
|
1570
|
+
displayLabel: 'Tone',
|
|
1571
|
+
pidLow: 0x0076, pidHigh: 0x000e,
|
|
1572
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1573
|
+
},
|
|
1574
|
+
// HW-019 (Session 30, 2026-04-25): Drive EQ-page knobs from
|
|
1575
|
+
// session-30-drive-basic-blackglass-7k. T808 OD only exposed
|
|
1576
|
+
// Drive/Tone/Level on its first page (session-30-drive-basic-t808-od
|
|
1577
|
+
// capture confirmed) — the EQ controls below are absent on simpler
|
|
1578
|
+
// pedal types and only surface on amp-emu drive types like
|
|
1579
|
+
// Blackglass 7K. Cache signatures pin the unit + range; sequence in
|
|
1580
|
+
// the cache (id 16/17 = Low/High Cut Hz, id 20/21/23 = Bass/Mid/
|
|
1581
|
+
// Treble knobs flanking id 22 = Mid Frequency) matches the AM4-Edit
|
|
1582
|
+
// EQ-1-page layout. Captured wiggle order on Blackglass differed
|
|
1583
|
+
// from the spec order; mapping is by cache-id sequence + signature
|
|
1584
|
+
// not capture order.
|
|
1585
|
+
'drive.low_cut': {
|
|
1586
|
+
block: 'drive', name: 'low_cut',
|
|
1587
|
+
displayLabel: 'Low Cut',
|
|
1588
|
+
pidLow: 0x0076, pidHigh: 0x0010,
|
|
1589
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
1590
|
+
},
|
|
1591
|
+
'drive.bass': {
|
|
1592
|
+
block: 'drive', name: 'bass',
|
|
1593
|
+
displayLabel: 'Bright Cap',
|
|
1594
|
+
pidLow: 0x0076, pidHigh: 0x0014,
|
|
1595
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1596
|
+
},
|
|
1597
|
+
'drive.mid': {
|
|
1598
|
+
block: 'drive', name: 'mid',
|
|
1599
|
+
pidLow: 0x0076, pidHigh: 0x0015,
|
|
1600
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1601
|
+
},
|
|
1602
|
+
'drive.mid_freq': {
|
|
1603
|
+
block: 'drive', name: 'mid_freq',
|
|
1604
|
+
displayLabel: 'XFormer Low Freq',
|
|
1605
|
+
pidLow: 0x0076, pidHigh: 0x0016,
|
|
1606
|
+
unit: 'hz', displayMin: 200, displayMax: 2000,
|
|
1607
|
+
},
|
|
1608
|
+
'drive.treble': {
|
|
1609
|
+
block: 'drive', name: 'treble',
|
|
1610
|
+
displayLabel: 'XFormer Hi Freq',
|
|
1611
|
+
pidLow: 0x0076, pidHigh: 0x0017,
|
|
1612
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1613
|
+
},
|
|
1614
|
+
'drive.channel': {
|
|
1615
|
+
block: 'drive', name: 'channel',
|
|
1616
|
+
pidLow: 0x0076, pidHigh: 0x07d2,
|
|
1617
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
1618
|
+
enumValues: { 0: 'A', 1: 'B', 2: 'C', 3: 'D' },
|
|
1619
|
+
},
|
|
1620
|
+
// HW-029 + HW-039 (Session 35, 2026-04-29): Blackglass 7K Drive
|
|
1621
|
+
// Expert-Edit page from session-31-drive-expert.pcapng + paired
|
|
1622
|
+
// AM4-Edit screenshot. 6 single-knob params + 10 GEQ bands + 1
|
|
1623
|
+
// type-specific knob (high_mid for Blackglass, may surface under
|
|
1624
|
+
// a different label on other types).
|
|
1625
|
+
//
|
|
1626
|
+
// Mirrored from CACHE_PARAMS so the type-check picks them up.
|
|
1627
|
+
'drive.high_cut': {
|
|
1628
|
+
block: 'drive', name: 'high_cut',
|
|
1629
|
+
displayLabel: 'High Cut Frequency',
|
|
1630
|
+
pidLow: 0x0076, pidHigh: 0x0011,
|
|
1631
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
1632
|
+
},
|
|
1633
|
+
'drive.bypass_mode': {
|
|
1634
|
+
block: 'drive', name: 'bypass_mode',
|
|
1635
|
+
pidLow: 0x0076, pidHigh: 0x0004,
|
|
1636
|
+
// Cache id=4: enum [Thru / Mute]. Hand-authored per-block non-Type
|
|
1637
|
+
// enum (gen-params skips these).
|
|
1638
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
1639
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
1640
|
+
},
|
|
1641
|
+
'drive.clip_type': {
|
|
1642
|
+
block: 'drive', name: 'clip_type',
|
|
1643
|
+
displayLabel: 'Frequency',
|
|
1644
|
+
pidLow: 0x0076, pidHigh: 0x0012,
|
|
1645
|
+
// Cache id=18: 14-entry enum. Hand-authored — generator only
|
|
1646
|
+
// attaches one enum import per block (used for `type` at id=10).
|
|
1647
|
+
unit: 'enum', displayMin: 0, displayMax: 13,
|
|
1648
|
+
enumValues: {
|
|
1649
|
+
0: 'LV TUBE', 1: 'HARD', 2: 'SOFT', 3: 'GERMANIUM', 4: 'FW RECT',
|
|
1650
|
+
5: 'HV TUBE', 6: 'SILICON', 7: '4558/DIODE', 8: 'LED', 9: 'FET',
|
|
1651
|
+
10: 'OP-AMP', 11: 'VARIABLE', 12: 'CMOS', 13: 'NULL',
|
|
1652
|
+
},
|
|
1653
|
+
},
|
|
1654
|
+
'drive.bit_reduce': {
|
|
1655
|
+
block: 'drive', name: 'bit_reduce',
|
|
1656
|
+
displayLabel: 'Location',
|
|
1657
|
+
pidLow: 0x0076, pidHigh: 0x0018,
|
|
1658
|
+
unit: 'count', displayMin: 0, displayMax: 24,
|
|
1659
|
+
},
|
|
1660
|
+
'drive.input_select': {
|
|
1661
|
+
block: 'drive', name: 'input_select',
|
|
1662
|
+
displayLabel: 'Amp Input Select',
|
|
1663
|
+
pidLow: 0x0076, pidHigh: 0x0019,
|
|
1664
|
+
// Cache id=25: enum [L+R / LEFT / RIGHT].
|
|
1665
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
1666
|
+
enumValues: { 0: 'L+R', 1: 'LEFT', 2: 'RIGHT' },
|
|
1667
|
+
},
|
|
1668
|
+
'drive.eq_position': {
|
|
1669
|
+
block: 'drive', name: 'eq_position',
|
|
1670
|
+
pidLow: 0x0076, pidHigh: 0x001c,
|
|
1671
|
+
// Cache id=28: enum [OFF / POST / PRE]. Selects whether the post-
|
|
1672
|
+
// Drive Graphic EQ is bypassed, post-drive, or pre-drive.
|
|
1673
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
1674
|
+
enumValues: { 0: 'OFF', 1: 'POST', 2: 'PRE' },
|
|
1675
|
+
},
|
|
1676
|
+
// HW-043 partial (Session 45, 2026-05-02) — Drive Expert-Edit ADVANCED
|
|
1677
|
+
// panel knobs from `session-45-drive-expert-blackglass.{pcapng,png}`.
|
|
1678
|
+
// Slew Rate is universal (also active on Pi Fuzz at wire 0.21044).
|
|
1679
|
+
// Bias is Blackglass-only (silent in Pi Fuzz capture) — type-conditional
|
|
1680
|
+
// UI but firmware-stable address. See docs/audit-output/drive-blackglass.md.
|
|
1681
|
+
// Note: drive.balance is currently registered at 0x0002 but Session 45
|
|
1682
|
+
// captures show actual Balance is at 0x000f (hdr2=0x0002 bipolar
|
|
1683
|
+
// signature). Re-point deferred until 0x0002's actual identity is
|
|
1684
|
+
// confirmed — see open follow-ups in session-44-findings.md.
|
|
1685
|
+
'drive.slew_rate': {
|
|
1686
|
+
block: 'drive', name: 'slew_rate',
|
|
1687
|
+
displayLabel: 'Depth',
|
|
1688
|
+
pidLow: 0x0076, pidHigh: 0x001a,
|
|
1689
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1690
|
+
},
|
|
1691
|
+
'drive.bias': {
|
|
1692
|
+
block: 'drive', name: 'bias',
|
|
1693
|
+
pidLow: 0x0076, pidHigh: 0x001b,
|
|
1694
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1695
|
+
},
|
|
1696
|
+
// 10-band Graphic EQ — frequencies 100/160/250/400/640/1000/1600/
|
|
1697
|
+
// 2500/4000/6400 Hz, each ±12 dB. Wire-display match exact across
|
|
1698
|
+
// all 10 bands.
|
|
1699
|
+
'drive.geq_band_1': { block: 'drive', name: 'geq_band_1', displayLabel: 'Supply Sag', pidLow: 0x0076, pidHigh: 0x001d, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1700
|
+
'drive.geq_band_2': { block: 'drive', name: 'geq_band_2', displayLabel: 'Presence', pidLow: 0x0076, pidHigh: 0x001e, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1701
|
+
'drive.geq_band_3': { block: 'drive', name: 'geq_band_3', displayLabel: 'Negative FB', pidLow: 0x0076, pidHigh: 0x001f, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1702
|
+
'drive.geq_band_4': { block: 'drive', name: 'geq_band_4', displayLabel: 'Presence Freq', pidLow: 0x0076, pidHigh: 0x0020, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1703
|
+
'drive.geq_band_5': { block: 'drive', name: 'geq_band_5', displayLabel: 'Low Freq', pidLow: 0x0076, pidHigh: 0x0021, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1704
|
+
'drive.geq_band_6': { block: 'drive', name: 'geq_band_6', displayLabel: 'Low Reso', pidLow: 0x0076, pidHigh: 0x0022, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1705
|
+
'drive.geq_band_7': { block: 'drive', name: 'geq_band_7', displayLabel: 'Amp Section', pidLow: 0x0076, pidHigh: 0x0023, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1706
|
+
'drive.geq_band_8': { block: 'drive', name: 'geq_band_8', displayLabel: 'Depth Freq', pidLow: 0x0076, pidHigh: 0x0024, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1707
|
+
'drive.geq_band_9': { block: 'drive', name: 'geq_band_9', pidLow: 0x0076, pidHigh: 0x0025, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1708
|
+
'drive.geq_band_10': { block: 'drive', name: 'geq_band_10', displayLabel: 'Master Vol Cap', pidLow: 0x0076, pidHigh: 0x0026, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
1709
|
+
'drive.high_mid': {
|
|
1710
|
+
block: 'drive', name: 'high_mid',
|
|
1711
|
+
pidLow: 0x0076, pidHigh: 0x002d,
|
|
1712
|
+
// Cache id=45: knob_0_10. Closes HW-029 — wiggle-order adjacency
|
|
1713
|
+
// pins this between drive.mid_freq (id=22) and drive.treble (id=23)
|
|
1714
|
+
// in the BASIC column on Blackglass 7K. Type-specific UI label
|
|
1715
|
+
// varies; the register name reflects the Blackglass usage.
|
|
1716
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1717
|
+
},
|
|
1718
|
+
'drive.type': {
|
|
1719
|
+
block: 'drive', name: 'type',
|
|
1720
|
+
pidLow: 0x0076, pidHigh: 0x000a,
|
|
1721
|
+
// Session 06 capture set drive type with wire-value 8; cache lists
|
|
1722
|
+
// index 8 as "T808 Mod" (Fractal's internal label for the TS808
|
|
1723
|
+
// variant AM4-Edit surfaces as "TS808"). Full 78-entry table from
|
|
1724
|
+
// cache lines up 1:1 with AM4-Edit's Drive Type dropdown order.
|
|
1725
|
+
unit: 'enum', displayMin: 0, displayMax: 77,
|
|
1726
|
+
enumValues: DRIVE_TYPES_VALUES,
|
|
1727
|
+
},
|
|
1728
|
+
'reverb.mix': {
|
|
1729
|
+
block: 'reverb', name: 'mix',
|
|
1730
|
+
pidLow: 0x0042, pidHigh: 0x0001,
|
|
1731
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1732
|
+
},
|
|
1733
|
+
'reverb.time': {
|
|
1734
|
+
// Blocks Guide §Reverb Basic Page: decay time, 0.1..100 seconds.
|
|
1735
|
+
// Uses 'seconds' unit (display = internal, scale 1).
|
|
1736
|
+
block: 'reverb', name: 'time',
|
|
1737
|
+
displayLabel: 'Time',
|
|
1738
|
+
pidLow: 0x0042, pidHigh: 0x000b,
|
|
1739
|
+
unit: 'seconds', displayMin: 0.1, displayMax: 100,
|
|
1740
|
+
},
|
|
1741
|
+
// renamed for UI-label match (audit row: REVERB 19)
|
|
1742
|
+
'reverb.pre_delay': {
|
|
1743
|
+
// BK-033 fix (HW-025 #1, Session 30): true address is pidHigh=0x0013,
|
|
1744
|
+
// not 0x0010. AM4-Edit capture for Pre-Delay→85 ms wrote 0x0042/0x0013
|
|
1745
|
+
// with float32(0.085) — confirms the `ms` unit's ÷1000 scale is right.
|
|
1746
|
+
// The 0x0010 register was a cache-derived guess that was structurally
|
|
1747
|
+
// plausible (range matched) but wrote to nothing. See SYSEX-MAP §6j.
|
|
1748
|
+
block: 'reverb', name: 'pre_delay',
|
|
1749
|
+
displayLabel: 'Pre-Delay',
|
|
1750
|
+
pidLow: 0x0042, pidHigh: 0x0013,
|
|
1751
|
+
unit: 'ms', displayMin: 0, displayMax: 250,
|
|
1752
|
+
},
|
|
1753
|
+
// Session 29 (HW-015): reverb Size at pidHigh=0x000f. Wire-verified
|
|
1754
|
+
// on two captures ("Plate Size" on Plate reverb + "Size" on Room
|
|
1755
|
+
// reverb) — same register, type-dependent UI label. Percent scale.
|
|
1756
|
+
'reverb.size': {
|
|
1757
|
+
block: 'reverb', name: 'size',
|
|
1758
|
+
displayLabel: 'Size',
|
|
1759
|
+
pidLow: 0x0042, pidHigh: 0x000f,
|
|
1760
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1761
|
+
},
|
|
1762
|
+
// Session 29 (HW-015): spring-reverb-specific params. Registers are
|
|
1763
|
+
// writable on any reverb type; AM4-Edit exposes the UI only when
|
|
1764
|
+
// a Spring reverb is active. HW-024 (Session 30 cont 3) wire-verified
|
|
1765
|
+
// both on Spring, Large reverb (springs=5 displayed exactly; spring_tone
|
|
1766
|
+
// 7.30 displayed exactly) — first-ever hardware test of these params.
|
|
1767
|
+
'reverb.springs': {
|
|
1768
|
+
block: 'reverb', name: 'springs',
|
|
1769
|
+
displayLabel: '# of Springs',
|
|
1770
|
+
pidLow: 0x0042, pidHigh: 0x001b,
|
|
1771
|
+
unit: 'count', displayMin: 2, displayMax: 6,
|
|
1772
|
+
},
|
|
1773
|
+
'reverb.spring_tone': {
|
|
1774
|
+
block: 'reverb', name: 'spring_tone',
|
|
1775
|
+
displayLabel: 'Tone',
|
|
1776
|
+
pidLow: 0x0042, pidHigh: 0x001c,
|
|
1777
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
1778
|
+
},
|
|
1779
|
+
// Session 29 follow-up: Shimmer Verb / Plex Verb pitch-shifter
|
|
1780
|
+
// voices. Blocks Guide §Shimmer Verb Parameters describes "Shift
|
|
1781
|
+
// 1–8" as detune amounts within ±24 semitones ("this is where
|
|
1782
|
+
// 'Shimmer' is born"). AM4's reverb exposes two such voices at
|
|
1783
|
+
// cache ids 56/57 — structural registration (cache signature
|
|
1784
|
+
// matches BG exactly: a=-24, b=24, c=1, step=1). HW-014 couldn't
|
|
1785
|
+
// verify on hardware display (both shifts hidden on the Plate
|
|
1786
|
+
// reverb type tested); awaits a Shimmer-type hardware spot-check
|
|
1787
|
+
// or AM4-Edit-side verification.
|
|
1788
|
+
// HW-018 (Session 30, 2026-04-25): 10 new universal/algorithmic-reverb
|
|
1789
|
+
// and Spring-specific knobs decoded from session-30-reverb-basic-hall
|
|
1790
|
+
// and session-30-reverb-spring captures. Cache metadata confirmed
|
|
1791
|
+
// pidLow/pidHigh/range for each; capture final values cross-checked
|
|
1792
|
+
// against the founder's AM4-Edit screenshot inventory. Hall + Spring
|
|
1793
|
+
// share the universal registers (high_cut / low_cut / input_gain /
|
|
1794
|
+
// ducking) while Hall-only adds algorithmic controls (density / quality
|
|
1795
|
+
// / stack_hold / stereo_spread) and Spring-only adds Spring-engine
|
|
1796
|
+
// controls (dwell / drip).
|
|
1797
|
+
'reverb.high_cut': {
|
|
1798
|
+
block: 'reverb', name: 'high_cut',
|
|
1799
|
+
displayLabel: 'High Cut',
|
|
1800
|
+
pidLow: 0x0042, pidHigh: 0x000c,
|
|
1801
|
+
// Cache: a=200, b=20000, c=1 → raw Hz, 200..20000 Hz. Hall capture
|
|
1802
|
+
// wrote 7000 Hz directly (numeric input field, action=0x0001).
|
|
1803
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
1804
|
+
},
|
|
1805
|
+
'reverb.low_cut': {
|
|
1806
|
+
block: 'reverb', name: 'low_cut',
|
|
1807
|
+
displayLabel: 'Low Cut',
|
|
1808
|
+
pidLow: 0x0042, pidHigh: 0x0014,
|
|
1809
|
+
// Cache: a=20, b=2000, c=1 → raw Hz, 20..2000 Hz.
|
|
1810
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
1811
|
+
},
|
|
1812
|
+
'reverb.input_gain': {
|
|
1813
|
+
block: 'reverb', name: 'input_gain',
|
|
1814
|
+
displayLabel: 'Input Gain',
|
|
1815
|
+
pidLow: 0x0042, pidHigh: 0x0017,
|
|
1816
|
+
// Cache: a=0, b=1, c=100 → percent 0..100. Spring final 0.8217 →
|
|
1817
|
+
// 82.17% matches the AM4-Edit screenshot's "Input Gain 82.2 %".
|
|
1818
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1819
|
+
},
|
|
1820
|
+
'reverb.density': {
|
|
1821
|
+
block: 'reverb', name: 'density',
|
|
1822
|
+
displayLabel: 'Density',
|
|
1823
|
+
pidLow: 0x0042, pidHigh: 0x0018,
|
|
1824
|
+
// Cache: a=4, b=8, c=1, kind=float typecode=16 → integer count
|
|
1825
|
+
// 4..8. Hall-only (algorithmic Hall/Plate/Room knob).
|
|
1826
|
+
unit: 'count', displayMin: 4, displayMax: 8,
|
|
1827
|
+
},
|
|
1828
|
+
'reverb.dwell': {
|
|
1829
|
+
block: 'reverb', name: 'dwell',
|
|
1830
|
+
displayLabel: 'Dwell',
|
|
1831
|
+
pidLow: 0x0042, pidHigh: 0x0024,
|
|
1832
|
+
// Cache: a=0.01, b=1, c=10 → knob_0_10 (display = wire × 10).
|
|
1833
|
+
// Spring final 0.4741 → 4.741 matches screenshot "Dwell 4.74".
|
|
1834
|
+
// Spring-engine specific (alongside spring_tone, drip).
|
|
1835
|
+
unit: 'knob_0_10', displayMin: 0.1, displayMax: 10,
|
|
1836
|
+
// typecode 80 = log10 (HW-053b cont audit)
|
|
1837
|
+
scaling: 'log10',
|
|
1838
|
+
},
|
|
1839
|
+
'reverb.stereo_spread': {
|
|
1840
|
+
block: 'reverb', name: 'stereo_spread',
|
|
1841
|
+
displayLabel: 'Stereo Spread',
|
|
1842
|
+
pidLow: 0x0042, pidHigh: 0x0027,
|
|
1843
|
+
// Cache: a=-2, b=2, c=100 → bipolar_percent allowing -200..+200%.
|
|
1844
|
+
// AM4-Edit screenshot shows Hall Stereo Spread as a positive 0..100%
|
|
1845
|
+
// knob (display value 90.0 %). Cache exposes the wider firmware
|
|
1846
|
+
// range — leave displayMin/displayMax at the cache values; Claude
|
|
1847
|
+
// can clamp to the typical 0..100 range when describing the knob.
|
|
1848
|
+
unit: 'bipolar_percent', displayMin: -200, displayMax: 200,
|
|
1849
|
+
},
|
|
1850
|
+
'reverb.ducking': {
|
|
1851
|
+
block: 'reverb', name: 'ducking',
|
|
1852
|
+
displayLabel: 'Ducking',
|
|
1853
|
+
pidLow: 0x0042, pidHigh: 0x0028,
|
|
1854
|
+
// Cache: a=0, b=80, c=1 → raw dB, 0..80 dB attenuation. Universal
|
|
1855
|
+
// (Hall + Spring both wrote here). Screenshot shows "Ducking 46.9 dB"
|
|
1856
|
+
// on both reverb types — typical mid-range attenuation.
|
|
1857
|
+
unit: 'db', displayMin: 0, displayMax: 80,
|
|
1858
|
+
},
|
|
1859
|
+
'reverb.quality': {
|
|
1860
|
+
block: 'reverb', name: 'quality',
|
|
1861
|
+
displayLabel: 'Quality',
|
|
1862
|
+
pidLow: 0x0042, pidHigh: 0x002f,
|
|
1863
|
+
// Cache: enum, values=["ECONOMY","NORMAL","HIGH","ULTRA-HIGH"].
|
|
1864
|
+
// Hall-only (algorithmic CPU-quality selector). Hand-authored enum
|
|
1865
|
+
// map; not yet exported via cacheEnums.ts since cacheEnums is
|
|
1866
|
+
// auto-generated from a different cache section. If a regen pass
|
|
1867
|
+
// adds REVERB_QUALITY_VALUES later, swap this inline map for the
|
|
1868
|
+
// import.
|
|
1869
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
1870
|
+
enumValues: { 0: 'ECONOMY', 1: 'NORMAL', 2: 'HIGH', 3: 'ULTRA-HIGH' },
|
|
1871
|
+
},
|
|
1872
|
+
'reverb.stack_hold': {
|
|
1873
|
+
block: 'reverb', name: 'stack_hold',
|
|
1874
|
+
displayLabel: 'Stack/Hold',
|
|
1875
|
+
pidLow: 0x0042, pidHigh: 0x0030,
|
|
1876
|
+
// Cache: enum, values=["OFF","STACK","HOLD"]. Hall-only. Same
|
|
1877
|
+
// hand-authored caveat as reverb.quality.
|
|
1878
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
1879
|
+
enumValues: { 0: 'OFF', 1: 'STACK', 2: 'HOLD' },
|
|
1880
|
+
},
|
|
1881
|
+
'reverb.drip': {
|
|
1882
|
+
block: 'reverb', name: 'drip',
|
|
1883
|
+
displayLabel: 'Drip',
|
|
1884
|
+
pidLow: 0x0042, pidHigh: 0x0034,
|
|
1885
|
+
// Cache: a=0, b=1, c=100 → percent 0..100. Spring final 0.9183 →
|
|
1886
|
+
// 91.83% matches screenshot "Drip 91.8 %". Spring-engine specific.
|
|
1887
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1888
|
+
},
|
|
1889
|
+
// renamed for UI-label match (audit row: REVERB 56)
|
|
1890
|
+
'reverb.voice_1_shift': {
|
|
1891
|
+
block: 'reverb', name: 'voice_1_shift',
|
|
1892
|
+
displayLabel: 'Voice 1 Shift',
|
|
1893
|
+
pidLow: 0x0042, pidHigh: 0x0038,
|
|
1894
|
+
unit: 'semitones', displayMin: -24, displayMax: 24,
|
|
1895
|
+
},
|
|
1896
|
+
// renamed for UI-label match (audit row: REVERB 57)
|
|
1897
|
+
'reverb.voice_2_shift': {
|
|
1898
|
+
block: 'reverb', name: 'voice_2_shift',
|
|
1899
|
+
displayLabel: 'Voice 2 Shift',
|
|
1900
|
+
pidLow: 0x0042, pidHigh: 0x0039,
|
|
1901
|
+
unit: 'semitones', displayMin: -24, displayMax: 24,
|
|
1902
|
+
},
|
|
1903
|
+
'reverb.channel': {
|
|
1904
|
+
block: 'reverb', name: 'channel',
|
|
1905
|
+
pidLow: 0x0042, pidHigh: 0x07d2,
|
|
1906
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
1907
|
+
enumValues: { 0: 'A', 1: 'B', 2: 'C', 3: 'D' },
|
|
1908
|
+
},
|
|
1909
|
+
'reverb.type': {
|
|
1910
|
+
block: 'reverb', name: 'type',
|
|
1911
|
+
pidLow: 0x0042, pidHigh: 0x000a,
|
|
1912
|
+
// Session 16: enum dictionary imported from cacheEnums.ts (79 models).
|
|
1913
|
+
// Untested against capture.
|
|
1914
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
1915
|
+
enumValues: REVERB_TYPES_VALUES,
|
|
1916
|
+
},
|
|
1917
|
+
'delay.time': {
|
|
1918
|
+
block: 'delay', name: 'time',
|
|
1919
|
+
displayLabel: 'Time',
|
|
1920
|
+
pidLow: 0x0046, pidHigh: 0x000c,
|
|
1921
|
+
// Session 16: cache says `b=8` seconds → UI max 8000 ms (was 5000).
|
|
1922
|
+
unit: 'ms', displayMin: 0, displayMax: 8000,
|
|
1923
|
+
},
|
|
1924
|
+
'delay.mix': {
|
|
1925
|
+
// Blocks Guide: delay has Mix at pidHigh 0x01. "Note that the
|
|
1926
|
+
// delay block uses a different Mix Law compared to other blocks" —
|
|
1927
|
+
// semantics differ but the param is at the standard location.
|
|
1928
|
+
block: 'delay', name: 'mix',
|
|
1929
|
+
pidLow: 0x0046, pidHigh: 0x0001,
|
|
1930
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
1931
|
+
},
|
|
1932
|
+
// Session 29 (HW-015): Feedback knobs on per-block delay/flanger/phaser.
|
|
1933
|
+
// All bipolar — negative feedback inverts the phase of the repeats/
|
|
1934
|
+
// sweep, a standard Fractal implementation detail.
|
|
1935
|
+
'delay.feedback': {
|
|
1936
|
+
block: 'delay', name: 'feedback',
|
|
1937
|
+
displayLabel: 'Feedback',
|
|
1938
|
+
pidLow: 0x0046, pidHigh: 0x000e,
|
|
1939
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
1940
|
+
},
|
|
1941
|
+
// HW-020 (Session 30, 2026-04-25): Delay first-page registers from
|
|
1942
|
+
// session-30-delay-basic-digital-mono. `level` follows the universal
|
|
1943
|
+
// pidHigh=0x0000 "Level" pattern shared with amp.level (no cache
|
|
1944
|
+
// record at id=0; out-of-band hand-author). `stack_hold` and
|
|
1945
|
+
// `ducking` mirror the same registers found on Reverb (HW-018).
|
|
1946
|
+
// `tempo` (pidHigh=0x0013) is captured but deferred — registering
|
|
1947
|
+
// it requires extracting the 79-entry tempo-division enum from cache
|
|
1948
|
+
// (queued as HW-027 follow-up).
|
|
1949
|
+
'delay.level': {
|
|
1950
|
+
block: 'delay', name: 'level',
|
|
1951
|
+
pidLow: 0x0046, pidHigh: 0x0000,
|
|
1952
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
1953
|
+
},
|
|
1954
|
+
// HW-040 (Session 36, 2026-04-29): Delay Expert-Edit page from
|
|
1955
|
+
// session-40-delay-expert.pcapng (Ambient Stereo). 32 new params
|
|
1956
|
+
// mirrored from CACHE_PARAMS + 7 hand-authored enums (bypass_mode,
|
|
1957
|
+
// kill_dry, lo_fi_drive, phase_reverse, low_cut_slope, high_cut_slope,
|
|
1958
|
+
// compander).
|
|
1959
|
+
'delay.bypass_mode': {
|
|
1960
|
+
block: 'delay', name: 'bypass_mode',
|
|
1961
|
+
pidLow: 0x0046, pidHigh: 0x0004,
|
|
1962
|
+
// Cache id=4 enum has 5 entries: [Thru, Mute FX Out, Mute Out,
|
|
1963
|
+
// Mute FX In, Mute In] — the cache extraction shows 4 visible
|
|
1964
|
+
// entries but the enum max is 4 (so 5 indices, 0..4).
|
|
1965
|
+
unit: 'enum', displayMin: 0, displayMax: 4,
|
|
1966
|
+
enumValues: { 0: 'Thru', 1: 'Mute FX Out', 2: 'Mute Out', 3: 'Mute FX In', 4: 'Mute In' },
|
|
1967
|
+
},
|
|
1968
|
+
'delay.kill_dry': {
|
|
1969
|
+
block: 'delay', name: 'kill_dry',
|
|
1970
|
+
pidLow: 0x0046, pidHigh: 0x0007,
|
|
1971
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
1972
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
1973
|
+
},
|
|
1974
|
+
'delay.lr_time_ratio': {
|
|
1975
|
+
block: 'delay', name: 'lr_time_ratio',
|
|
1976
|
+
displayLabel: 'L/R Time Ratio',
|
|
1977
|
+
pidLow: 0x0046, pidHigh: 0x000d,
|
|
1978
|
+
unit: 'percent', displayMin: 1, displayMax: 100,
|
|
1979
|
+
},
|
|
1980
|
+
'delay.feedback_r': {
|
|
1981
|
+
block: 'delay', name: 'feedback_r',
|
|
1982
|
+
displayLabel: 'Feedback R',
|
|
1983
|
+
pidLow: 0x0046, pidHigh: 0x0010,
|
|
1984
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
1985
|
+
},
|
|
1986
|
+
'delay.stereo_spread': {
|
|
1987
|
+
block: 'delay', name: 'stereo_spread',
|
|
1988
|
+
displayLabel: 'Stereo Spread',
|
|
1989
|
+
pidLow: 0x0046, pidHigh: 0x0012,
|
|
1990
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
1991
|
+
},
|
|
1992
|
+
'delay.low_cut': {
|
|
1993
|
+
block: 'delay', name: 'low_cut',
|
|
1994
|
+
displayLabel: 'Low Cut',
|
|
1995
|
+
pidLow: 0x0046, pidHigh: 0x0014,
|
|
1996
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
1997
|
+
},
|
|
1998
|
+
'delay.high_cut': {
|
|
1999
|
+
block: 'delay', name: 'high_cut',
|
|
2000
|
+
displayLabel: 'High Cut',
|
|
2001
|
+
pidLow: 0x0046, pidHigh: 0x0015,
|
|
2002
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
2003
|
+
},
|
|
2004
|
+
'delay.lo_fi_drive': {
|
|
2005
|
+
block: 'delay', name: 'lo_fi_drive',
|
|
2006
|
+
displayLabel: 'Drive',
|
|
2007
|
+
pidLow: 0x0046, pidHigh: 0x001a,
|
|
2008
|
+
// Cache id=26: float a=0.05 b=50 c=10 → display = wire × 10,
|
|
2009
|
+
// range 0.5..500. Same encoding shape as knob_0_10 (scale 10);
|
|
2010
|
+
// the unit name is structural, the bounds carry the actual range.
|
|
2011
|
+
unit: 'knob_0_10', displayMin: 0.5, displayMax: 500,
|
|
2012
|
+
// typecode 80 = log10 (HW-053b cont audit)
|
|
2013
|
+
scaling: 'log10',
|
|
2014
|
+
},
|
|
2015
|
+
'delay.input_gain': {
|
|
2016
|
+
block: 'delay', name: 'input_gain',
|
|
2017
|
+
displayLabel: 'Input Gain',
|
|
2018
|
+
pidLow: 0x0046, pidHigh: 0x001b,
|
|
2019
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2020
|
+
},
|
|
2021
|
+
'delay.master_feedback': {
|
|
2022
|
+
block: 'delay', name: 'master_feedback',
|
|
2023
|
+
displayLabel: 'Master Feedback',
|
|
2024
|
+
pidLow: 0x0046, pidHigh: 0x0020,
|
|
2025
|
+
// Cache id=32: a=0 b=2 c=100 → display 0..200%.
|
|
2026
|
+
unit: 'percent', displayMin: 0, displayMax: 200,
|
|
2027
|
+
},
|
|
2028
|
+
'delay.high_cut_slope': {
|
|
2029
|
+
block: 'delay', name: 'high_cut_slope',
|
|
2030
|
+
displayLabel: 'High Cut Slope',
|
|
2031
|
+
pidLow: 0x0046, pidHigh: 0x002d,
|
|
2032
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2033
|
+
enumValues: { 0: '6 dB/OCT', 1: '12 dB/OCT', 2: '24 dB/OCT', 3: '36 dB/OCT' },
|
|
2034
|
+
},
|
|
2035
|
+
'delay.ducker_threshold': {
|
|
2036
|
+
block: 'delay', name: 'ducker_threshold',
|
|
2037
|
+
displayLabel: 'Threshold',
|
|
2038
|
+
pidLow: 0x0046, pidHigh: 0x002f,
|
|
2039
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2040
|
+
},
|
|
2041
|
+
'delay.ducker_release': {
|
|
2042
|
+
block: 'delay', name: 'ducker_release',
|
|
2043
|
+
displayLabel: 'Release',
|
|
2044
|
+
pidLow: 0x0046, pidHigh: 0x0030,
|
|
2045
|
+
unit: 'ms', displayMin: 1, displayMax: 1000, scaling: 'log10',
|
|
2046
|
+
},
|
|
2047
|
+
// renamed for UI-label match (audit row: DELAY 49)
|
|
2048
|
+
'delay.diffuser': {
|
|
2049
|
+
block: 'delay', name: 'diffuser',
|
|
2050
|
+
displayLabel: 'Diffuser',
|
|
2051
|
+
pidLow: 0x0046, pidHigh: 0x0031,
|
|
2052
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2053
|
+
},
|
|
2054
|
+
'delay.diffusion_time': {
|
|
2055
|
+
block: 'delay', name: 'diffusion_time',
|
|
2056
|
+
displayLabel: 'Diffusion Time',
|
|
2057
|
+
pidLow: 0x0046, pidHigh: 0x0032,
|
|
2058
|
+
unit: 'percent', displayMin: 1, displayMax: 100,
|
|
2059
|
+
},
|
|
2060
|
+
'delay.phase_reverse': {
|
|
2061
|
+
block: 'delay', name: 'phase_reverse',
|
|
2062
|
+
displayLabel: 'Phase Reverse',
|
|
2063
|
+
pidLow: 0x0046, pidHigh: 0x0033,
|
|
2064
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2065
|
+
enumValues: { 0: 'NONE', 1: 'RIGHT', 2: 'LEFT', 3: 'BOTH' },
|
|
2066
|
+
},
|
|
2067
|
+
'delay.eq_q_high_low': {
|
|
2068
|
+
block: 'delay', name: 'eq_q_high_low',
|
|
2069
|
+
displayLabel: 'Q (High + Low)',
|
|
2070
|
+
pidLow: 0x0046, pidHigh: 0x003f,
|
|
2071
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
2072
|
+
},
|
|
2073
|
+
'delay.bit_reduction': {
|
|
2074
|
+
block: 'delay', name: 'bit_reduction',
|
|
2075
|
+
displayLabel: 'Bit Reduction',
|
|
2076
|
+
pidLow: 0x0046, pidHigh: 0x0040,
|
|
2077
|
+
unit: 'count', displayMin: 0, displayMax: 24,
|
|
2078
|
+
},
|
|
2079
|
+
'delay.eq_freq_1': {
|
|
2080
|
+
block: 'delay', name: 'eq_freq_1',
|
|
2081
|
+
displayLabel: 'Frequency 1',
|
|
2082
|
+
pidLow: 0x0046, pidHigh: 0x0041,
|
|
2083
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
2084
|
+
},
|
|
2085
|
+
'delay.eq_freq_2': {
|
|
2086
|
+
block: 'delay', name: 'eq_freq_2',
|
|
2087
|
+
displayLabel: 'Frequency 2',
|
|
2088
|
+
pidLow: 0x0046, pidHigh: 0x0042,
|
|
2089
|
+
unit: 'hz', displayMin: 100, displayMax: 10000,
|
|
2090
|
+
},
|
|
2091
|
+
'delay.eq_q_1': {
|
|
2092
|
+
block: 'delay', name: 'eq_q_1',
|
|
2093
|
+
displayLabel: 'Q 1',
|
|
2094
|
+
pidLow: 0x0046, pidHigh: 0x0043,
|
|
2095
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
2096
|
+
},
|
|
2097
|
+
'delay.eq_q_2': {
|
|
2098
|
+
block: 'delay', name: 'eq_q_2',
|
|
2099
|
+
displayLabel: 'Q 2',
|
|
2100
|
+
pidLow: 0x0046, pidHigh: 0x0044,
|
|
2101
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
2102
|
+
},
|
|
2103
|
+
'delay.eq_gain_1': {
|
|
2104
|
+
block: 'delay', name: 'eq_gain_1',
|
|
2105
|
+
displayLabel: 'Gain 1',
|
|
2106
|
+
pidLow: 0x0046, pidHigh: 0x0045,
|
|
2107
|
+
unit: 'db', displayMin: -12, displayMax: 12,
|
|
2108
|
+
},
|
|
2109
|
+
'delay.eq_gain_2': {
|
|
2110
|
+
block: 'delay', name: 'eq_gain_2',
|
|
2111
|
+
displayLabel: 'Gain 2',
|
|
2112
|
+
pidLow: 0x0046, pidHigh: 0x0046,
|
|
2113
|
+
unit: 'db', displayMin: -12, displayMax: 12,
|
|
2114
|
+
},
|
|
2115
|
+
'delay.low_cut_slope': {
|
|
2116
|
+
block: 'delay', name: 'low_cut_slope',
|
|
2117
|
+
displayLabel: 'Low Cut Slope',
|
|
2118
|
+
pidLow: 0x0046, pidHigh: 0x004a,
|
|
2119
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2120
|
+
enumValues: { 0: '6 dB/OCT', 1: '12 dB/OCT', 2: '24 dB/OCT', 3: '36 dB/OCT' },
|
|
2121
|
+
},
|
|
2122
|
+
'delay.compander': {
|
|
2123
|
+
block: 'delay', name: 'compander',
|
|
2124
|
+
displayLabel: 'Compander',
|
|
2125
|
+
pidLow: 0x0046, pidHigh: 0x004b,
|
|
2126
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
2127
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
2128
|
+
},
|
|
2129
|
+
'delay.compander_time': {
|
|
2130
|
+
block: 'delay', name: 'compander_time',
|
|
2131
|
+
displayLabel: 'Time',
|
|
2132
|
+
pidLow: 0x0046, pidHigh: 0x004c,
|
|
2133
|
+
unit: 'ms', displayMin: 1, displayMax: 100, scaling: 'log10',
|
|
2134
|
+
},
|
|
2135
|
+
'delay.compander_threshold': {
|
|
2136
|
+
block: 'delay', name: 'compander_threshold',
|
|
2137
|
+
displayLabel: 'Threshold',
|
|
2138
|
+
pidLow: 0x0046, pidHigh: 0x004d,
|
|
2139
|
+
unit: 'db', displayMin: -100, displayMax: -20,
|
|
2140
|
+
},
|
|
2141
|
+
'delay.master_time': {
|
|
2142
|
+
block: 'delay', name: 'master_time',
|
|
2143
|
+
displayLabel: 'Master Time',
|
|
2144
|
+
pidLow: 0x0046, pidHigh: 0x004e,
|
|
2145
|
+
unit: 'percent', displayMin: 25, displayMax: 400,
|
|
2146
|
+
},
|
|
2147
|
+
'delay.lfo_rate': {
|
|
2148
|
+
block: 'delay', name: 'lfo_rate',
|
|
2149
|
+
displayLabel: 'LFO Rate',
|
|
2150
|
+
pidLow: 0x0046, pidHigh: 0x004f,
|
|
2151
|
+
unit: 'hz', displayMin: 0.1, displayMax: 10,
|
|
2152
|
+
},
|
|
2153
|
+
'delay.lfo_depth': {
|
|
2154
|
+
block: 'delay', name: 'lfo_depth',
|
|
2155
|
+
displayLabel: 'LFO Depth',
|
|
2156
|
+
pidLow: 0x0046, pidHigh: 0x0050,
|
|
2157
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2158
|
+
},
|
|
2159
|
+
'delay.stack_feedback': {
|
|
2160
|
+
block: 'delay', name: 'stack_feedback',
|
|
2161
|
+
displayLabel: 'Stack Feedback',
|
|
2162
|
+
pidLow: 0x0046, pidHigh: 0x0057,
|
|
2163
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2164
|
+
},
|
|
2165
|
+
'delay.hold_feedback': {
|
|
2166
|
+
block: 'delay', name: 'hold_feedback',
|
|
2167
|
+
displayLabel: 'Hold Feedback',
|
|
2168
|
+
pidLow: 0x0046, pidHigh: 0x0058,
|
|
2169
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2170
|
+
},
|
|
2171
|
+
// renamed for UI-label match (audit row: DELAY 31)
|
|
2172
|
+
'delay.repeat_stack_hold': {
|
|
2173
|
+
block: 'delay', name: 'repeat_stack_hold',
|
|
2174
|
+
displayLabel: 'Repeat Stack/Hold',
|
|
2175
|
+
pidLow: 0x0046, pidHigh: 0x001f,
|
|
2176
|
+
// Cache id=31: enum [OFF|STACK|HOLD]. Hand-authored — generator
|
|
2177
|
+
// can't emit per-block non-Type enums (it would mis-import the
|
|
2178
|
+
// block's TYPES_VALUES instead of these three).
|
|
2179
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
2180
|
+
enumValues: { 0: 'OFF', 1: 'STACK', 2: 'HOLD' },
|
|
2181
|
+
},
|
|
2182
|
+
'delay.ducking': {
|
|
2183
|
+
block: 'delay', name: 'ducking',
|
|
2184
|
+
displayLabel: 'Ducking',
|
|
2185
|
+
pidLow: 0x0046, pidHigh: 0x002e,
|
|
2186
|
+
// Cache id=46: float a=0 b=80 c=1 → raw dB 0..80 attenuation.
|
|
2187
|
+
// Same signature as reverb.ducking (HW-018).
|
|
2188
|
+
unit: 'db', displayMin: 0, displayMax: 80,
|
|
2189
|
+
},
|
|
2190
|
+
// HW-027 (Session 30 cont 2, 2026-04-25): tempo-sync registers across
|
|
2191
|
+
// every modulation block. Cache contains 14 79-entry tempo enums (delay
|
|
2192
|
+
// × 6, chorus × 2, reverb / flanger / rotary / phaser / tremolo /
|
|
2193
|
+
// filter × 1 each) — all string-identical, sharing the
|
|
2194
|
+
// TEMPO_DIVISIONS_VALUES dictionary emitted by gen-cache-enums.ts.
|
|
2195
|
+
// The first/lowest-id tempo enum on each block is canonically the main
|
|
2196
|
+
// "Tempo Sync" knob per Blocks Guide §Common LFO Parameters. We
|
|
2197
|
+
// register the high-confidence ones below (delay = wire-verified;
|
|
2198
|
+
// chorus/flanger/phaser/tremolo = structural-by-symmetry, every
|
|
2199
|
+
// modulation block has a Tempo Sync knob). Filter / reverb / rotary
|
|
2200
|
+
// tempo registers deferred — semantics uncertain (auto-wah env follower
|
|
2201
|
+
// vs LFO sync; reverb-modulation tempo for Vibrato-King types only).
|
|
2202
|
+
// Hand-authored in KNOWN_PARAMS rather than via paramNames+generator
|
|
2203
|
+
// because the generator's enum-handling defaults to the block's
|
|
2204
|
+
// TYPES_VALUES, which would mis-import for these non-Type enums.
|
|
2205
|
+
'delay.tempo': {
|
|
2206
|
+
block: 'delay', name: 'tempo',
|
|
2207
|
+
displayLabel: 'Tempo',
|
|
2208
|
+
pidLow: 0x0046, pidHigh: 0x0013,
|
|
2209
|
+
// Wire-verified: session-30-delay-basic-digital-mono captured
|
|
2210
|
+
// value=11 (= "1/8" tempo division).
|
|
2211
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
2212
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
2213
|
+
},
|
|
2214
|
+
'chorus.tempo': {
|
|
2215
|
+
block: 'chorus', name: 'tempo',
|
|
2216
|
+
displayLabel: 'Tempo',
|
|
2217
|
+
pidLow: 0x004e, pidHigh: 0x000d,
|
|
2218
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
2219
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
2220
|
+
},
|
|
2221
|
+
'flanger.tempo': {
|
|
2222
|
+
block: 'flanger', name: 'tempo',
|
|
2223
|
+
displayLabel: 'Tempo',
|
|
2224
|
+
pidLow: 0x0052, pidHigh: 0x000c,
|
|
2225
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
2226
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
2227
|
+
},
|
|
2228
|
+
'phaser.tempo': {
|
|
2229
|
+
block: 'phaser', name: 'tempo',
|
|
2230
|
+
displayLabel: 'Tempo',
|
|
2231
|
+
pidLow: 0x005a, pidHigh: 0x000e,
|
|
2232
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
2233
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
2234
|
+
},
|
|
2235
|
+
'tremolo.tempo': {
|
|
2236
|
+
block: 'tremolo', name: 'tempo',
|
|
2237
|
+
displayLabel: 'Tempo',
|
|
2238
|
+
pidLow: 0x006a, pidHigh: 0x000f,
|
|
2239
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
2240
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
2241
|
+
},
|
|
2242
|
+
'delay.channel': {
|
|
2243
|
+
block: 'delay', name: 'channel',
|
|
2244
|
+
pidLow: 0x0046, pidHigh: 0x07d2,
|
|
2245
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2246
|
+
enumValues: { 0: 'A', 1: 'B', 2: 'C', 3: 'D' },
|
|
2247
|
+
},
|
|
2248
|
+
'delay.type': {
|
|
2249
|
+
block: 'delay', name: 'type',
|
|
2250
|
+
pidLow: 0x0046, pidHigh: 0x000a,
|
|
2251
|
+
// Session 16: enum dictionary imported from cacheEnums.ts (29 models).
|
|
2252
|
+
// Untested against capture.
|
|
2253
|
+
unit: 'enum', displayMin: 0, displayMax: 28,
|
|
2254
|
+
enumValues: DELAY_TYPES_VALUES,
|
|
2255
|
+
},
|
|
2256
|
+
// Session 18 — 6 additional block Type selectors, each pinned to wire
|
|
2257
|
+
// pidLow by a Tier-3 AM4-Edit capture of a Type-dropdown change. The
|
|
2258
|
+
// cache record id is the wire pidHigh (10 for the effect blocks, 19/20
|
|
2259
|
+
// for Comp/GEQ because their cache slot reserves ids 0..12 for band
|
|
2260
|
+
// levels / assign slots).
|
|
2261
|
+
// P1-010 Session B (2026-04-20) — universal Mix control per the
|
|
2262
|
+
// Blocks Guide §Common Mix/Level Parameters (p. 7). Every effect
|
|
2263
|
+
// block with a wet/dry concept exposes Mix at pidHigh 0x01 with the
|
|
2264
|
+
// same percent signature as the confirmed reverb.mix. Skipped for
|
|
2265
|
+
// Wah/GEQ/Gate/Volume-Pan (AM4 manual p. 34: "Effects with no mix,
|
|
2266
|
+
// such as Wah, GEQ, etc., will show 'NA'"). HW-014 partial: delay
|
|
2267
|
+
// / chorus / reverb mix verified correct; flanger.mix and
|
|
2268
|
+
// phaser.mix surfaced the BK-034 encoding bug (see entries below);
|
|
2269
|
+
// tremolo.mix / compressor.mix / filter.mix hidden on hardware
|
|
2270
|
+
// display (awaits AM4-Edit verification).
|
|
2271
|
+
// Modulation-block LFO rates + depths (Session 26 Unit-extension pass).
|
|
2272
|
+
// Rate uses the 'hz' unit (raw passthrough, c=1 in cache). Depth is a
|
|
2273
|
+
// standard percent knob. Blocks Guide §Chorus/Flanger/Phaser document
|
|
2274
|
+
// all three as Basic Page controls across these blocks.
|
|
2275
|
+
'chorus.mix': {
|
|
2276
|
+
block: 'chorus', name: 'mix',
|
|
2277
|
+
pidLow: 0x004e, pidHigh: 0x0001,
|
|
2278
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2279
|
+
},
|
|
2280
|
+
'chorus.type': {
|
|
2281
|
+
block: 'chorus', name: 'type',
|
|
2282
|
+
pidLow: 0x004e, pidHigh: 0x000a,
|
|
2283
|
+
unit: 'enum', displayMin: 0, displayMax: 19,
|
|
2284
|
+
enumValues: CHORUS_TYPES_VALUES,
|
|
2285
|
+
},
|
|
2286
|
+
'chorus.rate': {
|
|
2287
|
+
// BK-034 resolved (HW-025 #2, Session 30): NOT an encoding bug.
|
|
2288
|
+
// AM4-Edit wire for Rate→3.4 Hz wrote pidLow=0x004e/pidHigh=0x000c
|
|
2289
|
+
// with float32(3.4) — byte-identical to our `unit: 'hz'` builder.
|
|
2290
|
+
// HW-014's hardware-display readback (3.4→0.5 Hz) is an AM4
|
|
2291
|
+
// hardware-screen rendering quirk for chorus rate, not a wire-
|
|
2292
|
+
// layer bug. Verify chorus rate via AM4-Edit, not the AM4 hardware
|
|
2293
|
+
// display, until the screen-side rendering is characterised.
|
|
2294
|
+
block: 'chorus', name: 'rate',
|
|
2295
|
+
displayLabel: 'Rate',
|
|
2296
|
+
pidLow: 0x004e, pidHigh: 0x000c,
|
|
2297
|
+
unit: 'hz', displayMin: 0.1, displayMax: 10,
|
|
2298
|
+
},
|
|
2299
|
+
'chorus.depth': {
|
|
2300
|
+
block: 'chorus', name: 'depth',
|
|
2301
|
+
displayLabel: 'Depth',
|
|
2302
|
+
pidLow: 0x004e, pidHigh: 0x000e,
|
|
2303
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2304
|
+
},
|
|
2305
|
+
// HW-022 (Session 31, 2026-04-26): wire-verified on Analog Stereo
|
|
2306
|
+
// chorus — `session-30-chorus-basic.pcapng`. Chorus first-page
|
|
2307
|
+
// additions: level / time / mod_phase / phase_reverse.
|
|
2308
|
+
'chorus.level': {
|
|
2309
|
+
block: 'chorus', name: 'level',
|
|
2310
|
+
pidLow: 0x004e, pidHigh: 0x0000,
|
|
2311
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2312
|
+
},
|
|
2313
|
+
// renamed for UI-label match (audit row: CHORUS 16)
|
|
2314
|
+
'chorus.delay_time': {
|
|
2315
|
+
block: 'chorus', name: 'delay_time',
|
|
2316
|
+
displayLabel: 'Delay Time',
|
|
2317
|
+
pidLow: 0x004e, pidHigh: 0x0010,
|
|
2318
|
+
// Cache id=16: float a=0.0001 b=0.05 c=1000 → display 0.1..50 ms.
|
|
2319
|
+
unit: 'ms', displayMin: 0.1, displayMax: 50,
|
|
2320
|
+
},
|
|
2321
|
+
'chorus.mod_phase': {
|
|
2322
|
+
block: 'chorus', name: 'mod_phase',
|
|
2323
|
+
displayLabel: 'Mod Phase',
|
|
2324
|
+
pidLow: 0x004e, pidHigh: 0x0011,
|
|
2325
|
+
// Cache id=17: float a=0 b=π c=180/π → display 0..180 deg.
|
|
2326
|
+
unit: 'degrees', displayMin: 0, displayMax: 180,
|
|
2327
|
+
},
|
|
2328
|
+
'chorus.phase_reverse': {
|
|
2329
|
+
block: 'chorus', name: 'phase_reverse',
|
|
2330
|
+
displayLabel: 'Phase Reverse',
|
|
2331
|
+
pidLow: 0x004e, pidHigh: 0x0014,
|
|
2332
|
+
// Cache id=20 enum: [NONE, RIGHT, LEFT, BOTH]. Default NONE.
|
|
2333
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2334
|
+
enumValues: { 0: 'NONE', 1: 'RIGHT', 2: 'LEFT', 3: 'BOTH' },
|
|
2335
|
+
},
|
|
2336
|
+
// HW-040 (Session 36, 2026-04-29): Chorus Expert-Edit page from
|
|
2337
|
+
// session-40-chorus-expert.pcapng (Analog Stereo). New non-Type
|
|
2338
|
+
// enums + cache mirrors.
|
|
2339
|
+
'chorus.bypass_mode': {
|
|
2340
|
+
block: 'chorus', name: 'bypass_mode',
|
|
2341
|
+
pidLow: 0x004e, pidHigh: 0x0004,
|
|
2342
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
2343
|
+
enumValues: { 0: 'Thru', 1: 'Mute FX Out', 2: 'Mute Out' },
|
|
2344
|
+
},
|
|
2345
|
+
// chorus.tempo already registered above (HW-027 added the
|
|
2346
|
+
// shared TEMPO_DIVISIONS_VALUES dictionary).
|
|
2347
|
+
'chorus.lfo_type': {
|
|
2348
|
+
block: 'chorus', name: 'lfo_type',
|
|
2349
|
+
displayLabel: 'LFO Type',
|
|
2350
|
+
pidLow: 0x004e, pidHigh: 0x0012,
|
|
2351
|
+
unit: 'enum', displayMin: 0, displayMax: 9,
|
|
2352
|
+
enumValues: LFO_WAVEFORMS_VALUES,
|
|
2353
|
+
},
|
|
2354
|
+
'chorus.auto_depth': {
|
|
2355
|
+
block: 'chorus', name: 'auto_depth',
|
|
2356
|
+
displayLabel: 'Auto Depth',
|
|
2357
|
+
pidLow: 0x004e, pidHigh: 0x0013,
|
|
2358
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
2359
|
+
enumValues: { 0: 'OFF', 1: 'LOW', 2: 'HIGH' },
|
|
2360
|
+
},
|
|
2361
|
+
// renamed for UI-label match (audit row: CHORUS 27)
|
|
2362
|
+
'chorus.mode': {
|
|
2363
|
+
block: 'chorus', name: 'mode',
|
|
2364
|
+
displayLabel: 'Mode',
|
|
2365
|
+
pidLow: 0x004e, pidHigh: 0x001b,
|
|
2366
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2367
|
+
enumValues: { 0: 'OFF', 1: 'LOW', 2: 'MED', 3: 'HIGH' },
|
|
2368
|
+
},
|
|
2369
|
+
'chorus.number_of_voices': {
|
|
2370
|
+
block: 'chorus', name: 'number_of_voices',
|
|
2371
|
+
displayLabel: 'Number of Voices',
|
|
2372
|
+
pidLow: 0x004e, pidHigh: 0x000b,
|
|
2373
|
+
unit: 'count', displayMin: 1, displayMax: 4,
|
|
2374
|
+
},
|
|
2375
|
+
'chorus.high_cut': {
|
|
2376
|
+
block: 'chorus', name: 'high_cut',
|
|
2377
|
+
displayLabel: 'High Cut',
|
|
2378
|
+
pidLow: 0x004e, pidHigh: 0x000f,
|
|
2379
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
2380
|
+
},
|
|
2381
|
+
'chorus.lfo_phase_pct': {
|
|
2382
|
+
block: 'chorus', name: 'lfo_phase_pct',
|
|
2383
|
+
displayLabel: 'Right Time Ratio',
|
|
2384
|
+
pidLow: 0x004e, pidHigh: 0x0015,
|
|
2385
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2386
|
+
},
|
|
2387
|
+
// renamed for UI-label match (audit row: CHORUS 22)
|
|
2388
|
+
'chorus.rate_right': {
|
|
2389
|
+
block: 'chorus', name: 'rate_right',
|
|
2390
|
+
displayLabel: 'Rate Right',
|
|
2391
|
+
pidLow: 0x004e, pidHigh: 0x0016,
|
|
2392
|
+
unit: 'hz', displayMin: 0.1, displayMax: 10,
|
|
2393
|
+
},
|
|
2394
|
+
// renamed for UI-label match (audit row: CHORUS 23)
|
|
2395
|
+
'chorus.lfo_2_depth': {
|
|
2396
|
+
block: 'chorus', name: 'lfo_2_depth',
|
|
2397
|
+
displayLabel: 'LFO 2 Depth',
|
|
2398
|
+
pidLow: 0x004e, pidHigh: 0x0017,
|
|
2399
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2400
|
+
},
|
|
2401
|
+
'chorus.drive': {
|
|
2402
|
+
block: 'chorus', name: 'drive',
|
|
2403
|
+
displayLabel: 'Drive',
|
|
2404
|
+
pidLow: 0x004e, pidHigh: 0x0018,
|
|
2405
|
+
// Cache id=24: float a=0.05 b=50 c=10 → display = wire × 10,
|
|
2406
|
+
// range 0.5..500. Same encoding shape as knob_0_10 with stretched
|
|
2407
|
+
// range; the unit is structural. typecode 80 → log10 (HW-053 cont).
|
|
2408
|
+
unit: 'knob_0_10', displayMin: 0.5, displayMax: 500,
|
|
2409
|
+
scaling: 'log10',
|
|
2410
|
+
},
|
|
2411
|
+
// renamed for UI-label match (audit row: CHORUS 25)
|
|
2412
|
+
'chorus.low_cut': {
|
|
2413
|
+
block: 'chorus', name: 'low_cut',
|
|
2414
|
+
displayLabel: 'Low Cut',
|
|
2415
|
+
pidLow: 0x004e, pidHigh: 0x0019,
|
|
2416
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
2417
|
+
},
|
|
2418
|
+
// renamed for UI-label match (audit row: CHORUS 26)
|
|
2419
|
+
'chorus.stereo_spread': {
|
|
2420
|
+
block: 'chorus', name: 'stereo_spread',
|
|
2421
|
+
displayLabel: 'Stereo Spread',
|
|
2422
|
+
pidLow: 0x004e, pidHigh: 0x001a,
|
|
2423
|
+
// Cache id=26: float a=-2 b=2 c=100 → display = wire × 100,
|
|
2424
|
+
// range -200..200% (bipolar with extended range).
|
|
2425
|
+
unit: 'bipolar_percent', displayMin: -200, displayMax: 200,
|
|
2426
|
+
},
|
|
2427
|
+
// HW-032 (Session 30 cont 8, 2026-04-25): wire-verified at +10 dB on
|
|
2428
|
+
// an Analog Stereo flanger — `session-32-flanger-extended.pcapng`.
|
|
2429
|
+
// Follows the universal pidHigh=0x0000 Level pattern.
|
|
2430
|
+
'flanger.level': {
|
|
2431
|
+
block: 'flanger', name: 'level',
|
|
2432
|
+
pidLow: 0x0052, pidHigh: 0x0000,
|
|
2433
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2434
|
+
},
|
|
2435
|
+
'flanger.mix': {
|
|
2436
|
+
// BK-034 resolved (HW-025 #3, Session 30): NOT an encoding bug.
|
|
2437
|
+
// AM4-Edit wire for Mix→54% wrote pidLow=0x0052/pidHigh=0x0001
|
|
2438
|
+
// with float32(0.54) — byte-identical to our `unit: 'percent'`
|
|
2439
|
+
// builder. HW-014's hardware-display readback (54%→50%) is a
|
|
2440
|
+
// hardware-screen rendering quirk; verify via AM4-Edit.
|
|
2441
|
+
block: 'flanger', name: 'mix',
|
|
2442
|
+
pidLow: 0x0052, pidHigh: 0x0001,
|
|
2443
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2444
|
+
},
|
|
2445
|
+
'flanger.type': {
|
|
2446
|
+
block: 'flanger', name: 'type',
|
|
2447
|
+
pidLow: 0x0052, pidHigh: 0x000a,
|
|
2448
|
+
unit: 'enum', displayMin: 0, displayMax: 31,
|
|
2449
|
+
enumValues: FLANGER_TYPES_VALUES,
|
|
2450
|
+
},
|
|
2451
|
+
// HW-024 (Session 30 cont 3): wire-verified at 1.7 Hz on an
|
|
2452
|
+
// Analog Stereo flanger (HW-014 left this unconfirmed in Round 2).
|
|
2453
|
+
'flanger.rate': {
|
|
2454
|
+
block: 'flanger', name: 'rate',
|
|
2455
|
+
displayLabel: 'Rate',
|
|
2456
|
+
pidLow: 0x0052, pidHigh: 0x000b,
|
|
2457
|
+
unit: 'hz', displayMin: 0.05, displayMax: 10,
|
|
2458
|
+
},
|
|
2459
|
+
'flanger.depth': {
|
|
2460
|
+
block: 'flanger', name: 'depth',
|
|
2461
|
+
displayLabel: 'Depth',
|
|
2462
|
+
pidLow: 0x0052, pidHigh: 0x000d,
|
|
2463
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2464
|
+
},
|
|
2465
|
+
'flanger.feedback': {
|
|
2466
|
+
// BK-034 resolved (HW-025 #4, Session 30): NOT an encoding bug.
|
|
2467
|
+
// AM4-Edit wire for Feedback→-61% wrote pidLow=0x0052/pidHigh=0x000e
|
|
2468
|
+
// with float32(-0.61) — byte-identical to our `unit: 'bipolar_percent'`
|
|
2469
|
+
// builder. HW-014's hardware-display readbacks (-61%→0; +99%→+90)
|
|
2470
|
+
// are hardware-screen rendering quirks; verify via AM4-Edit.
|
|
2471
|
+
block: 'flanger', name: 'feedback',
|
|
2472
|
+
displayLabel: 'Feedback',
|
|
2473
|
+
pidLow: 0x0052, pidHigh: 0x000e,
|
|
2474
|
+
// Cache caps internal range at ±0.995 — display scale 100 ⇒ ±99%.
|
|
2475
|
+
unit: 'bipolar_percent', displayMin: -99, displayMax: 99,
|
|
2476
|
+
},
|
|
2477
|
+
// HW-022 (Session 31, 2026-04-26): wire-verified on Analog Stereo
|
|
2478
|
+
// flanger — `session-30-flanger-basic.pcapng`. Manual is a 0–10 knob
|
|
2479
|
+
// (no unit suffix shown in AM4-Edit); Mod Phase mirrors the chorus
|
|
2480
|
+
// degrees encoding.
|
|
2481
|
+
'flanger.manual': {
|
|
2482
|
+
block: 'flanger', name: 'manual',
|
|
2483
|
+
displayLabel: 'Manual',
|
|
2484
|
+
pidLow: 0x0052, pidHigh: 0x000f,
|
|
2485
|
+
// Cache id=15: float a=0 b=1 c=10 → display 0..10.
|
|
2486
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2487
|
+
},
|
|
2488
|
+
'flanger.mod_phase': {
|
|
2489
|
+
block: 'flanger', name: 'mod_phase',
|
|
2490
|
+
displayLabel: 'Mod Phase',
|
|
2491
|
+
pidLow: 0x0052, pidHigh: 0x0011,
|
|
2492
|
+
// Cache id=17: float a=0 b=π c=180/π → display 0..180 deg.
|
|
2493
|
+
unit: 'degrees', displayMin: 0, displayMax: 180,
|
|
2494
|
+
},
|
|
2495
|
+
'phaser.mix': {
|
|
2496
|
+
// BK-034 resolved (HW-025 #5, Session 30): NOT an encoding bug.
|
|
2497
|
+
// AM4-Edit wire for Mix→88% wrote pidLow=0x005a/pidHigh=0x0001
|
|
2498
|
+
// with float32(0.88) — byte-identical to our `unit: 'percent'`
|
|
2499
|
+
// builder. HW-014's hardware-display readback (88%→53%) is a
|
|
2500
|
+
// hardware-screen rendering quirk; verify via AM4-Edit.
|
|
2501
|
+
block: 'phaser', name: 'mix',
|
|
2502
|
+
pidLow: 0x005a, pidHigh: 0x0001,
|
|
2503
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2504
|
+
},
|
|
2505
|
+
'phaser.type': {
|
|
2506
|
+
block: 'phaser', name: 'type',
|
|
2507
|
+
pidLow: 0x005a, pidHigh: 0x000a,
|
|
2508
|
+
unit: 'enum', displayMin: 0, displayMax: 16,
|
|
2509
|
+
enumValues: PHASER_TYPES_VALUES,
|
|
2510
|
+
},
|
|
2511
|
+
// HW-024 (Session 30 cont 3): wire-verified at 2.3 Hz on a Digital
|
|
2512
|
+
// Mono phaser (HW-014 left this unconfirmed in Round 2).
|
|
2513
|
+
'phaser.rate': {
|
|
2514
|
+
block: 'phaser', name: 'rate',
|
|
2515
|
+
displayLabel: 'Rate',
|
|
2516
|
+
pidLow: 0x005a, pidHigh: 0x000c,
|
|
2517
|
+
unit: 'hz', displayMin: 0.1, displayMax: 10,
|
|
2518
|
+
},
|
|
2519
|
+
'phaser.feedback': {
|
|
2520
|
+
block: 'phaser', name: 'feedback',
|
|
2521
|
+
displayLabel: 'Feedback',
|
|
2522
|
+
pidLow: 0x005a, pidHigh: 0x0010,
|
|
2523
|
+
// Cache signature is unusual — internal ±0.9, display-scale 111.1.
|
|
2524
|
+
// We use standard bipolar_percent (scale 100) with clamped bounds
|
|
2525
|
+
// so input stays inside the internal range; AM4-Edit's displayed
|
|
2526
|
+
// percentage may read slightly higher than the value set (an input
|
|
2527
|
+
// of "50" sets internal 0.5 which AM4-Edit shows as ~55.5%). The
|
|
2528
|
+
// natural-language UX impact is negligible.
|
|
2529
|
+
unit: 'bipolar_percent', displayMin: -90, displayMax: 90,
|
|
2530
|
+
},
|
|
2531
|
+
// HW-022 (Session 31, 2026-04-26): wire-verified on Digital Stereo
|
|
2532
|
+
// phaser — `session-30-phaser-basic.pcapng`. Phaser uses 0–10 knob
|
|
2533
|
+
// semantics for Depth + Manual (unlike chorus/flanger which use
|
|
2534
|
+
// percent for Depth). Mod Phase address differs from chorus/flanger
|
|
2535
|
+
// (0x0013 here vs 0x0011 there) — cache lays it out at id=19 not id=17.
|
|
2536
|
+
'phaser.level': {
|
|
2537
|
+
block: 'phaser', name: 'level',
|
|
2538
|
+
pidLow: 0x005a, pidHigh: 0x0000,
|
|
2539
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2540
|
+
},
|
|
2541
|
+
'phaser.depth': {
|
|
2542
|
+
block: 'phaser', name: 'depth',
|
|
2543
|
+
displayLabel: 'Depth',
|
|
2544
|
+
pidLow: 0x005a, pidHigh: 0x000f,
|
|
2545
|
+
// Cache id=15: float a=0 b=1 c=10 → display 0..10.
|
|
2546
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2547
|
+
},
|
|
2548
|
+
'phaser.mod_phase': {
|
|
2549
|
+
block: 'phaser', name: 'mod_phase',
|
|
2550
|
+
displayLabel: 'Mod Phase',
|
|
2551
|
+
pidLow: 0x005a, pidHigh: 0x0013,
|
|
2552
|
+
// Cache id=19: float a=0 b=π c=180/π → display 0..180 deg.
|
|
2553
|
+
unit: 'degrees', displayMin: 0, displayMax: 180,
|
|
2554
|
+
},
|
|
2555
|
+
'phaser.manual': {
|
|
2556
|
+
block: 'phaser', name: 'manual',
|
|
2557
|
+
displayLabel: 'Manual',
|
|
2558
|
+
pidLow: 0x005a, pidHigh: 0x0022,
|
|
2559
|
+
// Cache id=34: float a=0 b=1 c=10 → display 0..10.
|
|
2560
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2561
|
+
},
|
|
2562
|
+
'wah.type': {
|
|
2563
|
+
block: 'wah', name: 'type',
|
|
2564
|
+
pidLow: 0x005e, pidHigh: 0x000a,
|
|
2565
|
+
unit: 'enum', displayMin: 0, displayMax: 8,
|
|
2566
|
+
enumValues: WAH_TYPES_VALUES,
|
|
2567
|
+
},
|
|
2568
|
+
// HW-040 (Session 36, 2026-04-29): Wah Expert-Edit page from
|
|
2569
|
+
// session-40-wah-expert.pcapng (FAS Wah). 18 new params + 3 hand-
|
|
2570
|
+
// authored enums. Closes the wah block from "type-only" registration
|
|
2571
|
+
// to full Expert coverage.
|
|
2572
|
+
//
|
|
2573
|
+
// **BK-035 audit (Session 36 cont, 2026-04-29):** Eight wah ids were
|
|
2574
|
+
// mis-named in the original auto-generation pass — the cache-id →
|
|
2575
|
+
// pidHigh ordering didn't match the AM4-Edit screenshot's knob
|
|
2576
|
+
// labels. Re-derived from the value-matched audit table (`scripts/
|
|
2577
|
+
// audit-block-vs-screenshot.ts` against `docs/audit-input/wah.json`).
|
|
2578
|
+
// Old → new:
|
|
2579
|
+
// 0x000d q (range 2..20) → q_resonance (range 0..10)
|
|
2580
|
+
// 0x000e q_resonance → q_tracking
|
|
2581
|
+
// 0x000f q_tracking → wah_control
|
|
2582
|
+
// 0x0010 control_taper + drive → fat
|
|
2583
|
+
// (was duplicate-pidHigh code bug — now resolved)
|
|
2584
|
+
// 0x0011 fat → drive
|
|
2585
|
+
// 0x0012 (unregistered) → control_taper (enum, hand-authored)
|
|
2586
|
+
// 0x0013 low_cut_frequency → inductor_bias (knob_0_10)
|
|
2587
|
+
// 0x0014 inductor_bias (hz) → low_cut_frequency (hz)
|
|
2588
|
+
'wah.level': {
|
|
2589
|
+
block: 'wah', name: 'level',
|
|
2590
|
+
pidLow: 0x005e, pidHigh: 0x0000,
|
|
2591
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2592
|
+
},
|
|
2593
|
+
'wah.bypass_mode': {
|
|
2594
|
+
block: 'wah', name: 'bypass_mode',
|
|
2595
|
+
pidLow: 0x005e, pidHigh: 0x0004,
|
|
2596
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
2597
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
2598
|
+
},
|
|
2599
|
+
// renamed for UI-label match (audit row: WAH 11)
|
|
2600
|
+
'wah.minimum_frequency': {
|
|
2601
|
+
block: 'wah', name: 'minimum_frequency',
|
|
2602
|
+
displayLabel: 'Minimum Frequency',
|
|
2603
|
+
pidLow: 0x005e, pidHigh: 0x000b,
|
|
2604
|
+
unit: 'hz', displayMin: 100, displayMax: 1000,
|
|
2605
|
+
},
|
|
2606
|
+
// renamed for UI-label match (audit row: WAH 12)
|
|
2607
|
+
'wah.maximum_frequency': {
|
|
2608
|
+
block: 'wah', name: 'maximum_frequency',
|
|
2609
|
+
displayLabel: 'Maximum Frequency',
|
|
2610
|
+
pidLow: 0x005e, pidHigh: 0x000c,
|
|
2611
|
+
// Cache id=12: a=500 b=5000 c=1.
|
|
2612
|
+
unit: 'hz', displayMin: 500, displayMax: 5000,
|
|
2613
|
+
},
|
|
2614
|
+
'wah.q_resonance': {
|
|
2615
|
+
block: 'wah', name: 'q_resonance',
|
|
2616
|
+
displayLabel: 'Resonance',
|
|
2617
|
+
pidLow: 0x005e, pidHigh: 0x000d,
|
|
2618
|
+
// BK-035: was `wah.q` with range 2..20. Screenshot showed 4.44 at
|
|
2619
|
+
// wire 0.444, which only matches knob_0_10 (×10). Range corrected.
|
|
2620
|
+
// typecode 80 → log10 (HW-053 cont); displayMin=0 falls back to linear.
|
|
2621
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2622
|
+
scaling: 'log10',
|
|
2623
|
+
},
|
|
2624
|
+
'wah.q_tracking': {
|
|
2625
|
+
block: 'wah', name: 'q_tracking',
|
|
2626
|
+
displayLabel: 'Q Tracking',
|
|
2627
|
+
pidLow: 0x005e, pidHigh: 0x000e,
|
|
2628
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2629
|
+
},
|
|
2630
|
+
'wah.wah_control': {
|
|
2631
|
+
block: 'wah', name: 'wah_control',
|
|
2632
|
+
displayLabel: 'Wah Control',
|
|
2633
|
+
pidLow: 0x005e, pidHigh: 0x000f,
|
|
2634
|
+
// BK-035: the actual pedal-position param. Without it, cocked-wah
|
|
2635
|
+
// presets are blocked — Claude can't sweep the wah filter sweep.
|
|
2636
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2637
|
+
},
|
|
2638
|
+
'wah.fat': {
|
|
2639
|
+
block: 'wah', name: 'fat',
|
|
2640
|
+
displayLabel: 'Fat',
|
|
2641
|
+
pidLow: 0x005e, pidHigh: 0x0010,
|
|
2642
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2643
|
+
},
|
|
2644
|
+
'wah.drive': {
|
|
2645
|
+
block: 'wah', name: 'drive',
|
|
2646
|
+
displayLabel: 'Drive',
|
|
2647
|
+
pidLow: 0x005e, pidHigh: 0x0011,
|
|
2648
|
+
// typecode 80 → log10 (HW-053 cont); displayMin=0 falls back to linear.
|
|
2649
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2650
|
+
scaling: 'log10',
|
|
2651
|
+
},
|
|
2652
|
+
'wah.control_taper': {
|
|
2653
|
+
block: 'wah', name: 'control_taper',
|
|
2654
|
+
displayLabel: 'Control Taper',
|
|
2655
|
+
pidLow: 0x005e, pidHigh: 0x0012,
|
|
2656
|
+
// BK-035: previously registered at 0x0010 (wrong pidHigh). The
|
|
2657
|
+
// captured wire at 0x0012 is float32(4) = enum index 4 = "Log 10A",
|
|
2658
|
+
// matching the screenshot's Control Taper dropdown.
|
|
2659
|
+
// Cache id=18 enum has 6 entries (max=5).
|
|
2660
|
+
unit: 'enum', displayMin: 0, displayMax: 5,
|
|
2661
|
+
enumValues: { 0: 'LINEAR', 1: 'LOG 30A', 2: 'LOG 20A', 3: 'LOG 15A', 4: 'LOG 10A', 5: 'LOG 5A' },
|
|
2662
|
+
},
|
|
2663
|
+
'wah.inductor_bias': {
|
|
2664
|
+
block: 'wah', name: 'inductor_bias',
|
|
2665
|
+
displayLabel: 'Inductor Bias',
|
|
2666
|
+
pidLow: 0x005e, pidHigh: 0x0013,
|
|
2667
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2668
|
+
},
|
|
2669
|
+
'wah.low_cut_frequency': {
|
|
2670
|
+
block: 'wah', name: 'low_cut_frequency',
|
|
2671
|
+
displayLabel: 'Low Cut Frequency',
|
|
2672
|
+
pidLow: 0x005e, pidHigh: 0x0014,
|
|
2673
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
2674
|
+
},
|
|
2675
|
+
'wah.eq_post': {
|
|
2676
|
+
block: 'wah', name: 'eq_post',
|
|
2677
|
+
displayLabel: 'EQ',
|
|
2678
|
+
pidLow: 0x005e, pidHigh: 0x0015,
|
|
2679
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
2680
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
2681
|
+
},
|
|
2682
|
+
'wah.graphic_eq_band_1': { block: 'wah', name: 'graphic_eq_band_1', displayLabel: '160', pidLow: 0x005e, pidHigh: 0x0016, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2683
|
+
'wah.graphic_eq_band_2': { block: 'wah', name: 'graphic_eq_band_2', displayLabel: '250', pidLow: 0x005e, pidHigh: 0x0017, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2684
|
+
'wah.graphic_eq_band_3': { block: 'wah', name: 'graphic_eq_band_3', displayLabel: '400', pidLow: 0x005e, pidHigh: 0x0018, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2685
|
+
'wah.graphic_eq_band_4': { block: 'wah', name: 'graphic_eq_band_4', displayLabel: '640', pidLow: 0x005e, pidHigh: 0x0019, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2686
|
+
'wah.graphic_eq_band_5': { block: 'wah', name: 'graphic_eq_band_5', displayLabel: '1000', pidLow: 0x005e, pidHigh: 0x001a, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2687
|
+
'wah.graphic_eq_band_6': { block: 'wah', name: 'graphic_eq_band_6', displayLabel: '1600', pidLow: 0x005e, pidHigh: 0x001b, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2688
|
+
'wah.graphic_eq_band_7': { block: 'wah', name: 'graphic_eq_band_7', displayLabel: '2500', pidLow: 0x005e, pidHigh: 0x001c, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2689
|
+
'wah.graphic_eq_band_8': { block: 'wah', name: 'graphic_eq_band_8', displayLabel: '4000', pidLow: 0x005e, pidHigh: 0x001d, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
2690
|
+
'compressor.mix': {
|
|
2691
|
+
block: 'compressor', name: 'mix',
|
|
2692
|
+
pidLow: 0x002e, pidHigh: 0x0001,
|
|
2693
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2694
|
+
},
|
|
2695
|
+
// HW-021 (Session 30, 2026-04-25): Compressor first-page registers
|
|
2696
|
+
// from session-30-comp-basic-jfet-studio. Cache ids 10..15 are the
|
|
2697
|
+
// canonical comp-config knobs (Threshold, Ratio, Attack, Release,
|
|
2698
|
+
// Knee Type enum, Auto Makeup OFF/ON). `level` follows the universal
|
|
2699
|
+
// pidHigh=0x0000 "Level" pattern (out-of-band hand-author).
|
|
2700
|
+
// Two more registers wiggled in the capture remain unidentified
|
|
2701
|
+
// (pidHigh=0x0017 cache id=23 float; pidHigh=0x0029 cache id=41
|
|
2702
|
+
// knob_0_10 with value 1.2 exceeding cache cap b=1) — queued as
|
|
2703
|
+
// HW-028 follow-up. The Optical/JFET-specific Light Type knob
|
|
2704
|
+
// wasn't reached in this capture.
|
|
2705
|
+
'compressor.level': {
|
|
2706
|
+
block: 'compressor', name: 'level',
|
|
2707
|
+
pidLow: 0x002e, pidHigh: 0x0000,
|
|
2708
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2709
|
+
},
|
|
2710
|
+
'compressor.threshold': {
|
|
2711
|
+
block: 'compressor', name: 'threshold',
|
|
2712
|
+
displayLabel: 'Threshold',
|
|
2713
|
+
pidLow: 0x002e, pidHigh: 0x000a,
|
|
2714
|
+
// Cache id=10: float a=-60 b=20 c=1 → dB -60..+20 (capture wrote
|
|
2715
|
+
// -30 dB).
|
|
2716
|
+
unit: 'db', displayMin: -60, displayMax: 20,
|
|
2717
|
+
},
|
|
2718
|
+
'compressor.ratio': {
|
|
2719
|
+
block: 'compressor', name: 'ratio',
|
|
2720
|
+
displayLabel: 'Ratio',
|
|
2721
|
+
pidLow: 0x002e, pidHigh: 0x000b,
|
|
2722
|
+
// Cache id=11: float a=1 b=20 c=1 step=0.01 → 1.0..20.0 ratio
|
|
2723
|
+
// (e.g. 4.0 ⇒ 4:1). Uses the `ratio` unit semantically; math is
|
|
2724
|
+
// identical to db/hz/seconds (display = internal, scale 1) but
|
|
2725
|
+
// the label tells Claude "4 means 4:1, not 4 dB".
|
|
2726
|
+
// BK-038 (Session 43 cont): typecode=64 → log10 scaling. Read
|
|
2727
|
+
// register stores Q15 of log10-normalized internal across [1..20].
|
|
2728
|
+
unit: 'ratio', displayMin: 1, displayMax: 20, scaling: 'log10',
|
|
2729
|
+
},
|
|
2730
|
+
// renamed for UI-label match (audit row: COMP 12)
|
|
2731
|
+
'compressor.attack_time': {
|
|
2732
|
+
block: 'compressor', name: 'attack_time',
|
|
2733
|
+
displayLabel: 'Attack Time',
|
|
2734
|
+
pidLow: 0x002e, pidHigh: 0x000c,
|
|
2735
|
+
// Cache id=12: float a=0.0001 b=0.1 c=1000 → 0.1..100 ms.
|
|
2736
|
+
// BK-038 (Session 43 cont): typecode=68 → log10 scaling. Verified
|
|
2737
|
+
// empirically — Sultans test wrote 40 ms, readback decoded as 867 ms
|
|
2738
|
+
// with old linear rule; with log10 rule, internal 0.867 → 40.0 ms.
|
|
2739
|
+
unit: 'ms', displayMin: 0.1, displayMax: 100, scaling: 'log10',
|
|
2740
|
+
},
|
|
2741
|
+
// renamed for UI-label match (audit row: COMP 13)
|
|
2742
|
+
'compressor.release_time': {
|
|
2743
|
+
block: 'compressor', name: 'release_time',
|
|
2744
|
+
displayLabel: 'Release Time',
|
|
2745
|
+
pidLow: 0x002e, pidHigh: 0x000d,
|
|
2746
|
+
// Cache id=13: float a=0.002 b=2 c=1000 → 2..2000 ms.
|
|
2747
|
+
// BK-038 (Session 43 cont): typecode=68 → log10 scaling. Sultans
|
|
2748
|
+
// test wrote 100 ms; readback internal 0.566 → log10 decode → 100 ms.
|
|
2749
|
+
unit: 'ms', displayMin: 2, displayMax: 2000, scaling: 'log10',
|
|
2750
|
+
},
|
|
2751
|
+
'compressor.auto_makeup': {
|
|
2752
|
+
block: 'compressor', name: 'auto_makeup',
|
|
2753
|
+
displayLabel: 'Auto Makeup',
|
|
2754
|
+
pidLow: 0x002e, pidHigh: 0x000f,
|
|
2755
|
+
// Cache id=15: enum [OFF|ON]. Hand-authored — see delay.stack_hold
|
|
2756
|
+
// for why per-block non-Type enums skip the generator.
|
|
2757
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
2758
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
2759
|
+
},
|
|
2760
|
+
'compressor.type': {
|
|
2761
|
+
block: 'compressor', name: 'type',
|
|
2762
|
+
pidLow: 0x002e, pidHigh: 0x0013,
|
|
2763
|
+
unit: 'enum', displayMin: 0, displayMax: 18,
|
|
2764
|
+
enumValues: COMPRESSOR_TYPES_VALUES,
|
|
2765
|
+
},
|
|
2766
|
+
// HW-028 + HW-039 (Session 35, 2026-04-29): Compressor Expert-Edit
|
|
2767
|
+
// Sidechain section + Drive-engine knobs from
|
|
2768
|
+
// session-31-comp-jfet-expert.pcapng + paired AM4-Edit screenshot
|
|
2769
|
+
// (JFET Studio Compressor type). Closes HW-028: 0x0017 = comp.emphasis
|
|
2770
|
+
// (knob_0_20 fine knob 0..20, screenshot 2.22 ↔ wire 0.111×20=2.22);
|
|
2771
|
+
// 0x0029 = comp.drive (knob_0_10, screenshot 6.66 ↔ wire 0.666). The
|
|
2772
|
+
// Sidechain section pins eight new params (filter Frequency/Q/Gain/
|
|
2773
|
+
// Low Cut/High Cut/Source/Filter Type/Emphasis Freq) with cache shapes
|
|
2774
|
+
// matching screenshot labels byte-for-byte. bypass_mode (0x0004) and
|
|
2775
|
+
// input_level (0x0019) are universal MIX-section enums.
|
|
2776
|
+
//
|
|
2777
|
+
// Mirrored from CACHE_PARAMS so the type-check picks them up.
|
|
2778
|
+
'compressor.bypass_mode': {
|
|
2779
|
+
block: 'compressor', name: 'bypass_mode',
|
|
2780
|
+
pidLow: 0x002e, pidHigh: 0x0004,
|
|
2781
|
+
// Cache id=4: enum [Thru / Mute FX Out / Mute Out]. Hand-authored —
|
|
2782
|
+
// not Type, so gen-params skips the enum-import attachment.
|
|
2783
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
2784
|
+
enumValues: { 0: 'Thru', 1: 'Mute FX Out', 2: 'Mute Out' },
|
|
2785
|
+
},
|
|
2786
|
+
'compressor.sidechain_low_cut': {
|
|
2787
|
+
block: 'compressor', name: 'sidechain_low_cut',
|
|
2788
|
+
displayLabel: 'Low Cut',
|
|
2789
|
+
pidLow: 0x002e, pidHigh: 0x0011,
|
|
2790
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
2791
|
+
},
|
|
2792
|
+
'compressor.sidechain_source': {
|
|
2793
|
+
block: 'compressor', name: 'sidechain_source',
|
|
2794
|
+
displayLabel: 'Sidechain Source',
|
|
2795
|
+
pidLow: 0x002e, pidHigh: 0x0012,
|
|
2796
|
+
// Cache id=18: enum [BLOCK L+R / INPUT 1 / BLOCK L / BLOCK R].
|
|
2797
|
+
// Same enum strings as gate.sidechain (capture wrote index 3 =
|
|
2798
|
+
// BLOCK R; matches screenshot "Block R").
|
|
2799
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
2800
|
+
enumValues: { 0: 'BLOCK L+R', 1: 'INPUT 1', 2: 'BLOCK L', 3: 'BLOCK R' },
|
|
2801
|
+
},
|
|
2802
|
+
'compressor.look_ahead_time': {
|
|
2803
|
+
block: 'compressor', name: 'look_ahead_time',
|
|
2804
|
+
displayLabel: 'Look-Ahead Time',
|
|
2805
|
+
pidLow: 0x002e, pidHigh: 0x0015,
|
|
2806
|
+
// Cache id=21: float a=0 b=0.002 c=1000 → 0..2 ms (fine resolution).
|
|
2807
|
+
unit: 'ms', displayMin: 0, displayMax: 2,
|
|
2808
|
+
},
|
|
2809
|
+
'compressor.emphasis': {
|
|
2810
|
+
block: 'compressor', name: 'emphasis',
|
|
2811
|
+
displayLabel: 'Emphasis',
|
|
2812
|
+
pidLow: 0x002e, pidHigh: 0x0017,
|
|
2813
|
+
// Cache id=23: float a=0 b=1 c=20 step=0.0005 → 0..20 fine knob.
|
|
2814
|
+
// First param to use the new `knob_0_20` unit (HW-028 closure).
|
|
2815
|
+
unit: 'knob_0_20', displayMin: 0, displayMax: 20,
|
|
2816
|
+
},
|
|
2817
|
+
'compressor.input_level': {
|
|
2818
|
+
block: 'compressor', name: 'input_level',
|
|
2819
|
+
displayLabel: 'Input Level',
|
|
2820
|
+
pidLow: 0x002e, pidHigh: 0x0019,
|
|
2821
|
+
// Cache id=25: enum [INSTRUMENT / LINE]. Capture wrote index 0 =
|
|
2822
|
+
// INSTRUMENT; matches screenshot "Instrument".
|
|
2823
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
2824
|
+
enumValues: { 0: 'INSTRUMENT', 1: 'LINE' },
|
|
2825
|
+
},
|
|
2826
|
+
'compressor.sidechain_high_cut': {
|
|
2827
|
+
block: 'compressor', name: 'sidechain_high_cut',
|
|
2828
|
+
displayLabel: 'High Cut',
|
|
2829
|
+
pidLow: 0x002e, pidHigh: 0x001a,
|
|
2830
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
2831
|
+
},
|
|
2832
|
+
'compressor.sidechain_gain': {
|
|
2833
|
+
block: 'compressor', name: 'sidechain_gain',
|
|
2834
|
+
displayLabel: 'Gain',
|
|
2835
|
+
pidLow: 0x002e, pidHigh: 0x001b,
|
|
2836
|
+
unit: 'db', displayMin: -12, displayMax: 12,
|
|
2837
|
+
},
|
|
2838
|
+
'compressor.sidechain_frequency': {
|
|
2839
|
+
block: 'compressor', name: 'sidechain_frequency',
|
|
2840
|
+
displayLabel: 'Frequency',
|
|
2841
|
+
pidLow: 0x002e, pidHigh: 0x001c,
|
|
2842
|
+
unit: 'hz', displayMin: 100, displayMax: 10000,
|
|
2843
|
+
},
|
|
2844
|
+
'compressor.sidechain_q': {
|
|
2845
|
+
block: 'compressor', name: 'sidechain_q',
|
|
2846
|
+
displayLabel: 'Q',
|
|
2847
|
+
pidLow: 0x002e, pidHigh: 0x001d,
|
|
2848
|
+
// Cache id=29: float a=0.1 b=10 c=1 → 0.1..10 fractional Q. Uses
|
|
2849
|
+
// `count` for the raw-passthrough scale (display = wire × 1) — the
|
|
2850
|
+
// unit is structural; Q is a quality factor, not a literal count.
|
|
2851
|
+
unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10',
|
|
2852
|
+
},
|
|
2853
|
+
'compressor.sidechain_filter_type': {
|
|
2854
|
+
block: 'compressor', name: 'sidechain_filter_type',
|
|
2855
|
+
displayLabel: 'Filter Type',
|
|
2856
|
+
pidLow: 0x002e, pidHigh: 0x0020,
|
|
2857
|
+
// HW-039 (closed 2026-04-30): cache id=32 enum has all 12 entries
|
|
2858
|
+
// (the earlier "4-entry truncation" finding from Session 35 was a
|
|
2859
|
+
// stale parse — `cache-section2.json` confirms count=12, max=11).
|
|
2860
|
+
// Hand-authored rather than emitted via gen-params-from-cache because
|
|
2861
|
+
// the generator's per-block `enumImport` only targets the Type
|
|
2862
|
+
// dropdown (id=19 here); non-Type enums are inlined.
|
|
2863
|
+
unit: 'enum', displayMin: 0, displayMax: 11,
|
|
2864
|
+
enumValues: {
|
|
2865
|
+
0: 'NULL',
|
|
2866
|
+
1: 'LOWPASS',
|
|
2867
|
+
2: 'BANDPASS',
|
|
2868
|
+
3: 'HIGHPASS',
|
|
2869
|
+
4: 'LOWSHELF',
|
|
2870
|
+
5: 'HIGHSHELF',
|
|
2871
|
+
6: 'PEAKING',
|
|
2872
|
+
7: 'NOTCH',
|
|
2873
|
+
8: 'TILT EQ',
|
|
2874
|
+
9: 'LOWSHELF 2',
|
|
2875
|
+
10: 'HIGHSHELF 2',
|
|
2876
|
+
11: 'PEAKING 2',
|
|
2877
|
+
},
|
|
2878
|
+
},
|
|
2879
|
+
'compressor.sidechain_emphasis_freq': {
|
|
2880
|
+
block: 'compressor', name: 'sidechain_emphasis_freq',
|
|
2881
|
+
displayLabel: 'Emphasis Freq',
|
|
2882
|
+
pidLow: 0x002e, pidHigh: 0x0027,
|
|
2883
|
+
unit: 'hz', displayMin: 100, displayMax: 10000,
|
|
2884
|
+
},
|
|
2885
|
+
'compressor.drive': {
|
|
2886
|
+
block: 'compressor', name: 'drive',
|
|
2887
|
+
displayLabel: 'Drive',
|
|
2888
|
+
pidLow: 0x002e, pidHigh: 0x0029,
|
|
2889
|
+
// Cache id=41: float a=0 b=1 c=10 → knob_0_10. HW-021 noted the
|
|
2890
|
+
// earlier capture wrote 1.2 (exceeds cache cap b=1) — that capture
|
|
2891
|
+
// was one of the AM4-Edit-side wiggles that briefly went past the
|
|
2892
|
+
// displayed range; the current capture wire is 0.666 → display 6.66
|
|
2893
|
+
// matches screenshot "Drive 6.66" cleanly.
|
|
2894
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
2895
|
+
},
|
|
2896
|
+
'geq.type': {
|
|
2897
|
+
block: 'geq', name: 'type',
|
|
2898
|
+
pidLow: 0x0032, pidHigh: 0x0014,
|
|
2899
|
+
unit: 'enum', displayMin: 0, displayMax: 17,
|
|
2900
|
+
enumValues: GEQ_TYPES_VALUES,
|
|
2901
|
+
},
|
|
2902
|
+
// Session 18 (continued) — 5 more Type/Mode selectors from block-placement
|
|
2903
|
+
// captures. PEQ (pidLow=0x36) and Rotary (pidLow=0x56) are also confirmed
|
|
2904
|
+
// block addresses but have no Type enum — their params will be added when
|
|
2905
|
+
// we start supporting specific knob names.
|
|
2906
|
+
// HW-032 (Session 30 cont 8, 2026-04-25): wire-verified at +12 dB on
|
|
2907
|
+
// a Low-Pass filter — `session-32-filter-extended.pcapng`. Follows
|
|
2908
|
+
// the universal pidHigh=0x0000 Level pattern.
|
|
2909
|
+
'filter.level': {
|
|
2910
|
+
block: 'filter', name: 'level',
|
|
2911
|
+
pidLow: 0x0072, pidHigh: 0x0000,
|
|
2912
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
2913
|
+
},
|
|
2914
|
+
'filter.mix': {
|
|
2915
|
+
block: 'filter', name: 'mix',
|
|
2916
|
+
pidLow: 0x0072, pidHigh: 0x0001,
|
|
2917
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2918
|
+
},
|
|
2919
|
+
'filter.type': {
|
|
2920
|
+
block: 'filter', name: 'type',
|
|
2921
|
+
pidLow: 0x0072, pidHigh: 0x000a,
|
|
2922
|
+
unit: 'enum', displayMin: 0, displayMax: 17,
|
|
2923
|
+
enumValues: FILTER_TYPES_VALUES,
|
|
2924
|
+
},
|
|
2925
|
+
// renamed for UI-label match (audit row: FILTER 11)
|
|
2926
|
+
'filter.frequency': {
|
|
2927
|
+
// Blocks Guide §Filter: Frequency is the filter cutoff. 20..20000 Hz,
|
|
2928
|
+
// c=1 raw (uses 'hz' unit). HW-024 (Session 30 cont 3): wire-verified
|
|
2929
|
+
// on Low-Pass at 1250 Hz; readback was 1249.9 Hz. The 0.1 Hz drift is
|
|
2930
|
+
// float→fixed-point quantization noise in the firmware (8e-5 relative
|
|
2931
|
+
// error), not a wire-layer encoding bug — drift scales with frequency.
|
|
2932
|
+
// Functionally inaudible; do not assume exact equality on round-trip
|
|
2933
|
+
// when comparing presets that differ only in filter.frequency.
|
|
2934
|
+
block: 'filter', name: 'frequency',
|
|
2935
|
+
displayLabel: 'Frequency',
|
|
2936
|
+
pidLow: 0x0072, pidHigh: 0x000b,
|
|
2937
|
+
unit: 'hz', displayMin: 20, displayMax: 20000,
|
|
2938
|
+
},
|
|
2939
|
+
// HW-032 (Session 30 cont 8, 2026-04-25): filter Config-page cuts.
|
|
2940
|
+
// Wire-verified at 100 Hz / 1800 Hz on a Low-Pass filter
|
|
2941
|
+
// (`session-32-filter-extended.pcapng`). Cache c=1 raw Hz at ids
|
|
2942
|
+
// 18 / 19. Mirrored from CACHE_PARAMS so the type-check picks them up.
|
|
2943
|
+
'filter.low_cut': {
|
|
2944
|
+
block: 'filter', name: 'low_cut',
|
|
2945
|
+
displayLabel: 'Low Cut',
|
|
2946
|
+
pidLow: 0x0072, pidHigh: 0x0012,
|
|
2947
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
2948
|
+
},
|
|
2949
|
+
'filter.high_cut': {
|
|
2950
|
+
block: 'filter', name: 'high_cut',
|
|
2951
|
+
displayLabel: 'High Cut',
|
|
2952
|
+
pidLow: 0x0072, pidHigh: 0x0013,
|
|
2953
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
2954
|
+
},
|
|
2955
|
+
// HW-034 (Session 33, 2026-04-26): All-Pass filter Config-page
|
|
2956
|
+
// residuals — `session-33-filter-extended.pcapng`. Wire-verified
|
|
2957
|
+
// at 13% Feedback / 4-pole Order. Feedback cache signature
|
|
2958
|
+
// (a=-1, b=1, c=100) is bipolar_percent ±100 (All-Pass feedback
|
|
2959
|
+
// can invert phase). Order is an integer pole count 1..12 — cache
|
|
2960
|
+
// typecode=0x0010 with c=1 raw. AM4-Edit's UI dropdown limits the
|
|
2961
|
+
// exposed options per filter type (All-Pass shows 2/4/6/8/10/12;
|
|
2962
|
+
// Low-Pass shows 2/4 only at cache id=14), but the wire register
|
|
2963
|
+
// accepts any integer in the cache range.
|
|
2964
|
+
'filter.feedback': {
|
|
2965
|
+
block: 'filter', name: 'feedback',
|
|
2966
|
+
displayLabel: 'Feedback',
|
|
2967
|
+
pidLow: 0x0072, pidHigh: 0x0015,
|
|
2968
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
2969
|
+
},
|
|
2970
|
+
'filter.order': {
|
|
2971
|
+
block: 'filter', name: 'order',
|
|
2972
|
+
displayLabel: 'Order',
|
|
2973
|
+
pidLow: 0x0072, pidHigh: 0x001c,
|
|
2974
|
+
unit: 'count', displayMin: 1, displayMax: 12,
|
|
2975
|
+
},
|
|
2976
|
+
'tremolo.mix': {
|
|
2977
|
+
block: 'tremolo', name: 'mix',
|
|
2978
|
+
pidLow: 0x006a, pidHigh: 0x0001,
|
|
2979
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2980
|
+
},
|
|
2981
|
+
'tremolo.type': {
|
|
2982
|
+
block: 'tremolo', name: 'type',
|
|
2983
|
+
pidLow: 0x006a, pidHigh: 0x000a,
|
|
2984
|
+
unit: 'enum', displayMin: 0, displayMax: 6,
|
|
2985
|
+
enumValues: TREMOLO_TYPES_VALUES,
|
|
2986
|
+
},
|
|
2987
|
+
'tremolo.rate': {
|
|
2988
|
+
block: 'tremolo', name: 'rate',
|
|
2989
|
+
displayLabel: 'Rate',
|
|
2990
|
+
pidLow: 0x006a, pidHigh: 0x000c,
|
|
2991
|
+
unit: 'hz', displayMin: 0.2, displayMax: 20,
|
|
2992
|
+
},
|
|
2993
|
+
'tremolo.depth': {
|
|
2994
|
+
block: 'tremolo', name: 'depth',
|
|
2995
|
+
displayLabel: 'Depth',
|
|
2996
|
+
pidLow: 0x006a, pidHigh: 0x000d,
|
|
2997
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
2998
|
+
},
|
|
2999
|
+
// HW-022 (Session 31, 2026-04-26): wire-verified on Panner-type
|
|
3000
|
+
// tremolo — `session-30-tremolo-basic.pcapng`. Tremolo's first page
|
|
3001
|
+
// is type-dependent: Panner exposes Width / Phase / Center / Ducking
|
|
3002
|
+
// / Waveform (instead of VCA Trem's Depth which lives at pidHigh
|
|
3003
|
+
// 0x000d). Level (pidHigh=0x0000) wasn't moved in this capture — to
|
|
3004
|
+
// be added when a future capture wiggles it.
|
|
3005
|
+
'tremolo.waveform': {
|
|
3006
|
+
block: 'tremolo', name: 'waveform',
|
|
3007
|
+
displayLabel: 'Waveform',
|
|
3008
|
+
pidLow: 0x006a, pidHigh: 0x000b,
|
|
3009
|
+
// Cache id=11 enum: 10-entry LFO_WAVEFORMS — SINE / TRIANGLE /
|
|
3010
|
+
// SQUARE / SAW UP / SAW DOWN / RANDOM / LOG / EXP / TRAPEZOID /
|
|
3011
|
+
// ASTABLE. Shared dictionary across modulation blocks (extracted
|
|
3012
|
+
// from chorus/id=18; cross-checked against flanger/phaser/tremolo).
|
|
3013
|
+
unit: 'enum', displayMin: 0, displayMax: 9,
|
|
3014
|
+
enumValues: LFO_WAVEFORMS_VALUES,
|
|
3015
|
+
},
|
|
3016
|
+
'tremolo.phase': {
|
|
3017
|
+
block: 'tremolo', name: 'phase',
|
|
3018
|
+
displayLabel: 'Phase',
|
|
3019
|
+
pidLow: 0x006a, pidHigh: 0x0010,
|
|
3020
|
+
// Cache id=16: float a=0 b=π c=180/π → display 0..180 deg.
|
|
3021
|
+
unit: 'degrees', displayMin: 0, displayMax: 180,
|
|
3022
|
+
},
|
|
3023
|
+
'tremolo.width': {
|
|
3024
|
+
block: 'tremolo', name: 'width',
|
|
3025
|
+
displayLabel: 'Width',
|
|
3026
|
+
pidLow: 0x006a, pidHigh: 0x0011,
|
|
3027
|
+
// Cache id=17: float a=0 b=4 c=100 — internal range allows up to
|
|
3028
|
+
// display 400, but AM4-Edit's Panner Width slider visually caps at
|
|
3029
|
+
// 100. Stay at 0..100 here; widen if a future capture proves
|
|
3030
|
+
// values >100 are user-reachable.
|
|
3031
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3032
|
+
},
|
|
3033
|
+
'tremolo.center': {
|
|
3034
|
+
block: 'tremolo', name: 'center',
|
|
3035
|
+
displayLabel: 'Center',
|
|
3036
|
+
pidLow: 0x006a, pidHigh: 0x0012,
|
|
3037
|
+
// Cache id=18: float a=-1 b=1 c=100 → display -100..+100. Panner
|
|
3038
|
+
// center-pan position; 0 = dead center, ±100 = full L/R.
|
|
3039
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
3040
|
+
},
|
|
3041
|
+
'tremolo.ducking': {
|
|
3042
|
+
block: 'tremolo', name: 'ducking',
|
|
3043
|
+
displayLabel: 'Ducking',
|
|
3044
|
+
pidLow: 0x006a, pidHigh: 0x0018,
|
|
3045
|
+
// Cache id=24: float a=0 b=1 c=10 → display 0..10.
|
|
3046
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
3047
|
+
},
|
|
3048
|
+
// HW-037 (Session 35, 2026-04-29): Enhancer Config-page knobs from
|
|
3049
|
+
// session-33-enhancer-extended.pcapng + paired AM4-Edit screenshot.
|
|
3050
|
+
// Wire-verified on a Modern enhancer at level=-6 dB / width=33% /
|
|
3051
|
+
// depth=11% / low_cut=22.2 Hz / high_cut=6500 Hz. Level is the
|
|
3052
|
+
// universal pidHigh=0x0000 out-of-band pattern (no cache record);
|
|
3053
|
+
// width/depth/low_cut/high_cut are mirrored from CACHE_PARAMS so
|
|
3054
|
+
// the type-check picks them up.
|
|
3055
|
+
'enhancer.level': {
|
|
3056
|
+
block: 'enhancer', name: 'level',
|
|
3057
|
+
pidLow: 0x007a, pidHigh: 0x0000,
|
|
3058
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3059
|
+
},
|
|
3060
|
+
'enhancer.width': {
|
|
3061
|
+
block: 'enhancer', name: 'width',
|
|
3062
|
+
displayLabel: 'Width',
|
|
3063
|
+
pidLow: 0x007a, pidHigh: 0x000a,
|
|
3064
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3065
|
+
},
|
|
3066
|
+
'enhancer.depth': {
|
|
3067
|
+
block: 'enhancer', name: 'depth',
|
|
3068
|
+
displayLabel: 'Depth',
|
|
3069
|
+
pidLow: 0x007a, pidHigh: 0x000b,
|
|
3070
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3071
|
+
},
|
|
3072
|
+
'enhancer.low_cut': {
|
|
3073
|
+
block: 'enhancer', name: 'low_cut',
|
|
3074
|
+
displayLabel: 'Low Cut',
|
|
3075
|
+
pidLow: 0x007a, pidHigh: 0x000c,
|
|
3076
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
3077
|
+
},
|
|
3078
|
+
'enhancer.high_cut': {
|
|
3079
|
+
block: 'enhancer', name: 'high_cut',
|
|
3080
|
+
displayLabel: 'High Cut',
|
|
3081
|
+
pidLow: 0x007a, pidHigh: 0x000d,
|
|
3082
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
3083
|
+
},
|
|
3084
|
+
// HW-024 (Session 30 cont 3) finding F1 — `enhancer.mix` is a phantom
|
|
3085
|
+
// register on the AM4 hardware display. The Enhancer block exposes
|
|
3086
|
+
// Width / Phase Invert / Pan Left / Pan Right / Balance / Level on
|
|
3087
|
+
// its UI pages — no Mix knob anywhere. Wire writes still ack (the
|
|
3088
|
+
// SET_PARAM goes through and the firmware accepts it), but the
|
|
3089
|
+
// parameter likely has no audible effect. Cache id=1 has the same
|
|
3090
|
+
// signature as every other block's `mix` (percent, c=100), which is
|
|
3091
|
+
// why P1-010 Session B registered it via the universal Mix-Page rule.
|
|
3092
|
+
// Keep registered for now but treat as "wire-acked, no observed
|
|
3093
|
+
// hardware effect" — pending an audio-effect spot-check (queued
|
|
3094
|
+
// under HW-032 follow-ups).
|
|
3095
|
+
'enhancer.mix': {
|
|
3096
|
+
block: 'enhancer', name: 'mix',
|
|
3097
|
+
pidLow: 0x007a, pidHigh: 0x0001,
|
|
3098
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3099
|
+
},
|
|
3100
|
+
// HW-024 (Session 30 cont 3): wire-verified — type "Classic" displayed
|
|
3101
|
+
// exactly. AM4-Edit labels this "Mode" on the dropdown but we keep
|
|
3102
|
+
// `type` for consistency across blocks.
|
|
3103
|
+
'enhancer.type': {
|
|
3104
|
+
block: 'enhancer', name: 'type',
|
|
3105
|
+
pidLow: 0x007a, pidHigh: 0x000e,
|
|
3106
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
3107
|
+
enumValues: ENHANCER_TYPES_VALUES,
|
|
3108
|
+
},
|
|
3109
|
+
// HW-024 (Session 30 cont 3): wire-verified — Modern Gate displayed
|
|
3110
|
+
// exactly. Round 4 first-time test for this block type.
|
|
3111
|
+
'gate.type': {
|
|
3112
|
+
block: 'gate', name: 'type',
|
|
3113
|
+
pidLow: 0x0092, pidHigh: 0x0013,
|
|
3114
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
3115
|
+
enumValues: GATE_TYPES_VALUES,
|
|
3116
|
+
},
|
|
3117
|
+
// HW-035 (Session 34, 2026-04-26): slot-Gate first-page knobs on a
|
|
3118
|
+
// Modern Gate type — `session-34-slotgate-extended.pcapng`. Wire-
|
|
3119
|
+
// verified at Threshold=-22 dB / Attack=1 ms / Hold=80 ms /
|
|
3120
|
+
// Release=90 ms / Attenuation=-33 dB / Sidechain=INPUT 1 / Level=
|
|
3121
|
+
// 12 dB. Threshold/Attack/Hold/Release/Attenuation are mirrored
|
|
3122
|
+
// from CACHE_PARAMS. Level (pidHigh=0x0000) follows the universal
|
|
3123
|
+
// out-of-band Level pattern. Sidechain (pidHigh=0x000f) is a
|
|
3124
|
+
// 4-entry enum sourced directly from cache id=15 enum strings
|
|
3125
|
+
// (BLOCK L+R / INPUT 1 / BLOCK L / BLOCK R) — hand-authored
|
|
3126
|
+
// because the cache generator only attaches the block-wide
|
|
3127
|
+
// GATE_TYPES_VALUES import.
|
|
3128
|
+
'gate.level': {
|
|
3129
|
+
block: 'gate', name: 'level',
|
|
3130
|
+
pidLow: 0x0092, pidHigh: 0x0000,
|
|
3131
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3132
|
+
},
|
|
3133
|
+
'gate.threshold': {
|
|
3134
|
+
block: 'gate', name: 'threshold',
|
|
3135
|
+
displayLabel: 'Threshold',
|
|
3136
|
+
pidLow: 0x0092, pidHigh: 0x000a,
|
|
3137
|
+
unit: 'db', displayMin: -100, displayMax: 0,
|
|
3138
|
+
},
|
|
3139
|
+
'gate.attack': {
|
|
3140
|
+
block: 'gate', name: 'attack',
|
|
3141
|
+
displayLabel: 'Attack',
|
|
3142
|
+
pidLow: 0x0092, pidHigh: 0x000b,
|
|
3143
|
+
unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10',
|
|
3144
|
+
},
|
|
3145
|
+
'gate.hold': {
|
|
3146
|
+
block: 'gate', name: 'hold',
|
|
3147
|
+
displayLabel: 'Hold',
|
|
3148
|
+
pidLow: 0x0092, pidHigh: 0x000c,
|
|
3149
|
+
unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10',
|
|
3150
|
+
},
|
|
3151
|
+
'gate.release': {
|
|
3152
|
+
block: 'gate', name: 'release',
|
|
3153
|
+
displayLabel: 'Release',
|
|
3154
|
+
pidLow: 0x0092, pidHigh: 0x000d,
|
|
3155
|
+
unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10',
|
|
3156
|
+
},
|
|
3157
|
+
'gate.sidechain': {
|
|
3158
|
+
block: 'gate', name: 'sidechain',
|
|
3159
|
+
displayLabel: 'Sidechain',
|
|
3160
|
+
pidLow: 0x0092, pidHigh: 0x000f,
|
|
3161
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
3162
|
+
enumValues: { 0: 'BLOCK L+R', 1: 'INPUT 1', 2: 'BLOCK L', 3: 'BLOCK R' },
|
|
3163
|
+
},
|
|
3164
|
+
'gate.attenuation': {
|
|
3165
|
+
block: 'gate', name: 'attenuation',
|
|
3166
|
+
displayLabel: 'Attenuation',
|
|
3167
|
+
pidLow: 0x0092, pidHigh: 0x0014,
|
|
3168
|
+
unit: 'db', displayMin: -80, displayMax: 0,
|
|
3169
|
+
},
|
|
3170
|
+
// HW-043 partial (Session 44, 2026-05-02) — slot-Gate Modern Expander
|
|
3171
|
+
// Expert-Edit page from `session-44-gate-expert.{pcapng,png}`. 7 new
|
|
3172
|
+
// first-page registrations: ratio, sidechain_low_cut, sidechain_high_cut,
|
|
3173
|
+
// bypass_mode, knee_type, detector_type, mix-phantom. Modern Expander
|
|
3174
|
+
// exposes Ratio at 0x000e (replaces the fixed Attenuation that Modern
|
|
3175
|
+
// Gate exposes at 0x0014); same firmware register surface, different
|
|
3176
|
+
// type-dependent UI. Knee_type vs detector_type pidHigh assignment
|
|
3177
|
+
// disambiguated via single-knob-isolation capture
|
|
3178
|
+
// `session-46-gate-knee-isolation.pcapng` — 0x0016 moved (knee_type),
|
|
3179
|
+
// 0x0015 stayed (detector_type by elimination). Ratio range 1..20
|
|
3180
|
+
// founder-confirmed at the device. See docs/audit-output/gate.md for
|
|
3181
|
+
// the full audit table.
|
|
3182
|
+
'gate.ratio': {
|
|
3183
|
+
block: 'gate', name: 'ratio',
|
|
3184
|
+
displayLabel: 'Ratio',
|
|
3185
|
+
pidLow: 0x0092, pidHigh: 0x000e,
|
|
3186
|
+
unit: 'ratio', displayMin: 1, displayMax: 20, scaling: 'log10',
|
|
3187
|
+
},
|
|
3188
|
+
'gate.sidechain_low_cut': {
|
|
3189
|
+
block: 'gate', name: 'sidechain_low_cut',
|
|
3190
|
+
displayLabel: 'Low Cut',
|
|
3191
|
+
pidLow: 0x0092, pidHigh: 0x0010,
|
|
3192
|
+
unit: 'hz', displayMin: 20, displayMax: 2000,
|
|
3193
|
+
},
|
|
3194
|
+
'gate.sidechain_high_cut': {
|
|
3195
|
+
block: 'gate', name: 'sidechain_high_cut',
|
|
3196
|
+
displayLabel: 'High Cut',
|
|
3197
|
+
pidLow: 0x0092, pidHigh: 0x0011,
|
|
3198
|
+
unit: 'hz', displayMin: 200, displayMax: 20000,
|
|
3199
|
+
},
|
|
3200
|
+
'gate.bypass_mode': {
|
|
3201
|
+
block: 'gate', name: 'bypass_mode',
|
|
3202
|
+
pidLow: 0x0092, pidHigh: 0x0004,
|
|
3203
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3204
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
3205
|
+
},
|
|
3206
|
+
// Detector type at 0x0015: wire 0 displayed as "RMS" in Session 44
|
|
3207
|
+
// Modern Expander capture. Likely 2-entry enum {0:RMS, 1:Peak} — only
|
|
3208
|
+
// the observed entry is registered until founder confirms the full
|
|
3209
|
+
// table.
|
|
3210
|
+
'gate.detector_type': {
|
|
3211
|
+
block: 'gate', name: 'detector_type',
|
|
3212
|
+
displayLabel: 'Detector Type',
|
|
3213
|
+
pidLow: 0x0092, pidHigh: 0x0015,
|
|
3214
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3215
|
+
enumValues: { 0: 'RMS' },
|
|
3216
|
+
},
|
|
3217
|
+
// Knee type at 0x0016: wire 4 displayed as "Soft" in Session 44.
|
|
3218
|
+
// Likely 5-entry enum {0:Hard, 1:Med Hard, 2:Med, 3:Med Soft, 4:Soft}
|
|
3219
|
+
// per typical compressor/gate UX — only the observed entry is
|
|
3220
|
+
// registered until founder confirms the full table.
|
|
3221
|
+
// renamed for UI-label match (audit row: GATE 22)
|
|
3222
|
+
'gate.knee': {
|
|
3223
|
+
block: 'gate', name: 'knee',
|
|
3224
|
+
displayLabel: 'Knee',
|
|
3225
|
+
pidLow: 0x0092, pidHigh: 0x0016,
|
|
3226
|
+
unit: 'enum', displayMin: 0, displayMax: 4,
|
|
3227
|
+
enumValues: { 4: 'Soft' },
|
|
3228
|
+
},
|
|
3229
|
+
// Phantom register: AM4-Edit displays "NA" for Mix on the Gate block
|
|
3230
|
+
// (gate is a dynamics block; absorb-vs-effect doesn't apply). Wire
|
|
3231
|
+
// still ack'd but no audible effect — same status as `enhancer.mix`
|
|
3232
|
+
// (HW-024 finding F1). Registered for completeness so the agent
|
|
3233
|
+
// doesn't surface it as a tweak target on its own.
|
|
3234
|
+
'gate.mix': {
|
|
3235
|
+
block: 'gate', name: 'mix',
|
|
3236
|
+
pidLow: 0x0092, pidHigh: 0x0001,
|
|
3237
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3238
|
+
},
|
|
3239
|
+
// HW-024 (Session 30 cont 3): wire-verified — Auto-Swell displayed
|
|
3240
|
+
// exactly. Round 4 first-time test for this block type.
|
|
3241
|
+
'volpan.mode': {
|
|
3242
|
+
// Block is "Volume/Pan"; this is the Volume-vs-Auto-Swell selector.
|
|
3243
|
+
block: 'volpan', name: 'mode',
|
|
3244
|
+
pidLow: 0x0066, pidHigh: 0x000f,
|
|
3245
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3246
|
+
enumValues: VOLPAN_MODES_VALUES,
|
|
3247
|
+
},
|
|
3248
|
+
// HW-032 (Session 30 cont 8, 2026-04-25): Volume/Pan Auto-Swell
|
|
3249
|
+
// envelope params. Wire-verified at -20 dB / 300 ms on the Auto-Swell
|
|
3250
|
+
// type (`session-32-volpan-extended.pcapng`). Cache ids 16 / 17 with
|
|
3251
|
+
// c=1 (raw dB) and c=1000 (display ms) respectively. Mirrored from
|
|
3252
|
+
// CACHE_PARAMS so the type-check picks them up.
|
|
3253
|
+
'volpan.threshold': {
|
|
3254
|
+
block: 'volpan', name: 'threshold',
|
|
3255
|
+
displayLabel: 'Threshold',
|
|
3256
|
+
pidLow: 0x0066, pidHigh: 0x0010,
|
|
3257
|
+
unit: 'db', displayMin: -100, displayMax: 0,
|
|
3258
|
+
},
|
|
3259
|
+
'volpan.attack': {
|
|
3260
|
+
block: 'volpan', name: 'attack',
|
|
3261
|
+
displayLabel: 'Attack',
|
|
3262
|
+
pidLow: 0x0066, pidHigh: 0x0011,
|
|
3263
|
+
unit: 'ms', displayMin: 1, displayMax: 5000, scaling: 'log10',
|
|
3264
|
+
},
|
|
3265
|
+
// HW-032 (Session 30 cont 8, 2026-04-25): wire-verified at +12 dB on
|
|
3266
|
+
// an Auto-Swell Volume/Pan — `session-32-volpan-extended.pcapng`.
|
|
3267
|
+
// Follows the universal pidHigh=0x0000 Level pattern.
|
|
3268
|
+
'volpan.level': {
|
|
3269
|
+
block: 'volpan', name: 'level',
|
|
3270
|
+
pidLow: 0x0066, pidHigh: 0x0000,
|
|
3271
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3272
|
+
},
|
|
3273
|
+
// HW-043 partial (Session 44, 2026-05-02) — Volume/Pan Expert-Edit
|
|
3274
|
+
// captures from `session-44-volpan-expert-{volume,autoswell}.{pcapng,png}`.
|
|
3275
|
+
// Confirmed type-dependent UI on volpan: Volume mode exposes
|
|
3276
|
+
// volume/pan_l/pan_r at 0x000a/c/d; Auto-Swell mode exposes
|
|
3277
|
+
// release/hysteresis at 0x0012/0x0013. Both modes share level/balance/
|
|
3278
|
+
// mix/bypass_mode/taper/input_select at the same pidHighs. Type-
|
|
3279
|
+
// agnostic firmware addressing — same pattern as gate. Hysteresis
|
|
3280
|
+
// range 0..12 dB founder-confirmed at the device. See
|
|
3281
|
+
// docs/audit-output/volpan-{volume,autoswell}.md for the full audit
|
|
3282
|
+
// tables.
|
|
3283
|
+
'volpan.volume': {
|
|
3284
|
+
block: 'volpan', name: 'volume',
|
|
3285
|
+
displayLabel: 'Volume',
|
|
3286
|
+
pidLow: 0x0066, pidHigh: 0x000a,
|
|
3287
|
+
unit: 'knob_0_10', displayMin: 0, displayMax: 10,
|
|
3288
|
+
},
|
|
3289
|
+
// renamed for UI-label match (audit row: VOLUME 12)
|
|
3290
|
+
'volpan.pan_left': {
|
|
3291
|
+
block: 'volpan', name: 'pan_left',
|
|
3292
|
+
displayLabel: 'Pan Left',
|
|
3293
|
+
pidLow: 0x0066, pidHigh: 0x000c,
|
|
3294
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
3295
|
+
},
|
|
3296
|
+
// renamed for UI-label match (audit row: VOLUME 13)
|
|
3297
|
+
'volpan.pan_right': {
|
|
3298
|
+
block: 'volpan', name: 'pan_right',
|
|
3299
|
+
displayLabel: 'Pan Right',
|
|
3300
|
+
pidLow: 0x0066, pidHigh: 0x000d,
|
|
3301
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
3302
|
+
},
|
|
3303
|
+
// Taper at 0x000b: shared register across Volume + Auto-Swell modes
|
|
3304
|
+
// with type-aware enum entries. Volume mode wire=5 → "Log 50";
|
|
3305
|
+
// Auto-Swell wire=1 → "Log 30A". Only observed entries registered
|
|
3306
|
+
// until founder confirms the full table.
|
|
3307
|
+
'volpan.taper': {
|
|
3308
|
+
block: 'volpan', name: 'taper',
|
|
3309
|
+
displayLabel: 'Taper',
|
|
3310
|
+
pidLow: 0x0066, pidHigh: 0x000b,
|
|
3311
|
+
unit: 'enum', displayMin: 0, displayMax: 10,
|
|
3312
|
+
enumValues: { 1: 'Log 30A', 5: 'Log 50' },
|
|
3313
|
+
},
|
|
3314
|
+
// Input Select at 0x000e: at minimum 3 entries observed across both
|
|
3315
|
+
// mode captures (wire=0 → "Stereo", wire=2 → "Right Only"). Index 1
|
|
3316
|
+
// unobserved but plausibly "Left Only". Full enum table needs founder
|
|
3317
|
+
// confirmation; registered with the partial mapping.
|
|
3318
|
+
'volpan.input_select': {
|
|
3319
|
+
block: 'volpan', name: 'input_select',
|
|
3320
|
+
displayLabel: 'Input Select',
|
|
3321
|
+
pidLow: 0x0066, pidHigh: 0x000e,
|
|
3322
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
3323
|
+
enumValues: { 0: 'Stereo', 2: 'Right Only' },
|
|
3324
|
+
},
|
|
3325
|
+
'volpan.bypass_mode': {
|
|
3326
|
+
block: 'volpan', name: 'bypass_mode',
|
|
3327
|
+
pidLow: 0x0066, pidHigh: 0x0004,
|
|
3328
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3329
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
3330
|
+
},
|
|
3331
|
+
// Auto-Swell-mode envelope params. Release mirrors attack at 0x0011
|
|
3332
|
+
// (same ms-stored-as-seconds + log10 scaling). Hysteresis is a dB
|
|
3333
|
+
// knob unique to Auto-Swell — no Volume-mode equivalent. Range
|
|
3334
|
+
// 0..12 dB founder-confirmed.
|
|
3335
|
+
'volpan.release': {
|
|
3336
|
+
block: 'volpan', name: 'release',
|
|
3337
|
+
displayLabel: 'Release',
|
|
3338
|
+
pidLow: 0x0066, pidHigh: 0x0012,
|
|
3339
|
+
unit: 'ms', displayMin: 1, displayMax: 5000, scaling: 'log10',
|
|
3340
|
+
},
|
|
3341
|
+
'volpan.hysteresis': {
|
|
3342
|
+
block: 'volpan', name: 'hysteresis',
|
|
3343
|
+
displayLabel: 'Hysteresis',
|
|
3344
|
+
pidLow: 0x0066, pidHigh: 0x0013,
|
|
3345
|
+
unit: 'db', displayMin: 0, displayMax: 12,
|
|
3346
|
+
},
|
|
3347
|
+
// Phantom register: AM4-Edit displays "NA" for Mix on Volume/Pan
|
|
3348
|
+
// (volpan is a signal-flow / routing block; absorb-vs-effect doesn't
|
|
3349
|
+
// apply). Wire still ack'd but no audible effect — same status as
|
|
3350
|
+
// `gate.mix` and `enhancer.mix`.
|
|
3351
|
+
'volpan.mix': {
|
|
3352
|
+
block: 'volpan', name: 'mix',
|
|
3353
|
+
pidLow: 0x0066, pidHigh: 0x0001,
|
|
3354
|
+
unit: 'percent', displayMin: 0, displayMax: 100,
|
|
3355
|
+
},
|
|
3356
|
+
// Input Noise Gate (HW-032, Session 30 cont 8). Always-on input stage
|
|
3357
|
+
// (per docs/BLOCK-PARAMS.md "Input Noise Gate (global, not a block
|
|
3358
|
+
// slot)"); not placeable in any of the 4 effect slots. Distinct from
|
|
3359
|
+
// the slot-placeable Gate effect block (pidLow=0x0092).
|
|
3360
|
+
// Wire-verified on `session-32-gate-extended.pcapng` against the
|
|
3361
|
+
// AM4-Edit "In-Gate" tab on Z04. Captured 4 distinct registers
|
|
3362
|
+
// (0x00 / 0x0a / 0x0c / 0x0f); `level` is the only one with a
|
|
3363
|
+
// unit-clean encoding so far. Threshold (0x0a, internal 0..1 →
|
|
3364
|
+
// display -100..0 dB), Release (0x0c, curve TBD) and Type (0x0f,
|
|
3365
|
+
// enum: Classic / Intelligent / Noise Reducer per the manual) need
|
|
3366
|
+
// a Unit-extension pass plus a type-walk capture and are queued as
|
|
3367
|
+
// HW-034. Pidlow 0x0025 has no cache backing — input gate isn't in
|
|
3368
|
+
// any of the 17 cache sub-blocks (none of the section 2 candidates
|
|
3369
|
+
// match its 4-register footprint).
|
|
3370
|
+
'ingate.level': {
|
|
3371
|
+
block: 'ingate', name: 'level',
|
|
3372
|
+
pidLow: 0x0025, pidHigh: 0x0000,
|
|
3373
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3374
|
+
},
|
|
3375
|
+
// HW-036 (Session 34, 2026-04-26): In-Gate Config-page residuals
|
|
3376
|
+
// from `session-34-inputgate-extended.pcapng`. Wire-verified at
|
|
3377
|
+
// Threshold=-44 dB / Release=60 ms / Type=Intelligent on the
|
|
3378
|
+
// In-Gate tab. All three were the HW-032 residuals queued for
|
|
3379
|
+
// unit + type-walk. Threshold curve is dB-direct (not the 0..1
|
|
3380
|
+
// normalized hypothesis from HW-032 — hardware writes raw dB).
|
|
3381
|
+
// Release uses the same display=internal × 1000 ms scaling as
|
|
3382
|
+
// every other release-style param. Type enum order matches
|
|
3383
|
+
// BLOCK-PARAMS.md (Classic Expander / Intelligent / Noise
|
|
3384
|
+
// Reducer); wire confirmed index 1 = Intelligent. No cache
|
|
3385
|
+
// backing — all hand-authored.
|
|
3386
|
+
'ingate.threshold': {
|
|
3387
|
+
block: 'ingate', name: 'threshold',
|
|
3388
|
+
displayLabel: 'Threshold',
|
|
3389
|
+
pidLow: 0x0025, pidHigh: 0x000a,
|
|
3390
|
+
unit: 'db', displayMin: -100, displayMax: 0,
|
|
3391
|
+
},
|
|
3392
|
+
'ingate.release': {
|
|
3393
|
+
block: 'ingate', name: 'release',
|
|
3394
|
+
displayLabel: 'Release',
|
|
3395
|
+
pidLow: 0x0025, pidHigh: 0x000c,
|
|
3396
|
+
unit: 'ms', displayMin: 0, displayMax: 1000,
|
|
3397
|
+
},
|
|
3398
|
+
'ingate.type': {
|
|
3399
|
+
block: 'ingate', name: 'type',
|
|
3400
|
+
displayLabel: 'Gate Type',
|
|
3401
|
+
pidLow: 0x0025, pidHigh: 0x000f,
|
|
3402
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
3403
|
+
enumValues: { 0: 'Classic Expander', 1: 'Intelligent', 2: 'Noise Reducer' },
|
|
3404
|
+
},
|
|
3405
|
+
// Universal per-block output Balance (Session 28 cont — P1-010
|
|
3406
|
+
// second unit-extension pass, introduced `bipolar_percent`).
|
|
3407
|
+
// Blocks Guide line 347: "Every block outputs both left and right
|
|
3408
|
+
// signals. As you adjust to the left or right, the opposite channel
|
|
3409
|
+
// [is reduced]." Confirmed as a universal block-level parameter at
|
|
3410
|
+
// lines 899 (Amp), 1233 (Chorus), 1430 (Flanger), 1733 (Delay),
|
|
3411
|
+
// 1883 (Phaser). Cache signature is identical across all 15
|
|
3412
|
+
// confirmed blocks: id=2, a=-1, b=1, c=100 (display = internal ×
|
|
3413
|
+
// 100, so -100..+100%).
|
|
3414
|
+
//
|
|
3415
|
+
// Hardware-display visibility per block (HW-014 + HW-024 finding F2):
|
|
3416
|
+
// visible: enhancer.balance (HW-024 at -33%), geq.balance (HW-014
|
|
3417
|
+
// at -67), volpan.balance is type-specific to the Pan range —
|
|
3418
|
+
// classified as an effect-block balance below.
|
|
3419
|
+
// hidden (wire-acked, no display readout): amp / compressor /
|
|
3420
|
+
// reverb / delay / chorus / flanger / phaser / wah / tremolo /
|
|
3421
|
+
// filter / drive / gate / volpan.
|
|
3422
|
+
// Visibility is block-type-dependent — the enhancer is a stereo
|
|
3423
|
+
// utility block where balance/pan controls are core, while effect
|
|
3424
|
+
// blocks treat balance as a hidden output mixer. Hidden writes still
|
|
3425
|
+
// affect the stereo image at the audio path (per Blocks Guide line
|
|
3426
|
+
// 347 — universal at the firmware level); audio-effect spot-check
|
|
3427
|
+
// queued under HW-032.
|
|
3428
|
+
'amp.balance': { block: 'amp', name: 'balance', pidLow: 0x003a, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3429
|
+
'compressor.balance': { block: 'compressor', name: 'balance', pidLow: 0x002e, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3430
|
+
'geq.balance': { block: 'geq', name: 'balance', pidLow: 0x0032, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3431
|
+
'reverb.balance': { block: 'reverb', name: 'balance', pidLow: 0x0042, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3432
|
+
'delay.balance': { block: 'delay', name: 'balance', pidLow: 0x0046, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3433
|
+
'chorus.balance': { block: 'chorus', name: 'balance', pidLow: 0x004e, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3434
|
+
'flanger.balance': { block: 'flanger', name: 'balance', pidLow: 0x0052, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3435
|
+
'phaser.balance': { block: 'phaser', name: 'balance', pidLow: 0x005a, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3436
|
+
'wah.balance': { block: 'wah', name: 'balance', pidLow: 0x005e, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3437
|
+
'tremolo.balance': { block: 'tremolo', name: 'balance', pidLow: 0x006a, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3438
|
+
'filter.balance': { block: 'filter', name: 'balance', pidLow: 0x0072, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3439
|
+
'drive.balance': { block: 'drive', name: 'balance', pidLow: 0x0076, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3440
|
+
'enhancer.balance': { block: 'enhancer', name: 'balance', pidLow: 0x007a, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3441
|
+
'gate.balance': { block: 'gate', name: 'balance', pidLow: 0x0092, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3442
|
+
'volpan.balance': { block: 'volpan', name: 'balance', pidLow: 0x0066, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3443
|
+
// HW-040 (Session 36, 2026-04-29): peq + rotary + geq + wah balance
|
|
3444
|
+
// mirrors. Plus the new-block universal mix entries.
|
|
3445
|
+
'peq.balance': { block: 'peq', name: 'balance', pidLow: 0x0036, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3446
|
+
'rotary.balance': { block: 'rotary', name: 'balance', pidLow: 0x0056, pidHigh: 0x0002, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3447
|
+
'wah.mix': { block: 'wah', name: 'mix', pidLow: 0x005e, pidHigh: 0x0001, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3448
|
+
'peq.mix': { block: 'peq', name: 'mix', pidLow: 0x0036, pidHigh: 0x0001, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3449
|
+
'rotary.mix': { block: 'rotary', name: 'mix', pidLow: 0x0056, pidHigh: 0x0001, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3450
|
+
// GEQ Expert-Edit 10-band mirrors + master_q.
|
|
3451
|
+
'geq.mix': { block: 'geq', name: 'mix', pidLow: 0x0032, pidHigh: 0x0001, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3452
|
+
'geq.band_1': { block: 'geq', name: 'band_1', displayLabel: '31', pidLow: 0x0032, pidHigh: 0x000a, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3453
|
+
'geq.band_2': { block: 'geq', name: 'band_2', displayLabel: '63', pidLow: 0x0032, pidHigh: 0x000b, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3454
|
+
'geq.band_3': { block: 'geq', name: 'band_3', displayLabel: '125', pidLow: 0x0032, pidHigh: 0x000c, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3455
|
+
'geq.band_4': { block: 'geq', name: 'band_4', displayLabel: '250', pidLow: 0x0032, pidHigh: 0x000d, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3456
|
+
'geq.band_5': { block: 'geq', name: 'band_5', displayLabel: '500', pidLow: 0x0032, pidHigh: 0x000e, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3457
|
+
'geq.band_6': { block: 'geq', name: 'band_6', displayLabel: '1k', pidLow: 0x0032, pidHigh: 0x000f, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3458
|
+
'geq.band_7': { block: 'geq', name: 'band_7', displayLabel: '2k', pidLow: 0x0032, pidHigh: 0x0010, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3459
|
+
'geq.band_8': { block: 'geq', name: 'band_8', displayLabel: '4k', pidLow: 0x0032, pidHigh: 0x0011, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3460
|
+
'geq.band_9': { block: 'geq', name: 'band_9', displayLabel: '8k', pidLow: 0x0032, pidHigh: 0x0012, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3461
|
+
'geq.band_10': { block: 'geq', name: 'band_10', displayLabel: '16k', pidLow: 0x0032, pidHigh: 0x0013, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3462
|
+
'geq.master_q': { block: 'geq', name: 'master_q', displayLabel: 'Master Q', pidLow: 0x0032, pidHigh: 0x0015, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3463
|
+
// PEQ 5-channel parametric EQ mirrors (frequency / Q / gain × 5 channels).
|
|
3464
|
+
'peq.channel_1_frequency': { block: 'peq', name: 'channel_1_frequency', displayLabel: 'Freq 1', pidLow: 0x0036, pidHigh: 0x000a, unit: 'hz', displayMin: 20, displayMax: 2000 },
|
|
3465
|
+
'peq.channel_2_frequency': { block: 'peq', name: 'channel_2_frequency', displayLabel: 'Freq 2', pidLow: 0x0036, pidHigh: 0x000b, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
3466
|
+
'peq.channel_3_frequency': { block: 'peq', name: 'channel_3_frequency', displayLabel: 'Freq 3', pidLow: 0x0036, pidHigh: 0x000c, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
3467
|
+
'peq.channel_4_frequency': { block: 'peq', name: 'channel_4_frequency', displayLabel: 'Freq 4', pidLow: 0x0036, pidHigh: 0x000d, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
3468
|
+
'peq.channel_5_frequency': { block: 'peq', name: 'channel_5_frequency', displayLabel: 'Freq 5', pidLow: 0x0036, pidHigh: 0x000e, unit: 'hz', displayMin: 200, displayMax: 20000 },
|
|
3469
|
+
'peq.channel_1_q': { block: 'peq', name: 'channel_1_q', displayLabel: 'Q1', pidLow: 0x0036, pidHigh: 0x000f, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3470
|
+
'peq.channel_2_q': { block: 'peq', name: 'channel_2_q', displayLabel: 'Q2', pidLow: 0x0036, pidHigh: 0x0010, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3471
|
+
'peq.channel_3_q': { block: 'peq', name: 'channel_3_q', displayLabel: 'Q3', pidLow: 0x0036, pidHigh: 0x0011, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3472
|
+
'peq.channel_4_q': { block: 'peq', name: 'channel_4_q', displayLabel: 'Q4', pidLow: 0x0036, pidHigh: 0x0012, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3473
|
+
'peq.channel_5_q': { block: 'peq', name: 'channel_5_q', displayLabel: 'Q5', pidLow: 0x0036, pidHigh: 0x0013, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3474
|
+
'peq.channel_1_gain': { block: 'peq', name: 'channel_1_gain', displayLabel: 'Gain 1', pidLow: 0x0036, pidHigh: 0x0014, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3475
|
+
'peq.channel_2_gain': { block: 'peq', name: 'channel_2_gain', displayLabel: 'Gain 2', pidLow: 0x0036, pidHigh: 0x0015, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3476
|
+
'peq.channel_3_gain': { block: 'peq', name: 'channel_3_gain', displayLabel: 'Gain 3', pidLow: 0x0036, pidHigh: 0x0016, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3477
|
+
'peq.channel_4_gain': { block: 'peq', name: 'channel_4_gain', displayLabel: 'Gain 4', pidLow: 0x0036, pidHigh: 0x0017, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3478
|
+
'peq.channel_5_gain': { block: 'peq', name: 'channel_5_gain', displayLabel: 'Gain 5', pidLow: 0x0036, pidHigh: 0x0018, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3479
|
+
// BK-035 audit (Session 36 cont, 2026-04-29): PEQ Bypass Mode +
|
|
3480
|
+
// 5 per-channel Type enums + 5 per-channel Solo toggles. Founder
|
|
3481
|
+
// confirmed labels from `session-40-peq-expert.png`. Cache provides
|
|
3482
|
+
// each channel's Type enum entries (different shapes per channel —
|
|
3483
|
+
// e.g. Channel 3 only has [Peaking, Peaking 2] while Channels 1/5
|
|
3484
|
+
// have the full [Shelving, Peaking, Blocking, Shelving 2, Peaking 2]).
|
|
3485
|
+
'peq.bypass_mode': {
|
|
3486
|
+
block: 'peq', name: 'bypass_mode',
|
|
3487
|
+
pidLow: 0x0036, pidHigh: 0x0004,
|
|
3488
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3489
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
3490
|
+
},
|
|
3491
|
+
'peq.channel_1_type': {
|
|
3492
|
+
block: 'peq', name: 'channel_1_type',
|
|
3493
|
+
displayLabel: 'Type 1',
|
|
3494
|
+
pidLow: 0x0036, pidHigh: 0x0019,
|
|
3495
|
+
unit: 'enum', displayMin: 0, displayMax: 4,
|
|
3496
|
+
enumValues: { 0: 'Shelving', 1: 'Peaking', 2: 'Blocking', 3: 'Shelving 2', 4: 'Peaking 2' },
|
|
3497
|
+
},
|
|
3498
|
+
'peq.channel_2_type': {
|
|
3499
|
+
block: 'peq', name: 'channel_2_type',
|
|
3500
|
+
displayLabel: 'Type 2',
|
|
3501
|
+
pidLow: 0x0036, pidHigh: 0x001a,
|
|
3502
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
3503
|
+
enumValues: { 0: 'Peaking', 1: 'Shelving', 2: 'Shelving 2', 3: 'Peaking 2' },
|
|
3504
|
+
},
|
|
3505
|
+
'peq.channel_3_type': {
|
|
3506
|
+
block: 'peq', name: 'channel_3_type',
|
|
3507
|
+
displayLabel: 'Type 3',
|
|
3508
|
+
pidLow: 0x0036, pidHigh: 0x001b,
|
|
3509
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3510
|
+
enumValues: { 0: 'Peaking', 1: 'Peaking 2' },
|
|
3511
|
+
},
|
|
3512
|
+
'peq.channel_4_type': {
|
|
3513
|
+
block: 'peq', name: 'channel_4_type',
|
|
3514
|
+
displayLabel: 'Type 4',
|
|
3515
|
+
pidLow: 0x0036, pidHigh: 0x001c,
|
|
3516
|
+
unit: 'enum', displayMin: 0, displayMax: 3,
|
|
3517
|
+
enumValues: { 0: 'Peaking', 1: 'Shelving', 2: 'Shelving 2', 3: 'Peaking 2' },
|
|
3518
|
+
},
|
|
3519
|
+
'peq.channel_5_type': {
|
|
3520
|
+
block: 'peq', name: 'channel_5_type',
|
|
3521
|
+
displayLabel: 'Type 5',
|
|
3522
|
+
pidLow: 0x0036, pidHigh: 0x001d,
|
|
3523
|
+
unit: 'enum', displayMin: 0, displayMax: 4,
|
|
3524
|
+
enumValues: { 0: 'Shelving', 1: 'Peaking', 2: 'Blocking', 3: 'Shelving 2', 4: 'Peaking 2' },
|
|
3525
|
+
},
|
|
3526
|
+
'peq.channel_1_solo': {
|
|
3527
|
+
block: 'peq', name: 'channel_1_solo',
|
|
3528
|
+
displayLabel: 'Solo',
|
|
3529
|
+
pidLow: 0x0036, pidHigh: 0x001e,
|
|
3530
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3531
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
3532
|
+
},
|
|
3533
|
+
'peq.channel_2_solo': {
|
|
3534
|
+
block: 'peq', name: 'channel_2_solo',
|
|
3535
|
+
displayLabel: 'Solo',
|
|
3536
|
+
pidLow: 0x0036, pidHigh: 0x001f,
|
|
3537
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3538
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
3539
|
+
},
|
|
3540
|
+
'peq.channel_3_solo': {
|
|
3541
|
+
block: 'peq', name: 'channel_3_solo',
|
|
3542
|
+
displayLabel: 'Solo',
|
|
3543
|
+
pidLow: 0x0036, pidHigh: 0x0020,
|
|
3544
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3545
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
3546
|
+
},
|
|
3547
|
+
'peq.channel_4_solo': {
|
|
3548
|
+
block: 'peq', name: 'channel_4_solo',
|
|
3549
|
+
displayLabel: 'Solo',
|
|
3550
|
+
pidLow: 0x0036, pidHigh: 0x0021,
|
|
3551
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3552
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
3553
|
+
},
|
|
3554
|
+
'peq.channel_5_solo': {
|
|
3555
|
+
block: 'peq', name: 'channel_5_solo',
|
|
3556
|
+
displayLabel: 'Solo',
|
|
3557
|
+
pidLow: 0x0036, pidHigh: 0x0022,
|
|
3558
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3559
|
+
enumValues: { 0: 'OFF', 1: 'ON' },
|
|
3560
|
+
},
|
|
3561
|
+
// BK-035 audit (Session 36 cont, 2026-04-29): GEQ Bypass Mode added.
|
|
3562
|
+
// GEQ Level was missing too — added via paramNames.ts auto-gen path.
|
|
3563
|
+
'geq.bypass_mode': {
|
|
3564
|
+
block: 'geq', name: 'bypass_mode',
|
|
3565
|
+
pidLow: 0x0032, pidHigh: 0x0004,
|
|
3566
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3567
|
+
enumValues: { 0: 'Thru', 1: 'Mute' },
|
|
3568
|
+
},
|
|
3569
|
+
'geq.level': { block: 'geq', name: 'level', pidLow: 0x0032, pidHigh: 0x0000, unit: 'db', displayMin: -80, displayMax: 20 },
|
|
3570
|
+
// Rotary cabinet sim mirrors.
|
|
3571
|
+
// BK-035 audit (Session 36 cont, 2026-04-29): rotary block had two
|
|
3572
|
+
// mis-registered pidHighs (drive ↔ mic_spacing swap) plus 5 unregistered
|
|
3573
|
+
// user-facing knobs that the founder's screenshot dictation surfaced:
|
|
3574
|
+
// id 10 (was `drive` count 0..10) → `rate` (Hz, Leslie speed knob —
|
|
3575
|
+
// **BK-035 headline gap closed**)
|
|
3576
|
+
// id 21 (was `mic_spacing`) → `drive` (knob_0_10 0.5..500)
|
|
3577
|
+
// id 16 (NEW) → `mic_spacing` (π-encoded scale,
|
|
3578
|
+
// unit `rotary_mic_spacing`, 0..100)
|
|
3579
|
+
// id 0 (NEW) → `level` (db, -80..20)
|
|
3580
|
+
// id 4 (NEW) → `bypass_mode` (enum, hand-authored)
|
|
3581
|
+
// id 14 (NEW) → `tempo` (TEMPO_DIVISIONS_VALUES, hand-authored)
|
|
3582
|
+
// id 20 (NEW) → `stereo_spread` (bipolar_percent -200..200)
|
|
3583
|
+
// id 23 (NEW) → `input_select` (enum [L+R/LEFT/RIGHT], hand-authored)
|
|
3584
|
+
'rotary.level': { block: 'rotary', name: 'level', pidLow: 0x0056, pidHigh: 0x0000, unit: 'db', displayMin: -80, displayMax: 20 },
|
|
3585
|
+
'rotary.bypass_mode': {
|
|
3586
|
+
block: 'rotary', name: 'bypass_mode',
|
|
3587
|
+
pidLow: 0x0056, pidHigh: 0x0004,
|
|
3588
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
3589
|
+
enumValues: { 0: 'Thru', 1: 'Mute FX Out', 2: 'Mute Out' },
|
|
3590
|
+
},
|
|
3591
|
+
'rotary.rate': { block: 'rotary', name: 'rate', displayLabel: 'Rate', pidLow: 0x0056, pidHigh: 0x000a, unit: 'hz', displayMin: 0, displayMax: 10 },
|
|
3592
|
+
'rotary.low_depth': { block: 'rotary', name: 'low_depth', displayLabel: 'Low Depth', pidLow: 0x0056, pidHigh: 0x000b, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3593
|
+
'rotary.high_depth': { block: 'rotary', name: 'high_depth', displayLabel: 'High Depth', pidLow: 0x0056, pidHigh: 0x000c, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3594
|
+
'rotary.high_level': { block: 'rotary', name: 'high_level', displayLabel: 'High Level', pidLow: 0x0056, pidHigh: 0x000d, unit: 'db', displayMin: -6, displayMax: 6 },
|
|
3595
|
+
'rotary.tempo': {
|
|
3596
|
+
block: 'rotary', name: 'tempo',
|
|
3597
|
+
displayLabel: 'Tempo',
|
|
3598
|
+
pidLow: 0x0056, pidHigh: 0x000e,
|
|
3599
|
+
unit: 'enum', displayMin: 0, displayMax: 78,
|
|
3600
|
+
enumValues: TEMPO_DIVISIONS_VALUES,
|
|
3601
|
+
},
|
|
3602
|
+
'rotary.rotor_length': { block: 'rotary', name: 'rotor_length', displayLabel: 'Rotor Length', pidLow: 0x0056, pidHigh: 0x000f, unit: 'percent', displayMin: 0.1, displayMax: 100 },
|
|
3603
|
+
'rotary.mic_spacing': { block: 'rotary', name: 'mic_spacing', displayLabel: 'Mic Spacing', pidLow: 0x0056, pidHigh: 0x0010, unit: 'rotary_mic_spacing', displayMin: 0, displayMax: 100 },
|
|
3604
|
+
'rotary.low_rate_multiplier': { block: 'rotary', name: 'low_rate_multiplier', displayLabel: 'Low Rate Multiplier', pidLow: 0x0056, pidHigh: 0x0011, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3605
|
+
'rotary.low_time_constant': { block: 'rotary', name: 'low_time_constant', displayLabel: 'Low Time Constant', pidLow: 0x0056, pidHigh: 0x0012, unit: 'count', displayMin: 0.1, displayMax: 10 },
|
|
3606
|
+
'rotary.high_time_constant': { block: 'rotary', name: 'high_time_constant', displayLabel: 'High Time Constant', pidLow: 0x0056, pidHigh: 0x0013, unit: 'count', displayMin: 0.1, displayMax: 10 },
|
|
3607
|
+
'rotary.stereo_spread': { block: 'rotary', name: 'stereo_spread', displayLabel: 'Stereo Spread', pidLow: 0x0056, pidHigh: 0x0014, unit: 'bipolar_percent', displayMin: -200, displayMax: 200 },
|
|
3608
|
+
'rotary.drive': { block: 'rotary', name: 'drive', displayLabel: 'Drive', pidLow: 0x0056, pidHigh: 0x0015, unit: 'knob_0_10', displayMin: 0.5, displayMax: 500, scaling: 'log10' /* typecode 80 — HW-053 cont */ },
|
|
3609
|
+
'rotary.mic_distance': { block: 'rotary', name: 'mic_distance', displayLabel: 'Mic Distance', pidLow: 0x0056, pidHigh: 0x0016, unit: 'count', displayMin: 0.01, displayMax: 1, scaling: 'log10' },
|
|
3610
|
+
'rotary.input_select': {
|
|
3611
|
+
block: 'rotary', name: 'input_select',
|
|
3612
|
+
displayLabel: 'Input Select',
|
|
3613
|
+
pidLow: 0x0056, pidHigh: 0x0017,
|
|
3614
|
+
unit: 'enum', displayMin: 0, displayMax: 2,
|
|
3615
|
+
enumValues: { 0: 'L+R', 1: 'LEFT', 2: 'RIGHT' },
|
|
3616
|
+
},
|
|
3617
|
+
// ── Main Levels page — pidLow=0x002A — HW-067a closed Session 84 (2026-05-16) ──
|
|
3618
|
+
// Capture: samples/captured/session-84-levels.pcapng. AM4-Edit 2.00 +
|
|
3619
|
+
// AM4 firmware 2.00 use action=0x0001 (the standard write action) on
|
|
3620
|
+
// this register family — supersedes Session 50's tentative 0x0002.
|
|
3621
|
+
// Anchors from screenshot match wire 1:1: preset.level wire 1.1100 →
|
|
3622
|
+
// display 1.1 dB; preset.balance wire 0.0222 → display 2.2 (× 100);
|
|
3623
|
+
// scene levels wire 3.33/4.44/5.55/6.66 → display 3.3/4.4/5.5/6.7 dB.
|
|
3624
|
+
'preset.level': {
|
|
3625
|
+
block: 'preset', name: 'level',
|
|
3626
|
+
pidLow: 0x002a, pidHigh: 0x0000,
|
|
3627
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3628
|
+
},
|
|
3629
|
+
'preset.balance': {
|
|
3630
|
+
block: 'preset', name: 'balance',
|
|
3631
|
+
pidLow: 0x002a, pidHigh: 0x0002,
|
|
3632
|
+
unit: 'bipolar_percent', displayMin: -100, displayMax: 100,
|
|
3633
|
+
},
|
|
3634
|
+
'preset.scene_1_level': {
|
|
3635
|
+
block: 'preset', name: 'scene_1_level',
|
|
3636
|
+
pidLow: 0x002a, pidHigh: 0x0018,
|
|
3637
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3638
|
+
},
|
|
3639
|
+
'preset.scene_2_level': {
|
|
3640
|
+
block: 'preset', name: 'scene_2_level',
|
|
3641
|
+
pidLow: 0x002a, pidHigh: 0x0019,
|
|
3642
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3643
|
+
},
|
|
3644
|
+
'preset.scene_3_level': {
|
|
3645
|
+
block: 'preset', name: 'scene_3_level',
|
|
3646
|
+
pidLow: 0x002a, pidHigh: 0x001a,
|
|
3647
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3648
|
+
},
|
|
3649
|
+
'preset.scene_4_level': {
|
|
3650
|
+
block: 'preset', name: 'scene_4_level',
|
|
3651
|
+
pidLow: 0x002a, pidHigh: 0x001b,
|
|
3652
|
+
unit: 'db', displayMin: -80, displayMax: 20,
|
|
3653
|
+
},
|
|
3654
|
+
// ── PATCH family — pidLow=0x00CE (cross-references catalog case 0x3c) ──
|
|
3655
|
+
// Closed Session 84 (2026-05-16) via samples/captured/session-84-routing-
|
|
3656
|
+
// mix-midi.pcapng. Wire shape decoded directly against Ghidra's PATCH
|
|
3657
|
+
// catalog: paramId N → pidHigh = N (matching §6p rule for every other
|
|
3658
|
+
// AM4 block). Same pidLow already hosts block-placement (pidHigh=
|
|
3659
|
+
// 0x0010+slot-1) and preset rename — PATCH is the umbrella family that
|
|
3660
|
+
// covers "everything preset-scoped that isn't a block parameter."
|
|
3661
|
+
//
|
|
3662
|
+
// Confirmed wire values for routing: Series=0.0, Parallel=1.0.
|
|
3663
|
+
// Founder toggled FX2/3/4 routing dropdowns in AM4-Edit; each click
|
|
3664
|
+
// produced a clean float write whose value matches the on-screen state.
|
|
3665
|
+
'preset.routing_slot_2': {
|
|
3666
|
+
block: 'preset', name: 'routing_slot_2',
|
|
3667
|
+
pidLow: 0x00ce, pidHigh: 0x0014,
|
|
3668
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3669
|
+
enumValues: { 0: 'Series', 1: 'Parallel' },
|
|
3670
|
+
},
|
|
3671
|
+
'preset.routing_slot_3': {
|
|
3672
|
+
block: 'preset', name: 'routing_slot_3',
|
|
3673
|
+
pidLow: 0x00ce, pidHigh: 0x0015,
|
|
3674
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3675
|
+
enumValues: { 0: 'Series', 1: 'Parallel' },
|
|
3676
|
+
},
|
|
3677
|
+
'preset.routing_slot_4': {
|
|
3678
|
+
block: 'preset', name: 'routing_slot_4',
|
|
3679
|
+
pidLow: 0x00ce, pidHigh: 0x0016,
|
|
3680
|
+
unit: 'enum', displayMin: 0, displayMax: 1,
|
|
3681
|
+
enumValues: { 0: 'Series', 1: 'Parallel' },
|
|
3682
|
+
},
|
|
3683
|
+
// ── PATCH scene-MIDI — pidLow=0x00CE, base rows 0x40/0x50/0x60 ──
|
|
3684
|
+
// Closed Session 85 + 86 (2026-05-16) via:
|
|
3685
|
+
// samples/captured/session-85-scene-midi.pcapng
|
|
3686
|
+
// samples/captured/session-86-scene-midi-disambiguate.pcapng
|
|
3687
|
+
//
|
|
3688
|
+
// Each scene has 4 MIDI message slots; each slot has 3 fields
|
|
3689
|
+
// (Type / Channel / Value). 4×4×3 = 48 wire-addressable params,
|
|
3690
|
+
// all on standard SET_PARAM action=0x0001 with hdr4=0x0004 and
|
|
3691
|
+
// a packed-float value. NO custom action needed.
|
|
3692
|
+
//
|
|
3693
|
+
// Wire layout:
|
|
3694
|
+
// pidHigh = base_row + (scene-1)*4 + (msg-1)
|
|
3695
|
+
// base_row 0x40 → Type (enum; PC=1.0 confirmed)
|
|
3696
|
+
// base_row 0x50 → Channel (1..16, raw int as float)
|
|
3697
|
+
// base_row 0x60 → Value (0..127, raw int as float)
|
|
3698
|
+
//
|
|
3699
|
+
// Type enum: only PC=1 is wire-confirmed. The (s=4,m=4) bonus in
|
|
3700
|
+
// session-85 showed Type=18.0 for what the founder believed was CC,
|
|
3701
|
+
// so CC=18 is hypothesized but not yet locked. A dedicated type-
|
|
3702
|
+
// sweep capture (cycle the Type dropdown through all entries on one
|
|
3703
|
+
// slot) would harvest the full enum. Treat unknown Type values as
|
|
3704
|
+
// raw int passthrough — the encoder will accept any int 0..127.
|
|
3705
|
+
//
|
|
3706
|
+
// The Session 84 §6n-patch anomaly (pidHigh=0x3e81 action=0x0017)
|
|
3707
|
+
// is unrelated to scene-MIDI authoring — it was triggered by a
|
|
3708
|
+
// different AM4-Edit operation. Not on this critical path.
|
|
3709
|
+
'preset.scene_1_midi_1_type': { block: 'preset', name: 'scene_1_midi_1_type',
|
|
3710
|
+
pidLow: 0x00ce, pidHigh: 0x0040, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3711
|
+
'preset.scene_1_midi_1_channel': { block: 'preset', name: 'scene_1_midi_1_channel',
|
|
3712
|
+
pidLow: 0x00ce, pidHigh: 0x0050, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3713
|
+
'preset.scene_1_midi_1_value': { block: 'preset', name: 'scene_1_midi_1_value',
|
|
3714
|
+
pidLow: 0x00ce, pidHigh: 0x0060, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3715
|
+
'preset.scene_1_midi_2_type': { block: 'preset', name: 'scene_1_midi_2_type',
|
|
3716
|
+
pidLow: 0x00ce, pidHigh: 0x0041, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3717
|
+
'preset.scene_1_midi_2_channel': { block: 'preset', name: 'scene_1_midi_2_channel',
|
|
3718
|
+
pidLow: 0x00ce, pidHigh: 0x0051, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3719
|
+
'preset.scene_1_midi_2_value': { block: 'preset', name: 'scene_1_midi_2_value',
|
|
3720
|
+
pidLow: 0x00ce, pidHigh: 0x0061, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3721
|
+
'preset.scene_1_midi_3_type': { block: 'preset', name: 'scene_1_midi_3_type',
|
|
3722
|
+
pidLow: 0x00ce, pidHigh: 0x0042, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3723
|
+
'preset.scene_1_midi_3_channel': { block: 'preset', name: 'scene_1_midi_3_channel',
|
|
3724
|
+
pidLow: 0x00ce, pidHigh: 0x0052, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3725
|
+
'preset.scene_1_midi_3_value': { block: 'preset', name: 'scene_1_midi_3_value',
|
|
3726
|
+
pidLow: 0x00ce, pidHigh: 0x0062, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3727
|
+
'preset.scene_1_midi_4_type': { block: 'preset', name: 'scene_1_midi_4_type',
|
|
3728
|
+
pidLow: 0x00ce, pidHigh: 0x0043, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3729
|
+
'preset.scene_1_midi_4_channel': { block: 'preset', name: 'scene_1_midi_4_channel',
|
|
3730
|
+
pidLow: 0x00ce, pidHigh: 0x0053, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3731
|
+
'preset.scene_1_midi_4_value': { block: 'preset', name: 'scene_1_midi_4_value',
|
|
3732
|
+
pidLow: 0x00ce, pidHigh: 0x0063, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3733
|
+
'preset.scene_2_midi_1_type': { block: 'preset', name: 'scene_2_midi_1_type',
|
|
3734
|
+
pidLow: 0x00ce, pidHigh: 0x0044, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3735
|
+
'preset.scene_2_midi_1_channel': { block: 'preset', name: 'scene_2_midi_1_channel',
|
|
3736
|
+
pidLow: 0x00ce, pidHigh: 0x0054, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3737
|
+
'preset.scene_2_midi_1_value': { block: 'preset', name: 'scene_2_midi_1_value',
|
|
3738
|
+
pidLow: 0x00ce, pidHigh: 0x0064, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3739
|
+
'preset.scene_2_midi_2_type': { block: 'preset', name: 'scene_2_midi_2_type',
|
|
3740
|
+
pidLow: 0x00ce, pidHigh: 0x0045, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3741
|
+
'preset.scene_2_midi_2_channel': { block: 'preset', name: 'scene_2_midi_2_channel',
|
|
3742
|
+
pidLow: 0x00ce, pidHigh: 0x0055, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3743
|
+
'preset.scene_2_midi_2_value': { block: 'preset', name: 'scene_2_midi_2_value',
|
|
3744
|
+
pidLow: 0x00ce, pidHigh: 0x0065, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3745
|
+
'preset.scene_2_midi_3_type': { block: 'preset', name: 'scene_2_midi_3_type',
|
|
3746
|
+
pidLow: 0x00ce, pidHigh: 0x0046, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3747
|
+
'preset.scene_2_midi_3_channel': { block: 'preset', name: 'scene_2_midi_3_channel',
|
|
3748
|
+
pidLow: 0x00ce, pidHigh: 0x0056, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3749
|
+
'preset.scene_2_midi_3_value': { block: 'preset', name: 'scene_2_midi_3_value',
|
|
3750
|
+
pidLow: 0x00ce, pidHigh: 0x0066, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3751
|
+
'preset.scene_2_midi_4_type': { block: 'preset', name: 'scene_2_midi_4_type',
|
|
3752
|
+
pidLow: 0x00ce, pidHigh: 0x0047, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3753
|
+
'preset.scene_2_midi_4_channel': { block: 'preset', name: 'scene_2_midi_4_channel',
|
|
3754
|
+
pidLow: 0x00ce, pidHigh: 0x0057, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3755
|
+
'preset.scene_2_midi_4_value': { block: 'preset', name: 'scene_2_midi_4_value',
|
|
3756
|
+
pidLow: 0x00ce, pidHigh: 0x0067, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3757
|
+
'preset.scene_3_midi_1_type': { block: 'preset', name: 'scene_3_midi_1_type',
|
|
3758
|
+
pidLow: 0x00ce, pidHigh: 0x0048, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3759
|
+
'preset.scene_3_midi_1_channel': { block: 'preset', name: 'scene_3_midi_1_channel',
|
|
3760
|
+
pidLow: 0x00ce, pidHigh: 0x0058, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3761
|
+
'preset.scene_3_midi_1_value': { block: 'preset', name: 'scene_3_midi_1_value',
|
|
3762
|
+
pidLow: 0x00ce, pidHigh: 0x0068, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3763
|
+
'preset.scene_3_midi_2_type': { block: 'preset', name: 'scene_3_midi_2_type',
|
|
3764
|
+
pidLow: 0x00ce, pidHigh: 0x0049, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3765
|
+
'preset.scene_3_midi_2_channel': { block: 'preset', name: 'scene_3_midi_2_channel',
|
|
3766
|
+
pidLow: 0x00ce, pidHigh: 0x0059, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3767
|
+
'preset.scene_3_midi_2_value': { block: 'preset', name: 'scene_3_midi_2_value',
|
|
3768
|
+
pidLow: 0x00ce, pidHigh: 0x0069, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3769
|
+
'preset.scene_3_midi_3_type': { block: 'preset', name: 'scene_3_midi_3_type',
|
|
3770
|
+
pidLow: 0x00ce, pidHigh: 0x004a, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3771
|
+
'preset.scene_3_midi_3_channel': { block: 'preset', name: 'scene_3_midi_3_channel',
|
|
3772
|
+
pidLow: 0x00ce, pidHigh: 0x005a, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3773
|
+
'preset.scene_3_midi_3_value': { block: 'preset', name: 'scene_3_midi_3_value',
|
|
3774
|
+
pidLow: 0x00ce, pidHigh: 0x006a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3775
|
+
'preset.scene_3_midi_4_type': { block: 'preset', name: 'scene_3_midi_4_type',
|
|
3776
|
+
pidLow: 0x00ce, pidHigh: 0x004b, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3777
|
+
'preset.scene_3_midi_4_channel': { block: 'preset', name: 'scene_3_midi_4_channel',
|
|
3778
|
+
pidLow: 0x00ce, pidHigh: 0x005b, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3779
|
+
'preset.scene_3_midi_4_value': { block: 'preset', name: 'scene_3_midi_4_value',
|
|
3780
|
+
pidLow: 0x00ce, pidHigh: 0x006b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3781
|
+
'preset.scene_4_midi_1_type': { block: 'preset', name: 'scene_4_midi_1_type',
|
|
3782
|
+
pidLow: 0x00ce, pidHigh: 0x004c, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3783
|
+
'preset.scene_4_midi_1_channel': { block: 'preset', name: 'scene_4_midi_1_channel',
|
|
3784
|
+
pidLow: 0x00ce, pidHigh: 0x005c, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3785
|
+
'preset.scene_4_midi_1_value': { block: 'preset', name: 'scene_4_midi_1_value',
|
|
3786
|
+
pidLow: 0x00ce, pidHigh: 0x006c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3787
|
+
'preset.scene_4_midi_2_type': { block: 'preset', name: 'scene_4_midi_2_type',
|
|
3788
|
+
pidLow: 0x00ce, pidHigh: 0x004d, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3789
|
+
'preset.scene_4_midi_2_channel': { block: 'preset', name: 'scene_4_midi_2_channel',
|
|
3790
|
+
pidLow: 0x00ce, pidHigh: 0x005d, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3791
|
+
'preset.scene_4_midi_2_value': { block: 'preset', name: 'scene_4_midi_2_value',
|
|
3792
|
+
pidLow: 0x00ce, pidHigh: 0x006d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3793
|
+
'preset.scene_4_midi_3_type': { block: 'preset', name: 'scene_4_midi_3_type',
|
|
3794
|
+
pidLow: 0x00ce, pidHigh: 0x004e, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3795
|
+
'preset.scene_4_midi_3_channel': { block: 'preset', name: 'scene_4_midi_3_channel',
|
|
3796
|
+
pidLow: 0x00ce, pidHigh: 0x005e, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3797
|
+
'preset.scene_4_midi_3_value': { block: 'preset', name: 'scene_4_midi_3_value',
|
|
3798
|
+
pidLow: 0x00ce, pidHigh: 0x006e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3799
|
+
'preset.scene_4_midi_4_type': { block: 'preset', name: 'scene_4_midi_4_type',
|
|
3800
|
+
pidLow: 0x00ce, pidHigh: 0x004f, unit: 'enum', displayMin: 0, displayMax: 129, enumValues: SCENE_MIDI_TYPE_ENUM },
|
|
3801
|
+
'preset.scene_4_midi_4_channel': { block: 'preset', name: 'scene_4_midi_4_channel',
|
|
3802
|
+
pidLow: 0x00ce, pidHigh: 0x005f, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
3803
|
+
'preset.scene_4_midi_4_value': { block: 'preset', name: 'scene_4_midi_4_value',
|
|
3804
|
+
pidLow: 0x00ce, pidHigh: 0x006f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
3805
|
+
// Session 90 (2026-05-17): REVERB + DELAY mirrors from CACHE_PARAMS.
|
|
3806
|
+
// Already shipping live via the `...CACHE_PARAMS` spread at line 427;
|
|
3807
|
+
// these mirrors exist so `scripts/coverage-audit.ts` (which greps
|
|
3808
|
+
// params.ts directly, not the merged registry) sees them. Unblocks
|
|
3809
|
+
// user prompts like "tighten up the delay ducker," "back off the
|
|
3810
|
+
// reverb modulation," "set delay echo pan left," etc. — all addresses
|
|
3811
|
+
// were already wire-shipping; only the audit was under-reporting.
|
|
3812
|
+
// Source: packages/am4/src/cacheParams.ts (auto-generated from
|
|
3813
|
+
// paramNames.ts + cache-section3.json by gen-params-from-cache.ts).
|
|
3814
|
+
'reverb.high_decay': { block: 'reverb', name: 'high_decay', displayLabel: "High Decay", pidLow: 0x0042, pidHigh: 0x000d, unit: 'count', displayMin: 0.01, displayMax: 1, scaling: 'log10' },
|
|
3815
|
+
'reverb.scattering': { block: 'reverb', name: 'scattering', displayLabel: "Scattering", pidLow: 0x0042, pidHigh: 0x000e, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3816
|
+
'reverb.reverbdelay': { block: 'reverb', name: 'reverbdelay', pidLow: 0x0042, pidHigh: 0x0010, unit: 'ms', displayMin: 0, displayMax: 250 },
|
|
3817
|
+
'reverb.early_level': { block: 'reverb', name: 'early_level', displayLabel: "Early Level", pidLow: 0x0042, pidHigh: 0x0011, unit: 'db', displayMin: -40, displayMax: 10 },
|
|
3818
|
+
'reverb.late_level': { block: 'reverb', name: 'late_level', displayLabel: "Late Level ", pidLow: 0x0042, pidHigh: 0x0012, unit: 'db', displayMin: -40, displayMax: 10 },
|
|
3819
|
+
'reverb.depth': { block: 'reverb', name: 'depth', displayLabel: "Depth", pidLow: 0x0042, pidHigh: 0x0015, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3820
|
+
'reverb.rate': { block: 'reverb', name: 'rate', displayLabel: "Rate", pidLow: 0x0042, pidHigh: 0x0016, unit: 'hz', displayMin: 0.01, displayMax: 1 },
|
|
3821
|
+
'reverb.diffusion': { block: 'reverb', name: 'diffusion', displayLabel: "Diffusion", pidLow: 0x0042, pidHigh: 0x0019, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3822
|
+
'reverb.diffusion_time': { block: 'reverb', name: 'diffusion_time', displayLabel: "Diffusion Time", pidLow: 0x0042, pidHigh: 0x001a, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3823
|
+
'reverb.pickup_spacing': { block: 'reverb', name: 'pickup_spacing', displayLabel: "Pickup Spacing", pidLow: 0x0042, pidHigh: 0x001d, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3824
|
+
'reverb.frequency_1': { block: 'reverb', name: 'frequency_1', displayLabel: "Frequency 1", pidLow: 0x0042, pidHigh: 0x001e, unit: 'hz', displayMin: 20, displayMax: 2000 },
|
|
3825
|
+
'reverb.frequency_2': { block: 'reverb', name: 'frequency_2', displayLabel: "Frequency 2", pidLow: 0x0042, pidHigh: 0x001f, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
3826
|
+
'reverb.q_1': { block: 'reverb', name: 'q_1', displayLabel: "Q 1", pidLow: 0x0042, pidHigh: 0x0020, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3827
|
+
'reverb.q_2': { block: 'reverb', name: 'q_2', displayLabel: "Q 2", pidLow: 0x0042, pidHigh: 0x0021, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3828
|
+
'reverb.gain_1': { block: 'reverb', name: 'gain_1', displayLabel: "Gain 1", pidLow: 0x0042, pidHigh: 0x0022, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3829
|
+
'reverb.gain_2': { block: 'reverb', name: 'gain_2', displayLabel: "Gain 2", pidLow: 0x0042, pidHigh: 0x0023, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
3830
|
+
'reverb.low_decay': { block: 'reverb', name: 'low_decay', displayLabel: "Low Decay", pidLow: 0x0042, pidHigh: 0x0025, unit: 'seconds', displayMin: 0.02, displayMax: 2, scaling: 'log10' },
|
|
3831
|
+
'reverb.xover_frequency': { block: 'reverb', name: 'xover_frequency', displayLabel: "Xover Frequency", pidLow: 0x0042, pidHigh: 0x0026, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
3832
|
+
'reverb.threshold': { block: 'reverb', name: 'threshold', displayLabel: "Threshold", pidLow: 0x0042, pidHigh: 0x0029, unit: 'db', displayMin: -80, displayMax: 20 },
|
|
3833
|
+
'reverb.release_time': { block: 'reverb', name: 'release_time', displayLabel: "Release Time", pidLow: 0x0042, pidHigh: 0x002a, unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10' },
|
|
3834
|
+
'reverb.early_diffusion': { block: 'reverb', name: 'early_diffusion', displayLabel: "Early Diffusion", pidLow: 0x0042, pidHigh: 0x002b, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3835
|
+
'reverb.early_diff_time': { block: 'reverb', name: 'early_diff_time', displayLabel: "Early Diff Time", pidLow: 0x0042, pidHigh: 0x002c, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3836
|
+
'reverb.early_decay': { block: 'reverb', name: 'early_decay', displayLabel: "Early Decay", pidLow: 0x0042, pidHigh: 0x002d, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3837
|
+
'reverb.late_input_mix': { block: 'reverb', name: 'late_input_mix', displayLabel: "Late Input Mix", pidLow: 0x0042, pidHigh: 0x002e, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3838
|
+
'reverb.basetype': { block: 'reverb', name: 'basetype', pidLow: 0x0042, pidHigh: 0x0031, unit: 'count', displayMin: 0, displayMax: 8 },
|
|
3839
|
+
'reverb.lfo_phase': { block: 'reverb', name: 'lfo_phase', displayLabel: "LFO Phase", pidLow: 0x0042, pidHigh: 0x0032, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
3840
|
+
'reverb.pitch_mix': { block: 'reverb', name: 'pitch_mix', displayLabel: "Pitch Mix", pidLow: 0x0042, pidHigh: 0x0037, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3841
|
+
'reverb.pitch_feedback': { block: 'reverb', name: 'pitch_feedback', displayLabel: "Pitch Feedback", pidLow: 0x0042, pidHigh: 0x003a, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3842
|
+
'reverb.splice_time': { block: 'reverb', name: 'splice_time', displayLabel: "Splice Time", pidLow: 0x0042, pidHigh: 0x003c, unit: 'ms', displayMin: 10, displayMax: 2000 },
|
|
3843
|
+
'reverb.pitch_modulation': { block: 'reverb', name: 'pitch_modulation', displayLabel: "Pitch Modulation", pidLow: 0x0042, pidHigh: 0x003e, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3844
|
+
'reverb.voice_balance': { block: 'reverb', name: 'voice_balance', displayLabel: "Voice Balance", pidLow: 0x0042, pidHigh: 0x003f, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3845
|
+
'reverb.feedback': { block: 'reverb', name: 'feedback', displayLabel: "Feedback", pidLow: 0x0042, pidHigh: 0x0041, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3846
|
+
'reverb.echo_mix': { block: 'reverb', name: 'echo_mix', displayLabel: "Echo Mix", pidLow: 0x0042, pidHigh: 0x0042, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3847
|
+
'reverb.pitch_high_cut': { block: 'reverb', name: 'pitch_high_cut', displayLabel: "Shimmer Tone", pidLow: 0x0042, pidHigh: 0x0043, unit: 'hz', displayMin: 200, displayMax: 20000 },
|
|
3848
|
+
'reverb.tonetype': { block: 'reverb', name: 'tonetype', pidLow: 0x0042, pidHigh: 0x0045, unit: 'db', displayMin: 0, displayMax: 3 },
|
|
3849
|
+
'reverb.low_cut_q': { block: 'reverb', name: 'low_cut_q', displayLabel: "Low Cut Q", pidLow: 0x0042, pidHigh: 0x0047, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3850
|
+
'reverb.high_cut_q': { block: 'reverb', name: 'high_cut_q', displayLabel: "High Cut Q", pidLow: 0x0042, pidHigh: 0x0048, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3851
|
+
// DELAY mirrors.
|
|
3852
|
+
'delay.tempo_1': { block: 'delay', name: 'tempo_1', pidLow: 0x0046, pidHigh: 0x000f, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3853
|
+
'delay.echo_pan': { block: 'delay', name: 'echo_pan', displayLabel: "Echo Pan", pidLow: 0x0046, pidHigh: 0x0011, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3854
|
+
'delay.mod_rate': { block: 'delay', name: 'mod_rate', displayLabel: "Mod Rate", pidLow: 0x0046, pidHigh: 0x0016, unit: 'hz', displayMin: 0.1, displayMax: 10 },
|
|
3855
|
+
'delay.rate': { block: 'delay', name: 'rate', displayLabel: "Rate", pidLow: 0x0046, pidHigh: 0x0017, unit: 'hz', displayMin: 0.2, displayMax: 20 },
|
|
3856
|
+
'delay.mod_depth': { block: 'delay', name: 'mod_depth', displayLabel: "Mod Depth", pidLow: 0x0046, pidHigh: 0x0018, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3857
|
+
'delay.mod_depth_depth2': { block: 'delay', name: 'mod_depth_depth2', displayLabel: "Mod Depth", pidLow: 0x0046, pidHigh: 0x0019, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3858
|
+
'delay.time_r': { block: 'delay', name: 'time_r', displayLabel: "Time R", pidLow: 0x0046, pidHigh: 0x001e, unit: 'ms', displayMin: 0, displayMax: 8000 },
|
|
3859
|
+
'delay.rotation': { block: 'delay', name: 'rotation', displayLabel: "Rotation", pidLow: 0x0046, pidHigh: 0x0022, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3860
|
+
'delay.lfo_phase': { block: 'delay', name: 'lfo_phase', pidLow: 0x0046, pidHigh: 0x0023, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3861
|
+
'delay.level_l': { block: 'delay', name: 'level_l', displayLabel: "Level L", pidLow: 0x0046, pidHigh: 0x0024, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3862
|
+
'delay.level_r': { block: 'delay', name: 'level_r', displayLabel: "Level R", pidLow: 0x0046, pidHigh: 0x0025, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3863
|
+
'delay.pan_l': { block: 'delay', name: 'pan_l', displayLabel: "Pan L", pidLow: 0x0046, pidHigh: 0x0026, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3864
|
+
'delay.pan_r': { block: 'delay', name: 'pan_r', displayLabel: "Pan R", pidLow: 0x0046, pidHigh: 0x0027, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3865
|
+
'delay.modulation_phase': { block: 'delay', name: 'modulation_phase', displayLabel: "Modulation Phase", pidLow: 0x0046, pidHigh: 0x0028, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
3866
|
+
'delay.lfo_phase_2': { block: 'delay', name: 'lfo_phase_2', displayLabel: "LFO Phase", pidLow: 0x0046, pidHigh: 0x0029, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
3867
|
+
'delay.crossfade_time': { block: 'delay', name: 'crossfade_time', displayLabel: "Crossfade Time", pidLow: 0x0046, pidHigh: 0x002a, unit: 'ms', displayMin: 1, displayMax: 255 },
|
|
3868
|
+
'delay.sweep_rate': { block: 'delay', name: 'sweep_rate', displayLabel: "Sweep Rate", pidLow: 0x0046, pidHigh: 0x0038, unit: 'hz', displayMin: 0.1, displayMax: 10 },
|
|
3869
|
+
'delay.sweep_phase': { block: 'delay', name: 'sweep_phase', displayLabel: "Sweep Phase", pidLow: 0x0046, pidHigh: 0x003a, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
3870
|
+
'delay.sweep_start_freq': { block: 'delay', name: 'sweep_start_freq', displayLabel: "Sweep Start Freq", pidLow: 0x0046, pidHigh: 0x003c, unit: 'hz', displayMin: 100, displayMax: 1000 },
|
|
3871
|
+
'delay.sweep_stop_freq': { block: 'delay', name: 'sweep_stop_freq', displayLabel: "Sweep Stop Freq", pidLow: 0x0046, pidHigh: 0x003d, unit: 'hz', displayMin: 500, displayMax: 5000 },
|
|
3872
|
+
'delay.sweep_resonance': { block: 'delay', name: 'sweep_resonance', displayLabel: "Sweep Resonance", pidLow: 0x0046, pidHigh: 0x003e, unit: 'count', displayMin: 0.2, displayMax: 20, scaling: 'log10' },
|
|
3873
|
+
'delay.motor_speed': { block: 'delay', name: 'motor_speed', displayLabel: "Motor Speed", pidLow: 0x0046, pidHigh: 0x0048, unit: 'count', displayMin: 0.5, displayMax: 2, scaling: 'log10' },
|
|
3874
|
+
'delay.right_post_delay': { block: 'delay', name: 'right_post_delay', displayLabel: "Right Post Delay", pidLow: 0x0046, pidHigh: 0x0049, unit: 'ms', displayMin: 0, displayMax: 100 },
|
|
3875
|
+
'delay.pan_rate': { block: 'delay', name: 'pan_rate', displayLabel: "Pan Rate", pidLow: 0x0046, pidHigh: 0x0052, unit: 'hz', displayMin: 0.1, displayMax: 10 },
|
|
3876
|
+
'delay.pan_depth': { block: 'delay', name: 'pan_depth', displayLabel: "Pan Depth", pidLow: 0x0046, pidHigh: 0x0054, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3877
|
+
'delay.lfo_phase_4': { block: 'delay', name: 'lfo_phase_4', displayLabel: "LFO Phase", pidLow: 0x0046, pidHigh: 0x0055, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
3878
|
+
// Session 90 (2026-05-17): Phase 3 — REVERB + DELAY enums + tempo-
|
|
3879
|
+
// sync registers from the Ghidra catalog. These have no cache record
|
|
3880
|
+
// (so the cacheParams generator can't emit them) but the paramNames.ts
|
|
3881
|
+
// TODOs document the expected range from prior structural analysis.
|
|
3882
|
+
// Confidence tier per entry:
|
|
3883
|
+
// • HIGH: shared dictionaries (TEMPO_DIVISIONS_VALUES, LFO_WAVEFORMS_VALUES)
|
|
3884
|
+
// — these are firmware-extracted cache enums, byte-identical to the
|
|
3885
|
+
// values the device understands. Wire-safe.
|
|
3886
|
+
// • MEDIUM: 2-value toggles with conventional OFF/ON or paired labels —
|
|
3887
|
+
// the wire range is documented but the display labels are educated
|
|
3888
|
+
// guesses. Wire writes are still safe (values 0 / 1 are in range).
|
|
3889
|
+
// • LOWER: multi-value enums without a known label table — shipped as
|
|
3890
|
+
// `unit: 'count'` so the agent can address the param but doesn't
|
|
3891
|
+
// claim to know what each numeric value means. Future hardware
|
|
3892
|
+
// verification can upgrade these to enum + labels.
|
|
3893
|
+
//
|
|
3894
|
+
// REVERB tempo-sync (HIGH — shared TEMPO_DIVISIONS dictionary):
|
|
3895
|
+
'reverb.predly_tempo': { block: 'reverb', name: 'predly_tempo', displayLabel: 'Pre-Delay Tempo', pidLow: 0x0042, pidHigh: 0x0040, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3896
|
+
// REVERB slope/toggle (MEDIUM — 2-value toggles, labels are conventional
|
|
3897
|
+
// guesses based on Blocks Guide §Reverb Common Page; wire writes safe):
|
|
3898
|
+
// Session 96 cont 2 review pass (2026-05-17): renamed `low_slope` →
|
|
3899
|
+
// `low_cut_slope` and `high_slope` → `high_cut_slope` to match the
|
|
3900
|
+
// AM4-Edit XML display labels exactly ("Low Cut Slope" / "High Cut
|
|
3901
|
+
// Slope"). Sibling `reverb.low_cut_q` / `reverb.high_cut_q` (pidHigh
|
|
3902
|
+
// 0x47/0x48) already use the `low_cut_` / `high_cut_` family prefix,
|
|
3903
|
+
// so this aligns the slope pair with the Q pair. Disambiguates from
|
|
3904
|
+
// `amp.low_slope` / `amp.high_slope` on the DISTORT register (whose
|
|
3905
|
+
// XML label is "Low Slope" — no "Cut"). LLM prompt "make the reverb
|
|
3906
|
+
// low cut slope steeper" now matches the param key directly.
|
|
3907
|
+
'reverb.low_cut_slope': { block: 'reverb', name: 'low_cut_slope', displayLabel: 'Low Cut Slope', pidLow: 0x0042, pidHigh: 0x0035, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'Normal', 1: 'Steep' } },
|
|
3908
|
+
'reverb.high_cut_slope': { block: 'reverb', name: 'high_cut_slope', displayLabel: 'High Cut Slope', pidLow: 0x0042, pidHigh: 0x0036, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'Normal', 1: 'Steep' } },
|
|
3909
|
+
'reverb.spring_type': { block: 'reverb', name: 'spring_type', displayLabel: 'Spring Type', pidLow: 0x0042, pidHigh: 0x0044, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'A', 1: 'B' } },
|
|
3910
|
+
'reverb.predly_tap': { block: 'reverb', name: 'predly_tap', displayLabel: 'Pre-Delay Tap', pidLow: 0x0042, pidHigh: 0x0046, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
3911
|
+
// REVERB input-select (MEDIUM — matches the standard Fractal input-select
|
|
3912
|
+
// 3-value pattern documented at paramNames.ts line 425 + used in rotary):
|
|
3913
|
+
'reverb.input_select': { block: 'reverb', name: 'input_select', displayLabel: 'Input Select', pidLow: 0x0042, pidHigh: 0x0033, unit: 'enum', displayMin: 0, displayMax: 2, enumValues: { 0: 'L+R', 1: 'LEFT', 2: 'RIGHT' } },
|
|
3914
|
+
// REVERB pitch direction / position (LOWER — multi-value with no cache
|
|
3915
|
+
// labels). Shipped as 'count' so the agent can write any in-range
|
|
3916
|
+
// value without claiming to know the labels.
|
|
3917
|
+
// Session 96 cont 2 review pass (2026-05-17): renamed `pitch_dir` →
|
|
3918
|
+
// `pitch_direction` and `pitch_pos` → `pitch_position` to spell out
|
|
3919
|
+
// the XML display labels ("Pitch Direction" / "Pitch Position"). The
|
|
3920
|
+
// agent picks up "pitch direction" / "pitch position" prompts
|
|
3921
|
+
// directly without needing to remember the truncated `_dir` / `_pos`
|
|
3922
|
+
// form.
|
|
3923
|
+
'reverb.pitch_direction': { block: 'reverb', name: 'pitch_direction', displayLabel: 'Pitch Direction', pidLow: 0x0042, pidHigh: 0x003b, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
3924
|
+
'reverb.pitch_position': { block: 'reverb', name: 'pitch_position', displayLabel: 'Pitch Position', pidLow: 0x0042, pidHigh: 0x003d, unit: 'count', displayMin: 0, displayMax: 2 },
|
|
3925
|
+
// DELAY tempo-sync (HIGH — shared TEMPO_DIVISIONS dictionary on right
|
|
3926
|
+
// channel + LFO1/2/3/4 tempo):
|
|
3927
|
+
'delay.tempo_r': { block: 'delay', name: 'tempo_r', displayLabel: 'Tempo R', pidLow: 0x0046, pidHigh: 0x0021, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3928
|
+
'delay.lfo_1_tempo': { block: 'delay', name: 'lfo_1_tempo', displayLabel: 'LFO 1 Tempo', pidLow: 0x0046, pidHigh: 0x0036, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3929
|
+
'delay.lfo_2_tempo': { block: 'delay', name: 'lfo_2_tempo', displayLabel: 'LFO 2 Tempo', pidLow: 0x0046, pidHigh: 0x0037, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3930
|
+
'delay.lfo_3_tempo': { block: 'delay', name: 'lfo_3_tempo', displayLabel: 'LFO 3 Tempo', pidLow: 0x0046, pidHigh: 0x003b, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3931
|
+
'delay.lfo_4_tempo': { block: 'delay', name: 'lfo_4_tempo', displayLabel: 'LFO 4 Tempo', pidLow: 0x0046, pidHigh: 0x0053, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
3932
|
+
// DELAY LFO waveform type (HIGH — shared LFO_WAVEFORMS dictionary,
|
|
3933
|
+
// 10 entries 0..9, matches chorus.lfo_type at line 2480):
|
|
3934
|
+
'delay.lfo_1_type': { block: 'delay', name: 'lfo_1_type', displayLabel: 'LFO 1 Type', pidLow: 0x0046, pidHigh: 0x001c, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
3935
|
+
'delay.lfo_2_type': { block: 'delay', name: 'lfo_2_type', displayLabel: 'LFO 2 Type', pidLow: 0x0046, pidHigh: 0x001d, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
3936
|
+
'delay.lfo_3_type': { block: 'delay', name: 'lfo_3_type', displayLabel: 'LFO 3 Type', pidLow: 0x0046, pidHigh: 0x0039, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
3937
|
+
'delay.lfo_4_type': { block: 'delay', name: 'lfo_4_type', displayLabel: 'LFO 4 Type', pidLow: 0x0046, pidHigh: 0x0051, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
3938
|
+
// DELAY 2-value toggles (MEDIUM — wire range documented; labels are
|
|
3939
|
+
// conventional OFF/ON or A/B guesses):
|
|
3940
|
+
'delay.run': { block: 'delay', name: 'run', displayLabel: 'Run', pidLow: 0x0046, pidHigh: 0x002b, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
3941
|
+
// Renamed to match AM4-Edit display ("Trigger Restart") — confirmed
|
|
3942
|
+
// via cross-ref audit. Wire range still 0..1.
|
|
3943
|
+
'delay.trigger_restart': { block: 'delay', name: 'trigger_restart', displayLabel: 'Trigger Restart', pidLow: 0x0046, pidHigh: 0x002c, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
3944
|
+
'delay.depth_range': { block: 'delay', name: 'depth_range', displayLabel: 'Depth Range', pidLow: 0x0046, pidHigh: 0x0047, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
3945
|
+
// DELAY LFO target selectors (LOWER — multi-value with no cache labels):
|
|
3946
|
+
'delay.lfo_1_target': { block: 'delay', name: 'lfo_1_target', displayLabel: 'LFO 1 Target', pidLow: 0x0046, pidHigh: 0x0034, unit: 'count', displayMin: 0, displayMax: 2 },
|
|
3947
|
+
'delay.lfo_2_target': { block: 'delay', name: 'lfo_2_target', displayLabel: 'LFO 2 Target', pidLow: 0x0046, pidHigh: 0x0035, unit: 'count', displayMin: 0, displayMax: 2 },
|
|
3948
|
+
'delay.lfo_4_target': { block: 'delay', name: 'lfo_4_target', displayLabel: 'LFO 4 Target', pidLow: 0x0046, pidHigh: 0x0056, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
3949
|
+
// DELAY state-variable filter type (LOWER — typical SVF is Low/Band/High
|
|
3950
|
+
// but TODO marked range 1..3 not 0..2, so the labels here would be wrong;
|
|
3951
|
+
// ship as count and let hardware verification supply the labels):
|
|
3952
|
+
'delay.sweep_filter': { block: 'delay', name: 'sweep_filter', displayLabel: 'Sweep Filter', pidLow: 0x0046, pidHigh: 0x0059, unit: 'count', displayMin: 1, displayMax: 3 },
|
|
3953
|
+
// Session 90 cont (2026-05-17): CHORUS / FLANGER / PHASER / FILTER /
|
|
3954
|
+
// TREMOLO / ENHANCER / COMPRESSOR mirror block. 53 entries from
|
|
3955
|
+
// cacheParams.ts (auto-generated from the paramNames.ts +
|
|
3956
|
+
// cache-section3.json pipeline) mirrored into params.ts so the
|
|
3957
|
+
// coverage-audit sees them. Includes 21 unit overrides added to
|
|
3958
|
+
// paramNames.ts this session to correct cache c=1 → 'db' fallbacks
|
|
3959
|
+
// for entries that are Hz / count / ratio / bipolar_percent.
|
|
3960
|
+
// Unblocks user prompts like "set the filter rate to 0.5 Hz", "set
|
|
3961
|
+
// phaser min freq to 200 Hz", "compressor ratio 4:1", etc.
|
|
3962
|
+
// CHORUS mirrors (3).
|
|
3963
|
+
'chorus.left_depth': { block: 'chorus', name: 'left_depth', displayLabel: "Left Depth", pidLow: 0x004e, pidHigh: 0x001c, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3964
|
+
'chorus.center_depth': { block: 'chorus', name: 'center_depth', displayLabel: "Center Depth", pidLow: 0x004e, pidHigh: 0x001d, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3965
|
+
'chorus.right_depth': { block: 'chorus', name: 'right_depth', displayLabel: "Right Depth", pidLow: 0x004e, pidHigh: 0x001e, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3966
|
+
// FLANGER mirrors (10).
|
|
3967
|
+
'flanger.dry_delay': { block: 'flanger', name: 'dry_delay', displayLabel: "Dry Delay", pidLow: 0x0052, pidHigh: 0x0010, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3968
|
+
'flanger.smooth_steps': { block: 'flanger', name: 'smooth_steps', displayLabel: "Smooth Steps", pidLow: 0x0052, pidHigh: 0x0013, unit: 'count', displayMin: 0.5, displayMax: 50 },
|
|
3969
|
+
'flanger.high_cut': { block: 'flanger', name: 'high_cut', displayLabel: "High Cut", pidLow: 0x0052, pidHigh: 0x0017, unit: 'hz', displayMin: 200, displayMax: 20000 },
|
|
3970
|
+
'flanger.drive': { block: 'flanger', name: 'drive', displayLabel: "Drive", pidLow: 0x0052, pidHigh: 0x0018, unit: 'knob_0_10', displayMin: 0, displayMax: 10, scaling: 'log10' },
|
|
3971
|
+
'flanger.low_cut': { block: 'flanger', name: 'low_cut', displayLabel: "Low Cut", pidLow: 0x0052, pidHigh: 0x0019, unit: 'hz', displayMin: 20, displayMax: 2000 },
|
|
3972
|
+
'flanger.stereo_spread': { block: 'flanger', name: 'stereo_spread', displayLabel: "Stereo Spread", pidLow: 0x0052, pidHigh: 0x001a, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3973
|
+
'flanger.bass_focus': { block: 'flanger', name: 'bass_focus', displayLabel: "Bass Focus", pidLow: 0x0052, pidHigh: 0x001e, unit: 'knob_0_10', displayMin: 0, displayMax: 10, scaling: 'log10' },
|
|
3974
|
+
'flanger.min_time': { block: 'flanger', name: 'min_time', displayLabel: "Min Time", pidLow: 0x0052, pidHigh: 0x0020, unit: 'ms', displayMin: 0, displayMax: 2 },
|
|
3975
|
+
'flanger.max_time': { block: 'flanger', name: 'max_time', displayLabel: "Max Time", pidLow: 0x0052, pidHigh: 0x0021, unit: 'ms', displayMin: 0, displayMax: 20 },
|
|
3976
|
+
'flanger.vpo_exponent': { block: 'flanger', name: 'vpo_exponent', displayLabel: "VPO Exponent", pidLow: 0x0052, pidHigh: 0x0023, unit: 'count', displayMin: 0.01, displayMax: 100, scaling: 'log10' },
|
|
3977
|
+
// PHASER mirrors (12).
|
|
3978
|
+
'phaser.min_frequency': { block: 'phaser', name: 'min_frequency', displayLabel: "Min Frequency", pidLow: 0x005a, pidHigh: 0x0011, unit: 'hz', displayMin: 5, displayMax: 500 },
|
|
3979
|
+
'phaser.max_frequency': { block: 'phaser', name: 'max_frequency', displayLabel: "Max Frequency", pidLow: 0x005a, pidHigh: 0x0012, unit: 'hz', displayMin: 200, displayMax: 20000 },
|
|
3980
|
+
'phaser.bias': { block: 'phaser', name: 'bias', displayLabel: "Bias", pidLow: 0x005a, pidHigh: 0x0014, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
3981
|
+
'phaser.feedback_point': { block: 'phaser', name: 'feedback_point', displayLabel: "Feedback Point", pidLow: 0x005a, pidHigh: 0x0016, unit: 'count', displayMin: 0, displayMax: 11 },
|
|
3982
|
+
'phaser.q': { block: 'phaser', name: 'q', displayLabel: "Q", pidLow: 0x005a, pidHigh: 0x0019, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3983
|
+
'phaser.shape_vcrk': { block: 'phaser', name: 'shape_vcrk', displayLabel: "Shape", pidLow: 0x005a, pidHigh: 0x001d, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3984
|
+
'phaser.shape': { block: 'phaser', name: 'shape', displayLabel: "Shape", pidLow: 0x005a, pidHigh: 0x001e, unit: 'count', displayMin: 0.01, displayMax: 0.99 },
|
|
3985
|
+
'phaser.high_cut': { block: 'phaser', name: 'high_cut', displayLabel: "High Cut", pidLow: 0x005a, pidHigh: 0x001f, unit: 'count', displayMin: 0.5, displayMax: 50 },
|
|
3986
|
+
'phaser.attack': { block: 'phaser', name: 'attack', displayLabel: "Attack", pidLow: 0x005a, pidHigh: 0x0020, unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10' },
|
|
3987
|
+
'phaser.release': { block: 'phaser', name: 'release', displayLabel: "Release", pidLow: 0x005a, pidHigh: 0x0021, unit: 'ms', displayMin: 0, displayMax: 100, scaling: 'log10' },
|
|
3988
|
+
'phaser.low_cut': { block: 'phaser', name: 'low_cut', displayLabel: "Low Cut", pidLow: 0x005a, pidHigh: 0x0023, unit: 'hz', displayMin: 20, displayMax: 200 },
|
|
3989
|
+
'phaser.high_cut_lpf': { block: 'phaser', name: 'high_cut_lpf', displayLabel: "High Cut", pidLow: 0x005a, pidHigh: 0x0024, unit: 'hz', displayMin: 2000, displayMax: 20000 },
|
|
3990
|
+
// FILTER mirrors (15).
|
|
3991
|
+
'filter.q': { block: 'filter', name: 'q', displayLabel: "Q", pidLow: 0x0072, pidHigh: 0x000c, unit: 'count', displayMin: 0.1, displayMax: 10, scaling: 'log10' },
|
|
3992
|
+
'filter.gain': { block: 'filter', name: 'gain', displayLabel: "Gain", pidLow: 0x0072, pidHigh: 0x000d, unit: 'db', displayMin: -20, displayMax: 20 },
|
|
3993
|
+
'filter.pan_left': { block: 'filter', name: 'pan_left', displayLabel: "Pan Left", pidLow: 0x0072, pidHigh: 0x000f, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3994
|
+
'filter.pan_right': { block: 'filter', name: 'pan_right', displayLabel: "Pan Right", pidLow: 0x0072, pidHigh: 0x0010, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3995
|
+
'filter.delay_time': { block: 'filter', name: 'delay_time', displayLabel: "Delay Time", pidLow: 0x0072, pidHigh: 0x0014, unit: 'ms', displayMin: 0, displayMax: 40 },
|
|
3996
|
+
'filter.rate': { block: 'filter', name: 'rate', displayLabel: "Rate", pidLow: 0x0072, pidHigh: 0x0018, unit: 'hz', displayMin: 0.1, displayMax: 10 },
|
|
3997
|
+
'filter.lfo_duty': { block: 'filter', name: 'lfo_duty', displayLabel: "Duty Cycle", pidLow: 0x0072, pidHigh: 0x0019, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
3998
|
+
'filter.mod_frequency': { block: 'filter', name: 'mod_frequency', displayLabel: "Mod Freq", pidLow: 0x0072, pidHigh: 0x001a, unit: 'hz', displayMin: 20, displayMax: 20000 },
|
|
3999
|
+
'filter.resonance': { block: 'filter', name: 'resonance', displayLabel: "Resonance", pidLow: 0x0072, pidHigh: 0x001e, unit: 'knob_0_10', displayMin: 0, displayMax: 10, scaling: 'log10' },
|
|
4000
|
+
'filter.start_frequency': { block: 'filter', name: 'start_frequency', displayLabel: "Start Frequency", pidLow: 0x0072, pidHigh: 0x001f, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
4001
|
+
'filter.stop_frequency': { block: 'filter', name: 'stop_frequency', displayLabel: "Stop Frequency", pidLow: 0x0072, pidHigh: 0x0020, unit: 'hz', displayMin: 100, displayMax: 10000 },
|
|
4002
|
+
'filter.sensitivity': { block: 'filter', name: 'sensitivity', displayLabel: "Sensitivity", pidLow: 0x0072, pidHigh: 0x0021, unit: 'count', displayMin: 0.1, displayMax: 40, scaling: 'log10' },
|
|
4003
|
+
'filter.attack_time': { block: 'filter', name: 'attack_time', displayLabel: "Attack Time", pidLow: 0x0072, pidHigh: 0x0022, unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10' },
|
|
4004
|
+
'filter.release_time': { block: 'filter', name: 'release_time', displayLabel: "Release Time", pidLow: 0x0072, pidHigh: 0x0023, unit: 'ms', displayMin: 0, displayMax: 2000, scaling: 'log10' },
|
|
4005
|
+
'filter.emphasis': { block: 'filter', name: 'emphasis', displayLabel: "Emphasis", pidLow: 0x0072, pidHigh: 0x0027, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4006
|
+
// TREMOLO mirrors (4).
|
|
4007
|
+
'tremolo.duty': { block: 'tremolo', name: 'duty', displayLabel: "Duty", pidLow: 0x006a, pidHigh: 0x000e, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4008
|
+
'tremolo.crossover_freq': { block: 'tremolo', name: 'crossover_freq', displayLabel: "Crossover Freq", pidLow: 0x006a, pidHigh: 0x0015, unit: 'hz', displayMin: 200, displayMax: 2000 },
|
|
4009
|
+
'tremolo.trigger_threshold': { block: 'tremolo', name: 'trigger_threshold', displayLabel: "Trigger Threshold", pidLow: 0x006a, pidHigh: 0x0016, unit: 'db', displayMin: -60, displayMax: 20 },
|
|
4010
|
+
'tremolo.shape': { block: 'tremolo', name: 'shape', displayLabel: "Shape", pidLow: 0x006a, pidHigh: 0x0017, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4011
|
+
// ENHANCER mirrors (2).
|
|
4012
|
+
'enhancer.pan_left': { block: 'enhancer', name: 'pan_left', displayLabel: "Pan Left", pidLow: 0x007a, pidHigh: 0x0010, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4013
|
+
'enhancer.pan_right': { block: 'enhancer', name: 'pan_right', displayLabel: "Pan Right", pidLow: 0x007a, pidHigh: 0x0011, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4014
|
+
// COMPRESSOR mirrors (7).
|
|
4015
|
+
'compressor.compression': { block: 'compressor', name: 'compression', displayLabel: "Compression", pidLow: 0x002e, pidHigh: 0x0014, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4016
|
+
'compressor.dynamics': { block: 'compressor', name: 'dynamics', displayLabel: "Dynamics", pidLow: 0x002e, pidHigh: 0x0018, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4017
|
+
'compressor.threshold_thresh2': { block: 'compressor', name: 'threshold_thresh2', displayLabel: "Threshold", pidLow: 0x002e, pidHigh: 0x0021, unit: 'db', displayMin: -60, displayMax: 20 },
|
|
4018
|
+
'compressor.ratio_compansion': { block: 'compressor', name: 'ratio_compansion', displayLabel: "Ratio", pidLow: 0x002e, pidHigh: 0x0024, unit: 'ratio', displayMin: 1, displayMax: 10, scaling: 'log10' },
|
|
4019
|
+
'compressor.time': { block: 'compressor', name: 'time', displayLabel: "Time", pidLow: 0x002e, pidHigh: 0x0025, unit: 'ms', displayMin: 0, displayMax: 1000, scaling: 'log10' },
|
|
4020
|
+
'compressor.transients': { block: 'compressor', name: 'transients', displayLabel: "Transients", pidLow: 0x002e, pidHigh: 0x0026, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4021
|
+
'compressor.tone': { block: 'compressor', name: 'tone', displayLabel: "Tone", pidLow: 0x002e, pidHigh: 0x0028, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4022
|
+
// Session 91 (2026-05-17): FLANGER / PHASER / FILTER UI-MISSING
|
|
4023
|
+
// closeout. 28 catalog symbols from the Ghidra paramId table that
|
|
4024
|
+
// have AM4-Edit XML labels but no params.ts entry. Confidence tiers
|
|
4025
|
+
// per the Session 90 convention:
|
|
4026
|
+
// • HIGH: shared LFO_WAVEFORMS_VALUES / TEMPO_DIVISIONS_VALUES
|
|
4027
|
+
// dictionaries, wire-byte identical to existing entries that use
|
|
4028
|
+
// them. Wire-safe.
|
|
4029
|
+
// • MEDIUM: 2-value toggles with the conventional { 0:'OFF', 1:'ON' }
|
|
4030
|
+
// labels. Wire range documented; labels are conventional guesses.
|
|
4031
|
+
// Wire writes still safe (values 0 / 1 in range).
|
|
4032
|
+
// • LOWER: multi-value enums without a known label table — shipped
|
|
4033
|
+
// as `unit: 'count'` so the agent can address the param without
|
|
4034
|
+
// claiming the labels. Hardware verification can upgrade later.
|
|
4035
|
+
// Resolver-name dedup suffixes follow the existing pattern
|
|
4036
|
+
// (`shape_vcrk`, `high_cut_lpf`, `ratio_compansion`): when the
|
|
4037
|
+
// AM4-Edit label collides with an existing entry's name, add a
|
|
4038
|
+
// disambiguating suffix and accept the WIRED-MISLABEL on the audit
|
|
4039
|
+
// (intentional disambiguation, ceiling bump).
|
|
4040
|
+
// FLANGER hand-author (9). All 9 names match the AM4-Edit XML
|
|
4041
|
+
// display labels → WIRED-MATCHED.
|
|
4042
|
+
'flanger.lfo_type': { block: 'flanger', name: 'lfo_type', displayLabel: 'LFO Type', pidLow: 0x0052, pidHigh: 0x0012, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
4043
|
+
'flanger.auto_depth': { block: 'flanger', name: 'auto_depth', displayLabel: 'Auto Depth', pidLow: 0x0052, pidHigh: 0x0014, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4044
|
+
'flanger.phase_reverse': { block: 'flanger', name: 'phase_reverse', displayLabel: 'Phase Reverse', pidLow: 0x0052, pidHigh: 0x0015, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4045
|
+
'flanger.thru_zero': { block: 'flanger', name: 'thru_zero', displayLabel: 'Thru Zero', pidLow: 0x0052, pidHigh: 0x0016, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4046
|
+
'flanger.bypass_reset': { block: 'flanger', name: 'bypass_reset', displayLabel: 'Bypass Reset', pidLow: 0x0052, pidHigh: 0x001b, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4047
|
+
// High/Low Cut Slope: filter-stage IIR order (typical Fractal range
|
|
4048
|
+
// 1..12). Shipped as count until hardware verification supplies the
|
|
4049
|
+
// discrete slope labels (typical: 6/12/18/24 dB/oct).
|
|
4050
|
+
'flanger.high_cut_slope': { block: 'flanger', name: 'high_cut_slope', displayLabel: 'High Cut Slope', pidLow: 0x0052, pidHigh: 0x001c, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4051
|
+
'flanger.low_cut_slope': { block: 'flanger', name: 'low_cut_slope', displayLabel: 'Low Cut Slope', pidLow: 0x0052, pidHigh: 0x001d, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4052
|
+
'flanger.vco_response': { block: 'flanger', name: 'vco_response', displayLabel: 'VCO Response', pidLow: 0x0052, pidHigh: 0x001f, unit: 'count', displayMin: 0, displayMax: 10 },
|
|
4053
|
+
'flanger.steps': { block: 'flanger', name: 'steps', displayLabel: 'Steps', pidLow: 0x0052, pidHigh: 0x0022, unit: 'count', displayMin: 0, displayMax: 32 },
|
|
4054
|
+
// PHASER hand-author (9). 6 MATCH the AM4-Edit display label;
|
|
4055
|
+
// 3 are intentional disambiguations (lfo_type, vcr_curve, lfo_mode
|
|
4056
|
+
// — AM4-Edit displays "Type" / "Type" / "Mode" but `phaser.type` and
|
|
4057
|
+
// `phaser.mode` are already used) → WIRED-MISLABEL with ceiling bump.
|
|
4058
|
+
'phaser.order': { block: 'phaser', name: 'order', displayLabel: 'Order', pidLow: 0x005a, pidHigh: 0x000b, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4059
|
+
'phaser.lfo_type': { block: 'phaser', name: 'lfo_type', displayLabel: 'LFO Type', pidLow: 0x005a, pidHigh: 0x000d, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
4060
|
+
'phaser.mode': { block: 'phaser', name: 'mode', displayLabel: 'Mode', pidLow: 0x005a, pidHigh: 0x0015, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4061
|
+
'phaser.tone': { block: 'phaser', name: 'tone', displayLabel: 'Tone', pidLow: 0x005a, pidHigh: 0x0017, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4062
|
+
'phaser.direction': { block: 'phaser', name: 'direction', displayLabel: 'Direction', pidLow: 0x005a, pidHigh: 0x0018, unit: 'count', displayMin: 0, displayMax: 2 },
|
|
4063
|
+
'phaser.reset_on_bypass': { block: 'phaser', name: 'reset_on_bypass', displayLabel: 'Reset on Bypass', pidLow: 0x005a, pidHigh: 0x001a, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4064
|
+
'phaser.quantize': { block: 'phaser', name: 'quantize', displayLabel: 'Quantize', pidLow: 0x005a, pidHigh: 0x001b, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4065
|
+
// vcr_curve: AM4-Edit label is "Type" (alpha curve for the VCR
|
|
4066
|
+
// simulation on the Config page). Disambiguating suffix since
|
|
4067
|
+
// `phaser.type` is the family Type enum.
|
|
4068
|
+
'phaser.vcr_curve': { block: 'phaser', name: 'vcr_curve', displayLabel: 'Type', pidLow: 0x005a, pidHigh: 0x001c, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4069
|
+
// lfo_mode: AM4-Edit label is "Mode" (LFO mode selector). Disambig
|
|
4070
|
+
// suffix since `phaser.mode` is already taken above (PHASER_MODE,
|
|
4071
|
+
// no XML label).
|
|
4072
|
+
'phaser.lfo_mode': { block: 'phaser', name: 'lfo_mode', displayLabel: 'Mode', pidLow: 0x005a, pidHigh: 0x0025, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4073
|
+
// FILTER hand-author (10). 9 MATCH the AM4-Edit display label;
|
|
4074
|
+
// 1 is intentional disambiguation (order_2 — AM4-Edit displays
|
|
4075
|
+
// "Order" but `filter.order` is already at pidHigh=0x1c from the
|
|
4076
|
+
// cache pipeline) → WIRED-MISLABEL with ceiling bump.
|
|
4077
|
+
'filter.order_2': { block: 'filter', name: 'order_2', displayLabel: 'Order', pidLow: 0x0072, pidHigh: 0x000e, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4078
|
+
'filter.phase_invert': { block: 'filter', name: 'phase_invert', displayLabel: 'Phase Invert', pidLow: 0x0072, pidHigh: 0x0011, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4079
|
+
// enable: AM4-Edit displays "Enable" (LFO Enable on the LFO page).
|
|
4080
|
+
// Naming as `enable` matches the AM4-Edit label.
|
|
4081
|
+
'filter.enable': { block: 'filter', name: 'enable', displayLabel: 'Enable', pidLow: 0x0072, pidHigh: 0x0016, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4082
|
+
'filter.lfo_type': { block: 'filter', name: 'lfo_type', displayLabel: 'LFO Type', pidLow: 0x0072, pidHigh: 0x0017, unit: 'enum', displayMin: 0, displayMax: 9, enumValues: LFO_WAVEFORMS_VALUES },
|
|
4083
|
+
'filter.quantize': { block: 'filter', name: 'quantize', displayLabel: 'Quantize', pidLow: 0x0072, pidHigh: 0x001b, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4084
|
+
'filter.mode': { block: 'filter', name: 'mode', displayLabel: 'Mode', pidLow: 0x0072, pidHigh: 0x001d, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4085
|
+
'filter.sweep_shape': { block: 'filter', name: 'sweep_shape', displayLabel: 'Sweep Shape', pidLow: 0x0072, pidHigh: 0x0024, unit: 'count', displayMin: 0, displayMax: 10 },
|
|
4086
|
+
'filter.detector_source': { block: 'filter', name: 'detector_source', displayLabel: 'Detector Source', pidLow: 0x0072, pidHigh: 0x0025, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4087
|
+
'filter.detect': { block: 'filter', name: 'detect', displayLabel: 'Detect', pidLow: 0x0072, pidHigh: 0x0026, unit: 'count', displayMin: 0, displayMax: 3 },
|
|
4088
|
+
'filter.tempo': { block: 'filter', name: 'tempo', displayLabel: 'Tempo', pidLow: 0x0072, pidHigh: 0x0028, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
4089
|
+
// ── Session 92 (2026-05-17) — CABINET UI-MISSING closeout ──
|
|
4090
|
+
// 24 hand-authored entries on the canonical CABINET register
|
|
4091
|
+
// (pidLow=0x003e). Catalog source: Ghidra-extracted PATCH family
|
|
4092
|
+
// params via samples/captured/decoded/ghidra-am4-paramnames.json,
|
|
4093
|
+
// cross-referenced with AM4-Edit's __block_layout.xml +
|
|
4094
|
+
// __block_layout_expert.xml. Display labels come from the XML
|
|
4095
|
+
// `name=` attribute; entries lacking a display string are XML-
|
|
4096
|
+
// invisible firmware-internal controls (still wired via the
|
|
4097
|
+
// catalog).
|
|
4098
|
+
//
|
|
4099
|
+
// Deferred from this session (already addressable via the cross-
|
|
4100
|
+
// block resolver path at pidLow=0x003a):
|
|
4101
|
+
// • CABINET_PROXIMITY2 → amp.proximity in cacheParams.ts at 0x15
|
|
4102
|
+
// • CABINET_DYNACAB_Z1 → amp.distance in cacheParams.ts at 0x47
|
|
4103
|
+
// • CABINET_DYNACAB_Z2 → amp.distance_dynacab_z2 at 0x48
|
|
4104
|
+
// • CABINET_ZOOM (UI-toggle for editor zoom view, not a real
|
|
4105
|
+
// device-side setting — btnRectangleToggle in expert XML only)
|
|
4106
|
+
//
|
|
4107
|
+
// Confidence tiers:
|
|
4108
|
+
// HIGH — mirrors an existing first-cab entry (bank/cab/pan/
|
|
4109
|
+
// low_slope/high_slope/dynacab)
|
|
4110
|
+
// MEDIUM — labeled in XML, tonal unit inferred from sibling
|
|
4111
|
+
// controls (BASS/MID = knob_0_10 like amp tone stack)
|
|
4112
|
+
// LOWER — no XML label; unit: 'count' as a safe-write placeholder
|
|
4113
|
+
// until hardware verification supplies the range/enum
|
|
4114
|
+
//
|
|
4115
|
+
// Naming convention: `_1`/`_2` suffix mirrors existing
|
|
4116
|
+
// `cab_1_blend`/`cab_2_blend` / `low_slope`/`high_slope` pattern.
|
|
4117
|
+
// Per-cab knob names get the `cab_` prefix when the bare name would
|
|
4118
|
+
// collide with an amp-stack knob (cab_bass vs amp.bass, cab_mid
|
|
4119
|
+
// vs amp.mid).
|
|
4120
|
+
// Second-cab mirrors of existing first-cab entries (HIGH confidence).
|
|
4121
|
+
'amp.bank_2': { block: 'amp', name: 'bank_2', displayLabel: 'Bank', pidLow: 0x003e, pidHigh: 0x000b, unit: 'enum', displayMin: 0, displayMax: 31 },
|
|
4122
|
+
'amp.cab_2': { block: 'amp', name: 'cab_2', displayLabel: 'Cab #', pidLow: 0x003e, pidHigh: 0x000d, unit: 'count', displayMin: 0, displayMax: 511 },
|
|
4123
|
+
'amp.pan_2': { block: 'amp', name: 'pan_2', displayLabel: 'Pan', pidLow: 0x003e, pidHigh: 0x0011, unit: 'bipolar_percent', displayMin: -100, displayMax: 100 },
|
|
4124
|
+
'amp.low_slope_2': { block: 'amp', name: 'low_slope_2', displayLabel: 'Low Slope', pidLow: 0x003e, pidHigh: 0x003c, unit: 'enum', displayMin: 0, displayMax: 7 },
|
|
4125
|
+
'amp.high_slope_2': { block: 'amp', name: 'high_slope_2', displayLabel: 'High Slope', pidLow: 0x003e, pidHigh: 0x003e, unit: 'enum', displayMin: 0, displayMax: 7 },
|
|
4126
|
+
'amp.dynacab_2': { block: 'amp', name: 'dynacab_2', displayLabel: 'DynaCab', pidLow: 0x003e, pidHigh: 0x0046, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4127
|
+
// Per-cab level + proximity + mute (LEVEL1/2 have no XML label —
|
|
4128
|
+
// firmware-internal, but the names follow the established `_N`
|
|
4129
|
+
// suffix convention).
|
|
4130
|
+
'amp.cab_level_1': { block: 'amp', name: 'cab_level_1', pidLow: 0x003e, pidHigh: 0x000e, unit: 'db', displayMin: -80, displayMax: 20 },
|
|
4131
|
+
'amp.cab_level_2': { block: 'amp', name: 'cab_level_2', pidLow: 0x003e, pidHigh: 0x000f, unit: 'db', displayMin: -80, displayMax: 20 },
|
|
4132
|
+
'amp.proximity_1': { block: 'amp', name: 'proximity_1', displayLabel: 'Proximity', pidLow: 0x003e, pidHigh: 0x0014, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4133
|
+
'amp.cab_mute_1': { block: 'amp', name: 'cab_mute_1', displayLabel: 'M', pidLow: 0x003e, pidHigh: 0x0016, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4134
|
+
'amp.cab_mute_2': { block: 'amp', name: 'cab_mute_2', displayLabel: 'M', pidLow: 0x003e, pidHigh: 0x0017, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4135
|
+
// Master / cab-level Hz filters (LOCUT = master low cut on the
|
|
4136
|
+
// Cab Master EQ page; LOCUT1 = per-cab-1 low cut on the Cab page).
|
|
4137
|
+
// The existing `cab_master_low_cut` at pidHigh=0x22 is actually
|
|
4138
|
+
// wired to CABINET_PROXFREQ (catalog id 34) — a Session 53-era
|
|
4139
|
+
// misname that's left as-is for backward compatibility; this new
|
|
4140
|
+
// `master_low_cut` is the true CABINET_LOCUT control.
|
|
4141
|
+
'amp.master_low_cut': { block: 'amp', name: 'master_low_cut', displayLabel: 'Low Cut', pidLow: 0x003e, pidHigh: 0x001f, unit: 'hz', displayMin: 20, displayMax: 20000 },
|
|
4142
|
+
'amp.cab_1_low_cut': { block: 'amp', name: 'cab_1_low_cut', displayLabel: 'Low Cut', pidLow: 0x003e, pidHigh: 0x0035, unit: 'hz', displayMin: 20, displayMax: 20000 },
|
|
4143
|
+
// Mic-preamp tone-stack on the Cab Mic Preamp page (BASS/MID at
|
|
4144
|
+
// catalog ids 37/38; the existing `cab_mic_preamp_treble` at
|
|
4145
|
+
// pidHigh=0x27 already covers TREBLE at id 39). PRETYPE is the
|
|
4146
|
+
// Type dropdown on the same page (mic-preamp circuit selector).
|
|
4147
|
+
'amp.cab_pretype': { block: 'amp', name: 'cab_pretype', displayLabel: 'Type', pidLow: 0x003e, pidHigh: 0x0024, unit: 'count', displayMin: 0, displayMax: 15 },
|
|
4148
|
+
'amp.cab_bass': { block: 'amp', name: 'cab_bass', displayLabel: 'Bass', pidLow: 0x003e, pidHigh: 0x0025, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4149
|
+
'amp.cab_mid': { block: 'amp', name: 'cab_mid', displayLabel: 'Mid', pidLow: 0x003e, pidHigh: 0x0026, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4150
|
+
// SMOOTH1/2 / ORDER / GAINMONITOR — no XML labels (firmware-
|
|
4151
|
+
// internal). LOWER confidence: shipped as 'count' so the agent
|
|
4152
|
+
// can write any in-range value without claiming an interpretation.
|
|
4153
|
+
// HW-NNN capture needed to confirm semantics.
|
|
4154
|
+
'amp.cab_smooth_1': { block: 'amp', name: 'cab_smooth_1', pidLow: 0x003e, pidHigh: 0x0029, unit: 'count', displayMin: 0, displayMax: 10 },
|
|
4155
|
+
'amp.cab_smooth_2': { block: 'amp', name: 'cab_smooth_2', pidLow: 0x003e, pidHigh: 0x002a, unit: 'count', displayMin: 0, displayMax: 10 },
|
|
4156
|
+
'amp.cab_order': { block: 'amp', name: 'cab_order', pidLow: 0x003e, pidHigh: 0x002b, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4157
|
+
'amp.cab_gain_monitor': { block: 'amp', name: 'cab_gain_monitor', pidLow: 0x003e, pidHigh: 0x0033, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4158
|
+
// DynaCab quad (TYPE1/2/MIC1/2). XML has empty `name=""` in regular
|
|
4159
|
+
// layout and "Cab"/"Mic" in expert layout — the audit picks the
|
|
4160
|
+
// first XML hit, so these will MATCH (empty display).
|
|
4161
|
+
'amp.dynacab_type_1': { block: 'amp', name: 'dynacab_type_1', displayLabel: "Cab", pidLow: 0x003e, pidHigh: 0x0041, unit: 'count', displayMin: 0, displayMax: 31 },
|
|
4162
|
+
'amp.dynacab_type_2': { block: 'amp', name: 'dynacab_type_2', displayLabel: "Cab", pidLow: 0x003e, pidHigh: 0x0042, unit: 'count', displayMin: 0, displayMax: 31 },
|
|
4163
|
+
'amp.dynacab_mic_1': { block: 'amp', name: 'dynacab_mic_1', displayLabel: "Mic", pidLow: 0x003e, pidHigh: 0x0043, unit: 'count', displayMin: 0, displayMax: 31 },
|
|
4164
|
+
'amp.dynacab_mic_2': { block: 'amp', name: 'dynacab_mic_2', displayLabel: "Mic", pidLow: 0x003e, pidHigh: 0x0044, unit: 'count', displayMin: 0, displayMax: 31 },
|
|
4165
|
+
// ============================================================
|
|
4166
|
+
// GLOBAL family (pidLow = 0x0001) — 98 entries.
|
|
4167
|
+
//
|
|
4168
|
+
// Wire pidLow decoded HW-112 (Session 96, 2026-05-17) from
|
|
4169
|
+
// samples/captured/session-95-am4-global-pidlow.pcapng. paramIds
|
|
4170
|
+
// sourced from samples/captured/decoded/ghidra-am4-paramnames.json
|
|
4171
|
+
// (effect_types.case_0x1.params, 99 entries; GLOBAL_FC_HOLD_TIMEOUT
|
|
4172
|
+
// appears twice at paramId 57 so deduped to 98).
|
|
4173
|
+
//
|
|
4174
|
+
// Two paramIds are HW-verified by the HW-112 capture: USBLEVEL1
|
|
4175
|
+
// (99) at 1.11 dB and TAP_TEMPO_MODE (46) at 1.0 = "Last Two".
|
|
4176
|
+
// All other unit/range pairs are name-inferred — entries default
|
|
4177
|
+
// to unit: 'count' as a safe write placeholder pending hardware
|
|
4178
|
+
// verification. The Ghidra catalog gives us the address and the
|
|
4179
|
+
// symbolic name; UI semantics still need front-panel or AM4-Edit
|
|
4180
|
+
// captures to confirm range/enum tables.
|
|
4181
|
+
//
|
|
4182
|
+
// Naming convention: `global.<lowercased>` with the GLOBAL_ prefix
|
|
4183
|
+
// stripped and `+N` array suffixes converted to `_N` (so
|
|
4184
|
+
// `GLOBAL_EXT_CC_BEGIN+1` -> `global.ext_cc_begin_1`).
|
|
4185
|
+
//
|
|
4186
|
+
// Regenerate: `npx tsx scripts/_research/generate-am4-global-block.ts`
|
|
4187
|
+
// tuning reference Hz convention — HW unverified
|
|
4188
|
+
'global.tuningref': { block: 'global', name: 'tuningref', displayLabel: "Calibration", pidLow: 0x0001, pidHigh: 0x000d, unit: 'hz', displayMin: 430, displayMax: 450 },
|
|
4189
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4190
|
+
'global.tunermute': { block: 'global', name: 'tunermute', displayLabel: "Mute Type", pidLow: 0x0001, pidHigh: 0x000e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4191
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4192
|
+
'global.delayspill': { block: 'global', name: 'delayspill', displayLabel: "Spillover", pidLow: 0x0001, pidHigh: 0x000f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4193
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4194
|
+
'global.usetuneoffsets': { block: 'global', name: 'usetuneoffsets', displayLabel: "Use Offsets", pidLow: 0x0001, pidHigh: 0x0010, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4195
|
+
// per-string tuning offset — HW unverified
|
|
4196
|
+
'global.offset1': { block: 'global', name: 'offset1', displayLabel: "E 1", pidLow: 0x0001, pidHigh: 0x0011, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4197
|
+
// per-string tuning offset — HW unverified
|
|
4198
|
+
'global.offset2': { block: 'global', name: 'offset2', displayLabel: "B 2", pidLow: 0x0001, pidHigh: 0x0012, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4199
|
+
// per-string tuning offset — HW unverified
|
|
4200
|
+
'global.offset3': { block: 'global', name: 'offset3', displayLabel: "G 3", pidLow: 0x0001, pidHigh: 0x0013, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4201
|
+
// per-string tuning offset — HW unverified
|
|
4202
|
+
'global.offset4': { block: 'global', name: 'offset4', displayLabel: "D 4", pidLow: 0x0001, pidHigh: 0x0014, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4203
|
+
// per-string tuning offset — HW unverified
|
|
4204
|
+
'global.offset5': { block: 'global', name: 'offset5', displayLabel: "A 5", pidLow: 0x0001, pidHigh: 0x0015, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4205
|
+
// per-string tuning offset — HW unverified
|
|
4206
|
+
'global.offset6': { block: 'global', name: 'offset6', displayLabel: "E 6", pidLow: 0x0001, pidHigh: 0x0016, unit: 'semitones', displayMin: -1, displayMax: 1 },
|
|
4207
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4208
|
+
'global.out2eq1': { block: 'global', name: 'out2eq1', pidLow: 0x0001, pidHigh: 0x0022, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4209
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4210
|
+
'global.out2eq2': { block: 'global', name: 'out2eq2', pidLow: 0x0001, pidHigh: 0x0023, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4211
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4212
|
+
'global.out2eq3': { block: 'global', name: 'out2eq3', pidLow: 0x0001, pidHigh: 0x0024, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4213
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4214
|
+
'global.out2eq4': { block: 'global', name: 'out2eq4', pidLow: 0x0001, pidHigh: 0x0025, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4215
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4216
|
+
'global.out2eq5': { block: 'global', name: 'out2eq5', pidLow: 0x0001, pidHigh: 0x0026, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4217
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4218
|
+
'global.out2eq6': { block: 'global', name: 'out2eq6', pidLow: 0x0001, pidHigh: 0x0027, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4219
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4220
|
+
'global.out2eq7': { block: 'global', name: 'out2eq7', pidLow: 0x0001, pidHigh: 0x0028, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4221
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4222
|
+
'global.out2eq8': { block: 'global', name: 'out2eq8', pidLow: 0x0001, pidHigh: 0x0029, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4223
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4224
|
+
'global.out2eq9': { block: 'global', name: 'out2eq9', pidLow: 0x0001, pidHigh: 0x002a, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4225
|
+
// GEQ band ±12 dB convention — HW unverified
|
|
4226
|
+
'global.out2eq10': { block: 'global', name: 'out2eq10', pidLow: 0x0001, pidHigh: 0x002b, unit: 'db', displayMin: -12, displayMax: 12 },
|
|
4227
|
+
// gate threshold offset dB — HW unverified
|
|
4228
|
+
'global.gate_offset': { block: 'global', name: 'gate_offset', displayLabel: "Noisegate Offset", pidLow: 0x0001, pidHigh: 0x002d, unit: 'db', displayMin: -40, displayMax: 0 },
|
|
4229
|
+
// HW-112 (Session 96) — captured at 1.0 = "Last Two"; full enum table pending HW
|
|
4230
|
+
'global.tap_tempo_mode': { block: 'global', name: 'tap_tempo_mode', displayLabel: "Tap Tempo Mode", pidLow: 0x0001, pidHigh: 0x002e, unit: 'enum', displayMin: 0, displayMax: 7 },
|
|
4231
|
+
// input trim percent — HW unverified
|
|
4232
|
+
'global.in1_trim': { block: 'global', name: 'in1_trim', displayLabel: "Input Pad", pidLow: 0x0001, pidHigh: 0x002f, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4233
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4234
|
+
'global.out1_config': { block: 'global', name: 'out1_config', displayLabel: "Output Mode", pidLow: 0x0001, pidHigh: 0x0030, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4235
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4236
|
+
'global.out1_phase': { block: 'global', name: 'out1_phase', displayLabel: "Output Phase", pidLow: 0x0001, pidHigh: 0x0031, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4237
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4238
|
+
'global.in1_source': { block: 'global', name: 'in1_source', displayLabel: "Input Source", pidLow: 0x0001, pidHigh: 0x0034, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4239
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4240
|
+
'global.in1_config': { block: 'global', name: 'in1_config', pidLow: 0x0001, pidHigh: 0x0035, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4241
|
+
// percent inferred from AM4-Edit display — HW unverified
|
|
4242
|
+
'global.lcd_contrast': { block: 'global', name: 'lcd_contrast', displayLabel: "LCD Contrast", pidLow: 0x0001, pidHigh: 0x0038, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4243
|
+
// press-hold timeout ms — HW unverified
|
|
4244
|
+
'global.fc_hold_timeout': { block: 'global', name: 'fc_hold_timeout', displayLabel: "Hold Timeout", pidLow: 0x0001, pidHigh: 0x0039, unit: 'ms', displayMin: 0, displayMax: 5000 },
|
|
4245
|
+
// MIDI channel 1..16
|
|
4246
|
+
'global.midi_chan': { block: 'global', name: 'midi_chan', displayLabel: "MIDI Channel", pidLow: 0x0001, pidHigh: 0x003a, unit: 'count', displayMin: 1, displayMax: 16 },
|
|
4247
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4248
|
+
'global.midi_prog_change': { block: 'global', name: 'midi_prog_change', displayLabel: "Receive MIDI PC", pidLow: 0x0001, pidHigh: 0x003b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4249
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4250
|
+
'global.no_redundant_pc': { block: 'global', name: 'no_redundant_pc', displayLabel: "Ignore Redundant PC", pidLow: 0x0001, pidHigh: 0x003c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4251
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4252
|
+
'global.send_midipc': { block: 'global', name: 'send_midipc', displayLabel: "Send MIDI PC", pidLow: 0x0001, pidHigh: 0x003f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4253
|
+
'global.in1_vol_cc': { block: 'global', name: 'in1_vol_cc', displayLabel: "Input Volume", pidLow: 0x0001, pidHigh: 0x0046, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4254
|
+
'global.out1_vol_cc': { block: 'global', name: 'out1_vol_cc', displayLabel: "Output Volume", pidLow: 0x0001, pidHigh: 0x0047, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4255
|
+
'global.tempo_cc': { block: 'global', name: 'tempo_cc', displayLabel: "Tap Tempo", pidLow: 0x0001, pidHigh: 0x0048, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4256
|
+
'global.tuner_cc': { block: 'global', name: 'tuner_cc', displayLabel: "Tuner", pidLow: 0x0001, pidHigh: 0x0049, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4257
|
+
'global.scene_cc': { block: 'global', name: 'scene_cc', displayLabel: "Scene Select", pidLow: 0x0001, pidHigh: 0x004a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4258
|
+
'global.scene_incr_cc': { block: 'global', name: 'scene_incr_cc', displayLabel: "Scene +1", pidLow: 0x0001, pidHigh: 0x004b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4259
|
+
'global.scene_decr_cc': { block: 'global', name: 'scene_decr_cc', displayLabel: "Scene -1", pidLow: 0x0001, pidHigh: 0x004c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4260
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4261
|
+
'global.scene_revert': { block: 'global', name: 'scene_revert', pidLow: 0x0001, pidHigh: 0x004d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4262
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4263
|
+
'global.custom_scale': { block: 'global', name: 'custom_scale', pidLow: 0x0001, pidHigh: 0x0050, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4264
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4265
|
+
'global.tuner_source': { block: 'global', name: 'tuner_source', pidLow: 0x0001, pidHigh: 0x0053, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4266
|
+
// AM4 has 4 scenes (1..4)
|
|
4267
|
+
'global.default_scene': { block: 'global', name: 'default_scene', displayLabel: "Default Scene", pidLow: 0x0001, pidHigh: 0x0056, unit: 'count', displayMin: 1, displayMax: 4 },
|
|
4268
|
+
// percent inferred from AM4-Edit display — HW unverified
|
|
4269
|
+
'global.fc_ring_bright_level': { block: 'global', name: 'fc_ring_bright_level', displayLabel: "Switch LED Bright", pidLow: 0x0001, pidHigh: 0x0058, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4270
|
+
// percent inferred from AM4-Edit display — HW unverified
|
|
4271
|
+
'global.fc_ring_dim_level': { block: 'global', name: 'fc_ring_dim_level', displayLabel: "Switch LED Dim", pidLow: 0x0001, pidHigh: 0x0059, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4272
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4273
|
+
'global.linefreq': { block: 'global', name: 'linefreq', displayLabel: "AC Line Frequency", pidLow: 0x0001, pidHigh: 0x005a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4274
|
+
'global.preset_incr_cc': { block: 'global', name: 'preset_incr_cc', displayLabel: "Preset +1", pidLow: 0x0001, pidHigh: 0x005d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4275
|
+
'global.preset_decr_cc': { block: 'global', name: 'preset_decr_cc', displayLabel: "Preset -1", pidLow: 0x0001, pidHigh: 0x005e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4276
|
+
// unit inferred from USBLEVEL1 sibling — HW unverified
|
|
4277
|
+
'global.metlevel1': { block: 'global', name: 'metlevel1', displayLabel: "Metronome Level", pidLow: 0x0001, pidHigh: 0x0061, unit: 'db', displayMin: -64, displayMax: 24 },
|
|
4278
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4279
|
+
'global.usb78_source': { block: 'global', name: 'usb78_source', displayLabel: "USB 3/4 Record Source", pidLow: 0x0001, pidHigh: 0x0062, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4280
|
+
// HW-112 (Session 96) — captured at 1.11 dB
|
|
4281
|
+
'global.usblevel1': { block: 'global', name: 'usblevel1', displayLabel: "USB 1/2 Level", pidLow: 0x0001, pidHigh: 0x0063, unit: 'db', displayMin: -64, displayMax: 24 },
|
|
4282
|
+
// unit inferred from USBLEVEL1 sibling — HW unverified
|
|
4283
|
+
'global.usblevel2': { block: 'global', name: 'usblevel2', displayLabel: "USB 3/4 Level", pidLow: 0x0001, pidHigh: 0x0064, unit: 'db', displayMin: -64, displayMax: 24 },
|
|
4284
|
+
// unit inferred from USBLEVEL1 sibling — HW unverified
|
|
4285
|
+
'global.aeslevel': { block: 'global', name: 'aeslevel', displayLabel: "SPDIF In Level", pidLow: 0x0001, pidHigh: 0x0065, unit: 'db', displayMin: -64, displayMax: 24 },
|
|
4286
|
+
// down-tune semitones — HW unverified
|
|
4287
|
+
'global.downtune': { block: 'global', name: 'downtune', displayLabel: "Downtune", pidLow: 0x0001, pidHigh: 0x0067, unit: 'semitones', displayMin: -12, displayMax: 0 },
|
|
4288
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4289
|
+
'global.tuneraccidentals': { block: 'global', name: 'tuneraccidentals', displayLabel: "Display Mode", pidLow: 0x0001, pidHigh: 0x0068, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4290
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4291
|
+
'global.midi_thru': { block: 'global', name: 'midi_thru', displayLabel: "MIDI Thru", pidLow: 0x0001, pidHigh: 0x006d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4292
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4293
|
+
'global.tuner_on_volume': { block: 'global', name: 'tuner_on_volume', displayLabel: "Tuner on Heel Down", pidLow: 0x0001, pidHigh: 0x006e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4294
|
+
'global.bypass_fx1_cc': { block: 'global', name: 'bypass_fx1_cc', displayLabel: "FX1 Bypass", pidLow: 0x0001, pidHigh: 0x006f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4295
|
+
'global.bypass_fx2_cc': { block: 'global', name: 'bypass_fx2_cc', displayLabel: "FX2 Bypass", pidLow: 0x0001, pidHigh: 0x0070, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4296
|
+
'global.bypass_fx3_cc': { block: 'global', name: 'bypass_fx3_cc', displayLabel: "FX3 Bypass", pidLow: 0x0001, pidHigh: 0x0071, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4297
|
+
'global.bypass_fx4_cc': { block: 'global', name: 'bypass_fx4_cc', displayLabel: "FX4 Bypass", pidLow: 0x0001, pidHigh: 0x0072, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4298
|
+
'global.channel_fx1_cc': { block: 'global', name: 'channel_fx1_cc', displayLabel: "FX1 Channel", pidLow: 0x0001, pidHigh: 0x0073, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4299
|
+
'global.channel_fx2_cc': { block: 'global', name: 'channel_fx2_cc', displayLabel: "FX2 Channel", pidLow: 0x0001, pidHigh: 0x0074, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4300
|
+
'global.channel_fx3_cc': { block: 'global', name: 'channel_fx3_cc', displayLabel: "FX3 Channel", pidLow: 0x0001, pidHigh: 0x0075, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4301
|
+
'global.channel_fx4_cc': { block: 'global', name: 'channel_fx4_cc', displayLabel: "FX4 Channel", pidLow: 0x0001, pidHigh: 0x0076, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4302
|
+
// external CC routing — CC number 0..127
|
|
4303
|
+
'global.ext_cc_begin': { block: 'global', name: 'ext_cc_begin', displayLabel: "External 1", pidLow: 0x0001, pidHigh: 0x0077, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4304
|
+
// external CC routing — CC number 0..127
|
|
4305
|
+
'global.ext_cc_begin_1': { block: 'global', name: 'ext_cc_begin_1', pidLow: 0x0001, pidHigh: 0x0078, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4306
|
+
// external CC routing — CC number 0..127
|
|
4307
|
+
'global.ext_cc_begin_2': { block: 'global', name: 'ext_cc_begin_2', pidLow: 0x0001, pidHigh: 0x0079, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4308
|
+
// external CC routing — CC number 0..127
|
|
4309
|
+
'global.ext_cc_begin_3': { block: 'global', name: 'ext_cc_begin_3', pidLow: 0x0001, pidHigh: 0x007a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4310
|
+
// external CC initial value 0..127
|
|
4311
|
+
'global.ext_startval_begin': { block: 'global', name: 'ext_startval_begin', displayLabel: "External 1", pidLow: 0x0001, pidHigh: 0x007b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4312
|
+
// external CC initial value 0..127
|
|
4313
|
+
'global.ext_startval_begin_1': { block: 'global', name: 'ext_startval_begin_1', pidLow: 0x0001, pidHigh: 0x007c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4314
|
+
// external CC initial value 0..127
|
|
4315
|
+
'global.ext_startval_begin_2': { block: 'global', name: 'ext_startval_begin_2', pidLow: 0x0001, pidHigh: 0x007d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4316
|
+
// external CC initial value 0..127
|
|
4317
|
+
'global.ext_startval_begin_3': { block: 'global', name: 'ext_startval_begin_3', pidLow: 0x0001, pidHigh: 0x007e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4318
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4319
|
+
'global.auto_truebypass': { block: 'global', name: 'auto_truebypass', displayLabel: "Automatic AM4 Bypass", pidLow: 0x0001, pidHigh: 0x0081, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4320
|
+
'global.truebypass_cc': { block: 'global', name: 'truebypass_cc', displayLabel: "AM4 Bypass", pidLow: 0x0001, pidHigh: 0x0083, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4321
|
+
// press-hold timeout ms — HW unverified
|
|
4322
|
+
'global.fs_press_hold1': { block: 'global', name: 'fs_press_hold1', displayLabel: "Press & Hold 1", pidLow: 0x0001, pidHigh: 0x0084, unit: 'ms', displayMin: 0, displayMax: 5000 },
|
|
4323
|
+
// press-hold timeout ms — HW unverified
|
|
4324
|
+
'global.fs_press_hold2': { block: 'global', name: 'fs_press_hold2', displayLabel: "Press & Hold 2", pidLow: 0x0001, pidHigh: 0x0085, unit: 'ms', displayMin: 0, displayMax: 5000 },
|
|
4325
|
+
// press-hold timeout ms — HW unverified
|
|
4326
|
+
'global.fs_press_hold3': { block: 'global', name: 'fs_press_hold3', displayLabel: "Press & Hold 3", pidLow: 0x0001, pidHigh: 0x0086, unit: 'ms', displayMin: 0, displayMax: 5000 },
|
|
4327
|
+
// press-hold timeout ms — HW unverified
|
|
4328
|
+
'global.fs_press_hold4': { block: 'global', name: 'fs_press_hold4', displayLabel: "Press & Hold 4", pidLow: 0x0001, pidHigh: 0x0087, unit: 'ms', displayMin: 0, displayMax: 5000 },
|
|
4329
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4330
|
+
'global.startup_mode': { block: 'global', name: 'startup_mode', displayLabel: "Startup Mode", pidLow: 0x0001, pidHigh: 0x0089, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4331
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4332
|
+
'global.gap_fill': { block: 'global', name: 'gap_fill', displayLabel: "Gapless Changes", pidLow: 0x0001, pidHigh: 0x008f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4333
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4334
|
+
'global.select_fade': { block: 'global', name: 'select_fade', displayLabel: "Fade Timeout", pidLow: 0x0001, pidHigh: 0x0091, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4335
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4336
|
+
'global.presshold_mode': { block: 'global', name: 'presshold_mode', displayLabel: "Press & Hold Mode", pidLow: 0x0001, pidHigh: 0x0092, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4337
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4338
|
+
'global.tap_amp_fx_mode': { block: 'global', name: 'tap_amp_fx_mode', displayLabel: "Tap Amp in FX Mode", pidLow: 0x0001, pidHigh: 0x0093, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4339
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4340
|
+
'global.tap_amp_ch_amp_mode': { block: 'global', name: 'tap_amp_ch_amp_mode', displayLabel: "Tap Current Ch. in Amp Mode", pidLow: 0x0001, pidHigh: 0x0094, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4341
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4342
|
+
'global.cabinetbyp': { block: 'global', name: 'cabinetbyp', displayLabel: "Cab Modeling", pidLow: 0x0001, pidHigh: 0x0095, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4343
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4344
|
+
'global.pwrampbyp': { block: 'global', name: 'pwrampbyp', displayLabel: "Power Amp Modeling", pidLow: 0x0001, pidHigh: 0x0096, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4345
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4346
|
+
'global.sprk_model': { block: 'global', name: 'sprk_model', displayLabel: "Speaker Imp. Curve", pidLow: 0x0001, pidHigh: 0x0097, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4347
|
+
'global.amp_chan_cc': { block: 'global', name: 'amp_chan_cc', displayLabel: "Amp Channel", pidLow: 0x0001, pidHigh: 0x0098, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4348
|
+
'global.out_boost_cc': { block: 'global', name: 'out_boost_cc', displayLabel: "Amp Out Boost", pidLow: 0x0001, pidHigh: 0x0099, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4349
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4350
|
+
'global.scenesync_ch': { block: 'global', name: 'scenesync_ch', displayLabel: "Scene Sync Channel", pidLow: 0x0001, pidHigh: 0x009c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4351
|
+
'global.scenesync_cc': { block: 'global', name: 'scenesync_cc', displayLabel: "Scene Sync CC#", pidLow: 0x0001, pidHigh: 0x009d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4352
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4353
|
+
'global.dynacab_sync': { block: 'global', name: 'dynacab_sync', pidLow: 0x0001, pidHigh: 0x009e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4354
|
+
'global.amp1_vol_cc': { block: 'global', name: 'amp1_vol_cc', displayLabel: "Amp Block Out Vol", pidLow: 0x0001, pidHigh: 0x009f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4355
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4356
|
+
'global.metronome': { block: 'global', name: 'metronome', displayLabel: "Metronome", pidLow: 0x0001, pidHigh: 0x00a0, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4357
|
+
'global.metronome_cc': { block: 'global', name: 'metronome_cc', displayLabel: "Metronome", pidLow: 0x0001, pidHigh: 0x00a1, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4358
|
+
// safe placeholder (range unverified) — Ghidra catalog entry only
|
|
4359
|
+
'global.inspdif_config': { block: 'global', name: 'inspdif_config', displayLabel: "SPDIF Input Mode", pidLow: 0x0001, pidHigh: 0x00a2, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4360
|
+
// ============================================================
|
|
4361
|
+
// Session 96 (2026-05-17) UI-MISSING closeout — wires the
|
|
4362
|
+
// remaining placeable-family entries the AM4-Edit XML exposes
|
|
4363
|
+
// but params.ts didn't carry. Catalog symbols sourced from
|
|
4364
|
+
// `samples/captured/decoded/ghidra-am4-paramnames.json`,
|
|
4365
|
+
// display labels from `__block_layout.xml` /
|
|
4366
|
+
// `__block_layout_expert.xml` (mined by
|
|
4367
|
+
// `scripts/_research/list-ui-missing.ts`).
|
|
4368
|
+
//
|
|
4369
|
+
// UI widgets (paramId >= 65000 — name/label/button/graph/menu
|
|
4370
|
+
// sentinels) intentionally skipped: those addresses back UI
|
|
4371
|
+
// chrome in AM4-Edit, not writable preset data. Catalog symbols
|
|
4372
|
+
// dropped: CABINET_NAME{1,2}, CABINET_LABEL{1,2},
|
|
4373
|
+
// CABINET_ALIGN_*, CABINET_COPY_MENU{1,2}, DISTORT_ZEROEQ.
|
|
4374
|
+
//
|
|
4375
|
+
// Unit/range pairs are name-inferred. Toggle-style switches
|
|
4376
|
+
// (*_SW / *_ONOFF) get enum 0..1 with OFF/ON. Type/menu/color
|
|
4377
|
+
// enums without captured enum tables default to count 0..127 so
|
|
4378
|
+
// the agent can write any in-range value without claiming an
|
|
4379
|
+
// interpretation. Knob-style names (Sag / Breakup / Compensation
|
|
4380
|
+
// / Pres. Shift) get knob_0_10 — a reasonable convention for the
|
|
4381
|
+
// amp Extras / Speaker pages until HW captures pin exact ranges.
|
|
4382
|
+
// ---- CABINET (pidLow=0x003e) — 4 entries ----
|
|
4383
|
+
'amp.cab_proximity_2': { block: 'amp', name: 'cab_proximity_2', displayLabel: 'Proximity', pidLow: 0x003e, pidHigh: 0x0015, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4384
|
+
'amp.cab_zoom': { block: 'amp', name: 'cab_zoom', displayLabel: "ZOOM", pidLow: 0x003e, pidHigh: 0x0021, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4385
|
+
'amp.cab_dynacab_z_1': { block: 'amp', name: 'cab_dynacab_z_1', displayLabel: 'Distance', pidLow: 0x003e, pidHigh: 0x0047, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4386
|
+
'amp.cab_dynacab_z_2': { block: 'amp', name: 'cab_dynacab_z_2', displayLabel: 'Distance', pidLow: 0x003e, pidHigh: 0x0048, unit: 'percent', displayMin: 0, displayMax: 100 },
|
|
4387
|
+
// ---- DISTORT / amp Extras + Speaker pages (pidLow=0x003a) — 18 entries ----
|
|
4388
|
+
'amp.in_boost_sw': { block: 'amp', name: 'in_boost_sw', displayLabel: 'In Boost Sw', pidLow: 0x003a, pidHigh: 0x002f, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4389
|
+
'amp.saturation_sw': { block: 'amp', name: 'saturation_sw', displayLabel: 'Saturation Sw', pidLow: 0x003a, pidHigh: 0x003d, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4390
|
+
'amp.preamp_tube_type': { block: 'amp', name: 'preamp_tube_type', displayLabel: 'Preamp Tube Type', pidLow: 0x003a, pidHigh: 0x004c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4391
|
+
'amp.power_type': { block: 'amp', name: 'power_type', displayLabel: 'Power Type', pidLow: 0x003a, pidHigh: 0x005d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4392
|
+
'amp.preamp_sag': { block: 'amp', name: 'preamp_sag', displayLabel: 'Preamp Sag', pidLow: 0x003a, pidHigh: 0x0067, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4393
|
+
'amp.in_eq_type': { block: 'amp', name: 'in_eq_type', displayLabel: 'Type', pidLow: 0x003a, pidHigh: 0x006d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4394
|
+
'amp.pres_shift': { block: 'amp', name: 'pres_shift', displayLabel: 'Pres. Shift', pidLow: 0x003a, pidHigh: 0x006f, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4395
|
+
'amp.eq_location': { block: 'amp', name: 'eq_location', displayLabel: 'Location', pidLow: 0x003a, pidHigh: 0x0075, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4396
|
+
'amp.in_boost_type': { block: 'amp', name: 'in_boost_type', displayLabel: 'In Boost Type', pidLow: 0x003a, pidHigh: 0x0082, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4397
|
+
'amp.eq_onoff': { block: 'amp', name: 'eq_onoff', displayLabel: 'Off / On', pidLow: 0x003a, pidHigh: 0x0085, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4398
|
+
'amp.spkr_imp_curve': { block: 'amp', name: 'spkr_imp_curve', displayLabel: 'Spkr Imp. Curve', pidLow: 0x003a, pidHigh: 0x0087, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4399
|
+
'amp.power_amp_modeling': { block: 'amp', name: 'power_amp_modeling', displayLabel: 'Power Amp Modeling', pidLow: 0x003a, pidHigh: 0x008d, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4400
|
+
'amp.spkr_breakup': { block: 'amp', name: 'spkr_breakup', displayLabel: 'Breakup', pidLow: 0x003a, pidHigh: 0x008e, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4401
|
+
'amp.plate_suppr_diodes': { block: 'amp', name: 'plate_suppr_diodes', displayLabel: 'Plate Suppr. Diodes', pidLow: 0x003a, pidHigh: 0x0090, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4402
|
+
'amp.dynamatch': { block: 'amp', name: 'dynamatch', displayLabel: 'DynaMatch', pidLow: 0x003a, pidHigh: 0x0092, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4403
|
+
'amp.nfb_compensation': { block: 'amp', name: 'nfb_compensation', displayLabel: 'NFB Compensation', pidLow: 0x003a, pidHigh: 0x0093, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4404
|
+
'amp.mid_gain_boost': { block: 'amp', name: 'mid_gain_boost', displayLabel: 'Mid/Gain Boost', pidLow: 0x003a, pidHigh: 0x0094, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4405
|
+
'amp.tubes': { block: 'amp', name: 'tubes', displayLabel: 'Tubes', pidLow: 0x003a, pidHigh: 0x0095, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4406
|
+
// ---- PATCH (pidLow=0x00ce) — 29 entries ----
|
|
4407
|
+
// Channel A/B/C/D color pickers. AM4-Edit shows ~8 named colors;
|
|
4408
|
+
// exact enum table not yet captured, so count 0..127 as
|
|
4409
|
+
// safe-write placeholder.
|
|
4410
|
+
'preset.channel_a_color': { block: 'preset', name: 'channel_a_color', displayLabel: 'Channel A Color', pidLow: 0x00ce, pidHigh: 0x0071, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4411
|
+
'preset.channel_b_color': { block: 'preset', name: 'channel_b_color', displayLabel: 'Channel B Color', pidLow: 0x00ce, pidHigh: 0x0072, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4412
|
+
'preset.channel_c_color': { block: 'preset', name: 'channel_c_color', displayLabel: 'Channel C Color', pidLow: 0x00ce, pidHigh: 0x0073, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4413
|
+
'preset.channel_d_color': { block: 'preset', name: 'channel_d_color', displayLabel: 'Channel D Color', pidLow: 0x00ce, pidHigh: 0x0074, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4414
|
+
// Scene MIDI EXEC slots (paramId 118..137 — 4 + 16 = 20).
|
|
4415
|
+
// XML labels are empty for these — they're PATCH-page editor
|
|
4416
|
+
// infrastructure. Catalog still lists them as writable params,
|
|
4417
|
+
// so we ship them as count placeholders for programmatic access
|
|
4418
|
+
// (copy/clear/inspect scene-MIDI command state from a script).
|
|
4419
|
+
// Naming mirrors the existing preset.scene_N_midi_M_{type,
|
|
4420
|
+
// channel,value} pattern shipping at pidHigh 0x40..0x67.
|
|
4421
|
+
'preset.scene_1_midi_exec': { block: 'preset', name: 'scene_1_midi_exec', pidLow: 0x00ce, pidHigh: 0x0076, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4422
|
+
'preset.scene_2_midi_exec': { block: 'preset', name: 'scene_2_midi_exec', pidLow: 0x00ce, pidHigh: 0x0077, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4423
|
+
'preset.scene_3_midi_exec': { block: 'preset', name: 'scene_3_midi_exec', pidLow: 0x00ce, pidHigh: 0x0078, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4424
|
+
'preset.scene_4_midi_exec': { block: 'preset', name: 'scene_4_midi_exec', pidLow: 0x00ce, pidHigh: 0x0079, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4425
|
+
'preset.scene_1_midi_exec_1': { block: 'preset', name: 'scene_1_midi_exec_1', pidLow: 0x00ce, pidHigh: 0x007a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4426
|
+
'preset.scene_1_midi_exec_2': { block: 'preset', name: 'scene_1_midi_exec_2', pidLow: 0x00ce, pidHigh: 0x007b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4427
|
+
'preset.scene_1_midi_exec_3': { block: 'preset', name: 'scene_1_midi_exec_3', pidLow: 0x00ce, pidHigh: 0x007c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4428
|
+
'preset.scene_1_midi_exec_4': { block: 'preset', name: 'scene_1_midi_exec_4', pidLow: 0x00ce, pidHigh: 0x007d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4429
|
+
'preset.scene_2_midi_exec_1': { block: 'preset', name: 'scene_2_midi_exec_1', pidLow: 0x00ce, pidHigh: 0x007e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4430
|
+
'preset.scene_2_midi_exec_2': { block: 'preset', name: 'scene_2_midi_exec_2', pidLow: 0x00ce, pidHigh: 0x007f, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4431
|
+
'preset.scene_2_midi_exec_3': { block: 'preset', name: 'scene_2_midi_exec_3', pidLow: 0x00ce, pidHigh: 0x0080, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4432
|
+
'preset.scene_2_midi_exec_4': { block: 'preset', name: 'scene_2_midi_exec_4', pidLow: 0x00ce, pidHigh: 0x0081, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4433
|
+
'preset.scene_3_midi_exec_1': { block: 'preset', name: 'scene_3_midi_exec_1', pidLow: 0x00ce, pidHigh: 0x0082, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4434
|
+
'preset.scene_3_midi_exec_2': { block: 'preset', name: 'scene_3_midi_exec_2', pidLow: 0x00ce, pidHigh: 0x0083, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4435
|
+
'preset.scene_3_midi_exec_3': { block: 'preset', name: 'scene_3_midi_exec_3', pidLow: 0x00ce, pidHigh: 0x0084, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4436
|
+
'preset.scene_3_midi_exec_4': { block: 'preset', name: 'scene_3_midi_exec_4', pidLow: 0x00ce, pidHigh: 0x0085, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4437
|
+
'preset.scene_4_midi_exec_1': { block: 'preset', name: 'scene_4_midi_exec_1', pidLow: 0x00ce, pidHigh: 0x0086, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4438
|
+
'preset.scene_4_midi_exec_2': { block: 'preset', name: 'scene_4_midi_exec_2', pidLow: 0x00ce, pidHigh: 0x0087, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4439
|
+
'preset.scene_4_midi_exec_3': { block: 'preset', name: 'scene_4_midi_exec_3', pidLow: 0x00ce, pidHigh: 0x0088, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4440
|
+
'preset.scene_4_midi_exec_4': { block: 'preset', name: 'scene_4_midi_exec_4', pidLow: 0x00ce, pidHigh: 0x0089, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4441
|
+
// Per-scene MIDI menu trigger + clear-all action.
|
|
4442
|
+
'preset.scene_1_menu': { block: 'preset', name: 'scene_1_menu', displayLabel: 'SCENE 1 menu', pidLow: 0x00ce, pidHigh: 0x008a, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4443
|
+
'preset.scene_2_menu': { block: 'preset', name: 'scene_2_menu', displayLabel: 'SCENE 2 menu', pidLow: 0x00ce, pidHigh: 0x008b, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4444
|
+
'preset.scene_3_menu': { block: 'preset', name: 'scene_3_menu', displayLabel: 'SCENE 3 menu', pidLow: 0x00ce, pidHigh: 0x008c, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4445
|
+
'preset.scene_4_menu': { block: 'preset', name: 'scene_4_menu', displayLabel: 'SCENE 4 menu', pidLow: 0x00ce, pidHigh: 0x008d, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4446
|
+
'preset.clear_all': { block: 'preset', name: 'clear_all', displayLabel: 'Clear All', pidLow: 0x00ce, pidHigh: 0x008e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4447
|
+
// ============================================================
|
|
4448
|
+
// Session 97 (2026-05-18) UI-MISSING residual closeout — wires the
|
|
4449
|
+
// 15 remaining placeable-family entries the AM4-Edit XML exposes
|
|
4450
|
+
// but params.ts didn't carry. Catalog symbols sourced from
|
|
4451
|
+
// `samples/captured/decoded/ghidra-am4-paramnames.json`,
|
|
4452
|
+
// display labels from `__block_layout.xml` /
|
|
4453
|
+
// `__block_layout_expert.xml` (mined by
|
|
4454
|
+
// `scripts/_research/list-ui-missing.ts`).
|
|
4455
|
+
//
|
|
4456
|
+
// UI widgets (paramId >= 65000 or empty XML label — meter/name/
|
|
4457
|
+
// label/button/graph/menu sentinels) intentionally skipped: those
|
|
4458
|
+
// addresses back UI chrome in AM4-Edit, not writable preset data.
|
|
4459
|
+
// Catalog symbols dropped this pass: CABINET_NAME{1,2},
|
|
4460
|
+
// CABINET_LABEL{1,2}, CABINET_ALIGN_*, CABINET_COPY_MENU{1,2},
|
|
4461
|
+
// GEQ_ZEROEQ, INPUT_METERS, VOLUME_METER, DISTORT_ZEROEQ.
|
|
4462
|
+
//
|
|
4463
|
+
// Unit/range conventions mirror commit b67e23f (Session 96):
|
|
4464
|
+
// toggle-style switches → enum 0..1 OFF/ON; type/menu enums
|
|
4465
|
+
// without captured tables → count 0..127; read-only meters
|
|
4466
|
+
// → knob_0_10. Slope params follow the FLANGER convention
|
|
4467
|
+
// (count 1..12) since no capture pins enum vs count yet.
|
|
4468
|
+
// ---- PEQ (pidLow=0x0036) — 2 entries ----
|
|
4469
|
+
// PEQ_LOWSLOPE / PEQ_HIGHSLOPE address the shelf-channel slope on
|
|
4470
|
+
// channel 1 (low shelf) and channel 5 (high shelf). XML labels
|
|
4471
|
+
// "Slope 1" / "Slope 5"; name follows the existing channel_N_*
|
|
4472
|
+
// family-prefix pattern (channel_1_frequency, channel_5_q, etc.).
|
|
4473
|
+
'peq.channel_1_slope': { block: 'peq', name: 'channel_1_slope', displayLabel: 'Slope 1', pidLow: 0x0036, pidHigh: 0x0023, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4474
|
+
'peq.channel_5_slope': { block: 'peq', name: 'channel_5_slope', displayLabel: 'Slope 5', pidLow: 0x0036, pidHigh: 0x0024, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4475
|
+
// ---- COMP (pidLow=0x002e) — 4 entries ----
|
|
4476
|
+
// gain_monitor is a read-only meter — `gain` collides with the
|
|
4477
|
+
// existing compressor knob; the _monitor suffix matches the AMP
|
|
4478
|
+
// family's b_plus_monitor / gain_monitor / headroom_monitor
|
|
4479
|
+
// convention from Session 89.
|
|
4480
|
+
'compressor.knee_type': { block: 'compressor', name: 'knee_type', displayLabel: 'Knee Type', pidLow: 0x002e, pidHigh: 0x000e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4481
|
+
'compressor.detector_type': { block: 'compressor', name: 'detector_type', displayLabel: 'Detector Type', pidLow: 0x002e, pidHigh: 0x0010, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4482
|
+
'compressor.auto_attack_release': { block: 'compressor', name: 'auto_attack_release', displayLabel: 'Auto Att/Rel', pidLow: 0x002e, pidHigh: 0x0016, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4483
|
+
'compressor.gain_monitor': { block: 'compressor', name: 'gain_monitor', displayLabel: 'Gain', pidLow: 0x002e, pidHigh: 0x001f, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4484
|
+
// ---- GATE (pidLow=0x0092) — 1 entry ----
|
|
4485
|
+
'gate.gain_monitor': { block: 'gate', name: 'gain_monitor', displayLabel: 'Gain', pidLow: 0x0092, pidHigh: 0x0012, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4486
|
+
// ---- INPUT / ingate (pidLow=0x0025) — 4 entries ----
|
|
4487
|
+
// The input-noise-gate block carries hidden compressor-style
|
|
4488
|
+
// controls (Ratio / Attack / Z / GainMonitor) the AM4-Edit Setup
|
|
4489
|
+
// page exposes but params.ts hadn't registered. INPUT_METERS
|
|
4490
|
+
// (paramId 65520) skipped as a UI widget.
|
|
4491
|
+
'ingate.ratio': { block: 'ingate', name: 'ratio', displayLabel: 'Ratio', pidLow: 0x0025, pidHigh: 0x000b, unit: 'ratio', displayMin: 1, displayMax: 10, scaling: 'log10' },
|
|
4492
|
+
'ingate.attack': { block: 'ingate', name: 'attack', displayLabel: 'Attack', pidLow: 0x0025, pidHigh: 0x000d, unit: 'ms', displayMin: 0, displayMax: 1000 },
|
|
4493
|
+
'ingate.input_impedance': { block: 'ingate', name: 'input_impedance', displayLabel: 'Input Impedance', pidLow: 0x0025, pidHigh: 0x000e, unit: 'count', displayMin: 0, displayMax: 127 },
|
|
4494
|
+
'ingate.gain_monitor': { block: 'ingate', name: 'gain_monitor', displayLabel: 'Gain', pidLow: 0x0025, pidHigh: 0x0010, unit: 'knob_0_10', displayMin: 0, displayMax: 10 },
|
|
4495
|
+
// ---- CHORUS (pidLow=0x004e) — 1 entry ----
|
|
4496
|
+
// Stereo "Tempo Right" companion to chorus.tempo (CHORUS_TEMPO).
|
|
4497
|
+
// Same TEMPO_DIVISIONS_VALUES enum since the right-channel tempo
|
|
4498
|
+
// ladder mirrors the master one.
|
|
4499
|
+
'chorus.tempo_right': { block: 'chorus', name: 'tempo_right', displayLabel: 'Tempo Right', pidLow: 0x004e, pidHigh: 0x001f, unit: 'enum', displayMin: 0, displayMax: 78, enumValues: TEMPO_DIVISIONS_VALUES },
|
|
4500
|
+
// ---- TREMOLO (pidLow=0x006a) — 2 entries ----
|
|
4501
|
+
// trigger_phase is the LFO start-phase on retrigger; degrees
|
|
4502
|
+
// convention matches tremolo.phase (Session 35, capture-verified
|
|
4503
|
+
// 0..180 deg). crossover_slope follows the FLANGER count 1..12
|
|
4504
|
+
// pattern pending range capture.
|
|
4505
|
+
'tremolo.trigger_phase': { block: 'tremolo', name: 'trigger_phase', displayLabel: 'Trigger Phase', pidLow: 0x006a, pidHigh: 0x0013, unit: 'degrees', displayMin: 0, displayMax: 180 },
|
|
4506
|
+
'tremolo.crossover_slope': { block: 'tremolo', name: 'crossover_slope', displayLabel: 'Crossover Slope', pidLow: 0x006a, pidHigh: 0x0014, unit: 'count', displayMin: 1, displayMax: 12 },
|
|
4507
|
+
// ---- ENHANCER (pidLow=0x007a) — 1 entry ----
|
|
4508
|
+
// OFF/ON enum mirrors filter.phase_invert (same XML "Phase Invert"
|
|
4509
|
+
// label, same shape).
|
|
4510
|
+
'enhancer.phase_invert': { block: 'enhancer', name: 'phase_invert', displayLabel: 'Phase Invert', pidLow: 0x007a, pidHigh: 0x000f, unit: 'enum', displayMin: 0, displayMax: 1, enumValues: { 0: 'OFF', 1: 'ON' } },
|
|
4511
|
+
// ============================================================
|
|
4512
|
+
// Session 97 cont 5 (2026-05-18) — REMOVED 15 speculative III-
|
|
4513
|
+
// inherited entries that Session 97 cont 3+4 had wired (DISTORT
|
|
4514
|
+
// TONETYPE/EXCURSIONTIME/RECOVERYTIME/CFGRID/DYNPRES/DYNDEPTH/
|
|
4515
|
+
// TREMFREQ/TREMDEPTH/BIASTYPE/INDYNAMICS/PRECOMPTYPE/CFHARDNESS/
|
|
4516
|
+
// DRIVETYPE/FBTYPE + COMP_LIGHTTYPE).
|
|
4517
|
+
//
|
|
4518
|
+
// Comprehensive scan of `__block_layout_expert.xml` (all 141
|
|
4519
|
+
// unique DISTORT_/COMP_ parameterNames across every conditional
|
|
4520
|
+
// Table for every amp type variant) confirmed: zero of the 29
|
|
4521
|
+
// catalog-only candidate symbols appear anywhere in AM4-Edit's
|
|
4522
|
+
// expert XML. The 15 had been wired from III `__amp_layout.xml`
|
|
4523
|
+
// labels — those don't apply to AM4.
|
|
4524
|
+
//
|
|
4525
|
+
// The 29 remain as GHOST in the cross-ref audit (catalog symbol,
|
|
4526
|
+
// no AM4 XML). If a future HW-114 capture surfaces any of them
|
|
4527
|
+
// on the AM4 front-panel Expert Edit menu, they'll be re-added
|
|
4528
|
+
// here with HARDWARE-VERIFIED labels (not III speculation).
|
|
4529
|
+
//
|
|
4530
|
+
// Coverage shift back to honest values:
|
|
4531
|
+
// - WIRED-MATCHED 609 -> 594, GHOST 34 -> 49
|
|
4532
|
+
// - AM4-Edit XML rendered controls: 100% wired (was already 100%
|
|
4533
|
+
// before Session 97 cont 3 — the 15 added were not part of
|
|
4534
|
+
// the rendered surface)
|
|
4535
|
+
// - coverage-audit.ts headline becomes meaningful: every wired
|
|
4536
|
+
// entry corresponds to a control the user can see in AM4-Edit.
|
|
4537
|
+
};
|