speechflow 1.4.5 → 1.5.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.
Files changed (166) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +220 -7
  3. package/etc/claude.md +70 -0
  4. package/etc/speechflow.yaml +5 -3
  5. package/etc/stx.conf +7 -0
  6. package/package.json +7 -6
  7. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.d.ts +1 -0
  8. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +155 -0
  9. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -0
  10. package/speechflow-cli/dst/speechflow-node-a2a-compressor.d.ts +15 -0
  11. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +287 -0
  12. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -0
  13. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.d.ts +1 -0
  14. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.js +208 -0
  15. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.js.map +1 -0
  16. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.d.ts +15 -0
  17. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.js +312 -0
  18. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.js.map +1 -0
  19. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.d.ts +1 -0
  20. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +161 -0
  21. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js.map +1 -0
  22. package/speechflow-cli/dst/speechflow-node-a2a-expander.d.ts +13 -0
  23. package/speechflow-cli/dst/speechflow-node-a2a-expander.js +208 -0
  24. package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -0
  25. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +13 -3
  26. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
  27. package/speechflow-cli/dst/speechflow-node-a2a-filler.d.ts +14 -0
  28. package/speechflow-cli/dst/speechflow-node-a2a-filler.js +233 -0
  29. package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -0
  30. package/speechflow-cli/dst/speechflow-node-a2a-gain.d.ts +12 -0
  31. package/speechflow-cli/dst/speechflow-node-a2a-gain.js +125 -0
  32. package/speechflow-cli/dst/speechflow-node-a2a-gain.js.map +1 -0
  33. package/speechflow-cli/dst/speechflow-node-a2a-gender.d.ts +0 -1
  34. package/speechflow-cli/dst/speechflow-node-a2a-gender.js +28 -12
  35. package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
  36. package/speechflow-cli/dst/speechflow-node-a2a-meter.d.ts +1 -0
  37. package/speechflow-cli/dst/speechflow-node-a2a-meter.js +12 -8
  38. package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
  39. package/speechflow-cli/dst/speechflow-node-a2a-mute.js +2 -1
  40. package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
  41. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.d.ts +1 -0
  42. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js +55 -0
  43. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js.map +1 -0
  44. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.d.ts +14 -0
  45. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js +184 -0
  46. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -0
  47. package/speechflow-cli/dst/speechflow-node-a2a-speex.d.ts +14 -0
  48. package/speechflow-cli/dst/speechflow-node-a2a-speex.js +156 -0
  49. package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -0
  50. package/speechflow-cli/dst/speechflow-node-a2a-vad.js +3 -3
  51. package/speechflow-cli/dst/speechflow-node-a2a-vad.js.map +1 -1
  52. package/speechflow-cli/dst/speechflow-node-a2a-wav.js +22 -17
  53. package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
  54. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.d.ts +18 -0
  55. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.js +317 -0
  56. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.js.map +1 -0
  57. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +15 -13
  58. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
  59. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.d.ts +19 -0
  60. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.js +351 -0
  61. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.js.map +1 -0
  62. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.d.ts +16 -0
  63. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.js +171 -0
  64. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.js.map +1 -0
  65. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +19 -14
  66. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
  67. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +11 -6
  68. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
  69. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.d.ts +13 -0
  70. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.js +141 -0
  71. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.js.map +1 -0
  72. package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +13 -15
  73. package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
  74. package/speechflow-cli/dst/speechflow-node-t2t-format.js +10 -15
  75. package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
  76. package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +44 -31
  77. package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +1 -1
  78. package/speechflow-cli/dst/speechflow-node-t2t-openai.js +44 -45
  79. package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +1 -1
  80. package/speechflow-cli/dst/speechflow-node-t2t-sentence.js +8 -8
  81. package/speechflow-cli/dst/speechflow-node-t2t-sentence.js.map +1 -1
  82. package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +10 -12
  83. package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
  84. package/speechflow-cli/dst/speechflow-node-t2t-transformers.js +22 -27
  85. package/speechflow-cli/dst/speechflow-node-t2t-transformers.js.map +1 -1
  86. package/speechflow-cli/dst/speechflow-node-x2x-filter.d.ts +1 -0
  87. package/speechflow-cli/dst/speechflow-node-x2x-filter.js +50 -15
  88. package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
  89. package/speechflow-cli/dst/speechflow-node-x2x-trace.js +17 -18
  90. package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
  91. package/speechflow-cli/dst/speechflow-node-xio-device.js +13 -21
  92. package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
  93. package/speechflow-cli/dst/speechflow-node-xio-mqtt.d.ts +1 -0
  94. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +22 -16
  95. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
  96. package/speechflow-cli/dst/speechflow-node-xio-websocket.js +19 -19
  97. package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
  98. package/speechflow-cli/dst/speechflow-node.d.ts +6 -3
  99. package/speechflow-cli/dst/speechflow-node.js +13 -2
  100. package/speechflow-cli/dst/speechflow-node.js.map +1 -1
  101. package/speechflow-cli/dst/speechflow-utils-audio-wt.d.ts +1 -0
  102. package/speechflow-cli/dst/speechflow-utils-audio-wt.js +124 -0
  103. package/speechflow-cli/dst/speechflow-utils-audio-wt.js.map +1 -0
  104. package/speechflow-cli/dst/speechflow-utils-audio.d.ts +13 -0
  105. package/speechflow-cli/dst/speechflow-utils-audio.js +137 -0
  106. package/speechflow-cli/dst/speechflow-utils-audio.js.map +1 -0
  107. package/speechflow-cli/dst/speechflow-utils.d.ts +18 -0
  108. package/speechflow-cli/dst/speechflow-utils.js +123 -35
  109. package/speechflow-cli/dst/speechflow-utils.js.map +1 -1
  110. package/speechflow-cli/dst/speechflow.js +69 -14
  111. package/speechflow-cli/dst/speechflow.js.map +1 -1
  112. package/speechflow-cli/etc/oxlint.jsonc +112 -11
  113. package/speechflow-cli/etc/stx.conf +2 -2
  114. package/speechflow-cli/etc/tsconfig.json +1 -1
  115. package/speechflow-cli/package.d/@shiguredo+rnnoise-wasm+2025.1.5.patch +25 -0
  116. package/speechflow-cli/package.json +102 -94
  117. package/speechflow-cli/src/lib.d.ts +24 -0
  118. package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +151 -0
  119. package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +303 -0
  120. package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +158 -0
  121. package/speechflow-cli/src/speechflow-node-a2a-expander.ts +212 -0
  122. package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +13 -3
  123. package/speechflow-cli/src/speechflow-node-a2a-filler.ts +223 -0
  124. package/speechflow-cli/src/speechflow-node-a2a-gain.ts +98 -0
  125. package/speechflow-cli/src/speechflow-node-a2a-gender.ts +31 -17
  126. package/speechflow-cli/src/speechflow-node-a2a-meter.ts +13 -9
  127. package/speechflow-cli/src/speechflow-node-a2a-mute.ts +3 -2
  128. package/speechflow-cli/src/speechflow-node-a2a-rnnoise-wt.ts +62 -0
  129. package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +164 -0
  130. package/speechflow-cli/src/speechflow-node-a2a-speex.ts +137 -0
  131. package/speechflow-cli/src/speechflow-node-a2a-vad.ts +3 -3
  132. package/speechflow-cli/src/speechflow-node-a2a-wav.ts +20 -13
  133. package/speechflow-cli/src/speechflow-node-a2t-awstranscribe.ts +308 -0
  134. package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +15 -13
  135. package/speechflow-cli/src/speechflow-node-a2t-openaitranscribe.ts +337 -0
  136. package/speechflow-cli/src/speechflow-node-t2a-awspolly.ts +187 -0
  137. package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +19 -14
  138. package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +12 -7
  139. package/speechflow-cli/src/speechflow-node-t2t-awstranslate.ts +152 -0
  140. package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +13 -15
  141. package/speechflow-cli/src/speechflow-node-t2t-format.ts +10 -15
  142. package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +55 -42
  143. package/speechflow-cli/src/speechflow-node-t2t-openai.ts +58 -58
  144. package/speechflow-cli/src/speechflow-node-t2t-sentence.ts +10 -10
  145. package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +15 -16
  146. package/speechflow-cli/src/speechflow-node-t2t-transformers.ts +27 -32
  147. package/speechflow-cli/src/speechflow-node-x2x-filter.ts +20 -16
  148. package/speechflow-cli/src/speechflow-node-x2x-trace.ts +20 -19
  149. package/speechflow-cli/src/speechflow-node-xio-device.ts +15 -23
  150. package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +23 -16
  151. package/speechflow-cli/src/speechflow-node-xio-websocket.ts +19 -19
  152. package/speechflow-cli/src/speechflow-node.ts +21 -8
  153. package/speechflow-cli/src/speechflow-utils-audio-wt.ts +172 -0
  154. package/speechflow-cli/src/speechflow-utils-audio.ts +147 -0
  155. package/speechflow-cli/src/speechflow-utils.ts +125 -32
  156. package/speechflow-cli/src/speechflow.ts +74 -17
  157. package/speechflow-ui-db/dst/index.js +31 -31
  158. package/speechflow-ui-db/etc/eslint.mjs +0 -1
  159. package/speechflow-ui-db/etc/tsc-client.json +3 -3
  160. package/speechflow-ui-db/package.json +11 -10
  161. package/speechflow-ui-db/src/app.vue +20 -6
  162. package/speechflow-ui-st/dst/index.js +26 -26
  163. package/speechflow-ui-st/etc/eslint.mjs +0 -1
  164. package/speechflow-ui-st/etc/tsc-client.json +3 -3
  165. package/speechflow-ui-st/package.json +11 -10
  166. package/speechflow-ui-st/src/app.vue +5 -12
