@buffered-audio/nodes 0.18.1 → 0.19.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 +47 -59
- package/dist/chunk-YJWZP2OD.js +2067 -0
- package/dist/cli.js +21 -16
- package/dist/index.d.ts +143 -221
- package/dist/index.js +1098 -3253
- package/dist/nlm-worker.d.ts +2 -0
- package/dist/nlm-worker.js +12 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -438,99 +438,87 @@ Write audio to a file
|
|
|
438
438
|
|
|
439
439
|
## Creating Nodes
|
|
440
440
|
|
|
441
|
-
Each node has two parts: a **Node** (inert descriptor) and a **Stream** (stateful runtime instance).
|
|
441
|
+
Each node has two parts: a **Node** (inert descriptor) and a **Stream** (stateful runtime instance). The node is pure static declaration — `nodeName`, `description`, `schema`, `Stream`, plus `packageName`/`packageVersion` — and carries no per-render state. The executor constructs one stream per node per render.
|
|
442
442
|
|
|
443
|
-
|
|
443
|
+
Transforms extend one of two stream bases from `@buffered-audio/core`, picked by whether the node needs the whole signal (or fixed-size blocks) before it can produce output:
|
|
444
|
+
|
|
445
|
+
- **`UnbufferedTransformStream`** — per-block streaming (gain, pan, dither). One input block in, zero or more output blocks out.
|
|
446
|
+
- **`BufferedTransformStream`** — measure-then-apply and windowed DSP (normalize, loudness). Accumulates into a `BlockBuffer` sized by `blockSize` (default `WHOLE_FILE`), then serves.
|
|
444
447
|
|
|
445
448
|
### Stream Hooks
|
|
446
449
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
- **`
|
|
450
|
-
- **`
|
|
450
|
+
All output hooks are generators — `yield` a block to emit it, yield nothing to drop it. Production is paced by downstream demand (one `yield` served per pull).
|
|
451
|
+
|
|
452
|
+
- **`_transform`** — the core hook. Unbuffered: `*_transform(block)` runs once per input block. Buffered: `async *_transform(buffered: BlockBuffer)` runs once per assembled block (and once at end of stream with the trailing partial); walk the buffer with `buffered.iterate(frames)` and `yield` output.
|
|
453
|
+
- **`_prepare(block)`** (buffered only) — a length-preserving transform on each incoming block before it is buffered. Use it to fold a streaming measurement (peak, LUFS) on the way in.
|
|
454
|
+
- **`_flush()`** — a generator emitting trailing output at graceful end of stream, after the final `_transform`.
|
|
455
|
+
- **`_setup(context)`** — context-dependent initialization (subprocess, ONNX session, FFT workspace). Runs before piping.
|
|
456
|
+
- **`_pipe(input)`** — maps the input readable to the output; override to compose inner streams (e.g. wrap the transform in resamplers).
|
|
457
|
+
- **`_destroy()`** — cleanup on every termination path (graceful end, error, cancel), invoked at most once. Close file handles, free native resources, release ONNX sessions.
|
|
458
|
+
|
|
459
|
+
Report progress with `this.emitProgress(phase, framesDone, framesTotal?)` (pace it with `createProgressGate`) and structured logs with `this.log(message, data?, level?)`.
|
|
451
460
|
|
|
452
|
-
###
|
|
461
|
+
### blockSize Modes (buffered)
|
|
453
462
|
|
|
454
|
-
- `
|
|
455
|
-
- `N` — block mode.
|
|
456
|
-
- `WHOLE_FILE` (`Infinity`) — full-file. All audio is buffered before `_process` and `_unbuffer` run.
|
|
463
|
+
- `WHOLE_FILE` (`Infinity`, the default) — one firing at end of stream with the whole signal.
|
|
464
|
+
- `N` — block mode. `_transform` fires each time the buffer fills to `N` frames (short only at end of stream).
|
|
457
465
|
|
|
458
466
|
### Example: Normalize
|
|
459
467
|
|
|
460
468
|
```ts
|
|
461
469
|
import { z } from "zod";
|
|
462
|
-
import { BufferedTransformStream, TransformNode, WHOLE_FILE, type
|
|
470
|
+
import { BufferedTransformStream, TransformNode, WHOLE_FILE, type Block, type BlockBuffer, type TransformNodeProperties } from "@buffered-audio/core";
|
|
463
471
|
|
|
464
|
-
const schema = z.object({
|
|
472
|
+
export const schema = z.object({
|
|
465
473
|
ceiling: z.number().min(0).max(1).multipleOf(0.01).default(1.0).describe("Ceiling"),
|
|
466
474
|
});
|
|
467
475
|
|
|
468
|
-
interface NormalizeProperties extends z.infer<typeof schema>, TransformNodeProperties {}
|
|
469
|
-
|
|
470
|
-
class NormalizeStream extends BufferedTransformStream<NormalizeProperties> {
|
|
471
|
-
private peak = 0;
|
|
472
|
-
private scale = 1;
|
|
473
|
-
|
|
474
|
-
override async _buffer(chunk: AudioChunk, buffer: ChunkBuffer): Promise<void> {
|
|
475
|
-
await super._buffer(chunk, buffer);
|
|
476
|
+
export interface NormalizeProperties extends z.infer<typeof schema>, TransformNodeProperties {}
|
|
476
477
|
|
|
477
|
-
|
|
478
|
-
|
|
478
|
+
export class NormalizeStream extends BufferedTransformStream<NormalizeNode> {
|
|
479
|
+
override blockSize = WHOLE_FILE;
|
|
479
480
|
|
|
480
|
-
|
|
481
|
-
const absolute = Math.abs(channel[si] ?? 0);
|
|
481
|
+
private peak = 0;
|
|
482
482
|
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
override _prepare(block: Block): Block {
|
|
484
|
+
for (const channel of block.samples) {
|
|
485
|
+
for (const sample of channel) this.peak = Math.max(this.peak, Math.abs(sample));
|
|
485
486
|
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
override _process(_buffer: ChunkBuffer): void {
|
|
489
|
-
const raw = this.peak === 0 ? 1 : this.properties.ceiling / this.peak;
|
|
490
487
|
|
|
491
|
-
|
|
488
|
+
return block;
|
|
492
489
|
}
|
|
493
490
|
|
|
494
|
-
override
|
|
495
|
-
|
|
491
|
+
override async *_transform(buffered: BlockBuffer): AsyncGenerator<Block> {
|
|
492
|
+
const scale = this.peak > 0 ? this.properties.ceiling / this.peak : 1;
|
|
496
493
|
|
|
497
|
-
const
|
|
498
|
-
|
|
494
|
+
for await (const block of buffered.iterate(44100)) {
|
|
495
|
+
if (scale === 1) {
|
|
496
|
+
yield block;
|
|
499
497
|
|
|
500
|
-
|
|
501
|
-
scaled[index] = (channel[index] ?? 0) * this.scale;
|
|
498
|
+
continue;
|
|
502
499
|
}
|
|
503
500
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
501
|
+
yield {
|
|
502
|
+
samples: block.samples.map((channel) => channel.map((sample) => sample * scale)),
|
|
503
|
+
offset: block.offset,
|
|
504
|
+
sampleRate: block.sampleRate,
|
|
505
|
+
bitDepth: block.bitDepth,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
-
class NormalizeNode extends TransformNode<NormalizeProperties> {
|
|
511
|
+
export class NormalizeNode extends TransformNode<NormalizeProperties> {
|
|
512
512
|
static override readonly nodeName = "Normalize";
|
|
513
|
-
static override readonly packageName = "buffered-audio
|
|
514
|
-
static override readonly
|
|
513
|
+
static override readonly packageName = "@buffered-audio/nodes";
|
|
514
|
+
static override readonly packageVersion = "0.8.0";
|
|
515
|
+
static override readonly description = "Adjust peak or loudness level to a target ceiling";
|
|
515
516
|
static override readonly schema = schema;
|
|
516
|
-
|
|
517
|
-
override readonly type = ["buffered-audio-node", "transform", "normalize"] as const;
|
|
518
|
-
|
|
519
|
-
constructor(properties: NormalizeProperties) {
|
|
520
|
-
super({ bufferSize: WHOLE_FILE, latency: WHOLE_FILE, ...properties });
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
override createStream(): NormalizeStream {
|
|
524
|
-
return new NormalizeStream({ ...this.properties, bufferSize: this.bufferSize, overlap: this.properties.overlap ?? 0 });
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
override clone(overrides?: Partial<NormalizeProperties>): NormalizeNode {
|
|
528
|
-
return new NormalizeNode({ ...this.properties, previousProperties: this.properties, ...overrides });
|
|
529
|
-
}
|
|
517
|
+
static override readonly Stream = NormalizeStream;
|
|
530
518
|
}
|
|
531
519
|
|
|
532
520
|
export function normalize(options?: { ceiling?: number; id?: string }): NormalizeNode {
|
|
533
|
-
return new NormalizeNode(
|
|
521
|
+
return new NormalizeNode(options ?? {});
|
|
534
522
|
}
|
|
535
523
|
```
|
|
536
524
|
|