@openmixer/omx-dsp 0.31.0 → 0.32.1
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/dist/curve.d.ts +17 -0
- package/dist/curve.js +26 -18
- package/dist/definitions.d.ts +94 -3
- package/dist/definitions.js +76 -3
- package/dist/fbs-place.d.ts +125 -0
- package/dist/fbs-place.js +280 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/meter.d.ts +77 -0
- package/dist/meter.js +114 -0
- package/oracle/ts-twin-oracle.c +137 -1
- package/package.json +3 -3
- package/src/curve.ts +50 -16
- package/src/definitions.ts +108 -3
- package/src/fbs-place.ts +367 -0
- package/src/index.ts +48 -0
- package/src/meter.ts +147 -0
package/dist/curve.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export declare const CURVE_WORDS: {
|
|
|
12
12
|
readonly roles: string[];
|
|
13
13
|
readonly units: string[];
|
|
14
14
|
readonly shapes: string[];
|
|
15
|
+
/** fbs-fixed and fbs-live: the origins are spelt with a hyphen */
|
|
16
|
+
readonly origins: string[];
|
|
15
17
|
};
|
|
16
18
|
/** What curvePoints answers when it draws nothing: a CURVE_CODES id other than `ok`. */
|
|
17
19
|
export type CurveCode = Exclude<(typeof CURVE_CODES)[number], 'ok'>;
|
|
@@ -27,6 +29,8 @@ export interface CurveTerm {
|
|
|
27
29
|
readonly unit: string;
|
|
28
30
|
/** For `band_type`, the shape its value selects (from the role's `shapes`); for `band_freq`, the fixed shape. */
|
|
29
31
|
readonly shape?: string;
|
|
32
|
+
/** Where the band comes from: `user` (the default), `fbs-fixed` or `fbs-live`. A band's is its band_freq term's. */
|
|
33
|
+
readonly origin?: string;
|
|
30
34
|
}
|
|
31
35
|
/** A curve request: one display of the description, bound. */
|
|
32
36
|
export interface CurveRequest {
|
|
@@ -45,6 +49,15 @@ export interface CurveRequest {
|
|
|
45
49
|
};
|
|
46
50
|
/** The terms; a later term of one role and index replaces an earlier. */
|
|
47
51
|
readonly terms: readonly CurveTerm[];
|
|
52
|
+
/** Also answer the curve over the `user` bands alone, at the same x. */
|
|
53
|
+
readonly userOnly?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** A band whose origin is not `user`: its centre (Hz), its own magnitude there (dB), its Q and its origin. */
|
|
56
|
+
export interface CurveMark {
|
|
57
|
+
readonly freq: number;
|
|
58
|
+
readonly depthDb: number;
|
|
59
|
+
readonly q: number;
|
|
60
|
+
readonly origin: string;
|
|
48
61
|
}
|
|
49
62
|
/** One point: Hz and dB for an EQ, input dB and output dB for a transfer curve. */
|
|
50
63
|
export interface CurvePoint {
|
|
@@ -54,6 +67,10 @@ export interface CurvePoint {
|
|
|
54
67
|
/** The answer: the points, ascending in x, or the code of what is missing or refused. */
|
|
55
68
|
export type CurveAnswer = {
|
|
56
69
|
readonly points: readonly CurvePoint[];
|
|
70
|
+
/** One per drawn band whose origin is not `user`, in band order; none for a transfer curve. */
|
|
71
|
+
readonly marks: readonly CurveMark[];
|
|
72
|
+
/** With `userOnly`: the curve over the user bands (and the head filters) alone, at the same x. */
|
|
73
|
+
readonly userPoints?: readonly CurvePoint[];
|
|
57
74
|
} | {
|
|
58
75
|
readonly code: CurveCode;
|
|
59
76
|
};
|
package/dist/curve.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* words) and the same codes (CURVE_CODES), checked in the same order. Pinned by test/agreement.test.mjs at the
|
|
7
7
|
* nine oracle rates: the EQ through the magnitude twins, the transfer curves through the gain computer twins.
|
|
8
8
|
*/
|
|
9
|
-
import { COMP_KNEE_DB_RANGE, COMP_RATIO_RANGE, CURVE_DISPLAYS, CURVE_EXTENTS, CURVE_FAMILIES, CURVE_POINTS_MAX, CURVE_ROLES, CURVE_SHAPES, CURVE_UNITS, GATE_RANGE_DB_RANGE, GATE_RATIO_RANGE, LIN_TO_DB_FLOOR, } from './definitions.js';
|
|
10
|
-
import { magnitudeSumDb, octavesToQ } from './eq.js';
|
|
9
|
+
import { COMP_KNEE_DB_RANGE, COMP_RATIO_RANGE, CURVE_DISPLAYS, CURVE_EXTENTS, CURVE_FAMILIES, CURVE_ORIGINS, CURVE_POINTS_MAX, CURVE_ROLES, CURVE_SHAPES, CURVE_UNITS, EQ_BAND_DEFAULTS, GATE_RANGE_DB_RANGE, GATE_RATIO_RANGE, LIN_TO_DB_FLOOR, } from './definitions.js';
|
|
10
|
+
import { clampEqQFor, magnitudeSumDb, octavesToQ } from './eq.js';
|
|
11
11
|
import { gaincompDb, gaincompDbShifted, gateKnee } from './gaincomp.js';
|
|
12
12
|
/** A set id as the description spells it: `eqResponse` is `eq_response`; the unshaped band is `-`. */
|
|
13
13
|
const wordOf = (id) => (id === 'unshaped' ? '-' : id.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`));
|
|
@@ -18,6 +18,8 @@ export const CURVE_WORDS = {
|
|
|
18
18
|
roles: CURVE_ROLES.map(wordOf),
|
|
19
19
|
units: CURVE_UNITS.map(wordOf),
|
|
20
20
|
shapes: CURVE_SHAPES.map(wordOf),
|
|
21
|
+
/** fbs-fixed and fbs-live: the origins are spelt with a hyphen */
|
|
22
|
+
origins: CURVE_ORIGINS.map((id) => id.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)),
|
|
21
23
|
};
|
|
22
24
|
/** The units each role converts from (omx_curve_unit_accepted). */
|
|
23
25
|
const ACCEPTS = {
|
|
@@ -46,6 +48,7 @@ const valueOf = (t) => {
|
|
|
46
48
|
};
|
|
47
49
|
const SHAPE_TYPE = {
|
|
48
50
|
bell: 'bell', lowshelf: 'lowshelf', highshelf: 'highshelf', highpass: 'highpass', lowpass: 'lowpass', notch: 'notch',
|
|
51
|
+
allpass1: 'allpass1', allpass2: 'allpass2',
|
|
49
52
|
};
|
|
50
53
|
/** The Q of each section of a Butterworth head filter (omx_eq_butterworth_qs): 12 dB/oct one at 1/sqrt(2), 24 dB/oct
|
|
51
54
|
* two whose product is maximally flat, the kernel's own digits. */
|
|
@@ -89,7 +92,7 @@ export function curvePoints(rq) {
|
|
|
89
92
|
return { code: 'valueNotFinite' };
|
|
90
93
|
if (rq.terms.some((t) => !Number.isFinite(t.value)))
|
|
91
94
|
return { code: 'valueNotFinite' };
|
|
92
|
-
if (rq.terms.some((t) => !ACCEPTS[t.role]?.includes(t.unit)))
|
|
95
|
+
if (rq.terms.some((t) => !ACCEPTS[t.role]?.includes(t.unit) || !CURVE_WORDS.origins.includes(t.origin ?? 'user')))
|
|
93
96
|
return { code: 'unitRefused' };
|
|
94
97
|
let lo, hi;
|
|
95
98
|
if (rq.extents)
|
|
@@ -122,6 +125,7 @@ function eqPoints(rq, find, lo, hi) {
|
|
|
122
125
|
nb = Math.max(nb, i + 1);
|
|
123
126
|
}
|
|
124
127
|
const bands = [];
|
|
128
|
+
const origin = [];
|
|
125
129
|
for (let b = 0; b < nb; b++) {
|
|
126
130
|
const type = find('band_type', b), freq = find('band_freq', b), gain = find('band_gain', b), q = find('band_q', b), on = find('band_on', b);
|
|
127
131
|
if (!type && !freq && !gain && !q && !on)
|
|
@@ -131,19 +135,18 @@ function eqPoints(rq, find, lo, hi) {
|
|
|
131
135
|
const shape = type?.shape ?? freq.shape;
|
|
132
136
|
if (shape === undefined)
|
|
133
137
|
return { code: 'termMissing' };
|
|
134
|
-
if (shape === 'off')
|
|
135
|
-
continue;
|
|
136
138
|
const kind = SHAPE_TYPE[shape];
|
|
137
139
|
if (!kind)
|
|
138
|
-
|
|
139
|
-
if (!q)
|
|
140
|
-
return { code: 'termMissing' };
|
|
140
|
+
continue; // off, or a choice with no shape (`-`): not drawn
|
|
141
141
|
const gains = kind === 'bell' || kind === 'lowshelf' || kind === 'highshelf';
|
|
142
142
|
if (gains && !gain)
|
|
143
143
|
return { code: 'termMissing' };
|
|
144
144
|
if (on && valueOf(on) === 0)
|
|
145
145
|
continue;
|
|
146
|
-
bands.push({ type: kind, freq: valueOf(freq), gainDb: gains && gain ? valueOf(gain) : 0,
|
|
146
|
+
bands.push({ type: kind, freq: valueOf(freq), gainDb: gains && gain ? valueOf(gain) : 0,
|
|
147
|
+
// no Q control: the declared default (EQ_BAND_DEFAULTS), clamped for the shape as the kernel clamps it
|
|
148
|
+
q: q ? valueOf(q) : Math.fround(clampEqQFor(kind === 'notch' ? 'notch' : 'bell', EQ_BAND_DEFAULTS.q)) });
|
|
149
|
+
origin.push(freq.origin ?? 'user');
|
|
147
150
|
}
|
|
148
151
|
const pass = [];
|
|
149
152
|
let present = false;
|
|
@@ -152,7 +155,8 @@ function eqPoints(rq, find, lo, hi) {
|
|
|
152
155
|
if (!fr && !sl && !on)
|
|
153
156
|
continue;
|
|
154
157
|
present = true;
|
|
155
|
-
|
|
158
|
+
// the slope in dB per octave, from the role's declared enumeration or a dB control; a bare choice value is none
|
|
159
|
+
if (!fr || !sl || sl.unit !== 'db')
|
|
156
160
|
return { code: 'termMissing' };
|
|
157
161
|
const slope = valueOf(sl);
|
|
158
162
|
if (slope !== 12 && slope !== 24)
|
|
@@ -170,20 +174,24 @@ function eqPoints(rq, find, lo, hi) {
|
|
|
170
174
|
if (rq.points + 3 * drawn.length > CURVE_POINTS_MAX)
|
|
171
175
|
return { code: 'pointsRange' };
|
|
172
176
|
const top = (rq.sampleRate / 2) * 0.999;
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
const xs = curveFreqs(drawn, lo, hi, rq.points);
|
|
178
|
+
const sum = (set) => xs.map((x) => ({ x, y: magnitudeSumDb(set, x < top ? x : top, rq.sampleRate, CURVE_EXTENTS.eqFloorDb) }));
|
|
179
|
+
const marks = bands.flatMap((b, i) => origin[i] === 'user' ? [] : [{ freq: b.freq, depthDb: magnitudeSumDb([b], b.freq, rq.sampleRate, CURVE_EXTENTS.eqFloorDb), q: b.q, origin: origin[i] }]);
|
|
180
|
+
const points = sum(drawn);
|
|
181
|
+
if (!rq.userOnly)
|
|
182
|
+
return { points, marks };
|
|
183
|
+
return { points, marks, userPoints: sum([...bands.filter((_, i) => origin[i] === 'user'), ...pass]) };
|
|
178
184
|
}
|
|
179
185
|
function transferPoints(rq, find, lo, hi) {
|
|
180
186
|
const below = rq.family === 'gate';
|
|
181
187
|
const thr = find('threshold'), ratio = find('ratio'), knee = find('knee'), makeup = find('makeup'), range = find('range');
|
|
182
188
|
const ks = find('knee_start'), ke = find('knee_end');
|
|
183
|
-
|
|
189
|
+
// a limiter has no ratio role: the dynamics form at ratio infinity, a hard corner at the threshold
|
|
190
|
+
const limiter = rq.family === 'limiter';
|
|
191
|
+
if (!thr || (!ratio && !limiter) || (below && !range) || (below && !ks !== !ke))
|
|
184
192
|
return { code: 'termMissing' };
|
|
185
193
|
const f = Math.fround;
|
|
186
|
-
const r = f(valueOf(ratio)), k = knee ? f(valueOf(knee)) : 0;
|
|
194
|
+
const r = ratio ? f(valueOf(ratio)) : Infinity, k = knee ? f(valueOf(knee)) : 0;
|
|
187
195
|
const rmin = f(below ? GATE_RATIO_RANGE.min : COMP_RATIO_RANGE.min);
|
|
188
196
|
const thresh = f(valueOf(thr));
|
|
189
197
|
let kneeDb = k < COMP_KNEE_DB_RANGE.min ? COMP_KNEE_DB_RANGE.min : k;
|
|
@@ -204,5 +212,5 @@ function transferPoints(rq, find, lo, hi) {
|
|
|
204
212
|
const g = below ? gaincompDbShifted(p, shiftDb, lv) : gaincompDb(p, lv);
|
|
205
213
|
points.push({ x: lv, y: lv + g + mk });
|
|
206
214
|
}
|
|
207
|
-
return { points };
|
|
215
|
+
return rq.userOnly ? { points, marks: [], userPoints: points } : { points, marks: [] };
|
|
208
216
|
}
|
package/dist/definitions.d.ts
CHANGED
|
@@ -13,6 +13,47 @@ export declare const LOWPASS_HANDOVER: {
|
|
|
13
13
|
readonly hiAtLoQ: 0.9;
|
|
14
14
|
readonly hiAtPeakQ: 0.8;
|
|
15
15
|
};
|
|
16
|
+
/** What every band of a fresh EQ comes up at, whatever its type and its strip: flat (0 dB) and Q 1. The band frequencies and types come from the default rule. @see data/kernels/eq.json */
|
|
17
|
+
export declare const EQ_BAND_DEFAULTS: {
|
|
18
|
+
readonly gainDb: 0;
|
|
19
|
+
readonly q: 1;
|
|
20
|
+
};
|
|
21
|
+
/** The deepest cut a band of an fbs-* origin may hold, in dB: the feedback corrector's own safety bound, never the operator EQ's ±15 (EQ_GAIN_RANGE), which stays the bound of every other origin. Declared here as one value until the vocabulary owner (omx-contract) carries it as its own word, a new ref beside EQ_GAIN_RANGE and never a widening of it; this item then becomes that ref, and no second copy of the number is ever written. (dB) @see data/kernels/fbs.json */
|
|
22
|
+
export declare const FBS_MAX_CUT_DB = -24;
|
|
23
|
+
/** How much deeper a live band's full depth goes each time regrowth re-clamps a release, in dB, down to FBS_MAX_CUT_DB: regrowth at a depth is the measurement that the depth was not enough. (dB) @see data/kernels/fbs.json */
|
|
24
|
+
export declare const FBS_RECLAMP_DEEPEN_DB = 3;
|
|
25
|
+
/** The most times the clean hold doubles after re-clamps: the hold before the first release stage is the channel's hold times 2^min(re-clamps, this). @see data/kernels/fbs.json */
|
|
26
|
+
export declare const FBS_RECLAMP_BACKOFF_CAP = 3;
|
|
27
|
+
/** How long one release stage's gain ramp takes, in ms, from the depth the band stands at to the stage's depth. (ms) @see data/kernels/fbs.json */
|
|
28
|
+
export declare const FBS_LIFT_RAMP_MS = 3000;
|
|
29
|
+
/** The equal steps one release ramp takes, FBS_LIFT_RAMP_MS / this apart: the last step lands the stage's depth exactly. @see data/kernels/fbs.json */
|
|
30
|
+
export declare const FBS_LIFT_RAMP_STEPS = 10;
|
|
31
|
+
/** Each release stage holds the planted depth times this ratio to the stage's power: every stage releases a third of what remains. @see data/kernels/fbs.json */
|
|
32
|
+
export declare const FBS_RELEASE_RATIO = 0.6666666666666666;
|
|
33
|
+
/** A release stage whose depth is shallower than this, in dB, removes the band instead of holding it: the cut is inaudible. (dB) @see data/kernels/fbs.json */
|
|
34
|
+
export declare const FBS_RELEASE_DONE_DB = 1;
|
|
35
|
+
/** How long a band listens at an eased stage, clean, before the next stage begins, in ms. (ms) @see data/kernels/fbs.json */
|
|
36
|
+
export declare const FBS_RELEASE_DWELL_MS = 8000;
|
|
37
|
+
/** The lowest frequency a confirmed ring is planted at, in Hz; one below it is refused as rejected-edge, never clamped onto the EQ's edge. (Hz) @see data/kernels/fbs.json */
|
|
38
|
+
export declare const FBS_RING_HZ_MIN = 60;
|
|
39
|
+
/** The highest frequency a confirmed ring is planted at, in Hz; one above it is refused as rejected-edge. (Hz) @see data/kernels/fbs.json */
|
|
40
|
+
export declare const FBS_RING_HZ_MAX = 16000;
|
|
41
|
+
/** Two readings are the same ringing frequency within this many Hz, or FBS_SAME_RING_SHARE of the higher one, whichever is wider. (Hz) @see data/kernels/fbs.json */
|
|
42
|
+
export declare const FBS_SAME_RING_HZ = 3;
|
|
43
|
+
/** The share of the higher frequency within which two readings are the same ringing frequency, when it is wider than FBS_SAME_RING_HZ: FFT bin spacing grows with frequency. @see data/kernels/fbs.json */
|
|
44
|
+
export declare const FBS_SAME_RING_SHARE = 0.015;
|
|
45
|
+
/** The clean hold, in seconds, before a live band's first release stage. (s) @see data/kernels/fbs.json */
|
|
46
|
+
export declare const FBS_DEFAULT_HOLD_SECONDS = 5;
|
|
47
|
+
/** How many bands one corrector may plant when nobody set its cap; a full pool plants nothing and says pool-full. @see data/kernels/fbs.json */
|
|
48
|
+
export declare const FBS_DEFAULT_MAX_AUTO_BANDS = 6;
|
|
49
|
+
/** The merge radius, in cents: a confirmed ring this close to a band already planted is that band's find, and plants nothing. (cents) @see data/kernels/fbs.json */
|
|
50
|
+
export declare const FBS_DEFAULT_MERGE_CENTS = 100;
|
|
51
|
+
/** How long a fully released find's re-clamp count is remembered, in seconds, so a chronic ringer re-plants with its doubled holds. (s) @see data/kernels/fbs.json */
|
|
52
|
+
export declare const FBS_DEFAULT_COOLDOWN_SECONDS = 600;
|
|
53
|
+
/** 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. @see data/kernels/fbs.json */
|
|
54
|
+
export declare const FBS_DEFAULT_NOTCH_Q = 116;
|
|
55
|
+
/** Released finds the ring memory holds at once. The console's list is unbounded and expires by FBS_DEFAULT_COOLDOWN_SECONDS; a full memory here forgets its oldest entry first, and counts it. @see data/kernels/fbs.json */
|
|
56
|
+
export declare const FBS_RING_MEMORY_SLOTS = 32;
|
|
16
57
|
/** The displays a panel description draws from a closed form, the kinds omx_curve_points answers: an EQ's magnitude response, x in Hz and y in dB, and a dynamics stage's static transfer curve, input dB to output dB. The wire spells each id in snake case (`eq_response`, `transfer_curve`), the description's own display word. @see data/primitives/curve.json */
|
|
17
58
|
export declare const CURVE_DISPLAYS: readonly ["eqResponse", "transferCurve"];
|
|
18
59
|
/** The panel families omx_curve_points draws, by the description's family word. `eq` draws an eq_response; the other four a transfer_curve, the family choosing the gain computer's mode: `dynamics`, `limiter` and `deesser` act ABOVE the threshold, `gate` BELOW it with the shifted knee of the gate's knee range. Any other family has no closed form here. @see data/primitives/curve.json */
|
|
@@ -21,9 +62,11 @@ export declare const CURVE_FAMILIES: readonly ["eq", "dynamics", "limiter", "gat
|
|
|
21
62
|
export declare const CURVE_ROLES: readonly ["bandType", "bandFreq", "bandGain", "bandQ", "bandOn", "hpfFreq", "hpfSlope", "hpfOn", "lpfFreq", "lpfSlope", "lpfOn", "threshold", "ratio", "knee", "makeup", "range", "kneeStart", "kneeEnd"];
|
|
22
63
|
/** The units a curve term's value may come in, the param-contract extension's unit tokens the served description gives a role. omx_curve_points converts once: `coef` to dB for a gain, `oct` to Q for a bandwidth, `khz` to Hz; a level in `db`, `dbfs`, `dbu` or `lufs` is read as dB from the threshold's own scale; `none` is a plain number, a switch or a choice; `ratio` a ratio. A unit its role does not accept is refused. @see data/primitives/curve.json */
|
|
23
64
|
export declare const CURVE_UNITS: readonly ["hz", "khz", "db", "dbfs", "dbu", "lufs", "coef", "oct", "none", "ratio"];
|
|
24
|
-
/** The shape of an EQ band, as the caller resolves it from the description: a `band_type` role's `shapes` list indexed by the control's choice value, or the fixed `shape` of a band no control selects. `off` is a band that is not drawn
|
|
25
|
-
export declare const CURVE_SHAPES: readonly ["off", "bell", "lowshelf", "highshelf", "highpass", "lowpass", "notch", "unshaped"];
|
|
26
|
-
/**
|
|
65
|
+
/** The shape of an EQ band, as the caller resolves it from the description: a `band_type` role's `shapes` list indexed by the control's choice value, or the fixed `shape` of a band no control selects. `off` is a band that is not drawn, and so is `unshaped`, spelt `-` on the wire, a choice value with no shape. The others design the band through omx_eq_design: a bell, the two shelves, the pass filters, the notch, and the first- and second-order allpasses, which draw what they run, 0 dB. @see data/primitives/curve.json */
|
|
66
|
+
export declare const CURVE_SHAPES: readonly ["off", "bell", "lowshelf", "highshelf", "highpass", "lowpass", "notch", "unshaped", "allpass1", "allpass2"];
|
|
67
|
+
/** Where an EQ band of a curve request comes from, as the console's strip EQ state says it (its BAND_ORIGINS): `user`, the operator's own band, and the bands a planter put there, `fbsFixed` and `fbsLive` (the feedback corrector's ring-out and show pools), `hrp` (the harmonic resonance processor's cuts) and `roomMode` (a room mode's correction), spelt `user`, `fbs-fixed`, `fbs-live`, `hrp` and `room-mode` on the wire. The sum ignores it: every drawn band is in the curve. A band whose origin is not `user` is answered as a mark (its frequency, depth, Q and origin), and a request that asks for it also gets the curve over the `user` bands alone. A plugin's descriptor carries no origin: a request with none draws no marks. @see data/primitives/curve.json */
|
|
68
|
+
export declare const CURVE_ORIGINS: readonly ["user", "fbsFixed", "fbsLive", "hrp", "roomMode"];
|
|
69
|
+
/** What omx_curve_points answers in its code: `ok`, a curve; `kindUnknown`, a kind, family or head filter slope with no closed form; `termMissing`, a term the closed form has no default for is not in the request (a band's frequency and shape, a bell's or shelf's gain, a head filter's corner, and its slope unless it comes from the role's declared enumeration as dB per octave; threshold and ratio for dynamics and the de-esser, threshold for a limiter (its ratio is infinity, a hard corner), threshold, range and ratio for a gate; both ends of a gate's knee range or neither); `unitRefused`, a term in a unit its role does not accept; `valueNotFinite`, a value, the rate or an extent that is not finite, a rate that is not positive; `pointsRange`, grid points outside 2 to CURVE_POINTS_MAX (for an EQ, with three anchors a drawn band), a band index past what fits, or extents that bound nothing; `room`, a caller's buffers too small. Where omx-dsp declares a default the curve takes it: a band's Q is EQ_BAND_DEFAULTS q, clamped for its shape as clampEqQFor clamps it. No curve is drawn from a guess. @see data/primitives/curve.json */
|
|
27
70
|
export declare const CURVE_CODES: readonly ["ok", "kindUnknown", "termMissing", "unitRefused", "valueNotFinite", "pointsRange", "room"];
|
|
28
71
|
/** The most points one curve carries, an EQ's band anchors included: a reply of x with four significant digits and y to 0.01 dB, about 13 bytes a point, fits the 4096-byte line a host's reply is built in. Every caller reads it here; it moves with that buffer, in this one place. @see data/primitives/curve.json */
|
|
29
72
|
export declare const CURVE_POINTS_MAX = 256;
|
|
@@ -41,6 +84,24 @@ export declare const LIN_TO_DB_FLOOR: {
|
|
|
41
84
|
readonly lin: 1e-9;
|
|
42
85
|
readonly db: -180;
|
|
43
86
|
};
|
|
87
|
+
/** A meter's view law, the same on every surface: the fill is linear in dB from `floorDb` (dBFS, an empty display) to 0 dBFS (a full one); a stepped display (an LED ladder) holds its count until the level moves `stepHysteresis` of a step past the count's own rounding edge; the peak marker falls `fallDbPerSecond` dB for each second elapsed at the view's draw tick, whatever the tick's rate, silence included. A host reads a plugin's held meter at `hostReadHz`; the console streams meter values at `streamHz`. dBFS, a fraction of a step, dB per second and Hz. @see data/primitives/meter.json */
|
|
88
|
+
export declare const METER_VIEW: {
|
|
89
|
+
readonly floorDb: -60;
|
|
90
|
+
readonly stepHysteresis: 0.25;
|
|
91
|
+
readonly fallDbPerSecond: 18;
|
|
92
|
+
readonly hostReadHz: 50;
|
|
93
|
+
readonly streamHz: 20;
|
|
94
|
+
};
|
|
95
|
+
/** What a meter measures, as a plugin's descriptor and the panel description spell it: `level`, a signal level (its measurement one of METER_MEASUREMENTS), and `gainReduction`, the gain a dynamics stage takes off, dB at or below 0. The wire spells them `level` and `gain-reduction`. `rms`, `vu` and `ppm` are not kinds. @see data/primitives/meter.json */
|
|
96
|
+
export declare const METER_KINDS: readonly ["level", "gainReduction"];
|
|
97
|
+
/** The measurement of a `level` meter: the sample peak (`peak`, dBFS), the true peak (`truePeak`, dBTP), and the loudness measures of omx_loudness.h: momentary, short-term and integrated loudness (`lufsM`, `lufsS`, `lufsI`, LUFS) and the loudness range (`lra`, LU). The wire spells them `peak`, `true-peak`, `lufs-m`, `lufs-s`, `lufs-i` and `lra`. A foreign meter's measurement is null, never guessed. @see data/primitives/meter.json */
|
|
98
|
+
export declare const METER_MEASUREMENTS: readonly ["peak", "truePeak", "lufsM", "lufsS", "lufsI", "lra"];
|
|
99
|
+
/** The unit a meter's values are in, spelt as its label: dBFS for a sample peak, dBTP for a true peak, LUFS for a loudness, LU for a loudness range, dB for a gain reduction. The scale a surface draws is captioned with it. @see data/primitives/meter.json */
|
|
100
|
+
export declare const METER_UNITS: readonly ["dbfs", "dbtp", "lufs", "lu", "db"];
|
|
101
|
+
/** The labels of METER_UNITS, in its order. @see data/primitives/meter.json */
|
|
102
|
+
export declare const METER_UNITS_LABELS: readonly ["dBFS", "dBTP", "LUFS", "LU", "dB"];
|
|
103
|
+
/** What a subscriber that decimates a meter stream keeps of the frames it drops, one per kind in METER_KINDS order, as the engine's slot keeps between two reads: a `level` keeps the `peak` (the largest value), a `gainReduction` the `deepest` (the smallest dB). Never the newest. @see data/primitives/meter.json */
|
|
104
|
+
export declare const METER_DECIMATION: readonly ["peak", "deepest"];
|
|
44
105
|
/** The Q (resonance) extent of a parametric band. @see data/kernels/eq.json */
|
|
45
106
|
export declare const EQ_Q_RANGE: {
|
|
46
107
|
readonly min: 0.3;
|
|
@@ -51,6 +112,36 @@ export declare const EQ_NOTCH_Q_RANGE: {
|
|
|
51
112
|
readonly min: 0.3;
|
|
52
113
|
readonly max: 116;
|
|
53
114
|
};
|
|
115
|
+
/** The parametric-band gain travel, in dB. The ± scalar `clampEqGain` enforces is READ off this (the engine derives its gain limit from `max`), so the bound is stated once and a surface cannot draw a wider knob than the clamp will honour. @see data/kernels/eq.json */
|
|
116
|
+
export declare const EQ_GAIN_RANGE: {
|
|
117
|
+
readonly min: -15;
|
|
118
|
+
readonly max: 15;
|
|
119
|
+
};
|
|
120
|
+
/** The frequency band a parametric band can be dragged across. @see data/kernels/eq.json */
|
|
121
|
+
export declare const EQ_FREQ_RANGE: {
|
|
122
|
+
readonly min: 20;
|
|
123
|
+
readonly max: 20000;
|
|
124
|
+
};
|
|
125
|
+
/** How many bands this corrector may plant at once (its pool), from one to the EQ's band count. An integer control. @see data/kernels/fbs.json */
|
|
126
|
+
export declare const FBS_BANDS_RANGE: {
|
|
127
|
+
readonly min: 1;
|
|
128
|
+
readonly max: 24;
|
|
129
|
+
};
|
|
130
|
+
/** The clean hold, in seconds, before a live band's first release stage. @see data/kernels/fbs.json */
|
|
131
|
+
export declare const FBS_HOLD_RANGE: {
|
|
132
|
+
readonly min: 1;
|
|
133
|
+
readonly max: 300;
|
|
134
|
+
};
|
|
135
|
+
/** The merge radius, in cents. An integer control. @see data/kernels/fbs.json */
|
|
136
|
+
export declare const FBS_MERGE_RANGE: {
|
|
137
|
+
readonly min: 0;
|
|
138
|
+
readonly max: 600;
|
|
139
|
+
};
|
|
140
|
+
/** How long a released find's escalation is remembered, in seconds. An integer control. @see data/kernels/fbs.json */
|
|
141
|
+
export declare const FBS_COOLDOWN_RANGE: {
|
|
142
|
+
readonly min: 0;
|
|
143
|
+
readonly max: 7200;
|
|
144
|
+
};
|
|
54
145
|
/** The travel of ratio, from its table COMP_LIMITS. @see data/kernels/comp.json */
|
|
55
146
|
export declare const COMP_RATIO_RANGE: {
|
|
56
147
|
readonly min: 1;
|
package/dist/definitions.js
CHANGED
|
@@ -16,6 +16,47 @@ export const LOWPASS_HANDOVER = {
|
|
|
16
16
|
hiAtLoQ: 0.9,
|
|
17
17
|
hiAtPeakQ: 0.8,
|
|
18
18
|
};
|
|
19
|
+
/** What every band of a fresh EQ comes up at, whatever its type and its strip: flat (0 dB) and Q 1. The band frequencies and types come from the default rule. @see data/kernels/eq.json */
|
|
20
|
+
export const EQ_BAND_DEFAULTS = {
|
|
21
|
+
gainDb: 0,
|
|
22
|
+
q: 1,
|
|
23
|
+
};
|
|
24
|
+
/** The deepest cut a band of an fbs-* origin may hold, in dB: the feedback corrector's own safety bound, never the operator EQ's ±15 (EQ_GAIN_RANGE), which stays the bound of every other origin. Declared here as one value until the vocabulary owner (omx-contract) carries it as its own word, a new ref beside EQ_GAIN_RANGE and never a widening of it; this item then becomes that ref, and no second copy of the number is ever written. (dB) @see data/kernels/fbs.json */
|
|
25
|
+
export const FBS_MAX_CUT_DB = -24;
|
|
26
|
+
/** How much deeper a live band's full depth goes each time regrowth re-clamps a release, in dB, down to FBS_MAX_CUT_DB: regrowth at a depth is the measurement that the depth was not enough. (dB) @see data/kernels/fbs.json */
|
|
27
|
+
export const FBS_RECLAMP_DEEPEN_DB = 3;
|
|
28
|
+
/** The most times the clean hold doubles after re-clamps: the hold before the first release stage is the channel's hold times 2^min(re-clamps, this). @see data/kernels/fbs.json */
|
|
29
|
+
export const FBS_RECLAMP_BACKOFF_CAP = 3;
|
|
30
|
+
/** How long one release stage's gain ramp takes, in ms, from the depth the band stands at to the stage's depth. (ms) @see data/kernels/fbs.json */
|
|
31
|
+
export const FBS_LIFT_RAMP_MS = 3000;
|
|
32
|
+
/** The equal steps one release ramp takes, FBS_LIFT_RAMP_MS / this apart: the last step lands the stage's depth exactly. @see data/kernels/fbs.json */
|
|
33
|
+
export const FBS_LIFT_RAMP_STEPS = 10;
|
|
34
|
+
/** Each release stage holds the planted depth times this ratio to the stage's power: every stage releases a third of what remains. @see data/kernels/fbs.json */
|
|
35
|
+
export const FBS_RELEASE_RATIO = 0.6666666666666666;
|
|
36
|
+
/** A release stage whose depth is shallower than this, in dB, removes the band instead of holding it: the cut is inaudible. (dB) @see data/kernels/fbs.json */
|
|
37
|
+
export const FBS_RELEASE_DONE_DB = 1;
|
|
38
|
+
/** How long a band listens at an eased stage, clean, before the next stage begins, in ms. (ms) @see data/kernels/fbs.json */
|
|
39
|
+
export const FBS_RELEASE_DWELL_MS = 8000;
|
|
40
|
+
/** The lowest frequency a confirmed ring is planted at, in Hz; one below it is refused as rejected-edge, never clamped onto the EQ's edge. (Hz) @see data/kernels/fbs.json */
|
|
41
|
+
export const FBS_RING_HZ_MIN = 60;
|
|
42
|
+
/** The highest frequency a confirmed ring is planted at, in Hz; one above it is refused as rejected-edge. (Hz) @see data/kernels/fbs.json */
|
|
43
|
+
export const FBS_RING_HZ_MAX = 16000;
|
|
44
|
+
/** Two readings are the same ringing frequency within this many Hz, or FBS_SAME_RING_SHARE of the higher one, whichever is wider. (Hz) @see data/kernels/fbs.json */
|
|
45
|
+
export const FBS_SAME_RING_HZ = 3;
|
|
46
|
+
/** The share of the higher frequency within which two readings are the same ringing frequency, when it is wider than FBS_SAME_RING_HZ: FFT bin spacing grows with frequency. @see data/kernels/fbs.json */
|
|
47
|
+
export const FBS_SAME_RING_SHARE = 0.015;
|
|
48
|
+
/** The clean hold, in seconds, before a live band's first release stage. (s) @see data/kernels/fbs.json */
|
|
49
|
+
export const FBS_DEFAULT_HOLD_SECONDS = 5;
|
|
50
|
+
/** How many bands one corrector may plant when nobody set its cap; a full pool plants nothing and says pool-full. @see data/kernels/fbs.json */
|
|
51
|
+
export const FBS_DEFAULT_MAX_AUTO_BANDS = 6;
|
|
52
|
+
/** The merge radius, in cents: a confirmed ring this close to a band already planted is that band's find, and plants nothing. (cents) @see data/kernels/fbs.json */
|
|
53
|
+
export const FBS_DEFAULT_MERGE_CENTS = 100;
|
|
54
|
+
/** How long a fully released find's re-clamp count is remembered, in seconds, so a chronic ringer re-plants with its doubled holds. (s) @see data/kernels/fbs.json */
|
|
55
|
+
export const FBS_DEFAULT_COOLDOWN_SECONDS = 600;
|
|
56
|
+
/** 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. @see data/kernels/fbs.json */
|
|
57
|
+
export const FBS_DEFAULT_NOTCH_Q = 116;
|
|
58
|
+
/** Released finds the ring memory holds at once. The console's list is unbounded and expires by FBS_DEFAULT_COOLDOWN_SECONDS; a full memory here forgets its oldest entry first, and counts it. @see data/kernels/fbs.json */
|
|
59
|
+
export const FBS_RING_MEMORY_SLOTS = 32;
|
|
19
60
|
/** The displays a panel description draws from a closed form, the kinds omx_curve_points answers: an EQ's magnitude response, x in Hz and y in dB, and a dynamics stage's static transfer curve, input dB to output dB. The wire spells each id in snake case (`eq_response`, `transfer_curve`), the description's own display word. @see data/primitives/curve.json */
|
|
20
61
|
export const CURVE_DISPLAYS = ['eqResponse', 'transferCurve'];
|
|
21
62
|
/** The panel families omx_curve_points draws, by the description's family word. `eq` draws an eq_response; the other four a transfer_curve, the family choosing the gain computer's mode: `dynamics`, `limiter` and `deesser` act ABOVE the threshold, `gate` BELOW it with the shifted knee of the gate's knee range. Any other family has no closed form here. @see data/primitives/curve.json */
|
|
@@ -24,9 +65,11 @@ export const CURVE_FAMILIES = ['eq', 'dynamics', 'limiter', 'gate', 'deesser'];
|
|
|
24
65
|
export const CURVE_ROLES = ['bandType', 'bandFreq', 'bandGain', 'bandQ', 'bandOn', 'hpfFreq', 'hpfSlope', 'hpfOn', 'lpfFreq', 'lpfSlope', 'lpfOn', 'threshold', 'ratio', 'knee', 'makeup', 'range', 'kneeStart', 'kneeEnd'];
|
|
25
66
|
/** The units a curve term's value may come in, the param-contract extension's unit tokens the served description gives a role. omx_curve_points converts once: `coef` to dB for a gain, `oct` to Q for a bandwidth, `khz` to Hz; a level in `db`, `dbfs`, `dbu` or `lufs` is read as dB from the threshold's own scale; `none` is a plain number, a switch or a choice; `ratio` a ratio. A unit its role does not accept is refused. @see data/primitives/curve.json */
|
|
26
67
|
export const CURVE_UNITS = ['hz', 'khz', 'db', 'dbfs', 'dbu', 'lufs', 'coef', 'oct', 'none', 'ratio'];
|
|
27
|
-
/** The shape of an EQ band, as the caller resolves it from the description: a `band_type` role's `shapes` list indexed by the control's choice value, or the fixed `shape` of a band no control selects. `off` is a band that is not drawn
|
|
28
|
-
export const CURVE_SHAPES = ['off', 'bell', 'lowshelf', 'highshelf', 'highpass', 'lowpass', 'notch', 'unshaped'];
|
|
29
|
-
/**
|
|
68
|
+
/** The shape of an EQ band, as the caller resolves it from the description: a `band_type` role's `shapes` list indexed by the control's choice value, or the fixed `shape` of a band no control selects. `off` is a band that is not drawn, and so is `unshaped`, spelt `-` on the wire, a choice value with no shape. The others design the band through omx_eq_design: a bell, the two shelves, the pass filters, the notch, and the first- and second-order allpasses, which draw what they run, 0 dB. @see data/primitives/curve.json */
|
|
69
|
+
export const CURVE_SHAPES = ['off', 'bell', 'lowshelf', 'highshelf', 'highpass', 'lowpass', 'notch', 'unshaped', 'allpass1', 'allpass2'];
|
|
70
|
+
/** Where an EQ band of a curve request comes from, as the console's strip EQ state says it (its BAND_ORIGINS): `user`, the operator's own band, and the bands a planter put there, `fbsFixed` and `fbsLive` (the feedback corrector's ring-out and show pools), `hrp` (the harmonic resonance processor's cuts) and `roomMode` (a room mode's correction), spelt `user`, `fbs-fixed`, `fbs-live`, `hrp` and `room-mode` on the wire. The sum ignores it: every drawn band is in the curve. A band whose origin is not `user` is answered as a mark (its frequency, depth, Q and origin), and a request that asks for it also gets the curve over the `user` bands alone. A plugin's descriptor carries no origin: a request with none draws no marks. @see data/primitives/curve.json */
|
|
71
|
+
export const CURVE_ORIGINS = ['user', 'fbsFixed', 'fbsLive', 'hrp', 'roomMode'];
|
|
72
|
+
/** What omx_curve_points answers in its code: `ok`, a curve; `kindUnknown`, a kind, family or head filter slope with no closed form; `termMissing`, a term the closed form has no default for is not in the request (a band's frequency and shape, a bell's or shelf's gain, a head filter's corner, and its slope unless it comes from the role's declared enumeration as dB per octave; threshold and ratio for dynamics and the de-esser, threshold for a limiter (its ratio is infinity, a hard corner), threshold, range and ratio for a gate; both ends of a gate's knee range or neither); `unitRefused`, a term in a unit its role does not accept; `valueNotFinite`, a value, the rate or an extent that is not finite, a rate that is not positive; `pointsRange`, grid points outside 2 to CURVE_POINTS_MAX (for an EQ, with three anchors a drawn band), a band index past what fits, or extents that bound nothing; `room`, a caller's buffers too small. Where omx-dsp declares a default the curve takes it: a band's Q is EQ_BAND_DEFAULTS q, clamped for its shape as clampEqQFor clamps it. No curve is drawn from a guess. @see data/primitives/curve.json */
|
|
30
73
|
export const CURVE_CODES = ['ok', 'kindUnknown', 'termMissing', 'unitRefused', 'valueNotFinite', 'pointsRange', 'room'];
|
|
31
74
|
/** The most points one curve carries, an EQ's band anchors included: a reply of x with four significant digits and y to 0.01 dB, about 13 bytes a point, fits the 4096-byte line a host's reply is built in. Every caller reads it here; it moves with that buffer, in this one place. @see data/primitives/curve.json */
|
|
32
75
|
export const CURVE_POINTS_MAX = 256;
|
|
@@ -44,10 +87,40 @@ export const LIN_TO_DB_FLOOR = {
|
|
|
44
87
|
lin: 1e-9,
|
|
45
88
|
db: -180,
|
|
46
89
|
};
|
|
90
|
+
/** A meter's view law, the same on every surface: the fill is linear in dB from `floorDb` (dBFS, an empty display) to 0 dBFS (a full one); a stepped display (an LED ladder) holds its count until the level moves `stepHysteresis` of a step past the count's own rounding edge; the peak marker falls `fallDbPerSecond` dB for each second elapsed at the view's draw tick, whatever the tick's rate, silence included. A host reads a plugin's held meter at `hostReadHz`; the console streams meter values at `streamHz`. dBFS, a fraction of a step, dB per second and Hz. @see data/primitives/meter.json */
|
|
91
|
+
export const METER_VIEW = {
|
|
92
|
+
floorDb: -60,
|
|
93
|
+
stepHysteresis: 0.25,
|
|
94
|
+
fallDbPerSecond: 18,
|
|
95
|
+
hostReadHz: 50,
|
|
96
|
+
streamHz: 20,
|
|
97
|
+
};
|
|
98
|
+
/** What a meter measures, as a plugin's descriptor and the panel description spell it: `level`, a signal level (its measurement one of METER_MEASUREMENTS), and `gainReduction`, the gain a dynamics stage takes off, dB at or below 0. The wire spells them `level` and `gain-reduction`. `rms`, `vu` and `ppm` are not kinds. @see data/primitives/meter.json */
|
|
99
|
+
export const METER_KINDS = ['level', 'gainReduction'];
|
|
100
|
+
/** The measurement of a `level` meter: the sample peak (`peak`, dBFS), the true peak (`truePeak`, dBTP), and the loudness measures of omx_loudness.h: momentary, short-term and integrated loudness (`lufsM`, `lufsS`, `lufsI`, LUFS) and the loudness range (`lra`, LU). The wire spells them `peak`, `true-peak`, `lufs-m`, `lufs-s`, `lufs-i` and `lra`. A foreign meter's measurement is null, never guessed. @see data/primitives/meter.json */
|
|
101
|
+
export const METER_MEASUREMENTS = ['peak', 'truePeak', 'lufsM', 'lufsS', 'lufsI', 'lra'];
|
|
102
|
+
/** The unit a meter's values are in, spelt as its label: dBFS for a sample peak, dBTP for a true peak, LUFS for a loudness, LU for a loudness range, dB for a gain reduction. The scale a surface draws is captioned with it. @see data/primitives/meter.json */
|
|
103
|
+
export const METER_UNITS = ['dbfs', 'dbtp', 'lufs', 'lu', 'db'];
|
|
104
|
+
/** The labels of METER_UNITS, in its order. @see data/primitives/meter.json */
|
|
105
|
+
export const METER_UNITS_LABELS = ['dBFS', 'dBTP', 'LUFS', 'LU', 'dB'];
|
|
106
|
+
/** What a subscriber that decimates a meter stream keeps of the frames it drops, one per kind in METER_KINDS order, as the engine's slot keeps between two reads: a `level` keeps the `peak` (the largest value), a `gainReduction` the `deepest` (the smallest dB). Never the newest. @see data/primitives/meter.json */
|
|
107
|
+
export const METER_DECIMATION = ['peak', 'deepest'];
|
|
47
108
|
/** The Q (resonance) extent of a parametric band. @see data/kernels/eq.json */
|
|
48
109
|
export const EQ_Q_RANGE = { min: 0.3, max: 8 };
|
|
49
110
|
/** The Q extent of a NOTCH band. Wider than EQ_Q_RANGE on purpose (#116, operator decision): an ultra-narrow surgical cut is the notch shape's whole point — the FBS ring-out pool plants dbx-AFS-style ring killers at Q ≈ 116 (~1/80 octave), inaudible on program yet fatal to a single ringing frequency. Gain-carrying shapes stay bounded at EQ_Q_RANGE — a Q-116 bell is a resonator, not an EQ move. @see data/kernels/eq.json */
|
|
50
111
|
export const EQ_NOTCH_Q_RANGE = { min: 0.3, max: 116 };
|
|
112
|
+
/** The parametric-band gain travel, in dB. The ± scalar `clampEqGain` enforces is READ off this (the engine derives its gain limit from `max`), so the bound is stated once and a surface cannot draw a wider knob than the clamp will honour. @see data/kernels/eq.json */
|
|
113
|
+
export const EQ_GAIN_RANGE = { min: -15, max: 15 };
|
|
114
|
+
/** The frequency band a parametric band can be dragged across. @see data/kernels/eq.json */
|
|
115
|
+
export const EQ_FREQ_RANGE = { min: 20, max: 20000 };
|
|
116
|
+
/** How many bands this corrector may plant at once (its pool), from one to the EQ's band count. An integer control. @see data/kernels/fbs.json */
|
|
117
|
+
export const FBS_BANDS_RANGE = { min: 1, max: 24 };
|
|
118
|
+
/** The clean hold, in seconds, before a live band's first release stage. @see data/kernels/fbs.json */
|
|
119
|
+
export const FBS_HOLD_RANGE = { min: 1, max: 300 };
|
|
120
|
+
/** The merge radius, in cents. An integer control. @see data/kernels/fbs.json */
|
|
121
|
+
export const FBS_MERGE_RANGE = { min: 0, max: 600 };
|
|
122
|
+
/** How long a released find's escalation is remembered, in seconds. An integer control. @see data/kernels/fbs.json */
|
|
123
|
+
export const FBS_COOLDOWN_RANGE = { min: 0, max: 7200 };
|
|
51
124
|
/** The travel of ratio, from its table COMP_LIMITS. @see data/kernels/comp.json */
|
|
52
125
|
export const COMP_RATIO_RANGE = { min: 1, max: 20 };
|
|
53
126
|
/** The travel of kneeDb, from its table COMP_LIMITS. @see data/kernels/comp.json */
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/** The pools: fixed (ring-out) and live, as OmxFbsPool numbers them. */
|
|
2
|
+
export type FbsPool = 'fixed' | 'live';
|
|
3
|
+
/** The console's FbsAction words, in OmxFbsAction's order. */
|
|
4
|
+
export declare const FBS_ACTIONS: readonly ["notched", "lifted", "pool-full", "re-armed", "easing", "rejected-edge"];
|
|
5
|
+
export type FbsAction = (typeof FBS_ACTIONS)[number];
|
|
6
|
+
/** The hold that never releases. */
|
|
7
|
+
export declare const FBS_HOLD_NEVER: "never";
|
|
8
|
+
/** The CURVE_ORIGINS wire words, by index. */
|
|
9
|
+
export declare const ORIGIN_WORDS: readonly string[];
|
|
10
|
+
/** The CURVE_SHAPES words, by index (the unshaped band is `-`). */
|
|
11
|
+
export declare const SHAPE_WORDS: readonly string[];
|
|
12
|
+
export declare const ORIGIN: {
|
|
13
|
+
readonly user: number;
|
|
14
|
+
readonly fbsFixed: number;
|
|
15
|
+
readonly fbsLive: number;
|
|
16
|
+
};
|
|
17
|
+
export declare const SHAPE: {
|
|
18
|
+
readonly off: number;
|
|
19
|
+
readonly bell: number;
|
|
20
|
+
readonly notch: number;
|
|
21
|
+
};
|
|
22
|
+
/** Slots one placement holds: the band cap's ceiling. */
|
|
23
|
+
export declare const FBS_PLACE_SLOTS: 24;
|
|
24
|
+
/** One report slot's six words, as omx_band_report.h lays them out. */
|
|
25
|
+
export interface BandReport {
|
|
26
|
+
readonly freqHz: number;
|
|
27
|
+
readonly depthDb: number;
|
|
28
|
+
readonly q: number;
|
|
29
|
+
readonly on: number;
|
|
30
|
+
readonly origin: number;
|
|
31
|
+
readonly shape: number;
|
|
32
|
+
}
|
|
33
|
+
/** One confirmed ring: the detector's frequency and depth. */
|
|
34
|
+
export interface FbsFind {
|
|
35
|
+
readonly freqHz: number;
|
|
36
|
+
readonly depthDb: number;
|
|
37
|
+
}
|
|
38
|
+
/** One action, with the slot it concerned (-1 for a refusal). */
|
|
39
|
+
export interface FbsEvent {
|
|
40
|
+
readonly action: FbsAction;
|
|
41
|
+
readonly freqHz: number;
|
|
42
|
+
readonly slot: number;
|
|
43
|
+
}
|
|
44
|
+
interface Slot {
|
|
45
|
+
freqHz: number;
|
|
46
|
+
gainDb: number;
|
|
47
|
+
q: number;
|
|
48
|
+
on: boolean;
|
|
49
|
+
origin: number;
|
|
50
|
+
shape: number;
|
|
51
|
+
seq: number;
|
|
52
|
+
live: boolean;
|
|
53
|
+
plantedDb: number;
|
|
54
|
+
lastRingMs: number;
|
|
55
|
+
stage: number;
|
|
56
|
+
dwellStartMs: number | null;
|
|
57
|
+
reclamps: number;
|
|
58
|
+
ramp: {
|
|
59
|
+
step: number;
|
|
60
|
+
stage: number;
|
|
61
|
+
fromDb: number;
|
|
62
|
+
toDb: number;
|
|
63
|
+
dueMs: number;
|
|
64
|
+
seq: number;
|
|
65
|
+
} | null;
|
|
66
|
+
}
|
|
67
|
+
/** The gain a band of `origin` may hold: fbs-* in [FBS_MAX_CUT_DB, 0] (NaN reads 0), every other origin in
|
|
68
|
+
* EQ_GAIN_RANGE (NaN stays NaN) — the strip store's arm. */
|
|
69
|
+
export declare function fbsGainCap(originIndex: number, db: number): number;
|
|
70
|
+
/** Two readings are the same ringing frequency: within FBS_SAME_RING_HZ or FBS_SAME_RING_SHARE of the higher. */
|
|
71
|
+
export declare function sameRingFreq(aHz: number, bHz: number): boolean;
|
|
72
|
+
/** omx_hrp_cents_between in float: `fabsf(1200 * log2f(a / b))`, 1e9 when either is not positive. */
|
|
73
|
+
export declare function fbsCents(aHz: number, bHz: number): number;
|
|
74
|
+
/** One corrector's placement: the console's FbsCorrector rules over fixed slots. */
|
|
75
|
+
export declare class FbsPlace {
|
|
76
|
+
pool: FbsPool;
|
|
77
|
+
holdS: number | typeof FBS_HOLD_NEVER;
|
|
78
|
+
maxBands: number;
|
|
79
|
+
notchQ: number;
|
|
80
|
+
mergeCents: number;
|
|
81
|
+
cooldownS: number;
|
|
82
|
+
nowMs: number;
|
|
83
|
+
memoryDropped: number;
|
|
84
|
+
protected slots: Slot[];
|
|
85
|
+
protected memory: Array<{
|
|
86
|
+
freqHz: number;
|
|
87
|
+
reclamps: number;
|
|
88
|
+
releasedMs: number;
|
|
89
|
+
}>;
|
|
90
|
+
protected seq: number;
|
|
91
|
+
protected timerSeq: number;
|
|
92
|
+
readonly log: FbsEvent[];
|
|
93
|
+
constructor(pool: FbsPool);
|
|
94
|
+
/** The arming values, each clamped as the console clamps it. */
|
|
95
|
+
set(holdS: number | typeof FBS_HOLD_NEVER, maxBands: number, notchQ: number, mergeCents: number, cooldownS: number): void;
|
|
96
|
+
/** The bands planted, fixed and live together. */
|
|
97
|
+
count(): number;
|
|
98
|
+
/** Slot k's six report words. */
|
|
99
|
+
report(k: number): BandReport;
|
|
100
|
+
/** The ramp steps due by `nowMs`, earliest first, ties in the order the ramps began. */
|
|
101
|
+
advance(nowMs: number): void;
|
|
102
|
+
/** One detector tick: the ramp steps due, a band per newly confirmed ring, then the clean holds. */
|
|
103
|
+
tick(nowMs: number, snapshotHz: readonly number[], confirmed: readonly FbsFind[]): void;
|
|
104
|
+
/** One find or another: the same-ring window, or the merge radius in cents (band first, find second). */
|
|
105
|
+
protected sameRegion(bandHz: number, findHz: number): boolean;
|
|
106
|
+
/** The pool a find goes to. */
|
|
107
|
+
protected poolOfFind(): FbsPool;
|
|
108
|
+
/** The gain cap the placement writes through. */
|
|
109
|
+
protected capGain(originIndex: number, db: number): number;
|
|
110
|
+
/** The stage a release eases to after `stage`. */
|
|
111
|
+
protected nextStage(stage: number): number;
|
|
112
|
+
/** Free slot k: it reports free and no other slot moves. */
|
|
113
|
+
protected release(k: number): void;
|
|
114
|
+
protected emit(action: FbsAction, freqHz: number, slot: number): void;
|
|
115
|
+
/** Occupied slots in plant order: the console's band order. */
|
|
116
|
+
protected bySeq(): number[];
|
|
117
|
+
protected correct(c: FbsFind): void;
|
|
118
|
+
protected holdSweep(snapshotHz: readonly number[]): void;
|
|
119
|
+
protected reArm(k: number): void;
|
|
120
|
+
protected beginStage(k: number, stage: number): void;
|
|
121
|
+
protected rampStep(k: number): void;
|
|
122
|
+
protected remember(freqHz: number, reclamps: number): void;
|
|
123
|
+
protected takeMemory(freqHz: number): number;
|
|
124
|
+
}
|
|
125
|
+
export {};
|