@aeonentertainment/mixer 0.1.0 → 0.3.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 +7 -2
- package/dist/index.d.mts +21 -7
- package/dist/index.mjs +8 -3
- package/native/binding/index.d.ts +16 -5
- package/native/binding/index.darwin-arm64.node +0 -0
- package/native/binding/index.darwin-x64.node +0 -0
- package/native/binding/index.js +1 -0
- package/native/binding/index.linux-arm64-gnu.node +0 -0
- package/native/binding/index.linux-x64-gnu.node +0 -0
- package/native/binding/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Each [release](https://github.com/aeonentertainment/aeon-mixer/releases) carries
|
|
|
15
15
|
Depend on its URL, and the lockfile pins its hash:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install https://github.com/aeonentertainment/aeon-mixer/releases/download/v0.
|
|
18
|
+
npm install https://github.com/aeonentertainment/aeon-mixer/releases/download/v0.3.0/aeonentertainment-mixer-0.3.0.tgz
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Use
|
|
@@ -51,13 +51,18 @@ await engine.close();
|
|
|
51
51
|
- **Slots** are the mics: 8 per engine by default, up to 16 with `openEngine({ slots })`. `rtp`
|
|
52
52
|
takes Opus over UDP from a phone or mediasoup, `l16` takes raw PCM over loopback from a house
|
|
53
53
|
mic, and `push` takes PCM the host hands to `mixer.push`. Each slot has gain, pan, mute, solo,
|
|
54
|
-
reverb, a pitch reading
|
|
54
|
+
reverb, a pitch reading, a melody guide and pitch correction toward it, whose delay `stats()`
|
|
55
|
+
reports.
|
|
55
56
|
- **The backing** is any format Symphonia decodes, resampled to 48 kHz. The armed key and speed
|
|
56
57
|
are rendered before `start` resolves. Live, it supports seek, pause, resume, a key change and
|
|
57
58
|
stem gains, and `start`, `seek` and `resume` report the position the lyric clock follows.
|
|
58
59
|
- **`rtpReturn`** sends the mix to mediasoup's PlainTransport as 10 ms Opus with in-band FEC.
|
|
59
60
|
`host` is an IP address, never a name.
|
|
60
61
|
- **Reactions** play through `engine.reactions.play` between songs and during them.
|
|
62
|
+
- **The timer engine**, `openEngine({ output: { timer: true } })`, is for a box with no sound
|
|
63
|
+
card. It opens no device; its own thread renders a block at each deadline on the OS's
|
|
64
|
+
monotonic clock, and the mix leaves on `rtpReturn`. `measure-clock` prints its timing:
|
|
65
|
+
`cargo run --release -p devices --bin measure-clock` in `native/`.
|
|
61
66
|
- **The offline engine**, `openEngine({ output: { offline: true } })`, opens no device and
|
|
62
67
|
renders only when its caller runs `engine.pump(blocks)`. The tests run on it.
|
|
63
68
|
|
package/dist/index.d.mts
CHANGED
|
@@ -19,7 +19,7 @@ declare class Engine$1 {
|
|
|
19
19
|
*/
|
|
20
20
|
createMixer(kinds: Array<string>, rtpReturn?: RtpReturnInput | undefined | null): Mixer$1;
|
|
21
21
|
get output(): OutputInfo$1;
|
|
22
|
-
/** The outputs this OS offers, the default marked. Empty on the offline
|
|
22
|
+
/** The outputs this OS offers, the default marked. Empty on the offline and timer clocks. */
|
|
23
23
|
outputs(): Array<OutputEntry>;
|
|
24
24
|
/** Offline clock only: renders `blocks` blocks and returns them as interleaved stereo. */
|
|
25
25
|
pump(blocks: number): Float32Array;
|
|
@@ -72,7 +72,7 @@ declare class Mixer$1 {
|
|
|
72
72
|
* recording it for null.
|
|
73
73
|
*/
|
|
74
74
|
recordSlot(index: number, path?: string | undefined | null): void;
|
|
75
|
-
/** Every slot's ingest counters, as the audio thread last published them. */
|
|
75
|
+
/** Every slot's ingest counters and corrector delay, as the audio thread last published them. */
|
|
76
76
|
stats(): Array<SlotStatsInfo>;
|
|
77
77
|
/** The return stream's counters, or null for a mixer without one. */
|
|
78
78
|
returnStats(): RtpReturnStats | null;
|
|
@@ -144,9 +144,8 @@ interface NoteInput {
|
|
|
144
144
|
endFrame: number;
|
|
145
145
|
}
|
|
146
146
|
interface OpenOptions {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
/** An id from `outputs`, or the default output. */
|
|
147
|
+
clock: 'offline' | 'timer' | 'device';
|
|
148
|
+
/** A device clock's output: an id from `outputs`, or the default output. */
|
|
150
149
|
device?: string;
|
|
151
150
|
periodFrames: number;
|
|
152
151
|
/** The jitter buffer's playout delay for every `rtp` and `l16` slot. */
|
|
@@ -199,6 +198,8 @@ interface SlotStatsInfo {
|
|
|
199
198
|
concealed: number;
|
|
200
199
|
resyncs: number;
|
|
201
200
|
jitterMs: number;
|
|
201
|
+
correctorDelayMs: number;
|
|
202
|
+
correctorMaxDelayMs: number;
|
|
202
203
|
}
|
|
203
204
|
interface StemGainsInput {
|
|
204
205
|
instrumental: number;
|
|
@@ -211,9 +212,15 @@ type Capability = "guideVocal" | "key" | "speed" | "seek" | "shortVersion" | "pa
|
|
|
211
212
|
type IngestKind = "rtp" | "l16" | "push";
|
|
212
213
|
type StemKind = "instrumental" | "guideVocals";
|
|
213
214
|
interface OpenEngineOptions {
|
|
215
|
+
/**
|
|
216
|
+
* A device; `timer` for a box with no sound card, whose own thread renders on the OS's clock
|
|
217
|
+
* and whose mix leaves only on a mixer's `rtpReturn`; `offline` for tests, which pump it.
|
|
218
|
+
*/
|
|
214
219
|
output: {
|
|
215
220
|
device?: string;
|
|
216
221
|
periodFrames?: 64 | 128;
|
|
222
|
+
} | {
|
|
223
|
+
timer: true;
|
|
217
224
|
} | {
|
|
218
225
|
offline: true;
|
|
219
226
|
};
|
|
@@ -285,6 +292,13 @@ interface SlotStats {
|
|
|
285
292
|
concealed: number;
|
|
286
293
|
resyncs: number;
|
|
287
294
|
jitterMs: number;
|
|
295
|
+
/**
|
|
296
|
+
* How far the corrector holds this slot's voice now; 0 with correction off. It moves with the
|
|
297
|
+
* voice and one read is a sample of it, so show it and never add it to a budget or a clock.
|
|
298
|
+
*/
|
|
299
|
+
correctorDelayMs: number;
|
|
300
|
+
/** The most that delay can reach; 0 with correction off. It holds still, so a budget adds this. */
|
|
301
|
+
correctorMaxDelayMs: number;
|
|
288
302
|
}
|
|
289
303
|
type EngineEvents = {
|
|
290
304
|
fault: (error: Error) => void;
|
|
@@ -424,8 +438,8 @@ export declare class Mixer {
|
|
|
424
438
|
/** An engine on the test clock. Its caller pumps it; nothing plays. */
|
|
425
439
|
type OfflineEngine = Engine & Required<Pick<Engine, "pump">>;
|
|
426
440
|
/**
|
|
427
|
-
* Opens the engine for the life of the process: the device,
|
|
428
|
-
* silent graph until a mixer starts.
|
|
441
|
+
* Opens the engine for the life of the process: the device, the timer clock on a box with no
|
|
442
|
+
* sound card, or the offline driver, running the silent graph until a mixer starts.
|
|
429
443
|
*/
|
|
430
444
|
export declare function openEngine(options: OpenEngineOptions & {
|
|
431
445
|
output: {
|
package/dist/index.mjs
CHANGED
|
@@ -546,16 +546,21 @@ var Engine = class {
|
|
|
546
546
|
};
|
|
547
547
|
if ("offline" in options.output) {
|
|
548
548
|
this.#native = new NativeEngine({
|
|
549
|
-
|
|
549
|
+
clock: "offline",
|
|
550
550
|
periodFrames: 128,
|
|
551
551
|
playoutDelayFrames
|
|
552
552
|
}, deliver);
|
|
553
553
|
this.pump = (blocks) => this.#native.pump(integerIn("blocks", blocks, 1, 1 << 20));
|
|
554
|
-
} else {
|
|
554
|
+
} else if ("timer" in options.output) this.#native = new NativeEngine({
|
|
555
|
+
clock: "timer",
|
|
556
|
+
periodFrames: 128,
|
|
557
|
+
playoutDelayFrames
|
|
558
|
+
}, deliver);
|
|
559
|
+
else {
|
|
555
560
|
const { device, periodFrames = 128 } = options.output;
|
|
556
561
|
if (periodFrames !== 64 && periodFrames !== 128) throw new RangeError(`periodFrames must be 64 or 128, got ${String(periodFrames)}`);
|
|
557
562
|
this.#native = new NativeEngine({
|
|
558
|
-
|
|
563
|
+
clock: "device",
|
|
559
564
|
periodFrames,
|
|
560
565
|
playoutDelayFrames,
|
|
561
566
|
...device === void 0 ? {} : { device }
|
|
@@ -31,7 +31,7 @@ export declare class Engine {
|
|
|
31
31
|
*/
|
|
32
32
|
createMixer(kinds: Array<string>, rtpReturn?: RtpReturnInput | undefined | null): Mixer
|
|
33
33
|
get output(): OutputInfo
|
|
34
|
-
/** The outputs this OS offers, the default marked. Empty on the offline
|
|
34
|
+
/** The outputs this OS offers, the default marked. Empty on the offline and timer clocks. */
|
|
35
35
|
outputs(): Array<OutputEntry>
|
|
36
36
|
/** Offline clock only: renders `blocks` blocks and returns them as interleaved stereo. */
|
|
37
37
|
pump(blocks: number): Float32Array
|
|
@@ -85,7 +85,7 @@ export declare class Mixer {
|
|
|
85
85
|
* recording it for null.
|
|
86
86
|
*/
|
|
87
87
|
recordSlot(index: number, path?: string | undefined | null): void
|
|
88
|
-
/** Every slot's ingest counters, as the audio thread last published them. */
|
|
88
|
+
/** Every slot's ingest counters and corrector delay, as the audio thread last published them. */
|
|
89
89
|
stats(): Array<SlotStatsInfo>
|
|
90
90
|
/** The return stream's counters, or null for a mixer without one. */
|
|
91
91
|
returnStats(): RtpReturnStats | null
|
|
@@ -105,6 +105,16 @@ export interface BackingInput {
|
|
|
105
105
|
speed: number
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/** What drives the audio thread. */
|
|
109
|
+
export declare const enum ClockKind {
|
|
110
|
+
/** The offline driver, pumped from JavaScript. */
|
|
111
|
+
Offline = 'offline',
|
|
112
|
+
/** The timer clock, for a box with no sound card: no device, and nothing to pump. */
|
|
113
|
+
Timer = 'timer',
|
|
114
|
+
/** An OS output. */
|
|
115
|
+
Device = 'device',
|
|
116
|
+
}
|
|
117
|
+
|
|
108
118
|
export interface CorrectorInput {
|
|
109
119
|
enabled: boolean
|
|
110
120
|
strength: number
|
|
@@ -137,9 +147,8 @@ export interface NoteInput {
|
|
|
137
147
|
}
|
|
138
148
|
|
|
139
149
|
export interface OpenOptions {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/** An id from `outputs`, or the default output. */
|
|
150
|
+
clock: 'offline' | 'timer' | 'device'
|
|
151
|
+
/** A device clock's output: an id from `outputs`, or the default output. */
|
|
143
152
|
device?: string
|
|
144
153
|
periodFrames: number
|
|
145
154
|
/** The jitter buffer's playout delay for every `rtp` and `l16` slot. */
|
|
@@ -199,6 +208,8 @@ export interface SlotStatsInfo {
|
|
|
199
208
|
concealed: number
|
|
200
209
|
resyncs: number
|
|
201
210
|
jitterMs: number
|
|
211
|
+
correctorDelayMs: number
|
|
212
|
+
correctorMaxDelayMs: number
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
export interface StemGainsInput {
|
|
Binary file
|
|
Binary file
|
package/native/binding/index.js
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeonentertainment/mixer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Low-latency LAN audio mixer for Aeon Karaoke: phone and house mics, a backing track, one mix to the room.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/aeonentertainment/aeon-mixer/issues"
|