@openmixer/omx-dsp 0.0.0-stage → 0.26.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/dist/definitions.d.ts +4 -0
- package/dist/definitions.js +7 -0
- package/dist/eq.d.ts +3 -0
- package/dist/eq.js +9 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/rta.d.ts +11 -0
- package/dist/rta.js +19 -0
- package/dist/units.d.ts +33 -0
- package/dist/units.js +41 -0
- package/package.json +38 -4
- package/src/definitions.ts +9 -0
- package/src/eq.ts +10 -0
- package/src/index.ts +10 -0
- package/src/rta.ts +20 -0
- package/src/units.ts +45 -0
- package/README.md +0 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The RTA's target bin resolution — generated into `omx_contract_limits.h` as `OMX_RTA_TARGET_BIN_HZ`, which `mix_dsp.h` reads; the engine's conformance test reads it back from the header. (Hz) @see data/kernels/rta.json */
|
|
2
|
+
export declare const RTA_TARGET_BIN_HZ = 5.9;
|
|
3
|
+
/** The largest RTA FFT the native ring holds — generated into `omx_contract_limits.h` as `OMX_RTA_FFT_SIZE_MAX`. @see data/kernels/rta.json */
|
|
4
|
+
export declare const RTA_FFT_SIZE_MAX = 32768;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
// GENERATED by ts/tools/definitions.mjs from omx-dsp data/kernels/ - do not edit.
|
|
4
|
+
/** The RTA's target bin resolution — generated into `omx_contract_limits.h` as `OMX_RTA_TARGET_BIN_HZ`, which `mix_dsp.h` reads; the engine's conformance test reads it back from the header. (Hz) @see data/kernels/rta.json */
|
|
5
|
+
export const RTA_TARGET_BIN_HZ = 5.9;
|
|
6
|
+
/** The largest RTA FFT the native ring holds — generated into `omx_contract_limits.h` as `OMX_RTA_FFT_SIZE_MAX`. @see data/kernels/rta.json */
|
|
7
|
+
export const RTA_FFT_SIZE_MAX = 32768;
|
package/dist/eq.d.ts
ADDED
package/dist/eq.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The twin of omx_eq_design.h omx_eq_octaves_q, moved verbatim from the console (its catalog package). */
|
|
4
|
+
/** Bandwidth in octaves → Q (the cookbook relation). */
|
|
5
|
+
export function octavesToQ(octaves) {
|
|
6
|
+
const bw = Math.max(octaves, 0.05);
|
|
7
|
+
const t = Math.pow(2, bw);
|
|
8
|
+
return Math.sqrt(t) / (t - 1);
|
|
9
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openmixer/omx-dsp: the TypeScript twins of omx-dsp kernels, the ones that stay in TypeScript because doing
|
|
3
|
+
* the work in C would be silly (a display, a unit conversion a browser runs). Each is pinned to its kernel by an
|
|
4
|
+
* agreement test in test/ that feeds both the same grid.
|
|
5
|
+
*/
|
|
6
|
+
export { ANALYSIS_FLOOR_DB, dbToLinearGain, linearGainToDb, linearToDbFloored } from './units.js';
|
|
7
|
+
export { octavesToQ } from './eq.js';
|
|
8
|
+
export { fftSizeForRate } from './rta.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/**
|
|
4
|
+
* @openmixer/omx-dsp: the TypeScript twins of omx-dsp kernels, the ones that stay in TypeScript because doing
|
|
5
|
+
* the work in C would be silly (a display, a unit conversion a browser runs). Each is pinned to its kernel by an
|
|
6
|
+
* agreement test in test/ that feeds both the same grid.
|
|
7
|
+
*/
|
|
8
|
+
export { ANALYSIS_FLOOR_DB, dbToLinearGain, linearGainToDb, linearToDbFloored } from './units.js';
|
|
9
|
+
export { octavesToQ } from './eq.js';
|
|
10
|
+
export { fftSizeForRate } from './rta.js';
|
package/dist/rta.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The twin of omx_rta.h omx_rta_fft_size_for, moved verbatim from the console (its spectrum bands); the two limits are omx-dsp's own (data/kernels/rta.json). */
|
|
2
|
+
/**
|
|
3
|
+
* The RTA FFT length for `rate` — the TypeScript mirror of `mix_dsp.h`'s `omx_rta_fft_size_for`:
|
|
4
|
+
* the smallest power of two whose bins are at or under {@link RTA_TARGET_BIN_HZ} (44.1/48 kHz →
|
|
5
|
+
* 8192, 88.2/96 kHz → 16384, 176.4/192 kHz → 32768). Window TIME stays ~171 ms at every rate —
|
|
6
|
+
* pinning the length instead of deriving it was how moving the rig to 96 kHz silently halved the
|
|
7
|
+
* resolution (2026-09-17 declare-derive audit, F2). Every consumer of an offline/synth or a
|
|
8
|
+
* server RTA frame derives its window from the graph rate through this function rather than
|
|
9
|
+
* declaring one of its own.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fftSizeForRate(rate: number): number;
|
package/dist/rta.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The twin of omx_rta.h omx_rta_fft_size_for, moved verbatim from the console (its spectrum bands); the two limits are omx-dsp's own (data/kernels/rta.json). */
|
|
4
|
+
import { RTA_TARGET_BIN_HZ, RTA_FFT_SIZE_MAX } from './definitions.js';
|
|
5
|
+
/**
|
|
6
|
+
* The RTA FFT length for `rate` — the TypeScript mirror of `mix_dsp.h`'s `omx_rta_fft_size_for`:
|
|
7
|
+
* the smallest power of two whose bins are at or under {@link RTA_TARGET_BIN_HZ} (44.1/48 kHz →
|
|
8
|
+
* 8192, 88.2/96 kHz → 16384, 176.4/192 kHz → 32768). Window TIME stays ~171 ms at every rate —
|
|
9
|
+
* pinning the length instead of deriving it was how moving the rig to 96 kHz silently halved the
|
|
10
|
+
* resolution (2026-09-17 declare-derive audit, F2). Every consumer of an offline/synth or a
|
|
11
|
+
* server RTA frame derives its window from the graph rate through this function rather than
|
|
12
|
+
* declaring one of its own.
|
|
13
|
+
*/
|
|
14
|
+
export function fftSizeForRate(rate) {
|
|
15
|
+
let n = 2048;
|
|
16
|
+
while (n < RTA_FFT_SIZE_MAX && rate / n > RTA_TARGET_BIN_HZ)
|
|
17
|
+
n *= 2;
|
|
18
|
+
return n;
|
|
19
|
+
}
|
package/dist/units.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** The dB and linear-amplitude twins of omx_units.h (omx_db_to_lin, omx_lin_to_db, omx_lin_to_db_d), moved verbatim from the console (its output routes). */
|
|
2
|
+
/**
|
|
3
|
+
* dB → linear amplitude (0 dB → 1, −6 dB → ~0.501). The trim/fold gain the engine applies.
|
|
4
|
+
*
|
|
5
|
+
* `-Infinity` dB → 0 falls out of the exponential itself (`10 ** -Infinity === 0`), so
|
|
6
|
+
* callers need no silence guard of their own.
|
|
7
|
+
*/
|
|
8
|
+
export declare function dbToLinearGain(db: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* Linear amplitude → dB — the exact inverse of {@link dbToLinearGain}, and the reason this
|
|
11
|
+
* one exists: without it the inverse direction was hand-rolled at every call site, which is
|
|
12
|
+
* how three different silence conventions (`1e-12`, `1e-7`, `-60`) grew up elsewhere in the
|
|
13
|
+
* tree for what is nominally the same conversion.
|
|
14
|
+
*
|
|
15
|
+
* Silence and any non-positive amplitude read `-Infinity`, not NaN: `Math.log10` of a
|
|
16
|
+
* negative is NaN, and an amplitude below zero is a phase-inverted sample's magnitude
|
|
17
|
+
* mistake, not a level. Note this is the LEVEL conversion — an analyser floors its own
|
|
18
|
+
* spectrum at a chosen epsilon instead, deliberately, and should keep doing so.
|
|
19
|
+
*/
|
|
20
|
+
export declare function linearGainToDb(linear: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* The analysers' magnitude floor: an FFT bin or an envelope at exact zero reads −240 dB, below
|
|
23
|
+
* any real signal and finite for the growth and ratio arithmetic built on it (was the epsilon
|
|
24
|
+
* `1e-12` inside three analysers' logarithms).
|
|
25
|
+
*/
|
|
26
|
+
export declare const ANALYSIS_FLOOR_DB = -240;
|
|
27
|
+
/**
|
|
28
|
+
* Linear amplitude → dB, never below `floorDb` — the conversion for a site whose floor is
|
|
29
|
+
* deliberate (an analyser's magnitude, a plot's axis, a meter that must stay finite). The floor
|
|
30
|
+
* is a named dB value, never an epsilon hidden inside the logarithm (`Math.max(x, 1e-12)` is
|
|
31
|
+
* `linearToDbFloored(x, -240)`); silence reads `floorDb`, not `-Infinity`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function linearToDbFloored(linear: number, floorDb: number): number;
|
package/dist/units.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The dB and linear-amplitude twins of omx_units.h (omx_db_to_lin, omx_lin_to_db, omx_lin_to_db_d), moved verbatim from the console (its output routes). */
|
|
4
|
+
/**
|
|
5
|
+
* dB → linear amplitude (0 dB → 1, −6 dB → ~0.501). The trim/fold gain the engine applies.
|
|
6
|
+
*
|
|
7
|
+
* `-Infinity` dB → 0 falls out of the exponential itself (`10 ** -Infinity === 0`), so
|
|
8
|
+
* callers need no silence guard of their own.
|
|
9
|
+
*/
|
|
10
|
+
export function dbToLinearGain(db) {
|
|
11
|
+
return 10 ** (db / 20);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Linear amplitude → dB — the exact inverse of {@link dbToLinearGain}, and the reason this
|
|
15
|
+
* one exists: without it the inverse direction was hand-rolled at every call site, which is
|
|
16
|
+
* how three different silence conventions (`1e-12`, `1e-7`, `-60`) grew up elsewhere in the
|
|
17
|
+
* tree for what is nominally the same conversion.
|
|
18
|
+
*
|
|
19
|
+
* Silence and any non-positive amplitude read `-Infinity`, not NaN: `Math.log10` of a
|
|
20
|
+
* negative is NaN, and an amplitude below zero is a phase-inverted sample's magnitude
|
|
21
|
+
* mistake, not a level. Note this is the LEVEL conversion — an analyser floors its own
|
|
22
|
+
* spectrum at a chosen epsilon instead, deliberately, and should keep doing so.
|
|
23
|
+
*/
|
|
24
|
+
export function linearGainToDb(linear) {
|
|
25
|
+
return linear <= 0 ? -Infinity : 20 * Math.log10(linear);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The analysers' magnitude floor: an FFT bin or an envelope at exact zero reads −240 dB, below
|
|
29
|
+
* any real signal and finite for the growth and ratio arithmetic built on it (was the epsilon
|
|
30
|
+
* `1e-12` inside three analysers' logarithms).
|
|
31
|
+
*/
|
|
32
|
+
export const ANALYSIS_FLOOR_DB = -240;
|
|
33
|
+
/**
|
|
34
|
+
* Linear amplitude → dB, never below `floorDb` — the conversion for a site whose floor is
|
|
35
|
+
* deliberate (an analyser's magnitude, a plot's axis, a meter that must stay finite). The floor
|
|
36
|
+
* is a named dB value, never an epsilon hidden inside the logarithm (`Math.max(x, 1e-12)` is
|
|
37
|
+
* `linearToDbFloored(x, -240)`); silence reads `floorDb`, not `-Infinity`.
|
|
38
|
+
*/
|
|
39
|
+
export function linearToDbFloored(linear, floorDb) {
|
|
40
|
+
return Math.max(floorDb, linearGainToDb(linear));
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmixer/omx-dsp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.26.0",
|
|
4
|
+
"description": "The TypeScript twins of omx-dsp kernels, each pinned to its C kernel by an agreement test",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "GPL-3.0-or-later",
|
|
7
|
+
"author": "Pau Aliagas <linuxnow@gmail.com>",
|
|
8
|
+
"homepage": "https://github.com/FreeMixer/omx-dsp",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/FreeMixer/omx-dsp.git",
|
|
12
|
+
"directory": "ts"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/",
|
|
23
|
+
"src/"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"test": "node tools/definitions.mjs --check && tsc -p tsconfig.json && node --test test/*.test.mjs",
|
|
28
|
+
"prepack": "tsc -p tsconfig.json"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"typescript": "^5.6.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22.18"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public",
|
|
38
|
+
"registry": "https://registry.npmjs.org/"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
// GENERATED by ts/tools/definitions.mjs from omx-dsp data/kernels/ - do not edit.
|
|
4
|
+
|
|
5
|
+
/** The RTA's target bin resolution — generated into `omx_contract_limits.h` as `OMX_RTA_TARGET_BIN_HZ`, which `mix_dsp.h` reads; the engine's conformance test reads it back from the header. (Hz) @see data/kernels/rta.json */
|
|
6
|
+
export const RTA_TARGET_BIN_HZ = 5.9;
|
|
7
|
+
|
|
8
|
+
/** The largest RTA FFT the native ring holds — generated into `omx_contract_limits.h` as `OMX_RTA_FFT_SIZE_MAX`. @see data/kernels/rta.json */
|
|
9
|
+
export const RTA_FFT_SIZE_MAX = 32768;
|
package/src/eq.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The twin of omx_eq_design.h omx_eq_octaves_q, moved verbatim from the console (its catalog package). */
|
|
4
|
+
|
|
5
|
+
/** Bandwidth in octaves → Q (the cookbook relation). */
|
|
6
|
+
export function octavesToQ(octaves: number): number {
|
|
7
|
+
const bw = Math.max(octaves, 0.05);
|
|
8
|
+
const t = Math.pow(2, bw);
|
|
9
|
+
return Math.sqrt(t) / (t - 1);
|
|
10
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/**
|
|
4
|
+
* @openmixer/omx-dsp: the TypeScript twins of omx-dsp kernels, the ones that stay in TypeScript because doing
|
|
5
|
+
* the work in C would be silly (a display, a unit conversion a browser runs). Each is pinned to its kernel by an
|
|
6
|
+
* agreement test in test/ that feeds both the same grid.
|
|
7
|
+
*/
|
|
8
|
+
export { ANALYSIS_FLOOR_DB, dbToLinearGain, linearGainToDb, linearToDbFloored } from './units.js';
|
|
9
|
+
export { octavesToQ } from './eq.js';
|
|
10
|
+
export { fftSizeForRate } from './rta.js';
|
package/src/rta.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The twin of omx_rta.h omx_rta_fft_size_for, moved verbatim from the console (its spectrum bands); the two limits are omx-dsp's own (data/kernels/rta.json). */
|
|
4
|
+
|
|
5
|
+
import { RTA_TARGET_BIN_HZ, RTA_FFT_SIZE_MAX } from './definitions.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The RTA FFT length for `rate` — the TypeScript mirror of `mix_dsp.h`'s `omx_rta_fft_size_for`:
|
|
9
|
+
* the smallest power of two whose bins are at or under {@link RTA_TARGET_BIN_HZ} (44.1/48 kHz →
|
|
10
|
+
* 8192, 88.2/96 kHz → 16384, 176.4/192 kHz → 32768). Window TIME stays ~171 ms at every rate —
|
|
11
|
+
* pinning the length instead of deriving it was how moving the rig to 96 kHz silently halved the
|
|
12
|
+
* resolution (2026-09-17 declare-derive audit, F2). Every consumer of an offline/synth or a
|
|
13
|
+
* server RTA frame derives its window from the graph rate through this function rather than
|
|
14
|
+
* declaring one of its own.
|
|
15
|
+
*/
|
|
16
|
+
export function fftSizeForRate(rate: number): number {
|
|
17
|
+
let n = 2048;
|
|
18
|
+
while (n < RTA_FFT_SIZE_MAX && rate / n > RTA_TARGET_BIN_HZ) n *= 2;
|
|
19
|
+
return n;
|
|
20
|
+
}
|
package/src/units.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/** The dB and linear-amplitude twins of omx_units.h (omx_db_to_lin, omx_lin_to_db, omx_lin_to_db_d), moved verbatim from the console (its output routes). */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* dB → linear amplitude (0 dB → 1, −6 dB → ~0.501). The trim/fold gain the engine applies.
|
|
7
|
+
*
|
|
8
|
+
* `-Infinity` dB → 0 falls out of the exponential itself (`10 ** -Infinity === 0`), so
|
|
9
|
+
* callers need no silence guard of their own.
|
|
10
|
+
*/
|
|
11
|
+
export function dbToLinearGain(db: number): number {
|
|
12
|
+
return 10 ** (db / 20);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Linear amplitude → dB — the exact inverse of {@link dbToLinearGain}, and the reason this
|
|
17
|
+
* one exists: without it the inverse direction was hand-rolled at every call site, which is
|
|
18
|
+
* how three different silence conventions (`1e-12`, `1e-7`, `-60`) grew up elsewhere in the
|
|
19
|
+
* tree for what is nominally the same conversion.
|
|
20
|
+
*
|
|
21
|
+
* Silence and any non-positive amplitude read `-Infinity`, not NaN: `Math.log10` of a
|
|
22
|
+
* negative is NaN, and an amplitude below zero is a phase-inverted sample's magnitude
|
|
23
|
+
* mistake, not a level. Note this is the LEVEL conversion — an analyser floors its own
|
|
24
|
+
* spectrum at a chosen epsilon instead, deliberately, and should keep doing so.
|
|
25
|
+
*/
|
|
26
|
+
export function linearGainToDb(linear: number): number {
|
|
27
|
+
return linear <= 0 ? -Infinity : 20 * Math.log10(linear);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The analysers' magnitude floor: an FFT bin or an envelope at exact zero reads −240 dB, below
|
|
32
|
+
* any real signal and finite for the growth and ratio arithmetic built on it (was the epsilon
|
|
33
|
+
* `1e-12` inside three analysers' logarithms).
|
|
34
|
+
*/
|
|
35
|
+
export const ANALYSIS_FLOOR_DB = -240;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Linear amplitude → dB, never below `floorDb` — the conversion for a site whose floor is
|
|
39
|
+
* deliberate (an analyser's magnitude, a plot's axis, a meter that must stay finite). The floor
|
|
40
|
+
* is a named dB value, never an epsilon hidden inside the logarithm (`Math.max(x, 1e-12)` is
|
|
41
|
+
* `linearToDbFloored(x, -240)`); silence reads `floorDb`, not `-Infinity`.
|
|
42
|
+
*/
|
|
43
|
+
export function linearToDbFloored(linear: number, floorDb: number): number {
|
|
44
|
+
return Math.max(floorDb, linearGainToDb(linear));
|
|
45
|
+
}
|
package/README.md
DELETED