@buffered-audio/nodes 0.17.0 → 0.18.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
@@ -318,18 +318,6 @@ Invert or rotate signal phase
318
318
  | `invert` | boolean | `true` | Invert |
319
319
  | `angle` | number (-180 to 180, step 1), optional | — | Angle |
320
320
 
321
- ### Read
322
-
323
- Read audio from a file
324
-
325
- [Source](./src/sources/read/index.ts)
326
-
327
- | Parameter | Type | Default | Description |
328
- | --- | --- | --- | --- |
329
- | `path` | string | `""` | |
330
- | `ffmpegPath` | string | `""` | FFmpeg — audio/video processing tool Download: [ffmpeg](https://ffmpeg.org/download.html) |
331
- | `ffprobePath` | string | `""` | FFprobe — media file analyzer (included with FFmpeg) Download: [ffprobe](https://ffmpeg.org/download.html) |
332
-
333
321
  ### Read FFmpeg
334
322
 
335
323
  Read audio from a file using FFmpeg
package/dist/cli.js CHANGED
@@ -2,9 +2,17 @@
2
2
  import { Command } from 'commander';
3
3
  import { existsSync, readFileSync } from 'fs';
4
4
  import { resolve } from 'path';
5
- import { SourceNode, validateGraphDefinition, renderGraph } from '@buffered-audio/core';
5
+ import { SourceNode, validateGraphDefinition, createRenderJobs, BufferedSourceStream } from '@buffered-audio/core';
6
6
 
7
7
  var labelOf = (node) => node.id ? `${node.nodeName}#${node.id}` : node.nodeName;
8
+ function sourceLabel(job) {
9
+ for (const [node, streams] of job.streams) {
10
+ if (streams.some((stream) => stream instanceof BufferedSourceStream)) {
11
+ return labelOf({ nodeName: node.constructor.nodeName, id: node.id });
12
+ }
13
+ }
14
+ return void 0;
15
+ }
8
16
  var collect = (value, previous) => [...previous, value];
9
17
  function parseParams(entries) {
10
18
  const parameters = /* @__PURE__ */ new Map();
@@ -33,39 +41,36 @@ function parseParams(entries) {
33
41
  }
34
42
  function createEventSink() {
35
43
  const totals = /* @__PURE__ */ new Map();
36
- const onEvent = (node, event) => {
37
- const label = labelOf(node);
38
- switch (event.kind) {
39
- case "started":
40
- process.stdout.write(`[${label}] started
44
+ const subscribe = (events) => {
45
+ events.on("started", (node) => {
46
+ process.stdout.write(`[${labelOf(node)}] started
41
47
  `);
42
- break;
43
- case "progress":
44
- if (event.framesTotal !== void 0) {
45
- const percent = Math.round(event.framesDone / event.framesTotal * 100);
46
- process.stdout.write(`[${label}] ${event.phase} ${percent}%
48
+ });
49
+ events.on("progress", (node, payload) => {
50
+ const label = labelOf(node);
51
+ if (payload.framesTotal !== void 0) {
52
+ const percent = Math.round(payload.framesDone / payload.framesTotal * 100);
53
+ process.stdout.write(`[${label}] ${payload.phase} ${percent}%
47
54
  `);
48
- } else {
49
- process.stdout.write(`[${label}] ${event.phase} frames=${event.framesDone}
55
+ } else {
56
+ process.stdout.write(`[${label}] ${payload.phase} frames=${payload.framesDone}
50
57
  `);
51
- }
52
- break;
53
- case "log": {
54
- const data = event.data ? Object.entries(event.data).map(([key, value]) => `${key}=${String(value)}`) : [];
55
- const parts = [event.message, ...data].join(" ");
56
- const prefix = event.level === "warn" ? "warn: " : "";
57
- process.stdout.write(`${prefix}[${label}] ${parts}
58
- `);
59
- break;
60
58
  }
61
- case "finished":
62
- totals.set(node, { framesDone: event.framesDone, processingMs: event.processingMs });
63
- process.stdout.write(`[${label}] finished
64
- `);
65
- break;
66
- }
59
+ });
60
+ events.on("log", (node, payload) => {
61
+ const data = payload.data ? Object.entries(payload.data).map(([key, value]) => `${key}=${String(value)}`) : [];
62
+ const parts = [payload.message, ...data].join(" ");
63
+ const prefix = payload.level === "warn" ? "warn: " : "";
64
+ process.stdout.write(`${prefix}[${labelOf(node)}] ${parts}
65
+ `);
66
+ });
67
+ events.on("finished", (node, payload) => {
68
+ totals.set(node, { framesDone: payload.framesDone, processingMs: payload.processingMs });
69
+ process.stdout.write(`[${labelOf(node)}] finished
70
+ `);
71
+ });
67
72
  };
68
- const printSummary = (sources) => {
73
+ const printSummary = (jobs) => {
69
74
  for (const [node, { framesDone, processingMs }] of totals) {
70
75
  const label = labelOf(node);
71
76
  if (processingMs !== void 0) {
@@ -76,15 +81,15 @@ function createEventSink() {
76
81
  `);
77
82
  }
78
83
  }
79
- for (const source of sources) {
80
- const timing = source.renderTiming;
84
+ for (const job of jobs) {
85
+ const timing = job.timing;
81
86
  if (!timing) continue;
82
- const label = labelOf({ nodeName: source.constructor.nodeName, id: source.id });
87
+ const label = sourceLabel(job) ?? "source";
83
88
  process.stdout.write(`[${label}] total ${(timing.totalMs / 1e3).toFixed(1)}s, ${timing.realTimeMultiplier.toFixed(1)}x RT
84
89
  `);
85
90
  }
86
91
  };
87
- return { onEvent, printSummary };
92
+ return { subscribe, printSummary };
88
93
  }
89
94
  var program = new Command();
90
95
  program.name("buffered-audio-nodes").description("Process audio through buffered audio node pipelines");
@@ -117,15 +122,12 @@ program.command("process").description("Run an async audio processing pipeline")
117
122
  process.exit(1);
118
123
  }
119
124
  const sink = createEventSink();
120
- const renderOptions = {
121
- chunkSize,
122
- highWaterMark,
123
- onEvent: sink.onEvent
124
- };
125
+ const job = source.createRenderJob({ chunkSize, highWaterMark });
126
+ sink.subscribe(job.events);
125
127
  process.stdout.write(`Processing pipeline: ${pipelinePath}
126
128
  `);
127
- await source.render(renderOptions);
128
- sink.printSummary([source]);
129
+ await job.render();
130
+ sink.printSummary([job]);
129
131
  process.stdout.write("Done.\n");
130
132
  } finally {
131
133
  await unregister();
@@ -164,8 +166,10 @@ program.command("render").description("Render a .bag graph definition file").arg
164
166
  process.stdout.write(`Rendering graph: ${definition.name}
165
167
  `);
166
168
  try {
167
- const sources = await renderGraph(definition, registry, { chunkSize, highWaterMark, parameters, onEvent: sink.onEvent });
168
- sink.printSummary(sources);
169
+ const jobs = createRenderJobs(definition, registry, { chunkSize, highWaterMark, parameters });
170
+ for (const job of jobs) sink.subscribe(job.events);
171
+ await Promise.all(jobs.map((job) => job.render()));
172
+ sink.printSummary(jobs);
169
173
  process.stdout.write("Done.\n");
170
174
  } catch (error) {
171
175
  process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}