@buffered-audio/nodes 0.20.0 → 0.22.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 CHANGED
@@ -43,47 +43,7 @@ await source.render();
43
43
 
44
44
  ## CLI
45
45
 
46
- ### `process`
47
-
48
- Run pipelines from TypeScript files. The file's default export must be a `SourceNode`.
49
-
50
- ```bash
51
- npx @buffered-audio/nodes process --pipeline pipeline.ts
52
- ```
53
-
54
- ```ts
55
- // pipeline.ts
56
- import { chain, read, normalize, trim, write } from "@buffered-audio/nodes";
57
-
58
- export default chain(read("input.wav"), normalize(), trim({ threshold: -60 }), write("output.wav"));
59
- ```
60
-
61
- ### `render`
62
-
63
- Render a `.bag` (Buffered Audio Graph) file. BAG files are JSON-serialized graph definitions.
64
-
65
- ```bash
66
- npx @buffered-audio/nodes render pipeline.bag
67
- ```
68
-
69
- | Flag | Description |
70
- | --------------------------- | ----------------------------------------------------------- |
71
- | `--chunk-size <samples>` | Chunk size in samples |
72
- | `--high-water-mark <count>` | Stream backpressure high water mark |
73
- | `--param <name=value>` | Bind a `{{name}}` template placeholder (repeatable) |
74
-
75
- #### Template parameters
76
-
77
- String values in a bag's node `parameters` may contain `{{name}}` placeholders. Each `--param name=value` binds one for that render; the same bag renders different inputs and outputs without editing the file. Every placeholder must be bound, and every `--param` must match a placeholder, or the render fails before any audio work.
78
-
79
- ```json
80
- { "id": "a", "packageName": "@buffered-audio/nodes", "packageVersion": "0.16.0", "nodeName": "Read", "parameters": { "path": "{{episode}}/raw.wav" } }
81
- { "id": "z", "packageName": "@buffered-audio/nodes", "packageVersion": "0.16.0", "nodeName": "Write", "parameters": { "path": "{{episode}}/master.wav" } }
82
- ```
83
-
84
- ```bash
85
- npx @buffered-audio/nodes render master.bag --param episode=./e260
86
- ```
46
+ Render `.bag` files and run pipelines from the command line with [`@buffered-audio/cli`](https://www.npmjs.com/package/@buffered-audio/cli).
87
47
 
88
48
  ## Nodes
89
49
 
@@ -438,7 +398,7 @@ Write audio to a file
438
398
 
439
399
  ## Creating Nodes
440
400
 
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.
401
+ 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` — and carries no per-render state. The executor constructs one stream per node per render.
442
402
 
443
403
  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
404
 
@@ -511,7 +471,6 @@ export class NormalizeStream extends BufferedTransformStream<NormalizeNode> {
511
471
  export class NormalizeNode extends TransformNode<NormalizeProperties> {
512
472
  static override readonly nodeName = "Normalize";
513
473
  static override readonly packageName = "@buffered-audio/nodes";
514
- static override readonly packageVersion = "0.8.0";
515
474
  static override readonly description = "Adjust peak or loudness level to a target ceiling";
516
475
  static override readonly schema = schema;
517
476
  static override readonly Stream = NormalizeStream;
package/dist/index.d.ts CHANGED
@@ -27,7 +27,6 @@ declare class ReadFfmpegStream extends BufferedSourceStream<ReadFfmpegNode> {
27
27
  declare class ReadFfmpegNode extends SourceNode<ReadFfmpegProperties> {
28
28
  static readonly nodeName = "Read FFmpeg";
29
29
  static readonly packageName: string;
30
- static readonly packageVersion: string;
31
30
  static readonly description = "Read audio from a file using FFmpeg";
32
31
  static readonly schema: z.ZodObject<{
33
32
  path: z.ZodDefault<z.ZodString>;
@@ -62,7 +61,6 @@ declare class ReadWavStream extends BufferedSourceStream<ReadWavNode> {
62
61
  declare class ReadWavNode extends SourceNode<ReadWavProperties> {
63
62
  static readonly nodeName = "Read WAV";
64
63
  static readonly packageName: string;
65
- static readonly packageVersion: string;
66
64
  static readonly description = "Read audio from a WAV file";
67
65
  static readonly schema: z.ZodObject<{
68
66
  path: z.ZodDefault<z.ZodString>;
@@ -118,7 +116,6 @@ declare class LoudnessStatsStream extends BufferedTargetStream<LoudnessStatsNode
118
116
  declare class LoudnessStatsNode extends TargetNode<LoudnessStatsProperties> {
119
117
  static readonly nodeName = "Loudness Stats";
120
118
  static readonly packageName: string;
121
- static readonly packageVersion: string;
122
119
  static readonly description = "Measure integrated loudness, true peak, and loudness range per EBU R128, plus an amplitude-distribution histogram";
123
120
  static readonly schema: z.ZodObject<{
124
121
  bucketCount: z.ZodDefault<z.ZodNumber>;
@@ -176,7 +173,6 @@ declare class SpectrogramStream extends BufferedTargetStream<SpectrogramNode> {
176
173
  declare class SpectrogramNode extends TargetNode<SpectrogramProperties> {
177
174
  static readonly nodeName = "Spectrogram";
178
175
  static readonly packageName: string;
179
- static readonly packageVersion: string;
180
176
  static readonly description = "Generate spectrogram visualization data";
181
177
  static readonly schema: z.ZodObject<{
182
178
  outputPath: z.ZodDefault<z.ZodString>;
@@ -227,7 +223,6 @@ declare class WaveformStream extends BufferedTargetStream<WaveformNode> {
227
223
  declare class WaveformNode extends TargetNode<WaveformProperties> {
228
224
  static readonly nodeName = "Waveform";
229
225
  static readonly packageName: string;
230
- static readonly packageVersion: string;
231
226
  static readonly description = "Generate waveform visualization data";
232
227
  static readonly schema: z.ZodObject<{
233
228
  outputPath: z.ZodDefault<z.ZodString>;
@@ -275,7 +270,6 @@ declare class WriteStream extends BufferedTargetStream<WriteNode> {
275
270
  declare class WriteNode extends TargetNode<WriteProperties> {
276
271
  static readonly nodeName = "Write";
277
272
  static readonly packageName: string;
278
- static readonly packageVersion: string;
279
273
  static readonly description = "Write audio to a file";
280
274
  static readonly schema: z.ZodObject<{
281
275
  path: z.ZodDefault<z.ZodString>;
@@ -328,7 +322,6 @@ declare class CutStream extends UnbufferedTransformStream<CutNode> {
328
322
  declare class CutNode extends TransformNode<CutProperties> {
329
323
  static readonly nodeName = "Cut";
330
324
  static readonly packageName: string;
331
- static readonly packageVersion: string;
332
325
  static readonly description = "Remove a region of audio";
333
326
  static readonly schema: z.ZodObject<{
334
327
  regions: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -355,7 +348,6 @@ declare class DitherStream extends UnbufferedTransformStream<DitherNode> {
355
348
  declare class DitherNode extends TransformNode<DitherProperties> {
356
349
  static readonly nodeName = "Dither";
357
350
  static readonly packageName: string;
358
- static readonly packageVersion: string;
359
351
  static readonly description = "Add shaped noise to reduce quantization distortion";
360
352
  static readonly schema: z.ZodObject<{
361
353
  bitDepth: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<16>, z.ZodLiteral<24>]>>;
@@ -382,7 +374,6 @@ declare class NormalizeStream extends BufferedTransformStream<NormalizeNode> {
382
374
  declare class NormalizeNode extends TransformNode<NormalizeProperties> {
383
375
  static readonly nodeName = "Normalize";
384
376
  static readonly packageName: string;
385
- static readonly packageVersion: string;
386
377
  static readonly description = "Adjust peak or loudness level to a target ceiling";
387
378
  static readonly schema: z.ZodObject<{
388
379
  ceiling: z.ZodDefault<z.ZodNumber>;
@@ -412,7 +403,6 @@ declare class PadStream extends UnbufferedTransformStream<PadNode> {
412
403
  declare class PadNode extends TransformNode<PadProperties> {
413
404
  static readonly nodeName = "Pad";
414
405
  static readonly packageName: string;
415
- static readonly packageVersion: string;
416
406
  static readonly description = "Add silence to start or end of audio";
417
407
  static readonly schema: z.ZodObject<{
418
408
  before: z.ZodDefault<z.ZodNumber>;
@@ -441,7 +431,6 @@ declare class PhaseStream extends UnbufferedTransformStream<PhaseNode> {
441
431
  declare class PhaseNode extends TransformNode<PhaseProperties> {
442
432
  static readonly nodeName = "Phase";
443
433
  static readonly packageName: string;
444
- static readonly packageVersion: string;
445
434
  static readonly description = "Invert or rotate signal phase";
446
435
  static readonly schema: z.ZodObject<{
447
436
  invert: z.ZodDefault<z.ZodBoolean>;
@@ -465,7 +454,6 @@ declare class ReverseStream extends BufferedTransformStream {
465
454
  declare class ReverseNode extends TransformNode {
466
455
  static readonly nodeName = "Reverse";
467
456
  static readonly packageName: string;
468
- static readonly packageVersion: string;
469
457
  static readonly description = "Reverse audio playback direction";
470
458
  static readonly schema: z.ZodObject<{}, z.core.$strip>;
471
459
  static readonly Stream: typeof ReverseStream;
@@ -492,7 +480,6 @@ declare class SpliceStream extends UnbufferedTransformStream<SpliceNode> {
492
480
  declare class SpliceNode extends TransformNode<SpliceProperties> {
493
481
  static readonly nodeName = "Splice";
494
482
  static readonly packageName: string;
495
- static readonly packageVersion: string;
496
483
  static readonly description = "Replace a region of audio with processed content";
497
484
  static readonly schema: z.ZodObject<{
498
485
  insertPath: z.ZodDefault<z.ZodString>;
@@ -523,7 +510,6 @@ declare class TrimStream extends BufferedTransformStream<TrimNode> {
523
510
  declare class TrimNode extends TransformNode<TrimProperties> {
524
511
  static readonly nodeName = "Trim";
525
512
  static readonly packageName: string;
526
- static readonly packageVersion: string;
527
513
  static readonly description = "Remove silence from start and end";
528
514
  static readonly schema: z.ZodObject<{
529
515
  threshold: z.ZodDefault<z.ZodNumber>;
@@ -547,7 +533,6 @@ declare class DownmixMonoStream extends UnbufferedTransformStream {
547
533
  declare class DownmixMonoNode extends TransformNode {
548
534
  static readonly nodeName = "Downmix Mono";
549
535
  static readonly packageName: string;
550
- static readonly packageVersion: string;
551
536
  static readonly description = "Mix all input channels to a single mono channel by averaging";
552
537
  static readonly schema: z.ZodObject<{}, z.core.$strip>;
553
538
  static readonly Stream: typeof DownmixMonoStream;
@@ -567,7 +552,6 @@ declare class DuplicateChannelsStream extends UnbufferedTransformStream<Duplicat
567
552
  declare class DuplicateChannelsNode extends TransformNode<DuplicateChannelsProperties> {
568
553
  static readonly nodeName = "Duplicate Channels";
569
554
  static readonly packageName: string;
570
- static readonly packageVersion: string;
571
555
  static readonly description = "Duplicate a mono signal into multiple identical output channels; requires exactly 1 input channel, throws otherwise";
572
556
  static readonly schema: z.ZodObject<{
573
557
  channels: z.ZodDefault<z.ZodNumber>;
@@ -590,7 +574,6 @@ declare class GainStream extends UnbufferedTransformStream<GainNode> {
590
574
  declare class GainNode extends TransformNode<GainProperties> {
591
575
  static readonly nodeName = "Gain";
592
576
  static readonly packageName: string;
593
- static readonly packageVersion: string;
594
577
  static readonly description = "Adjust signal level by a fixed amount in dB";
595
578
  static readonly schema: z.ZodObject<{
596
579
  gain: z.ZodDefault<z.ZodNumber>;
@@ -613,7 +596,6 @@ declare class PanStream extends UnbufferedTransformStream<PanNode> {
613
596
  declare class PanNode extends TransformNode<PanProperties> {
614
597
  static readonly nodeName = "Pan";
615
598
  static readonly packageName: string;
616
- static readonly packageVersion: string;
617
599
  static readonly description = "Position mono signal in stereo field or adjust stereo balance; throws for inputs with more than 2 channels";
618
600
  static readonly schema: z.ZodObject<{
619
601
  pan: z.ZodDefault<z.ZodNumber>;
@@ -654,7 +636,6 @@ declare class FfmpegStream<P extends FfmpegProperties = FfmpegProperties> extend
654
636
  declare class FfmpegNode<P extends FfmpegProperties = FfmpegProperties> extends TransformNode<P> {
655
637
  static readonly nodeName: string;
656
638
  static readonly packageName: string;
657
- static readonly packageVersion: string;
658
639
  static readonly description: string;
659
640
  static readonly schema: z.ZodType;
660
641
  static readonly Stream: typeof FfmpegStream;
@@ -703,7 +684,6 @@ declare class LoudnessTargetStream extends BufferedTransformStream<LoudnessTarge
703
684
  declare class LoudnessTargetNode extends TransformNode<LoudnessTargetProperties> {
704
685
  static readonly nodeName = "Loudness Target";
705
686
  static readonly packageName: string;
706
- static readonly packageVersion: string;
707
687
  static readonly description = "Peak-aware content-adaptive curve fitting (LUFS, true-peak, LRA) via a single combined gain envelope with a peak-respecting two-stage smoother. The upper-arm peak anchor jointly iterates with the body gain to land both LUFS and true-peak targets in one envelope.";
708
688
  static readonly schema: z.ZodObject<{
709
689
  targetLufs: z.ZodDefault<z.ZodNumber>;
@@ -747,7 +727,6 @@ declare class LoudnessNormalizeStream extends BufferedTransformStream<LoudnessNo
747
727
  declare class LoudnessNormalizeNode extends TransformNode<LoudnessNormalizeProperties> {
748
728
  static readonly nodeName = "Loudness Normalize";
749
729
  static readonly packageName: string;
750
- static readonly packageVersion: string;
751
730
  static readonly description = "Measure integrated loudness (BS.1770) and apply a single linear gain to hit a target LUFS \u2014 no limiting, no dynamics";
752
731
  static readonly schema: z.ZodObject<{
753
732
  target: z.ZodDefault<z.ZodNumber>;
@@ -774,7 +753,6 @@ declare class TruePeakNormalizeStream extends BufferedTransformStream<TruePeakNo
774
753
  declare class TruePeakNormalizeNode extends TransformNode<TruePeakNormalizeProperties> {
775
754
  static readonly nodeName = "True Peak Normalize";
776
755
  static readonly packageName: string;
777
- static readonly packageVersion: string;
778
756
  static readonly description = "Measure source true peak (4\u00D7 upsampled, BS.1770-4 style) and apply a single linear gain to hit a target dBTP";
779
757
  static readonly schema: z.ZodObject<{
780
758
  target: z.ZodDefault<z.ZodNumber>;
@@ -807,7 +785,6 @@ declare class CrestReduceStream extends BufferedTransformStream<CrestReduceNode>
807
785
  declare class CrestReduceNode extends TransformNode<CrestReduceProperties> {
808
786
  static readonly nodeName = "Crest Reduce";
809
787
  static readonly packageName: string;
810
- static readonly packageVersion: string;
811
788
  static readonly description = "Content-adaptive, magnitude-preserving, phase-only crest-factor reducer \u2014 a pre-limiter headroom stage that rearranges signal phase to flatten true-peak excursions without changing the magnitude spectrum, never increasing crest factor";
812
789
  static readonly schema: z.ZodObject<{
813
790
  smoothing: z.ZodDefault<z.ZodNumber>;
@@ -861,7 +838,6 @@ declare class DeBleedStream extends BufferedTransformStream<DeBleedNode> {
861
838
  declare class DeBleedNode extends TransformNode<DeBleedProperties> {
862
839
  static readonly nodeName = "De-Bleed Adaptive";
863
840
  static readonly packageName: string;
864
- static readonly packageVersion: string;
865
841
  static readonly description = "Adaptive (MEF FDAF Kalman + MWF + MSAD) reference-based microphone bleed reduction. Stages 1+2 are MEF Meyer-Elshamy-Fingscheidt 2020; Stage 3 is Lukin-Todd 2D NLM+DFTT post-filter.";
866
842
  static readonly schema: z.ZodObject<{
867
843
  references: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -918,7 +894,6 @@ declare class DeepFilterNet3Stream extends BufferedTransformStream<DeepFilterNet
918
894
  declare class DeepFilterNet3Node extends TransformNode<DeepFilterNet3Properties> {
919
895
  static readonly nodeName = "DeepFilterNet3 (Denoiser)";
920
896
  static readonly packageName: string;
921
- static readonly packageVersion: string;
922
897
  static readonly description = "Remove background noise from speech using DeepFilterNet3 (48 kHz full-band CRN)";
923
898
  static readonly schema: z.ZodObject<{
924
899
  modelPath: z.ZodDefault<z.ZodString>;
@@ -961,7 +936,6 @@ declare class DtlnStream extends BufferedTransformStream<DtlnNode> {
961
936
  declare class DtlnNode extends TransformNode<DtlnProperties> {
962
937
  static readonly nodeName = "DTLN (Denoiser)";
963
938
  static readonly packageName: string;
964
- static readonly packageVersion: string;
965
939
  static readonly description = "Remove background noise from speech using DTLN neural network";
966
940
  static readonly schema: z.ZodObject<{
967
941
  modelPath1: z.ZodDefault<z.ZodString>;
@@ -1010,7 +984,6 @@ declare class HtdemucsStream extends BufferedTransformStream<HtdemucsNode> {
1010
984
  declare class HtdemucsNode extends TransformNode<HtdemucsProperties> {
1011
985
  static readonly nodeName = "HTDemucs (Stem Separator)";
1012
986
  static readonly packageName: string;
1013
- static readonly packageVersion: string;
1014
987
  static readonly description = "Rebalance stem volumes using HTDemucs source separation";
1015
988
  static readonly schema: z.ZodObject<{
1016
989
  modelPath: z.ZodDefault<z.ZodString>;
@@ -1049,7 +1022,6 @@ declare class KimVocal2Stream extends BufferedTransformStream<KimVocal2Node> {
1049
1022
  declare class KimVocal2Node extends TransformNode<KimVocal2Properties> {
1050
1023
  static readonly nodeName = "Kim Vocal 2 (Stem Separator)";
1051
1024
  static readonly packageName: string;
1052
- static readonly packageVersion: string;
1053
1025
  static readonly description = "Isolate dialogue from background using MDX-Net vocal separation";
1054
1026
  static readonly schema: z.ZodObject<{
1055
1027
  modelPath: z.ZodDefault<z.ZodString>;
@@ -1093,7 +1065,6 @@ declare class Vst3Stream<P extends Vst3Properties = Vst3Properties> extends Buff
1093
1065
  declare class Vst3Node<P extends Vst3Properties = Vst3Properties> extends TransformNode<P> {
1094
1066
  static readonly nodeName: string;
1095
1067
  static readonly packageName: string;
1096
- static readonly packageVersion: string;
1097
1068
  static readonly description: string;
1098
1069
  static readonly schema: z.ZodType;
1099
1070
  static readonly Stream: typeof Vst3Stream;
package/dist/index.js CHANGED
@@ -16714,7 +16714,7 @@ __export2(core_exports22, {
16714
16714
  parse: () => parse3,
16715
16715
  parseAsync: () => parseAsync3,
16716
16716
  prettifyError: () => prettifyError2,
16717
- process: () => process3,
16717
+ process: () => process22,
16718
16718
  regexes: () => regexes_exports2,
16719
16719
  registry: () => registry2,
16720
16720
  safeDecode: () => safeDecode3,
@@ -26989,7 +26989,7 @@ function initializeContext2(params) {
26989
26989
  external: params?.external ?? void 0
26990
26990
  };
26991
26991
  }
26992
- function process3(schema28, ctx, _params = { path: [], schemaPath: [] }) {
26992
+ function process22(schema28, ctx, _params = { path: [], schemaPath: [] }) {
26993
26993
  var _a22;
26994
26994
  const def = schema28._zod.def;
26995
26995
  const seen = ctx.seen.get(schema28);
@@ -27026,7 +27026,7 @@ function process3(schema28, ctx, _params = { path: [], schemaPath: [] }) {
27026
27026
  if (parent) {
27027
27027
  if (!result.ref)
27028
27028
  result.ref = parent;
27029
- process3(parent, ctx, params);
27029
+ process22(parent, ctx, params);
27030
27030
  ctx.seen.get(parent).isParent = true;
27031
27031
  }
27032
27032
  }
@@ -27306,14 +27306,14 @@ function isTransforming2(_schema, _ctx) {
27306
27306
  }
27307
27307
  var createToJSONSchemaMethod2 = (schema28, processors = {}) => (params) => {
27308
27308
  const ctx = initializeContext2({ ...params, processors });
27309
- process3(schema28, ctx);
27309
+ process22(schema28, ctx);
27310
27310
  extractDefs2(ctx, schema28);
27311
27311
  return finalize2(ctx, schema28);
27312
27312
  };
27313
27313
  var createStandardJSONSchemaMethod2 = (schema28, io, processors = {}) => (params) => {
27314
27314
  const { libraryOptions, target } = params ?? {};
27315
27315
  const ctx = initializeContext2({ ...libraryOptions ?? {}, target, io, processors });
27316
- process3(schema28, ctx);
27316
+ process22(schema28, ctx);
27317
27317
  extractDefs2(ctx, schema28);
27318
27318
  return finalize2(ctx, schema28);
27319
27319
  };
@@ -27567,7 +27567,7 @@ var arrayProcessor2 = (schema28, ctx, _json, params) => {
27567
27567
  if (typeof maximum === "number")
27568
27568
  json22.maxItems = maximum;
27569
27569
  json22.type = "array";
27570
- json22.items = process3(def.element, ctx, { ...params, path: [...params.path, "items"] });
27570
+ json22.items = process22(def.element, ctx, { ...params, path: [...params.path, "items"] });
27571
27571
  };
27572
27572
  var objectProcessor2 = (schema28, ctx, _json, params) => {
27573
27573
  const json22 = _json;
@@ -27576,7 +27576,7 @@ var objectProcessor2 = (schema28, ctx, _json, params) => {
27576
27576
  json22.properties = {};
27577
27577
  const shape = def.shape;
27578
27578
  for (const key in shape) {
27579
- json22.properties[key] = process3(shape[key], ctx, {
27579
+ json22.properties[key] = process22(shape[key], ctx, {
27580
27580
  ...params,
27581
27581
  path: [...params.path, "properties", key]
27582
27582
  });
@@ -27599,7 +27599,7 @@ var objectProcessor2 = (schema28, ctx, _json, params) => {
27599
27599
  if (ctx.io === "output")
27600
27600
  json22.additionalProperties = false;
27601
27601
  } else if (def.catchall) {
27602
- json22.additionalProperties = process3(def.catchall, ctx, {
27602
+ json22.additionalProperties = process22(def.catchall, ctx, {
27603
27603
  ...params,
27604
27604
  path: [...params.path, "additionalProperties"]
27605
27605
  });
@@ -27608,7 +27608,7 @@ var objectProcessor2 = (schema28, ctx, _json, params) => {
27608
27608
  var unionProcessor2 = (schema28, ctx, json22, params) => {
27609
27609
  const def = schema28._zod.def;
27610
27610
  const isExclusive = def.inclusive === false;
27611
- const options = def.options.map((x, i) => process3(x, ctx, {
27611
+ const options = def.options.map((x, i) => process22(x, ctx, {
27612
27612
  ...params,
27613
27613
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
27614
27614
  }));
@@ -27620,11 +27620,11 @@ var unionProcessor2 = (schema28, ctx, json22, params) => {
27620
27620
  };
27621
27621
  var intersectionProcessor2 = (schema28, ctx, json22, params) => {
27622
27622
  const def = schema28._zod.def;
27623
- const a = process3(def.left, ctx, {
27623
+ const a = process22(def.left, ctx, {
27624
27624
  ...params,
27625
27625
  path: [...params.path, "allOf", 0]
27626
27626
  });
27627
- const b = process3(def.right, ctx, {
27627
+ const b = process22(def.right, ctx, {
27628
27628
  ...params,
27629
27629
  path: [...params.path, "allOf", 1]
27630
27630
  });
@@ -27641,11 +27641,11 @@ var tupleProcessor2 = (schema28, ctx, _json, params) => {
27641
27641
  json22.type = "array";
27642
27642
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
27643
27643
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
27644
- const prefixItems = def.items.map((x, i) => process3(x, ctx, {
27644
+ const prefixItems = def.items.map((x, i) => process22(x, ctx, {
27645
27645
  ...params,
27646
27646
  path: [...params.path, prefixPath, i]
27647
27647
  }));
27648
- const rest = def.rest ? process3(def.rest, ctx, {
27648
+ const rest = def.rest ? process22(def.rest, ctx, {
27649
27649
  ...params,
27650
27650
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
27651
27651
  }) : null;
@@ -27685,7 +27685,7 @@ var recordProcessor2 = (schema28, ctx, _json, params) => {
27685
27685
  const keyBag = keyType._zod.bag;
27686
27686
  const patterns = keyBag?.patterns;
27687
27687
  if (def.mode === "loose" && patterns && patterns.size > 0) {
27688
- const valueSchema = process3(def.valueType, ctx, {
27688
+ const valueSchema = process22(def.valueType, ctx, {
27689
27689
  ...params,
27690
27690
  path: [...params.path, "patternProperties", "*"]
27691
27691
  });
@@ -27695,12 +27695,12 @@ var recordProcessor2 = (schema28, ctx, _json, params) => {
27695
27695
  }
27696
27696
  } else {
27697
27697
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
27698
- json22.propertyNames = process3(def.keyType, ctx, {
27698
+ json22.propertyNames = process22(def.keyType, ctx, {
27699
27699
  ...params,
27700
27700
  path: [...params.path, "propertyNames"]
27701
27701
  });
27702
27702
  }
27703
- json22.additionalProperties = process3(def.valueType, ctx, {
27703
+ json22.additionalProperties = process22(def.valueType, ctx, {
27704
27704
  ...params,
27705
27705
  path: [...params.path, "additionalProperties"]
27706
27706
  });
@@ -27715,7 +27715,7 @@ var recordProcessor2 = (schema28, ctx, _json, params) => {
27715
27715
  };
27716
27716
  var nullableProcessor2 = (schema28, ctx, json22, params) => {
27717
27717
  const def = schema28._zod.def;
27718
- const inner = process3(def.innerType, ctx, params);
27718
+ const inner = process22(def.innerType, ctx, params);
27719
27719
  const seen = ctx.seen.get(schema28);
27720
27720
  if (ctx.target === "openapi-3.0") {
27721
27721
  seen.ref = def.innerType;
@@ -27726,20 +27726,20 @@ var nullableProcessor2 = (schema28, ctx, json22, params) => {
27726
27726
  };
27727
27727
  var nonoptionalProcessor2 = (schema28, ctx, _json, params) => {
27728
27728
  const def = schema28._zod.def;
27729
- process3(def.innerType, ctx, params);
27729
+ process22(def.innerType, ctx, params);
27730
27730
  const seen = ctx.seen.get(schema28);
27731
27731
  seen.ref = def.innerType;
27732
27732
  };
27733
27733
  var defaultProcessor2 = (schema28, ctx, json22, params) => {
27734
27734
  const def = schema28._zod.def;
27735
- process3(def.innerType, ctx, params);
27735
+ process22(def.innerType, ctx, params);
27736
27736
  const seen = ctx.seen.get(schema28);
27737
27737
  seen.ref = def.innerType;
27738
27738
  json22.default = JSON.parse(JSON.stringify(def.defaultValue));
27739
27739
  };
27740
27740
  var prefaultProcessor2 = (schema28, ctx, json22, params) => {
27741
27741
  const def = schema28._zod.def;
27742
- process3(def.innerType, ctx, params);
27742
+ process22(def.innerType, ctx, params);
27743
27743
  const seen = ctx.seen.get(schema28);
27744
27744
  seen.ref = def.innerType;
27745
27745
  if (ctx.io === "input")
@@ -27747,7 +27747,7 @@ var prefaultProcessor2 = (schema28, ctx, json22, params) => {
27747
27747
  };
27748
27748
  var catchProcessor2 = (schema28, ctx, json22, params) => {
27749
27749
  const def = schema28._zod.def;
27750
- process3(def.innerType, ctx, params);
27750
+ process22(def.innerType, ctx, params);
27751
27751
  const seen = ctx.seen.get(schema28);
27752
27752
  seen.ref = def.innerType;
27753
27753
  let catchValue;
@@ -27761,32 +27761,32 @@ var catchProcessor2 = (schema28, ctx, json22, params) => {
27761
27761
  var pipeProcessor2 = (schema28, ctx, _json, params) => {
27762
27762
  const def = schema28._zod.def;
27763
27763
  const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
27764
- process3(innerType, ctx, params);
27764
+ process22(innerType, ctx, params);
27765
27765
  const seen = ctx.seen.get(schema28);
27766
27766
  seen.ref = innerType;
27767
27767
  };
27768
27768
  var readonlyProcessor2 = (schema28, ctx, json22, params) => {
27769
27769
  const def = schema28._zod.def;
27770
- process3(def.innerType, ctx, params);
27770
+ process22(def.innerType, ctx, params);
27771
27771
  const seen = ctx.seen.get(schema28);
27772
27772
  seen.ref = def.innerType;
27773
27773
  json22.readOnly = true;
27774
27774
  };
27775
27775
  var promiseProcessor2 = (schema28, ctx, _json, params) => {
27776
27776
  const def = schema28._zod.def;
27777
- process3(def.innerType, ctx, params);
27777
+ process22(def.innerType, ctx, params);
27778
27778
  const seen = ctx.seen.get(schema28);
27779
27779
  seen.ref = def.innerType;
27780
27780
  };
27781
27781
  var optionalProcessor2 = (schema28, ctx, _json, params) => {
27782
27782
  const def = schema28._zod.def;
27783
- process3(def.innerType, ctx, params);
27783
+ process22(def.innerType, ctx, params);
27784
27784
  const seen = ctx.seen.get(schema28);
27785
27785
  seen.ref = def.innerType;
27786
27786
  };
27787
27787
  var lazyProcessor2 = (schema28, ctx, _json, params) => {
27788
27788
  const innerType = schema28._zod.innerType;
27789
- process3(innerType, ctx, params);
27789
+ process22(innerType, ctx, params);
27790
27790
  const seen = ctx.seen.get(schema28);
27791
27791
  seen.ref = innerType;
27792
27792
  };
@@ -27838,7 +27838,7 @@ function toJSONSchema2(input, params) {
27838
27838
  const defs = {};
27839
27839
  for (const entry of registry22._idmap.entries()) {
27840
27840
  const [_, schema28] = entry;
27841
- process3(schema28, ctx2);
27841
+ process22(schema28, ctx2);
27842
27842
  }
27843
27843
  const schemas = {};
27844
27844
  const external = {
@@ -27861,7 +27861,7 @@ function toJSONSchema2(input, params) {
27861
27861
  return { schemas };
27862
27862
  }
27863
27863
  const ctx = initializeContext2({ ...params, processors: allProcessors2 });
27864
- process3(input, ctx);
27864
+ process22(input, ctx);
27865
27865
  extractDefs2(ctx, input);
27866
27866
  return finalize2(ctx, input);
27867
27867
  }
@@ -27917,7 +27917,7 @@ var JSONSchemaGenerator2 = class {
27917
27917
  * This must be called before emit().
27918
27918
  */
27919
27919
  process(schema28, _params = { path: [], schemaPath: [] }) {
27920
- return process3(schema28, this.ctx, _params);
27920
+ return process22(schema28, this.ctx, _params);
27921
27921
  }
27922
27922
  /**
27923
27923
  * Emit the final JSON Schema after processing.
@@ -29850,7 +29850,6 @@ var BufferedAudioNode = class {
29850
29850
  return this.properties.children ?? [];
29851
29851
  }
29852
29852
  };
29853
- BufferedAudioNode.packageVersion = "0.0.0";
29854
29853
  BufferedAudioNode.apiVersion = 1;
29855
29854
  BufferedAudioNode.description = "";
29856
29855
  BufferedAudioNode.schema = external_exports2.object({});
@@ -30022,8 +30021,14 @@ var RenderJob = class {
30022
30021
  } else {
30023
30022
  this.streamsMap.set(node, [stream]);
30024
30023
  }
30024
+ const effective = this.effectiveChildren(node.children, path2);
30025
+ if (effective.length === 0 && typeof node.to === "function") {
30026
+ const nodeName = node.constructor.nodeName;
30027
+ const suffix = node.id !== void 0 ? `#${node.id}` : "";
30028
+ throw new Error(`Graph leaf "${nodeName}"${suffix} is not a target \u2014 every path must end in a target node`);
30029
+ }
30025
30030
  const children = [];
