@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
|
@@ -1,101 +1,121 @@
|
|
|
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": "deessFreq",
|
|
6
|
+
"kind": "travel",
|
|
7
|
+
"global": "DEESS_FREQ_RANGE",
|
|
8
|
+
"doc": "The detector band's CENTRE, in Hz. Sibilance lives at 5–10 kHz on most voices; 7 kHz with the default width covers 4 950–9 900 Hz, which is where an \"s\" and a \"t\" sit on a close vocal mic. The travel is wider than the come-up on both sides on purpose: a bright female vocal wants the band up near 9 kHz and a chesty male one down at 5, and a surface narrower than the row removes reach the console genuinely has (the same reasoning core's `REVERB_CUT_RANGE` records).",
|
|
9
|
+
"travel": {
|
|
10
|
+
"min": 2000,
|
|
11
|
+
"max": 16000,
|
|
12
|
+
"step": 10,
|
|
13
|
+
"unit": "Hz",
|
|
14
|
+
"default": 7000,
|
|
15
|
+
"defaultFrom": "desk"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "deessWidth",
|
|
20
|
+
"kind": "travel",
|
|
21
|
+
"global": "DEESS_WIDTH_RANGE",
|
|
22
|
+
"doc": "The band's WIDTH, in OCTAVES around the centre: the edges are `f / 2^(w/2)` and `f · 2^(w/2)`, which is what makes the centre the geometric middle at every width. Octaves and not a Q, because a Q is a property of one section and this band is TWO (a highpass and a lowpass, `mix_deesser.h`) — an operator asked to dial a Q would be dialling a number neither filter carries. One octave is the classic de-esser band: wide enough for a sibilant that moves with the vowel, narrow enough that a 1 kHz vowel sits 27.8 dB down the skirt.",
|
|
23
|
+
"travel": {
|
|
24
|
+
"min": 0.25,
|
|
25
|
+
"max": 4,
|
|
26
|
+
"step": 0.05,
|
|
27
|
+
"unit": "oct",
|
|
28
|
+
"default": 1,
|
|
29
|
+
"defaultFrom": "desk"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "deessThreshold",
|
|
34
|
+
"kind": "travel",
|
|
35
|
+
"global": "DEESS_THRESHOLD_RANGE",
|
|
36
|
+
"doc": "Where reduction starts — the level of the BAND, not of the strip, which is why the come-up is so much lower than the compressor's. A vocal peaking −12 dBFS carries roughly −30 dBFS in a one-octave band at 7 kHz on its sibilants and under −40 on its vowels, so −30 sits between the two and the stage opens on an \"s\" and stays shut on an \"ah\".",
|
|
37
|
+
"travel": {
|
|
38
|
+
"min": -60,
|
|
39
|
+
"max": 0,
|
|
40
|
+
"step": 0.5,
|
|
41
|
+
"unit": "dB",
|
|
42
|
+
"default": -30,
|
|
43
|
+
"defaultFrom": "desk"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "deessRatio",
|
|
48
|
+
"kind": "travel",
|
|
49
|
+
"global": "DEESS_RATIO_RANGE",
|
|
50
|
+
"doc": "How hard the band is held once it is over the threshold. 4:1 is the textbook de-esser ratio: firm on the \"s\", short of a limiter.",
|
|
51
|
+
"travel": {
|
|
52
|
+
"min": 1,
|
|
53
|
+
"max": 20,
|
|
54
|
+
"step": 0.1,
|
|
55
|
+
"unit": "",
|
|
56
|
+
"default": 4,
|
|
57
|
+
"defaultFrom": "desk"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "deessRange",
|
|
62
|
+
"kind": "travel",
|
|
63
|
+
"global": "DEESS_RANGE_RANGE",
|
|
64
|
+
"doc": "The FLOOR on the reduction, in dB and never positive — the deepest cut the stage may reach however loud the sibilant is (`mix_deesser.h`'s clamp, §4c). 12 dB tames a hard sibilant; past that a voice starts to lisp, and a de-esser with NO floor turns a shouted \"s\" into a hole. The ceiling is 0, which switches the reduction off without switching the stage off — a legitimate thing to want while dialling the band in by ear.",
|
|
65
|
+
"travel": {
|
|
66
|
+
"min": -24,
|
|
67
|
+
"max": 0,
|
|
68
|
+
"step": 0.5,
|
|
69
|
+
"unit": "dB",
|
|
70
|
+
"default": -12,
|
|
71
|
+
"defaultFrom": "desk"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "deessAttack",
|
|
76
|
+
"kind": "travel",
|
|
77
|
+
"global": "DEESS_ATTACK_RANGE",
|
|
78
|
+
"doc": "The detector's ATTACK, in ms. A sibilant's onset is a few milliseconds; 1 ms catches it without the detector chattering on the band's own waveform.",
|
|
79
|
+
"travel": {
|
|
80
|
+
"min": 0.1,
|
|
81
|
+
"max": 50,
|
|
82
|
+
"step": 0.1,
|
|
83
|
+
"unit": "ms",
|
|
84
|
+
"default": 1,
|
|
85
|
+
"defaultFrom": "desk"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "deessRelease",
|
|
90
|
+
"kind": "travel",
|
|
91
|
+
"global": "DEESS_RELEASE_RANGE",
|
|
92
|
+
"doc": "The detector's RELEASE, in ms. 60 ms is long enough not to modulate inside one \"s\" and short enough to be open again for the next syllable.",
|
|
93
|
+
"travel": {
|
|
94
|
+
"min": 5,
|
|
95
|
+
"max": 500,
|
|
96
|
+
"step": 1,
|
|
97
|
+
"unit": "ms",
|
|
98
|
+
"default": 60,
|
|
99
|
+
"defaultFrom": "desk"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "deessMode",
|
|
104
|
+
"kind": "choice",
|
|
105
|
+
"global": "DEESS_MODES",
|
|
106
|
+
"doc": "The de-esser's modes, in the order of the integer the kernel reads: split attenuates the detected band only, wideband the whole signal while the sibilance lasts.",
|
|
107
|
+
"ids": [
|
|
108
|
+
"split",
|
|
109
|
+
"wideband"
|
|
110
|
+
]
|
|
13
111
|
}
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"min": 0.25,
|
|
20
|
-
"max": 4,
|
|
21
|
-
"step": 0.05,
|
|
22
|
-
"unit": "oct",
|
|
23
|
-
"default": 1,
|
|
24
|
-
"defaultFrom": "desk"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"DEESS_THRESHOLD_RANGE": {
|
|
28
|
-
"kind": "travels",
|
|
29
|
-
"doc": "Where reduction starts — the level of the BAND, not of the strip, which is why the come-up is so much lower than the compressor's. A vocal peaking −12 dBFS carries roughly −30 dBFS in a one-octave band at 7 kHz on its sibilants and under −40 on its vowels, so −30 sits between the two and the stage opens on an \"s\" and stays shut on an \"ah\".",
|
|
30
|
-
"travel": {
|
|
31
|
-
"min": -60,
|
|
32
|
-
"max": 0,
|
|
33
|
-
"step": 0.5,
|
|
34
|
-
"unit": "dB",
|
|
35
|
-
"default": -30,
|
|
36
|
-
"defaultFrom": "desk"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"DEESS_RATIO_RANGE": {
|
|
40
|
-
"kind": "travels",
|
|
41
|
-
"doc": "How hard the band is held once it is over the threshold. 4:1 is the textbook de-esser ratio: firm on the \"s\", short of a limiter.",
|
|
42
|
-
"travel": {
|
|
43
|
-
"min": 1,
|
|
44
|
-
"max": 20,
|
|
45
|
-
"step": 0.1,
|
|
46
|
-
"unit": "",
|
|
47
|
-
"default": 4,
|
|
48
|
-
"defaultFrom": "desk"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"DEESS_RANGE_RANGE": {
|
|
52
|
-
"kind": "travels",
|
|
53
|
-
"doc": "The FLOOR on the reduction, in dB and never positive — the deepest cut the stage may reach however loud the sibilant is (`mix_deesser.h`'s clamp, §4c). 12 dB tames a hard sibilant; past that a voice starts to lisp, and a de-esser with NO floor turns a shouted \"s\" into a hole. The ceiling is 0, which switches the reduction off without switching the stage off — a legitimate thing to want while dialling the band in by ear.",
|
|
54
|
-
"travel": {
|
|
55
|
-
"min": -24,
|
|
56
|
-
"max": 0,
|
|
57
|
-
"step": 0.5,
|
|
112
|
+
],
|
|
113
|
+
"constants": {
|
|
114
|
+
"DEESS_KNEE_DB": {
|
|
115
|
+
"kind": "scalar",
|
|
116
|
+
"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.",
|
|
58
117
|
"unit": "dB",
|
|
59
|
-
"
|
|
60
|
-
"defaultFrom": "desk"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
"DEESS_ATTACK_RANGE": {
|
|
64
|
-
"kind": "travels",
|
|
65
|
-
"doc": "The detector's ATTACK, in ms. A sibilant's onset is a few milliseconds; 1 ms catches it without the detector chattering on the band's own waveform.",
|
|
66
|
-
"travel": {
|
|
67
|
-
"min": 0.1,
|
|
68
|
-
"max": 50,
|
|
69
|
-
"step": 0.1,
|
|
70
|
-
"unit": "ms",
|
|
71
|
-
"default": 1,
|
|
72
|
-
"defaultFrom": "desk"
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"DEESS_RELEASE_RANGE": {
|
|
76
|
-
"kind": "travels",
|
|
77
|
-
"doc": "The detector's RELEASE, in ms. 60 ms is long enough not to modulate inside one \"s\" and short enough to be open again for the next syllable.",
|
|
78
|
-
"travel": {
|
|
79
|
-
"min": 5,
|
|
80
|
-
"max": 500,
|
|
81
|
-
"step": 1,
|
|
82
|
-
"unit": "ms",
|
|
83
|
-
"default": 60,
|
|
84
|
-
"defaultFrom": "desk"
|
|
118
|
+
"value": 6
|
|
85
119
|
}
|
|
86
|
-
},
|
|
87
|
-
"DEESS_KNEE_DB": {
|
|
88
|
-
"kind": "scalar",
|
|
89
|
-
"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.",
|
|
90
|
-
"unit": "dB",
|
|
91
|
-
"value": 6
|
|
92
|
-
},
|
|
93
|
-
"DEESS_MODES": {
|
|
94
|
-
"kind": "set",
|
|
95
|
-
"doc": "The de-esser's modes, in the order of the integer the kernel reads: split attenuates the detected band only, wideband the whole signal while the sibilance lasts.",
|
|
96
|
-
"ids": [
|
|
97
|
-
"split",
|
|
98
|
-
"wideband"
|
|
99
|
-
]
|
|
100
120
|
}
|
|
101
121
|
}
|
package/data/kernels/delay.json
CHANGED
|
@@ -1,66 +1,76 @@
|
|
|
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": "fxDelayTime",
|
|
6
|
+
"kind": "travel",
|
|
7
|
+
"global": "FX_DELAY_TIME_RANGE",
|
|
8
|
+
"doc": "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.",
|
|
9
|
+
"travel": {
|
|
10
|
+
"min": 0,
|
|
11
|
+
"max": 2000,
|
|
12
|
+
"step": 1,
|
|
13
|
+
"unit": "ms",
|
|
14
|
+
"default": 300,
|
|
15
|
+
"defaultFrom": "desk"
|
|
16
|
+
},
|
|
17
|
+
"c": {
|
|
18
|
+
"alias": {
|
|
19
|
+
"fact": "delay",
|
|
20
|
+
"field": "timeMs"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
13
23
|
},
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
{
|
|
25
|
+
"name": "fxDelayFeedback",
|
|
26
|
+
"kind": "travel",
|
|
27
|
+
"global": "FX_DELAY_FEEDBACK_RANGE",
|
|
28
|
+
"doc": "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.",
|
|
29
|
+
"travel": {
|
|
30
|
+
"min": 0,
|
|
31
|
+
"max": 0.99,
|
|
32
|
+
"step": 0,
|
|
33
|
+
"unit": "",
|
|
34
|
+
"default": 0.3,
|
|
35
|
+
"defaultFrom": "desk"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "tone",
|
|
40
|
+
"kind": "travel",
|
|
41
|
+
"doc": "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.",
|
|
42
|
+
"travel": {
|
|
43
|
+
"min": 0,
|
|
44
|
+
"max": 1,
|
|
45
|
+
"step": 0,
|
|
46
|
+
"unit": "",
|
|
47
|
+
"default": 0.3,
|
|
48
|
+
"defaultFrom": "desk"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "mix",
|
|
53
|
+
"kind": "travel",
|
|
54
|
+
"doc": "The FX DELAY's wet/dry — the same split as REVERB_MIX_RANGE, its own declaration.",
|
|
55
|
+
"travel": {
|
|
56
|
+
"min": 0,
|
|
57
|
+
"max": 1,
|
|
58
|
+
"step": 0,
|
|
59
|
+
"unit": "",
|
|
60
|
+
"default": 0.3,
|
|
61
|
+
"defaultFrom": "desk",
|
|
62
|
+
"byKind": {
|
|
63
|
+
"fxReturn": 1
|
|
64
|
+
}
|
|
18
65
|
}
|
|
19
66
|
}
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"min": 0,
|
|
26
|
-
"max": 0.99,
|
|
27
|
-
"step": 0,
|
|
28
|
-
"unit": "",
|
|
29
|
-
"default": 0.3,
|
|
30
|
-
"defaultFrom": "desk"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"DELAY_TONE_RANGE": {
|
|
34
|
-
"kind": "travels",
|
|
35
|
-
"doc": "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.",
|
|
36
|
-
"travel": {
|
|
37
|
-
"min": 0,
|
|
38
|
-
"max": 1,
|
|
39
|
-
"step": 0,
|
|
40
|
-
"unit": "",
|
|
41
|
-
"default": 0.3,
|
|
42
|
-
"defaultFrom": "desk"
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
"DELAY_MIX_RANGE": {
|
|
46
|
-
"kind": "travels",
|
|
47
|
-
"doc": "The FX DELAY's wet/dry — the same split as REVERB_MIX_RANGE, its own declaration.",
|
|
48
|
-
"travel": {
|
|
49
|
-
"min": 0,
|
|
50
|
-
"max": 1,
|
|
51
|
-
"step": 0,
|
|
67
|
+
],
|
|
68
|
+
"constants": {
|
|
69
|
+
"FX_DELAY_PINGPONG_DEFAULT": {
|
|
70
|
+
"kind": "scalar",
|
|
71
|
+
"doc": "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.",
|
|
52
72
|
"unit": "",
|
|
53
|
-
"
|
|
54
|
-
"defaultFrom": "desk",
|
|
55
|
-
"byKind": {
|
|
56
|
-
"fxReturn": 1
|
|
57
|
-
}
|
|
73
|
+
"value": false
|
|
58
74
|
}
|
|
59
|
-
},
|
|
60
|
-
"FX_DELAY_PINGPONG_DEFAULT": {
|
|
61
|
-
"kind": "scalar",
|
|
62
|
-
"doc": "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.",
|
|
63
|
-
"unit": "",
|
|
64
|
-
"value": false
|
|
65
75
|
}
|
|
66
76
|
}
|
package/data/kernels/drive.json
CHANGED
|
@@ -1,122 +1,133 @@
|
|
|
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
|
-
|
|
3
|
+
"controls": [
|
|
4
|
+
{
|
|
5
|
+
"name": "amount",
|
|
6
|
+
"kind": "travel",
|
|
7
|
+
"doc": "The PRE-CURVE gain, in dB. 0 dB is unity into the curve, so a stage switched on at its defaults changes almost nothing — which is what an `on` switch should mean. The ceiling is where every curve is saturating hard on any signal a console carries.",
|
|
8
|
+
"travel": {
|
|
9
|
+
"min": 0,
|
|
10
|
+
"max": 36,
|
|
11
|
+
"step": 0.1,
|
|
12
|
+
"unit": "dB",
|
|
13
|
+
"default": 0,
|
|
14
|
+
"defaultFrom": "desk"
|
|
15
|
+
},
|
|
16
|
+
"c": {
|
|
17
|
+
"alias": {
|
|
18
|
+
"fact": "drive",
|
|
19
|
+
"field": "driveDb"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
22
|
},
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
{
|
|
24
|
+
"name": "character",
|
|
25
|
+
"kind": "travel",
|
|
26
|
+
"doc": "The EVEN/ODD harmonic balance. −1 is pure odd (the curve itself), +1 is pure even, 0 an equal blend — the kernel splits its own distortion residue into an odd and an even half and fades between them, so the two ends are exact rather than approximate (`mix_drive.h`, measured: H2 at −317 dBc at −1, H3 at −118 dBc at +1). Unitless, and signed by construction. NOT NORMALIZED_RANGE: this is a BALANCE with a meaningful centre, and a 0..1 travel would put its centre at 0.5 and its neutral nowhere.",
|
|
27
|
+
"travel": {
|
|
28
|
+
"min": -1,
|
|
29
|
+
"max": 1,
|
|
30
|
+
"step": 0.01,
|
|
31
|
+
"unit": "",
|
|
32
|
+
"default": 0,
|
|
33
|
+
"defaultFrom": "desk"
|
|
34
|
+
},
|
|
35
|
+
"c": {
|
|
36
|
+
"alias": {
|
|
37
|
+
"fact": "drive",
|
|
38
|
+
"field": "character"
|
|
39
|
+
}
|
|
27
40
|
}
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"DRIVE_CHARACTER_RANGE": {
|
|
31
|
-
"kind": "travels",
|
|
32
|
-
"doc": "The EVEN/ODD harmonic balance. −1 is pure odd (the curve itself), +1 is pure even, 0 an equal blend — the kernel splits its own distortion residue into an odd and an even half and fades between them, so the two ends are exact rather than approximate (`mix_drive.h`, measured: H2 at −317 dBc at −1, H3 at −118 dBc at +1). Unitless, and signed by construction. NOT NORMALIZED_RANGE: this is a BALANCE with a meaningful centre, and a 0..1 travel would put its centre at 0.5 and its neutral nowhere.",
|
|
33
|
-
"travel": {
|
|
34
|
-
"min": -1,
|
|
35
|
-
"max": 1,
|
|
36
|
-
"step": 0.01,
|
|
37
|
-
"unit": "",
|
|
38
|
-
"default": 0,
|
|
39
|
-
"defaultFrom": "desk"
|
|
40
41
|
},
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
{
|
|
43
|
+
"name": "bandFreq",
|
|
44
|
+
"kind": "travel",
|
|
45
|
+
"doc": "The band split / tilt corner, in Hz. ONE travel for all three band modes, because the C imposes one constraint on all of them: it is the corner of a single biquad, and the split's other half is `x − LP(x)`. The full audio band, not the channel filters' narrower HPF/LPF pair — the same reasoning REVERB_CUT_RANGE records: a surface narrower than the row removes reach the console genuinely has.",
|
|
46
|
+
"travel": {
|
|
47
|
+
"min": 20,
|
|
48
|
+
"max": 20000,
|
|
49
|
+
"step": 1,
|
|
50
|
+
"unit": "Hz",
|
|
51
|
+
"default": 2000,
|
|
52
|
+
"defaultFrom": "desk"
|
|
53
|
+
},
|
|
54
|
+
"c": {
|
|
55
|
+
"alias": {
|
|
56
|
+
"fact": "drive",
|
|
57
|
+
"field": "bandHz"
|
|
58
|
+
}
|
|
45
59
|
}
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
"DRIVE_BAND_FREQ_RANGE": {
|
|
49
|
-
"kind": "travels",
|
|
50
|
-
"doc": "The band split / tilt corner, in Hz. ONE travel for all three band modes, because the C imposes one constraint on all of them: it is the corner of a single biquad, and the split's other half is `x − LP(x)`. The full audio band, not the channel filters' narrower HPF/LPF pair — the same reasoning REVERB_CUT_RANGE records: a surface narrower than the row removes reach the console genuinely has.",
|
|
51
|
-
"travel": {
|
|
52
|
-
"min": 20,
|
|
53
|
-
"max": 20000,
|
|
54
|
-
"step": 1,
|
|
55
|
-
"unit": "Hz",
|
|
56
|
-
"default": 2000,
|
|
57
|
-
"defaultFrom": "desk"
|
|
58
60
|
},
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
{
|
|
62
|
+
"name": "mix",
|
|
63
|
+
"kind": "travel",
|
|
64
|
+
"doc": "The wet/dry, as a PERCENT — the unit a drive control is read in on every desk that has one. Deliberately not NORMALIZED_RANGE (which is unitless 0..1): a mix a surface must label \"0.35\" when the operator thinks in \"35 %\" is a control whose declaration is fighting its reader. The kernel divides by 100 where it resolves the atom, in one place. The come-up is 100 %, not the reverb's modest 30: a saturator's insert use is IN the path. The `exciter` curve seeds itself lower (DRIVE_EXCITER_SEED), because that is a property of the TOPOLOGY and not of the travel.",
|
|
65
|
+
"travel": {
|
|
66
|
+
"min": 0,
|
|
67
|
+
"max": 100,
|
|
68
|
+
"step": 0.1,
|
|
69
|
+
"unit": "%",
|
|
70
|
+
"default": 100,
|
|
71
|
+
"defaultFrom": "desk"
|
|
72
|
+
},
|
|
73
|
+
"c": {
|
|
74
|
+
"alias": {
|
|
75
|
+
"fact": "drive",
|
|
76
|
+
"field": "mix"
|
|
77
|
+
}
|
|
63
78
|
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
"DRIVE_MIX_RANGE": {
|
|
67
|
-
"kind": "travels",
|
|
68
|
-
"doc": "The wet/dry, as a PERCENT — the unit a drive control is read in on every desk that has one. Deliberately not NORMALIZED_RANGE (which is unitless 0..1): a mix a surface must label \"0.35\" when the operator thinks in \"35 %\" is a control whose declaration is fighting its reader. The kernel divides by 100 where it resolves the atom, in one place. The come-up is 100 %, not the reverb's modest 30: a saturator's insert use is IN the path. The `exciter` curve seeds itself lower (DRIVE_EXCITER_SEED), because that is a property of the TOPOLOGY and not of the travel.",
|
|
69
|
-
"travel": {
|
|
70
|
-
"min": 0,
|
|
71
|
-
"max": 100,
|
|
72
|
-
"step": 0.1,
|
|
73
|
-
"unit": "%",
|
|
74
|
-
"default": 100,
|
|
75
|
-
"defaultFrom": "desk"
|
|
76
79
|
},
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
{
|
|
81
|
+
"name": "trim",
|
|
82
|
+
"kind": "travel",
|
|
83
|
+
"doc": "The POST-stage make-up, in dB. Symmetric enough either way that an operator can null the stage in and out against the bypass, which is how a colour stage is actually judged.",
|
|
84
|
+
"travel": {
|
|
85
|
+
"min": -24,
|
|
86
|
+
"max": 12,
|
|
87
|
+
"step": 0.1,
|
|
88
|
+
"unit": "dB",
|
|
89
|
+
"default": 0,
|
|
90
|
+
"defaultFrom": "desk"
|
|
91
|
+
},
|
|
92
|
+
"c": {
|
|
93
|
+
"alias": {
|
|
94
|
+
"fact": "drive",
|
|
95
|
+
"field": "trimDb"
|
|
96
|
+
}
|
|
81
97
|
}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
"DRIVE_TRIM_RANGE": {
|
|
85
|
-
"kind": "travels",
|
|
86
|
-
"doc": "The POST-stage make-up, in dB. Symmetric enough either way that an operator can null the stage in and out against the bypass, which is how a colour stage is actually judged.",
|
|
87
|
-
"travel": {
|
|
88
|
-
"min": -24,
|
|
89
|
-
"max": 12,
|
|
90
|
-
"step": 0.1,
|
|
91
|
-
"unit": "dB",
|
|
92
|
-
"default": 0,
|
|
93
|
-
"defaultFrom": "desk"
|
|
94
98
|
},
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
{
|
|
100
|
+
"name": "curve",
|
|
101
|
+
"kind": "choice",
|
|
102
|
+
"doc": "The drive's shaper curves, in the order of the integer the kernel reads. Exciter runs the soft shape in a parallel-sum topology.",
|
|
103
|
+
"ids": [
|
|
104
|
+
"soft",
|
|
105
|
+
"tape",
|
|
106
|
+
"tube",
|
|
107
|
+
"exciter"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "band",
|
|
112
|
+
"kind": "choice",
|
|
113
|
+
"doc": "Which part of the spectrum the drive's curve is fed, in the order of the integer the kernel reads. The split is complementary, so mix 0 stays bit-identical to the dry signal.",
|
|
114
|
+
"ids": [
|
|
115
|
+
"full",
|
|
116
|
+
"low",
|
|
117
|
+
"high",
|
|
118
|
+
"tilt"
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"constants": {
|
|
123
|
+
"DRIVE_BIAS_MAX": {
|
|
124
|
+
"kind": "scalar",
|
|
125
|
+
"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.",
|
|
126
|
+
"unit": "",
|
|
127
|
+
"value": {
|
|
128
|
+
"derive": "sqrt",
|
|
129
|
+
"of": 0.5
|
|
99
130
|
}
|
|
100
131
|
}
|
|
101
|
-
},
|
|
102
|
-
"DRIVE_CURVES": {
|
|
103
|
-
"kind": "set",
|
|
104
|
-
"doc": "The drive's shaper curves, in the order of the integer the kernel reads. Exciter runs the soft shape in a parallel-sum topology.",
|
|
105
|
-
"ids": [
|
|
106
|
-
"soft",
|
|
107
|
-
"tape",
|
|
108
|
-
"tube",
|
|
109
|
-
"exciter"
|
|
110
|
-
]
|
|
111
|
-
},
|
|
112
|
-
"DRIVE_BANDS": {
|
|
113
|
-
"kind": "set",
|
|
114
|
-
"doc": "Which part of the spectrum the drive's curve is fed, in the order of the integer the kernel reads. The split is complementary, so mix 0 stays bit-identical to the dry signal.",
|
|
115
|
-
"ids": [
|
|
116
|
-
"full",
|
|
117
|
-
"low",
|
|
118
|
-
"high",
|
|
119
|
-
"tilt"
|
|
120
|
-
]
|
|
121
132
|
}
|
|
122
133
|
}
|