@openmixer/omx-contract 1.3.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 +68 -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 +26 -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 +134 -3
- package/lib/fmt.mjs +22 -2
- package/lib/validate.mjs +43 -2
- package/package.json +1 -1
- package/render/json.mjs +6 -2
- package/share/omx-contract/omx-contract.json +865 -128
package/data/kernels/fbs.json
CHANGED
|
@@ -1,148 +1,150 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "../../schema/omx-contract.schema.json",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"
|
|
3
|
+
"constants": {
|
|
4
|
+
"SUBHARMONIC_RADIUS_BINS": {
|
|
5
|
+
"kind": "scalar",
|
|
6
|
+
"doc": "How far (bins) around bin/2 and bin/3 PSHR (`omx_fbs_pshr`) scans for a sub-harmonic line. A true half/third partial lands mid-bin in the worst case (bin/2 and bin/3 are rarely integers) and spectral leakage smears it one bin further; ±2 covers both. Measured on the #116 live-music corpus: every false positive's sub-line sat inside this window. Deliberately NOT wider — at low bins the window is already a large fraction of an octave, and widening it would start reading unrelated program lines as \"sub-harmonics\" of real feedback.",
|
|
7
|
+
"unit": "",
|
|
8
|
+
"value": 2
|
|
9
|
+
},
|
|
10
|
+
"FBS_PAPR_GUARD_BINS": {
|
|
11
|
+
"kind": "scalar",
|
|
12
|
+
"doc": "PAPR's guard band: bins either side of the peak left out of the floor average (its own skirt).",
|
|
13
|
+
"unit": "",
|
|
14
|
+
"value": 2
|
|
15
|
+
},
|
|
16
|
+
"FBS_PNPR_RADIUS_BINS": {
|
|
17
|
+
"kind": "scalar",
|
|
18
|
+
"doc": "PNPR's neighbourhood radius in bins, and the guard inside it that belongs to the peak's own skirt: a pure tone is compared with bins 2 and 3 away on each side.",
|
|
19
|
+
"unit": "",
|
|
20
|
+
"value": 3
|
|
21
|
+
},
|
|
22
|
+
"FBS_PNPR_GUARD_BINS": {
|
|
23
|
+
"kind": "scalar",
|
|
24
|
+
"doc": "The guard inside PNPR's neighbourhood radius that belongs to the peak's own skirt, in bins.",
|
|
25
|
+
"unit": "",
|
|
26
|
+
"value": 1
|
|
27
|
+
},
|
|
28
|
+
"FBS_PHPR_HARMONICS": {
|
|
29
|
+
"kind": "scalar",
|
|
30
|
+
"doc": "How many harmonics PHPR reads above the candidate: 2f, 3f and 4f.",
|
|
31
|
+
"unit": "",
|
|
32
|
+
"value": 3
|
|
33
|
+
},
|
|
34
|
+
"FBS_PSHR_SELF_SKIP_BINS": {
|
|
35
|
+
"kind": "scalar",
|
|
36
|
+
"doc": "PSHR skips sub-window bins within this many of the candidate, so a low bin never measures its own skirt as a sub-harmonic.",
|
|
37
|
+
"unit": "",
|
|
38
|
+
"value": 3
|
|
39
|
+
},
|
|
40
|
+
"FBS_FLOOR_LIN": {
|
|
41
|
+
"kind": "scalar",
|
|
42
|
+
"doc": "The magnitude floor of every detector dB reading (−240 dB): a zero bin stays finite.",
|
|
43
|
+
"unit": "",
|
|
44
|
+
"value": 1e-12
|
|
45
|
+
},
|
|
46
|
+
"FBS_TRACK_SLOTS": {
|
|
47
|
+
"kind": "scalar",
|
|
48
|
+
"doc": "Tracked candidate bins per armed channel. A candidate that finds no free slot is COUNTED and reported, never dropped silently; the identity corpus peaks at 34.",
|
|
49
|
+
"unit": "",
|
|
50
|
+
"value": 512
|
|
51
|
+
},
|
|
52
|
+
"PSHR_MIN_DB": {
|
|
53
|
+
"kind": "scalar",
|
|
54
|
+
"doc": "Minimum PSHR (`omx_fbs_pshr`) (dB) for a candidate frame to count as sub-harmonic-CLEAN. Evidence-set on the #116 corpus, margin on both sides: the four live false positives (musical overtones at 1 869.1 / 832.0 / 263.7 / 228.5 Hz) read PSHR between −10.2 and +8.8 dB across their windows — never a 5-frame sub-clean stretch, and the single closest approach (+8.8) is isolated between frames at ≈ −1 and −10 — while the committed #106 injected ramp reads ≥ +12.2 dB from its second frame on (its frame 0 sits at +9.4, costing exactly one frame of confirm latency, pinned in the corpus test). A static program line at f/2 of REAL feedback also clears this fast: the runaway gains several dB per hop on anything static, so the deferral is transient.",
|
|
55
|
+
"unit": "dB",
|
|
56
|
+
"value": 10
|
|
57
|
+
},
|
|
58
|
+
"GROWTH_WINDOW_FRAMES": {
|
|
59
|
+
"kind": "scalar",
|
|
60
|
+
"doc": "How many of a candidate bin's most recent dB readings feed the growth-slope estimate (the engine's least-squares slope) — set equal to DEFAULT_THRESHOLDS's `persistFrames` so growth is judged over the SAME window persistence already demands (the full run since the bin became a candidate, not a shorter or longer slice of it). Long enough that a couple of noisy/vibrato frames can't fake a trend by themselves.",
|
|
61
|
+
"unit": "",
|
|
62
|
+
"value": 5
|
|
63
|
+
},
|
|
64
|
+
"DEEP_PLATEAU_FRAMES": {
|
|
65
|
+
"kind": "scalar",
|
|
66
|
+
"doc": "The DEEP plateau tier's dwell: ~2 s at the watcher's 10 Hz — the TIME that buys the deeper floor its music safety (see DetectThresholds.deepPlateauFloorDb).",
|
|
67
|
+
"unit": "",
|
|
68
|
+
"value": 20
|
|
69
|
+
},
|
|
70
|
+
"GROWTH_MIN_DB_PER_FRAME": {
|
|
71
|
+
"kind": "scalar",
|
|
72
|
+
"doc": "Minimum least-squares slope, in dB PER FRAME, over GROWTH_WINDOW_FRAMES for a bin to count as \"running away\" rather than merely holding level. Set with real margin on BOTH sides — comfortably above measurement jitter on a held tone or a quiet/broadband mix (well under 0.2 dB/frame in practice) and comfortably below a genuine feedback ramp, which climbs several dB across a handful of ~20 ms hops as it heads toward clipping. Issue #91's acceptance bar is \"arming must never burst-alarm on non-growing content\", so this errs conservative (under-fire a marginal ramp) rather than tight (risk a false alarm) — the ramp gate (`omx_fbs_is_growing`) also requires the window's end to sit above its start, a cheap belt-and-braces check against a fit dragged positive by one mid-window wobble.",
|
|
73
|
+
"unit": "dB",
|
|
74
|
+
"value": 0.8
|
|
75
|
+
},
|
|
76
|
+
"GROWTH_MAX_DIP_DB": {
|
|
77
|
+
"kind": "scalar",
|
|
78
|
+
"doc": "Largest single-frame DIP (dB) a run-away window may contain. Real feedback climbs every hop; a small allowance covers measurement jitter and the −0.3 dB-ish wobble frames seen on live captures, while any real drop (a note ending, tremolo) breaks the run.",
|
|
79
|
+
"unit": "dB",
|
|
80
|
+
"value": 0.5
|
|
81
|
+
},
|
|
82
|
+
"GROWTH_MIN_TOTAL_RISE_DB": {
|
|
83
|
+
"kind": "scalar",
|
|
84
|
+
"doc": "Minimum END-TO-END rise (dB) across the window. The live-music corpus (issue #106) showed sustained melody notes drifting up ~4–5 dB over a window without ever being feedback; a loop past unity gains several dB per hop and clears 6 dB in a window trivially. Below this the tone is holding level, not running away.",
|
|
85
|
+
"unit": "dB",
|
|
86
|
+
"value": 6
|
|
87
|
+
},
|
|
88
|
+
"GROWTH_MAX_SINGLE_FRAME_SHARE": {
|
|
89
|
+
"kind": "scalar",
|
|
90
|
+
"doc": "Cap on the share of the window's total rise a SINGLE frame may carry. Feedback is exponential in amplitude ⇒ linear in dB ⇒ its rise is distributed roughly evenly across the window; a musical attack / re-articulation puts almost the whole rise in one hop (the exact shape behind every one of issue #106's 72 live false positives). One half is generous to real ramps (an even N-frame ramp puts 1/(N−1) per hop) and fatal to steps. A side effect worth knowing: a 2-sample window can never pass (one hop IS the whole rise), so confirmation always rests on at least three frames of actual ramp evidence.",
|
|
91
|
+
"unit": "",
|
|
92
|
+
"value": 0.5
|
|
93
|
+
},
|
|
94
|
+
"GROWTH_CONFIRM_FRAMES": {
|
|
95
|
+
"kind": "scalar",
|
|
96
|
+
"doc": "How many CONSECUTIVE frames the ramp gate (`omx_fbs_is_growing`) must hold before a bin confirms — the time-domain tiebreak for the one shape a single window cannot judge (issue #106): a smooth musical crescendo. Within one window a +6 dB swell (live corpus: a C6 at 1 049 Hz, `[-53.7, -51.4, -50.4, -48, -47.3]`) is indistinguishable from slow feedback — the difference is only visible on the NEXT hop, where a crescendo peaks and plateaus (the window's rise collapses) while feedback keeps climbing. Requiring the gate to hold twice in a row costs a clean ramp nothing — its gate is already true while persistence is still arming — and blocks the swell that peaks the very frame it would have confirmed.",
|
|
97
|
+
"unit": "",
|
|
98
|
+
"value": 2
|
|
99
|
+
},
|
|
100
|
+
"DEFAULT_THRESHOLDS": {
|
|
101
|
+
"kind": "sheet",
|
|
102
|
+
"doc": "The corpus-tuned SAFE DEFAULT — today's exact gates, assembled byte-for-byte from the exported consts above (which stay the authoritative literal source, so the corpus test's import type { MagnitudeSeries } from './spectrum-bands.js'; imports remain the single truth). This is the ANCHOR the whole sensitivity mapping pins to: thresholdsFor`(0, 'live')` and `(0, 'fixed')` both deep-equal this object, so an untouched channel runs the identical detector it does now. `plateauFloorDb` is omitted ⇒ the #140 plateau route is OFF at the default.",
|
|
103
|
+
"value": {
|
|
104
|
+
"paprDb": 18,
|
|
105
|
+
"pnprDb": 12,
|
|
106
|
+
"phprDb": 9,
|
|
107
|
+
"persistFrames": 5,
|
|
108
|
+
"growthConfirmFrames": {
|
|
109
|
+
"ref": "GROWTH_CONFIRM_FRAMES"
|
|
110
|
+
},
|
|
111
|
+
"subCleanFrames": {
|
|
112
|
+
"ref": "GROWTH_WINDOW_FRAMES"
|
|
113
|
+
},
|
|
114
|
+
"growthMinTotalRiseDb": {
|
|
115
|
+
"ref": "GROWTH_MIN_TOTAL_RISE_DB"
|
|
116
|
+
},
|
|
117
|
+
"growthMaxSingleFrameShare": {
|
|
118
|
+
"ref": "GROWTH_MAX_SINGLE_FRAME_SHARE"
|
|
119
|
+
},
|
|
120
|
+
"growthMinDbPerFrame": {
|
|
121
|
+
"ref": "GROWTH_MIN_DB_PER_FRAME"
|
|
122
|
+
},
|
|
123
|
+
"growthMaxDipDb": {
|
|
124
|
+
"ref": "GROWTH_MAX_DIP_DB"
|
|
125
|
+
},
|
|
126
|
+
"pshrMinDb": {
|
|
127
|
+
"ref": "PSHR_MIN_DB"
|
|
128
|
+
}
|
|
127
129
|
}
|
|
130
|
+
},
|
|
131
|
+
"FBS_MAX_NOTCH_DEPTH_DB": {
|
|
132
|
+
"kind": "scalar",
|
|
133
|
+
"doc": "THE NOTCH DEPTH LAW: the deepest cut any machine planter may propose from one reading, in dB. A number, not a literal at the call site, because two planters now lean on it. FBS derives a candidate's depth from the peak-to-average ratio around its bin and stops here; Room Analysis derives a mode's depth from its height above the median curve and is held to the SAME ceiling (2026-09-08-room-analysis.md §4 — \"never more than the FBS notch depth law\"). Written twice as `18` those two bounds would be equal by coincidence and could drift apart in silence. It is a CEILING ON THE PROPOSAL, not the final gain: a band that lands as a rampable BELL is bounded again by `EQ_GAIN_RANGE`, which is tighter. A planter must honour both and REPORT when either bit, never quietly deliver a shallower cut than it was asked for.",
|
|
134
|
+
"unit": "dB",
|
|
135
|
+
"value": 18
|
|
136
|
+
},
|
|
137
|
+
"FBS_DEFAULT_NOTCH_Q": {
|
|
138
|
+
"kind": "scalar",
|
|
139
|
+
"doc": "Default planted-notch width (Q) — the dbx-AFS-style ultra-narrow notch the corrector plants. `addBand`'s per-shape clamp holds it at 116 for a fixed notch and narrows it to 8 for a live bell, so this is the declared starting point rather than the width every notch ends up with.",
|
|
140
|
+
"unit": "",
|
|
141
|
+
"value": 116
|
|
142
|
+
},
|
|
143
|
+
"FBS_DEFAULT_MAX_AUTO_BANDS": {
|
|
144
|
+
"kind": "scalar",
|
|
145
|
+
"doc": "Default per-channel cap on auto-planted bands — a full pool plants nothing and raises a pool-full alert instead (predictability over silent eviction).",
|
|
146
|
+
"unit": "",
|
|
147
|
+
"value": 6
|
|
128
148
|
}
|
|
129
|
-
},
|
|
130
|
-
"FBS_MAX_NOTCH_DEPTH_DB": {
|
|
131
|
-
"kind": "scalar",
|
|
132
|
-
"doc": "THE NOTCH DEPTH LAW: the deepest cut any machine planter may propose from one reading, in dB. A number, not a literal at the call site, because two planters now lean on it. FBS derives a candidate's depth from the peak-to-average ratio around its bin and stops here; Room Analysis derives a mode's depth from its height above the median curve and is held to the SAME ceiling (2026-09-08-room-analysis.md §4 — \"never more than the FBS notch depth law\"). Written twice as `18` those two bounds would be equal by coincidence and could drift apart in silence. It is a CEILING ON THE PROPOSAL, not the final gain: a band that lands as a rampable BELL is bounded again by `EQ_GAIN_RANGE`, which is tighter. A planter must honour both and REPORT when either bit, never quietly deliver a shallower cut than it was asked for.",
|
|
133
|
-
"unit": "dB",
|
|
134
|
-
"value": 18
|
|
135
|
-
},
|
|
136
|
-
"FBS_DEFAULT_NOTCH_Q": {
|
|
137
|
-
"kind": "scalar",
|
|
138
|
-
"doc": "Default planted-notch width (Q) — the dbx-AFS-style ultra-narrow notch the corrector plants. `addBand`'s per-shape clamp holds it at 116 for a fixed notch and narrows it to 8 for a live bell, so this is the declared starting point rather than the width every notch ends up with.",
|
|
139
|
-
"unit": "",
|
|
140
|
-
"value": 116
|
|
141
|
-
},
|
|
142
|
-
"FBS_DEFAULT_MAX_AUTO_BANDS": {
|
|
143
|
-
"kind": "scalar",
|
|
144
|
-
"doc": "Default per-channel cap on auto-planted bands — a full pool plants nothing and raises a pool-full alert instead (predictability over silent eviction).",
|
|
145
|
-
"unit": "",
|
|
146
|
-
"value": 6
|
|
147
149
|
}
|
|
148
150
|
}
|
|
@@ -1,73 +1,81 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "../../schema/omx-contract.schema.json",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
"controls": [
|
|
4
|
+
{
|
|
5
|
+
"name": "rate",
|
|
6
|
+
"kind": "travel",
|
|
7
|
+
"doc": "The flanger's jet sweep (§3b).",
|
|
8
|
+
"travel": {
|
|
9
|
+
"min": 0.05,
|
|
10
|
+
"max": 5,
|
|
11
|
+
"step": 0.01,
|
|
12
|
+
"unit": "Hz",
|
|
13
|
+
"default": 0.25,
|
|
14
|
+
"defaultFrom": "desk"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "depth",
|
|
19
|
+
"kind": "travel",
|
|
20
|
+
"doc": "The flanger's peak-to-peak excursion above its declared 0.5 ms base (§3b).",
|
|
21
|
+
"travel": {
|
|
22
|
+
"min": 0,
|
|
23
|
+
"max": 5,
|
|
24
|
+
"step": 0.1,
|
|
25
|
+
"unit": "ms",
|
|
26
|
+
"default": 2,
|
|
27
|
+
"defaultFrom": "desk"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "feedback",
|
|
32
|
+
"kind": "travel",
|
|
33
|
+
"doc": "The flanger's SIGNED resonance (§3b). The ±0.95 clamp is DECLARED here — a PATCH asking for 1.0 is answered by this travel — and the kernel's own clamp is the enforcement half.",
|
|
34
|
+
"travel": {
|
|
35
|
+
"min": -0.95,
|
|
36
|
+
"max": 0.95,
|
|
37
|
+
"step": 0.01,
|
|
38
|
+
"unit": "",
|
|
39
|
+
"default": 0.6,
|
|
40
|
+
"defaultFrom": "desk"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "mix",
|
|
45
|
+
"kind": "travel",
|
|
46
|
+
"doc": "The flanger's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, equal dry and wet, where the comb is deepest (§3b).",
|
|
47
|
+
"travel": {
|
|
48
|
+
"min": 0,
|
|
49
|
+
"max": 100,
|
|
50
|
+
"step": 0.1,
|
|
51
|
+
"unit": "%",
|
|
52
|
+
"default": 50,
|
|
53
|
+
"defaultFrom": "desk"
|
|
54
|
+
}
|
|
13
55
|
}
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"min": 0,
|
|
20
|
-
"max": 5,
|
|
21
|
-
"step": 0.1,
|
|
56
|
+
],
|
|
57
|
+
"constants": {
|
|
58
|
+
"FLANGER_BASE_MS": {
|
|
59
|
+
"kind": "scalar",
|
|
60
|
+
"doc": "The flanger's base delay, ms: the sweep rides on it up to the depth.",
|
|
22
61
|
"unit": "ms",
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"kind": "travels",
|
|
41
|
-
"doc": "The flanger's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, equal dry and wet, where the comb is deepest (§3b).",
|
|
42
|
-
"travel": {
|
|
43
|
-
"min": 0,
|
|
44
|
-
"max": 100,
|
|
45
|
-
"step": 0.1,
|
|
46
|
-
"unit": "%",
|
|
47
|
-
"default": 50,
|
|
48
|
-
"defaultFrom": "desk"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"FLANGER_BASE_MS": {
|
|
52
|
-
"kind": "scalar",
|
|
53
|
-
"doc": "The flanger's base delay, ms: the sweep rides on it up to the depth.",
|
|
54
|
-
"unit": "ms",
|
|
55
|
-
"value": 0.5
|
|
56
|
-
},
|
|
57
|
-
"FLANGER_MAX_MS": {
|
|
58
|
-
"kind": "scalar",
|
|
59
|
-
"doc": "The longest delay a flanger sweep reaches, rounded up to whole ms: the base delay plus the depth maximum. The delay line is sized from it.",
|
|
60
|
-
"unit": "ms",
|
|
61
|
-
"value": {
|
|
62
|
-
"derive": "ceilSum",
|
|
63
|
-
"of": [
|
|
64
|
-
{
|
|
65
|
-
"ref": "FLANGER_BASE_MS"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"ref": "FLANGER_DEPTH_RANGE.max"
|
|
69
|
-
}
|
|
70
|
-
]
|
|
62
|
+
"value": 0.5
|
|
63
|
+
},
|
|
64
|
+
"FLANGER_MAX_MS": {
|
|
65
|
+
"kind": "scalar",
|
|
66
|
+
"doc": "The longest delay a flanger sweep reaches, rounded up to whole ms: the base delay plus the depth maximum. The delay line is sized from it.",
|
|
67
|
+
"unit": "ms",
|
|
68
|
+
"value": {
|
|
69
|
+
"derive": "ceilSum",
|
|
70
|
+
"of": [
|
|
71
|
+
{
|
|
72
|
+
"ref": "FLANGER_BASE_MS"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"ref": "FLANGER_DEPTH_RANGE.max"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
71
79
|
}
|
|
72
80
|
}
|
|
73
81
|
}
|
package/data/kernels/gate.json
CHANGED
|
@@ -1,74 +1,124 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "../../schema/omx-contract.schema.json",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
3
|
+
"controls": [
|
|
4
|
+
{
|
|
5
|
+
"name": "keySource",
|
|
6
|
+
"kind": "choice",
|
|
7
|
+
"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.",
|
|
8
|
+
"ids": [
|
|
9
|
+
"self",
|
|
10
|
+
"sidechain"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "thresholdDb",
|
|
15
|
+
"kind": "travel",
|
|
16
|
+
"table": "GATE_LIMITS",
|
|
17
|
+
"travel": {
|
|
8
18
|
"min": -80,
|
|
9
19
|
"max": 0,
|
|
10
20
|
"step": 1,
|
|
11
21
|
"unit": "dB",
|
|
12
22
|
"default": -40,
|
|
13
23
|
"defaultFrom": "desk"
|
|
14
|
-
}
|
|
15
|
-
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "rangeDb",
|
|
28
|
+
"kind": "travel",
|
|
29
|
+
"table": "GATE_LIMITS",
|
|
30
|
+
"travel": {
|
|
16
31
|
"min": -90,
|
|
17
32
|
"max": 0,
|
|
18
33
|
"step": 1,
|
|
19
34
|
"unit": "dB",
|
|
20
35
|
"default": -90,
|
|
21
36
|
"defaultFrom": "desk"
|
|
22
|
-
}
|
|
23
|
-
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "kneeStartDb",
|
|
41
|
+
"kind": "travel",
|
|
42
|
+
"table": "GATE_LIMITS",
|
|
43
|
+
"travel": {
|
|
24
44
|
"min": -80,
|
|
25
45
|
"max": 0,
|
|
26
46
|
"step": 1,
|
|
27
47
|
"unit": "dB",
|
|
28
48
|
"default": -43,
|
|
29
49
|
"defaultFrom": "desk"
|
|
30
|
-
}
|
|
31
|
-
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "kneeEndDb",
|
|
54
|
+
"kind": "travel",
|
|
55
|
+
"table": "GATE_LIMITS",
|
|
56
|
+
"travel": {
|
|
32
57
|
"min": -80,
|
|
33
58
|
"max": 0,
|
|
34
59
|
"step": 1,
|
|
35
60
|
"unit": "dB",
|
|
36
61
|
"default": -37,
|
|
37
62
|
"defaultFrom": "desk"
|
|
38
|
-
}
|
|
39
|
-
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "attackMs",
|
|
67
|
+
"kind": "travel",
|
|
68
|
+
"table": "GATE_LIMITS",
|
|
69
|
+
"travel": {
|
|
40
70
|
"min": 0,
|
|
41
71
|
"max": 500,
|
|
42
72
|
"step": 0.5,
|
|
43
73
|
"unit": "ms",
|
|
44
74
|
"default": 1,
|
|
45
75
|
"defaultFrom": "desk"
|
|
46
|
-
}
|
|
47
|
-
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "holdMs",
|
|
80
|
+
"kind": "travel",
|
|
81
|
+
"table": "GATE_LIMITS",
|
|
82
|
+
"travel": {
|
|
48
83
|
"min": 0,
|
|
49
84
|
"max": 2000,
|
|
50
85
|
"step": 5,
|
|
51
86
|
"unit": "ms",
|
|
52
87
|
"default": 10,
|
|
53
88
|
"defaultFrom": "desk"
|
|
54
|
-
}
|
|
55
|
-
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "releaseMs",
|
|
93
|
+
"kind": "travel",
|
|
94
|
+
"table": "GATE_LIMITS",
|
|
95
|
+
"travel": {
|
|
56
96
|
"min": 0,
|
|
57
97
|
"max": 5000,
|
|
58
98
|
"step": 10,
|
|
59
99
|
"unit": "ms",
|
|
60
100
|
"default": 100,
|
|
61
101
|
"defaultFrom": "desk"
|
|
62
|
-
}
|
|
63
|
-
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "hysteresisDb",
|
|
106
|
+
"kind": "travel",
|
|
107
|
+
"table": "GATE_LIMITS",
|
|
108
|
+
"travel": {
|
|
64
109
|
"min": 0,
|
|
65
110
|
"max": 24,
|
|
66
111
|
"step": 0.5,
|
|
67
112
|
"unit": "dB",
|
|
68
113
|
"default": 3,
|
|
69
114
|
"defaultFrom": "desk"
|
|
70
|
-
}
|
|
71
|
-
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "ratio",
|
|
119
|
+
"kind": "travel",
|
|
120
|
+
"table": "GATE_LIMITS",
|
|
121
|
+
"travel": {
|
|
72
122
|
"min": 1,
|
|
73
123
|
"max": 100,
|
|
74
124
|
"step": 1,
|
|
@@ -77,13 +127,10 @@
|
|
|
77
127
|
"defaultFrom": "desk"
|
|
78
128
|
}
|
|
79
129
|
}
|
|
80
|
-
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"self",
|
|
86
|
-
"sidechain"
|
|
87
|
-
]
|
|
130
|
+
],
|
|
131
|
+
"tables": {
|
|
132
|
+
"GATE_LIMITS": {
|
|
133
|
+
"doc": "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)."
|
|
134
|
+
}
|
|
88
135
|
}
|
|
89
136
|
}
|