@nodetool-ai/base-nodes 0.7.0-rc.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audio-wav.d.ts +66 -0
- package/dist/lib/audio-wav.d.ts.map +1 -0
- package/dist/lib/audio-wav.js +215 -0
- package/dist/lib/audio-wav.js.map +1 -0
- package/dist/nodes/agents.d.ts +253 -0
- package/dist/nodes/agents.d.ts.map +1 -0
- package/dist/nodes/agents.js +2784 -0
- package/dist/nodes/agents.js.map +1 -0
- package/dist/nodes/anthropic.d.ts +26 -0
- package/dist/nodes/anthropic.d.ts.map +1 -0
- package/dist/nodes/anthropic.js +133 -0
- package/dist/nodes/anthropic.js.map +1 -0
- package/dist/nodes/apify.d.ts +120 -0
- package/dist/nodes/apify.d.ts.map +1 -0
- package/dist/nodes/apify.js +618 -0
- package/dist/nodes/apify.js.map +1 -0
- package/dist/nodes/audio.d.ts +301 -0
- package/dist/nodes/audio.d.ts.map +1 -0
- package/dist/nodes/audio.js +1274 -0
- package/dist/nodes/audio.js.map +1 -0
- package/dist/nodes/code-node.d.ts +34 -0
- package/dist/nodes/code-node.d.ts.map +1 -0
- package/dist/nodes/code-node.js +343 -0
- package/dist/nodes/code-node.js.map +1 -0
- package/dist/nodes/code.d.ts +301 -0
- package/dist/nodes/code.d.ts.map +1 -0
- package/dist/nodes/code.js +850 -0
- package/dist/nodes/code.js.map +1 -0
- package/dist/nodes/compare.d.ts +18 -0
- package/dist/nodes/compare.d.ts.map +1 -0
- package/dist/nodes/compare.js +122 -0
- package/dist/nodes/compare.js.map +1 -0
- package/dist/nodes/constant.d.ts +315 -0
- package/dist/nodes/constant.d.ts.map +1 -0
- package/dist/nodes/constant.js +715 -0
- package/dist/nodes/constant.js.map +1 -0
- package/dist/nodes/control.d.ts +83 -0
- package/dist/nodes/control.d.ts.map +1 -0
- package/dist/nodes/control.js +212 -0
- package/dist/nodes/control.js.map +1 -0
- package/dist/nodes/data.d.ts +369 -0
- package/dist/nodes/data.d.ts.map +1 -0
- package/dist/nodes/data.js +1590 -0
- package/dist/nodes/data.js.map +1 -0
- package/dist/nodes/document.d.ts +134 -0
- package/dist/nodes/document.d.ts.map +1 -0
- package/dist/nodes/document.js +984 -0
- package/dist/nodes/document.js.map +1 -0
- package/dist/nodes/extended-placeholders.d.ts +6 -0
- package/dist/nodes/extended-placeholders.d.ts.map +1 -0
- package/dist/nodes/extended-placeholders.js +19 -0
- package/dist/nodes/extended-placeholders.js.map +1 -0
- package/dist/nodes/gemini.d.ts +109 -0
- package/dist/nodes/gemini.d.ts.map +1 -0
- package/dist/nodes/gemini.js +861 -0
- package/dist/nodes/gemini.js.map +1 -0
- package/dist/nodes/generators.d.ts +84 -0
- package/dist/nodes/generators.d.ts.map +1 -0
- package/dist/nodes/generators.js +937 -0
- package/dist/nodes/generators.js.map +1 -0
- package/dist/nodes/image.d.ts +232 -0
- package/dist/nodes/image.d.ts.map +1 -0
- package/dist/nodes/image.js +1395 -0
- package/dist/nodes/image.js.map +1 -0
- package/dist/nodes/input.d.ts +445 -0
- package/dist/nodes/input.d.ts.map +1 -0
- package/dist/nodes/input.js +1459 -0
- package/dist/nodes/input.js.map +1 -0
- package/dist/nodes/kie-dynamic.d.ts +31 -0
- package/dist/nodes/kie-dynamic.d.ts.map +1 -0
- package/dist/nodes/kie-dynamic.js +270 -0
- package/dist/nodes/kie-dynamic.js.map +1 -0
- package/dist/nodes/lib-audio-dsp.d.ts +85 -0
- package/dist/nodes/lib-audio-dsp.d.ts.map +1 -0
- package/dist/nodes/lib-audio-dsp.js +450 -0
- package/dist/nodes/lib-audio-dsp.js.map +1 -0
- package/dist/nodes/lib-audio-effects.d.ts +116 -0
- package/dist/nodes/lib-audio-effects.d.ts.map +1 -0
- package/dist/nodes/lib-audio-effects.js +905 -0
- package/dist/nodes/lib-audio-effects.js.map +1 -0
- package/dist/nodes/lib-browser.d.ts +99 -0
- package/dist/nodes/lib-browser.d.ts.map +1 -0
- package/dist/nodes/lib-browser.js +692 -0
- package/dist/nodes/lib-browser.js.map +1 -0
- package/dist/nodes/lib-charts.d.ts +20 -0
- package/dist/nodes/lib-charts.d.ts.map +1 -0
- package/dist/nodes/lib-charts.js +245 -0
- package/dist/nodes/lib-charts.js.map +1 -0
- package/dist/nodes/lib-datetime.d.ts +108 -0
- package/dist/nodes/lib-datetime.d.ts.map +1 -0
- package/dist/nodes/lib-datetime.js +421 -0
- package/dist/nodes/lib-datetime.js.map +1 -0
- package/dist/nodes/lib-doc-convert.d.ts +19 -0
- package/dist/nodes/lib-doc-convert.d.ts.map +1 -0
- package/dist/nodes/lib-doc-convert.js +257 -0
- package/dist/nodes/lib-doc-convert.js.map +1 -0
- package/dist/nodes/lib-doc-transform.d.ts +39 -0
- package/dist/nodes/lib-doc-transform.d.ts.map +1 -0
- package/dist/nodes/lib-doc-transform.js +335 -0
- package/dist/nodes/lib-doc-transform.js.map +1 -0
- package/dist/nodes/lib-docx.d.ts +106 -0
- package/dist/nodes/lib-docx.d.ts.map +1 -0
- package/dist/nodes/lib-docx.js +595 -0
- package/dist/nodes/lib-docx.js.map +1 -0
- package/dist/nodes/lib-epub.d.ts +55 -0
- package/dist/nodes/lib-epub.d.ts.map +1 -0
- package/dist/nodes/lib-epub.js +220 -0
- package/dist/nodes/lib-epub.js.map +1 -0
- package/dist/nodes/lib-excel.d.ts +74 -0
- package/dist/nodes/lib-excel.d.ts.map +1 -0
- package/dist/nodes/lib-excel.js +448 -0
- package/dist/nodes/lib-excel.js.map +1 -0
- package/dist/nodes/lib-graphql.d.ts +66 -0
- package/dist/nodes/lib-graphql.d.ts.map +1 -0
- package/dist/nodes/lib-graphql.js +333 -0
- package/dist/nodes/lib-graphql.js.map +1 -0
- package/dist/nodes/lib-grid.d.ts +27 -0
- package/dist/nodes/lib-grid.d.ts.map +1 -0
- package/dist/nodes/lib-grid.js +172 -0
- package/dist/nodes/lib-grid.js.map +1 -0
- package/dist/nodes/lib-html-parse.d.ts +108 -0
- package/dist/nodes/lib-html-parse.d.ts.map +1 -0
- package/dist/nodes/lib-html-parse.js +365 -0
- package/dist/nodes/lib-html-parse.js.map +1 -0
- package/dist/nodes/lib-http.d.ts +98 -0
- package/dist/nodes/lib-http.d.ts.map +1 -0
- package/dist/nodes/lib-http.js +267 -0
- package/dist/nodes/lib-http.js.map +1 -0
- package/dist/nodes/lib-image-color-grading.d.ts +3 -0
- package/dist/nodes/lib-image-color-grading.d.ts.map +1 -0
- package/dist/nodes/lib-image-color-grading.js +1386 -0
- package/dist/nodes/lib-image-color-grading.js.map +1 -0
- package/dist/nodes/lib-image-draw.d.ts +3 -0
- package/dist/nodes/lib-image-draw.d.ts.map +1 -0
- package/dist/nodes/lib-image-draw.js +470 -0
- package/dist/nodes/lib-image-draw.js.map +1 -0
- package/dist/nodes/lib-image-enhance.d.ts +3 -0
- package/dist/nodes/lib-image-enhance.d.ts.map +1 -0
- package/dist/nodes/lib-image-enhance.js +731 -0
- package/dist/nodes/lib-image-enhance.js.map +1 -0
- package/dist/nodes/lib-image-filter.d.ts +3 -0
- package/dist/nodes/lib-image-filter.d.ts.map +1 -0
- package/dist/nodes/lib-image-filter.js +684 -0
- package/dist/nodes/lib-image-filter.js.map +1 -0
- package/dist/nodes/lib-image-utils.d.ts +24 -0
- package/dist/nodes/lib-image-utils.d.ts.map +1 -0
- package/dist/nodes/lib-image-utils.js +150 -0
- package/dist/nodes/lib-image-utils.js.map +1 -0
- package/dist/nodes/lib-mail.d.ts +74 -0
- package/dist/nodes/lib-mail.d.ts.map +1 -0
- package/dist/nodes/lib-mail.js +452 -0
- package/dist/nodes/lib-mail.js.map +1 -0
- package/dist/nodes/lib-markdown.d.ts +70 -0
- package/dist/nodes/lib-markdown.d.ts.map +1 -0
- package/dist/nodes/lib-markdown.js +236 -0
- package/dist/nodes/lib-markdown.js.map +1 -0
- package/dist/nodes/lib-nlp.d.ts +98 -0
- package/dist/nodes/lib-nlp.d.ts.map +1 -0
- package/dist/nodes/lib-nlp.js +374 -0
- package/dist/nodes/lib-nlp.js.map +1 -0
- package/dist/nodes/lib-notion.d.ts +99 -0
- package/dist/nodes/lib-notion.d.ts.map +1 -0
- package/dist/nodes/lib-notion.js +601 -0
- package/dist/nodes/lib-notion.js.map +1 -0
- package/dist/nodes/lib-ocr.d.ts +31 -0
- package/dist/nodes/lib-ocr.d.ts.map +1 -0
- package/dist/nodes/lib-ocr.js +143 -0
- package/dist/nodes/lib-ocr.js.map +1 -0
- package/dist/nodes/lib-os.d.ts +312 -0
- package/dist/nodes/lib-os.d.ts.map +1 -0
- package/dist/nodes/lib-os.js +909 -0
- package/dist/nodes/lib-os.js.map +1 -0
- package/dist/nodes/lib-pdf.d.ts +142 -0
- package/dist/nodes/lib-pdf.d.ts.map +1 -0
- package/dist/nodes/lib-pdf.js +871 -0
- package/dist/nodes/lib-pdf.js.map +1 -0
- package/dist/nodes/lib-pptx.d.ts +29 -0
- package/dist/nodes/lib-pptx.d.ts.map +1 -0
- package/dist/nodes/lib-pptx.js +122 -0
- package/dist/nodes/lib-pptx.js.map +1 -0
- package/dist/nodes/lib-rss.d.ts +31 -0
- package/dist/nodes/lib-rss.d.ts.map +1 -0
- package/dist/nodes/lib-rss.js +163 -0
- package/dist/nodes/lib-rss.js.map +1 -0
- package/dist/nodes/lib-s3.d.ts +112 -0
- package/dist/nodes/lib-s3.d.ts.map +1 -0
- package/dist/nodes/lib-s3.js +521 -0
- package/dist/nodes/lib-s3.js.map +1 -0
- package/dist/nodes/lib-secret.d.ts +15 -0
- package/dist/nodes/lib-secret.d.ts.map +1 -0
- package/dist/nodes/lib-secret.js +42 -0
- package/dist/nodes/lib-secret.js.map +1 -0
- package/dist/nodes/lib-sqlite.d.ts +102 -0
- package/dist/nodes/lib-sqlite.d.ts.map +1 -0
- package/dist/nodes/lib-sqlite.js +532 -0
- package/dist/nodes/lib-sqlite.js.map +1 -0
- package/dist/nodes/lib-supabase.d.ts +86 -0
- package/dist/nodes/lib-supabase.d.ts.map +1 -0
- package/dist/nodes/lib-supabase.js +425 -0
- package/dist/nodes/lib-supabase.js.map +1 -0
- package/dist/nodes/lib-svg.d.ts +199 -0
- package/dist/nodes/lib-svg.d.ts.map +1 -0
- package/dist/nodes/lib-svg.js +1027 -0
- package/dist/nodes/lib-svg.js.map +1 -0
- package/dist/nodes/lib-tensorflow.d.ts +71 -0
- package/dist/nodes/lib-tensorflow.d.ts.map +1 -0
- package/dist/nodes/lib-tensorflow.js +351 -0
- package/dist/nodes/lib-tensorflow.js.map +1 -0
- package/dist/nodes/lib-twilio.d.ts +71 -0
- package/dist/nodes/lib-twilio.d.ts.map +1 -0
- package/dist/nodes/lib-twilio.js +469 -0
- package/dist/nodes/lib-twilio.js.map +1 -0
- package/dist/nodes/lib-validate.d.ts +84 -0
- package/dist/nodes/lib-validate.d.ts.map +1 -0
- package/dist/nodes/lib-validate.js +215 -0
- package/dist/nodes/lib-validate.js.map +1 -0
- package/dist/nodes/lib-video-download.d.ts +26 -0
- package/dist/nodes/lib-video-download.d.ts.map +1 -0
- package/dist/nodes/lib-video-download.js +299 -0
- package/dist/nodes/lib-video-download.js.map +1 -0
- package/dist/nodes/messaging.d.ts +88 -0
- package/dist/nodes/messaging.d.ts.map +1 -0
- package/dist/nodes/messaging.js +418 -0
- package/dist/nodes/messaging.js.map +1 -0
- package/dist/nodes/mistral.d.ts +83 -0
- package/dist/nodes/mistral.d.ts.map +1 -0
- package/dist/nodes/mistral.js +450 -0
- package/dist/nodes/mistral.js.map +1 -0
- package/dist/nodes/model3d/analysis.d.ts +13 -0
- package/dist/nodes/model3d/analysis.d.ts.map +1 -0
- package/dist/nodes/model3d/analysis.js +36 -0
- package/dist/nodes/model3d/analysis.js.map +1 -0
- package/dist/nodes/model3d/base.d.ts +11 -0
- package/dist/nodes/model3d/base.d.ts.map +1 -0
- package/dist/nodes/model3d/base.js +20 -0
- package/dist/nodes/model3d/base.js.map +1 -0
- package/dist/nodes/model3d/boolean-ops.d.ts +2 -0
- package/dist/nodes/model3d/boolean-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/boolean-ops.js +172 -0
- package/dist/nodes/model3d/boolean-ops.js.map +1 -0
- package/dist/nodes/model3d/cleanup.d.ts +47 -0
- package/dist/nodes/model3d/cleanup.d.ts.map +1 -0
- package/dist/nodes/model3d/cleanup.js +136 -0
- package/dist/nodes/model3d/cleanup.js.map +1 -0
- package/dist/nodes/model3d/convert.d.ts +14 -0
- package/dist/nodes/model3d/convert.d.ts.map +1 -0
- package/dist/nodes/model3d/convert.js +64 -0
- package/dist/nodes/model3d/convert.js.map +1 -0
- package/dist/nodes/model3d/defaults.d.ts +34 -0
- package/dist/nodes/model3d/defaults.d.ts.map +1 -0
- package/dist/nodes/model3d/defaults.js +28 -0
- package/dist/nodes/model3d/defaults.js.map +1 -0
- package/dist/nodes/model3d/document-ops.d.ts +4 -0
- package/dist/nodes/model3d/document-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/document-ops.js +40 -0
- package/dist/nodes/model3d/document-ops.js.map +1 -0
- package/dist/nodes/model3d/generation.d.ts +39 -0
- package/dist/nodes/model3d/generation.d.ts.map +1 -0
- package/dist/nodes/model3d/generation.js +179 -0
- package/dist/nodes/model3d/generation.js.map +1 -0
- package/dist/nodes/model3d/glb.d.ts +29 -0
- package/dist/nodes/model3d/glb.d.ts.map +1 -0
- package/dist/nodes/model3d/glb.js +255 -0
- package/dist/nodes/model3d/glb.js.map +1 -0
- package/dist/nodes/model3d/index.d.ts +20 -0
- package/dist/nodes/model3d/index.d.ts.map +1 -0
- package/dist/nodes/model3d/index.js +38 -0
- package/dist/nodes/model3d/index.js.map +1 -0
- package/dist/nodes/model3d/io.d.ts +38 -0
- package/dist/nodes/model3d/io.d.ts.map +1 -0
- package/dist/nodes/model3d/io.js +162 -0
- package/dist/nodes/model3d/io.js.map +1 -0
- package/dist/nodes/model3d/mesh-ops.d.ts +40 -0
- package/dist/nodes/model3d/mesh-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/mesh-ops.js +775 -0
- package/dist/nodes/model3d/mesh-ops.js.map +1 -0
- package/dist/nodes/model3d/nodes.d.ts +2 -0
- package/dist/nodes/model3d/nodes.d.ts.map +1 -0
- package/dist/nodes/model3d/nodes.js +2 -0
- package/dist/nodes/model3d/nodes.js.map +1 -0
- package/dist/nodes/model3d/ops.d.ts +37 -0
- package/dist/nodes/model3d/ops.d.ts.map +1 -0
- package/dist/nodes/model3d/ops.js +137 -0
- package/dist/nodes/model3d/ops.js.map +1 -0
- package/dist/nodes/model3d/transforms.d.ts +49 -0
- package/dist/nodes/model3d/transforms.d.ts.map +1 -0
- package/dist/nodes/model3d/transforms.js +142 -0
- package/dist/nodes/model3d/transforms.js.map +1 -0
- package/dist/nodes/model3d/types.d.ts +81 -0
- package/dist/nodes/model3d/types.d.ts.map +1 -0
- package/dist/nodes/model3d/types.js +2 -0
- package/dist/nodes/model3d/types.js.map +1 -0
- package/dist/nodes/model3d/utils.d.ts +34 -0
- package/dist/nodes/model3d/utils.d.ts.map +1 -0
- package/dist/nodes/model3d/utils.js +185 -0
- package/dist/nodes/model3d/utils.js.map +1 -0
- package/dist/nodes/model3d.d.ts +2 -0
- package/dist/nodes/model3d.d.ts.map +1 -0
- package/dist/nodes/model3d.js +2 -0
- package/dist/nodes/model3d.js.map +1 -0
- package/dist/nodes/openai.d.ts +172 -0
- package/dist/nodes/openai.d.ts.map +1 -0
- package/dist/nodes/openai.js +1294 -0
- package/dist/nodes/openai.js.map +1 -0
- package/dist/nodes/output.d.ts +29 -0
- package/dist/nodes/output.d.ts.map +1 -0
- package/dist/nodes/output.js +87 -0
- package/dist/nodes/output.js.map +1 -0
- package/dist/nodes/sandbox.d.ts +67 -0
- package/dist/nodes/sandbox.d.ts.map +1 -0
- package/dist/nodes/sandbox.js +681 -0
- package/dist/nodes/sandbox.js.map +1 -0
- package/dist/nodes/search.d.ts +117 -0
- package/dist/nodes/search.d.ts.map +1 -0
- package/dist/nodes/search.js +607 -0
- package/dist/nodes/search.js.map +1 -0
- package/dist/nodes/team.d.ts +74 -0
- package/dist/nodes/team.d.ts.map +1 -0
- package/dist/nodes/team.js +304 -0
- package/dist/nodes/team.js.map +1 -0
- package/dist/nodes/text-extra.d.ts +633 -0
- package/dist/nodes/text-extra.d.ts.map +1 -0
- package/dist/nodes/text-extra.js +2226 -0
- package/dist/nodes/text-extra.js.map +1 -0
- package/dist/nodes/tool-agents.d.ts +334 -0
- package/dist/nodes/tool-agents.d.ts.map +1 -0
- package/dist/nodes/tool-agents.js +1861 -0
- package/dist/nodes/tool-agents.js.map +1 -0
- package/dist/nodes/triggers.d.ts +107 -0
- package/dist/nodes/triggers.d.ts.map +1 -0
- package/dist/nodes/triggers.js +706 -0
- package/dist/nodes/triggers.js.map +1 -0
- package/dist/nodes/vector.d.ts +168 -0
- package/dist/nodes/vector.d.ts.map +1 -0
- package/dist/nodes/vector.js +1121 -0
- package/dist/nodes/vector.js.map +1 -0
- package/dist/nodes/video.d.ts +387 -0
- package/dist/nodes/video.d.ts.map +1 -0
- package/dist/nodes/video.js +2361 -0
- package/dist/nodes/video.js.map +1 -0
- package/dist/nodes/workflow.d.ts +24 -0
- package/dist/nodes/workflow.d.ts.map +1 -0
- package/dist/nodes/workflow.js +146 -0
- package/dist/nodes/workflow.js.map +1 -0
- package/dist/nodes/workspace.d.ts +203 -0
- package/dist/nodes/workspace.d.ts.map +1 -0
- package/dist/nodes/workspace.js +795 -0
- package/dist/nodes/workspace.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,1274 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseNode, prop } from "@nodetool-ai/node-sdk";
|
|
8
|
+
import { promises as fs } from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { audioBytes, audioBytesAsync, audioRefFromBytes, audioRefFromWav, concatBytes, encodePcm16Wav, encodeWav, toBytes, tryDecodeWav, uriToPath } from "../lib/audio-wav.js";
|
|
11
|
+
function dateName(name) {
|
|
12
|
+
const now = new Date();
|
|
13
|
+
const pad = (v) => String(v).padStart(2, "0");
|
|
14
|
+
return name
|
|
15
|
+
.replaceAll("%Y", String(now.getFullYear()))
|
|
16
|
+
.replaceAll("%m", pad(now.getMonth() + 1))
|
|
17
|
+
.replaceAll("%d", pad(now.getDate()))
|
|
18
|
+
.replaceAll("%H", pad(now.getHours()))
|
|
19
|
+
.replaceAll("%M", pad(now.getMinutes()))
|
|
20
|
+
.replaceAll("%S", pad(now.getSeconds()));
|
|
21
|
+
}
|
|
22
|
+
function getModelConfig(props) {
|
|
23
|
+
const model = (props.model ?? {});
|
|
24
|
+
if (typeof model === "string") {
|
|
25
|
+
return { providerId: "", modelId: model };
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
providerId: typeof model.provider === "string" ? model.provider : "",
|
|
29
|
+
modelId: typeof model.id === "string" ? model.id : ""
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function hasProviderSupport(context, providerId, modelId) {
|
|
33
|
+
return (!!context &&
|
|
34
|
+
typeof context.runProviderPrediction === "function" &&
|
|
35
|
+
typeof context.streamProviderPrediction === "function" &&
|
|
36
|
+
!!providerId &&
|
|
37
|
+
!!modelId);
|
|
38
|
+
}
|
|
39
|
+
export class LoadAudioAssetsNode extends BaseNode {
|
|
40
|
+
static nodeType = "nodetool.audio.LoadAudioAssets";
|
|
41
|
+
static title = "Load Audio Assets";
|
|
42
|
+
static description = "Load audio files from an asset folder.\n load, audio, file, import";
|
|
43
|
+
static metadataOutputTypes = {
|
|
44
|
+
audio: "audio",
|
|
45
|
+
name: "str",
|
|
46
|
+
audios: "list"
|
|
47
|
+
};
|
|
48
|
+
static isStreamingOutput = true;
|
|
49
|
+
async process() {
|
|
50
|
+
const collected = [];
|
|
51
|
+
for await (const item of this._loadAudios()) {
|
|
52
|
+
collected.push(item.audio);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
audio: collected[0] ?? {},
|
|
56
|
+
name: "",
|
|
57
|
+
audios: collected
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async *_loadAudios() {
|
|
61
|
+
const raw = this.folder;
|
|
62
|
+
const folder = typeof raw === "string" && raw.length > 0
|
|
63
|
+
? raw.startsWith("file:")
|
|
64
|
+
? uriToPath(raw)
|
|
65
|
+
: raw
|
|
66
|
+
: typeof raw === "object" && raw !== null && typeof raw.uri === "string" && raw.uri.length > 0
|
|
67
|
+
? uriToPath(raw.uri)
|
|
68
|
+
: "";
|
|
69
|
+
if (!folder)
|
|
70
|
+
return;
|
|
71
|
+
let entries;
|
|
72
|
+
try {
|
|
73
|
+
entries = await fs.readdir(folder, { withFileTypes: true });
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// folder does not exist or is not accessible
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
if (!entry.isFile())
|
|
81
|
+
continue;
|
|
82
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
83
|
+
if (![".wav", ".mp3", ".m4a", ".flac", ".ogg"].includes(ext))
|
|
84
|
+
continue;
|
|
85
|
+
const full = path.join(folder, entry.name);
|
|
86
|
+
const data = new Uint8Array(await fs.readFile(full));
|
|
87
|
+
yield {
|
|
88
|
+
audio: audioRefFromBytes(data, `file://${full}`),
|
|
89
|
+
name: entry.name
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async *genProcess() {
|
|
94
|
+
const collected = [];
|
|
95
|
+
for await (const item of this._loadAudios()) {
|
|
96
|
+
collected.push(item.audio);
|
|
97
|
+
yield item;
|
|
98
|
+
}
|
|
99
|
+
yield { audios: collected };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
__decorate([
|
|
103
|
+
prop({
|
|
104
|
+
type: "folder",
|
|
105
|
+
default: {
|
|
106
|
+
type: "folder",
|
|
107
|
+
uri: "",
|
|
108
|
+
asset_id: null,
|
|
109
|
+
data: null,
|
|
110
|
+
metadata: null
|
|
111
|
+
},
|
|
112
|
+
title: "Folder",
|
|
113
|
+
description: "The asset folder to load the audio files from."
|
|
114
|
+
})
|
|
115
|
+
], LoadAudioAssetsNode.prototype, "folder", void 0);
|
|
116
|
+
export class LoadAudioFileNode extends BaseNode {
|
|
117
|
+
static nodeType = "nodetool.audio.LoadAudioFile";
|
|
118
|
+
static title = "Load Audio File";
|
|
119
|
+
static description = "Read an audio file from disk.\n audio, input, load, file";
|
|
120
|
+
static metadataOutputTypes = {
|
|
121
|
+
output: "audio"
|
|
122
|
+
};
|
|
123
|
+
async process() {
|
|
124
|
+
const p = uriToPath(String(this.path ?? ""));
|
|
125
|
+
const data = new Uint8Array(await fs.readFile(p));
|
|
126
|
+
return { output: audioRefFromBytes(data, `file://${p}`) };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
__decorate([
|
|
130
|
+
prop({
|
|
131
|
+
type: "str",
|
|
132
|
+
default: "",
|
|
133
|
+
title: "Path",
|
|
134
|
+
description: "Path to the audio file to read"
|
|
135
|
+
})
|
|
136
|
+
], LoadAudioFileNode.prototype, "path", void 0);
|
|
137
|
+
export class LoadAudioFolderNode extends BaseNode {
|
|
138
|
+
static nodeType = "nodetool.audio.LoadAudioFolder";
|
|
139
|
+
static title = "Load Audio Folder";
|
|
140
|
+
static description = "Load all audio files from a folder, optionally including subfolders.\n audio, load, folder, files";
|
|
141
|
+
static metadataOutputTypes = {
|
|
142
|
+
audio: "audio",
|
|
143
|
+
path: "str",
|
|
144
|
+
audios: "list"
|
|
145
|
+
};
|
|
146
|
+
static isStreamingOutput = true;
|
|
147
|
+
async process() {
|
|
148
|
+
const loader = new LoadAudioAssetsNode();
|
|
149
|
+
loader.assign({ folder: this.folder ?? "." });
|
|
150
|
+
const result = await loader.process();
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
async *genProcess() {
|
|
154
|
+
const loader = new LoadAudioAssetsNode();
|
|
155
|
+
loader.assign({ folder: this.folder ?? "." });
|
|
156
|
+
for await (const item of loader.genProcess()) {
|
|
157
|
+
yield item;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
__decorate([
|
|
162
|
+
prop({
|
|
163
|
+
type: "str",
|
|
164
|
+
default: "",
|
|
165
|
+
title: "Folder",
|
|
166
|
+
description: "Folder to scan for audio files"
|
|
167
|
+
})
|
|
168
|
+
], LoadAudioFolderNode.prototype, "folder", void 0);
|
|
169
|
+
__decorate([
|
|
170
|
+
prop({
|
|
171
|
+
type: "bool",
|
|
172
|
+
default: false,
|
|
173
|
+
title: "Include Subdirectories",
|
|
174
|
+
description: "Include audio in subfolders"
|
|
175
|
+
})
|
|
176
|
+
], LoadAudioFolderNode.prototype, "include_subdirectories", void 0);
|
|
177
|
+
__decorate([
|
|
178
|
+
prop({
|
|
179
|
+
type: "list[str]",
|
|
180
|
+
default: [".mp3", ".wav", ".flac", ".ogg", ".m4a", ".aac"],
|
|
181
|
+
title: "Extensions",
|
|
182
|
+
description: "Audio file extensions to include"
|
|
183
|
+
})
|
|
184
|
+
], LoadAudioFolderNode.prototype, "extensions", void 0);
|
|
185
|
+
export class SaveAudioNode extends BaseNode {
|
|
186
|
+
static nodeType = "nodetool.audio.SaveAudio";
|
|
187
|
+
static title = "Save Audio Asset";
|
|
188
|
+
static description = "Save an audio file to a specified asset folder.\n audio, folder, name";
|
|
189
|
+
static metadataOutputTypes = {
|
|
190
|
+
output: "audio"
|
|
191
|
+
};
|
|
192
|
+
static exposeAsTool = true;
|
|
193
|
+
async process() {
|
|
194
|
+
const audio = this.audio;
|
|
195
|
+
const folder = String(this.folder ?? ".");
|
|
196
|
+
const name = dateName(String(this.name ?? "audio.wav"));
|
|
197
|
+
const full = path.resolve(folder, name);
|
|
198
|
+
await fs.mkdir(path.dirname(full), { recursive: true });
|
|
199
|
+
await fs.writeFile(full, audioBytes(audio));
|
|
200
|
+
return { output: audioRefFromBytes(audioBytes(audio), `file://${full}`) };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
__decorate([
|
|
204
|
+
prop({
|
|
205
|
+
type: "audio",
|
|
206
|
+
default: {
|
|
207
|
+
type: "audio",
|
|
208
|
+
uri: "",
|
|
209
|
+
asset_id: null,
|
|
210
|
+
data: null,
|
|
211
|
+
metadata: null
|
|
212
|
+
},
|
|
213
|
+
title: "Audio"
|
|
214
|
+
})
|
|
215
|
+
], SaveAudioNode.prototype, "audio", void 0);
|
|
216
|
+
__decorate([
|
|
217
|
+
prop({
|
|
218
|
+
type: "folder",
|
|
219
|
+
default: {
|
|
220
|
+
type: "folder",
|
|
221
|
+
uri: "",
|
|
222
|
+
asset_id: null,
|
|
223
|
+
data: null,
|
|
224
|
+
metadata: null
|
|
225
|
+
},
|
|
226
|
+
title: "Folder",
|
|
227
|
+
description: "The asset folder to save the audio file to. "
|
|
228
|
+
})
|
|
229
|
+
], SaveAudioNode.prototype, "folder", void 0);
|
|
230
|
+
__decorate([
|
|
231
|
+
prop({
|
|
232
|
+
type: "str",
|
|
233
|
+
default: "%Y-%m-%d-%H-%M-%S.opus",
|
|
234
|
+
title: "Name",
|
|
235
|
+
description: "\n The name of the audio file.\n You can use time and date variables to create unique names:\n %Y - Year\n %m - Month\n %d - Day\n %H - Hour\n %M - Minute\n %S - Second\n "
|
|
236
|
+
})
|
|
237
|
+
], SaveAudioNode.prototype, "name", void 0);
|
|
238
|
+
export class SaveAudioFileNode extends BaseNode {
|
|
239
|
+
static nodeType = "nodetool.audio.SaveAudioFile";
|
|
240
|
+
static title = "Save Audio File";
|
|
241
|
+
static description = "Write an audio file to disk.\n audio, output, save, file\n\n The filename can include time and date variables:\n %Y - Year, %m - Month, %d - Day\n %H - Hour, %M - Minute, %S - Second\n\n Supported formats: mp3, wav, ogg, flac, aac, m4a";
|
|
242
|
+
static metadataOutputTypes = {
|
|
243
|
+
output: "audio"
|
|
244
|
+
};
|
|
245
|
+
async process() {
|
|
246
|
+
const audio = this.audio;
|
|
247
|
+
const folder = String(this.folder ?? ".");
|
|
248
|
+
const fname = dateName(String(this.filename ?? "audio.wav"));
|
|
249
|
+
const p = path.resolve(folder, fname);
|
|
250
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
251
|
+
await fs.writeFile(p, audioBytes(audio));
|
|
252
|
+
return { output: p };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
__decorate([
|
|
256
|
+
prop({
|
|
257
|
+
type: "audio",
|
|
258
|
+
default: {
|
|
259
|
+
type: "audio",
|
|
260
|
+
uri: "",
|
|
261
|
+
asset_id: null,
|
|
262
|
+
data: null,
|
|
263
|
+
metadata: null
|
|
264
|
+
},
|
|
265
|
+
title: "Audio",
|
|
266
|
+
description: "The audio to save"
|
|
267
|
+
})
|
|
268
|
+
], SaveAudioFileNode.prototype, "audio", void 0);
|
|
269
|
+
__decorate([
|
|
270
|
+
prop({
|
|
271
|
+
type: "str",
|
|
272
|
+
default: "",
|
|
273
|
+
title: "Folder",
|
|
274
|
+
description: "Folder where the file will be saved"
|
|
275
|
+
})
|
|
276
|
+
], SaveAudioFileNode.prototype, "folder", void 0);
|
|
277
|
+
__decorate([
|
|
278
|
+
prop({
|
|
279
|
+
type: "str",
|
|
280
|
+
default: "",
|
|
281
|
+
title: "Filename",
|
|
282
|
+
description: "\n Name of the file to save.\n You can use time and date variables to create unique names:\n %Y - Year\n %m - Month\n %d - Day\n %H - Hour\n %M - Minute\n %S - Second\n "
|
|
283
|
+
})
|
|
284
|
+
], SaveAudioFileNode.prototype, "filename", void 0);
|
|
285
|
+
__decorate([
|
|
286
|
+
prop({
|
|
287
|
+
type: "dict[str, str]",
|
|
288
|
+
default: {
|
|
289
|
+
".mp3": "mp3",
|
|
290
|
+
".wav": "wav",
|
|
291
|
+
".ogg": "ogg",
|
|
292
|
+
".flac": "flac",
|
|
293
|
+
".aac": "adts",
|
|
294
|
+
".m4a": "ipod"
|
|
295
|
+
},
|
|
296
|
+
title: "Format Map"
|
|
297
|
+
})
|
|
298
|
+
], SaveAudioFileNode.prototype, "FORMAT_MAP", void 0);
|
|
299
|
+
export class NormalizeAudioNode extends BaseNode {
|
|
300
|
+
static nodeType = "nodetool.audio.Normalize";
|
|
301
|
+
static title = "Normalize";
|
|
302
|
+
static description = "Normalizes the volume of an audio file.\n audio, fix, dynamics, volume";
|
|
303
|
+
static metadataOutputTypes = {
|
|
304
|
+
output: "audio"
|
|
305
|
+
};
|
|
306
|
+
static exposeAsTool = true;
|
|
307
|
+
async process(context) {
|
|
308
|
+
const bytes = await audioBytesAsync(this.audio, context);
|
|
309
|
+
const wav = tryDecodeWav({ data: bytes });
|
|
310
|
+
if (!wav || wav.samples.length === 0) {
|
|
311
|
+
return { output: audioRefFromBytes(bytes) };
|
|
312
|
+
}
|
|
313
|
+
let peak = 0;
|
|
314
|
+
for (const sample of wav.samples)
|
|
315
|
+
peak = Math.max(peak, Math.abs(sample));
|
|
316
|
+
if (peak === 0)
|
|
317
|
+
return { output: audioRefFromBytes(bytes) };
|
|
318
|
+
const gain = 1 / peak;
|
|
319
|
+
const normalized = new Float32Array(wav.samples.length);
|
|
320
|
+
for (let i = 0; i < wav.samples.length; i += 1) {
|
|
321
|
+
normalized[i] = wav.samples[i] * gain;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
output: audioRefFromWav(encodeWav(normalized, wav.sampleRate, wav.numChannels))
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
__decorate([
|
|
329
|
+
prop({
|
|
330
|
+
type: "audio",
|
|
331
|
+
default: {
|
|
332
|
+
type: "audio",
|
|
333
|
+
uri: "",
|
|
334
|
+
asset_id: null,
|
|
335
|
+
data: null,
|
|
336
|
+
metadata: null
|
|
337
|
+
},
|
|
338
|
+
title: "Audio",
|
|
339
|
+
description: "The audio file to normalize."
|
|
340
|
+
})
|
|
341
|
+
], NormalizeAudioNode.prototype, "audio", void 0);
|
|
342
|
+
export class OverlayAudioNode extends BaseNode {
|
|
343
|
+
static nodeType = "nodetool.audio.OverlayAudio";
|
|
344
|
+
static title = "Overlay Audio";
|
|
345
|
+
static description = "Overlays two audio files together.\n audio, edit, transform";
|
|
346
|
+
static metadataOutputTypes = {
|
|
347
|
+
output: "audio"
|
|
348
|
+
};
|
|
349
|
+
static exposeAsTool = true;
|
|
350
|
+
async process() {
|
|
351
|
+
const a = audioBytes(this.a);
|
|
352
|
+
const b = audioBytes(this.b);
|
|
353
|
+
const len = Math.max(a.length, b.length);
|
|
354
|
+
const out = new Uint8Array(len);
|
|
355
|
+
for (let i = 0; i < len; i += 1) {
|
|
356
|
+
out[i] = Math.max(a[i] ?? 0, b[i] ?? 0);
|
|
357
|
+
}
|
|
358
|
+
return { output: audioRefFromBytes(out) };
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
__decorate([
|
|
362
|
+
prop({
|
|
363
|
+
type: "audio",
|
|
364
|
+
default: {
|
|
365
|
+
type: "audio",
|
|
366
|
+
uri: "",
|
|
367
|
+
asset_id: null,
|
|
368
|
+
data: null,
|
|
369
|
+
metadata: null
|
|
370
|
+
},
|
|
371
|
+
title: "A",
|
|
372
|
+
description: "The first audio file."
|
|
373
|
+
})
|
|
374
|
+
], OverlayAudioNode.prototype, "a", void 0);
|
|
375
|
+
__decorate([
|
|
376
|
+
prop({
|
|
377
|
+
type: "audio",
|
|
378
|
+
default: {
|
|
379
|
+
type: "audio",
|
|
380
|
+
uri: "",
|
|
381
|
+
asset_id: null,
|
|
382
|
+
data: null,
|
|
383
|
+
metadata: null
|
|
384
|
+
},
|
|
385
|
+
title: "B",
|
|
386
|
+
description: "The second audio file."
|
|
387
|
+
})
|
|
388
|
+
], OverlayAudioNode.prototype, "b", void 0);
|
|
389
|
+
export class RemoveSilenceNode extends BaseNode {
|
|
390
|
+
static nodeType = "nodetool.audio.RemoveSilence";
|
|
391
|
+
static title = "Remove Silence";
|
|
392
|
+
static description = "Removes or shortens silence in an audio file with smooth transitions.\n audio, edit, clean";
|
|
393
|
+
static metadataOutputTypes = {
|
|
394
|
+
output: "audio"
|
|
395
|
+
};
|
|
396
|
+
static exposeAsTool = true;
|
|
397
|
+
async process() {
|
|
398
|
+
const data = audioBytes(this.audio);
|
|
399
|
+
const filtered = data.filter((v) => v !== 0);
|
|
400
|
+
return { output: audioRefFromBytes(filtered) };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
__decorate([
|
|
404
|
+
prop({
|
|
405
|
+
type: "audio",
|
|
406
|
+
default: {
|
|
407
|
+
type: "audio",
|
|
408
|
+
uri: "",
|
|
409
|
+
asset_id: null,
|
|
410
|
+
data: null,
|
|
411
|
+
metadata: null
|
|
412
|
+
},
|
|
413
|
+
title: "Audio",
|
|
414
|
+
description: "The audio file to process."
|
|
415
|
+
})
|
|
416
|
+
], RemoveSilenceNode.prototype, "audio", void 0);
|
|
417
|
+
__decorate([
|
|
418
|
+
prop({
|
|
419
|
+
type: "int",
|
|
420
|
+
default: 200,
|
|
421
|
+
title: "Min Length",
|
|
422
|
+
description: "Minimum length of silence to be processed (in milliseconds).",
|
|
423
|
+
min: 0,
|
|
424
|
+
max: 10000
|
|
425
|
+
})
|
|
426
|
+
], RemoveSilenceNode.prototype, "min_length", void 0);
|
|
427
|
+
__decorate([
|
|
428
|
+
prop({
|
|
429
|
+
type: "int",
|
|
430
|
+
default: -40,
|
|
431
|
+
title: "Threshold",
|
|
432
|
+
description: "Silence threshold in dB (relative to full scale). Higher values detect more silence.",
|
|
433
|
+
min: -60,
|
|
434
|
+
max: 0
|
|
435
|
+
})
|
|
436
|
+
], RemoveSilenceNode.prototype, "threshold", void 0);
|
|
437
|
+
__decorate([
|
|
438
|
+
prop({
|
|
439
|
+
type: "float",
|
|
440
|
+
default: 1,
|
|
441
|
+
title: "Reduction Factor",
|
|
442
|
+
description: "Factor to reduce silent parts (0.0 to 1.0). 0.0 keeps silence as is, 1.0 removes it completely.",
|
|
443
|
+
min: 0,
|
|
444
|
+
max: 1
|
|
445
|
+
})
|
|
446
|
+
], RemoveSilenceNode.prototype, "reduction_factor", void 0);
|
|
447
|
+
__decorate([
|
|
448
|
+
prop({
|
|
449
|
+
type: "int",
|
|
450
|
+
default: 10,
|
|
451
|
+
title: "Crossfade",
|
|
452
|
+
description: "Duration of crossfade in milliseconds to apply between segments for smooth transitions.",
|
|
453
|
+
min: 0,
|
|
454
|
+
max: 50
|
|
455
|
+
})
|
|
456
|
+
], RemoveSilenceNode.prototype, "crossfade", void 0);
|
|
457
|
+
__decorate([
|
|
458
|
+
prop({
|
|
459
|
+
type: "int",
|
|
460
|
+
default: 100,
|
|
461
|
+
title: "Min Silence Between Parts",
|
|
462
|
+
description: "Minimum silence duration in milliseconds to maintain between non-silent segments",
|
|
463
|
+
min: 0,
|
|
464
|
+
max: 500
|
|
465
|
+
})
|
|
466
|
+
], RemoveSilenceNode.prototype, "min_silence_between_parts", void 0);
|
|
467
|
+
export class SliceAudioNode extends BaseNode {
|
|
468
|
+
static nodeType = "nodetool.audio.SliceAudio";
|
|
469
|
+
static title = "Slice Audio";
|
|
470
|
+
static description = "Extracts a section of an audio file.\n audio, edit, trim";
|
|
471
|
+
static metadataOutputTypes = {
|
|
472
|
+
output: "audio"
|
|
473
|
+
};
|
|
474
|
+
static exposeAsTool = true;
|
|
475
|
+
async process() {
|
|
476
|
+
const data = audioBytes(this.audio);
|
|
477
|
+
const start = Number(this.start ?? 0);
|
|
478
|
+
let end = Number(this.end ?? -1);
|
|
479
|
+
if (end < 0)
|
|
480
|
+
end = data.length;
|
|
481
|
+
return { output: audioRefFromBytes(data.slice(start, end)) };
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
__decorate([
|
|
485
|
+
prop({
|
|
486
|
+
type: "audio",
|
|
487
|
+
default: {
|
|
488
|
+
type: "audio",
|
|
489
|
+
uri: "",
|
|
490
|
+
asset_id: null,
|
|
491
|
+
data: null,
|
|
492
|
+
metadata: null
|
|
493
|
+
},
|
|
494
|
+
title: "Audio",
|
|
495
|
+
description: "The audio file."
|
|
496
|
+
})
|
|
497
|
+
], SliceAudioNode.prototype, "audio", void 0);
|
|
498
|
+
__decorate([
|
|
499
|
+
prop({
|
|
500
|
+
type: "float",
|
|
501
|
+
default: 0,
|
|
502
|
+
title: "Start",
|
|
503
|
+
description: "The start time in seconds.",
|
|
504
|
+
min: 0
|
|
505
|
+
})
|
|
506
|
+
], SliceAudioNode.prototype, "start", void 0);
|
|
507
|
+
__decorate([
|
|
508
|
+
prop({
|
|
509
|
+
type: "float",
|
|
510
|
+
default: 1,
|
|
511
|
+
title: "End",
|
|
512
|
+
description: "The end time in seconds.",
|
|
513
|
+
min: 0
|
|
514
|
+
})
|
|
515
|
+
], SliceAudioNode.prototype, "end", void 0);
|
|
516
|
+
export class MonoToStereoNode extends BaseNode {
|
|
517
|
+
static nodeType = "nodetool.audio.MonoToStereo";
|
|
518
|
+
static title = "Mono To Stereo";
|
|
519
|
+
static description = "Converts a mono audio signal to stereo.\n audio, convert, channels";
|
|
520
|
+
static metadataOutputTypes = {
|
|
521
|
+
output: "audio"
|
|
522
|
+
};
|
|
523
|
+
static exposeAsTool = true;
|
|
524
|
+
async process() {
|
|
525
|
+
const mono = audioBytes(this.audio);
|
|
526
|
+
const out = new Uint8Array(mono.length * 2);
|
|
527
|
+
for (let i = 0; i < mono.length; i += 1) {
|
|
528
|
+
out[i * 2] = mono[i];
|
|
529
|
+
out[i * 2 + 1] = mono[i];
|
|
530
|
+
}
|
|
531
|
+
return { output: audioRefFromBytes(out) };
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
__decorate([
|
|
535
|
+
prop({
|
|
536
|
+
type: "audio",
|
|
537
|
+
default: {
|
|
538
|
+
type: "audio",
|
|
539
|
+
uri: "",
|
|
540
|
+
asset_id: null,
|
|
541
|
+
data: null,
|
|
542
|
+
metadata: null
|
|
543
|
+
},
|
|
544
|
+
title: "Audio",
|
|
545
|
+
description: "The mono audio file to convert."
|
|
546
|
+
})
|
|
547
|
+
], MonoToStereoNode.prototype, "audio", void 0);
|
|
548
|
+
export class StereoToMonoNode extends BaseNode {
|
|
549
|
+
static nodeType = "nodetool.audio.StereoToMono";
|
|
550
|
+
static title = "Stereo To Mono";
|
|
551
|
+
static description = "Converts a stereo audio signal to mono.\n audio, convert, channels";
|
|
552
|
+
static metadataOutputTypes = {
|
|
553
|
+
output: "audio"
|
|
554
|
+
};
|
|
555
|
+
static exposeAsTool = true;
|
|
556
|
+
async process() {
|
|
557
|
+
const stereo = audioBytes(this.audio);
|
|
558
|
+
const out = new Uint8Array(Math.ceil(stereo.length / 2));
|
|
559
|
+
for (let i = 0, j = 0; i < stereo.length; i += 2, j += 1) {
|
|
560
|
+
out[j] = stereo[i];
|
|
561
|
+
}
|
|
562
|
+
return { output: audioRefFromBytes(out) };
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
__decorate([
|
|
566
|
+
prop({
|
|
567
|
+
type: "audio",
|
|
568
|
+
default: {
|
|
569
|
+
type: "audio",
|
|
570
|
+
uri: "",
|
|
571
|
+
asset_id: null,
|
|
572
|
+
data: null,
|
|
573
|
+
metadata: null
|
|
574
|
+
},
|
|
575
|
+
title: "Audio",
|
|
576
|
+
description: "The stereo audio file to convert."
|
|
577
|
+
})
|
|
578
|
+
], StereoToMonoNode.prototype, "audio", void 0);
|
|
579
|
+
__decorate([
|
|
580
|
+
prop({
|
|
581
|
+
type: "str",
|
|
582
|
+
default: "average",
|
|
583
|
+
title: "Method",
|
|
584
|
+
description: "Method to use for conversion: 'average', 'left', or 'right'."
|
|
585
|
+
})
|
|
586
|
+
], StereoToMonoNode.prototype, "method", void 0);
|
|
587
|
+
export class ReverseAudioNode extends BaseNode {
|
|
588
|
+
static nodeType = "nodetool.audio.Reverse";
|
|
589
|
+
static title = "Reverse";
|
|
590
|
+
static description = "Reverses an audio file.\n audio, edit, transform";
|
|
591
|
+
static metadataOutputTypes = {
|
|
592
|
+
output: "audio"
|
|
593
|
+
};
|
|
594
|
+
static exposeAsTool = true;
|
|
595
|
+
async process() {
|
|
596
|
+
const data = audioBytes(this.audio);
|
|
597
|
+
return { output: audioRefFromBytes(new Uint8Array([...data].reverse())) };
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
__decorate([
|
|
601
|
+
prop({
|
|
602
|
+
type: "audio",
|
|
603
|
+
default: {
|
|
604
|
+
type: "audio",
|
|
605
|
+
uri: "",
|
|
606
|
+
asset_id: null,
|
|
607
|
+
data: null,
|
|
608
|
+
metadata: null
|
|
609
|
+
},
|
|
610
|
+
title: "Audio",
|
|
611
|
+
description: "The audio file to reverse."
|
|
612
|
+
})
|
|
613
|
+
], ReverseAudioNode.prototype, "audio", void 0);
|
|
614
|
+
export class FadeInAudioNode extends BaseNode {
|
|
615
|
+
static nodeType = "nodetool.audio.FadeIn";
|
|
616
|
+
static title = "Fade In";
|
|
617
|
+
static description = "Applies a fade-in effect to the beginning of an audio file.\n audio, edit, transition";
|
|
618
|
+
static metadataOutputTypes = {
|
|
619
|
+
output: "audio"
|
|
620
|
+
};
|
|
621
|
+
static exposeAsTool = true;
|
|
622
|
+
async process() {
|
|
623
|
+
const data = new Uint8Array(audioBytes(this.audio));
|
|
624
|
+
const duration = Math.max(1, Number(this.duration ?? 1024));
|
|
625
|
+
for (let i = 0; i < Math.min(duration, data.length); i += 1) {
|
|
626
|
+
data[i] = Math.floor(data[i] * (i / duration));
|
|
627
|
+
}
|
|
628
|
+
return { output: audioRefFromBytes(data) };
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
__decorate([
|
|
632
|
+
prop({
|
|
633
|
+
type: "audio",
|
|
634
|
+
default: {
|
|
635
|
+
type: "audio",
|
|
636
|
+
uri: "",
|
|
637
|
+
asset_id: null,
|
|
638
|
+
data: null,
|
|
639
|
+
metadata: null
|
|
640
|
+
},
|
|
641
|
+
title: "Audio",
|
|
642
|
+
description: "The audio file to apply fade-in to."
|
|
643
|
+
})
|
|
644
|
+
], FadeInAudioNode.prototype, "audio", void 0);
|
|
645
|
+
__decorate([
|
|
646
|
+
prop({
|
|
647
|
+
type: "float",
|
|
648
|
+
default: 1,
|
|
649
|
+
title: "Duration",
|
|
650
|
+
description: "Duration of the fade-in effect in seconds.",
|
|
651
|
+
min: 0
|
|
652
|
+
})
|
|
653
|
+
], FadeInAudioNode.prototype, "duration", void 0);
|
|
654
|
+
export class FadeOutAudioNode extends BaseNode {
|
|
655
|
+
static nodeType = "nodetool.audio.FadeOut";
|
|
656
|
+
static title = "Fade Out";
|
|
657
|
+
static description = "Applies a fade-out effect to the end of an audio file.\n audio, edit, transition";
|
|
658
|
+
static metadataOutputTypes = {
|
|
659
|
+
output: "audio"
|
|
660
|
+
};
|
|
661
|
+
static exposeAsTool = true;
|
|
662
|
+
async process() {
|
|
663
|
+
const data = new Uint8Array(audioBytes(this.audio));
|
|
664
|
+
const duration = Math.max(1, Number(this.duration ?? 1024));
|
|
665
|
+
const start = Math.max(0, data.length - duration);
|
|
666
|
+
for (let i = start; i < data.length; i += 1) {
|
|
667
|
+
const factor = (data.length - i) / Math.max(1, data.length - start);
|
|
668
|
+
data[i] = Math.floor(data[i] * factor);
|
|
669
|
+
}
|
|
670
|
+
return { output: audioRefFromBytes(data) };
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
__decorate([
|
|
674
|
+
prop({
|
|
675
|
+
type: "audio",
|
|
676
|
+
default: {
|
|
677
|
+
type: "audio",
|
|
678
|
+
uri: "",
|
|
679
|
+
asset_id: null,
|
|
680
|
+
data: null,
|
|
681
|
+
metadata: null
|
|
682
|
+
},
|
|
683
|
+
title: "Audio",
|
|
684
|
+
description: "The audio file to apply fade-out to."
|
|
685
|
+
})
|
|
686
|
+
], FadeOutAudioNode.prototype, "audio", void 0);
|
|
687
|
+
__decorate([
|
|
688
|
+
prop({
|
|
689
|
+
type: "float",
|
|
690
|
+
default: 1,
|
|
691
|
+
title: "Duration",
|
|
692
|
+
description: "Duration of the fade-out effect in seconds.",
|
|
693
|
+
min: 0
|
|
694
|
+
})
|
|
695
|
+
], FadeOutAudioNode.prototype, "duration", void 0);
|
|
696
|
+
export class RepeatAudioNode extends BaseNode {
|
|
697
|
+
static nodeType = "nodetool.audio.Repeat";
|
|
698
|
+
static title = "Repeat";
|
|
699
|
+
static description = "Loops an audio file a specified number of times.\n audio, edit, repeat";
|
|
700
|
+
static metadataOutputTypes = {
|
|
701
|
+
output: "audio"
|
|
702
|
+
};
|
|
703
|
+
static exposeAsTool = true;
|
|
704
|
+
async process() {
|
|
705
|
+
const data = audioBytes(this.audio);
|
|
706
|
+
const count = Math.max(1, Number(this.loops ?? 2));
|
|
707
|
+
return {
|
|
708
|
+
output: audioRefFromBytes(concatBytes(Array.from({ length: count }, () => data)))
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
__decorate([
|
|
713
|
+
prop({
|
|
714
|
+
type: "audio",
|
|
715
|
+
default: {
|
|
716
|
+
type: "audio",
|
|
717
|
+
uri: "",
|
|
718
|
+
asset_id: null,
|
|
719
|
+
data: null,
|
|
720
|
+
metadata: null
|
|
721
|
+
},
|
|
722
|
+
title: "Audio",
|
|
723
|
+
description: "The audio file to loop."
|
|
724
|
+
})
|
|
725
|
+
], RepeatAudioNode.prototype, "audio", void 0);
|
|
726
|
+
__decorate([
|
|
727
|
+
prop({
|
|
728
|
+
type: "int",
|
|
729
|
+
default: 2,
|
|
730
|
+
title: "Loops",
|
|
731
|
+
description: "Number of times to loop the audio. Minimum 1 (plays once), maximum 100.",
|
|
732
|
+
min: 1,
|
|
733
|
+
max: 100
|
|
734
|
+
})
|
|
735
|
+
], RepeatAudioNode.prototype, "loops", void 0);
|
|
736
|
+
export class AudioMixerNode extends BaseNode {
|
|
737
|
+
static nodeType = "nodetool.audio.AudioMixer";
|
|
738
|
+
static title = "Audio Mixer";
|
|
739
|
+
static description = "Mix up to 5 audio tracks together with individual volume controls.\n audio, mix, volume, combine, blend, layer, add, overlay";
|
|
740
|
+
static metadataOutputTypes = {
|
|
741
|
+
output: "audio"
|
|
742
|
+
};
|
|
743
|
+
async process() {
|
|
744
|
+
const entries = [
|
|
745
|
+
{ track: this.track1, volume: this.volume1 },
|
|
746
|
+
{ track: this.track2, volume: this.volume2 },
|
|
747
|
+
{ track: this.track3, volume: this.volume3 },
|
|
748
|
+
{ track: this.track4, volume: this.volume4 },
|
|
749
|
+
{ track: this.track5, volume: this.volume5 }
|
|
750
|
+
];
|
|
751
|
+
const filtered = entries.filter((e) => e.track && typeof e.track === "object");
|
|
752
|
+
const tracks = (await Promise.all(filtered.map(async (e) => ({
|
|
753
|
+
bytes: await audioBytesAsync(e.track),
|
|
754
|
+
volume: Number.isFinite(Number(e.volume)) ? Number(e.volume) : 1
|
|
755
|
+
})))).filter((t) => t.bytes.length > 0);
|
|
756
|
+
if (tracks.length === 0)
|
|
757
|
+
return { output: audioRefFromBytes(new Uint8Array()) };
|
|
758
|
+
// If every track is a valid WAV file, mix in Float32 sample space and
|
|
759
|
+
// emit a valid WAV so downstream nodes receive a playable file.
|
|
760
|
+
const parsed = tracks.map((t) => ({
|
|
761
|
+
wav: tryDecodeWav({ data: t.bytes }),
|
|
762
|
+
bytes: t.bytes,
|
|
763
|
+
volume: t.volume
|
|
764
|
+
}));
|
|
765
|
+
if (parsed.every((p) => p.wav !== null)) {
|
|
766
|
+
const wavs = parsed;
|
|
767
|
+
const len = Math.max(...wavs.map((p) => p.wav.samples.length));
|
|
768
|
+
const mixed = new Float32Array(len);
|
|
769
|
+
for (let i = 0; i < len; i += 1) {
|
|
770
|
+
let total = 0;
|
|
771
|
+
for (const p of wavs)
|
|
772
|
+
total += (p.wav.samples[i] ?? 0) * p.volume;
|
|
773
|
+
mixed[i] = total / wavs.length;
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
output: audioRefFromWav(encodeWav(mixed, wavs[0].wav.sampleRate, wavs[0].wav.numChannels))
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
// Fallback: byte-level averaging with volume scaling (preserves
|
|
780
|
+
// backward-compatible behavior for non-WAV / headerless byte streams).
|
|
781
|
+
const len = Math.max(...tracks.map((t) => t.bytes.length));
|
|
782
|
+
const out = new Uint8Array(len);
|
|
783
|
+
for (let i = 0; i < len; i += 1) {
|
|
784
|
+
let total = 0;
|
|
785
|
+
for (const t of tracks)
|
|
786
|
+
total += (t.bytes[i] ?? 0) * t.volume;
|
|
787
|
+
const avg = total / tracks.length;
|
|
788
|
+
out[i] = Math.max(0, Math.min(255, Math.round(avg)));
|
|
789
|
+
}
|
|
790
|
+
return { output: audioRefFromBytes(out) };
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
__decorate([
|
|
794
|
+
prop({
|
|
795
|
+
type: "audio",
|
|
796
|
+
default: {
|
|
797
|
+
type: "audio",
|
|
798
|
+
uri: "",
|
|
799
|
+
asset_id: null,
|
|
800
|
+
data: null,
|
|
801
|
+
metadata: null
|
|
802
|
+
},
|
|
803
|
+
title: "Track1",
|
|
804
|
+
description: "First audio track to mix."
|
|
805
|
+
})
|
|
806
|
+
], AudioMixerNode.prototype, "track1", void 0);
|
|
807
|
+
__decorate([
|
|
808
|
+
prop({
|
|
809
|
+
type: "audio",
|
|
810
|
+
default: {
|
|
811
|
+
type: "audio",
|
|
812
|
+
uri: "",
|
|
813
|
+
asset_id: null,
|
|
814
|
+
data: null,
|
|
815
|
+
metadata: null
|
|
816
|
+
},
|
|
817
|
+
title: "Track2",
|
|
818
|
+
description: "Second audio track to mix."
|
|
819
|
+
})
|
|
820
|
+
], AudioMixerNode.prototype, "track2", void 0);
|
|
821
|
+
__decorate([
|
|
822
|
+
prop({
|
|
823
|
+
type: "audio",
|
|
824
|
+
default: {
|
|
825
|
+
type: "audio",
|
|
826
|
+
uri: "",
|
|
827
|
+
asset_id: null,
|
|
828
|
+
data: null,
|
|
829
|
+
metadata: null
|
|
830
|
+
},
|
|
831
|
+
title: "Track3",
|
|
832
|
+
description: "Third audio track to mix."
|
|
833
|
+
})
|
|
834
|
+
], AudioMixerNode.prototype, "track3", void 0);
|
|
835
|
+
__decorate([
|
|
836
|
+
prop({
|
|
837
|
+
type: "audio",
|
|
838
|
+
default: {
|
|
839
|
+
type: "audio",
|
|
840
|
+
uri: "",
|
|
841
|
+
asset_id: null,
|
|
842
|
+
data: null,
|
|
843
|
+
metadata: null
|
|
844
|
+
},
|
|
845
|
+
title: "Track4",
|
|
846
|
+
description: "Fourth audio track to mix."
|
|
847
|
+
})
|
|
848
|
+
], AudioMixerNode.prototype, "track4", void 0);
|
|
849
|
+
__decorate([
|
|
850
|
+
prop({
|
|
851
|
+
type: "audio",
|
|
852
|
+
default: {
|
|
853
|
+
type: "audio",
|
|
854
|
+
uri: "",
|
|
855
|
+
asset_id: null,
|
|
856
|
+
data: null,
|
|
857
|
+
metadata: null
|
|
858
|
+
},
|
|
859
|
+
title: "Track5",
|
|
860
|
+
description: "Fifth audio track to mix."
|
|
861
|
+
})
|
|
862
|
+
], AudioMixerNode.prototype, "track5", void 0);
|
|
863
|
+
__decorate([
|
|
864
|
+
prop({
|
|
865
|
+
type: "float",
|
|
866
|
+
default: 1,
|
|
867
|
+
title: "Volume1",
|
|
868
|
+
description: "Volume for track 1. 1.0 is original volume.",
|
|
869
|
+
min: 0,
|
|
870
|
+
max: 2
|
|
871
|
+
})
|
|
872
|
+
], AudioMixerNode.prototype, "volume1", void 0);
|
|
873
|
+
__decorate([
|
|
874
|
+
prop({
|
|
875
|
+
type: "float",
|
|
876
|
+
default: 1,
|
|
877
|
+
title: "Volume2",
|
|
878
|
+
description: "Volume for track 2. 1.0 is original volume.",
|
|
879
|
+
min: 0,
|
|
880
|
+
max: 2
|
|
881
|
+
})
|
|
882
|
+
], AudioMixerNode.prototype, "volume2", void 0);
|
|
883
|
+
__decorate([
|
|
884
|
+
prop({
|
|
885
|
+
type: "float",
|
|
886
|
+
default: 1,
|
|
887
|
+
title: "Volume3",
|
|
888
|
+
description: "Volume for track 3. 1.0 is original volume.",
|
|
889
|
+
min: 0,
|
|
890
|
+
max: 2
|
|
891
|
+
})
|
|
892
|
+
], AudioMixerNode.prototype, "volume3", void 0);
|
|
893
|
+
__decorate([
|
|
894
|
+
prop({
|
|
895
|
+
type: "float",
|
|
896
|
+
default: 1,
|
|
897
|
+
title: "Volume4",
|
|
898
|
+
description: "Volume for track 4. 1.0 is original volume.",
|
|
899
|
+
min: 0,
|
|
900
|
+
max: 2
|
|
901
|
+
})
|
|
902
|
+
], AudioMixerNode.prototype, "volume4", void 0);
|
|
903
|
+
__decorate([
|
|
904
|
+
prop({
|
|
905
|
+
type: "float",
|
|
906
|
+
default: 1,
|
|
907
|
+
title: "Volume5",
|
|
908
|
+
description: "Volume for track 5. 1.0 is original volume.",
|
|
909
|
+
min: 0,
|
|
910
|
+
max: 2
|
|
911
|
+
})
|
|
912
|
+
], AudioMixerNode.prototype, "volume5", void 0);
|
|
913
|
+
export class TrimAudioNode extends BaseNode {
|
|
914
|
+
static nodeType = "nodetool.audio.Trim";
|
|
915
|
+
static title = "Trim";
|
|
916
|
+
static description = "Trim an audio file to a specified duration.\n audio, trim, cut";
|
|
917
|
+
static metadataOutputTypes = {
|
|
918
|
+
output: "audio"
|
|
919
|
+
};
|
|
920
|
+
static exposeAsTool = true;
|
|
921
|
+
async process() {
|
|
922
|
+
const data = audioBytes(this.audio);
|
|
923
|
+
const start = Math.max(0, Number(this.start ?? 0));
|
|
924
|
+
const end = Math.max(0, Number(this.end ?? 0));
|
|
925
|
+
return {
|
|
926
|
+
output: audioRefFromBytes(data.slice(start, Math.max(start, data.length - end)))
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
__decorate([
|
|
931
|
+
prop({
|
|
932
|
+
type: "audio",
|
|
933
|
+
default: {
|
|
934
|
+
type: "audio",
|
|
935
|
+
uri: "",
|
|
936
|
+
asset_id: null,
|
|
937
|
+
data: null,
|
|
938
|
+
metadata: null
|
|
939
|
+
},
|
|
940
|
+
title: "Audio",
|
|
941
|
+
description: "The audio file to trim."
|
|
942
|
+
})
|
|
943
|
+
], TrimAudioNode.prototype, "audio", void 0);
|
|
944
|
+
__decorate([
|
|
945
|
+
prop({
|
|
946
|
+
type: "float",
|
|
947
|
+
default: 0,
|
|
948
|
+
title: "Start",
|
|
949
|
+
description: "The start time of the trimmed audio in seconds.",
|
|
950
|
+
min: 0
|
|
951
|
+
})
|
|
952
|
+
], TrimAudioNode.prototype, "start", void 0);
|
|
953
|
+
__decorate([
|
|
954
|
+
prop({
|
|
955
|
+
type: "float",
|
|
956
|
+
default: 0,
|
|
957
|
+
title: "End",
|
|
958
|
+
description: "The end time of the trimmed audio in seconds.",
|
|
959
|
+
min: 0
|
|
960
|
+
})
|
|
961
|
+
], TrimAudioNode.prototype, "end", void 0);
|
|
962
|
+
export class CreateSilenceNode extends BaseNode {
|
|
963
|
+
static nodeType = "nodetool.audio.CreateSilence";
|
|
964
|
+
static title = "Create Silence";
|
|
965
|
+
static description = "Creates a silent audio file with a specified duration.\n audio, silence, empty";
|
|
966
|
+
static metadataOutputTypes = {
|
|
967
|
+
output: "audio"
|
|
968
|
+
};
|
|
969
|
+
async process() {
|
|
970
|
+
const length = Math.max(0, Number(this.duration ?? 16000));
|
|
971
|
+
return { output: audioRefFromBytes(new Uint8Array(length)) };
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
__decorate([
|
|
975
|
+
prop({
|
|
976
|
+
type: "float",
|
|
977
|
+
default: 1,
|
|
978
|
+
title: "Duration",
|
|
979
|
+
description: "The duration of the silence in seconds.",
|
|
980
|
+
min: 0
|
|
981
|
+
})
|
|
982
|
+
], CreateSilenceNode.prototype, "duration", void 0);
|
|
983
|
+
export class ConcatAudioNode extends BaseNode {
|
|
984
|
+
static nodeType = "nodetool.audio.Concat";
|
|
985
|
+
static title = "Concat";
|
|
986
|
+
static description = "Concatenates audio files together.\n audio, edit, join, +";
|
|
987
|
+
static metadataOutputTypes = {
|
|
988
|
+
output: "audio"
|
|
989
|
+
};
|
|
990
|
+
static exposeAsTool = true;
|
|
991
|
+
static isDynamic = true;
|
|
992
|
+
async process() {
|
|
993
|
+
const parts = [this.a, this.b, ...Array.from(this.dynamicProps.values())].map((value) => audioBytes(value));
|
|
994
|
+
return { output: audioRefFromBytes(concatBytes(parts)) };
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
__decorate([
|
|
998
|
+
prop({
|
|
999
|
+
type: "audio",
|
|
1000
|
+
default: {
|
|
1001
|
+
type: "audio",
|
|
1002
|
+
uri: "",
|
|
1003
|
+
asset_id: null,
|
|
1004
|
+
data: null,
|
|
1005
|
+
metadata: null
|
|
1006
|
+
},
|
|
1007
|
+
title: "A",
|
|
1008
|
+
description: "The first audio file."
|
|
1009
|
+
})
|
|
1010
|
+
], ConcatAudioNode.prototype, "a", void 0);
|
|
1011
|
+
__decorate([
|
|
1012
|
+
prop({
|
|
1013
|
+
type: "audio",
|
|
1014
|
+
default: {
|
|
1015
|
+
type: "audio",
|
|
1016
|
+
uri: "",
|
|
1017
|
+
asset_id: null,
|
|
1018
|
+
data: null,
|
|
1019
|
+
metadata: null
|
|
1020
|
+
},
|
|
1021
|
+
title: "B",
|
|
1022
|
+
description: "The second audio file."
|
|
1023
|
+
})
|
|
1024
|
+
], ConcatAudioNode.prototype, "b", void 0);
|
|
1025
|
+
export class ConcatAudioListNode extends BaseNode {
|
|
1026
|
+
static nodeType = "nodetool.audio.ConcatList";
|
|
1027
|
+
static title = "Concat List";
|
|
1028
|
+
static description = "Concatenates multiple audio files together in sequence.\n audio, edit, join, multiple, +";
|
|
1029
|
+
static metadataOutputTypes = {
|
|
1030
|
+
output: "audio"
|
|
1031
|
+
};
|
|
1032
|
+
static exposeAsTool = true;
|
|
1033
|
+
async process() {
|
|
1034
|
+
const audios = Array.isArray(this.audio_files)
|
|
1035
|
+
? this.audio_files
|
|
1036
|
+
: [];
|
|
1037
|
+
const merged = concatBytes(audios.map((a) => audioBytes(a)));
|
|
1038
|
+
return { output: audioRefFromBytes(merged) };
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
__decorate([
|
|
1042
|
+
prop({
|
|
1043
|
+
type: "list[audio]",
|
|
1044
|
+
default: [],
|
|
1045
|
+
title: "Audio Files",
|
|
1046
|
+
description: "List of audio files to concatenate in sequence."
|
|
1047
|
+
})
|
|
1048
|
+
], ConcatAudioListNode.prototype, "audio_files", void 0);
|
|
1049
|
+
export class TextToSpeechNode extends BaseNode {
|
|
1050
|
+
static nodeType = "nodetool.audio.TextToSpeech";
|
|
1051
|
+
static title = "Text To Speech";
|
|
1052
|
+
static description = "Generate speech audio from text using any supported TTS provider. Automatically routes to the appropriate backend (OpenAI, HuggingFace, MLX).\n audio, generation, AI, text-to-speech, tts, voice";
|
|
1053
|
+
static metadataOutputTypes = {
|
|
1054
|
+
audio: "audio",
|
|
1055
|
+
chunk: "chunk"
|
|
1056
|
+
};
|
|
1057
|
+
static basicFields = ["model", "text", "voice", "speed"];
|
|
1058
|
+
static autoSaveAsset = true;
|
|
1059
|
+
static exposeAsTool = true;
|
|
1060
|
+
static isStreamingOutput = true;
|
|
1061
|
+
async process(context) {
|
|
1062
|
+
const text = String(this.text ?? "");
|
|
1063
|
+
const { providerId, modelId } = getModelConfig(this.serialize());
|
|
1064
|
+
const modelObj = (this.model ?? {});
|
|
1065
|
+
const explicitVoice = typeof modelObj.selected_voice === "string"
|
|
1066
|
+
? modelObj.selected_voice
|
|
1067
|
+
: "";
|
|
1068
|
+
const voiceList = Array.isArray(modelObj.voices)
|
|
1069
|
+
? modelObj.voices
|
|
1070
|
+
: [];
|
|
1071
|
+
const voice = explicitVoice || voiceList[0] || "";
|
|
1072
|
+
if (hasProviderSupport(context, providerId, modelId)) {
|
|
1073
|
+
const chunks = [];
|
|
1074
|
+
let sampleRate = 24000;
|
|
1075
|
+
for await (const item of context.streamProviderPrediction({
|
|
1076
|
+
provider: providerId,
|
|
1077
|
+
capability: "text_to_speech",
|
|
1078
|
+
model: modelId,
|
|
1079
|
+
params: {
|
|
1080
|
+
text,
|
|
1081
|
+
voice,
|
|
1082
|
+
speed: this.speed
|
|
1083
|
+
}
|
|
1084
|
+
})) {
|
|
1085
|
+
const piece = item;
|
|
1086
|
+
if (typeof piece.sampleRate === "number" && piece.sampleRate > 0) {
|
|
1087
|
+
sampleRate = piece.sampleRate;
|
|
1088
|
+
}
|
|
1089
|
+
if (piece.samples instanceof Int16Array) {
|
|
1090
|
+
chunks.push(new Uint8Array(piece.samples.buffer.slice(piece.samples.byteOffset, piece.samples.byteOffset + piece.samples.byteLength)));
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const wav = encodePcm16Wav(concatBytes(chunks), sampleRate, 1);
|
|
1094
|
+
return { output: audioRefFromWav(wav) };
|
|
1095
|
+
}
|
|
1096
|
+
const bytes = Uint8Array.from(Buffer.from(text, "utf8"));
|
|
1097
|
+
return { output: audioRefFromBytes(bytes) };
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
__decorate([
|
|
1101
|
+
prop({
|
|
1102
|
+
type: "tts_model",
|
|
1103
|
+
default: {
|
|
1104
|
+
type: "tts_model",
|
|
1105
|
+
provider: "openai",
|
|
1106
|
+
id: "tts-1",
|
|
1107
|
+
name: "TTS 1",
|
|
1108
|
+
path: null,
|
|
1109
|
+
voices: ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
|
|
1110
|
+
selected_voice: "alloy"
|
|
1111
|
+
},
|
|
1112
|
+
title: "Model",
|
|
1113
|
+
description: "The text-to-speech model to use"
|
|
1114
|
+
})
|
|
1115
|
+
], TextToSpeechNode.prototype, "model", void 0);
|
|
1116
|
+
__decorate([
|
|
1117
|
+
prop({
|
|
1118
|
+
type: "str",
|
|
1119
|
+
default: "Hello! This is a text-to-speech demonstration.",
|
|
1120
|
+
title: "Text",
|
|
1121
|
+
description: "Text to convert to speech"
|
|
1122
|
+
})
|
|
1123
|
+
], TextToSpeechNode.prototype, "text", void 0);
|
|
1124
|
+
__decorate([
|
|
1125
|
+
prop({
|
|
1126
|
+
type: "float",
|
|
1127
|
+
default: 1,
|
|
1128
|
+
title: "Speed",
|
|
1129
|
+
description: "Speech speed multiplier (0.25 to 4.0)",
|
|
1130
|
+
min: 0.25,
|
|
1131
|
+
max: 4
|
|
1132
|
+
})
|
|
1133
|
+
], TextToSpeechNode.prototype, "speed", void 0);
|
|
1134
|
+
export class ChunkToAudioNode extends BaseNode {
|
|
1135
|
+
static nodeType = "nodetool.audio.ChunkToAudio";
|
|
1136
|
+
static title = "Chunk To Audio";
|
|
1137
|
+
static description = "Aggregates audio chunks from an input stream into AudioRef objects.\n audio, stream, chunk, aggregate, collect, batch";
|
|
1138
|
+
static metadataOutputTypes = {
|
|
1139
|
+
audio: "audio"
|
|
1140
|
+
};
|
|
1141
|
+
async process() {
|
|
1142
|
+
const chunk = this.chunk ?? {};
|
|
1143
|
+
if (chunk && typeof chunk === "object") {
|
|
1144
|
+
const image = chunk;
|
|
1145
|
+
if (image.data || image.uri) {
|
|
1146
|
+
return { output: audioRefFromBytes(toBytes(image.data)) };
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
return { output: audioRefFromBytes(new Uint8Array()) };
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
__decorate([
|
|
1153
|
+
prop({
|
|
1154
|
+
type: "chunk",
|
|
1155
|
+
default: {
|
|
1156
|
+
type: "chunk",
|
|
1157
|
+
node_id: null,
|
|
1158
|
+
thread_id: null,
|
|
1159
|
+
workflow_id: null,
|
|
1160
|
+
content_type: "text",
|
|
1161
|
+
content: "",
|
|
1162
|
+
content_metadata: {},
|
|
1163
|
+
done: false,
|
|
1164
|
+
thinking: false
|
|
1165
|
+
},
|
|
1166
|
+
title: "Chunk",
|
|
1167
|
+
description: "Stream of audio chunks"
|
|
1168
|
+
})
|
|
1169
|
+
], ChunkToAudioNode.prototype, "chunk", void 0);
|
|
1170
|
+
__decorate([
|
|
1171
|
+
prop({
|
|
1172
|
+
type: "int",
|
|
1173
|
+
default: 50,
|
|
1174
|
+
title: "Batch Size",
|
|
1175
|
+
description: "Number of chunks to aggregate per output"
|
|
1176
|
+
})
|
|
1177
|
+
], ChunkToAudioNode.prototype, "batch_size", void 0);
|
|
1178
|
+
export class GetAudioInfoNode extends BaseNode {
|
|
1179
|
+
static nodeType = "nodetool.audio.GetAudioInfo";
|
|
1180
|
+
static title = "Get Audio Info";
|
|
1181
|
+
static description = "Extract metadata from an audio file: duration, sample rate, channels, format.\n audio, info, metadata, duration, sample_rate, channels, format";
|
|
1182
|
+
static metadataOutputTypes = {
|
|
1183
|
+
duration: "float",
|
|
1184
|
+
sample_rate: "int",
|
|
1185
|
+
channels: "int",
|
|
1186
|
+
format: "str",
|
|
1187
|
+
size_bytes: "int"
|
|
1188
|
+
};
|
|
1189
|
+
async process(context) {
|
|
1190
|
+
const bytes = await audioBytesAsync(this.audio, context);
|
|
1191
|
+
if (bytes.length === 0) {
|
|
1192
|
+
return { duration: 0, sample_rate: 0, channels: 0, format: "unknown", size_bytes: 0 };
|
|
1193
|
+
}
|
|
1194
|
+
let format = "unknown";
|
|
1195
|
+
let sampleRate = 0;
|
|
1196
|
+
let channels = 0;
|
|
1197
|
+
let duration = 0;
|
|
1198
|
+
if (bytes.length >= 44) {
|
|
1199
|
+
const header = Buffer.from(bytes);
|
|
1200
|
+
const riff = header.toString("ascii", 0, 4);
|
|
1201
|
+
const wave = header.toString("ascii", 8, 12);
|
|
1202
|
+
if (riff === "RIFF" && wave === "WAVE") {
|
|
1203
|
+
format = "wav";
|
|
1204
|
+
channels = header.readUInt16LE(22);
|
|
1205
|
+
sampleRate = header.readUInt32LE(24);
|
|
1206
|
+
const bitsPerSample = header.readUInt16LE(34);
|
|
1207
|
+
const dataSize = header.readUInt32LE(40);
|
|
1208
|
+
if (sampleRate > 0 && channels > 0 && bitsPerSample > 0) {
|
|
1209
|
+
duration = dataSize / (sampleRate * channels * (bitsPerSample / 8));
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (format === "unknown" && bytes.length >= 4) {
|
|
1214
|
+
if (bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0) {
|
|
1215
|
+
format = "mp3";
|
|
1216
|
+
}
|
|
1217
|
+
else if (bytes[0] === 0x66 && bytes[1] === 0x4c &&
|
|
1218
|
+
bytes[2] === 0x61 && bytes[3] === 0x43) {
|
|
1219
|
+
format = "flac";
|
|
1220
|
+
}
|
|
1221
|
+
else if (bytes[0] === 0x4f && bytes[1] === 0x67 &&
|
|
1222
|
+
bytes[2] === 0x67 && bytes[3] === 0x53) {
|
|
1223
|
+
format = "ogg";
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return {
|
|
1227
|
+
duration: Math.round(duration * 1000) / 1000,
|
|
1228
|
+
sample_rate: sampleRate,
|
|
1229
|
+
channels,
|
|
1230
|
+
format,
|
|
1231
|
+
size_bytes: bytes.length
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
__decorate([
|
|
1236
|
+
prop({
|
|
1237
|
+
type: "audio",
|
|
1238
|
+
default: {
|
|
1239
|
+
type: "audio",
|
|
1240
|
+
uri: "",
|
|
1241
|
+
asset_id: null,
|
|
1242
|
+
data: null,
|
|
1243
|
+
metadata: null
|
|
1244
|
+
},
|
|
1245
|
+
title: "Audio",
|
|
1246
|
+
description: "The audio to inspect."
|
|
1247
|
+
})
|
|
1248
|
+
], GetAudioInfoNode.prototype, "audio", void 0);
|
|
1249
|
+
export const AUDIO_NODES = [
|
|
1250
|
+
LoadAudioAssetsNode,
|
|
1251
|
+
LoadAudioFileNode,
|
|
1252
|
+
LoadAudioFolderNode,
|
|
1253
|
+
SaveAudioNode,
|
|
1254
|
+
SaveAudioFileNode,
|
|
1255
|
+
NormalizeAudioNode,
|
|
1256
|
+
OverlayAudioNode,
|
|
1257
|
+
RemoveSilenceNode,
|
|
1258
|
+
SliceAudioNode,
|
|
1259
|
+
MonoToStereoNode,
|
|
1260
|
+
StereoToMonoNode,
|
|
1261
|
+
ReverseAudioNode,
|
|
1262
|
+
FadeInAudioNode,
|
|
1263
|
+
FadeOutAudioNode,
|
|
1264
|
+
RepeatAudioNode,
|
|
1265
|
+
AudioMixerNode,
|
|
1266
|
+
TrimAudioNode,
|
|
1267
|
+
CreateSilenceNode,
|
|
1268
|
+
ConcatAudioNode,
|
|
1269
|
+
ConcatAudioListNode,
|
|
1270
|
+
TextToSpeechNode,
|
|
1271
|
+
ChunkToAudioNode,
|
|
1272
|
+
GetAudioInfoNode
|
|
1273
|
+
];
|
|
1274
|
+
//# sourceMappingURL=audio.js.map
|