30026
- for (const child of this.effectiveChildren(node.children, path2)) {
30031
+ for (const child of effective) {
30027
30032
  children.push(this.build(child, path2));
30028
30033
  }
30029
30034
  path2.delete(node);
@@ -30113,7 +30118,6 @@ var TransformNode = class extends BufferedAudioNode {
30113
30118
  var graphNodeSchema = external_exports2.object({
30114
30119
  id: external_exports2.string().min(1),
30115
30120
  packageName: external_exports2.string().min(1),
30116
- packageVersion: external_exports2.string().min(1),
30117
30121
  nodeName: external_exports2.string().min(1),
30118
30122
  parameters: external_exports2.record(external_exports2.string(), external_exports2.unknown()).optional(),
30119
30123
  options: external_exports2.object({
@@ -30128,18 +30132,23 @@ external_exports2.object({
30128
30132
  id: external_exports2.uuid(),
30129
30133
  name: external_exports2.string().default("Untitled"),
30130
30134
  apiVersion: external_exports2.number().int().min(1),
30135
+ packages: external_exports2.record(external_exports2.string(), external_exports2.string().min(1)),
30131
30136
  nodes: external_exports2.array(graphNodeSchema),
30132
30137
  edges: external_exports2.array(graphEdgeSchema)
30138
+ }).superRefine((definition, context) => {
30139
+ for (const node of definition.nodes) {
30140
+ if (!Object.prototype.hasOwnProperty.call(definition.packages, node.packageName)) {
30141
+ context.addIssue(`Node "${node.id}" references package "${node.packageName}" which has no entry in the graph packages map`);
30142
+ }
30143
+ }
30133
30144
  });
30134
30145
 
30135
30146
  // package.json
30136
30147
  var package_default = {
30137
- name: "@buffered-audio/nodes",
30138
- version: "0.20.0"};
30148
+ name: "@buffered-audio/nodes"};
30139
30149
 
30140
30150
  // src/package-metadata.ts
30141
30151
  var PACKAGE_NAME = package_default.name;
30142
- var PACKAGE_VERSION = package_default.version;
30143
30152
 
30144
30153
  // src/sources/read/ffmpeg/index.ts
30145
30154
  var ffmpegSchema = external_exports.object({
@@ -30320,7 +30329,6 @@ var ReadFfmpegNode = class extends SourceNode {
30320
30329
  };
30321
30330
  ReadFfmpegNode.nodeName = "Read FFmpeg";
30322
30331
  ReadFfmpegNode.packageName = PACKAGE_NAME;
30323
- ReadFfmpegNode.packageVersion = PACKAGE_VERSION;
30324
30332
  ReadFfmpegNode.description = "Read audio from a file using FFmpeg";
30325
30333
  ReadFfmpegNode.schema = ffmpegSchema;
30326
30334
  ReadFfmpegNode.Stream = ReadFfmpegStream;
@@ -30489,7 +30497,6 @@ var ReadWavNode = class extends SourceNode {
30489
30497
  };
30490
30498
  ReadWavNode.nodeName = "Read WAV";
30491
30499
  ReadWavNode.packageName = PACKAGE_NAME;
30492
- ReadWavNode.packageVersion = PACKAGE_VERSION;
30493
30500
  ReadWavNode.description = "Read audio from a WAV file";
30494
30501
  ReadWavNode.schema = wavSchema;
30495
30502
  ReadWavNode.Stream = ReadWavStream;
@@ -30535,7 +30542,7 @@ function amplitudePercentile(buckets, bucketMax, totalSamples, percent) {
30535
30542
  // src/targets/loudness-stats/index.ts
30536
30543
  var schema = external_exports.object({
30537
30544
  bucketCount: external_exports.number().int().positive().default(1024).describe("Amplitude histogram bucket count"),
30538
- outputPath: external_exports.string().default("").meta({ input: "file", mode: "save" }).describe("Output Path (JSON sidecar). Empty string disables file output.")
30545
+ outputPath: external_exports.string().default("").meta({ input: "file", mode: "save", accept: ".json" }).describe("Output Path (JSON sidecar). Empty string disables file output.")
30539
30546
  });
30540
30547
  var LoudnessStatsStream = class extends BufferedTargetStream {
30541
30548
  constructor() {
@@ -30622,7 +30629,6 @@ var LoudnessStatsNode = class extends TargetNode {
30622
30629
  };
30623
30630
  LoudnessStatsNode.nodeName = "Loudness Stats";
30624
30631
  LoudnessStatsNode.packageName = PACKAGE_NAME;
30625
- LoudnessStatsNode.packageVersion = PACKAGE_VERSION;
30626
30632
  LoudnessStatsNode.description = "Measure integrated loudness, true peak, and loudness range per EBU R128, plus an amplitude-distribution histogram";
30627
30633
  LoudnessStatsNode.schema = schema;
30628
30634
  LoudnessStatsNode.Stream = LoudnessStatsStream;
@@ -30764,7 +30770,7 @@ function computeLogBandMappings(numBands, minFreq, maxFreq, sampleRate, fftSize)
30764
30770
 
30765
30771
  // src/targets/spectrogram/index.ts
30766
30772
  var schema2 = external_exports.object({
30767
- outputPath: external_exports.string().default("").meta({ input: "file", mode: "save" }).describe("Output Path"),
30773
+ outputPath: external_exports.string().default("").meta({ input: "file", mode: "save", accept: ".bin" }).describe("Output Path"),
30768
30774
  fftSize: external_exports.number().min(256).max(8192).multipleOf(256).default(2048).describe("FFT Size"),
30769
30775
  hopSize: external_exports.number().min(64).max(8192).multipleOf(64).default(512).describe("Hop Size"),
30770
30776
  fftwAddonPath: external_exports.string().default("").meta({ input: "file", mode: "open", binary: "fftw-addon" }).describe("FFTW Addon")
@@ -30948,7 +30954,6 @@ var SpectrogramNode = class extends TargetNode {
30948
30954
  };
30949
30955
  SpectrogramNode.nodeName = "Spectrogram";
30950
30956
  SpectrogramNode.packageName = PACKAGE_NAME;
30951
- SpectrogramNode.packageVersion = PACKAGE_VERSION;
30952
30957
  SpectrogramNode.description = "Generate spectrogram visualization data";
30953
30958
  SpectrogramNode.schema = schema2;
30954
30959
  SpectrogramNode.Stream = SpectrogramStream;
@@ -30975,7 +30980,7 @@ function writeMinMaxPoint(min, max, channels, target, offset) {
30975
30980
 
30976
30981
  // src/targets/waveform/index.ts
30977
30982
  var schema3 = external_exports.object({
30978
- outputPath: external_exports.string().default("").meta({ input: "file", mode: "save" }).describe("Output Path"),
30983
+ outputPath: external_exports.string().default("").meta({ input: "file", mode: "save", accept: ".bin" }).describe("Output Path"),
30979
30984
  resolution: external_exports.number().min(100).max(1e4).multipleOf(100).default(1e3).describe("Resolution")
30980
30985
  });
30981
30986
  var HEADER_SIZE2 = 16;
@@ -31077,7 +31082,6 @@ var WaveformNode = class extends TargetNode {
31077
31082
  };
31078
31083
  WaveformNode.nodeName = "Waveform";
31079
31084
  WaveformNode.packageName = PACKAGE_NAME;
31080
- WaveformNode.packageVersion = PACKAGE_VERSION;
31081
31085
  WaveformNode.description = "Generate waveform visualization data";
31082
31086
  WaveformNode.schema = schema3;
31083
31087
  WaveformNode.Stream = WaveformStream;
@@ -31218,11 +31222,11 @@ function bitDepthToPcmFormat(bitDepth) {
31218
31222
  var encodingSchema = external_exports.object({
31219
31223
  format: external_exports.enum(["wav", "flac", "mp3", "aac"]),
31220
31224
  bitrate: external_exports.string().optional(),
31221
- vbr: external_exports.number().optional(),
31225
+ vbr: external_exports.number().min(0).max(9).optional(),
31222
31226
  sampleRate: external_exports.number().int().positive().optional().describe("Output sample rate (Hz). When set, ffmpeg resamples on encode.")
31223
31227
  });
31224
31228
  var schema4 = external_exports.object({
31225
- path: external_exports.string().default("").meta({ input: "file", mode: "save" }),
31229
+ path: external_exports.string().default("").meta({ input: "file", mode: "save", accept: ".wav,.flac,.mp3,.aac" }),
31226
31230
  ffmpegPath: external_exports.string().default("").meta({ input: "file", mode: "open", binary: "ffmpeg", download: "https://ffmpeg.org/download.html" }).describe("FFmpeg \u2014 audio/video processing tool"),
31227
31231
  bitDepth: external_exports.enum(["16", "24", "32", "32f"]).default("16"),
31228
31232
  encoding: encodingSchema.optional().describe("Encode through ffmpeg to a non-WAV format. Requires `ffmpegPath`.")
@@ -31382,7 +31386,6 @@ var WriteNode = class extends TargetNode {
31382
31386
  };
31383
31387
  WriteNode.nodeName = "Write";
31384
31388
  WriteNode.packageName = PACKAGE_NAME;
31385
- WriteNode.packageVersion = PACKAGE_VERSION;
31386
31389
  WriteNode.description = "Write audio to a file";
31387
31390
  WriteNode.schema = schema4;
31388
31391
  WriteNode.Stream = WriteStream;
@@ -31413,8 +31416,8 @@ function computeKeepRanges(sortedRegions, chunkStartSec, sampleRate, chunkFrames
31413
31416
 
31414
31417
  // src/transforms/cut/index.ts
31415
31418
  var cutRegionSchema = external_exports.object({
31416
- start: external_exports.number().min(0).describe("Start (seconds)"),
31417
- end: external_exports.number().min(0).describe("End (seconds)")
31419
+ start: external_exports.number().min(0).max(86400).describe("Start (seconds)"),
31420
+ end: external_exports.number().min(0).max(86400).describe("End (seconds)")
31418
31421
  });
31419
31422
  var schema5 = external_exports.object({
31420
31423
  regions: external_exports.array(cutRegionSchema).default([]).describe("Regions")
@@ -31461,7 +31464,6 @@ var CutNode = class extends TransformNode {
31461
31464
  };
31462
31465
  CutNode.nodeName = "Cut";
31463
31466
  CutNode.packageName = PACKAGE_NAME;
31464
- CutNode.packageVersion = PACKAGE_VERSION;
31465
31467
  CutNode.description = "Remove a region of audio";
31466
31468
  CutNode.schema = schema5;
31467
31469
  CutNode.Stream = CutStream;
@@ -31518,7 +31520,6 @@ var DitherNode = class extends TransformNode {
31518
31520
  };
31519
31521
  DitherNode.nodeName = "Dither";
31520
31522
  DitherNode.packageName = PACKAGE_NAME;
31521
- DitherNode.packageVersion = PACKAGE_VERSION;
31522
31523
  DitherNode.description = "Add shaped noise to reduce quantization distortion";
31523
31524
  DitherNode.schema = schema6;
31524
31525
  DitherNode.Stream = DitherStream;
@@ -31579,7 +31580,6 @@ var NormalizeNode = class extends TransformNode {
31579
31580
  };
31580
31581
  NormalizeNode.nodeName = "Normalize";
31581
31582
  NormalizeNode.packageName = PACKAGE_NAME;
31582
- NormalizeNode.packageVersion = PACKAGE_VERSION;
31583
31583
  NormalizeNode.description = "Adjust peak or loudness level to a target ceiling";
31584
31584
  NormalizeNode.schema = schema7;
31585
31585
  NormalizeNode.Stream = NormalizeStream;
@@ -31602,8 +31602,8 @@ function silenceChunkSizes(total, chunkFrames) {
31602
31602
 
31603
31603
  // src/transforms/pad/index.ts
31604
31604
  var schema8 = external_exports.object({
31605
- before: external_exports.number().min(0).multipleOf(1e-3).default(0).describe("Before"),
31606
- after: external_exports.number().min(0).multipleOf(1e-3).default(0).describe("After")
31605
+ before: external_exports.number().min(0).max(300).multipleOf(1e-3).default(0).describe("Before"),
31606
+ after: external_exports.number().min(0).max(300).multipleOf(1e-3).default(0).describe("After")
31607
31607
  });
31608
31608
  var PadStream = class extends UnbufferedTransformStream {
31609
31609
  constructor() {
@@ -31653,7 +31653,6 @@ var PadNode = class extends TransformNode {
31653
31653
  };
31654
31654
  PadNode.nodeName = "Pad";
31655
31655
  PadNode.packageName = PACKAGE_NAME;
31656
- PadNode.packageVersion = PACKAGE_VERSION;
31657
31656
  PadNode.description = "Add silence to start or end of audio";
31658
31657
  PadNode.schema = schema8;
31659
31658
  PadNode.Stream = PadStream;
@@ -31728,7 +31727,6 @@ var PhaseNode = class extends TransformNode {
31728
31727
  };
31729
31728
  PhaseNode.nodeName = "Phase";
31730
31729
  PhaseNode.packageName = PACKAGE_NAME;
31731
- PhaseNode.packageVersion = PACKAGE_VERSION;
31732
31730
  PhaseNode.description = "Invert or rotate signal phase";
31733
31731
  PhaseNode.schema = schema9;
31734
31732
  PhaseNode.Stream = PhaseStream;
@@ -31763,7 +31761,6 @@ var ReverseNode = class extends TransformNode {
31763
31761
  };
31764
31762
  ReverseNode.nodeName = "Reverse";
31765
31763
  ReverseNode.packageName = PACKAGE_NAME;
31766
- ReverseNode.packageVersion = PACKAGE_VERSION;
31767
31764
  ReverseNode.description = "Reverse audio playback direction";
31768
31765
  ReverseNode.schema = schema10;
31769
31766
  ReverseNode.Stream = ReverseStream;
@@ -31822,7 +31819,7 @@ function applyInsert(destChannel, insertChannel, overlap) {
31822
31819
  // src/transforms/splice/index.ts
31823
31820
  var schema11 = external_exports.object({
31824
31821
  insertPath: external_exports.string().default("").meta({ input: "file", mode: "open", accept: ".wav" }).describe("Insert File Path"),
31825
- insertAt: external_exports.number().min(0).default(0).describe("Insert At (frames)")
31822
+ insertAt: external_exports.number().min(0).max(1e9).default(0).describe("Insert At (frames)")
31826
31823
  });
31827
31824
  var SpliceStream = class extends UnbufferedTransformStream {
31828
31825
  constructor() {
@@ -31884,7 +31881,6 @@ var SpliceNode = class extends TransformNode {
31884
31881
  };
31885
31882
  SpliceNode.nodeName = "Splice";
31886
31883
  SpliceNode.packageName = PACKAGE_NAME;
31887
- SpliceNode.packageVersion = PACKAGE_VERSION;
31888
31884
  SpliceNode.description = "Replace a region of audio with processed content";
31889
31885
  SpliceNode.schema = schema11;
31890
31886
  SpliceNode.Stream = SpliceStream;
@@ -31984,7 +31980,6 @@ var TrimNode = class extends TransformNode {
31984
31980
  };
31985
31981
  TrimNode.nodeName = "Trim";
31986
31982
  TrimNode.packageName = PACKAGE_NAME;
31987
- TrimNode.packageVersion = PACKAGE_VERSION;
31988
31983
  TrimNode.description = "Remove silence from start and end";
31989
31984
  TrimNode.schema = schema12;
31990
31985
  TrimNode.Stream = TrimStream;
@@ -32024,7 +32019,6 @@ var DownmixMonoNode = class extends TransformNode {
32024
32019
  };
32025
32020
  DownmixMonoNode.nodeName = "Downmix Mono";
32026
32021
  DownmixMonoNode.packageName = PACKAGE_NAME;
32027
- DownmixMonoNode.packageVersion = PACKAGE_VERSION;
32028
32022
  DownmixMonoNode.description = "Mix all input channels to a single mono channel by averaging";
32029
32023
  DownmixMonoNode.schema = schema13;
32030
32024
  DownmixMonoNode.Stream = DownmixMonoStream;
@@ -32055,7 +32049,6 @@ var DuplicateChannelsNode = class extends TransformNode {
32055
32049
  };
32056
32050
  DuplicateChannelsNode.nodeName = "Duplicate Channels";
32057
32051
  DuplicateChannelsNode.packageName = PACKAGE_NAME;
32058
- DuplicateChannelsNode.packageVersion = PACKAGE_VERSION;
32059
32052
  DuplicateChannelsNode.description = "Duplicate a mono signal into multiple identical output channels; requires exactly 1 input channel, throws otherwise";
32060
32053
  DuplicateChannelsNode.schema = schema14;
32061
32054
  DuplicateChannelsNode.Stream = DuplicateChannelsStream;
@@ -32088,7 +32081,6 @@ var GainNode = class extends TransformNode {
32088
32081
  };
32089
32082
  GainNode.nodeName = "Gain";
32090
32083
  GainNode.packageName = PACKAGE_NAME;
32091
- GainNode.packageVersion = PACKAGE_VERSION;
32092
32084
  GainNode.description = "Adjust signal level by a fixed amount in dB";
32093
32085
  GainNode.schema = schema15;
32094
32086
  GainNode.Stream = GainStream;
@@ -32147,7 +32139,6 @@ var PanNode = class extends TransformNode {
32147
32139
  };
32148
32140
  PanNode.nodeName = "Pan";
32149
32141
  PanNode.packageName = PACKAGE_NAME;
32150
- PanNode.packageVersion = PACKAGE_VERSION;
32151
32142
  PanNode.description = "Position mono signal in stereo field or adjust stereo balance; throws for inputs with more than 2 channels";
32152
32143
  PanNode.schema = schema16;
32153
32144
  PanNode.Stream = PanStream;
@@ -32349,7 +32340,6 @@ var FfmpegNode = class extends TransformNode {
32349
32340
  };
32350
32341
  FfmpegNode.nodeName = "FFmpeg";
32351
32342
  FfmpegNode.packageName = PACKAGE_NAME;
32352
- FfmpegNode.packageVersion = PACKAGE_VERSION;
32353
32343
  FfmpegNode.description = "Process audio through FFmpeg filters";
32354
32344
  FfmpegNode.schema = schema17;
32355
32345
  FfmpegNode.Stream = FfmpegStream;
@@ -33191,15 +33181,15 @@ function predictInitialB(args) {
33191
33181
  var FLOOR_PIVOT_EPSILON_DB = 0.01;
33192
33182
  var schema18 = external_exports.object({
33193
33183
  targetLufs: external_exports.number().min(-50).max(0).multipleOf(0.1).default(-16).describe("Target integrated loudness (LUFS)"),
33194
- pivot: external_exports.number().lt(0).optional().describe("Body anchor (dB). Default: median(considered LRA blocks) from BS.1770 LRA gating in pass 1."),
33195
- floor: external_exports.number().lt(0).optional().describe("Silence threshold (dB). Default: min(considered LRA blocks); no floor when no blocks survive gating."),
33184
+ pivot: external_exports.number().min(-80).lt(0).optional().describe("Body anchor (dB). Default: median(considered LRA blocks) from BS.1770 LRA gating in pass 1."),
33185
+ floor: external_exports.number().min(-100).lt(0).optional().describe("Silence threshold (dB). Default: min(considered LRA blocks); no floor when no blocks survive gating."),
33196
33186
  limitPercentile: external_exports.number().min(0.5).max(1).default(0.995).describe("Top-1\u2212p fraction of detection samples to brick-wall. Default 0.995 brick-walls the top 0.5%."),
33197
- limitDb: external_exports.number().lt(0).optional().describe("Limit-anchor override (dB). Default: auto-derived from quantile(detection histogram, limitPercentile). Set explicitly to fix the limit anchor."),
33187
+ limitDb: external_exports.number().min(-60).lt(0).optional().describe("Limit-anchor override (dB). Default: auto-derived from quantile(detection histogram, limitPercentile). Set explicitly to fix the limit anchor."),
33198
33188
  maxAttempts: external_exports.number().int().min(1).default(10).describe("Hard cap on iteration attempts."),
33199
- targetTp: external_exports.number().lt(0).optional().describe("True-peak target (dBTP). Default: source true peak (peaks unchanged)."),
33189
+ targetTp: external_exports.number().min(-24).lt(0).optional().describe("True-peak target (dBTP). Default: source true peak (peaks unchanged)."),
33200
33190
  smoothing: external_exports.number().min(0.01).max(200).default(1).describe("Peak-respecting envelope time constant (ms)."),
33201
- tolerance: external_exports.number().gt(0).default(0.5).describe("Iteration exit threshold (LUFS dB)."),
33202
- peakTolerance: external_exports.number().gt(0).default(0.1).describe("One-sided iteration exit threshold for output true-peak overshoot (dBTP; ceiling \u2014 undershoot ignored).")
33191
+ tolerance: external_exports.number().gt(0).max(6).default(0.5).describe("Iteration exit threshold (LUFS dB)."),
33192
+ peakTolerance: external_exports.number().gt(0).max(6).default(0.1).describe("One-sided iteration exit threshold for output true-peak overshoot (dBTP; ceiling \u2014 undershoot ignored).")
33203
33193
  }).refine(
33204
33194
  ({ floor, pivot }) => floor === void 0 || pivot === void 0 || floor < pivot,
33205
33195
  { message: "loudnessTarget requires floor < pivot when floor is set" }
@@ -33477,7 +33467,6 @@ var LoudnessTargetNode = class extends TransformNode {
33477
33467
  };
33478
33468
  LoudnessTargetNode.nodeName = "Loudness Target";
33479
33469
  LoudnessTargetNode.packageName = PACKAGE_NAME;
33480
- LoudnessTargetNode.packageVersion = PACKAGE_VERSION;
33481
33470
  LoudnessTargetNode.description = "Peak-aware content-adaptive curve fitting (LUFS, true-peak, LRA) via a single combined gain envelope with a peak-respecting two-stage smoother. The upper-arm peak anchor jointly iterates with the body gain to land both LUFS and true-peak targets in one envelope.";
33482
33471
  LoudnessTargetNode.schema = schema18;
33483
33472
  LoudnessTargetNode.Stream = LoudnessTargetStream;
@@ -33531,7 +33520,6 @@ var LoudnessNormalizeNode = class extends TransformNode {
33531
33520
  };
33532
33521
  LoudnessNormalizeNode.nodeName = "Loudness Normalize";
33533
33522
  LoudnessNormalizeNode.packageName = PACKAGE_NAME;
33534
- LoudnessNormalizeNode.packageVersion = PACKAGE_VERSION;
33535
33523
  LoudnessNormalizeNode.description = "Measure integrated loudness (BS.1770) and apply a single linear gain to hit a target LUFS \u2014 no limiting, no dynamics";
33536
33524
  LoudnessNormalizeNode.schema = schema19;
33537
33525
  LoudnessNormalizeNode.Stream = LoudnessNormalizeStream;
@@ -33548,7 +33536,7 @@ function resolveTruePeakGain(sourcePeakLinear, target) {
33548
33536
 
33549
33537
  // src/transforms/true-peak-normalize/index.ts
33550
33538
  var schema20 = external_exports.object({
33551
- target: external_exports.number().lt(0).default(-1).describe("Target true peak (dBTP). Must be < 0.")
33539
+ target: external_exports.number().min(-24).lt(0).default(-1).describe("Target true peak (dBTP). Must be < 0.")
33552
33540
  });
33553
33541
  var TruePeakNormalizeStream = class extends BufferedTransformStream {
33554
33542
  constructor() {
@@ -33591,7 +33579,6 @@ var TruePeakNormalizeNode = class extends TransformNode {
33591
33579
  };
33592
33580
  TruePeakNormalizeNode.nodeName = "True Peak Normalize";
33593
33581
  TruePeakNormalizeNode.packageName = PACKAGE_NAME;
33594
- TruePeakNormalizeNode.packageVersion = PACKAGE_VERSION;
33595
33582
  TruePeakNormalizeNode.description = "Measure source true peak (4\xD7 upsampled, BS.1770-4 style) and apply a single linear gain to hit a target dBTP";
33596
33583
  TruePeakNormalizeNode.schema = schema20;
33597
33584
  TruePeakNormalizeNode.Stream = TruePeakNormalizeStream;
@@ -34307,7 +34294,6 @@ var CrestReduceNode = class extends TransformNode {
34307
34294
  };
34308
34295
  CrestReduceNode.nodeName = "Crest Reduce";
34309
34296
  CrestReduceNode.packageName = PACKAGE_NAME;
34310
- CrestReduceNode.packageVersion = PACKAGE_VERSION;
34311
34297
  CrestReduceNode.description = "Content-adaptive, magnitude-preserving, phase-only crest-factor reducer \u2014 a pre-limiter headroom stage that rearranges signal phase to flatten true-peak excursions without changing the magnitude spectrum, never increasing crest factor";
34312
34298
  CrestReduceNode.schema = schema21;
34313
34299
  CrestReduceNode.Stream = CrestReduceStream;
@@ -35352,7 +35338,6 @@ var DeBleedNode = class extends TransformNode {
35352
35338
  };
35353
35339
  DeBleedNode.nodeName = "De-Bleed Adaptive";
35354
35340
  DeBleedNode.packageName = PACKAGE_NAME;
35355
- DeBleedNode.packageVersion = PACKAGE_VERSION;
35356
35341
  DeBleedNode.description = "Adaptive (MEF FDAF Kalman + MWF + MSAD) reference-based microphone bleed reduction. Stages 1+2 are MEF Meyer-Elshamy-Fingscheidt 2020; Stage 3 is Lukin-Todd 2D NLM+DFTT post-filter.";
35357
35342
  DeBleedNode.schema = schema22;
35358
35343
  DeBleedNode.Stream = DeBleedStream;
@@ -35522,7 +35507,6 @@ var DeepFilterNet3Node = class extends TransformNode {
35522
35507
  };
35523
35508
  DeepFilterNet3Node.nodeName = "DeepFilterNet3 (Denoiser)";
35524
35509
  DeepFilterNet3Node.packageName = PACKAGE_NAME;
35525
- DeepFilterNet3Node.packageVersion = PACKAGE_VERSION;
35526
35510
  DeepFilterNet3Node.description = "Remove background noise from speech using DeepFilterNet3 (48 kHz full-band CRN)";
35527
35511
  DeepFilterNet3Node.schema = schema23;
35528
35512
  DeepFilterNet3Node.Stream = DeepFilterNet3Stream;
@@ -35943,7 +35927,6 @@ var DtlnNode = class extends TransformNode {
35943
35927
  };
35944
35928
  DtlnNode.nodeName = "DTLN (Denoiser)";
35945
35929
  DtlnNode.packageName = PACKAGE_NAME;
35946
- DtlnNode.packageVersion = PACKAGE_VERSION;
35947
35930
  DtlnNode.description = "Remove background noise from speech using DTLN neural network";
35948
35931
  DtlnNode.schema = schema24;
35949
35932
  DtlnNode.Stream = DtlnStream;
@@ -36436,7 +36419,6 @@ var HtdemucsNode = class extends TransformNode {
36436
36419
  };
36437
36420
  HtdemucsNode.nodeName = "HTDemucs (Stem Separator)";
36438
36421
  HtdemucsNode.packageName = PACKAGE_NAME;
36439
- HtdemucsNode.packageVersion = PACKAGE_VERSION;
36440
36422
  HtdemucsNode.description = "Rebalance stem volumes using HTDemucs source separation";
36441
36423
  HtdemucsNode.schema = schema25;
36442
36424
  HtdemucsNode.Stream = HtdemucsStream;
@@ -36835,7 +36817,6 @@ var KimVocal2Node = class extends TransformNode {
36835
36817
  };
36836
36818
  KimVocal2Node.nodeName = "Kim Vocal 2 (Stem Separator)";
36837
36819
  KimVocal2Node.packageName = PACKAGE_NAME;
36838
- KimVocal2Node.packageVersion = PACKAGE_VERSION;
36839
36820
  KimVocal2Node.description = "Isolate dialogue from background using MDX-Net vocal separation";
36840
36821
  KimVocal2Node.schema = schema26;
36841
36822
  KimVocal2Node.Stream = KimVocal2Stream;
@@ -37075,7 +37056,6 @@ var Vst3Node = class extends TransformNode {
37075
37056
  };
37076
37057
  Vst3Node.nodeName = "VST3";
37077
37058
  Vst3Node.packageName = PACKAGE_NAME;
37078
- Vst3Node.packageVersion = PACKAGE_VERSION;
37079
37059
  Vst3Node.description = "Host a chain of VST3 effect plugins via Pedalboard (whole-file offline mode)";
37080
37060
  Vst3Node.schema = schema27;
37081
37061
  Vst3Node.Stream = Vst3Stream;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buffered-audio/nodes",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -8,9 +8,6 @@
8
8
  "types": "./dist/index.d.ts"
9
9
  }
10
10
  },
11
- "bin": {
12
- "buffered-audio-nodes": "./dist/cli.js"
13
- },
14
11
  "files": [
15
12
  "dist"
16
13
  ],
@@ -42,15 +39,14 @@
42
39
  "@types/node": "^25.3.5",
43
40
  "concurrently": "*",
44
41
  "tsup": "^8.0.0",
42
+ "tsx": "^4.21.0",
45
43
  "typescript": "*",
46
44
  "vitest": "^3.0.0"
47
45
  },
48
46
  "dependencies": {
49
- "@buffered-audio/core": "0.9.0",
50
- "@buffered-audio/utils": "0.6.4",
47
+ "@buffered-audio/core": "0.10.0",
48
+ "@buffered-audio/utils": "0.6.5",
51
49
  "bufferfy": "^4.0.3",
52
- "commander": "^14.0.3",
53
- "tsx": "^4.21.0",
54
50
  "wavefile": "^11.0.0",
55
51
  "zod": "^4.3.6"
56
52
  }
package/dist/cli.js DELETED
@@ -1,188 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { existsSync, readFileSync } from 'fs';
4
- import { resolve } from 'path';
5
- import { SourceNode, validateGraphDefinition, createRenderJobs, BufferedSourceStream } from '@buffered-audio/core';
6
-
7
- var labelOf = (identity) => identity.nodeId !== void 0 ? `${identity.nodeName}#${identity.nodeId}` : `${identity.nodeName}#${identity.streamId}`;
8
- function sourceLabel(job) {
9
- for (const streams of job.streams.values()) {
10
- for (const stream of streams) {
11
- if (stream instanceof BufferedSourceStream) return labelOf(stream.identity);
12
- }
13
- }
14
- return void 0;
15
- }
16
- var collect = (value, previous) => [...previous, value];
17
- function parseParams(entries) {
18
- const parameters = /* @__PURE__ */ new Map();
19
- for (const entry of entries) {
20
- const separatorIndex = entry.indexOf("=");
21
- if (separatorIndex === -1) {
22
- process.stderr.write(`Error: --param must be in name=value form, got "${entry}"
23
- `);
24
- process.exit(1);
25
- }
26
- const name = entry.slice(0, separatorIndex);
27
- const value = entry.slice(separatorIndex + 1);
28
- if (name === "") {
29
- process.stderr.write(`Error: --param name must not be empty, got "${entry}"
30
- `);
31
- process.exit(1);
32
- }
33
- if (parameters.has(name)) {
34
- process.stderr.write(`Error: --param ${name} given more than once
35
- `);
36
- process.exit(1);
37
- }
38
- parameters.set(name, value);
39
- }
40
- return Object.fromEntries(parameters);
41
- }
42
- function stamp(createdAt) {
43
- const date = new Date(createdAt);
44
- const pad = (value) => String(value).padStart(2, "0");
45
- return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
46
- }
47
- function createEventSink() {
48
- const totals = /* @__PURE__ */ new Map();
49
- const subscribe = (events) => {
50
- events.on("started", (node, payload) => {
51
- process.stdout.write(`${stamp(payload.createdAt)} [${labelOf(node)}] started
52
- `);
53
- });
54
- events.on("progress", (node, payload) => {
55
- const label = labelOf(node);
56
- if (payload.framesTotal !== void 0) {
57
- const percent = Math.round(payload.framesDone / payload.framesTotal * 100);
58
- process.stdout.write(`${stamp(payload.createdAt)} [${label}] ${payload.phase} ${percent}%
59
- `);
60
- } else {
61
- process.stdout.write(`${stamp(payload.createdAt)} [${label}] ${payload.phase} frames=${payload.framesDone}
62
- `);
63
- }
64
- });
65
- events.on("log", (node, payload) => {
66
- const data = payload.data ? Object.entries(payload.data).map(([key, value]) => `${key}=${String(value)}`) : [];
67
- const parts = [payload.message, ...data].join(" ");
68
- const prefix = payload.level === "warn" ? "warn: " : "";
69
- process.stdout.write(`${stamp(payload.createdAt)} ${prefix}[${labelOf(node)}] ${parts}
70
- `);
71
- });
72
- events.on("finished", (node, payload) => {
73
- totals.set(node.streamId, { label: labelOf(node), framesDone: payload.framesDone, processingMs: payload.processingMs });
74
- const ms = payload.processingMs !== void 0 ? ` ms=${Math.round(payload.processingMs)}` : "";
75
- process.stdout.write(`${stamp(payload.createdAt)} [${labelOf(node)}] finished frames=${payload.framesDone}${ms}
76
- `);
77
- });
78
- };
79
- const printSummary = (jobs) => {
80
- for (const { label, framesDone, processingMs } of totals.values()) {
81
- if (processingMs !== void 0) {
82
- process.stdout.write(`${stamp(Date.now())} [${label}] processed ${framesDone} frames in ${Math.round(processingMs)}ms
83
- `);
84
- } else {
85
- process.stdout.write(`${stamp(Date.now())} [${label}] processed ${framesDone} frames
86
- `);
87
- }
88
- }
89
- for (const job of jobs) {
90
- const timing = job.timing;
91
- if (!timing) continue;
92
- const label = sourceLabel(job) ?? "source";
93
- process.stdout.write(`${stamp(Date.now())} [${label}] total ${(timing.totalMs / 1e3).toFixed(1)}s, ${timing.realTimeMultiplier.toFixed(1)}x RT
94
- `);
95
- }
96
- };
97
- return { subscribe, printSummary };
98
- }
99
- var program = new Command();
100
- program.name("buffered-audio-nodes").description("Process audio through buffered audio node pipelines");
101
- program.command("process").description("Run an async audio processing pipeline").requiredOption("--pipeline <file>", "TypeScript file with default SourceAsyncModule export").option("--chunk-size <samples>", "Chunk size in samples").option("--high-water-mark <count>", "Stream backpressure high water mark").action(async (options) => {
102
- const pipelinePath = resolve(options.pipeline);
103
- if (!existsSync(pipelinePath)) {
104
- process.stderr.write(`Error: pipeline file not found: ${pipelinePath}
105
- `);
106
- process.exit(1);
107
- }
108
- const { register } = await import('tsx/esm/api');
109
- const unregister = register();
110
- try {
111
- const mod = await import(pipelinePath);
112
- const source = mod.default;
113
- if (!(source instanceof SourceNode)) {
114
- process.stderr.write("Error: default export must be a SourceAsyncModule\n");
115
- process.exit(1);
116
- }
117
- const chunkSize = options.chunkSize ? parseInt(options.chunkSize, 10) : void 0;
118
- const highWaterMark = options.highWaterMark ? parseInt(options.highWaterMark, 10) : void 0;
119
- if (chunkSize !== void 0 && (!Number.isFinite(chunkSize) || chunkSize <= 0)) {
120
- process.stderr.write(`Error: --chunk-size must be a positive integer, got "${options.chunkSize}"
121
- `);
122
- process.exit(1);
123
- }
124
- if (highWaterMark !== void 0 && (!Number.isFinite(highWaterMark) || highWaterMark <= 0)) {
125
- process.stderr.write(`Error: --high-water-mark must be a positive integer, got "${options.highWaterMark}"
126
- `);
127
- process.exit(1);
128
- }
129
- const sink = createEventSink();
130
- const job = source.createRenderJob({ chunkSize, highWaterMark });
131
- sink.subscribe(job.events);
132
- process.stdout.write(`Processing pipeline: ${pipelinePath}
133
- `);
134
- await job.render();
135
- sink.printSummary([job]);
136
- process.stdout.write("Done.\n");
137
- } finally {
138
- await unregister();
139
- }
140
- });
141
- program.command("render").description("Render a .bag graph definition file").argument("<file>", "Path to .bag file (JSON)").option("--chunk-size <samples>", "Chunk size in samples").option("--high-water-mark <count>", "Stream backpressure high water mark").option("--param <name=value>", "Bind a {{name}} template placeholder in the bag (repeatable)", collect, []).action(async (file, options) => {
142
- const bagPath = resolve(file);
143
- if (!existsSync(bagPath)) {
144
- process.stderr.write(`Error: file not found: ${bagPath}
145
- `);
146
- process.exit(1);
147
- }
148
- const json = JSON.parse(readFileSync(bagPath, "utf-8"));
149
- const definition = validateGraphDefinition(json);
150
- const { register } = await import('tsx/esm/api');
151
- const unregister = register();
152
- try {
153
- const registry = /* @__PURE__ */ new Map();
154
- for (const nodeDef of definition.nodes) {
155
- if (!registry.has(nodeDef.packageName)) {
156
- const mod = await import(nodeDef.packageName);
157
- const packageMap = /* @__PURE__ */ new Map();
158
- for (const value of Object.values(mod)) {
159
- if (typeof value !== "function") continue;
160
- const ctor = value;
161
- if (typeof ctor.nodeName !== "string") continue;
162
- packageMap.set(ctor.nodeName, ctor);
163
- }
164
- registry.set(nodeDef.packageName, packageMap);
165
- }
166
- }
167
- const chunkSize = options.chunkSize ? parseInt(options.chunkSize, 10) : void 0;
168
- const highWaterMark = options.highWaterMark ? parseInt(options.highWaterMark, 10) : void 0;
169
- const parameters = parseParams(options.param);
170
- const sink = createEventSink();
171
- process.stdout.write(`Rendering graph: ${definition.name}
172
- `);
173
- try {
174
- const jobs = createRenderJobs(definition, registry, { chunkSize, highWaterMark, parameters });
175
- for (const job of jobs) sink.subscribe(job.events);
176
- await Promise.all(jobs.map((job) => job.render()));
177
- sink.printSummary(jobs);
178
- process.stdout.write("Done.\n");
179
- } catch (error) {
180
- process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}
181
- `);
182
- process.exitCode = 1;
183
- }
184
- } finally {
185
- await unregister();
186
- }
187
- });
188
- program.parse();