@openmixer/omx-contract 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ RTA constants, the EQ band budget, the choice enums (as the `set` kind), the EQ
13
13
  one rule that gives a fresh EQ its bands, the measurement rate sets and the bus input cap. What is
14
14
  declared here is declared nowhere else: the EQ band budget that 1.2.0 left in openmixer is here too.
15
15
  2.0.0 changes how a kernel file is written, not what it declares: every render is the same.
16
+ 2.1.0 adds each kernel's ordered controls to the JSON render, and a control's `rearms` flag.
16
17
 
17
18
  ```
18
19
  data/ the declaration, one file per group, edited by hand
@@ -54,7 +55,10 @@ A kernel file, `data/kernels/<kernel>.json`, holds four sections and nothing els
54
55
  - `controls`, in order: a `travel` (one travel) or a `choice` (ordered `ids`, an optional `default` and `labels`).
55
56
  Its item name is `<KERNEL>_<NAME>_RANGE` for a travel and `<KERNEL>_<NAME>S` for a choice (`depth` in
56
57
  tremolo.json is `TREMOLO_DEPTH_RANGE`, `mode` is `TREMOLO_MODES`); `global` names it when it is anything else.
57
- A control with a `table` is one field of that table.
58
+ A control with a `table` is one field of that table. `"rearms": true` marks a control whose change re-arms the
59
+ kernel's state, so it is not a smooth parameter (the limiter's `lookaheadMs`: omx-dsp's limiter face re-arms
60
+ the state and restarts the gain at unity when the look-ahead moves by a frame). It is a boolean, only on a
61
+ control; it is no item, so the C and TypeScript renders do not carry it.
58
62
  - `tables`: a travels table whose fields are the controls that name it, in control order (`GATE_LIMITS`).
59
63
  - `aggregates`: a travels table whose fields are references to controls declared once above, listed by name.
60
64
  - `constants`: scalars, lists and sheets, as items.
@@ -62,6 +66,36 @@ A kernel file, `data/kernels/<kernel>.json`, holds four sections and nothing els
62
66
  `omx-contract validate` refuses any other key, a constant that is a travel or a set, and a kernel file written
63
67
  as a flat item map (the 1.x shape). `rates.json` and `primitives.json` stay item maps.
64
68
 
69
+ ## The JSON render's kernels
70
+
71
+ Beside `items`, `share/omx-contract/omx-contract.json` carries `kernels`: for every kernel file, its controls in
72
+ the order the file declares them. A consumer reads control order and kinds here, never from a kernel file.
73
+
74
+ ```json
75
+ "kernels": {
76
+ "limiter": {
77
+ "controls": [
78
+ { "name": "ceilingDb", "kind": "travel", "global": "LIMITER_LIMITS", "table": "LIMITER_LIMITS" },
79
+ { "name": "lookaheadMs", "kind": "travel", "global": "LIMITER_LIMITS", "table": "LIMITER_LIMITS", "rearms": true },
80
+ { "name": "releaseMs", "kind": "travel", "global": "LIMITER_LIMITS", "table": "LIMITER_LIMITS" }
81
+ ]
82
+ },
83
+ "tremolo": {
84
+ "controls": [
85
+ { "name": "rateHz", "kind": "travel", "global": "TREMOLO_RATE_RANGE" },
86
+ { "name": "mode", "kind": "choice", "global": "TREMOLO_MODES" }
87
+ ]
88
+ }
89
+ }
90
+ ```
91
+
92
+ - `kind`: `travel` or `choice`.
93
+ - `global`: the item the control's value lives in: `items[global].value` for a travel or a choice, and
94
+ `items[global].value[name]` for a field of a table, when `table` (the same item) is present.
95
+ - `rearms`: present, and `true`, only on a control that declares it.
96
+
97
+ A kernel with no controls (fbs, mixmatrix, rta) is listed with an empty `controls`.
98
+
65
99
  ## The CLI
66
100
 
67
101
  ```
