@openmixer/omx-contract 1.3.0 → 2.0.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 +34 -2
- package/bin/omx-contract.mjs +14 -3
- package/data/kernels/balance.json +18 -14
- package/data/kernels/band_dyn.json +132 -0
- package/data/kernels/chorus.json +87 -78
- package/data/kernels/comp.json +67 -29
- package/data/kernels/deesser.json +114 -94
- package/data/kernels/delay.json +67 -57
- package/data/kernels/drive.json +118 -107
- package/data/kernels/eq.json +282 -267
- package/data/kernels/fbs.json +144 -142
- package/data/kernels/flanger.json +74 -66
- package/data/kernels/gate.json +76 -29
- package/data/kernels/geq.json +32 -27
- package/data/kernels/hrp.json +62 -56
- package/data/kernels/limiter.json +25 -9
- package/data/kernels/mixmatrix.json +7 -5
- package/data/kernels/phaser.json +110 -106
- package/data/kernels/pitch.json +35 -17
- package/data/kernels/reverb.json +176 -159
- package/data/kernels/rotary.json +189 -186
- package/data/kernels/rta.json +13 -11
- package/data/kernels/transient.json +64 -36
- package/data/kernels/tremolo.json +59 -57
- package/dist/ts/omx-contract.d.ts +157 -67
- package/dist/ts/omx-contract.js +211 -118
- package/include/omxcontract/omx_contract_limits.h +35 -0
- package/lib/data.mjs +104 -2
- package/lib/fmt.mjs +22 -2
- package/lib/validate.mjs +39 -2
- package/package.json +1 -1
- package/share/omx-contract/omx-contract.json +230 -128
package/lib/validate.mjs
CHANGED
|
@@ -8,13 +8,47 @@
|
|
|
8
8
|
import { readFileSync } from 'node:fs';
|
|
9
9
|
import { posix } from 'node:path';
|
|
10
10
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
11
|
-
import { resolveData } from './data.mjs';
|
|
11
|
+
import { KERNEL_SECTIONS, entriesOf, isKernelFile, resolveData } from './data.mjs';
|
|
12
12
|
import { eqDefaultBands, eqDefaultParams } from './eq-defaults.mjs';
|
|
13
13
|
import { renderC } from '../render/c.mjs';
|
|
14
14
|
import { renderTs } from '../render/ts.mjs';
|
|
15
15
|
|
|
16
16
|
const SCHEMA = JSON.parse(readFileSync(new URL('../schema/omx-contract.schema.json', import.meta.url), 'utf8'));
|
|
17
17
|
let compiled;
|
|
18
|
+
/**
|
|
19
|
+
* The kernel-file shape (2.0.0), which the item schema cannot see: only the four sections at the top; every control
|
|
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.
|
|
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
|
+
*/
|
|
24
|
+
export function shapeProblems(rel, doc) {
|
|
25
|
+
if (!isKernelFile(rel)) return [];
|
|
26
|
+
const sections = KERNEL_SECTIONS;
|
|
27
|
+
const keys = Object.keys(doc).filter((k) => k !== '$schema');
|
|
28
|
+
if (keys.length && !keys.some((k) => sections.includes(k))) {
|
|
29
|
+
return [`${rel} is a flat item map (the 1.x shape): a kernel file declares its items under ${sections.join(', ')}`];
|
|
30
|
+
}
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const k of keys) if (!sections.includes(k)) out.push(`unknown top-level key ${k}: a kernel file holds ${sections.join(', ')}`);
|
|
33
|
+
const controls = doc.controls ?? [];
|
|
34
|
+
if (!Array.isArray(controls)) return [...out, 'controls must be a list'];
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
for (const [i, c] of controls.entries()) {
|
|
37
|
+
if (typeof c.name !== 'string' || !/^[a-z][A-Za-z0-9]*$/.test(c.name)) out.push(`controls[${i}]: name ${JSON.stringify(c.name)} is not a lowerCamel identifier`);
|
|
38
|
+
if (seen.has(c.name)) out.push(`controls[${i}]: name ${c.name} declared twice`);
|
|
39
|
+
seen.add(c.name);
|
|
40
|
+
if (c.kind === 'travel' && !c.travel) out.push(`controls[${i}] ${c.name}: a travel without "travel"`);
|
|
41
|
+
else if (c.kind === 'choice' && !Array.isArray(c.ids)) out.push(`controls[${i}] ${c.name}: a choice without "ids"`);
|
|
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
|
+
if (c.table && !(doc.tables && c.table in doc.tables)) out.push(`controls[${i}] ${c.name}: table ${c.table} is not declared`);
|
|
44
|
+
}
|
|
45
|
+
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
|
+
for (const [n, it] of Object.entries(doc.constants ?? {})) {
|
|
47
|
+
if (!['scalar', 'list', 'sheet'].includes(it?.kind)) out.push(`constant ${n}: kind ${JSON.stringify(it?.kind)} is not scalar, list or sheet (a travel or a set is a control)`);
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
18
52
|
/** The compiled schema validator. */
|
|
19
53
|
export function schemaValidator() {
|
|
20
54
|
if (!compiled) compiled = new Ajv2020({ allErrors: true, strict: true, strictRequired: false, allowUnionTypes: true }).compile(SCHEMA);
|
|
@@ -88,7 +122,10 @@ export function validateData(data) {
|
|
|
88
122
|
const depth = f.rel.split('/').length - 1;
|
|
89
123
|
const want = posix.join(...Array(depth).fill('..'), 'schema/omx-contract.schema.json');
|
|
90
124
|
if (f.doc.$schema !== want) say(f.rel, '-', 'schema-path', `"$schema" must be "${want}"`);
|
|
91
|
-
|
|
125
|
+
for (const m of shapeProblems(f.rel, f.doc)) say(f.rel, '-', 'shape', m);
|
|
126
|
+
// The schema reads items: a kernel file is checked as the items it expands to, so no rule is lost.
|
|
127
|
+
const items = { $schema: f.doc.$schema, ...Object.fromEntries(entriesOf(f.rel, f.doc)) };
|
|
128
|
+
if (!validate(items)) {
|
|
92
129
|
for (const e of validate.errors) {
|
|
93
130
|
const item = e.instancePath.split('/')[1] || '-';
|
|
94
131
|
say(f.rel, item, 'schema', `${e.instancePath || '/'} ${e.message}${e.params?.allowedValues ? ` (${e.params.allowedValues.join(', ')})` : ''}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmixer/omx-contract",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmixer/omx-contract",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"items": {
|
|
5
5
|
"PAN_RANGE": {
|
|
6
6
|
"rel": "data/kernels/balance.json",
|
|
@@ -20,6 +20,107 @@
|
|
|
20
20
|
"unit": ""
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
|
+
"BAND_DYN_MODES": {
|
|
24
|
+
"rel": "data/kernels/band_dyn.json",
|
|
25
|
+
"kind": "set",
|
|
26
|
+
"doc": "The side of the threshold the band acts on. Above acts when the band is loud, taming a resonance that only rings when pushed; below acts when it is quiet, lifting a band that drops out. The order is the integer the kernel reads: above is 0, below is 1.",
|
|
27
|
+
"default": "above",
|
|
28
|
+
"value": [
|
|
29
|
+
"above",
|
|
30
|
+
"below"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"BAND_DYN_THRESHOLD_RANGE": {
|
|
34
|
+
"rel": "data/kernels/band_dyn.json",
|
|
35
|
+
"kind": "travels",
|
|
36
|
+
"doc": "Where the band starts to act, in dB of the band's own level and not the strip's. It is the same fact the de-esser's threshold is, so it carries the same travel.",
|
|
37
|
+
"shape": "travel",
|
|
38
|
+
"value": {
|
|
39
|
+
"min": -60,
|
|
40
|
+
"max": 0,
|
|
41
|
+
"step": 0.5,
|
|
42
|
+
"unit": "dB",
|
|
43
|
+
"default": -30,
|
|
44
|
+
"defaultFrom": "desk"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"BAND_DYN_RATIO_RANGE": {
|
|
48
|
+
"rel": "data/kernels/band_dyn.json",
|
|
49
|
+
"kind": "travels",
|
|
50
|
+
"doc": "How hard the band is held once it is past its threshold. 2:1 rather than the de-esser's 4:1, because a dynamic band is corrective, not a limiter for a sibilant.",
|
|
51
|
+
"shape": "travel",
|
|
52
|
+
"value": {
|
|
53
|
+
"min": 1,
|
|
54
|
+
"max": 20,
|
|
55
|
+
"step": 0.1,
|
|
56
|
+
"unit": "",
|
|
57
|
+
"default": 2,
|
|
58
|
+
"defaultFrom": "desk"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"BAND_DYN_RANGE_RANGE": {
|
|
62
|
+
"rel": "data/kernels/band_dyn.json",
|
|
63
|
+
"kind": "travels",
|
|
64
|
+
"doc": "The most the band may add to its static gain, signed: below zero the deepest cut, above zero the largest boost. The ceiling of +12 keeps static plus dynamic inside the EQ's own travel. Zero makes the band inert without switching it off.",
|
|
65
|
+
"shape": "travel",
|
|
66
|
+
"value": {
|
|
67
|
+
"min": -24,
|
|
68
|
+
"max": 12,
|
|
69
|
+
"step": 0.5,
|
|
70
|
+
"unit": "dB",
|
|
71
|
+
"default": -6,
|
|
72
|
+
"defaultFrom": "desk"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"BAND_DYN_ATTACK_RANGE": {
|
|
76
|
+
"rel": "data/kernels/band_dyn.json",
|
|
77
|
+
"kind": "travels",
|
|
78
|
+
"doc": "The detector's attack, in ms. The travel stops at the oversampling floor, below which the band would need the compressor's delayed control path.",
|
|
79
|
+
"shape": "travel",
|
|
80
|
+
"value": {
|
|
81
|
+
"min": 0.5,
|
|
82
|
+
"max": 100,
|
|
83
|
+
"step": 0.1,
|
|
84
|
+
"unit": "ms",
|
|
85
|
+
"default": 5,
|
|
86
|
+
"defaultFrom": "desk"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"BAND_DYN_RELEASE_RANGE": {
|
|
90
|
+
"rel": "data/kernels/band_dyn.json",
|
|
91
|
+
"kind": "travels",
|
|
92
|
+
"doc": "The detector's release, in ms. 100 ms is long enough not to modulate a 40 Hz band inside four cycles.",
|
|
93
|
+
"shape": "travel",
|
|
94
|
+
"value": {
|
|
95
|
+
"min": 5,
|
|
96
|
+
"max": 3000,
|
|
97
|
+
"step": 1,
|
|
98
|
+
"unit": "ms",
|
|
99
|
+
"default": 100,
|
|
100
|
+
"defaultFrom": "desk"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"BAND_DYN_KNEE_DB": {
|
|
104
|
+
"rel": "data/kernels/band_dyn.json",
|
|
105
|
+
"kind": "scalar",
|
|
106
|
+
"doc": "The soft knee of the band's gain computer, in dB. One knee for the one band-dynamics word, shared by every stage that runs it, the de-esser included: a second spelling of 6 would be a second place where the reduction starts.",
|
|
107
|
+
"unit": "dB",
|
|
108
|
+
"value": 6
|
|
109
|
+
},
|
|
110
|
+
"BAND_DYN_MAX_BANDS": {
|
|
111
|
+
"rel": "data/kernels/band_dyn.json",
|
|
112
|
+
"kind": "scalar",
|
|
113
|
+
"doc": "How many dynamic bands a channel may hold. A dynamic band is an operator band, so the capacity is the operator's reserve, read and not typed again.",
|
|
114
|
+
"unit": "",
|
|
115
|
+
"value": 9
|
|
116
|
+
},
|
|
117
|
+
"DETECTOR_OVERSAMPLE_AUTO_MS": {
|
|
118
|
+
"rel": "data/kernels/band_dyn.json",
|
|
119
|
+
"kind": "scalar",
|
|
120
|
+
"doc": "The shortest attack, in ms, at which the compressor's detector does not alias. Below it the compressor engages its 4x control path, which adds 72 samples of latency; a zero-latency band has no such path, so its attack travel stops at this floor.",
|
|
121
|
+
"unit": "ms",
|
|
122
|
+
"value": 0.5
|
|
123
|
+
},
|
|
23
124
|
"CHORUS_SPREAD_RANGE": {
|
|
24
125
|
"rel": "data/kernels/chorus.json",
|
|
25
126
|
"kind": "travels",
|
|
@@ -283,13 +384,6 @@
|
|
|
283
384
|
"defaultFrom": "desk"
|
|
284
385
|
}
|
|
285
386
|
},
|
|
286
|
-
"DEESS_KNEE_DB": {
|
|
287
|
-
"rel": "data/kernels/deesser.json",
|
|
288
|
-
"kind": "scalar",
|
|
289
|
-
"doc": "The knee, in dB — a CONSTANT of the stage and not a row field (`2026-09-22-native-deesser-stage.md` §4b): a de-esser without a soft knee latches audibly on the first sibilant of a phrase, and no other value of this number is a de-esser anyone would dial. The controller pushes it to the node and this is the same number; a second spelling would be a picture that disagrees with the audio about where the reduction starts.",
|
|
290
|
-
"unit": "dB",
|
|
291
|
-
"value": 6
|
|
292
|
-
},
|
|
293
387
|
"DEESS_MODES": {
|
|
294
388
|
"rel": "data/kernels/deesser.json",
|
|
295
389
|
"kind": "set",
|
|
@@ -299,6 +393,13 @@
|
|
|
299
393
|
"wideband"
|
|
300
394
|
]
|
|
301
395
|
},
|
|
396
|
+
"DEESS_KNEE_DB": {
|
|
397
|
+
"rel": "data/kernels/deesser.json",
|
|
398
|
+
"kind": "scalar",
|
|
399
|
+
"doc": "The knee, in dB — a CONSTANT of the stage and not a row field (`2026-09-22-native-deesser-stage.md` §4b): a de-esser without a soft knee latches audibly on the first sibilant of a phrase, and no other value of this number is a de-esser anyone would dial. The controller pushes it to the node and this is the same number; a second spelling would be a picture that disagrees with the audio about where the reduction starts.",
|
|
400
|
+
"unit": "dB",
|
|
401
|
+
"value": 6
|
|
402
|
+
},
|
|
302
403
|
"FX_DELAY_TIME_RANGE": {
|
|
303
404
|
"rel": "data/kernels/delay.json",
|
|
304
405
|
"kind": "travels",
|
|
@@ -371,13 +472,6 @@
|
|
|
371
472
|
"unit": "",
|
|
372
473
|
"value": false
|
|
373
474
|
},
|
|
374
|
-
"DRIVE_BIAS_MAX": {
|
|
375
|
-
"rel": "data/kernels/drive.json",
|
|
376
|
-
"kind": "scalar",
|
|
377
|
-
"doc": "The bias at `character = +1`, in the SHAPER's own input units — `OMX_DRIVE_BIAS_MAX`. DERIVED, not chosen (§4b). In the saturating limit every knee tends to `sgn`, the output is a rectangular wave of duty `d = ½ + asin(b)/π`, and its `n`th harmonic goes as `sin(nπd)/n` — so `|H2|` is maximal at `d = ¾`, which is `b = sin(π/4) = 1/√2` exactly. Measured too: the H2-maximising bias for a full-scale sine at unity drive is 0.712 (soft), 0.658 (tape), 0.645 (tube), and this one value costs 0.000 / 0.035 / 0.088 dB of H2 against each curve's own optimum. ONE normalised bias for all three knees, not three.",
|
|
378
|
-
"unit": "",
|
|
379
|
-
"value": 0.7071067811865476
|
|
380
|
-
},
|
|
381
475
|
"DRIVE_AMOUNT_RANGE": {
|
|
382
476
|
"rel": "data/kernels/drive.json",
|
|
383
477
|
"kind": "travels",
|
|
@@ -500,58 +594,12 @@
|
|
|
500
594
|
"tilt"
|
|
501
595
|
]
|
|
502
596
|
},
|
|
503
|
-
"
|
|
504
|
-
"rel": "data/kernels/
|
|
505
|
-
"kind": "scalar",
|
|
506
|
-
"doc": "The maximum number of parametric bands a channel EQ may hold — the operator can add up to this many. Generated into `omx_contract_limits.h` as `OMX_EQ_MAX_BANDS`, which `omx_biquad.h` reads (`output-delay-ceiling.test.ts` reads the header): the native lane allocates exactly this many biquad slots per channel and silently clamps above it, so the model, the wire, and the DSP agree by test, not by memory.",
|
|
507
|
-
"unit": "",
|
|
508
|
-
"value": 24
|
|
509
|
-
},
|
|
510
|
-
"ISO_THIRD_OCTAVE_CENTRES_HZ": {
|
|
511
|
-
"rel": "data/kernels/eq.json",
|
|
512
|
-
"kind": "list",
|
|
513
|
-
"doc": "The standard ISO 266 one-third-octave centre frequencies, 20 Hz–20 kHz (31 bands) — the classic 31-band graphic-EQ layout's centres.",
|
|
514
|
-
"unit": "Hz",
|
|
515
|
-
"value": [
|
|
516
|
-
20,
|
|
517
|
-
25,
|
|
518
|
-
31.5,
|
|
519
|
-
40,
|
|
520
|
-
50,
|
|
521
|
-
63,
|
|
522
|
-
80,
|
|
523
|
-
100,
|
|
524
|
-
125,
|
|
525
|
-
160,
|
|
526
|
-
200,
|
|
527
|
-
250,
|
|
528
|
-
315,
|
|
529
|
-
400,
|
|
530
|
-
500,
|
|
531
|
-
630,
|
|
532
|
-
800,
|
|
533
|
-
1000,
|
|
534
|
-
1250,
|
|
535
|
-
1600,
|
|
536
|
-
2000,
|
|
537
|
-
2500,
|
|
538
|
-
3150,
|
|
539
|
-
4000,
|
|
540
|
-
5000,
|
|
541
|
-
6300,
|
|
542
|
-
8000,
|
|
543
|
-
10000,
|
|
544
|
-
12500,
|
|
545
|
-
16000,
|
|
546
|
-
20000
|
|
547
|
-
]
|
|
548
|
-
},
|
|
549
|
-
"GEQ_BANDS": {
|
|
550
|
-
"rel": "data/kernels/eq.json",
|
|
597
|
+
"DRIVE_BIAS_MAX": {
|
|
598
|
+
"rel": "data/kernels/drive.json",
|
|
551
599
|
"kind": "scalar",
|
|
552
|
-
"doc": "The
|
|
600
|
+
"doc": "The bias at `character = +1`, in the SHAPER's own input units — `OMX_DRIVE_BIAS_MAX`. DERIVED, not chosen (§4b). In the saturating limit every knee tends to `sgn`, the output is a rectangular wave of duty `d = ½ + asin(b)/π`, and its `n`th harmonic goes as `sin(nπd)/n` — so `|H2|` is maximal at `d = ¾`, which is `b = sin(π/4) = 1/√2` exactly. Measured too: the H2-maximising bias for a full-scale sine at unity drive is 0.712 (soft), 0.658 (tape), 0.645 (tube), and this one value costs 0.000 / 0.035 / 0.088 dB of H2 against each curve's own optimum. ONE normalised bias for all three knees, not three.",
|
|
553
601
|
"unit": "",
|
|
554
|
-
"value":
|
|
602
|
+
"value": 0.7071067811865476
|
|
555
603
|
},
|
|
556
604
|
"EQ_FREQ_RANGE": {
|
|
557
605
|
"rel": "data/kernels/eq.json",
|
|
@@ -625,13 +673,6 @@
|
|
|
625
673
|
"unit": "Hz"
|
|
626
674
|
}
|
|
627
675
|
},
|
|
628
|
-
"OPERATOR_EQ_BANDS_RESERVE": {
|
|
629
|
-
"rel": "data/kernels/eq.json",
|
|
630
|
-
"kind": "scalar",
|
|
631
|
-
"doc": "The band slots kept for the operator's own hand: the reserve the feedback suppressor and the ring correction may never eat into. Nine is the working set a live EQ actually holds. The budget OPERATOR_EQ_BANDS_RESERVE + FBS_DEFAULT_MAX_AUTO_BANDS + HRP_DEFAULT_MAX_AUTO_BANDS (9 + 6 + 8 = 23) must fit EQ_MAX_BANDS, and `omx-contract validate` refuses data where it does not.",
|
|
632
|
-
"unit": "",
|
|
633
|
-
"value": 9
|
|
634
|
-
},
|
|
635
676
|
"EQ_BAND_TYPES": {
|
|
636
677
|
"rel": "data/kernels/eq.json",
|
|
637
678
|
"kind": "set",
|
|
@@ -664,6 +705,66 @@
|
|
|
664
705
|
24
|
|
665
706
|
]
|
|
666
707
|
},
|
|
708
|
+
"EQ_MAX_BANDS": {
|
|
709
|
+
"rel": "data/kernels/eq.json",
|
|
710
|
+
"kind": "scalar",
|
|
711
|
+
"doc": "The maximum number of parametric bands a channel EQ may hold — the operator can add up to this many. Generated into `omx_contract_limits.h` as `OMX_EQ_MAX_BANDS`, which `omx_biquad.h` reads (`output-delay-ceiling.test.ts` reads the header): the native lane allocates exactly this many biquad slots per channel and silently clamps above it, so the model, the wire, and the DSP agree by test, not by memory.",
|
|
712
|
+
"unit": "",
|
|
713
|
+
"value": 24
|
|
714
|
+
},
|
|
715
|
+
"ISO_THIRD_OCTAVE_CENTRES_HZ": {
|
|
716
|
+
"rel": "data/kernels/eq.json",
|
|
717
|
+
"kind": "list",
|
|
718
|
+
"doc": "The standard ISO 266 one-third-octave centre frequencies, 20 Hz–20 kHz (31 bands) — the classic 31-band graphic-EQ layout's centres.",
|
|
719
|
+
"unit": "Hz",
|
|
720
|
+
"value": [
|
|
721
|
+
20,
|
|
722
|
+
25,
|
|
723
|
+
31.5,
|
|
724
|
+
40,
|
|
725
|
+
50,
|
|
726
|
+
63,
|
|
727
|
+
80,
|
|
728
|
+
100,
|
|
729
|
+
125,
|
|
730
|
+
160,
|
|
731
|
+
200,
|
|
732
|
+
250,
|
|
733
|
+
315,
|
|
734
|
+
400,
|
|
735
|
+
500,
|
|
736
|
+
630,
|
|
737
|
+
800,
|
|
738
|
+
1000,
|
|
739
|
+
1250,
|
|
740
|
+
1600,
|
|
741
|
+
2000,
|
|
742
|
+
2500,
|
|
743
|
+
3150,
|
|
744
|
+
4000,
|
|
745
|
+
5000,
|
|
746
|
+
6300,
|
|
747
|
+
8000,
|
|
748
|
+
10000,
|
|
749
|
+
12500,
|
|
750
|
+
16000,
|
|
751
|
+
20000
|
|
752
|
+
]
|
|
753
|
+
},
|
|
754
|
+
"GEQ_BANDS": {
|
|
755
|
+
"rel": "data/kernels/eq.json",
|
|
756
|
+
"kind": "scalar",
|
|
757
|
+
"doc": "The graphic EQ's section count: DERIVED from ISO_THIRD_OCTAVE_CENTRES_HZ, never a second literal. Generated into `omx_contract_limits.h` as `OMX_GEQ_BANDS`, which sizes `mix_geq.h`'s section array — its OWN budget, never a claimant on EQ_MAX_BANDS (graphic-eq-31 spec §3, roster ruling 3).",
|
|
758
|
+
"unit": "",
|
|
759
|
+
"value": 31
|
|
760
|
+
},
|
|
761
|
+
"OPERATOR_EQ_BANDS_RESERVE": {
|
|
762
|
+
"rel": "data/kernels/eq.json",
|
|
763
|
+
"kind": "scalar",
|
|
764
|
+
"doc": "The band slots kept for the operator's own hand: the reserve the feedback suppressor and the ring correction may never eat into. Nine is the working set a live EQ actually holds. The budget OPERATOR_EQ_BANDS_RESERVE + FBS_DEFAULT_MAX_AUTO_BANDS + HRP_DEFAULT_MAX_AUTO_BANDS (9 + 6 + 8 = 23) must fit EQ_MAX_BANDS, and `omx-contract validate` refuses data where it does not.",
|
|
765
|
+
"unit": "",
|
|
766
|
+
"value": 9
|
|
767
|
+
},
|
|
667
768
|
"EQ_BAND_COUNTS": {
|
|
668
769
|
"rel": "data/kernels/eq.json",
|
|
669
770
|
"kind": "sheet",
|
|
@@ -1011,6 +1112,15 @@
|
|
|
1011
1112
|
"unit": "ms",
|
|
1012
1113
|
"value": 6
|
|
1013
1114
|
},
|
|
1115
|
+
"GATE_KEY_SOURCES": {
|
|
1116
|
+
"rel": "data/kernels/gate.json",
|
|
1117
|
+
"kind": "set",
|
|
1118
|
+
"doc": "Where the gate listens: its own input (self), or the key it is handed (sidechain), in the order of the integer the key port carries.",
|
|
1119
|
+
"value": [
|
|
1120
|
+
"self",
|
|
1121
|
+
"sidechain"
|
|
1122
|
+
]
|
|
1123
|
+
},
|
|
1014
1124
|
"GATE_LIMITS": {
|
|
1015
1125
|
"rel": "data/kernels/gate.json",
|
|
1016
1126
|
"kind": "travels",
|
|
@@ -1091,15 +1201,6 @@
|
|
|
1091
1201
|
}
|
|
1092
1202
|
}
|
|
1093
1203
|
},
|
|
1094
|
-
"GATE_KEY_SOURCES": {
|
|
1095
|
-
"rel": "data/kernels/gate.json",
|
|
1096
|
-
"kind": "set",
|
|
1097
|
-
"doc": "Where the gate listens: its own input (self), or the key it is handed (sidechain), in the order of the integer the key port carries.",
|
|
1098
|
-
"value": [
|
|
1099
|
-
"self",
|
|
1100
|
-
"sidechain"
|
|
1101
|
-
]
|
|
1102
|
-
},
|
|
1103
1204
|
"GEQ_BAND_RANGE": {
|
|
1104
1205
|
"rel": "data/kernels/geq.json",
|
|
1105
1206
|
"kind": "travels",
|
|
@@ -1135,6 +1236,20 @@
|
|
|
1135
1236
|
"unit": "dB",
|
|
1136
1237
|
"value": 30
|
|
1137
1238
|
},
|
|
1239
|
+
"HRP_AMOUNT_RANGE": {
|
|
1240
|
+
"rel": "data/kernels/hrp.json",
|
|
1241
|
+
"kind": "travels",
|
|
1242
|
+
"doc": "How much of the computed correction HRP applies: 0 = analyse only, 1 = the full cut. It comes up at 0.5, half the computed cut.",
|
|
1243
|
+
"shape": "travel",
|
|
1244
|
+
"value": {
|
|
1245
|
+
"min": 0,
|
|
1246
|
+
"max": 1,
|
|
1247
|
+
"step": 0,
|
|
1248
|
+
"unit": "",
|
|
1249
|
+
"default": 0.5,
|
|
1250
|
+
"defaultFrom": "desk"
|
|
1251
|
+
}
|
|
1252
|
+
},
|
|
1138
1253
|
"HRP_MAX_CUT_DB": {
|
|
1139
1254
|
"rel": "data/kernels/hrp.json",
|
|
1140
1255
|
"kind": "scalar",
|
|
@@ -1191,19 +1306,6 @@
|
|
|
1191
1306
|
"unit": "",
|
|
1192
1307
|
"value": 8
|
|
1193
1308
|
},
|
|
1194
|
-
"HRP_AMOUNT_RANGE": {
|
|
1195
|
-
"rel": "data/kernels/hrp.json",
|
|
1196
|
-
"kind": "travels",
|
|
1197
|
-
"doc": "How much of the computed correction HRP applies: 0 = analyse only, 1 = the full cut. It comes up at 0.5, half the computed cut.",
|
|
1198
|
-
"shape": "travel",
|
|
1199
|
-
"value": {
|
|
1200
|
-
"min": 0,
|
|
1201
|
-
"max": 1,
|
|
1202
|
-
"step": 0,
|
|
1203
|
-
"unit": "",
|
|
1204
|
-
"default": 0.5
|
|
1205
|
-
}
|
|
1206
|
-
},
|
|
1207
1309
|
"LIMITER_LIMITS": {
|
|
1208
1310
|
"rel": "data/kernels/limiter.json",
|
|
1209
1311
|
"kind": "travels",
|
|
@@ -1299,20 +1401,6 @@
|
|
|
1299
1401
|
"defaultFrom": "desk"
|
|
1300
1402
|
}
|
|
1301
1403
|
},
|
|
1302
|
-
"PHASER_STAGE_COUNTS": {
|
|
1303
|
-
"rel": "data/kernels/phaser.json",
|
|
1304
|
-
"kind": "list",
|
|
1305
|
-
"doc": "The member set the `stages` field accepts: PHASER_STAGES_RANGE walked by its step.",
|
|
1306
|
-
"unit": "",
|
|
1307
|
-
"value": [
|
|
1308
|
-
2,
|
|
1309
|
-
4,
|
|
1310
|
-
6,
|
|
1311
|
-
8,
|
|
1312
|
-
10,
|
|
1313
|
-
12
|
|
1314
|
-
]
|
|
1315
|
-
},
|
|
1316
1404
|
"PHASER_FEEDBACK_RANGE": {
|
|
1317
1405
|
"rel": "data/kernels/phaser.json",
|
|
1318
1406
|
"kind": "travels",
|
|
@@ -1389,6 +1477,20 @@
|
|
|
1389
1477
|
}
|
|
1390
1478
|
}
|
|
1391
1479
|
},
|
|
1480
|
+
"PHASER_STAGE_COUNTS": {
|
|
1481
|
+
"rel": "data/kernels/phaser.json",
|
|
1482
|
+
"kind": "list",
|
|
1483
|
+
"doc": "The member set the `stages` field accepts: PHASER_STAGES_RANGE walked by its step.",
|
|
1484
|
+
"unit": "",
|
|
1485
|
+
"value": [
|
|
1486
|
+
2,
|
|
1487
|
+
4,
|
|
1488
|
+
6,
|
|
1489
|
+
8,
|
|
1490
|
+
10,
|
|
1491
|
+
12
|
|
1492
|
+
]
|
|
1493
|
+
},
|
|
1392
1494
|
"PHASER_F_TOP_HZ": {
|
|
1393
1495
|
"rel": "data/kernels/phaser.json",
|
|
1394
1496
|
"kind": "scalar",
|
|
@@ -1717,6 +1819,16 @@
|
|
|
1717
1819
|
"defaultFrom": "desk"
|
|
1718
1820
|
}
|
|
1719
1821
|
},
|
|
1822
|
+
"ROTARY_SPEEDS": {
|
|
1823
|
+
"rel": "data/kernels/rotary.json",
|
|
1824
|
+
"kind": "set",
|
|
1825
|
+
"doc": "The rotary speaker's speed settings, in the order of the integer the kernel reads: the rotors stopped, at their chorale (slow) rate, or at their tremolo (fast) rate.",
|
|
1826
|
+
"value": [
|
|
1827
|
+
"stop",
|
|
1828
|
+
"slow",
|
|
1829
|
+
"fast"
|
|
1830
|
+
]
|
|
1831
|
+
},
|
|
1720
1832
|
"ROTARY_TRAVELS": {
|
|
1721
1833
|
"rel": "data/kernels/rotary.json",
|
|
1722
1834
|
"kind": "travels",
|
|
@@ -1865,16 +1977,6 @@
|
|
|
1865
1977
|
"unit": "",
|
|
1866
1978
|
"value": 256
|
|
1867
1979
|
},
|
|
1868
|
-
"ROTARY_SPEEDS": {
|
|
1869
|
-
"rel": "data/kernels/rotary.json",
|
|
1870
|
-
"kind": "set",
|
|
1871
|
-
"doc": "The rotary speaker's speed settings, in the order of the integer the kernel reads: the rotors stopped, at their chorale (slow) rate, or at their tremolo (fast) rate.",
|
|
1872
|
-
"value": [
|
|
1873
|
-
"stop",
|
|
1874
|
-
"slow",
|
|
1875
|
-
"fast"
|
|
1876
|
-
]
|
|
1877
|
-
},
|
|
1878
1980
|
"RTA_TARGET_BIN_HZ": {
|
|
1879
1981
|
"rel": "data/kernels/rta.json",
|
|
1880
1982
|
"kind": "scalar",
|
|
@@ -2007,6 +2109,16 @@
|
|
|
2007
2109
|
"defaultFrom": "desk"
|
|
2008
2110
|
}
|
|
2009
2111
|
},
|
|
2112
|
+
"TREMOLO_MODES": {
|
|
2113
|
+
"rel": "data/kernels/tremolo.json",
|
|
2114
|
+
"kind": "set",
|
|
2115
|
+
"doc": "What the tremolo's one oscillator modulates, in the order of the integer the kernel reads: the level of both legs in phase (tremolo), or the balance law's position with the legs in opposition (pan).",
|
|
2116
|
+
"default": "tremolo",
|
|
2117
|
+
"value": [
|
|
2118
|
+
"tremolo",
|
|
2119
|
+
"pan"
|
|
2120
|
+
]
|
|
2121
|
+
},
|
|
2010
2122
|
"TREMOLO_TRAVELS": {
|
|
2011
2123
|
"rel": "data/kernels/tremolo.json",
|
|
2012
2124
|
"kind": "travels",
|
|
@@ -2039,16 +2151,6 @@
|
|
|
2039
2151
|
}
|
|
2040
2152
|
}
|
|
2041
2153
|
},
|
|
2042
|
-
"TREMOLO_MODES": {
|
|
2043
|
-
"rel": "data/kernels/tremolo.json",
|
|
2044
|
-
"kind": "set",
|
|
2045
|
-
"doc": "What the tremolo's one oscillator modulates, in the order of the integer the kernel reads: the level of both legs in phase (tremolo), or the balance law's position with the legs in opposition (pan).",
|
|
2046
|
-
"default": "tremolo",
|
|
2047
|
-
"value": [
|
|
2048
|
-
"tremolo",
|
|
2049
|
-
"pan"
|
|
2050
|
-
]
|
|
2051
|
-
},
|
|
2052
2154
|
"BUTTERWORTH_Q": {
|
|
2053
2155
|
"rel": "data/primitives.json",
|
|
2054
2156
|
"kind": "scalar",
|