@@ -1,116 +1,124 @@
1
1
  {
2
- "private": "true",
3
- "name": "speechflow",
4
- "version": "0.0.0",
5
- "homepage": "https://github.com/rse/speechflow",
6
- "description": "Speech Processing Flow Graph",
7
- "license": "GPL-3.0-only",
2
+ "private": true,
3
+ "name": "speechflow",
4
+ "version": "0.0.0",
5
+ "homepage": "https://github.com/rse/speechflow",
6
+ "description": "Speech Processing Flow Graph",
7
+ "license": "GPL-3.0-only",
8
8
  "author": {
9
- "name": "Dr. Ralf S. Engelschall",
10
- "email": "rse@engelschall.com",
11
- "url": "http://engelschall.com"
9
+ "name": "Dr. Ralf S. Engelschall",
10
+ "email": "rse@engelschall.com",
11
+ "url": "http://engelschall.com"
12
12
  },
13
13
  "repository": {
14
- "type": "git",
15
- "url": "git+https://github.com/rse/speechflow.git"
14
+ "type": "git",
15
+ "url": "git+https://github.com/rse/speechflow.git"
16
16
  },
17
17
  "dependencies": {
18
- "cli-io": "0.9.13",
19
- "yargs": "18.0.0",
20
- "flowlink": "1.0.0",
21
- "js-yaml": "4.1.0",
22
- "@gpeng/naudiodon": "2.4.1",
23
- "@deepgram/sdk": "4.11.2",
24
- "deepl-node": "1.19.0",
25
- "@elevenlabs/elevenlabs-js": "2.8.0",
26
- "stream-transform": "3.4.0",
27
- "get-stream": "9.0.1",
28
- "@dotenvx/dotenvx": "1.48.4",
29
- "speex-resampler": "3.0.1",
30
- "object-path": "0.11.8",
31
- "ws": "8.18.3",
32
- "bufferutil": "4.0.9",
33
- "utf-8-validate": "6.0.5",
34
- "@hapi/hapi": "21.4.2",
35
- "@hapi/boom": "10.0.1",
36
- "@hapi/inert": "7.1.0",
37
- "hapi-plugin-header": "1.1.8",
38
- "hapi-plugin-websocket": "2.4.11",
39
- "@opensumi/reconnecting-websocket": "4.4.0",
40
- "ollama": "0.5.16",
41
- "openai": "5.12.0",
42
- "@rse/ffmpeg": "1.4.2",
43
- "ffmpeg-stream": "1.0.1",
44
- "installed-packages": "1.0.13",
45
- "syspath": "1.0.8",
46
- "wav": "1.0.2",
47
- "mqtt": "5.14.0",
48
- "cbor2": "2.0.1",
49
- "arktype": "2.1.20",
50
- "pure-uuid": "1.8.1",
51
- "wavefile": "11.0.0",
52
- "audio-inspect": "0.0.4",
53
- "@huggingface/transformers": "3.7.1",
54
- "kokoro-js": "1.2.1",
55
- "@ericedouard/vad-node-realtime": "0.2.0",
56
- "luxon": "3.7.1",
57
- "node-interval-tree": "2.1.2",
58
- "wrap-text": "1.0.10",
59
- "cli-table3": "0.6.5",
60
- "@rse/stx": "1.0.7"
18
+ "cli-io": "0.9.13",
19
+ "yargs": "18.0.0",
20
+ "flowlink": "1.2.1",
21
+ "js-yaml": "4.1.0",
22
+ "@gpeng/naudiodon": "2.4.1",
23
+ "@deepgram/sdk": "4.11.2",
24
+ "deepl-node": "1.19.0",
25
+ "@elevenlabs/elevenlabs-js": "2.13.0",
26
+ "stream-transform": "3.4.0",
27
+ "get-stream": "9.0.1",
28
+ "@dotenvx/dotenvx": "1.49.0",
29
+ "speex-resampler": "3.0.1",
30
+ "@sapphi-red/speex-preprocess-wasm": "0.4.0",
31
+ "@shiguredo/rnnoise-wasm": "2025.1.5",
32
+ "@aws-sdk/client-transcribe-streaming": "3.879.0",
33
+ "@aws-sdk/client-translate": "3.879.0",
34
+ "@aws-sdk/client-polly": "3.879.0",
35
+ "node-web-audio-api": "1.0.4",
36
+ "object-path": "0.11.8",
37
+ "ws": "8.18.3",
38
+ "bufferutil": "4.0.9",
39
+ "utf-8-validate": "6.0.5",
40
+ "@hapi/hapi": "21.4.3",
41
+ "@hapi/boom": "10.0.1",
42
+ "@hapi/inert": "7.1.0",
43
+ "hapi-plugin-header": "1.1.8",
44
+ "hapi-plugin-websocket": "2.4.11",
45
+ "@opensumi/reconnecting-websocket": "4.4.0",
46
+ "ollama": "0.5.17",
47
+ "openai": "5.16.0",
48
+ "@rse/ffmpeg": "1.4.2",
49
+ "ffmpeg-stream": "1.0.1",
50
+ "installed-packages": "1.0.13",
51
+ "syspath": "1.0.8",
52
+ "wav": "1.0.2",
53
+ "mqtt": "5.14.0",
54
+ "cbor2": "2.0.1",
55
+ "arktype": "2.1.20",
56
+ "pure-uuid": "1.8.1",
57
+ "wavefile": "11.0.0",
58
+ "audio-inspect": "0.0.4",
59
+ "@huggingface/transformers": "3.7.2",
60
+ "kokoro-js": "1.2.1",
61
+ "@ericedouard/vad-node-realtime": "0.2.0",
62
+ "osc-js": "2.4.1",
63
+ "luxon": "3.7.1",
64
+ "node-interval-tree": "2.1.2",
65
+ "wrap-text": "1.0.10",
66
+ "cli-table3": "0.6.5",
67
+ "@rse/stx": "1.0.9"
61
68
  },
62
69
  "devDependencies": {
63
- "eslint": "9.32.0",
64
- "@eslint/js": "9.32.0",
65
- "neostandard": "0.12.2",
66
- "eslint-plugin-promise": "7.2.1",
67
- "eslint-plugin-import": "2.32.0",
68
- "eslint-plugin-node": "11.1.0",
69
- "@typescript-eslint/eslint-plugin": "8.39.0",
70
- "@typescript-eslint/parser": "8.39.0",
71
- "oxlint": "1.10.0",
72
- "eslint-plugin-oxlint": "1.10.0",
73
- "@biomejs/biome": "2.0.6",
74
- "eslint-config-biome": "2.1.3",
70
+ "eslint": "9.34.0",
71
+ "@eslint/js": "9.34.0",
72
+ "neostandard": "0.12.2",
73
+ "eslint-plugin-promise": "7.2.1",
74
+ "eslint-plugin-import": "2.32.0",
75
+ "eslint-plugin-node": "11.1.0",
76
+ "typescript-eslint": "8.41.0",
77
+ "@typescript-eslint/eslint-plugin": "8.41.0",
78
+ "@typescript-eslint/parser": "8.41.0",
79
+ "oxlint": "1.14.0",
80
+ "eslint-plugin-oxlint": "1.14.0",
81
+ "@biomejs/biome": "2.0.6",
82
+ "eslint-config-biome": "2.1.3",
75
83
 
76
- "@types/node": "24.2.0",
77
- "@types/yargs": "17.0.33",
78
- "@types/js-yaml": "4.0.9",
79
- "@types/object-path": "0.11.4",
80
- "@types/ws": "8.18.1",
81
- "@types/resolve": "1.20.6",
82
- "@types/wav": "1.0.4",
83
- "@types/luxon": "3.7.1",
84
- "@types/wrap-text": "1.0.2",
84
+ "@types/node": "24.3.0",
85
+ "@types/yargs": "17.0.33",
86
+ "@types/js-yaml": "4.0.9",
87
+ "@types/object-path": "0.11.4",
88
+ "@types/ws": "8.18.1",
89
+ "@types/resolve": "1.20.6",
90
+ "@types/wav": "1.0.4",
91
+ "@types/luxon": "3.7.1",
92
+ "@types/wrap-text": "1.0.2",
85
93
 
86
- "patch-package": "8.0.0",
87
- "stmux": "1.8.11",
88
- "nodemon": "3.1.10",
89
- "shx": "0.4.0",
90
- "@yao-pkg/pkg": "6.6.0",
91
- "typescript": "5.9.2",
92
- "delay-cli": "2.0.0",
93
- "cross-env": "10.0.0"
94
+ "patch-package": "8.0.0",
95
+ "stmux": "1.8.11",
96
+ "nodemon": "3.1.10",
97
+ "shx": "0.4.0",
98
+ "@yao-pkg/pkg": "6.6.0",
99
+ "typescript": "5.9.2",
100
+ "delay-cli": "2.0.0",
101
+ "cross-env": "10.0.0"
94
102
  },
95
103
  "overrides": {
96
- "@huggingface/transformers": { "onnxruntime-node": "1.23.0-dev.20250703-7fc6235861" }
104
+ "@huggingface/transformers": { "onnxruntime-node": "1.23.0-dev.20250703-7fc6235861" }
97
105
  },
98
- "upd": [ "!@biomejs/biome" ],
106
+ "upd": [ "!@biomejs/biome" ],
99
107
  "engines": {
100
- "node": ">=22.0.0"
108
+ "node": ">=22.0.0"
101
109
  },
102
- "bin": { "speechflow": "dst/speechflow.js" },
103
- "types": "./dst/speechflow-node.d.ts",
104
- "module": "./dst/speechflow-node.js",
105
- "main": "./dst/speechflow-node.js",
110
+ "bin": { "speechflow": "dst/speechflow.js" },
111
+ "types": "./dst/speechflow-node.d.ts",
112
+ "module": "./dst/speechflow-node.js",
113
+ "main": "./dst/speechflow-node.js",
106
114
  "exports": {
107
115
  ".": {
108
- "import": { "types": "./dst/speechflow-node.d.ts", "default": "./dst/speechflow-node.js" },
109
- "require": { "types": "./dst/speechflow-node.d.ts", "default": "./dst/speechflow-node.js" }
116
+ "import": { "types": "./dst/speechflow-node.d.ts", "default": "./dst/speechflow-node.js" },
117
+ "require": { "types": "./dst/speechflow-node.d.ts", "default": "./dst/speechflow-node.js" }
110
118
  }
111
119
  },
112
120
  "scripts": {
113
- "postinstall": "npm start patch-apply",
114
- "start": "stx -v4 -c etc/stx.conf"
121
+ "postinstall": "npm start patch-apply",
122
+ "start": "stx -v4 -c etc/stx.conf"
115
123
  }
116
124
  }