@@ -78,9 +112,9 @@ share/omx-contract` and `render --target ts --out test/golden/ts`; CI holds all
78
112
 
79
113
  ## Consuming it
80
114
 
81
- Pin one version (`omx-contract 2.0.0` in `.github/pins.txt`) and build against its renders, committing
115
+ Pin one version (`omx-contract 2.1.0` in `.github/pins.txt`) and build against its renders, committing
82
116
  none: the installed `omx-contract-devel` / `libomx-contract-dev` at exactly that version
83
- (`pkg-config --exact-version=2.0.0 omx-contract`), else the release's npm tarball, unpacked, and
117
+ (`pkg-config --exact-version=2.1.0 omx-contract`), else the release's npm tarball, unpacked, and
84
118
  `omx-contract render --target c --out build/omx-contract/include`. Include
85
119
  `<omxcontract/omx_contract_limits.h>`. A plugin's parameter header is rendered by omx-plugins from its
86
120
  declaration, by reference to the kernel travels here (since 1.1.0).
@@ -18,6 +18,7 @@
18
18
  "name": "lookaheadMs",
19
19
  "kind": "travel",
20
20
  "table": "LIMITER_LIMITS",
21
+ "rearms": true,
21
22
  "travel": {
22
23
  "min": 0.5,
23
24
  "max": 5,
package/lib/data.mjs CHANGED
@@ -70,7 +70,7 @@ export function entriesOf(rel, doc) {
70
70
  const controls = Array.isArray(doc.controls) ? doc.controls : [];
71
71
  const tables = new Map(Object.entries(doc.tables ?? {}).map(([n, meta]) => [n, { kind: 'travels', ...meta, fields: {} }]));
72
72
  for (const c of controls) {
73
- const { name, kind, global, table, ...rest } = c;
73
+ const { name, kind, global, table, rearms, ...rest } = c;
74
74
  if (table) {
75
75
  if (!tables.has(table)) throw new Error(`${rel}: control ${name} names table ${table}, which is not declared`);
76
76
  tables.get(table).fields[name] = rest.travel;
@@ -91,6 +91,33 @@ export function entriesOf(rel, doc) {
91
91
  return out;
92
92
  }
93
93
 
94
+ /** A kernel's name, read off its file name: `kernels/band_dyn.json` is band_dyn. */
95
+ export const kernelName = (rel) => rel.replace(/^.*\//, '').replace(/\.json$/, '');
96
+
97
+ /**
98
+ * Every kernel's controls, in its file's order: `{ <kernel>: { controls: [{ name, kind, global, table?, rearms? }] } }`,
99
+ * kernels in file order. `global` is the item the control's value lives in: its own travel or set, or, for a field of
100
+ * a table, the table (`table` names it too, and the field is the control's name). `rearms` is carried only when true:
101
+ * changing the control re-arms the kernel's state, it is not a smooth parameter.
102
+ */
103
+ export function kernelControls(data) {
104
+ const out = {};
105
+ for (const f of data.files) {
106
+ if (!isKernelFile(f.rel)) continue;
107
+ const controls = Array.isArray(f.doc.controls) ? f.doc.controls : [];
108
+ out[kernelName(f.rel)] = {
109
+ controls: controls.map((c) => ({
110
+ name: c.name,
111
+ kind: c.kind,
112
+ global: c.table ?? controlGlobal(f.rel, c),
113
+ ...(c.table ? { table: c.table } : {}),
114
+ ...(c.rearms === true ? { rearms: true } : {}),
115
+ })),
116
+ };
117
+ }
118
+ return out;
119
+ }
120
+
94
121
  const isWholeRef = (v) => typeof v === 'object' && v !== null && Object.keys(v).length === 1 && typeof v.ref === 'string' && !v.ref.includes('.');
95
122
 
96
123
  /**
@@ -213,7 +240,8 @@ const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
213
240
 
214
241
  /**
215
242
  * Resolve every item: `{ name, rel, kind, doc, why?, unit?, c?, shape?, default?, labels?, value }` (default and labels: a set's), where `value` has
216
- * every `{ref}` and `{derive}` evaluated.
243
+ * every `{ref}` and `{derive}` evaluated. The returned map also carries `kernels`, every kernel's ordered controls
244
+ * (kernelControls), which the json render publishes beside the items.
217
245
  * @throws naming the item: a reference that does not resolve, a cycle, an unknown derivation.
218
246
  */
219
247
  export function resolveData(data) {
@@ -262,6 +290,7 @@ export function resolveData(data) {
262
290
  }
263
291
  const out = new Map();
264
292
  for (const name of data.items.keys()) out.set(name, resolveItem(name));
293
+ out.kernels = kernelControls(data);
265
294
  return out;
266
295
  }
267
296
 
package/lib/fmt.mjs CHANGED
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  const ORDER = {
11
- control: ['name', 'kind', 'global', 'table', 'since', 'doc', 'why', 'unit', 'ids', 'default', 'labels', 'travel', 'c'],
11
+ control: ['name', 'kind', 'global', 'table', 'rearms', 'since', 'doc', 'why', 'unit', 'ids', 'default', 'labels', 'travel', 'c'],
12
12
  sections: ['controls', 'tables', 'aggregates', 'constants'],
13
13
  item: ['kind', 'since', 'doc', 'why', 'unit', 'value', 'values', 'ids', 'default', 'labels', 'fields', 'travel', 'c'],
14
14
  travel: ['min', 'max', 'step', 'unit', 'default', 'defaultFrom', 'scale', 'byKind', 'doc', 'why'],
package/lib/validate.mjs CHANGED
@@ -18,7 +18,7 @@ let compiled;
18
18
  /**
19
19
  * The kernel-file shape (2.0.0), which the item schema cannot see: only the four sections at the top; every control
20
20
  * named, of kind travel or choice, unique by name, a travel carrying a `travel` and a choice its `ids`; a control's
21
- * `table` declared under `tables`; an aggregate's fields naming controls; a constant a scalar, a list or a sheet.
21
+ * `table` declared under `tables`; `rearms` a boolean, and only on a control; an aggregate's fields naming controls; a constant a scalar, a list or a sheet.
22
22
  * A kernel file written as a flat item map (the 1.x shape) is refused as a whole. Any other data file returns [].
23
23
  */
24
24
  export function shapeProblems(rel, doc) {
@@ -41,6 +41,10 @@ export function shapeProblems(rel, doc) {
41
41
  else if (c.kind === 'choice' && !Array.isArray(c.ids)) out.push(`controls[${i}] ${c.name}: a choice without "ids"`);
42
42
  else if (c.kind !== 'travel' && c.kind !== 'choice') out.push(`controls[${i}] ${c.name}: kind ${JSON.stringify(c.kind)} is neither travel nor choice`);
43
43
  if (c.table && !(doc.tables && c.table in doc.tables)) out.push(`controls[${i}] ${c.name}: table ${c.table} is not declared`);
44
+ if ('rearms' in c && typeof c.rearms !== 'boolean') out.push(`controls[${i}] ${c.name}: rearms ${JSON.stringify(c.rearms)} is not a boolean`);
45
+ }
46
+ for (const s of ['tables', 'aggregates', 'constants']) {
47
+ for (const [n, it] of Object.entries(doc[s] ?? {})) if (it && typeof it === 'object' && 'rearms' in it) out.push(`${s} ${n}: rearms is a control's flag, never a ${s.slice(0, -1)}'s`);
44
48
  }
45
49
  for (const [n, a] of Object.entries(doc.aggregates ?? {})) for (const f of a.fields ?? []) if (!seen.has(f)) out.push(`aggregate ${n}: field ${f} names no control`);
46
50
  for (const [n, it] of Object.entries(doc.constants ?? {})) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmixer/omx-contract",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "The FreeMixer declarations as data: a JSON Schema, the data, and one CLI that renders them into C, TypeScript and JSON",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
package/render/json.mjs CHANGED
@@ -2,7 +2,9 @@
2
2
  // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
3
  /**
4
4
  * The `json` target: the resolved data (every reference and derivation evaluated) for readers in
5
- * other languages, which need no resolver of their own.
5
+ * other languages, which need no resolver of their own. Beside the items, `kernels` lists each
6
+ * kernel's controls in their declared order (name, kind, the global each resolves to, the table of a
7
+ * table field, `rearms` when changing it re-arms the kernel's state), so a reader needs no kernel file.
6
8
  */
7
9
 
8
10
  /** Every file of the `json` target: `[{ path, text }]`. */
@@ -12,5 +14,7 @@ export function renderJson(resolved, version) {
12
14
  const { name, ...rest } = r;
13
15
  items[name] = rest;
14
16
  }
15
- return [{ path: 'omx-contract.json', text: `${JSON.stringify({ name: '@openmixer/omx-contract', version, items }, null, 2)}\n` }];
17
+ const doc = { name: '@openmixer/omx-contract', version, items };
18
+ if (resolved.kernels) doc.kernels = resolved.kernels;
19
+ return [{ path: 'omx-contract.json', text: `${JSON.stringify(doc, null, 2)}\n` }];
16
20
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmixer/omx-contract",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "items": {
5
5
  "PAN_RANGE": {
6
6
  "rel": "data/kernels/balance.json",
@@ -2369,5 +2369,640 @@
2369
2369
  192000
2370
2370
  ]
2371
2371
  }
2372
+ },
2373
+ "kernels": {
2374
+ "balance": {
2375
+ "controls": [
2376
+ {
2377
+ "name": "pan",
2378
+ "kind": "travel",
2379
+ "global": "PAN_RANGE"
2380
+ }
2381
+ ]
2382
+ },
2383
+ "band_dyn": {
2384
+ "controls": [
2385
+ {
2386
+ "name": "mode",
2387
+ "kind": "choice",
2388
+ "global": "BAND_DYN_MODES"
2389
+ },
2390
+ {
2391
+ "name": "threshold",
2392
+ "kind": "travel",
2393
+ "global": "BAND_DYN_THRESHOLD_RANGE"
2394
+ },
2395
+ {
2396
+ "name": "ratio",
2397
+ "kind": "travel",
2398
+ "global": "BAND_DYN_RATIO_RANGE"
2399
+ },
2400
+ {
2401
+ "name": "range",
2402
+ "kind": "travel",
2403
+ "global": "BAND_DYN_RANGE_RANGE"
2404
+ },
2405
+ {
2406
+ "name": "attack",
2407
+ "kind": "travel",
2408
+ "global": "BAND_DYN_ATTACK_RANGE"
2409
+ },
2410
+ {
2411
+ "name": "release",
2412
+ "kind": "travel",
2413
+ "global": "BAND_DYN_RELEASE_RANGE"
2414
+ }
2415
+ ]
2416
+ },
2417
+ "chorus": {
2418
+ "controls": [
2419
+ {
2420
+ "name": "spread",
2421
+ "kind": "travel",
2422
+ "global": "CHORUS_SPREAD_RANGE"
2423
+ },
2424
+ {
2425
+ "name": "rate",
2426
+ "kind": "travel",
2427
+ "global": "CHORUS_RATE_RANGE"
2428
+ },
2429
+ {
2430
+ "name": "depth",
2431
+ "kind": "travel",
2432
+ "global": "CHORUS_DEPTH_RANGE"
2433
+ },
2434
+ {
2435
+ "name": "voices",
2436
+ "kind": "travel",
2437
+ "global": "CHORUS_VOICES_RANGE"
2438
+ },
2439
+ {
2440
+ "name": "mix",
2441
+ "kind": "travel",
2442
+ "global": "CHORUS_MIX_RANGE"
2443
+ }
2444
+ ]
2445
+ },
2446
+ "comp": {
2447
+ "controls": [
2448
+ {
2449
+ "name": "thresholdDb",
2450
+ "kind": "travel",
2451
+ "global": "COMP_LIMITS",
2452
+ "table": "COMP_LIMITS"
2453
+ },
2454
+ {
2455
+ "name": "ratio",
2456
+ "kind": "travel",
2457
+ "global": "COMP_LIMITS",
2458
+ "table": "COMP_LIMITS"
2459
+ },
2460
+ {
2461
+ "name": "kneeDb",
2462
+ "kind": "travel",
2463
+ "global": "COMP_LIMITS",
2464
+ "table": "COMP_LIMITS"
2465
+ },
2466
+ {
2467
+ "name": "attackMs",
2468
+ "kind": "travel",
2469
+ "global": "COMP_LIMITS",
2470
+ "table": "COMP_LIMITS"
2471
+ },
2472
+ {
2473
+ "name": "releaseMs",
2474
+ "kind": "travel",
2475
+ "global": "COMP_LIMITS",
2476
+ "table": "COMP_LIMITS"
2477
+ },
2478
+ {
2479
+ "name": "makeupDb",
2480
+ "kind": "travel",
2481
+ "global": "COMP_LIMITS",
2482
+ "table": "COMP_LIMITS"
2483
+ },
2484
+ {
2485
+ "name": "mixPct",
2486
+ "kind": "travel",
2487
+ "global": "COMP_LIMITS",
2488
+ "table": "COMP_LIMITS"
2489
+ }
2490
+ ]
2491
+ },
2492
+ "deesser": {
2493
+ "controls": [
2494
+ {
2495
+ "name": "deessFreq",
2496
+ "kind": "travel",
2497
+ "global": "DEESS_FREQ_RANGE"
2498
+ },
2499
+ {
2500
+ "name": "deessWidth",
2501
+ "kind": "travel",
2502
+ "global": "DEESS_WIDTH_RANGE"
2503
+ },
2504
+ {
2505
+ "name": "deessThreshold",
2506
+ "kind": "travel",
2507
+ "global": "DEESS_THRESHOLD_RANGE"
2508
+ },
2509
+ {
2510
+ "name": "deessRatio",
2511
+ "kind": "travel",
2512
+ "global": "DEESS_RATIO_RANGE"
2513
+ },
2514
+ {
2515
+ "name": "deessRange",
2516
+ "kind": "travel",
2517
+ "global": "DEESS_RANGE_RANGE"
2518
+ },
2519
+ {
2520
+ "name": "deessAttack",
2521
+ "kind": "travel",
2522
+ "global": "DEESS_ATTACK_RANGE"
2523
+ },
2524
+ {
2525
+ "name": "deessRelease",
2526
+ "kind": "travel",
2527
+ "global": "DEESS_RELEASE_RANGE"
2528
+ },
2529
+ {
2530
+ "name": "deessMode",
2531
+ "kind": "choice",
2532
+ "global": "DEESS_MODES"
2533
+ }
2534
+ ]
2535
+ },
2536
+ "delay": {
2537
+ "controls": [
2538
+ {
2539
+ "name": "fxDelayTime",
2540
+ "kind": "travel",
2541
+ "global": "FX_DELAY_TIME_RANGE"
2542
+ },
2543
+ {
2544
+ "name": "fxDelayFeedback",
2545
+ "kind": "travel",
2546
+ "global": "FX_DELAY_FEEDBACK_RANGE"
2547
+ },
2548
+ {
2549
+ "name": "tone",
2550
+ "kind": "travel",
2551
+ "global": "DELAY_TONE_RANGE"
2552
+ },
2553
+ {
2554
+ "name": "mix",
2555
+ "kind": "travel",
2556
+ "global": "DELAY_MIX_RANGE"
2557
+ }
2558
+ ]
2559
+ },
2560
+ "drive": {
2561
+ "controls": [
2562
+ {
2563
+ "name": "amount",
2564
+ "kind": "travel",
2565
+ "global": "DRIVE_AMOUNT_RANGE"
2566
+ },
2567
+ {
2568
+ "name": "character",
2569
+ "kind": "travel",
2570
+ "global": "DRIVE_CHARACTER_RANGE"
2571
+ },
2572
+ {
2573
+ "name": "bandFreq",
2574
+ "kind": "travel",
2575
+ "global": "DRIVE_BAND_FREQ_RANGE"
2576
+ },
2577
+ {
2578
+ "name": "mix",
2579
+ "kind": "travel",
2580
+ "global": "DRIVE_MIX_RANGE"
2581
+ },
2582
+ {
2583
+ "name": "trim",
2584
+ "kind": "travel",
2585
+ "global": "DRIVE_TRIM_RANGE"
2586
+ },
2587
+ {
2588
+ "name": "curve",
2589
+ "kind": "choice",
2590
+ "global": "DRIVE_CURVES"
2591
+ },
2592
+ {
2593
+ "name": "band",
2594
+ "kind": "choice",
2595
+ "global": "DRIVE_BANDS"
2596
+ }
2597
+ ]
2598
+ },
2599
+ "eq": {
2600
+ "controls": [
2601
+ {
2602
+ "name": "freq",
2603
+ "kind": "travel",
2604
+ "global": "EQ_FREQ_RANGE"
2605
+ },
2606
+ {
2607
+ "name": "gain",
2608
+ "kind": "travel",
2609
+ "global": "EQ_GAIN_RANGE"
2610
+ },
2611
+ {
2612
+ "name": "q",
2613
+ "kind": "travel",
2614
+ "global": "EQ_Q_RANGE"
2615
+ },
2616
+ {
2617
+ "name": "notchQ",
2618
+ "kind": "travel",
2619
+ "global": "EQ_NOTCH_Q_RANGE"
2620
+ },
2621
+ {
2622
+ "name": "hpfFreq",
2623
+ "kind": "travel",
2624
+ "global": "HPF_FREQ_RANGE"
2625
+ },
2626
+ {
2627
+ "name": "lpfFreq",
2628
+ "kind": "travel",
2629
+ "global": "LPF_FREQ_RANGE"
2630
+ },
2631
+ {
2632
+ "name": "bandType",
2633
+ "kind": "choice",
2634
+ "global": "EQ_BAND_TYPES"
2635
+ },
2636
+ {
2637
+ "name": "filterSlope",
2638
+ "kind": "choice",
2639
+ "global": "FILTER_SLOPES"
2640
+ }
2641
+ ]
2642
+ },
2643
+ "fbs": {
2644
+ "controls": []
2645
+ },
2646
+ "flanger": {
2647
+ "controls": [
2648
+ {
2649
+ "name": "rate",
2650
+ "kind": "travel",
2651
+ "global": "FLANGER_RATE_RANGE"
2652
+ },
2653
+ {
2654
+ "name": "depth",
2655
+ "kind": "travel",
2656
+ "global": "FLANGER_DEPTH_RANGE"
2657
+ },
2658
+ {
2659
+ "name": "feedback",
2660
+ "kind": "travel",
2661
+ "global": "FLANGER_FEEDBACK_RANGE"
2662
+ },
2663
+ {
2664
+ "name": "mix",
2665
+ "kind": "travel",
2666
+ "global": "FLANGER_MIX_RANGE"
2667
+ }
2668
+ ]
2669
+ },
2670
+ "gate": {
2671
+ "controls": [
2672
+ {
2673
+ "name": "keySource",
2674
+ "kind": "choice",
2675
+ "global": "GATE_KEY_SOURCES"
2676
+ },
2677
+ {
2678
+ "name": "thresholdDb",
2679
+ "kind": "travel",
2680
+ "global": "GATE_LIMITS",
2681
+ "table": "GATE_LIMITS"
2682
+ },
2683
+ {
2684
+ "name": "rangeDb",
2685
+ "kind": "travel",
2686
+ "global": "GATE_LIMITS",
2687
+ "table": "GATE_LIMITS"
2688
+ },
2689
+ {
2690
+ "name": "kneeStartDb",
2691
+ "kind": "travel",
2692
+ "global": "GATE_LIMITS",
2693
+ "table": "GATE_LIMITS"
2694
+ },
2695
+ {
2696
+ "name": "kneeEndDb",
2697
+ "kind": "travel",
2698
+ "global": "GATE_LIMITS",
2699
+ "table": "GATE_LIMITS"
2700
+ },
2701
+ {
2702
+ "name": "attackMs",
2703
+ "kind": "travel",
2704
+ "global": "GATE_LIMITS",
2705
+ "table": "GATE_LIMITS"
2706
+ },
2707
+ {
2708
+ "name": "holdMs",
2709
+ "kind": "travel",
2710
+ "global": "GATE_LIMITS",
2711
+ "table": "GATE_LIMITS"
2712
+ },
2713
+ {
2714
+ "name": "releaseMs",
2715
+ "kind": "travel",
2716
+ "global": "GATE_LIMITS",
2717
+ "table": "GATE_LIMITS"
2718
+ },
2719
+ {
2720
+ "name": "hysteresisDb",
2721
+ "kind": "travel",
2722
+ "global": "GATE_LIMITS",
2723
+ "table": "GATE_LIMITS"
2724
+ },
2725
+ {
2726
+ "name": "ratio",
2727
+ "kind": "travel",
2728
+ "global": "GATE_LIMITS",
2729
+ "table": "GATE_LIMITS"
2730
+ }
2731
+ ]
2732
+ },
2733
+ "geq": {
2734
+ "controls": [
2735
+ {
2736
+ "name": "band",
2737
+ "kind": "travel",
2738
+ "global": "GEQ_BAND_RANGE"
2739
+ }
2740
+ ]
2741
+ },
2742
+ "hrp": {
2743
+ "controls": [
2744
+ {
2745
+ "name": "amount",
2746
+ "kind": "travel",
2747
+ "global": "HRP_AMOUNT_RANGE"
2748
+ }
2749
+ ]
2750
+ },
2751
+ "limiter": {
2752
+ "controls": [
2753
+ {
2754
+ "name": "ceilingDb",
2755
+ "kind": "travel",
2756
+ "global": "LIMITER_LIMITS",
2757
+ "table": "LIMITER_LIMITS"
2758
+ },
2759
+ {
2760
+ "name": "lookaheadMs",
2761
+ "kind": "travel",
2762
+ "global": "LIMITER_LIMITS",
2763
+ "table": "LIMITER_LIMITS",
2764
+ "rearms": true
2765
+ },
2766
+ {
2767
+ "name": "releaseMs",
2768
+ "kind": "travel",
2769
+ "global": "LIMITER_LIMITS",
2770
+ "table": "LIMITER_LIMITS"
2771
+ }
2772
+ ]
2773
+ },
2774
+ "mixmatrix": {
2775
+ "controls": []
2776
+ },
2777
+ "phaser": {
2778
+ "controls": [
2779
+ {
2780
+ "name": "rateHz",
2781
+ "kind": "travel",
2782
+ "global": "PHASER_RATE_RANGE"
2783
+ },
2784
+ {
2785
+ "name": "baseHz",
2786
+ "kind": "travel",
2787
+ "global": "PHASER_BASE_RANGE"
2788
+ },
2789
+ {
2790
+ "name": "depthOct",
2791
+ "kind": "travel",
2792
+ "global": "PHASER_DEPTH_RANGE"
2793
+ },
2794
+ {
2795
+ "name": "stages",
2796
+ "kind": "travel",
2797
+ "global": "PHASER_STAGES_RANGE"
2798
+ },
2799
+ {
2800
+ "name": "feedback",
2801
+ "kind": "travel",
2802
+ "global": "PHASER_FEEDBACK_RANGE"
2803
+ },
2804
+ {
2805
+ "name": "mix",
2806
+ "kind": "travel",
2807
+ "global": "PHASER_MIX_RANGE"
2808
+ }
2809
+ ]
2810
+ },
2811
+ "pitch": {
2812
+ "controls": [
2813
+ {
2814
+ "name": "semitones",
2815
+ "kind": "travel",
2816
+ "global": "PITCH_LIMITS",
2817
+ "table": "PITCH_LIMITS"
2818
+ },
2819
+ {
2820
+ "name": "cents",
2821
+ "kind": "travel",
2822
+ "global": "PITCH_LIMITS",
2823
+ "table": "PITCH_LIMITS"
2824
+ },
2825
+ {
2826
+ "name": "mix",
2827
+ "kind": "travel",
2828
+ "global": "PITCH_LIMITS",
2829
+ "table": "PITCH_LIMITS"
2830
+ }
2831
+ ]
2832
+ },
2833
+ "reverb": {
2834
+ "controls": [
2835
+ {
2836
+ "name": "plateModDepth",
2837
+ "kind": "travel",
2838
+ "global": "REVERB_PLATE_MOD_DEPTH_RANGE"
2839
+ },
2840
+ {
2841
+ "name": "mix",
2842
+ "kind": "travel",
2843
+ "global": "REVERB_MIX_RANGE"
2844
+ },
2845
+ {
2846
+ "name": "size",
2847
+ "kind": "travel",
2848
+ "global": "REVERB_SIZE_RANGE"
2849
+ },
2850
+ {
2851
+ "name": "damping",
2852
+ "kind": "travel",
2853
+ "global": "REVERB_DAMPING_RANGE"
2854
+ },
2855
+ {
2856
+ "name": "width",
2857
+ "kind": "travel",
2858
+ "global": "REVERB_WIDTH_RANGE"
2859
+ },
2860
+ {
2861
+ "name": "predelay",
2862
+ "kind": "travel",
2863
+ "global": "REVERB_PREDELAY_RANGE"
2864
+ },
2865
+ {
2866
+ "name": "lowcut",
2867
+ "kind": "travel",
2868
+ "global": "REVERB_LOWCUT_RANGE"
2869
+ },
2870
+ {
2871
+ "name": "highcut",
2872
+ "kind": "travel",
2873
+ "global": "REVERB_HIGHCUT_RANGE"
2874
+ },
2875
+ {
2876
+ "name": "reverse",
2877
+ "kind": "travel",
2878
+ "global": "REVERB_REVERSE_RANGE"
2879
+ },
2880
+ {
2881
+ "name": "hold",
2882
+ "kind": "travel",
2883
+ "global": "REVERB_HOLD_RANGE"
2884
+ },
2885
+ {
2886
+ "name": "release",
2887
+ "kind": "travel",
2888
+ "global": "REVERB_RELEASE_RANGE"
2889
+ },
2890
+ {
2891
+ "name": "gateThreshold",
2892
+ "kind": "travel",
2893
+ "global": "REVERB_GATE_THRESHOLD_RANGE"
2894
+ },
2895
+ {
2896
+ "name": "algorithm",
2897
+ "kind": "choice",
2898
+ "global": "REVERB_ALGORITHMS"
2899
+ }
2900
+ ]
2901
+ },
2902
+ "rotary": {
2903
+ "controls": [
2904
+ {
2905
+ "name": "hornSlowHz",
2906
+ "kind": "travel",
2907
+ "global": "ROTARY_HORN_SLOW_RANGE"
2908
+ },
2909
+ {
2910
+ "name": "hornFastHz",
2911
+ "kind": "travel",
2912
+ "global": "ROTARY_HORN_FAST_RANGE"
2913
+ },
2914
+ {
2915
+ "name": "drumSlowHz",
2916
+ "kind": "travel",
2917
+ "global": "ROTARY_DRUM_SLOW_RANGE"
2918
+ },
2919
+ {
2920
+ "name": "drumFastHz",
2921
+ "kind": "travel",
2922
+ "global": "ROTARY_DRUM_FAST_RANGE"
2923
+ },
2924
+ {
2925
+ "name": "accel",
2926
+ "kind": "travel",
2927
+ "global": "ROTARY_ACCEL_RANGE"
2928
+ },
2929
+ {
2930
+ "name": "balance",
2931
+ "kind": "travel",
2932
+ "global": "ROTARY_BALANCE_RANGE"
2933
+ },
2934
+ {
2935
+ "name": "mix",
2936
+ "kind": "travel",
2937
+ "global": "ROTARY_MIX_RANGE"
2938
+ },
2939
+ {
2940
+ "name": "speed",
2941
+ "kind": "choice",
2942
+ "global": "ROTARY_SPEEDS"
2943
+ }
2944
+ ]
2945
+ },
2946
+ "rta": {
2947
+ "controls": []
2948
+ },
2949
+ "transient": {
2950
+ "controls": [
2951
+ {
2952
+ "name": "attackDb",
2953
+ "kind": "travel",
2954
+ "global": "TRANSIENT_LIMITS",
2955
+ "table": "TRANSIENT_LIMITS"
2956
+ },
2957
+ {
2958
+ "name": "sustainDb",
2959
+ "kind": "travel",
2960
+ "global": "TRANSIENT_LIMITS",
2961
+ "table": "TRANSIENT_LIMITS"
2962
+ },
2963
+ {
2964
+ "name": "attackTimeMs",
2965
+ "kind": "travel",
2966
+ "global": "TRANSIENT_LIMITS",
2967
+ "table": "TRANSIENT_LIMITS"
2968
+ },
2969
+ {
2970
+ "name": "sustainTimeMs",
2971
+ "kind": "travel",
2972
+ "global": "TRANSIENT_LIMITS",
2973
+ "table": "TRANSIENT_LIMITS"
2974
+ },
2975
+ {
2976
+ "name": "outputDb",
2977
+ "kind": "travel",
2978
+ "global": "TRANSIENT_LIMITS",
2979
+ "table": "TRANSIENT_LIMITS"
2980
+ }
2981
+ ]
2982
+ },
2983
+ "tremolo": {
2984
+ "controls": [
2985
+ {
2986
+ "name": "rateHz",
2987
+ "kind": "travel",
2988
+ "global": "TREMOLO_RATE_RANGE"
2989
+ },
2990
+ {
2991
+ "name": "depth",
2992
+ "kind": "travel",
2993
+ "global": "TREMOLO_DEPTH_RANGE"
2994
+ },
2995
+ {
2996
+ "name": "mix",
2997
+ "kind": "travel",
2998
+ "global": "TREMOLO_MIX_RANGE"
2999
+ },
3000
+ {
3001
+ "name": "mode",
3002
+ "kind": "choice",
3003
+ "global": "TREMOLO_MODES"
3004
+ }
3005
+ ]
3006
+ }
2372
3007
  }
2373
3008
  }