speechflow 1.0.0 → 1.2.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 +19 -0
- package/README.md +46 -11
- package/dst/speechflow-node-a2a-gender.d.ts +17 -0
- package/dst/speechflow-node-a2a-gender.js +272 -0
- package/dst/speechflow-node-a2a-gender.js.map +1 -0
- package/dst/speechflow-node-a2a-meter.js +7 -3
- package/dst/speechflow-node-a2a-meter.js.map +1 -1
- package/dst/speechflow-node-a2a-mute.js +1 -0
- package/dst/speechflow-node-a2a-mute.js.map +1 -1
- package/dst/speechflow-node-a2a-vad.js +47 -63
- package/dst/speechflow-node-a2a-vad.js.map +1 -1
- package/dst/speechflow-node-a2a-wav.js +145 -122
- package/dst/speechflow-node-a2a-wav.js.map +1 -1
- package/dst/speechflow-node-a2t-deepgram.d.ts +3 -0
- package/dst/speechflow-node-a2t-deepgram.js +29 -4
- package/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/dst/speechflow-node-t2a-elevenlabs.d.ts +3 -0
- package/dst/speechflow-node-t2a-elevenlabs.js +18 -6
- package/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/dst/speechflow-node-t2t-deepl.d.ts +3 -0
- package/dst/speechflow-node-t2t-deepl.js +8 -1
- package/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/dst/speechflow-node-t2t-format.js.map +1 -1
- package/dst/speechflow-node-t2t-ollama.js.map +1 -1
- package/dst/speechflow-node-t2t-openai.js +1 -1
- package/dst/speechflow-node-t2t-openai.js.map +1 -1
- package/dst/speechflow-node-t2t-subtitle.js.map +1 -1
- package/dst/speechflow-node-t2t-transformers.js.map +1 -1
- package/dst/speechflow-node-x2x-filter.d.ts +11 -0
- package/dst/speechflow-node-x2x-filter.js +113 -0
- package/dst/speechflow-node-x2x-filter.js.map +1 -0
- package/dst/speechflow-node-x2x-trace.js +25 -11
- package/dst/speechflow-node-x2x-trace.js.map +1 -1
- package/dst/speechflow-node-xio-device.js +17 -6
- package/dst/speechflow-node-xio-device.js.map +1 -1
- package/dst/speechflow-node-xio-file.js +61 -28
- package/dst/speechflow-node-xio-file.js.map +1 -1
- package/dst/speechflow-node-xio-mqtt.js +7 -5
- package/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/dst/speechflow-node-xio-websocket.js +5 -5
- package/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/dst/speechflow-node.d.ts +5 -1
- package/dst/speechflow-node.js +9 -2
- package/dst/speechflow-node.js.map +1 -1
- package/dst/speechflow-utils.d.ts +14 -1
- package/dst/speechflow-utils.js +110 -2
- package/dst/speechflow-utils.js.map +1 -1
- package/dst/speechflow.js +73 -14
- package/dst/speechflow.js.map +1 -1
- package/etc/speechflow.yaml +53 -26
- package/package.json +12 -10
- package/src/speechflow-node-a2a-gender.ts +272 -0
- package/src/speechflow-node-a2a-meter.ts +8 -4
- package/src/speechflow-node-a2a-mute.ts +1 -0
- package/src/speechflow-node-a2a-vad.ts +58 -68
- package/src/speechflow-node-a2a-wav.ts +128 -91
- package/src/speechflow-node-a2t-deepgram.ts +32 -5
- package/src/speechflow-node-t2a-elevenlabs.ts +21 -8
- package/src/speechflow-node-t2a-kokoro.ts +3 -3
- package/src/speechflow-node-t2t-deepl.ts +11 -3
- package/src/speechflow-node-t2t-format.ts +2 -2
- package/src/speechflow-node-t2t-ollama.ts +2 -2
- package/src/speechflow-node-t2t-openai.ts +3 -3
- package/src/speechflow-node-t2t-subtitle.ts +1 -1
- package/src/speechflow-node-t2t-transformers.ts +2 -2
- package/src/speechflow-node-x2x-filter.ts +122 -0
- package/src/speechflow-node-x2x-trace.ts +29 -12
- package/src/speechflow-node-xio-device.ts +24 -9
- package/src/speechflow-node-xio-file.ts +76 -36
- package/src/speechflow-node-xio-mqtt.ts +11 -9
- package/src/speechflow-node-xio-websocket.ts +7 -7
- package/src/speechflow-node.ts +11 -2
- package/src/speechflow-utils.ts +81 -2
- package/src/speechflow.ts +96 -35
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
ChangeLog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
1.2.0 (2025-07-21)
|
|
6
|
+
------------------
|
|
7
|
+
|
|
8
|
+
- IMPROVEMENT: rewrite "wav" node to be self-contained and preserve chunk information (time, meta)
|
|
9
|
+
- IMPROVEMENT: the "trace" node now also outputs meta information
|
|
10
|
+
- IMPROVEMENT: add "gender" node for male/female speaker detection (result is passed as meta information)
|
|
11
|
+
- IMPROVEMENT: add "filter" node for filtering based on meta information
|
|
12
|
+
- IMPROVEMENT: do not segment audio stream chunks for "vad" node even if it internally has to segment it
|
|
13
|
+
- IMPROVEMENT: allow chunking duration/size to be controlled for device/file nodes
|
|
14
|
+
- UPGRADE: upgrade NPM dependencies
|
|
15
|
+
|
|
16
|
+
1.1.0 (2025-07-19)
|
|
17
|
+
------------------
|
|
18
|
+
|
|
19
|
+
- IMPROVEMENT: allow querying the status of nodes: currently used for gathering credit/usage information
|
|
20
|
+
- BUGFIX: add "final" callback to Stream.Transform of "meter" node
|
|
21
|
+
- BUGFIX: fix positional argument usage in "meter" node
|
|
22
|
+
- UPGRADE: upgrade NPM dependencies
|
|
23
|
+
|
|
5
24
|
1.0.0 (2025-07-16)
|
|
6
25
|
------------------
|
|
7
26
|
|
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ They can also be found in the sample [speechflow.yaml](./etc/speechflow.yaml) fi
|
|
|
97
97
|
```
|
|
98
98
|
file(path: argv.0, mode: "r", type: "audio") |
|
|
99
99
|
ffmpeg(src: "mp3", dst: "pcm") |
|
|
100
|
-
deepgram(language: "de", key: env.
|
|
100
|
+
deepgram(language: "de", key: env.SPEECHFLOW_DEEPGRAM_KEY) |
|
|
101
101
|
format(width: 80) |
|
|
102
102
|
file(path: argv.1, mode: "w", type: "text")
|
|
103
103
|
```
|
|
@@ -107,7 +107,7 @@ They can also be found in the sample [speechflow.yaml](./etc/speechflow.yaml) fi
|
|
|
107
107
|
```
|
|
108
108
|
file(path: argv.0, mode: "r", type: "audio") |
|
|
109
109
|
ffmpeg(src: "mp3", dst: "pcm") |
|
|
110
|
-
deepgram(language: "de", key: env.
|
|
110
|
+
deepgram(language: "de", key: env.SPEECHFLOW_DEEPGRAM_KEY) |
|
|
111
111
|
subtitle(format: "vtt") |
|
|
112
112
|
file(path: argv.1, mode: "w", type: "text")
|
|
113
113
|
```
|
|
@@ -137,10 +137,10 @@ They can also be found in the sample [speechflow.yaml](./etc/speechflow.yaml) fi
|
|
|
137
137
|
device(device: "coreaudio:Elgato Wave:3", mode: "r") | {
|
|
138
138
|
wav(mode: "encode") |
|
|
139
139
|
file(path: "program-de.wav", mode: "w", type: "audio"),
|
|
140
|
-
deepgram(key: env.
|
|
140
|
+
deepgram(key: env.SPEECHFLOW_DEEPGRAM_KEY, language: "de") | {
|
|
141
141
|
format(width: 80) |
|
|
142
142
|
file(path: "program-de.txt", mode: "w", type: "text"),
|
|
143
|
-
deepl(key: env.
|
|
143
|
+
deepl(key: env.SPEECHFLOW_DEEPL_KEY, src: "de", dst: "en") | {
|
|
144
144
|
format(width: 80) |
|
|
145
145
|
file(path: "program-en.txt", mode: "w", type: "text"),
|
|
146
146
|
subtitle(format: "vtt") | {
|
|
@@ -175,9 +175,10 @@ First a short overview of the available processing nodes:
|
|
|
175
175
|
- Audio-to-Audio nodes:
|
|
176
176
|
**ffmpeg**,
|
|
177
177
|
**wav**,
|
|
178
|
-
**mute
|
|
179
|
-
**meter
|
|
180
|
-
**vad
|
|
178
|
+
**mute**,
|
|
179
|
+
**meter**,
|
|
180
|
+
**vad**,
|
|
181
|
+
**gender**.
|
|
181
182
|
- Audio-to-Text nodes:
|
|
182
183
|
**deepgram**.
|
|
183
184
|
- Text-to-Text nodes:
|
|
@@ -190,6 +191,7 @@ First a short overview of the available processing nodes:
|
|
|
190
191
|
- Text-to-Audio nodes:
|
|
191
192
|
**elevenlabs**.
|
|
192
193
|
- Any-to-Any nodes:
|
|
194
|
+
**filter**,
|
|
193
195
|
**trace**.
|
|
194
196
|
|
|
195
197
|
### Input/Output Nodes:
|
|
@@ -208,6 +210,8 @@ First a short overview of the available processing nodes:
|
|
|
208
210
|
| **path** | 0 | *none* | *none* |
|
|
209
211
|
| **mode** | 1 | "r" | `/^(?:r\|w\|rw)$/` |
|
|
210
212
|
| **type** | 2 | "audio" | `/^(?:audio\|text)$/` |
|
|
213
|
+
| **chunka** | | 200 | `10 <= n <= 1000` |
|
|
214
|
+
| **chunkt** | | 65536 | `1024 <= n <= 131072` |
|
|
211
215
|
|
|
212
216
|
- Node: **device**<br/>
|
|
213
217
|
Purpose: **Microphone/speaker device source/sink**<br/>
|
|
@@ -222,6 +226,7 @@ First a short overview of the available processing nodes:
|
|
|
222
226
|
| ----------- | --------- | -------- | ------------------ |
|
|
223
227
|
| **device** | 0 | *none* | `/^(.+?):(.+)$/` |
|
|
224
228
|
| **mode** | 1 | "rw" | `/^(?:r\|w\|rw)$/` |
|
|
229
|
+
| **chunk** | 2 | 200 | `10 <= n <= 1000` |
|
|
225
230
|
|
|
226
231
|
- Node: **websocket**<br/>
|
|
227
232
|
Purpose: **WebSocket source/sink**<br/>
|
|
@@ -329,6 +334,19 @@ First a short overview of the available processing nodes:
|
|
|
329
334
|
| **redemptionFrames** | *none* | 12 | *none* |
|
|
330
335
|
| **preSpeechPadFrames** | *none* | 1 | *none* |
|
|
331
336
|
|
|
337
|
+
- Node: **gender**<br/>
|
|
338
|
+
Purpose: **Gender Detection node**<br/>
|
|
339
|
+
Example: `gender()`
|
|
340
|
+
|
|
341
|
+
| Port | Payload |
|
|
342
|
+
| ------- | ----------- |
|
|
343
|
+
| input | audio |
|
|
344
|
+
| output | audio |
|
|
345
|
+
|
|
346
|
+
| Parameter | Position | Default | Requirement |
|
|
347
|
+
| ----------- | --------- | -------- | ------------------------ |
|
|
348
|
+
| **window** | 0 | 500 | *none* |
|
|
349
|
+
|
|
332
350
|
### Audio-to-Text Nodes:
|
|
333
351
|
|
|
334
352
|
- Node: **deepgram**<br/>
|
|
@@ -343,7 +361,8 @@ First a short overview of the available processing nodes:
|
|
|
343
361
|
|
|
344
362
|
| Parameter | Position | Default | Requirement |
|
|
345
363
|
| ------------ | --------- | -------- | ------------------ |
|
|
346
|
-
| **key** | *none* | env.SPEECHFLOW\_KEY
|
|
364
|
+
| **key** | *none* | env.SPEECHFLOW\_DEEPGRAM\_KEY | *none* |
|
|
365
|
+
| **keyAdm** | *none* | env.SPEECHFLOW\_DEEPGRAM\_KEY\_ADM | *none* |
|
|
347
366
|
| **model** | 0 | "nova-3" | *none* |
|
|
348
367
|
| **version** | 1 | "latest" | *none* |
|
|
349
368
|
| **language** | 2 | "multi" | *none* |
|
|
@@ -362,7 +381,7 @@ First a short overview of the available processing nodes:
|
|
|
362
381
|
|
|
363
382
|
| Parameter | Position | Default | Requirement |
|
|
364
383
|
| ------------ | --------- | -------- | ------------------ |
|
|
365
|
-
| **key** | *none* | env.SPEECHFLOW\_KEY
|
|
384
|
+
| **key** | *none* | env.SPEECHFLOW\_DEEPL\_KEY | *none* |
|
|
366
385
|
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
367
386
|
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
368
387
|
|
|
@@ -381,7 +400,7 @@ First a short overview of the available processing nodes:
|
|
|
381
400
|
| **api** | *none* | "https://api.openai.com" | `/^https?:\/\/.+?:\d+$/` |
|
|
382
401
|
| **src** | 0 | "de" | `/^(?:de\|en)$/` |
|
|
383
402
|
| **dst** | 1 | "en" | `/^(?:de\|en)$/` |
|
|
384
|
-
| **key** | *none* | env.SPEECHFLOW\_KEY
|
|
403
|
+
| **key** | *none* | env.SPEECHFLOW\_OPENAI\_KEY | *none* |
|
|
385
404
|
| **model** | *none* | "gpt-4o-mini" | *none* |
|
|
386
405
|
|
|
387
406
|
- Node: **ollama**<br/>
|
|
@@ -456,7 +475,7 @@ First a short overview of the available processing nodes:
|
|
|
456
475
|
|
|
457
476
|
| Parameter | Position | Default | Requirement |
|
|
458
477
|
| ------------ | --------- | -------- | ------------------ |
|
|
459
|
-
| **key** | *none* | env.SPEECHFLOW\_KEY
|
|
478
|
+
| **key** | *none* | env.SPEECHFLOW\_ELEVENLABS\_KEY | *none* |
|
|
460
479
|
| **voice** | 0 | "Brian" | *none* |
|
|
461
480
|
| **language** | 1 | "de" | *none* |
|
|
462
481
|
|
|
@@ -478,6 +497,22 @@ First a short overview of the available processing nodes:
|
|
|
478
497
|
|
|
479
498
|
### Any-to-Any Nodes:
|
|
480
499
|
|
|
500
|
+
- Node: **filter**<br/>
|
|
501
|
+
Purpose: **meta information based filter**<br/>
|
|
502
|
+
Example: `filter(type: "audio", var: "meta:gender", op: "==", val: "male")`<br/>
|
|
503
|
+
|
|
504
|
+
| Port | Payload |
|
|
505
|
+
| ------- | ----------- |
|
|
506
|
+
| input | text, audio |
|
|
507
|
+
| output | text, audio |
|
|
508
|
+
|
|
509
|
+
| Parameter | Position | Default | Requirement |
|
|
510
|
+
| ------------ | --------- | -------- | --------------------- |
|
|
511
|
+
| **type** | 0 | "audio" | `/^(?:audio\|text)$/` |
|
|
512
|
+
| **var** | 1 | "" | `/^(?:meta:.+|payload:(?:length|text)|time:(?:start|end))$/` |
|
|
513
|
+
| **op** | 2 | "==" | `/^(?:<|<=|==|!=|~~|!~|>=|>)$/` |
|
|
514
|
+
| **val** | 3 | "" | `/^.*$/` |
|
|
515
|
+
|
|
481
516
|
- Node: **trace**<br/>
|
|
482
517
|
Purpose: **data flow tracing**<br/>
|
|
483
518
|
Example: `trace(type: "audio")`<br/>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
+
export default class SpeechFlowNodeGender extends SpeechFlowNode {
|
|
3
|
+
static name: string;
|
|
4
|
+
private static speexInitialized;
|
|
5
|
+
private classifier;
|
|
6
|
+
private queue;
|
|
7
|
+
private queueRecv;
|
|
8
|
+
private queueAC;
|
|
9
|
+
private queueSend;
|
|
10
|
+
constructor(id: string, cfg: {
|
|
11
|
+
[id: string]: any;
|
|
12
|
+
}, opts: {
|
|
13
|
+
[id: string]: any;
|
|
14
|
+
}, args: any[]);
|
|
15
|
+
open(): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
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_path_1 = __importDefault(require("node:path"));
|
|
46
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
47
|
+
/* external dependencies */
|
|
48
|
+
const Transformers = __importStar(require("@huggingface/transformers"));
|
|
49
|
+
const wavefile_1 = require("wavefile");
|
|
50
|
+
/* internal dependencies */
|
|
51
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
52
|
+
const utils = __importStar(require("./speechflow-utils"));
|
|
53
|
+
/* SpeechFlow node for Gender recognition */
|
|
54
|
+
class SpeechFlowNodeGender extends speechflow_node_1.default {
|
|
55
|
+
/* declare official node name */
|
|
56
|
+
static name = "gender";
|
|
57
|
+
/* internal state */
|
|
58
|
+
static speexInitialized = false;
|
|
59
|
+
classifier = null;
|
|
60
|
+
queue = new utils.Queue();
|
|
61
|
+
queueRecv = this.queue.pointerUse("recv");
|
|
62
|
+
queueAC = this.queue.pointerUse("ac");
|
|
63
|
+
queueSend = this.queue.pointerUse("send");
|
|
64
|
+
/* construct node */
|
|
65
|
+
constructor(id, cfg, opts, args) {
|
|
66
|
+
super(id, cfg, opts, args);
|
|
67
|
+
/* declare node configuration parameters */
|
|
68
|
+
this.configure({
|
|
69
|
+
window: { type: "number", pos: 0, val: 500 }
|
|
70
|
+
});
|
|
71
|
+
/* declare node input/output format */
|
|
72
|
+
this.input = "audio";
|
|
73
|
+
this.output = "audio";
|
|
74
|
+
}
|
|
75
|
+
/* open node */
|
|
76
|
+
async open() {
|
|
77
|
+
/* sanity check situation */
|
|
78
|
+
if (this.config.audioBitDepth !== 16 || !this.config.audioLittleEndian)
|
|
79
|
+
throw new Error("Gender node currently supports PCM-S16LE audio only");
|
|
80
|
+
/* pass-through logging */
|
|
81
|
+
const log = (level, msg) => { this.log(level, msg); };
|
|
82
|
+
/* the used model */
|
|
83
|
+
const model = "Xenova/wav2vec2-large-xlsr-53-gender-recognition-librispeech";
|
|
84
|
+
/* track download progress when instantiating Transformers engine and model */
|
|
85
|
+
const progressState = new Map();
|
|
86
|
+
const progressCallback = (progress) => {
|
|
87
|
+
let artifact = model;
|
|
88
|
+
if (typeof progress.file === "string")
|
|
89
|
+
artifact += `:${progress.file}`;
|
|
90
|
+
let percent = 0;
|
|
91
|
+
if (typeof progress.loaded === "number" && typeof progress.total === "number")
|
|
92
|
+
percent = progress.loaded / progress.total * 100;
|
|
93
|
+
else if (typeof progress.progress === "number")
|
|
94
|
+
percent = progress.progress;
|
|
95
|
+
if (percent > 0)
|
|
96
|
+
progressState.set(artifact, percent);
|
|
97
|
+
};
|
|
98
|
+
const interval = setInterval(() => {
|
|
99
|
+
for (const [artifact, percent] of progressState) {
|
|
100
|
+
this.log("info", `downloaded ${percent.toFixed(2)}% of artifact "${artifact}"`);
|
|
101
|
+
if (percent >= 1.0)
|
|
102
|
+
progressState.delete(artifact);
|
|
103
|
+
}
|
|
104
|
+
}, 1000);
|
|
105
|
+
/* instantiate Transformers engine and model */
|
|
106
|
+
const pipeline = Transformers.pipeline("audio-classification", model, {
|
|
107
|
+
cache_dir: node_path_1.default.join(this.config.cacheDir, "gender"),
|
|
108
|
+
dtype: "q4",
|
|
109
|
+
device: "auto",
|
|
110
|
+
progress_callback: progressCallback
|
|
111
|
+
});
|
|
112
|
+
this.classifier = await pipeline;
|
|
113
|
+
clearInterval(interval);
|
|
114
|
+
if (this.classifier === null)
|
|
115
|
+
throw new Error("failed to instantiate classifier pipeline");
|
|
116
|
+
/* classify a single large-enough concatenated audio frame */
|
|
117
|
+
const classify = async (data) => {
|
|
118
|
+
const result = await this.classifier(data);
|
|
119
|
+
const classified = Array.isArray(result) ? result : [result];
|
|
120
|
+
const c1 = classified.find((c) => c.label === "male");
|
|
121
|
+
const c2 = classified.find((c) => c.label === "female");
|
|
122
|
+
const male = c1 ? c1.score : 0.0;
|
|
123
|
+
const female = c2 ? c2.score : 0.0;
|
|
124
|
+
return (male > female ? "male" : "female");
|
|
125
|
+
};
|
|
126
|
+
/* work off queued audio frames */
|
|
127
|
+
const frameWindowDuration = 0.5;
|
|
128
|
+
const frameWindowSamples = frameWindowDuration * this.config.audioSampleRate;
|
|
129
|
+
let lastGender = "";
|
|
130
|
+
let workingOffTimer = null;
|
|
131
|
+
let workingOff = false;
|
|
132
|
+
const workOffQueue = async () => {
|
|
133
|
+
/* control working off round */
|
|
134
|
+
if (workingOff)
|
|
135
|
+
return;
|
|
136
|
+
workingOff = true;
|
|
137
|
+
if (workingOffTimer !== null) {
|
|
138
|
+
clearTimeout(workingOffTimer);
|
|
139
|
+
workingOffTimer = null;
|
|
140
|
+
}
|
|
141
|
+
let pos0 = this.queueAC.position();
|
|
142
|
+
const posL = this.queueAC.maxPosition();
|
|
143
|
+
const data = new Float32Array(frameWindowSamples);
|
|
144
|
+
data.fill(0);
|
|
145
|
+
let samples = 0;
|
|
146
|
+
let pos = pos0;
|
|
147
|
+
while (pos < posL && samples < frameWindowSamples) {
|
|
148
|
+
const element = this.queueAC.peek(pos);
|
|
149
|
+
if (element === undefined || element.type !== "audio-frame")
|
|
150
|
+
break;
|
|
151
|
+
if ((samples + element.data.length) < frameWindowSamples) {
|
|
152
|
+
data.set(element.data, samples);
|
|
153
|
+
samples += element.data.length;
|
|
154
|
+
}
|
|
155
|
+
pos++;
|
|
156
|
+
}
|
|
157
|
+
if (pos0 < pos && samples > frameWindowSamples * 0.75) {
|
|
158
|
+
const gender = await classify(data);
|
|
159
|
+
const posM = pos0 + Math.trunc((pos - pos0) * 0.25);
|
|
160
|
+
while (pos0 < posM && pos0 < posL) {
|
|
161
|
+
const element = this.queueAC.peek(pos0);
|
|
162
|
+
if (element === undefined || element.type !== "audio-frame")
|
|
163
|
+
break;
|
|
164
|
+
element.gender = gender;
|
|
165
|
+
this.queueAC.touch();
|
|
166
|
+
this.queueAC.walk(+1);
|
|
167
|
+
pos0++;
|
|
168
|
+
}
|
|
169
|
+
if (lastGender !== gender) {
|
|
170
|
+
log("info", `gender now recognized as <${gender}>`);
|
|
171
|
+
lastGender = gender;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/* re-initiate working off round */
|
|
175
|
+
workingOff = false;
|
|
176
|
+
workingOffTimer = setTimeout(() => { workOffQueue(); }, 100);
|
|
177
|
+
this.queue.once("write", () => { workOffQueue(); });
|
|
178
|
+
};
|
|
179
|
+
this.queue.once("write", () => { workOffQueue(); });
|
|
180
|
+
/* define sample rate required by model */
|
|
181
|
+
const sampleRateTarget = 16000;
|
|
182
|
+
/* provide Duplex stream and internally attach to classifier */
|
|
183
|
+
const self = this;
|
|
184
|
+
this.stream = new node_stream_1.default.Duplex({
|
|
185
|
+
writableObjectMode: true,
|
|
186
|
+
readableObjectMode: true,
|
|
187
|
+
decodeStrings: false,
|
|
188
|
+
/* receive audio chunk (writable side of stream) */
|
|
189
|
+
write(chunk, encoding, callback) {
|
|
190
|
+
if (!Buffer.isBuffer(chunk.payload))
|
|
191
|
+
callback(new Error("expected audio input as Buffer chunks"));
|
|
192
|
+
else if (chunk.payload.byteLength === 0)
|
|
193
|
+
callback();
|
|
194
|
+
else {
|
|
195
|
+
/* convert audio samples from PCM/I16/48KHz to PCM/F32/16KHz */
|
|
196
|
+
let data = utils.convertBufToF32(chunk.payload, self.config.audioLittleEndian);
|
|
197
|
+
const wav = new wavefile_1.WaveFile();
|
|
198
|
+
wav.fromScratch(self.config.audioChannels, self.config.audioSampleRate, "32f", data);
|
|
199
|
+
wav.toSampleRate(sampleRateTarget, { method: "cubic" });
|
|
200
|
+
data = wav.getSamples(false, (Float32Array));
|
|
201
|
+
/* queue chunk and converted data */
|
|
202
|
+
self.queueRecv.append({ type: "audio-frame", chunk, data });
|
|
203
|
+
callback();
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
/* receive no more audio chunks (writable side of stream) */
|
|
207
|
+
final(callback) {
|
|
208
|
+
/* signal end of file */
|
|
209
|
+
self.queueRecv.append({ type: "audio-eof" });
|
|
210
|
+
callback();
|
|
211
|
+
},
|
|
212
|
+
/* send audio chunk(s) (readable side of stream) */
|
|
213
|
+
read(_size) {
|
|
214
|
+
/* flush pending audio chunks */
|
|
215
|
+
const flushPendingChunks = () => {
|
|
216
|
+
while (true) {
|
|
217
|
+
const element = self.queueSend.peek();
|
|
218
|
+
if (element === undefined)
|
|
219
|
+
break;
|
|
220
|
+
else if (element.type === "audio-eof") {
|
|
221
|
+
this.push(null);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
else if (element.type === "audio-frame"
|
|
225
|
+
&& element.gender === undefined)
|
|
226
|
+
break;
|
|
227
|
+
const duration = utils.audioArrayDuration(element.data);
|
|
228
|
+
log("info", `send chunk (${duration.toFixed(3)}s) with gender <${element.gender}>`);
|
|
229
|
+
element.chunk.meta.set("gender", element.gender);
|
|
230
|
+
this.push(element.chunk);
|
|
231
|
+
self.queueSend.walk(+1);
|
|
232
|
+
self.queue.trim();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
/* await forthcoming audio chunks */
|
|
236
|
+
const awaitForthcomingChunks = () => {
|
|
237
|
+
const element = self.queueSend.peek();
|
|
238
|
+
if (element !== undefined
|
|
239
|
+
&& element.type === "audio-frame"
|
|
240
|
+
&& element.gender !== undefined)
|
|
241
|
+
flushPendingChunks();
|
|
242
|
+
else
|
|
243
|
+
self.queue.once("write", awaitForthcomingChunks);
|
|
244
|
+
};
|
|
245
|
+
const element = self.queueSend.peek();
|
|
246
|
+
if (element !== undefined && element.type === "audio-eof")
|
|
247
|
+
this.push(null);
|
|
248
|
+
else if (element !== undefined
|
|
249
|
+
&& element.type === "audio-frame"
|
|
250
|
+
&& element.gender !== undefined)
|
|
251
|
+
flushPendingChunks();
|
|
252
|
+
else
|
|
253
|
+
self.queue.once("write", awaitForthcomingChunks);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/* close node */
|
|
258
|
+
async close() {
|
|
259
|
+
/* close stream */
|
|
260
|
+
if (this.stream !== null) {
|
|
261
|
+
this.stream.destroy();
|
|
262
|
+
this.stream = null;
|
|
263
|
+
}
|
|
264
|
+
/* close classifier */
|
|
265
|
+
if (this.classifier !== null) {
|
|
266
|
+
this.classifier.dispose();
|
|
267
|
+
this.classifier = null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
exports.default = SpeechFlowNodeGender;
|
|
272
|
+
//# sourceMappingURL=speechflow-node-a2a-gender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-gender.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-gender.ts"],"names":[],"mappings":"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"}
|
|
@@ -59,7 +59,7 @@ class SpeechFlowNodeMeter extends speechflow_node_1.default {
|
|
|
59
59
|
super(id, cfg, opts, args);
|
|
60
60
|
/* declare node configuration parameters */
|
|
61
61
|
this.configure({
|
|
62
|
-
interval: { type: "number", val: 250 }
|
|
62
|
+
interval: { type: "number", pos: 0, val: 250 }
|
|
63
63
|
});
|
|
64
64
|
/* declare node input/output format */
|
|
65
65
|
this.input = "audio";
|
|
@@ -69,7 +69,7 @@ class SpeechFlowNodeMeter extends speechflow_node_1.default {
|
|
|
69
69
|
async open() {
|
|
70
70
|
/* sanity check situation */
|
|
71
71
|
if (this.config.audioBitDepth !== 16 || !this.config.audioLittleEndian)
|
|
72
|
-
throw new Error("
|
|
72
|
+
throw new Error("meter node currently supports PCM-S16LE audio only");
|
|
73
73
|
/* internal state */
|
|
74
74
|
const sampleWindowDuration = 3; /* LUFS-S requires 3s */
|
|
75
75
|
const sampleWindowSize = this.config.audioSampleRate * sampleWindowDuration;
|
|
@@ -77,7 +77,7 @@ class SpeechFlowNodeMeter extends speechflow_node_1.default {
|
|
|
77
77
|
sampleWindow.fill(0, 0, sampleWindowSize);
|
|
78
78
|
let lufss = 0;
|
|
79
79
|
let rms = 0;
|
|
80
|
-
/* setup
|
|
80
|
+
/* setup loudness emitting interval */
|
|
81
81
|
this.interval = setInterval(() => {
|
|
82
82
|
this.log("info", `LUFS-S: ${lufss.toFixed(1)} dB, RMS: ${rms.toFixed(1)} dB`);
|
|
83
83
|
this.sendResponse(["meter", "LUFS-S", lufss]);
|
|
@@ -126,6 +126,10 @@ class SpeechFlowNodeMeter extends speechflow_node_1.default {
|
|
|
126
126
|
this.push(chunk);
|
|
127
127
|
callback();
|
|
128
128
|
}
|
|
129
|
+
},
|
|
130
|
+
final(callback) {
|
|
131
|
+
this.push(null);
|
|
132
|
+
callback();
|
|
129
133
|
}
|
|
130
134
|
});
|
|
131
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speechflow-node-a2a-meter.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-meter.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,
|
|
1
|
+
{"version":3,"file":"speechflow-node-a2a-meter.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-meter.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,6 +61,7 @@ class SpeechFlowNodeMute extends speechflow_node_1.default {
|
|
|
61
61
|
else if (self.muteMode === "silenced") {
|
|
62
62
|
/* pass-through a silenced chunk */
|
|
63
63
|
chunk = chunk.clone();
|
|
64
|
+
chunk.meta.set("muted", true);
|
|
64
65
|
const buffer = chunk.payload;
|
|
65
66
|
buffer.fill(0);
|
|
66
67
|
callback();
|
|
@@ -1 +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
|
+
{"version":3,"file":"speechflow-node-a2a-mute.js","sourceRoot":"","sources":["../src/speechflow-node-a2a-mute.ts"],"names":[],"mappings":"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"}
|