@openmixer/omx-contract 0.0.0 → 1.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.
@@ -0,0 +1,562 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ // GENERATED by `omx-contract render --target ts` from FreeMixer/omx-contract's data/ — do not edit.
4
+
5
+ /**
6
+ * The chorus's right-leg phase offset, in TURNS of its one oscillator (§2, §3a; the native-FX catalogue's M32 Dimension row). The right leg's voice k reads the LFO at k/N + spread: 0 is both legs one phase (the stage without the field, bit for bit), 0.25 quadrature, 0.5 the Dimension's opposed sweep. A fraction of a cycle carries no engineering symbol, so the unit is ''.
7
+ * @see data/kernels/chorus.json
8
+ */
9
+ export const CHORUS_SPREAD_RANGE = {
10
+ "min": 0,
11
+ "max": 0.5,
12
+ "step": 0.01,
13
+ "unit": "",
14
+ "default": 0,
15
+ "defaultFrom": "desk"
16
+ };
17
+
18
+ /**
19
+ * The legal range of each compressor field (engineering units). The widget clamps drags to these, `normalizeComp` enforces them, the row's codec refuses by them and the travel sheet publishes them. `default`/`defaultFrom` are the come-up values `defaultCompState` seeds a fresh strip with, read BACK from here rather than restated there.
20
+ * @see data/kernels/comp.json
21
+ */
22
+ export const COMP_LIMITS = {
23
+ "thresholdDb": {
24
+ "min": -60,
25
+ "max": 0,
26
+ "step": 1,
27
+ "unit": "dB",
28
+ "default": -18,
29
+ "defaultFrom": "desk"
30
+ },
31
+ "ratio": {
32
+ "min": 1,
33
+ "max": 20,
34
+ "step": 0.5,
35
+ "unit": "",
36
+ "default": 4,
37
+ "defaultFrom": "desk"
38
+ },
39
+ "kneeDb": {
40
+ "min": 0,
41
+ "max": 24,
42
+ "step": 0.5,
43
+ "unit": "dB",
44
+ "default": 6,
45
+ "defaultFrom": "desk"
46
+ },
47
+ "attackMs": {
48
+ "min": 0.1,
49
+ "max": 100,
50
+ "step": 1,
51
+ "unit": "ms",
52
+ "default": 5,
53
+ "defaultFrom": "desk"
54
+ },
55
+ "releaseMs": {
56
+ "min": 5,
57
+ "max": 3000,
58
+ "step": 10,
59
+ "unit": "ms",
60
+ "default": 200,
61
+ "defaultFrom": "desk"
62
+ },
63
+ "makeupDb": {
64
+ "min": 0,
65
+ "max": 24,
66
+ "step": 0.5,
67
+ "unit": "dB",
68
+ "default": 0,
69
+ "defaultFrom": "desk"
70
+ },
71
+ "mixPct": {
72
+ "min": 0,
73
+ "max": 100,
74
+ "step": 5,
75
+ "unit": "%",
76
+ "default": 100,
77
+ "defaultFrom": "desk"
78
+ }
79
+ };
80
+
81
+ /**
82
+ * The program-dependent release's model constants — the LA-2A's opto cell as DATA (`docs/design/specs/2026-09-26-compressor-models.md` §3b). `chargeMs`/`dischargeMs` are the word's memory constants, shared by every profile; each profile's `fastMs`, `slowMinMs`, `slowMaxMs` and `share` fit the unit's published two-stage recovery. Not operator controls: generated into `omx_contract_limits.h` as `OMX_PROGRAM_RELEASE_*`, which libomxdsp's `omx_env_program_release` reads.
83
+ * @see data/kernels/comp.json
84
+ */
85
+ export const PROGRAM_RELEASE = {
86
+ "chargeMs": 1000,
87
+ "dischargeMs": 5000,
88
+ "profiles": {
89
+ "opto": {
90
+ "fastMs": 70,
91
+ "slowMinMs": 110,
92
+ "slowMaxMs": 1100,
93
+ "share": 0.5
94
+ }
95
+ }
96
+ };
97
+
98
+ /**
99
+ * The FX delay's time travel. `max` is the NATIVE ring's ceiling — the same number as `OMX_FXDELAY_MAX_MS` in `omx_delay.h`, pinned to it by `output-delay-ceiling.test.ts`. Distinct from the per-route ALIGNMENT delay (`OUTPUT_DELAY_RANGE`, 1 s, `OMX_DELAY_MAX_MS`): one is a musical echo with feedback and mix, the other is a pure latency. Two facts, two rings, two ceilings — sharing the word "delay" is why they keep being confused for each other.
100
+ * @see data/kernels/delay.json
101
+ */
102
+ export const FX_DELAY_TIME_RANGE = {
103
+ "min": 0,
104
+ "max": 2000,
105
+ "step": 1,
106
+ "unit": "ms",
107
+ "default": 300,
108
+ "defaultFrom": "desk"
109
+ };
110
+
111
+ /**
112
+ * The FX delay's REGENERATION travel — how much of the wet tail feeds back in. Stops short of 1: unity feedback is a runaway the kernel hard-clamps anyway, so offering it would draw travel the DSP refuses. Not NORMALIZED_RANGE for exactly that reason — it is a 0..1 quantity whose top the DSP does not accept, and a control must not offer a value its actuator will eat.
113
+ * @see data/kernels/delay.json
114
+ */
115
+ export const FX_DELAY_FEEDBACK_RANGE = {
116
+ "min": 0,
117
+ "max": 0.99,
118
+ "step": 0,
119
+ "unit": "",
120
+ "default": 0.3,
121
+ "defaultFrom": "desk"
122
+ };
123
+
124
+ /**
125
+ * The FX delay's TONE — a NORMALIZED_RANGE instance with its own come-up value, matching `DEFAULT_DELAY_STATE.tone`. See REVERB_SIZE_RANGE for why this is a named constant rather than a default on the shared shape.
126
+ * @see data/kernels/delay.json
127
+ */
128
+ export const DELAY_TONE_RANGE = {
129
+ "min": 0,
130
+ "max": 1,
131
+ "step": 0,
132
+ "unit": "",
133
+ "default": 0.3,
134
+ "defaultFrom": "desk"
135
+ };
136
+
137
+ /**
138
+ * The FX DELAY's wet/dry — the same split as REVERB_MIX_RANGE, its own declaration.
139
+ * @see data/kernels/delay.json
140
+ */
141
+ export const DELAY_MIX_RANGE = {
142
+ "min": 0,
143
+ "max": 1,
144
+ "step": 0,
145
+ "unit": "",
146
+ "default": 0.3,
147
+ "defaultFrom": "desk",
148
+ "byKind": {
149
+ "fxReturn": 1
150
+ }
151
+ };
152
+
153
+ /**
154
+ * The FX delay's PING-PONG come-up value — a toggle, so it has no travel, only this. Declared here rather than as a literal in the server's `DEFAULT_DELAY_STATE` (which now reads it) so the DPF plugin generator (`packages/omx-plugins/tools/params-gen.mjs`, `2026-09-25-omx-plugins-dpf.md` §3a) reads the same fact the desk seeds a fresh strip with.
155
+ * @see data/kernels/delay.json
156
+ */
157
+ export const FX_DELAY_PINGPONG_DEFAULT = false;
158
+
159
+ /**
160
+ * 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.
161
+ * @see data/kernels/drive.json
162
+ */
163
+ export const DRIVE_BIAS_MAX = 0.7071067811865476;
164
+
165
+ /**
166
+ * 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.
167
+ * @see data/kernels/eq.json
168
+ */
169
+ export const EQ_MAX_BANDS = 24;
170
+
171
+ /**
172
+ * The standard ISO 266 one-third-octave centre frequencies, 20 Hz–20 kHz (31 bands) — the classic 31-band graphic-EQ layout's centres.
173
+ * @see data/kernels/eq.json
174
+ */
175
+ export const ISO_THIRD_OCTAVE_CENTRES_HZ = [
176
+ 20,
177
+ 25,
178
+ 31.5,
179
+ 40,
180
+ 50,
181
+ 63,
182
+ 80,
183
+ 100,
184
+ 125,
185
+ 160,
186
+ 200,
187
+ 250,
188
+ 315,
189
+ 400,
190
+ 500,
191
+ 630,
192
+ 800,
193
+ 1000,
194
+ 1250,
195
+ 1600,
196
+ 2000,
197
+ 2500,
198
+ 3150,
199
+ 4000,
200
+ 5000,
201
+ 6300,
202
+ 8000,
203
+ 10000,
204
+ 12500,
205
+ 16000,
206
+ 20000
207
+ ];
208
+
209
+ /**
210
+ * 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).
211
+ * @see data/kernels/eq.json
212
+ */
213
+ export const GEQ_BANDS = 31;
214
+
215
+ /**
216
+ * The legal range of each gate field (engineering units). The widget clamps drags to these, `normalizeGate` enforces them, the row's codec refuses by them and the travel sheet publishes them — one source of truth. `rangeDb` reaches GATE_RANGE_FLOOR_DB, shown as "−∞" in readouts (a gate fully closed is silence).
217
+ * @see data/kernels/gate.json
218
+ */
219
+ export const GATE_LIMITS = {
220
+ "thresholdDb": {
221
+ "min": -80,
222
+ "max": 0,
223
+ "step": 1,
224
+ "unit": "dB",
225
+ "default": -40,
226
+ "defaultFrom": "desk"
227
+ },
228
+ "rangeDb": {
229
+ "min": -90,
230
+ "max": 0,
231
+ "step": 1,
232
+ "unit": "dB",
233
+ "default": -90,
234
+ "defaultFrom": "desk"
235
+ },
236
+ "kneeStartDb": {
237
+ "min": -80,
238
+ "max": 0,
239
+ "step": 1,
240
+ "unit": "dB",
241
+ "default": -43,
242
+ "defaultFrom": "desk"
243
+ },
244
+ "kneeEndDb": {
245
+ "min": -80,
246
+ "max": 0,
247
+ "step": 1,
248
+ "unit": "dB",
249
+ "default": -37,
250
+ "defaultFrom": "desk"
251
+ },
252
+ "attackMs": {
253
+ "min": 0,
254
+ "max": 500,
255
+ "step": 0.5,
256
+ "unit": "ms",
257
+ "default": 1,
258
+ "defaultFrom": "desk"
259
+ },
260
+ "holdMs": {
261
+ "min": 0,
262
+ "max": 2000,
263
+ "step": 5,
264
+ "unit": "ms",
265
+ "default": 10,
266
+ "defaultFrom": "desk"
267
+ },
268
+ "releaseMs": {
269
+ "min": 0,
270
+ "max": 5000,
271
+ "step": 10,
272
+ "unit": "ms",
273
+ "default": 100,
274
+ "defaultFrom": "desk"
275
+ },
276
+ "hysteresisDb": {
277
+ "min": 0,
278
+ "max": 24,
279
+ "step": 0.5,
280
+ "unit": "dB",
281
+ "default": 3,
282
+ "defaultFrom": "desk"
283
+ },
284
+ "ratio": {
285
+ "min": 1,
286
+ "max": 100,
287
+ "step": 1,
288
+ "unit": "",
289
+ "default": 16,
290
+ "defaultFrom": "desk"
291
+ }
292
+ };
293
+
294
+ /**
295
+ * The precision limiter's travels (`2026-09-27-precision-limiter.md` §2), rendered into `omx_contract_limits.h` as `OMX_LIMITER_*` by `harness/contract-limits-gen.mjs`, so `mix_limiter.h` reads them and never restates one (R-094). The ceiling is a TRUE peak in dBFS (the ×4 detector); the look-ahead sets the declared latency; the release is the envelope's time constant on the gain depth.
296
+ * @see data/kernels/limiter.json
297
+ */
298
+ export const LIMITER_LIMITS = {
299
+ "ceilingDb": {
300
+ "min": -12,
301
+ "max": 0,
302
+ "step": 0.1,
303
+ "unit": "dBFS",
304
+ "default": -1,
305
+ "defaultFrom": "desk"
306
+ },
307
+ "lookaheadMs": {
308
+ "min": 0.5,
309
+ "max": 5,
310
+ "step": 0.1,
311
+ "unit": "ms",
312
+ "default": 1.5,
313
+ "defaultFrom": "desk"
314
+ },
315
+ "releaseMs": {
316
+ "min": 1,
317
+ "max": 1000,
318
+ "step": 1,
319
+ "unit": "ms",
320
+ "default": 50,
321
+ "defaultFrom": "desk"
322
+ }
323
+ };
324
+
325
+ /**
326
+ * PITCH_LIMITS, moved from openmixer.
327
+ * @see data/kernels/pitch.json
328
+ */
329
+ export const PITCH_LIMITS = {
330
+ "semitones": {
331
+ "min": -12,
332
+ "max": 12,
333
+ "default": 0
334
+ },
335
+ "cents": {
336
+ "min": -50,
337
+ "max": 50,
338
+ "default": 0
339
+ },
340
+ "mix": {
341
+ "min": 0,
342
+ "max": 100,
343
+ "default": 100
344
+ }
345
+ };
346
+
347
+ /**
348
+ * PITCH_KERNEL, moved from openmixer.
349
+ * @see data/kernels/pitch.json
350
+ */
351
+ export const PITCH_KERNEL = {
352
+ "windowMs": 40,
353
+ "prefilterCeilingHz": 20000,
354
+ "prefilterQ": 0.7071067811865476
355
+ };
356
+
357
+ /**
358
+ * PLATE's tank MODULATION DEPTH, in percent of Dattorro's own excursion (±8 samples at his 29 761 Hz tuning rate, scaled to the live rate the way the tank lengths are). 100 is the depth the plate has always run at, so the come-up is bit-identical to the plate before the field; 0 brings back the unmodulated tank's ring; 400 is the wide, chorused EMT-style swing. The rate stays 1 Hz. Only PLATE reads it (`2026-09-26-native-fx-catalogue.md` §2, Reverb).
359
+ * @see data/kernels/reverb.json
360
+ */
361
+ export const REVERB_PLATE_MOD_DEPTH_RANGE = {
362
+ "min": 0,
363
+ "max": 400,
364
+ "step": 1,
365
+ "unit": "%",
366
+ "default": 100,
367
+ "defaultFrom": "desk"
368
+ };
369
+
370
+ /**
371
+ * The legal range of each transient-designer field (engineering units), transient spec §3. Every kind comes up flat: no per-kind default differs. `harness/contract-limits-gen.mjs` emits each as `OMX_TRANSIENT_<FIELD>_{MIN,MAX,DEFAULT}` for `mix_transient.h`'s resolve; the row publishes them on OPTIONS when it lands (issue #921).
372
+ * @see data/kernels/transient.json
373
+ */
374
+ export const TRANSIENT_LIMITS = {
375
+ "attackDb": {
376
+ "min": -24,
377
+ "max": 24,
378
+ "step": 0.1,
379
+ "unit": "dB",
380
+ "default": 0,
381
+ "defaultFrom": "desk"
382
+ },
383
+ "sustainDb": {
384
+ "min": -24,
385
+ "max": 24,
386
+ "step": 0.1,
387
+ "unit": "dB",
388
+ "default": 0,
389
+ "defaultFrom": "desk"
390
+ },
391
+ "attackTimeMs": {
392
+ "min": 2,
393
+ "max": 50,
394
+ "step": 0.1,
395
+ "unit": "ms",
396
+ "default": 10,
397
+ "defaultFrom": "desk"
398
+ },
399
+ "sustainTimeMs": {
400
+ "min": 50,
401
+ "max": 2000,
402
+ "step": 1,
403
+ "unit": "ms",
404
+ "default": 250,
405
+ "defaultFrom": "desk"
406
+ },
407
+ "outputDb": {
408
+ "min": -24,
409
+ "max": 12,
410
+ "step": 0.1,
411
+ "unit": "dB",
412
+ "default": 0,
413
+ "defaultFrom": "desk"
414
+ }
415
+ };
416
+
417
+ /**
418
+ * The fast follower's attack, ms: exactly the dynamics detector's no-oversampling line (transient spec §3, L7).
419
+ * @see data/kernels/transient.json
420
+ */
421
+ export const TRANSIENT_FAST_ATTACK_MS = 0.5;
422
+
423
+ /**
424
+ * The fast follower's release, ms: one 50 Hz cycle held, a 180 bpm sixteenth forgotten (transient spec §3).
425
+ * @see data/kernels/transient.json
426
+ */
427
+ export const TRANSIENT_FAST_RELEASE_MS = 20;
428
+
429
+ /**
430
+ * The contrast, dB, at which a knob reaches its full value (transient spec §2, §3).
431
+ * @see data/kernels/transient.json
432
+ */
433
+ export const TRANSIENT_REF_DB = 6;
434
+
435
+ /**
436
+ * The detector floor, linear (−100 dBFS): below it both envelopes read the floor and the stage is unity (transient spec §3).
437
+ * @see data/kernels/transient.json
438
+ */
439
+ export const TRANSIENT_FLOOR_LIN = 0.00001;
440
+
441
+ /**
442
+ * The delay plugin's parameters, in append-only order: DPF's parameter index is the CLAP param id and the LV2 port order (omx-plugins-dpf §3b). Moved from openmixer's packages/omx-plugins/tools/params-gen.mjs PLUGINS.delay.
443
+ *
444
+ * Why: mix is per instance on the desk (insert or fxReturn); a plugin racked in a foreign host is an INSERT, so it reads the input kind's default (omx-plugins-dpf §3a).
445
+ * @see data/plugins/delay.json
446
+ */
447
+ export const DELAY_PLUGIN = {
448
+ "plugin": "delay",
449
+ "header": "omx_delay_params.h",
450
+ "prefix": "OMX_DELAY",
451
+ "params": [
452
+ {
453
+ "symbol": "timeMs",
454
+ "min": 0,
455
+ "max": 2000,
456
+ "def": 300,
457
+ "step": 1,
458
+ "unit": "ms",
459
+ "toggle": false
460
+ },
461
+ {
462
+ "symbol": "feedback",
463
+ "min": 0,
464
+ "max": 0.99,
465
+ "def": 0.3,
466
+ "step": 0,
467
+ "unit": "",
468
+ "toggle": false
469
+ },
470
+ {
471
+ "symbol": "mix",
472
+ "min": 0,
473
+ "max": 1,
474
+ "def": 0.3,
475
+ "step": 0,
476
+ "unit": "",
477
+ "toggle": false
478
+ },
479
+ {
480
+ "symbol": "tone",
481
+ "min": 0,
482
+ "max": 1,
483
+ "def": 0.3,
484
+ "step": 0,
485
+ "unit": "",
486
+ "toggle": false
487
+ },
488
+ {
489
+ "symbol": "pingpong",
490
+ "min": 0,
491
+ "max": 1,
492
+ "def": 0,
493
+ "step": 1,
494
+ "unit": "",
495
+ "toggle": true
496
+ }
497
+ ]
498
+ };
499
+
500
+ /**
501
+ * The Q of a second-order Butterworth section, 1/√2 — maximally flat, the one value every Butterworth biquad in the tree designs at: the LR4 crossover section, the pitch pre-filter and the drive's tilt / band / HF sections, in TS and (as `OMX_BUTTERWORTH_Q`) in C (§7, the scalar door).
502
+ * @see data/primitives.json
503
+ */
504
+ export const BUTTERWORTH_Q = 0.7071067811865476;
505
+
506
+ /**
507
+ * ALLPASS_LIMITS, moved from openmixer.
508
+ * @see data/primitives.json
509
+ */
510
+ export const ALLPASS_LIMITS = {
511
+ "unityTolerance": 0.0001
512
+ };
513
+
514
+ /**
515
+ * XOVER_LIMITS, moved from openmixer.
516
+ * @see data/primitives.json
517
+ */
518
+ export const XOVER_LIMITS = {
519
+ "lr2SectionQ": 0.5,
520
+ "lr4SectionQ": 0.7071067811865476,
521
+ "partitionTolerance": 0.00001
522
+ };
523
+
524
+ /**
525
+ * The order the chorus and flanger construct their lines with (four taps; the fdelay spec §1).
526
+ * @see data/primitives.json
527
+ */
528
+ export const FDELAY_MOD_READ_ORDER = 3;
529
+
530
+ /**
531
+ * `Λ` for the chorus/flanger read — ONE value; the header and every law read this.
532
+ * @see data/primitives.json
533
+ */
534
+ export const FDELAY_READ_L1_NORM = 1.25;
535
+
536
+ /**
537
+ * The standard sample rates (Hz) the desk recognises — the pro-audio superset. One source of truth for the clock controller's `clock.allowed-rates` seed, the force row's validation ceiling and the device-rate probe fallback. What the operator is OFFERED is always the DEVICE's own `supportedRates` (`2026-07-15-clock-rate-honest-force-rate.md`) — this is the ceiling a write is refused by, never a menu.
538
+ * @see data/rates.json
539
+ */
540
+ export const STANDARD_SAMPLE_RATES = [
541
+ 44100,
542
+ 48000,
543
+ 88200,
544
+ 96000,
545
+ 176400,
546
+ 192000
547
+ ];
548
+
549
+ /**
550
+ * THE declaration: 192 kHz at quantum 128.
551
+ * @see data/rates.json
552
+ */
553
+ export const RT_HARD_TARGET = {
554
+ "rate": 192000,
555
+ "quantum": 128
556
+ };
557
+
558
+ /**
559
+ * The rate a unit-range DSP knob is quoted at (R-058): the rate this desk runs (ruling 2026-09-14). A kernel raises the knob to `REF / sr`, so at this rate the exponent is exactly 1 and the response is bit-for-bit the one cut before the law. Emitted to C as `OMX_DSP_KNOB_REFERENCE_RATE`; the reverb damping and FX-delay tone references `#define` from it.
560
+ * @see data/rates.json
561
+ */
562
+ export const DSP_KNOB_REFERENCE_RATE = 96000;