speechflow 0.9.8 → 1.0.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/CHANGELOG.md +18 -0
- package/LICENSE.txt +674 -0
- package/README.md +114 -17
- package/dst/speechflow-node-a2a-ffmpeg.js +1 -0
- package/dst/speechflow-node-a2a-ffmpeg.js.map +1 -0
- package/dst/{speechflow-node-deepl.d.ts → speechflow-node-a2a-meter.d.ts} +2 -2
- package/dst/speechflow-node-a2a-meter.js +147 -0
- package/dst/speechflow-node-a2a-meter.js.map +1 -0
- package/dst/speechflow-node-a2a-mute.d.ts +16 -0
- package/dst/speechflow-node-a2a-mute.js +90 -0
- package/dst/speechflow-node-a2a-mute.js.map +1 -0
- package/dst/{speechflow-node-whisper.d.ts → speechflow-node-a2a-vad.d.ts} +2 -5
- package/dst/speechflow-node-a2a-vad.js +272 -0
- package/dst/speechflow-node-a2a-vad.js.map +1 -0
- package/dst/speechflow-node-a2a-wav.js +1 -0
- package/dst/speechflow-node-a2a-wav.js.map +1 -0
- package/dst/speechflow-node-a2t-deepgram.js +2 -1
- package/dst/speechflow-node-a2t-deepgram.js.map +1 -0
- package/dst/speechflow-node-t2a-elevenlabs.js +1 -0
- package/dst/speechflow-node-t2a-elevenlabs.js.map +1 -0
- package/dst/{speechflow-node-elevenlabs.d.ts → speechflow-node-t2a-kokoro.d.ts} +2 -2
- package/dst/speechflow-node-t2a-kokoro.js +148 -0
- package/dst/speechflow-node-t2a-kokoro.js.map +1 -0
- package/dst/speechflow-node-t2t-deepl.js +1 -0
- package/dst/speechflow-node-t2t-deepl.js.map +1 -0
- package/dst/speechflow-node-t2t-format.js +1 -0
- package/dst/speechflow-node-t2t-format.js.map +1 -0
- package/dst/{speechflow-node-gemma.d.ts → speechflow-node-t2t-ollama.d.ts} +1 -1
- package/dst/{speechflow-node-gemma.js → speechflow-node-t2t-ollama.js} +41 -8
- package/dst/speechflow-node-t2t-ollama.js.map +1 -0
- package/dst/{speechflow-node-t2t-gemma.d.ts → speechflow-node-t2t-openai.d.ts} +2 -2
- package/dst/{speechflow-node-t2t-gemma.js → speechflow-node-t2t-openai.js} +43 -30
- package/dst/speechflow-node-t2t-openai.js.map +1 -0
- package/dst/speechflow-node-t2t-subtitle.js +1 -0
- package/dst/speechflow-node-t2t-subtitle.js.map +1 -0
- package/dst/{speechflow-node-opus.d.ts → speechflow-node-t2t-transformers.d.ts} +3 -1
- package/dst/speechflow-node-t2t-transformers.js +264 -0
- package/dst/speechflow-node-t2t-transformers.js.map +1 -0
- package/dst/speechflow-node-x2x-trace.js +3 -2
- package/dst/speechflow-node-x2x-trace.js.map +1 -0
- package/dst/speechflow-node-xio-device.js +1 -0
- package/dst/speechflow-node-xio-device.js.map +1 -0
- package/dst/speechflow-node-xio-file.js +1 -0
- package/dst/speechflow-node-xio-file.js.map +1 -0
- package/dst/speechflow-node-xio-mqtt.js +1 -0
- package/dst/speechflow-node-xio-mqtt.js.map +1 -0
- package/dst/speechflow-node-xio-websocket.js +1 -0
- package/dst/speechflow-node-xio-websocket.js.map +1 -0
- package/dst/speechflow-node.d.ts +3 -0
- package/dst/speechflow-node.js +10 -0
- package/dst/speechflow-node.js.map +1 -0
- package/dst/speechflow-utils.d.ts +33 -0
- package/dst/speechflow-utils.js +183 -1
- package/dst/speechflow-utils.js.map +1 -0
- package/dst/speechflow.js +295 -46
- package/dst/speechflow.js.map +1 -0
- package/etc/speechflow.yaml +14 -5
- package/etc/stx.conf +1 -1
- package/etc/tsconfig.json +2 -2
- package/package.json +17 -10
- package/src/speechflow-node-a2a-meter.ts +125 -0
- package/src/speechflow-node-a2a-mute.ts +101 -0
- package/src/speechflow-node-a2a-vad.ts +266 -0
- package/src/speechflow-node-a2t-deepgram.ts +1 -1
- package/src/speechflow-node-t2a-kokoro.ts +160 -0
- package/src/{speechflow-node-t2t-gemma.ts → speechflow-node-t2t-ollama.ts} +44 -10
- package/src/speechflow-node-t2t-openai.ts +246 -0
- package/src/speechflow-node-t2t-transformers.ts +249 -0
- package/src/speechflow-node-x2x-trace.ts +2 -2
- package/src/speechflow-node-xio-websocket.ts +5 -5
- package/src/speechflow-node.ts +12 -0
- package/src/speechflow-utils.ts +195 -0
- package/src/speechflow.ts +279 -46
- package/dst/speechflow-node-deepgram.d.ts +0 -12
- package/dst/speechflow-node-deepgram.js +0 -220
- package/dst/speechflow-node-deepl.js +0 -128
- package/dst/speechflow-node-device.d.ts +0 -13
- package/dst/speechflow-node-device.js +0 -205
- package/dst/speechflow-node-elevenlabs.js +0 -182
- package/dst/speechflow-node-ffmpeg.d.ts +0 -13
- package/dst/speechflow-node-ffmpeg.js +0 -152
- package/dst/speechflow-node-file.d.ts +0 -11
- package/dst/speechflow-node-file.js +0 -176
- package/dst/speechflow-node-format.d.ts +0 -11
- package/dst/speechflow-node-format.js +0 -80
- package/dst/speechflow-node-mqtt.d.ts +0 -13
- package/dst/speechflow-node-mqtt.js +0 -181
- package/dst/speechflow-node-opus.js +0 -135
- package/dst/speechflow-node-subtitle.d.ts +0 -12
- package/dst/speechflow-node-subtitle.js +0 -96
- package/dst/speechflow-node-t2t-opus.d.ts +0 -12
- package/dst/speechflow-node-t2t-opus.js +0 -135
- package/dst/speechflow-node-trace.d.ts +0 -11
- package/dst/speechflow-node-trace.js +0 -88
- package/dst/speechflow-node-wav.d.ts +0 -11
- package/dst/speechflow-node-wav.js +0 -170
- package/dst/speechflow-node-websocket.d.ts +0 -13
- package/dst/speechflow-node-websocket.js +0 -275
- package/dst/speechflow-node-whisper-common.d.ts +0 -34
- package/dst/speechflow-node-whisper-common.js +0 -7
- package/dst/speechflow-node-whisper-ggml.d.ts +0 -1
- package/dst/speechflow-node-whisper-ggml.js +0 -97
- package/dst/speechflow-node-whisper-onnx.d.ts +0 -1
- package/dst/speechflow-node-whisper-onnx.js +0 -131
- package/dst/speechflow-node-whisper-worker-ggml.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker-ggml.js +0 -97
- package/dst/speechflow-node-whisper-worker-onnx.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker-onnx.js +0 -131
- package/dst/speechflow-node-whisper-worker.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker.js +0 -116
- package/dst/speechflow-node-whisper-worker2.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker2.js +0 -82
- package/dst/speechflow-node-whisper.js +0 -604
- package/src/speechflow-node-t2t-opus.ts +0 -111
package/README.md
CHANGED
|
@@ -14,9 +14,13 @@ SpeechFlow
|
|
|
14
14
|
About
|
|
15
15
|
-----
|
|
16
16
|
|
|
17
|
-
**SpeechFlow** is a command-line interface based tool for establishing
|
|
18
|
-
directed data flow graph of audio and text processing nodes. This
|
|
19
|
-
it allows to perform various speech processing tasks in a
|
|
17
|
+
**SpeechFlow** is a command-line interface based tool for establishing
|
|
18
|
+
a directed data flow graph of audio and text processing nodes. This
|
|
19
|
+
way, it allows to perform various speech processing tasks in a very
|
|
20
|
+
flexible and configurable way. The usual supported tasks are capturing
|
|
21
|
+
audio, generate narrations of text (aka text-to-speech), generate
|
|
22
|
+
transcriptions or subtitles for audio (aka speech-to-text), and generate
|
|
23
|
+
translations for audio (aka speech-to-speech).
|
|
20
24
|
|
|
21
25
|
**SpeechFlow** comes with built-in graph nodes for
|
|
22
26
|
local file I/O,
|
|
@@ -26,8 +30,8 @@ remote MQTT network I/O,
|
|
|
26
30
|
cloud-based [Deepgram](https://deepgram.com) speech-to-text conversion,
|
|
27
31
|
cloud-based [ElevenLabs](https://elevenlabs.io/) text-to-speech conversion,
|
|
28
32
|
cloud-based [DeepL](https://deepl.com) text-to-text translation,
|
|
29
|
-
|
|
30
|
-
local [Gemma
|
|
33
|
+
cloud-based [OpenAI/GPT](https://openai.com) text-to-text translation (or spelling correction),
|
|
34
|
+
local [Ollama/Gemma](https://ollama.com) text-to-text translation (or spelling correction),
|
|
31
35
|
local [OPUS/ONNX](https://github.com/Helsinki-NLP/Opus-MT) text-to-text translation,
|
|
32
36
|
local [FFmpeg](https://ffmpeg.org/) speech-to-speech encoding,
|
|
33
37
|
local WAV speech-to-speech encoding,
|
|
@@ -88,7 +92,7 @@ They can also be found in the sample [speechflow.yaml](./etc/speechflow.yaml) fi
|
|
|
88
92
|
}
|
|
89
93
|
```
|
|
90
94
|
|
|
91
|
-
- **
|
|
95
|
+
- **Transcription**: Generate text file with German transcription of MP3 audio file:
|
|
92
96
|
|
|
93
97
|
```
|
|
94
98
|
file(path: argv.0, mode: "r", type: "audio") |
|
|
@@ -108,6 +112,15 @@ They can also be found in the sample [speechflow.yaml](./etc/speechflow.yaml) fi
|
|
|
108
112
|
file(path: argv.1, mode: "w", type: "text")
|
|
109
113
|
```
|
|
110
114
|
|
|
115
|
+
- **Speaking**: Generate audio file with English voice for a text file:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
file(path: argv.0, mode: "r", type: "text") |
|
|
119
|
+
kokoro(language: "en") |
|
|
120
|
+
wav(mode: "encode") |
|
|
121
|
+
file(path: argv.1, mode: "w", type: "audio")
|
|
122
|
+
```
|
|
123
|
+
|
|
111
124
|
- **Ad-Hoc Translation**: Ad-Hoc text translation from German to English
|
|
112
125
|
via stdin/stdout:
|
|
113
126
|
|
|
@@ -161,13 +174,17 @@ First a short overview of the available processing nodes:
|
|
|
161
174
|
**mqtt**.
|
|
162
175
|
- Audio-to-Audio nodes:
|
|
163
176
|
**ffmpeg**,
|
|
164
|
-
**wav
|
|
177
|
+
**wav**,
|
|
178
|
+
**mute**.
|
|
179
|
+
**meter**.
|
|
180
|
+
**vad**.
|
|
165
181
|
- Audio-to-Text nodes:
|
|
166
182
|
**deepgram**.
|
|
167
183
|
- Text-to-Text nodes:
|
|
168
184
|
**deepl**,
|
|
169
|
-
**
|
|
170
|
-
**
|
|
185
|
+
**openai**,
|
|
186
|
+
**ollama**,
|
|
187
|
+
**transformers**,
|
|
171
188
|
**subtitle**,
|
|
172
189
|
**format**.
|
|
173
190
|
- Text-to-Audio nodes:
|
|
@@ -268,6 +285,50 @@ First a short overview of the available processing nodes:
|
|
|
268
285
|
| ----------- | --------- | -------- | ------------------------ |
|
|
269
286
|
| **mode** | 0 | "encode" | `/^(?:encode\|decode)$/` |
|
|
270
287
|
|
|
288
|
+
- Node: **mute**<br/>
|
|
289
|
+
Purpose: **volume muting node**<br/>
|
|
290
|
+
Example: `mute()`
|
|
291
|
+
Notice: this node has to be externally controlled via REST/WebSockets!
|
|
292
|
+
|
|
293
|
+
| Port | Payload |
|
|
294
|
+
| ------- | ----------- |
|
|
295
|
+
| input | audio |
|
|
296
|
+
| output | audio |
|
|
297
|
+
|
|
298
|
+
| Parameter | Position | Default | Requirement |
|
|
299
|
+
| ----------- | --------- | -------- | ------------------------ |
|
|
300
|
+
|
|
301
|
+
- Node: **meter**<br/>
|
|
302
|
+
Purpose: **Loudness metering node**<br/>
|
|
303
|
+
Example: `meter(250)`
|
|
304
|
+
|
|
305
|
+
| Port | Payload |
|
|
306
|
+
| ------- | ----------- |
|
|
307
|
+
| input | audio |
|
|
308
|
+
| output | audio |
|
|
309
|
+
|
|
310
|
+
| Parameter | Position | Default | Requirement |
|
|
311
|
+
| ----------- | --------- | -------- | ------------------------ |
|
|
312
|
+
| **interval** | 0 | 250 | *none* |
|
|
313
|
+
|
|
314
|
+
- Node: **vad**<br/>
|
|
315
|
+
Purpose: **Voice Audio Detection (VAD) node**<br/>
|
|
316
|
+
Example: `vad()`
|
|
317
|
+
|
|
318
|
+
| Port | Payload |
|
|
319
|
+
| ------- | ----------- |
|
|
320
|
+
| input | audio |
|
|
321
|
+
| output | audio |
|
|
322
|
+
|
|
323
|
+
| Parameter | Position | Default | Requirement |
|
|
324
|
+
| ----------- | --------- | -------- | ------------------------ |
|
|
325
|
+
| **mode** | *none* | "unplugged" | `/^(?:silenced|unplugged)$/` |
|
|
326
|
+
| **posSpeechThreshold** | *none* | 0.50 | *none* |
|
|
327
|
+
| **negSpeechThreshold** | *none* | 0.35 | *none* |
|
|
328
|
+
| **minSpeechFrames** | *none* | 2 | *none* |
|
|
329
|
+
| **redemptionFrames** | *none* | 12 | *none* |
|
|
330
|
+
| **preSpeechPadFrames** | *none* | 1 | *none* |
|
|
331
|
+
|
|
271
332
|
### Audio-to-Text Nodes:
|
|
272
333
|
|
|
273
334
|
- Node: **deepgram**<br/>
|
|
@@ -305,10 +366,10 @@ First a short overview of the available processing nodes:
|
|
|
305
366
|
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
306
367
|
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
307
368
|
|
|
308
|
-
- Node: **
|
|
309
|
-
Purpose: **
|
|
310
|
-
Example: `
|
|
311
|
-
Notice
|
|
369
|
+
- Node: **openai**<br/>
|
|
370
|
+
Purpose: **OpenAI/GPT Text-to-Text translation and spelling correction**<br/>
|
|
371
|
+
Example: `openai(src: "de", dst: "en")`<br/>
|
|
372
|
+
Notice: this node requires an OpenAI API key!
|
|
312
373
|
|
|
313
374
|
| Port | Payload |
|
|
314
375
|
| ------- | ----------- |
|
|
@@ -317,13 +378,32 @@ First a short overview of the available processing nodes:
|
|
|
317
378
|
|
|
318
379
|
| Parameter | Position | Default | Requirement |
|
|
319
380
|
| ------------ | --------- | -------- | ------------------ |
|
|
320
|
-
| **
|
|
381
|
+
| **api** | *none* | "https://api.openai.com" | `/^https?:\/\/.+?:\d+$/` |
|
|
321
382
|
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
322
383
|
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
384
|
+
| **key** | *none* | env.SPEECHFLOW\_KEY\_OPENAI | *none* |
|
|
385
|
+
| **model** | *none* | "gpt-4o-mini" | *none* |
|
|
323
386
|
|
|
324
|
-
- Node: **
|
|
325
|
-
Purpose: **
|
|
326
|
-
Example: `
|
|
387
|
+
- Node: **ollama**<br/>
|
|
388
|
+
Purpose: **Ollama/Gemma Text-to-Text translation and spelling correction**<br/>
|
|
389
|
+
Example: `ollama(src: "de", dst: "en")`<br/>
|
|
390
|
+
Notice: this node requires the Ollama API!
|
|
391
|
+
|
|
392
|
+
| Port | Payload |
|
|
393
|
+
| ------- | ----------- |
|
|
394
|
+
| input | text |
|
|
395
|
+
| output | text |
|
|
396
|
+
|
|
397
|
+
| Parameter | Position | Default | Requirement |
|
|
398
|
+
| ------------ | --------- | -------- | ------------------ |
|
|
399
|
+
| **api** | *none* | "http://127.0.0.1:11434" | `/^https?:\/\/.+?:\d+$/` |
|
|
400
|
+
| **model** | *none* | "gemma3:4b-it-q4_K_M" | *none* |
|
|
401
|
+
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
402
|
+
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
403
|
+
|
|
404
|
+
- Node: **transformers**<br/>
|
|
405
|
+
Purpose: **Transformers Text-to-Text translation**<br/>
|
|
406
|
+
Example: `transformers(src: "de", dst: "en")`<br/>
|
|
327
407
|
|
|
328
408
|
| Port | Payload |
|
|
329
409
|
| ------- | ----------- |
|
|
@@ -332,6 +412,7 @@ First a short overview of the available processing nodes:
|
|
|
332
412
|
|
|
333
413
|
| Parameter | Position | Default | Requirement |
|
|
334
414
|
| ------------ | --------- | -------- | ---------------- |
|
|
415
|
+
| **model** | *none* | "OPUS" | `/^(?:OPUS|SmolLM3)$/` |
|
|
335
416
|
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
336
417
|
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
337
418
|
|
|
@@ -379,6 +460,22 @@ First a short overview of the available processing nodes:
|
|
|
379
460
|
| **voice** | 0 | "Brian" | *none* |
|
|
380
461
|
| **language** | 1 | "de" | *none* |
|
|
381
462
|
|
|
463
|
+
- Node: **kokoro**<br/>
|
|
464
|
+
Purpose: **Kokoro Text-to-Speech conversion**<br/>
|
|
465
|
+
Example: `kokoro(language: "en")`<br/>
|
|
466
|
+
Notice: this currently support English language only!
|
|
467
|
+
|
|
468
|
+
| Port | Payload |
|
|
469
|
+
| ------- | ----------- |
|
|
470
|
+
| input | text |
|
|
471
|
+
| output | audio |
|
|
472
|
+
|
|
473
|
+
| Parameter | Position | Default | Requirement |
|
|
474
|
+
| ------------ | --------- | -------- | ----------- |
|
|
475
|
+
| **voice** | 0 | "Aoede" | `/^(?:Aoede|Heart|Puck|Fenrir)$/` |
|
|
476
|
+
| **language** | 1 | "en" | `/^en$/` |
|
|
477
|
+
| **speed** | 2 | 1.25 | 1.0...1.30 |
|
|
478
|
+
|
|
382
479
|
### Any-to-Any Nodes:
|
|
383
480
|
|
|
384
481
|
- Node: **trace**<br/>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-ffmpeg.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-ffmpeg.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
-
export default class
|
|
2
|
+
export default class SpeechFlowNodeMeter extends SpeechFlowNode {
|
|
3
3
|
static name: string;
|
|
4
|
-
|
|
4
|
+
interval: ReturnType<typeof setInterval> | null;
|
|
5
5
|
constructor(id: string, cfg: {
|
|
6
6
|
[id: string]: any;
|
|
7
7
|
}, opts: {
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
4
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
5
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
/* standard dependencies */
|
|
45
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
46
|
+
/* external dependencies */
|
|
47
|
+
const audio_inspect_1 = require("audio-inspect");
|
|
48
|
+
/* internal dependencies */
|
|
49
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
50
|
+
const utils = __importStar(require("./speechflow-utils"));
|
|
51
|
+
/* SpeechFlow node for audio metering */
|
|
52
|
+
class SpeechFlowNodeMeter extends speechflow_node_1.default {
|
|
53
|
+
/* declare official node name */
|
|
54
|
+
static name = "meter";
|
|
55
|
+
/* internal state */
|
|
56
|
+
interval = null;
|
|
57
|
+
/* construct node */
|
|
58
|
+
constructor(id, cfg, opts, args) {
|
|
59
|
+
super(id, cfg, opts, args);
|
|
60
|
+
/* declare node configuration parameters */
|
|
61
|
+
this.configure({
|
|
62
|
+
interval: { type: "number", val: 250 }
|
|
63
|
+
});
|
|
64
|
+
/* declare node input/output format */
|
|
65
|
+
this.input = "audio";
|
|
66
|
+
this.output = "audio";
|
|
67
|
+
}
|
|
68
|
+
/* open node */
|
|
69
|
+
async open() {
|
|
70
|
+
/* sanity check situation */
|
|
71
|
+
if (this.config.audioBitDepth !== 16 || !this.config.audioLittleEndian)
|
|
72
|
+
throw new Error("VAD node currently supports PCM-S16LE audio only");
|
|
73
|
+
/* internal state */
|
|
74
|
+
const sampleWindowDuration = 3; /* LUFS-S requires 3s */
|
|
75
|
+
const sampleWindowSize = this.config.audioSampleRate * sampleWindowDuration;
|
|
76
|
+
let sampleWindow = new Float32Array(sampleWindowSize);
|
|
77
|
+
sampleWindow.fill(0, 0, sampleWindowSize);
|
|
78
|
+
let lufss = 0;
|
|
79
|
+
let rms = 0;
|
|
80
|
+
/* setup loundess emitting interval */
|
|
81
|
+
this.interval = setInterval(() => {
|
|
82
|
+
this.log("info", `LUFS-S: ${lufss.toFixed(1)} dB, RMS: ${rms.toFixed(1)} dB`);
|
|
83
|
+
this.sendResponse(["meter", "LUFS-S", lufss]);
|
|
84
|
+
this.sendResponse(["meter", "RMS", rms]);
|
|
85
|
+
}, this.params.interval);
|
|
86
|
+
/* provide Duplex stream and internally attach to VAD */
|
|
87
|
+
const self = this;
|
|
88
|
+
this.stream = new node_stream_1.default.Transform({
|
|
89
|
+
writableObjectMode: true,
|
|
90
|
+
readableObjectMode: true,
|
|
91
|
+
decodeStrings: false,
|
|
92
|
+
/* transform audio chunk */
|
|
93
|
+
transform(chunk, encoding, callback) {
|
|
94
|
+
if (!Buffer.isBuffer(chunk.payload))
|
|
95
|
+
callback(new Error("expected audio input as Buffer chunks"));
|
|
96
|
+
else if (chunk.payload.byteLength === 0)
|
|
97
|
+
callback();
|
|
98
|
+
else {
|
|
99
|
+
/* convert audio samples from PCM/I16 to PCM/F32 */
|
|
100
|
+
const data = utils.convertBufToF32(chunk.payload, self.config.audioLittleEndian);
|
|
101
|
+
/* update internal audio sample sliding window */
|
|
102
|
+
const fusion = new Float32Array(sampleWindow.length + data.length);
|
|
103
|
+
fusion.set(sampleWindow, 0);
|
|
104
|
+
fusion.set(data, sampleWindow.length);
|
|
105
|
+
sampleWindow = fusion.slice(fusion.length - sampleWindowSize);
|
|
106
|
+
/* asynchronously calculate the LUFS-S metric */
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
const audioData = {
|
|
109
|
+
sampleRate: self.config.audioSampleRate,
|
|
110
|
+
numberOfChannels: self.config.audioChannels,
|
|
111
|
+
channelData: [sampleWindow],
|
|
112
|
+
duration: sampleWindowDuration,
|
|
113
|
+
length: sampleWindow.length
|
|
114
|
+
};
|
|
115
|
+
const lufs = (0, audio_inspect_1.getLUFS)(audioData, {
|
|
116
|
+
channelMode: self.config.audioChannels === 1 ? "mono" : "stereo",
|
|
117
|
+
calculateShortTerm: true,
|
|
118
|
+
calculateMomentary: false,
|
|
119
|
+
calculateLoudnessRange: false,
|
|
120
|
+
calculateTruePeak: false
|
|
121
|
+
});
|
|
122
|
+
lufss = lufs.shortTerm ? lufs.shortTerm[0] : 0;
|
|
123
|
+
rms = (0, audio_inspect_1.getRMS)(audioData, { asDB: true });
|
|
124
|
+
}, 0);
|
|
125
|
+
/* pass-through original audio chunk */
|
|
126
|
+
this.push(chunk);
|
|
127
|
+
callback();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/* close node */
|
|
133
|
+
async close() {
|
|
134
|
+
/* close stream */
|
|
135
|
+
if (this.stream !== null) {
|
|
136
|
+
this.stream.destroy();
|
|
137
|
+
this.stream = null;
|
|
138
|
+
}
|
|
139
|
+
/* stop interval */
|
|
140
|
+
if (this.interval !== null) {
|
|
141
|
+
clearInterval(this.interval);
|
|
142
|
+
this.interval = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.default = SpeechFlowNodeMeter;
|
|
147
|
+
//# sourceMappingURL=speechflow-node-a2a-meter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-meter.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-meter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
+
type MuteMode = "none" | /* not muted */ "silenced" | /* muted by changing audio samples to silence */ "unplugged";
|
|
3
|
+
export default class SpeechFlowNodeMute extends SpeechFlowNode {
|
|
4
|
+
static name: string;
|
|
5
|
+
private muteMode;
|
|
6
|
+
constructor(id: string, cfg: {
|
|
7
|
+
[id: string]: any;
|
|
8
|
+
}, opts: {
|
|
9
|
+
[id: string]: any;
|
|
10
|
+
}, args: any[]);
|
|
11
|
+
receiveRequest(params: any[]): Promise<void>;
|
|
12
|
+
setMuteMode(mode: MuteMode): void;
|
|
13
|
+
open(): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
4
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
5
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
/* standard dependencies */
|
|
12
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
13
|
+
/* internal dependencies */
|
|
14
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
15
|
+
/* SpeechFlow node for muting in audio-to-audio passing */
|
|
16
|
+
class SpeechFlowNodeMute extends speechflow_node_1.default {
|
|
17
|
+
/* declare official node name */
|
|
18
|
+
static name = "mute";
|
|
19
|
+
/* internal state */
|
|
20
|
+
muteMode = "none";
|
|
21
|
+
/* construct node */
|
|
22
|
+
constructor(id, cfg, opts, args) {
|
|
23
|
+
super(id, cfg, opts, args);
|
|
24
|
+
/* declare node configuration parameters */
|
|
25
|
+
this.configure({});
|
|
26
|
+
/* declare node input/output format */
|
|
27
|
+
this.input = "audio";
|
|
28
|
+
this.output = "audio";
|
|
29
|
+
}
|
|
30
|
+
/* receive external request */
|
|
31
|
+
async receiveRequest(params) {
|
|
32
|
+
if (params.length === 2 && params[0] === "mode") {
|
|
33
|
+
if (!params[1].match(/^(?:none|silenced|unplugged)$/))
|
|
34
|
+
throw new Error("mute: invalid mode argument in external request");
|
|
35
|
+
const muteMode = params[1];
|
|
36
|
+
this.setMuteMode(muteMode);
|
|
37
|
+
this.sendResponse(["mute", "mode", muteMode]);
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
throw new Error("mute: invalid arguments in external request");
|
|
41
|
+
}
|
|
42
|
+
/* change mute mode */
|
|
43
|
+
setMuteMode(mode) {
|
|
44
|
+
this.log("info", `setting mute mode to "${mode}"`);
|
|
45
|
+
this.muteMode = mode;
|
|
46
|
+
}
|
|
47
|
+
/* open node */
|
|
48
|
+
async open() {
|
|
49
|
+
/* establish a transform stream */
|
|
50
|
+
const self = this;
|
|
51
|
+
this.stream = new node_stream_1.default.Transform({
|
|
52
|
+
readableObjectMode: true,
|
|
53
|
+
writableObjectMode: true,
|
|
54
|
+
decodeStrings: false,
|
|
55
|
+
transform(chunk, encoding, callback) {
|
|
56
|
+
if (!Buffer.isBuffer(chunk.payload))
|
|
57
|
+
callback(new Error("invalid chunk payload type"));
|
|
58
|
+
else if (self.muteMode === "unplugged")
|
|
59
|
+
/* pass-through nothing */
|
|
60
|
+
callback();
|
|
61
|
+
else if (self.muteMode === "silenced") {
|
|
62
|
+
/* pass-through a silenced chunk */
|
|
63
|
+
chunk = chunk.clone();
|
|
64
|
+
const buffer = chunk.payload;
|
|
65
|
+
buffer.fill(0);
|
|
66
|
+
callback();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
/* pass-through original chunk */
|
|
70
|
+
this.push(chunk);
|
|
71
|
+
callback();
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
final(callback) {
|
|
75
|
+
this.push(null);
|
|
76
|
+
callback();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/* close node */
|
|
81
|
+
async close() {
|
|
82
|
+
/* close stream */
|
|
83
|
+
if (this.stream !== null) {
|
|
84
|
+
this.stream.destroy();
|
|
85
|
+
this.stream = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.default = SpeechFlowNodeMute;
|
|
90
|
+
//# sourceMappingURL=speechflow-node-a2a-mute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-mute.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-mute.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
-
export default class
|
|
2
|
+
export default class SpeechFlowNodeVAD extends SpeechFlowNode {
|
|
3
3
|
static name: string;
|
|
4
|
-
private models;
|
|
5
|
-
private transcriber;
|
|
6
4
|
private vad;
|
|
7
5
|
private queue;
|
|
8
6
|
private queueRecv;
|
|
9
7
|
private queueVAD;
|
|
10
|
-
private
|
|
11
|
-
private tqueue;
|
|
8
|
+
private queueSend;
|
|
12
9
|
constructor(id: string, cfg: {
|
|
13
10
|
[id: string]: any;
|
|
14
11
|
}, opts: {
|