@openmixer/omx-contract 2.11.0 → 2.12.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 +2 -2
- package/bin/omx-contract.mjs +1 -1
- package/data/hosting.json +93 -0
- package/data/kernels/chorus.json +5 -5
- package/data/kernels/comp.json +2 -2
- package/data/kernels/deesser.json +1 -1
- package/data/kernels/delay.json +1 -1
- package/data/kernels/drive.json +3 -3
- package/data/kernels/eq.json +1 -1
- package/data/kernels/fbs.json +5 -5
- package/data/kernels/flanger.json +4 -4
- package/data/kernels/geq.json +4 -4
- package/data/kernels/hrp.json +5 -5
- package/data/kernels/mixmatrix.json +1 -1
- package/data/kernels/phaser.json +7 -7
- package/data/kernels/pitch.json +12 -3
- package/data/kernels/rotary.json +1 -1
- package/data/kernels/transient.json +5 -5
- package/data/primitives.json +1 -1
- package/dist/ts/omx-contract.d.ts +124 -46
- package/dist/ts/omx-contract.js +127 -49
- package/include/omxcontract/clap_host_limits.h +66 -0
- package/include/omxcontract/omx_contract_limits.h +20 -0
- package/lib/data.mjs +3 -1
- package/lib/fmt.mjs +3 -2
- package/lib/semver.mjs +11 -3
- package/lib/validate.mjs +21 -1
- package/package.json +1 -1
- package/render/c/clap-host-limits.mjs +78 -0
- package/render/c.mjs +10 -5
- package/render/ts.mjs +1 -1
- package/schema/omx-contract.schema.json +38 -4
- package/share/omx-contract/omx-contract.json +149 -50
|
@@ -1,7 +1,97 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmixer/omx-contract",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"items": {
|
|
5
|
+
"HOSTED_STAGE_LIMITS": {
|
|
6
|
+
"rel": "data/hosting.json",
|
|
7
|
+
"kind": "sheet",
|
|
8
|
+
"doc": "The numbers a hosted plugin's stage limits itself to: the warm-up before it is published, the blocks of non-finite output that strike it, the level its output is clamped at, the parameter queue and the events one block delivers, the polls and timeouts of the hand-over between threads, the ports the core accepts and the caps on a plugin's state, log and parameter count. These are the stage's safety numbers, not an operator's travel.",
|
|
9
|
+
"docs": {
|
|
10
|
+
"warmupLevelDbfs": "the level of the warm-up signal, in dBFS",
|
|
11
|
+
"nonFiniteStrikes": "the blocks of non-finite output that strike a stage",
|
|
12
|
+
"clampDbfs": "the level the output is clamped at, in dBFS",
|
|
13
|
+
"paramQueueDepth": "the records the parameter queue holds",
|
|
14
|
+
"eventsPerBlock": "the parameter events delivered in one block",
|
|
15
|
+
"unpublishPollUs": "the poll interval while an unpublish waits for the audio thread, in microseconds",
|
|
16
|
+
"unpublishTimeoutUs": "the longest an unpublish waits for the audio thread, in microseconds",
|
|
17
|
+
"workerPollUs": "how often an LV2 instance's worker thread polls its request ring, in microseconds",
|
|
18
|
+
"workerRingBytes": "the bytes of each of an LV2 instance's two worker rings; a power of two, 16 or more",
|
|
19
|
+
"notesPerBlock": "the note events delivered in one block",
|
|
20
|
+
"mainPortChannels": "the channels the main port is limited to",
|
|
21
|
+
"auxOutputs": "the auxiliary output ports the core accepts",
|
|
22
|
+
"auxInputs": "the auxiliary input ports (side chains) the core accepts",
|
|
23
|
+
"stateMaxBytes": "the largest plugin state the core saves or loads, in bytes",
|
|
24
|
+
"logBytes": "the size of a plugin log message, in bytes",
|
|
25
|
+
"rolePollUs": "the poll interval while the audio role is taken, in microseconds",
|
|
26
|
+
"roleTimeoutUs": "the longest the audio role is waited for, in microseconds",
|
|
27
|
+
"paramCountMax": "the widest parameter count the core trusts",
|
|
28
|
+
"latencyHoldMs": "the hold before a hosted stage's new latency takes effect, in milliseconds"
|
|
29
|
+
},
|
|
30
|
+
"value": {
|
|
31
|
+
"warmupBlocks": 64,
|
|
32
|
+
"warmupLevelDbfs": -6,
|
|
33
|
+
"nonFiniteStrikes": 3,
|
|
34
|
+
"clampDbfs": 24,
|
|
35
|
+
"paramQueueDepth": 256,
|
|
36
|
+
"eventsPerBlock": 64,
|
|
37
|
+
"unpublishPollUs": 100,
|
|
38
|
+
"unpublishTimeoutUs": 2000000,
|
|
39
|
+
"workerPollUs": 1000,
|
|
40
|
+
"workerRingBytes": 16384,
|
|
41
|
+
"notesPerBlock": 256,
|
|
42
|
+
"mainPortChannels": 2,
|
|
43
|
+
"auxOutputs": 8,
|
|
44
|
+
"auxInputs": 8,
|
|
45
|
+
"stateMaxBytes": 1048576,
|
|
46
|
+
"logBytes": 256,
|
|
47
|
+
"rolePollUs": 1000,
|
|
48
|
+
"roleTimeoutUs": 200000,
|
|
49
|
+
"paramCountMax": 2048,
|
|
50
|
+
"latencyHoldMs": 250
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"HOSTING_CODES": {
|
|
54
|
+
"rel": "data/hosting.json",
|
|
55
|
+
"kind": "codes",
|
|
56
|
+
"doc": "The refusals the CLAP core returns, by the hosting code a verdict names them by. A code is never reworded.",
|
|
57
|
+
"value": {
|
|
58
|
+
"headlessFailed": {
|
|
59
|
+
"code": "hosting.clap.headless-failed"
|
|
60
|
+
},
|
|
61
|
+
"notAudioEffect": {
|
|
62
|
+
"code": "hosting.clap.not-audio-effect",
|
|
63
|
+
"doc": "the plugin is not an audio effect"
|
|
64
|
+
},
|
|
65
|
+
"noteInput": {
|
|
66
|
+
"code": "hosting.clap.note-input",
|
|
67
|
+
"doc": "the plugin declares a note input the configuration refuses"
|
|
68
|
+
},
|
|
69
|
+
"noAudioInput": {
|
|
70
|
+
"code": "hosting.topology.no-audio-input",
|
|
71
|
+
"doc": "the plugin has no audio input"
|
|
72
|
+
},
|
|
73
|
+
"noAudioOutput": {
|
|
74
|
+
"code": "hosting.topology.no-audio-output",
|
|
75
|
+
"doc": "the plugin has no audio output"
|
|
76
|
+
},
|
|
77
|
+
"widerThanStrip": {
|
|
78
|
+
"code": "hosting.topology.wider-than-strip",
|
|
79
|
+
"doc": "the plugin is wider than the strip"
|
|
80
|
+
},
|
|
81
|
+
"extraInputs": {
|
|
82
|
+
"code": "hosting.topology.extra-inputs-fed-silence",
|
|
83
|
+
"doc": "the plugin has extra inputs, fed silence"
|
|
84
|
+
},
|
|
85
|
+
"crashedLive": {
|
|
86
|
+
"code": "hosting.stability.crashed-live-on-this-rig",
|
|
87
|
+
"doc": "the plugin crashed live on this rig"
|
|
88
|
+
},
|
|
89
|
+
"outputNonFinite": {
|
|
90
|
+
"code": "hosting.output.non-finite",
|
|
91
|
+
"doc": "the plugin produced non-finite output"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
5
95
|
"PAN_RANGE": {
|
|
6
96
|
"rel": "data/kernels/balance.json",
|
|
7
97
|
"kind": "travels",
|
|
@@ -124,7 +214,7 @@
|
|
|
124
214
|
"CHORUS_SPREAD_RANGE": {
|
|
125
215
|
"rel": "data/kernels/chorus.json",
|
|
126
216
|
"kind": "travels",
|
|
127
|
-
"doc": "The chorus's right-leg phase offset, in TURNS of its one oscillator
|
|
217
|
+
"doc": "The chorus's right-leg phase offset, in TURNS of its one oscillator. 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 ''.",
|
|
128
218
|
"shape": "travel",
|
|
129
219
|
"value": {
|
|
130
220
|
"min": 0,
|
|
@@ -138,7 +228,7 @@
|
|
|
138
228
|
"CHORUS_RATE_RANGE": {
|
|
139
229
|
"rel": "data/kernels/chorus.json",
|
|
140
230
|
"kind": "travels",
|
|
141
|
-
"doc": "The chorus sweep's speed
|
|
231
|
+
"doc": "The chorus sweep's speed. Above ~3 Hz it stops being a chorus and becomes a vibrato.",
|
|
142
232
|
"shape": "travel",
|
|
143
233
|
"value": {
|
|
144
234
|
"min": 0.05,
|
|
@@ -152,7 +242,7 @@
|
|
|
152
242
|
"CHORUS_DEPTH_RANGE": {
|
|
153
243
|
"rel": "data/kernels/chorus.json",
|
|
154
244
|
"kind": "travels",
|
|
155
|
-
"doc": "The chorus's peak-to-peak excursion above its declared 10 ms base
|
|
245
|
+
"doc": "The chorus's peak-to-peak excursion above its declared 10 ms base.",
|
|
156
246
|
"shape": "travel",
|
|
157
247
|
"value": {
|
|
158
248
|
"min": 0,
|
|
@@ -166,7 +256,7 @@
|
|
|
166
256
|
"CHORUS_VOICES_RANGE": {
|
|
167
257
|
"rel": "data/kernels/chorus.json",
|
|
168
258
|
"kind": "travels",
|
|
169
|
-
"doc": "The chorus's tap count — one oscillator read at k/N
|
|
259
|
+
"doc": "The chorus's tap count — one oscillator read at k/N.",
|
|
170
260
|
"shape": "travel",
|
|
171
261
|
"value": {
|
|
172
262
|
"min": 1,
|
|
@@ -180,7 +270,7 @@
|
|
|
180
270
|
"CHORUS_MIX_RANGE": {
|
|
181
271
|
"rel": "data/kernels/chorus.json",
|
|
182
272
|
"kind": "travels",
|
|
183
|
-
"doc": "The chorus's wet/dry, as an instance of DRIVE_MIX_RANGE — the same percent travel, its own come-up value: 35 %, a colour under the dry on a strip
|
|
273
|
+
"doc": "The chorus's wet/dry, as an instance of DRIVE_MIX_RANGE — the same percent travel, its own come-up value: 35 %, a colour under the dry on a strip. The REVERB_LOWCUT_RANGE-over- REVERB_CUT_RANGE shape: one travel, one declared default per field that reads it.",
|
|
184
274
|
"shape": "travel",
|
|
185
275
|
"value": {
|
|
186
276
|
"min": 0,
|
|
@@ -302,7 +392,7 @@
|
|
|
302
392
|
"DETECTOR_TOPOLOGY": {
|
|
303
393
|
"rel": "data/kernels/comp.json",
|
|
304
394
|
"kind": "set",
|
|
305
|
-
"doc": "Where the compressor's detector listens: `feedforward` hears the slot's input (or its key), `feedback` hears the slot's own pre-make-up output DYN_FB_LOOP_DELAY_SAMPLES late, through one envelope stage, and a keyed slot stays feed-forward (omx-dsp's OMX_DYN_TOPOLOGY_FEEDFORWARD 0 and _FEEDBACK 1, in that order; the set is named for its control, so C spells them OMX_DETECTOR_TOPOLOGY_*). The console's comp row carries it (`detectorTopology
|
|
395
|
+
"doc": "Where the compressor's detector listens: `feedforward` hears the slot's input (or its key), `feedback` hears the slot's own pre-make-up output DYN_FB_LOOP_DELAY_SAMPLES late, through one envelope stage, and a keyed slot stays feed-forward (omx-dsp's OMX_DYN_TOPOLOGY_FEEDFORWARD 0 and _FEEDBACK 1, in that order; the set is named for its control, so C spells them OMX_DETECTOR_TOPOLOGY_*). The console's comp row carries it (`detectorTopology`) and comes up `feedforward`, so a zeroed atom is the compressor every slot runs.",
|
|
306
396
|
"default": "feedforward",
|
|
307
397
|
"value": [
|
|
308
398
|
"feedforward",
|
|
@@ -312,7 +402,7 @@
|
|
|
312
402
|
"PROGRAM_RELEASE": {
|
|
313
403
|
"rel": "data/kernels/comp.json",
|
|
314
404
|
"kind": "sheet",
|
|
315
|
-
"doc": "The program-dependent release's model constants — the LA-2A's opto cell as DATA
|
|
405
|
+
"doc": "The program-dependent release's model constants — the LA-2A's opto cell as DATA. `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.",
|
|
316
406
|
"value": {
|
|
317
407
|
"chargeMs": 1000,
|
|
318
408
|
"dischargeMs": 5000,
|
|
@@ -392,7 +482,7 @@
|
|
|
392
482
|
"DEESS_RANGE_RANGE": {
|
|
393
483
|
"rel": "data/kernels/deesser.json",
|
|
394
484
|
"kind": "travels",
|
|
395
|
-
"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
|
|
485
|
+
"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). 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.",
|
|
396
486
|
"shape": "travel",
|
|
397
487
|
"value": {
|
|
398
488
|
"min": -24,
|
|
@@ -529,7 +619,7 @@
|
|
|
529
619
|
"FX_DELAY_PINGPONG_DEFAULT": {
|
|
530
620
|
"rel": "data/kernels/delay.json",
|
|
531
621
|
"kind": "scalar",
|
|
532
|
-
"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 console's delay default state (which now reads it) so the DPF plugin generator (omx-plugins
|
|
622
|
+
"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 console's delay default state (which now reads it) so the DPF plugin generator (omx-plugins) reads the same fact the desk seeds a fresh strip with.",
|
|
533
623
|
"unit": "",
|
|
534
624
|
"value": false
|
|
535
625
|
},
|
|
@@ -658,7 +748,7 @@
|
|
|
658
748
|
"DRIVE_AUTO_GAINS": {
|
|
659
749
|
"rel": "data/kernels/drive.json",
|
|
660
750
|
"kind": "set",
|
|
661
|
-
"doc": "The drive's AUTO-GAIN switch: on, the stage measures its own level change and matches it out (`omx_drive.h`'s `struct omx_drive.auto_gain
|
|
751
|
+
"doc": "The drive's AUTO-GAIN switch: on, the stage measures its own level change and matches it out (`omx_drive.h`'s `struct omx_drive.auto_gain`), so turning the drive up adds colour rather than loudness. A field of the console's drive row (`DriveState.autoGain`), on at come-up there and in omx-dsp's drive face.",
|
|
662
752
|
"default": "on",
|
|
663
753
|
"labels": [
|
|
664
754
|
"Off",
|
|
@@ -672,7 +762,7 @@
|
|
|
672
762
|
"DRIVE_STEREO_LINKS": {
|
|
673
763
|
"rel": "data/kernels/drive.json",
|
|
674
764
|
"kind": "set",
|
|
675
|
-
"doc": "The drive's STEREO LINK switch: on, ONE auto-gain path is driven by both legs' summed energy, so the image cannot shift under the level match; off, each leg matches its own (`omx_drive.h`'s `struct omx_drive.stereo_link
|
|
765
|
+
"doc": "The drive's STEREO LINK switch: on, ONE auto-gain path is driven by both legs' summed energy, so the image cannot shift under the level match; off, each leg matches its own (`omx_drive.h`'s `struct omx_drive.stereo_link`). A field of the console's drive row (`DriveState.stereoLink`), on at come-up there and in omx-dsp's drive face.",
|
|
676
766
|
"default": "on",
|
|
677
767
|
"labels": [
|
|
678
768
|
"Off",
|
|
@@ -724,7 +814,7 @@
|
|
|
724
814
|
"DRIVE_BIAS_MAX": {
|
|
725
815
|
"rel": "data/kernels/drive.json",
|
|
726
816
|
"kind": "scalar",
|
|
727
|
-
"doc": "The bias at `character = +1`, in the SHAPER's own input units — `OMX_DRIVE_BIAS_MAX`. DERIVED, not chosen
|
|
817
|
+
"doc": "The bias at `character = +1`, in the SHAPER's own input units — `OMX_DRIVE_BIAS_MAX`. DERIVED, not chosen. 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.",
|
|
728
818
|
"unit": "",
|
|
729
819
|
"value": 0.7071067811865476
|
|
730
820
|
},
|
|
@@ -923,7 +1013,7 @@
|
|
|
923
1013
|
"GEQ_BANDS": {
|
|
924
1014
|
"rel": "data/kernels/eq.json",
|
|
925
1015
|
"kind": "scalar",
|
|
926
|
-
"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 (
|
|
1016
|
+
"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 (roster ruling 3).",
|
|
927
1017
|
"unit": "",
|
|
928
1018
|
"value": 31
|
|
929
1019
|
},
|
|
@@ -1140,7 +1230,7 @@
|
|
|
1140
1230
|
"GROWTH_MIN_DB_PER_FRAME": {
|
|
1141
1231
|
"rel": "data/kernels/fbs.json",
|
|
1142
1232
|
"kind": "scalar",
|
|
1143
|
-
"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.
|
|
1233
|
+
"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. The 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.",
|
|
1144
1234
|
"unit": "dB",
|
|
1145
1235
|
"value": 0.8
|
|
1146
1236
|
},
|
|
@@ -1154,21 +1244,21 @@
|
|
|
1154
1244
|
"GROWTH_MIN_TOTAL_RISE_DB": {
|
|
1155
1245
|
"rel": "data/kernels/fbs.json",
|
|
1156
1246
|
"kind": "scalar",
|
|
1157
|
-
"doc": "Minimum END-TO-END rise (dB) across the window. The live-music corpus
|
|
1247
|
+
"doc": "Minimum END-TO-END rise (dB) across the window. The live-music corpus 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.",
|
|
1158
1248
|
"unit": "dB",
|
|
1159
1249
|
"value": 6
|
|
1160
1250
|
},
|
|
1161
1251
|
"GROWTH_MAX_SINGLE_FRAME_SHARE": {
|
|
1162
1252
|
"rel": "data/kernels/fbs.json",
|
|
1163
1253
|
"kind": "scalar",
|
|
1164
|
-
"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
|
|
1254
|
+
"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 the 72 live false positives of the live-music corpus). 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.",
|
|
1165
1255
|
"unit": "",
|
|
1166
1256
|
"value": 0.5
|
|
1167
1257
|
},
|
|
1168
1258
|
"GROWTH_CONFIRM_FRAMES": {
|
|
1169
1259
|
"rel": "data/kernels/fbs.json",
|
|
1170
1260
|
"kind": "scalar",
|
|
1171
|
-
"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
|
|
1261
|
+
"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: 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.",
|
|
1172
1262
|
"unit": "",
|
|
1173
1263
|
"value": 2
|
|
1174
1264
|
},
|
|
@@ -1193,7 +1283,7 @@
|
|
|
1193
1283
|
"FBS_MAX_NOTCH_DEPTH_DB": {
|
|
1194
1284
|
"rel": "data/kernels/fbs.json",
|
|
1195
1285
|
"kind": "scalar",
|
|
1196
|
-
"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 (the room-analysis design
|
|
1286
|
+
"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 (the room-analysis design — \"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.",
|
|
1197
1287
|
"unit": "dB",
|
|
1198
1288
|
"value": 18
|
|
1199
1289
|
},
|
|
@@ -1214,7 +1304,7 @@
|
|
|
1214
1304
|
"FLANGER_RATE_RANGE": {
|
|
1215
1305
|
"rel": "data/kernels/flanger.json",
|
|
1216
1306
|
"kind": "travels",
|
|
1217
|
-
"doc": "The flanger's jet sweep
|
|
1307
|
+
"doc": "The flanger's jet sweep.",
|
|
1218
1308
|
"shape": "travel",
|
|
1219
1309
|
"value": {
|
|
1220
1310
|
"min": 0.05,
|
|
@@ -1228,7 +1318,7 @@
|
|
|
1228
1318
|
"FLANGER_DEPTH_RANGE": {
|
|
1229
1319
|
"rel": "data/kernels/flanger.json",
|
|
1230
1320
|
"kind": "travels",
|
|
1231
|
-
"doc": "The flanger's peak-to-peak excursion above its declared 0.5 ms base
|
|
1321
|
+
"doc": "The flanger's peak-to-peak excursion above its declared 0.5 ms base.",
|
|
1232
1322
|
"shape": "travel",
|
|
1233
1323
|
"value": {
|
|
1234
1324
|
"min": 0,
|
|
@@ -1242,7 +1332,7 @@
|
|
|
1242
1332
|
"FLANGER_FEEDBACK_RANGE": {
|
|
1243
1333
|
"rel": "data/kernels/flanger.json",
|
|
1244
1334
|
"kind": "travels",
|
|
1245
|
-
"doc": "The flanger's SIGNED resonance
|
|
1335
|
+
"doc": "The flanger's SIGNED resonance. 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.",
|
|
1246
1336
|
"shape": "travel",
|
|
1247
1337
|
"value": {
|
|
1248
1338
|
"min": -0.95,
|
|
@@ -1256,7 +1346,7 @@
|
|
|
1256
1346
|
"FLANGER_MIX_RANGE": {
|
|
1257
1347
|
"rel": "data/kernels/flanger.json",
|
|
1258
1348
|
"kind": "travels",
|
|
1259
|
-
"doc": "The flanger's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, equal dry and wet, where the comb is deepest
|
|
1349
|
+
"doc": "The flanger's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, equal dry and wet, where the comb is deepest.",
|
|
1260
1350
|
"shape": "travel",
|
|
1261
1351
|
"value": {
|
|
1262
1352
|
"min": 0,
|
|
@@ -1414,7 +1504,7 @@
|
|
|
1414
1504
|
"GEQ_BAND_RANGE": {
|
|
1415
1505
|
"rel": "data/kernels/geq.json",
|
|
1416
1506
|
"kind": "travels",
|
|
1417
|
-
"doc": "One graphic-EQ fader's travel: EQ_GAIN_RANGE by reference (a graphic fader is an EQ gain), with the come-up value it needs as a row field — flat, 0 dB
|
|
1507
|
+
"doc": "One graphic-EQ fader's travel: EQ_GAIN_RANGE by reference (a graphic fader is an EQ gain), with the come-up value it needs as a row field — flat, 0 dB.",
|
|
1418
1508
|
"shape": "travel",
|
|
1419
1509
|
"value": {
|
|
1420
1510
|
"min": -15,
|
|
@@ -1428,21 +1518,21 @@
|
|
|
1428
1518
|
"GEQ_BAND_Q": {
|
|
1429
1519
|
"rel": "data/kernels/geq.json",
|
|
1430
1520
|
"kind": "scalar",
|
|
1431
|
-
"doc": "The graphic EQ's band Q: the ISO third-octave bandwidth, `2^(1/6)/(2^(1/3) − 1) ≈ 4.318`, to one decimal as the M32 GEQ carries it. Read by the `geq31` preset and the graphic EQ's section design
|
|
1521
|
+
"doc": "The graphic EQ's band Q: the ISO third-octave bandwidth, `2^(1/6)/(2^(1/3) − 1) ≈ 4.318`, to one decimal as the M32 GEQ carries it. Read by the `geq31` preset and the graphic EQ's section design.",
|
|
1432
1522
|
"unit": "",
|
|
1433
1523
|
"value": 4.3
|
|
1434
1524
|
},
|
|
1435
1525
|
"GEQ_PROTO_DB": {
|
|
1436
1526
|
"rel": "data/kernels/geq.json",
|
|
1437
1527
|
"kind": "scalar",
|
|
1438
|
-
"doc": "The prototype gain the `true` solve's first interaction matrix is evaluated at
|
|
1528
|
+
"doc": "The prototype gain the `true` solve's first interaction matrix is evaluated at: the middle of the travel's magnitude, where a matched-Z section's dB response per dB of gain is closest to its average.",
|
|
1439
1529
|
"unit": "dB",
|
|
1440
1530
|
"value": 12
|
|
1441
1531
|
},
|
|
1442
1532
|
"GEQ_DESIGN_GAIN_MAX_DB": {
|
|
1443
1533
|
"rel": "data/kernels/geq.json",
|
|
1444
1534
|
"kind": "scalar",
|
|
1445
|
-
"doc": "The ceiling on a section gain the `true` solve may ask for
|
|
1535
|
+
"doc": "The ceiling on a section gain the `true` solve may ask for: above the travel's worst case (26.0 dB, the alternating ±15 set) with margin. A solve past it clamps and the row says so (`designClamped`), never silently.",
|
|
1446
1536
|
"unit": "dB",
|
|
1447
1537
|
"value": 30
|
|
1448
1538
|
},
|
|
@@ -1484,35 +1574,35 @@
|
|
|
1484
1574
|
"HRP_EXCESS_THRESHOLD_DB": {
|
|
1485
1575
|
"rel": "data/kernels/hrp.json",
|
|
1486
1576
|
"kind": "scalar",
|
|
1487
|
-
"doc": "How far a partial must stand above its LEARNED BASELINE before HRP calls it a resonance (increment 8
|
|
1577
|
+
"doc": "How far a partial must stand above its LEARNED BASELINE before HRP calls it a resonance (increment 8: `deviation = measured − baseline[note][harmonic]`). A partial level tells you nothing on its own; what marks a resonance is a partial louder than THIS instrument normally measures at THIS note. Three decibels is the same order as the feedback detector's peak-to-neighbour gate and for the same reason: below it, an ordinary performance's variation — a bow dug in, a verse sung harder — would be flattened, and flattening expression is not correcting a room. (Before the learned model existed this same threshold gated the placeholder neighbour rule; the number and its reasoning carried over.)",
|
|
1488
1578
|
"unit": "dB",
|
|
1489
1579
|
"value": 3
|
|
1490
1580
|
},
|
|
1491
1581
|
"HRP_GAIN_STEP_DB": {
|
|
1492
1582
|
"rel": "data/kernels/hrp.json",
|
|
1493
1583
|
"kind": "scalar",
|
|
1494
|
-
"doc": "How far ONE reconcile pass may move an HRP band's gain, in dB —
|
|
1584
|
+
"doc": "How far ONE reconcile pass may move an HRP band's gain, in dB — the gain smoothing, done at the control level because the native cascade applies pushed coefficients verbatim and the design forbids interpolating there. An unbounded gain step is a waveform discontinuity — the click heard when a correction entered or left at full depth (found live, 2026-08-20, the evening increment 9 raised the enter/leave rate). Bounded, a correction ENTERS by deepening from silence and LEAVES by walking to exactly 0 dB — the provable parked identity (`eqBandIsIdentity`) — from which removal is bit-identical. Two decibels per pass at the corrector's 10 Hz cadence walks the full HRP_MAX_CUT_DB travel in ~300 ms: the same order as the tracker's stability hold and FBS's lift steps, while each individual move stays below audibility on a Q-5 bell.",
|
|
1495
1585
|
"unit": "dB",
|
|
1496
1586
|
"value": 2
|
|
1497
1587
|
},
|
|
1498
1588
|
"HRP_COLLISION_CENTS": {
|
|
1499
1589
|
"rel": "data/kernels/hrp.json",
|
|
1500
1590
|
"kind": "scalar",
|
|
1501
|
-
"doc": "How close two correction candidates must sit, in cents, to count as the SAME spectral region
|
|
1591
|
+
"doc": "How close two correction candidates must sit, in cents, to count as the SAME spectral region: within it, the stronger candidate is selected and the weaker discarded rather than two near-identical filters being planted. One semitone, and the number follows from HRP_BAND_Q: a Q-5 bell's −3 dB half-width is ~170 cents, so two cuts a semitone apart overlap over most of their travel — the second one deepens the first far more than it shapes anything of its own. The design makes the threshold configurable and tested: declared once here, a parameter everywhere below.",
|
|
1502
1592
|
"unit": "cents",
|
|
1503
1593
|
"value": 100
|
|
1504
1594
|
},
|
|
1505
1595
|
"HRP_ATTRIBUTION_CENTS": {
|
|
1506
1596
|
"rel": "data/kernels/hrp.json",
|
|
1507
1597
|
"kind": "scalar",
|
|
1508
|
-
"doc": "The ATTRIBUTION window
|
|
1598
|
+
"doc": "The ATTRIBUTION window: two partials closer than this are one spectral event as far as the desk can tell — the same ±1 bin `omx_hrp_bin_peak` reads over, expressed musically so it holds across the range. A different law from HRP_COLLISION_CENTS (the SELECTION window, which stays above it): this one is the analyser's resolution, that one the corrector's. Generated into `omx_contract_limits.h` as `OMX_HRP_ATTRIBUTION_CENTS`; `hrp_attribute.h` reads it.",
|
|
1509
1599
|
"unit": "cents",
|
|
1510
1600
|
"value": 60
|
|
1511
1601
|
},
|
|
1512
1602
|
"HRP_DEFAULT_MAX_AUTO_BANDS": {
|
|
1513
1603
|
"rel": "data/kernels/hrp.json",
|
|
1514
1604
|
"kind": "scalar",
|
|
1515
|
-
"doc": "How many bands HRP may plant on ONE channel — its half of the machine budget, and the number that makes the budget FORECASTABLE rather than emergent. Without it the count is whatever the material happens to provoke: the placement law is sparse, so a clean note plants two bands and a resonant room plants nine, and nobody can answer \"will this fit?\" until it does not. With FBS senior
|
|
1605
|
+
"doc": "How many bands HRP may plant on ONE channel — its half of the machine budget, and the number that makes the budget FORECASTABLE rather than emergent. Without it the count is whatever the material happens to provoke: the placement law is sparse, so a clean note plants two bands and a resonant room plants nine, and nobody can answer \"will this fit?\" until it does not. With FBS senior that discovery would happen at showtime, to the junior planter, silently. Declared instead, the whole sum is arithmetic an operator can read before a note is played: operator bands + FBS maxAutoBands + HRP maxAutoBands <= EQ_MAX_BANDS EIGHT — ONE CORRECTION PER VOICE at full polyphony (operator sizing, 2026-09-01). The detector's ceiling is HRP_MAX_VOICES voices, a guitar's six strings and a piano/string voicing's eight, and a budget below the voice count would decide by arithmetic which of the notes actually sounding may be corrected — a limit nobody could read off the desk. Scarcity is handled where it belongs instead: the candidates from every voice meet in ONE globally ranked list and the head of it is what gets planted. It is NOT a claim to seniority, and it is larger than FBS's six. Seniority is the ALLOCATION ORDER — `HrpPlanter` takes only `EQ_MAX_BANDS − others.length`, the remainder after the operator and every other machine — so a bigger junior default cannot reach a senior slot; it only means HRP asks for more of what is left. the engine's conformance test asserts both halves. The per-channel DEFAULT; the row's travel is HRP_AUTO_BANDS_RANGE, so a channel that needs more can have more, as an explicit decision with a visible cost.",
|
|
1516
1606
|
"unit": "",
|
|
1517
1607
|
"value": 8
|
|
1518
1608
|
},
|
|
@@ -1551,14 +1641,14 @@
|
|
|
1551
1641
|
"BUS_INPUT_CAP": {
|
|
1552
1642
|
"rel": "data/kernels/mixmatrix.json",
|
|
1553
1643
|
"kind": "scalar",
|
|
1554
|
-
"doc": "The input cap a summing bus can be sized to — **the engine's declared input ceiling**, read from
|
|
1644
|
+
"doc": "The input cap a summing bus can be sized to — **the engine's declared input ceiling**, read from the engine's declarations rather than re-typed here. A gig with more than this many inputs needs more than one engine node; below it a bus is sized to `min(N, BUS_INPUT_CAP)`. It was a literal 64 until 2026-09-15, said to mirror the engine's `MAX_BUS_INPUTS` — and it did, but that 64 was the PipeWire builtin mixer's single-tier fan-in (8 × 8), never the engine's bound: the native node has allocated `OMX_MAX_STRIPS` (128) strips all along. Two literals agreeing by hand is how the console came to refuse a 96-channel desk it could carry. the engine's conformance test holds this to the C header; the console allocation design carries the ruling and the measured cost of width.",
|
|
1555
1645
|
"unit": "",
|
|
1556
1646
|
"value": 128
|
|
1557
1647
|
},
|
|
1558
1648
|
"PHASER_RATE_RANGE": {
|
|
1559
1649
|
"rel": "data/kernels/phaser.json",
|
|
1560
1650
|
"kind": "travels",
|
|
1561
|
-
"doc": "The phaser's sweep speed
|
|
1651
|
+
"doc": "The phaser's sweep speed. `omx_lfo_inc` freezes at Nyquist; this travel stays far below.",
|
|
1562
1652
|
"shape": "travel",
|
|
1563
1653
|
"value": {
|
|
1564
1654
|
"min": 0.05,
|
|
@@ -1572,7 +1662,7 @@
|
|
|
1572
1662
|
"PHASER_BASE_RANGE": {
|
|
1573
1663
|
"rel": "data/kernels/phaser.json",
|
|
1574
1664
|
"kind": "travels",
|
|
1575
|
-
"doc": "The phaser's lowest centre frequency; the sweep runs upward from it
|
|
1665
|
+
"doc": "The phaser's lowest centre frequency; the sweep runs upward from it.",
|
|
1576
1666
|
"shape": "travel",
|
|
1577
1667
|
"value": {
|
|
1578
1668
|
"min": 50,
|
|
@@ -1586,7 +1676,7 @@
|
|
|
1586
1676
|
"PHASER_DEPTH_RANGE": {
|
|
1587
1677
|
"rel": "data/kernels/phaser.json",
|
|
1588
1678
|
"kind": "travels",
|
|
1589
|
-
"doc": "The sweep's span above `base`, in octaves; 0 is a static phaser at `base
|
|
1679
|
+
"doc": "The sweep's span above `base`, in octaves; 0 is a static phaser at `base`.",
|
|
1590
1680
|
"shape": "travel",
|
|
1591
1681
|
"value": {
|
|
1592
1682
|
"min": 0,
|
|
@@ -1600,7 +1690,7 @@
|
|
|
1600
1690
|
"PHASER_STAGES_RANGE": {
|
|
1601
1691
|
"rel": "data/kernels/phaser.json",
|
|
1602
1692
|
"kind": "travels",
|
|
1603
|
-
"doc": "The phaser's section count per leg — EVEN, 2 … 12 (
|
|
1693
|
+
"doc": "The phaser's section count per leg — EVEN, 2 … 12 (two sections per notch). Its ends are the kernel's state capacity (`OMX_PHASER_MAX_STAGES` reads `OMX_PHASER_STAGES_RANGE_MAX`); the row moves it through the closed member set PHASER_STAGE_COUNTS, which is derived from it.",
|
|
1604
1694
|
"shape": "travel",
|
|
1605
1695
|
"value": {
|
|
1606
1696
|
"min": 2,
|
|
@@ -1614,7 +1704,7 @@
|
|
|
1614
1704
|
"PHASER_FEEDBACK_RANGE": {
|
|
1615
1705
|
"rel": "data/kernels/phaser.json",
|
|
1616
1706
|
"kind": "travels",
|
|
1617
|
-
"doc": "The phaser's SIGNED resonance
|
|
1707
|
+
"doc": "The phaser's SIGNED resonance. ±0.9, tighter than the flanger's ±0.95: the loop runs through a time-varying chain. Declared here (the refusal half); the kernel's clamp is the enforcement half.",
|
|
1618
1708
|
"shape": "travel",
|
|
1619
1709
|
"value": {
|
|
1620
1710
|
"min": -0.9,
|
|
@@ -1628,7 +1718,7 @@
|
|
|
1628
1718
|
"PHASER_MIX_RANGE": {
|
|
1629
1719
|
"rel": "data/kernels/phaser.json",
|
|
1630
1720
|
"kind": "travels",
|
|
1631
|
-
"doc": "The phaser's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, where the notch is complete
|
|
1721
|
+
"doc": "The phaser's wet/dry, as an instance of DRIVE_MIX_RANGE: 50 %, where the notch is complete.",
|
|
1632
1722
|
"shape": "travel",
|
|
1633
1723
|
"value": {
|
|
1634
1724
|
"min": 0,
|
|
@@ -1642,7 +1732,7 @@
|
|
|
1642
1732
|
"PHASER_TRAVELS": {
|
|
1643
1733
|
"rel": "data/kernels/phaser.json",
|
|
1644
1734
|
"kind": "travels",
|
|
1645
|
-
"doc": "The phaser's continuous travels by row field — the ONE map its control bounds and its row travels both read
|
|
1735
|
+
"doc": "The phaser's continuous travels by row field — the ONE map its control bounds and its row travels both read. `stages` is not here: it moves through PHASER_STAGE_COUNTS.",
|
|
1646
1736
|
"shape": "table",
|
|
1647
1737
|
"value": {
|
|
1648
1738
|
"rateHz": {
|
|
@@ -1717,17 +1807,26 @@
|
|
|
1717
1807
|
"semitones": {
|
|
1718
1808
|
"min": -12,
|
|
1719
1809
|
"max": 12,
|
|
1720
|
-
"
|
|
1810
|
+
"step": 1,
|
|
1811
|
+
"unit": "st",
|
|
1812
|
+
"default": 0,
|
|
1813
|
+
"defaultFrom": "desk"
|
|
1721
1814
|
},
|
|
1722
1815
|
"cents": {
|
|
1723
1816
|
"min": -50,
|
|
1724
1817
|
"max": 50,
|
|
1725
|
-
"
|
|
1818
|
+
"step": 1,
|
|
1819
|
+
"unit": "cents",
|
|
1820
|
+
"default": 0,
|
|
1821
|
+
"defaultFrom": "desk"
|
|
1726
1822
|
},
|
|
1727
1823
|
"mix": {
|
|
1728
1824
|
"min": 0,
|
|
1729
1825
|
"max": 100,
|
|
1730
|
-
"
|
|
1826
|
+
"step": 0.1,
|
|
1827
|
+
"unit": "%",
|
|
1828
|
+
"default": 100,
|
|
1829
|
+
"defaultFrom": "desk"
|
|
1731
1830
|
}
|
|
1732
1831
|
}
|
|
1733
1832
|
},
|
|
@@ -2018,7 +2117,7 @@
|
|
|
2018
2117
|
"ROTARY_MIX_RANGE": {
|
|
2019
2118
|
"rel": "data/kernels/rotary.json",
|
|
2020
2119
|
"kind": "travels",
|
|
2021
|
-
"doc": "The rotary's wet/dry, as an instance of DRIVE_MIX_RANGE: 100 %, because a rotary on an insert IS the sound (it replaces the cabinet) and an `fxReturn` wants it wet too
|
|
2120
|
+
"doc": "The rotary's wet/dry, as an instance of DRIVE_MIX_RANGE: 100 %, because a rotary on an insert IS the sound (it replaces the cabinet) and an `fxReturn` wants it wet too.",
|
|
2022
2121
|
"shape": "travel",
|
|
2023
2122
|
"value": {
|
|
2024
2123
|
"min": 0,
|
|
@@ -2232,7 +2331,7 @@
|
|
|
2232
2331
|
"TRANSIENT_LIMITS": {
|
|
2233
2332
|
"rel": "data/kernels/transient.json",
|
|
2234
2333
|
"kind": "travels",
|
|
2235
|
-
"doc": "The legal range of each transient-designer field (engineering units)
|
|
2334
|
+
"doc": "The legal range of each transient-designer field (engineering units). Every kind comes up flat: no per-kind default differs. the engine's limits generator emits each as `OMX_TRANSIENT_<FIELD>_{MIN,MAX,DEFAULT}` for `mix_transient.h`'s resolve; the row publishes them on OPTIONS when it lands.",
|
|
2236
2335
|
"shape": "table",
|
|
2237
2336
|
"value": {
|
|
2238
2337
|
"attackDb": {
|
|
@@ -2280,28 +2379,28 @@
|
|
|
2280
2379
|
"TRANSIENT_FAST_ATTACK_MS": {
|
|
2281
2380
|
"rel": "data/kernels/transient.json",
|
|
2282
2381
|
"kind": "scalar",
|
|
2283
|
-
"doc": "The fast follower's attack, ms: exactly the dynamics detector's no-oversampling line
|
|
2382
|
+
"doc": "The fast follower's attack, ms: exactly the dynamics detector's no-oversampling line.",
|
|
2284
2383
|
"unit": "ms",
|
|
2285
2384
|
"value": 0.5
|
|
2286
2385
|
},
|
|
2287
2386
|
"TRANSIENT_FAST_RELEASE_MS": {
|
|
2288
2387
|
"rel": "data/kernels/transient.json",
|
|
2289
2388
|
"kind": "scalar",
|
|
2290
|
-
"doc": "The fast follower's release, ms: one 50 Hz cycle held, a 180 bpm sixteenth forgotten
|
|
2389
|
+
"doc": "The fast follower's release, ms: one 50 Hz cycle held, a 180 bpm sixteenth forgotten.",
|
|
2291
2390
|
"unit": "ms",
|
|
2292
2391
|
"value": 20
|
|
2293
2392
|
},
|
|
2294
2393
|
"TRANSIENT_REF_DB": {
|
|
2295
2394
|
"rel": "data/kernels/transient.json",
|
|
2296
2395
|
"kind": "scalar",
|
|
2297
|
-
"doc": "The contrast, dB, at which a knob reaches its full value
|
|
2396
|
+
"doc": "The contrast, dB, at which a knob reaches its full value.",
|
|
2298
2397
|
"unit": "dB",
|
|
2299
2398
|
"value": 6
|
|
2300
2399
|
},
|
|
2301
2400
|
"TRANSIENT_FLOOR_LIN": {
|
|
2302
2401
|
"rel": "data/kernels/transient.json",
|
|
2303
2402
|
"kind": "scalar",
|
|
2304
|
-
"doc": "The detector floor, linear (−100 dBFS): below it both envelopes read the floor and the stage is unity
|
|
2403
|
+
"doc": "The detector floor, linear (−100 dBFS): below it both envelopes read the floor and the stage is unity.",
|
|
2305
2404
|
"unit": "",
|
|
2306
2405
|
"value": 0.00001
|
|
2307
2406
|
},
|
|
@@ -2447,7 +2546,7 @@
|
|
|
2447
2546
|
"FDELAY_MOD_READ_ORDER": {
|
|
2448
2547
|
"rel": "data/primitives.json",
|
|
2449
2548
|
"kind": "scalar",
|
|
2450
|
-
"doc": "The order the chorus and flanger construct their lines with (four taps
|
|
2549
|
+
"doc": "The order the chorus and flanger construct their lines with (four taps).",
|
|
2451
2550
|
"unit": "",
|
|
2452
2551
|
"value": 3
|
|
2453
2552
|
},
|