@@ -9,3 +9,27 @@ declare module "node:stream" {
9
9
  export function compose (...streams: Stream[]): Duplex
10
10
  }
11
11
 
12
+ /* type definitions for AudioWorkletProcessor */
13
+ declare interface AudioWorkletProcessor {
14
+ readonly port: MessagePort
15
+ process(
16
+ inputs: Float32Array[][],
17
+ outputs: Float32Array[][],
18
+ parameters: Record<string, Float32Array>
19
+ ): boolean
20
+ }
21
+ declare const AudioWorkletProcessor: {
22
+ prototype: AudioWorkletProcessor
23
+ new(): AudioWorkletProcessor
24
+ }
25
+ declare interface AudioParamDescriptor {
26
+ name: string
27
+ defaultValue?: number
28
+ minValue?: number
29
+ maxValue?: number
30
+ automationRate?: "a-rate" | "k-rate"
31
+ }
32
+ declare function registerProcessor(
33
+ name: string,
34
+ processorCtor: new (...args: any[]) => AudioWorkletProcessor
35
+ ): void
@@ -0,0 +1,151 @@
1
+ /*
2
+ ** SpeechFlow - Speech Processing Flow Graph
3
+ ** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
+ ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
+ */
6
+
7
+ import * as utils from "./speechflow-utils"
8
+
9
+ /* downward compressor with soft knee */
10
+ class CompressorProcessor extends AudioWorkletProcessor {
11
+ /* internal state */
12
+ private env: number[] = []
13
+ private sampleRate: number
14
+ public reduction = 0
15
+
16
+ /* eslint no-undef: off */
17
+ static get parameterDescriptors(): AudioParamDescriptor[] {
18
+ return [
19
+ { name: "threshold", defaultValue: -23, minValue: -100, maxValue: 0, automationRate: "k-rate" }, // dBFS
20
+ { name: "ratio", defaultValue: 4.0, minValue: 1.0, maxValue: 20, automationRate: "k-rate" }, // compression ratio
21
+ { name: "attack", defaultValue: 0.010, minValue: 0.0, maxValue: 1, automationRate: "k-rate" }, // seconds
22
+ { name: "release", defaultValue: 0.050, minValue: 0.0, maxValue: 1, automationRate: "k-rate" }, // seconds
23
+ { name: "knee", defaultValue: 6.0, minValue: 0.0, maxValue: 40, automationRate: "k-rate" }, // dB
24
+ { name: "makeup", defaultValue: 0.0, minValue: -24, maxValue: 24, automationRate: "k-rate" } // dB
25
+ ]
26
+ }
27
+
28
+ /* class constructor for custom option processing */
29
+ constructor (options: any) {
30
+ super()
31
+ const { sampleRate } = options.processorOptions
32
+ this.sampleRate = sampleRate as number
33
+ }
34
+
35
+ /* determine gain difference */
36
+ private gainDBFor (levelDB: number, thresholdDB: number, ratio: number, kneeDB: number): number {
37
+ /* short-circuit for unreasonable ratio */
38
+ if (ratio <= 1.0)
39
+ return 0
40
+
41
+ /* determine thresholds */
42
+ const halfKnee = kneeDB * 0.5
43
+ const belowThr = levelDB < thresholdDB
44
+ const aboveKnee = levelDB >= (thresholdDB + halfKnee)
45
+
46
+ /* short-circuit for no compression (below threshold) */
47
+ if (belowThr)
48
+ return 0
49
+
50
+ /* apply soft-knee */
51
+ if (kneeDB > 0 && !aboveKnee) {
52
+ const x = (levelDB - thresholdDB) / kneeDB
53
+ const idealGainDB = (thresholdDB + (levelDB - thresholdDB) / ratio) - levelDB
54
+ return idealGainDB * x * x
55
+ }
56
+
57
+ /* determine target level */
58
+ const targetOut = thresholdDB + (levelDB - thresholdDB) / ratio
59
+
60
+ /* return gain difference */
61
+ return targetOut - levelDB
62
+ }
63
+
64
+ /* update envelope (smoothed amplitude contour) for single channel */
65
+ private updateEnvelopeForChannel (
66
+ chan: number,
67
+ samples: Float32Array,
68
+ attack: number,
69
+ release: number
70
+ ): void {
71
+ /* fetch old envelope value */
72
+ if (this.env[chan] === undefined)
73
+ this.env[chan] = 1e-12
74
+ let env = this.env[chan]
75
+
76
+ /* calculate attack/release alpha values */
77
+ const alphaA = Math.exp(-1 / (attack * this.sampleRate))
78
+ const alphaR = Math.exp(-1 / (release * this.sampleRate))
79
+
80
+ /* iterate over all samples and calculate RMS */
81
+ for (const s of samples) {
82
+ const x = Math.abs(s)
83
+ const det = x * x
84
+ if (det > env)
85
+ env = alphaA * env + (1 - alphaA) * det
86
+ else
87
+ env = alphaR * env + (1 - alphaR) * det
88
+ }
89
+ this.env[chan] = Math.sqrt(Math.max(env, 1e-12))
90
+ }
91
+
92
+ /* process a single sample frame */
93
+ process(
94
+ inputs: Float32Array[][],
95
+ outputs: Float32Array[][],
96
+ parameters: Record<string, Float32Array>
97
+ ): boolean {
98
+ /* sanity check */
99
+ const input = inputs[0]
100
+ const output = outputs[0]
101
+ if (!input || input.length === 0 || !output)
102
+ return true
103
+
104
+ /* determine number of channels */
105
+ const nCh = input.length
106
+
107
+ /* initially just copy input to output (pass-through) */
108
+ for (let c = 0; c < output.length; c++) {
109
+ if (!output[c] || !input[c])
110
+ continue
111
+ output[c].set(input[c])
112
+ }
113
+
114
+ /* fetch parameters */
115
+ const thresholdDB = parameters["threshold"][0]
116
+ const ratio = parameters["ratio"][0]
117
+ const kneeDB = parameters["knee"][0]
118
+ const attackS = Math.max(parameters["attack"][0], 1 / this.sampleRate)
119
+ const releaseS = Math.max(parameters["release"][0], 1 / this.sampleRate)
120
+ const makeupDB = parameters["makeup"][0]
121
+
122
+ /* update envelope per channel */
123
+ for (let ch = 0; ch < nCh; ch++)
124
+ this.updateEnvelopeForChannel(ch, input[ch], attackS, releaseS)
125
+
126
+ /* determine linear value from decibel makeup value */
127
+ const makeUpLin = utils.dB2lin(makeupDB)
128
+
129
+ /* iterate over all channels */
130
+ this.reduction = 0
131
+ for (let ch = 0; ch < nCh; ch++) {
132
+ const levelDB = utils.lin2dB(this.env[ch])
133
+ const gainDB = this.gainDBFor(levelDB, thresholdDB, ratio, kneeDB)
134
+ const gainLin = utils.dB2lin(gainDB) * makeUpLin
135
+
136
+ /* on first channel, calculate reduction */
137
+ if (ch === 0)
138
+ this.reduction = Math.min(0, gainDB)
139
+
140
+ /* apply gain change to channel */
141
+ const inp = input[ch]
142
+ const out = output[ch]
143
+ for (let i = 0; i < inp.length; i++)
144
+ out[i] = inp[i] * gainLin
145
+ }
146
+ return true
147
+ }
148
+ }
149
+
150
+ /* register the new audio nodes */
151
+ registerProcessor("compressor", CompressorProcessor)