echogarden 1.8.7 → 2.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.
Files changed (299) hide show
  1. package/README.md +23 -18
  2. package/data/schemas/options.json +52 -47
  3. package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
  4. package/dist/alignment/DTWSequenceAlignment.js +5 -5
  5. package/dist/alignment/DTWSequenceAlignment.js.map +1 -1
  6. package/dist/alignment/SpeechAlignment.js +6 -6
  7. package/dist/alignment/SpeechAlignment.js.map +1 -1
  8. package/dist/api/Alignment.d.ts +1 -1
  9. package/dist/api/Alignment.js +49 -11
  10. package/dist/api/Alignment.js.map +1 -1
  11. package/dist/api/Denoising.d.ts +4 -2
  12. package/dist/api/Denoising.js +65 -13
  13. package/dist/api/Denoising.js.map +1 -1
  14. package/dist/api/SourceSeparation.js +9 -6
  15. package/dist/api/SourceSeparation.js.map +1 -1
  16. package/dist/api/SpeechLanguageDetection.js +4 -4
  17. package/dist/api/SpeechLanguageDetection.js.map +1 -1
  18. package/dist/api/Synthesis.d.ts +2 -2
  19. package/dist/api/Synthesis.js +10 -7
  20. package/dist/api/Synthesis.js.map +1 -1
  21. package/dist/api/VoiceActivityDetection.js +2 -2
  22. package/dist/api/VoiceActivityDetection.js.map +1 -1
  23. package/dist/audio/AudioBufferConversion.d.ts +2 -2
  24. package/dist/audio/AudioBufferConversion.js +77 -43
  25. package/dist/audio/AudioBufferConversion.js.map +1 -1
  26. package/dist/audio/AudioPlayer.d.ts +7 -5
  27. package/dist/audio/AudioPlayer.js +135 -49
  28. package/dist/audio/AudioPlayer.js.map +1 -1
  29. package/dist/audio/AudioUtilities.d.ts +4 -3
  30. package/dist/audio/AudioUtilities.js +30 -15
  31. package/dist/audio/AudioUtilities.js.map +1 -1
  32. package/dist/audio/SoxPath.js +3 -3
  33. package/dist/audio/SoxPath.js.map +1 -1
  34. package/dist/build-tools/MakeTarballsForInstalledPackages.js +3 -3
  35. package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -1
  36. package/dist/cli/CLI.js +30 -36
  37. package/dist/cli/CLI.js.map +1 -1
  38. package/dist/cli/CLIConfigFile.js +2 -2
  39. package/dist/cli/CLIConfigFile.js.map +1 -1
  40. package/dist/cli/CLIOptions.d.ts +2 -0
  41. package/dist/cli/CLIOptions.js +1 -1
  42. package/dist/cli/CLIOptions.js.map +1 -1
  43. package/dist/codecs/FFMpegTranscoder.d.ts +3 -3
  44. package/dist/codecs/FFMpegTranscoder.js +6 -6
  45. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  46. package/dist/codecs/TIMITCodec.d.ts +1 -1
  47. package/dist/codecs/TIMITCodec.js +4 -3
  48. package/dist/codecs/TIMITCodec.js.map +1 -1
  49. package/dist/codecs/WaveCodec.d.ts +3 -3
  50. package/dist/codecs/WaveCodec.js +37 -34
  51. package/dist/codecs/WaveCodec.js.map +1 -1
  52. package/dist/data-structures/DynamicTypedArray.d.ts +17 -0
  53. package/dist/data-structures/DynamicTypedArray.js +47 -0
  54. package/dist/data-structures/DynamicTypedArray.js.map +1 -0
  55. package/dist/data-structures/Queue.js.map +1 -0
  56. package/dist/data-structures/WindowedList.js.map +1 -0
  57. package/dist/denoising/NSNet2.d.ts +26 -0
  58. package/dist/denoising/NSNet2.js +128 -0
  59. package/dist/denoising/NSNet2.js.map +1 -0
  60. package/dist/denoising/RNNoise.js +3 -3
  61. package/dist/denoising/RNNoise.js.map +1 -1
  62. package/dist/dsp/FFT.d.ts +6 -1
  63. package/dist/dsp/FFT.js +17 -0
  64. package/dist/dsp/FFT.js.map +1 -1
  65. package/dist/encodings/Ascii.d.ts +10 -0
  66. package/dist/encodings/Ascii.js +41 -0
  67. package/dist/encodings/Ascii.js.map +1 -0
  68. package/dist/encodings/Base64.d.ts +5 -0
  69. package/dist/encodings/Base64.js +114 -0
  70. package/dist/encodings/Base64.js.map +1 -0
  71. package/dist/encodings/Hex.d.ts +3 -0
  72. package/dist/encodings/Hex.js +52 -0
  73. package/dist/encodings/Hex.js.map +1 -0
  74. package/dist/{utilities → encodings}/LEB128.d.ts +1 -1
  75. package/dist/{utilities → encodings}/LEB128.js +4 -4
  76. package/dist/encodings/LEB128.js.map +1 -0
  77. package/dist/{utilities → encodings}/LPVarInt.d.ts +1 -1
  78. package/dist/{utilities → encodings}/LPVarInt.js +6 -6
  79. package/dist/encodings/LPVarInt.js.map +1 -0
  80. package/dist/encodings/TextEncodingsCommon.d.ts +4 -0
  81. package/dist/encodings/TextEncodingsCommon.js +2 -0
  82. package/dist/encodings/TextEncodingsCommon.js.map +1 -0
  83. package/dist/encodings/Utf16.d.ts +10 -0
  84. package/dist/encodings/Utf16.js +36 -0
  85. package/dist/encodings/Utf16.js.map +1 -0
  86. package/dist/encodings/Utf32.d.ts +9 -0
  87. package/dist/encodings/Utf32.js +44 -0
  88. package/dist/encodings/Utf32.js.map +1 -0
  89. package/dist/encodings/Utf8.d.ts +10 -0
  90. package/dist/encodings/Utf8.js +97 -0
  91. package/dist/encodings/Utf8.js.map +1 -0
  92. package/dist/math/MedianFilter.js.map +1 -1
  93. package/dist/nlp/JapaneseSegmentation.js +2 -2
  94. package/dist/nlp/JapaneseSegmentation.js.map +1 -1
  95. package/dist/recognition/GoogleCloudSTT.js +2 -1
  96. package/dist/recognition/GoogleCloudSTT.js.map +1 -1
  97. package/dist/recognition/SileroSTT.js +3 -3
  98. package/dist/recognition/SileroSTT.js.map +1 -1
  99. package/dist/recognition/VoskSTT.js +3 -3
  100. package/dist/recognition/VoskSTT.js.map +1 -1
  101. package/dist/recognition/WhisperCppSTT.js +4 -5
  102. package/dist/recognition/WhisperCppSTT.js.map +1 -1
  103. package/dist/recognition/WhisperSTT.js +8 -7
  104. package/dist/recognition/WhisperSTT.js.map +1 -1
  105. package/dist/server/Client.d.ts +1 -1
  106. package/dist/server/Client.js +2 -1
  107. package/dist/server/Client.js.map +1 -1
  108. package/dist/server/Server.js +5 -4
  109. package/dist/server/Server.js.map +1 -1
  110. package/dist/server/Worker.js +1 -1
  111. package/dist/server/Worker.js.map +1 -1
  112. package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
  113. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  114. package/dist/speech-search/DTWSpeechSearch.d.ts +1 -1
  115. package/dist/speech-search/DTWSpeechSearch.js +25 -6
  116. package/dist/speech-search/DTWSpeechSearch.js.map +1 -1
  117. package/dist/subtitles/Subtitles.js +2 -2
  118. package/dist/subtitles/Subtitles.js.map +1 -1
  119. package/dist/synthesis/AzureCognitiveServicesTTS.js +17 -18
  120. package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
  121. package/dist/synthesis/CoquiServerTTS.js +1 -1
  122. package/dist/synthesis/CoquiServerTTS.js.map +1 -1
  123. package/dist/synthesis/ElevenlabsTTS.js +1 -1
  124. package/dist/synthesis/ElevenlabsTTS.js.map +1 -1
  125. package/dist/synthesis/EspeakTTS.d.ts +0 -1
  126. package/dist/synthesis/EspeakTTS.js +0 -9
  127. package/dist/synthesis/EspeakTTS.js.map +1 -1
  128. package/dist/synthesis/FliteTTS.js +7 -8
  129. package/dist/synthesis/FliteTTS.js.map +1 -1
  130. package/dist/synthesis/GoogleCloudTTS.d.ts +1 -1
  131. package/dist/synthesis/GoogleCloudTTS.js +2 -1
  132. package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
  133. package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
  134. package/dist/synthesis/GoogleTranslateTTS.js +4 -3
  135. package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
  136. package/dist/synthesis/MicrosoftEdgeTTS.js +32 -7
  137. package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
  138. package/dist/synthesis/SapiTTS.js +1 -1
  139. package/dist/synthesis/SapiTTS.js.map +1 -1
  140. package/dist/synthesis/StreamlabsPollyTTS.d.ts +1 -1
  141. package/dist/synthesis/StreamlabsPollyTTS.js +1 -1
  142. package/dist/synthesis/StreamlabsPollyTTS.js.map +1 -1
  143. package/dist/synthesis/SvoxPicoTTS.js +6 -6
  144. package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
  145. package/dist/synthesis/VitsTTS.js +2 -2
  146. package/dist/synthesis/VitsTTS.js.map +1 -1
  147. package/dist/tests/Test.js +1 -47
  148. package/dist/tests/Test.js.map +1 -1
  149. package/dist/text-language-detection/FastTextLanguageDetection.js +2 -2
  150. package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
  151. package/dist/typings/TypedArray.d.ts +4 -0
  152. package/dist/typings/TypedArray.js +2 -0
  153. package/dist/typings/TypedArray.js.map +1 -0
  154. package/dist/utilities/BinaryArrayConversion.d.ts +12 -22
  155. package/dist/utilities/BinaryArrayConversion.js +40 -90
  156. package/dist/utilities/BinaryArrayConversion.js.map +1 -1
  157. package/dist/utilities/BinaryUtilities.d.ts +13 -0
  158. package/dist/utilities/BinaryUtilities.js +113 -0
  159. package/dist/utilities/BinaryUtilities.js.map +1 -0
  160. package/dist/utilities/Compression.js +7 -6
  161. package/dist/utilities/Compression.js.map +1 -1
  162. package/dist/utilities/FileDownloader.js +26 -47
  163. package/dist/utilities/FileDownloader.js.map +1 -1
  164. package/dist/utilities/FileReader.d.ts +14 -0
  165. package/dist/utilities/FileReader.js +71 -0
  166. package/dist/utilities/FileReader.js.map +1 -0
  167. package/dist/utilities/FileSystem.d.ts +19 -16
  168. package/dist/utilities/FileSystem.js +170 -109
  169. package/dist/utilities/FileSystem.js.map +1 -1
  170. package/dist/utilities/FileWriter.d.ts +12 -0
  171. package/dist/utilities/FileWriter.js +60 -0
  172. package/dist/utilities/FileWriter.js.map +1 -0
  173. package/dist/utilities/NpmUtilities.d.ts +1 -0
  174. package/dist/utilities/NpmUtilities.js +14 -0
  175. package/dist/utilities/NpmUtilities.js.map +1 -0
  176. package/dist/utilities/PackageManager.js +7 -5
  177. package/dist/utilities/PackageManager.js.map +1 -1
  178. package/dist/utilities/PathUtilities.d.ts +8 -0
  179. package/dist/utilities/PathUtilities.js +28 -7
  180. package/dist/utilities/PathUtilities.js.map +1 -1
  181. package/dist/utilities/SignalChannel.d.ts +3 -1
  182. package/dist/utilities/SignalChannel.js +9 -5
  183. package/dist/utilities/SignalChannel.js.map +1 -1
  184. package/dist/utilities/StringBuilder.d.ts +10 -0
  185. package/dist/utilities/StringBuilder.js +39 -0
  186. package/dist/utilities/StringBuilder.js.map +1 -0
  187. package/dist/utilities/StringUtilities.js.map +1 -1
  188. package/dist/utilities/TarballMaker.js +6 -7
  189. package/dist/utilities/TarballMaker.js.map +1 -1
  190. package/dist/utilities/Timer.js +2 -2
  191. package/dist/utilities/Timer.js.map +1 -1
  192. package/dist/utilities/Utilities.d.ts +11 -5
  193. package/dist/utilities/Utilities.js +69 -33
  194. package/dist/utilities/Utilities.js.map +1 -1
  195. package/dist/utilities/VirtualFileReadStream.d.ts +3 -3
  196. package/dist/utilities/VirtualFileReadStream.js.map +1 -1
  197. package/dist/utilities/WasmMemoryManager.d.ts +5 -2
  198. package/dist/utilities/WasmMemoryManager.js +15 -4
  199. package/dist/utilities/WasmMemoryManager.js.map +1 -1
  200. package/docs/API.md +1 -1
  201. package/docs/Licenses.md +3 -0
  202. package/docs/Options.md +9 -3
  203. package/docs/Tasklist.md +0 -1
  204. package/docs/Technical.md +2 -2
  205. package/package.json +20 -22
  206. package/src/alignment/DTWSequenceAlignment.ts +5 -5
  207. package/src/alignment/SpeechAlignment.ts +6 -6
  208. package/src/api/Alignment.ts +65 -12
  209. package/src/api/Denoising.ts +97 -17
  210. package/src/api/SourceSeparation.ts +11 -8
  211. package/src/api/SpeechLanguageDetection.ts +4 -4
  212. package/src/api/Synthesis.ts +15 -11
  213. package/src/api/VoiceActivityDetection.ts +2 -2
  214. package/src/audio/AudioBufferConversion.ts +84 -45
  215. package/src/audio/AudioPlayer.ts +155 -53
  216. package/src/audio/AudioUtilities.ts +38 -22
  217. package/src/audio/SoxPath.ts +3 -3
  218. package/src/build-tools/MakeTarballsForInstalledPackages.ts +3 -3
  219. package/src/cli/CLI.ts +30 -36
  220. package/src/cli/CLIConfigFile.ts +2 -2
  221. package/src/cli/CLIOptions.ts +4 -1
  222. package/src/codecs/FFMpegTranscoder.ts +11 -11
  223. package/src/codecs/TIMITCodec.ts +5 -4
  224. package/src/codecs/WaveCodec.ts +42 -39
  225. package/src/data-structures/DynamicTypedArray.ts +64 -0
  226. package/src/denoising/NSNet2.ts +182 -0
  227. package/src/denoising/RNNoise.ts +3 -3
  228. package/src/dsp/FFT.ts +21 -1
  229. package/src/encodings/Ascii.ts +60 -0
  230. package/src/encodings/Base64.ts +157 -0
  231. package/src/encodings/Hex.ts +67 -0
  232. package/src/{utilities → encodings}/LEB128.ts +4 -4
  233. package/src/{utilities → encodings}/LPVarInt.ts +6 -6
  234. package/src/encodings/TextEncodingsCommon.ts +4 -0
  235. package/src/encodings/Utf16.ts +52 -0
  236. package/src/encodings/Utf32.ts +62 -0
  237. package/src/encodings/Utf8.ts +117 -0
  238. package/src/math/MedianFilter.ts +0 -2
  239. package/src/nlp/JapaneseSegmentation.ts +2 -2
  240. package/src/recognition/GoogleCloudSTT.ts +2 -1
  241. package/src/recognition/SileroSTT.ts +3 -3
  242. package/src/recognition/VoskSTT.ts +3 -3
  243. package/src/recognition/WhisperCppSTT.ts +4 -5
  244. package/src/recognition/WhisperSTT.ts +8 -7
  245. package/src/server/Client.ts +4 -3
  246. package/src/server/Server.ts +6 -5
  247. package/src/server/Worker.ts +1 -1
  248. package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
  249. package/src/speech-search/DTWSpeechSearch.ts +36 -7
  250. package/src/subtitles/Subtitles.ts +3 -3
  251. package/src/synthesis/AzureCognitiveServicesTTS.ts +18 -15
  252. package/src/synthesis/CoquiServerTTS.ts +2 -2
  253. package/src/synthesis/ElevenlabsTTS.ts +1 -1
  254. package/src/synthesis/EspeakTTS.ts +0 -15
  255. package/src/synthesis/FliteTTS.ts +7 -8
  256. package/src/synthesis/GoogleCloudTTS.ts +3 -2
  257. package/src/synthesis/GoogleTranslateTTS.ts +5 -4
  258. package/src/synthesis/MicrosoftEdgeTTS.ts +47 -15
  259. package/src/synthesis/SapiTTS.ts +1 -1
  260. package/src/synthesis/StreamlabsPollyTTS.ts +1 -1
  261. package/src/synthesis/SvoxPicoTTS.ts +8 -8
  262. package/src/synthesis/VitsTTS.ts +2 -2
  263. package/src/tests/Test.ts +1 -60
  264. package/src/text-language-detection/FastTextLanguageDetection.ts +2 -2
  265. package/src/typings/Fillers.d.ts +2 -4
  266. package/src/typings/TypedArray.ts +5 -0
  267. package/src/utilities/BinaryArrayConversion.ts +51 -125
  268. package/src/utilities/BinaryUtilities.ts +138 -0
  269. package/src/utilities/Compression.ts +7 -6
  270. package/src/utilities/FileDownloader.ts +27 -52
  271. package/src/utilities/FileReader.ts +89 -0
  272. package/src/utilities/FileSystem.ts +213 -120
  273. package/src/utilities/FileWriter.ts +72 -0
  274. package/src/utilities/NpmUtilities.ts +23 -0
  275. package/src/utilities/PackageManager.ts +8 -5
  276. package/src/utilities/PathUtilities.ts +36 -7
  277. package/src/utilities/SignalChannel.ts +14 -7
  278. package/src/utilities/StringBuilder.ts +45 -0
  279. package/src/utilities/StringUtilities.ts +2 -0
  280. package/src/utilities/TarballMaker.ts +6 -7
  281. package/src/utilities/Timer.ts +4 -2
  282. package/src/utilities/Utilities.ts +79 -45
  283. package/src/utilities/VirtualFileReadStream.ts +5 -5
  284. package/src/utilities/WasmMemoryManager.ts +20 -6
  285. package/tsconfig.json +96 -0
  286. package/dist/utilities/DynamicUint8Array.d.ts +0 -9
  287. package/dist/utilities/DynamicUint8Array.js +0 -31
  288. package/dist/utilities/DynamicUint8Array.js.map +0 -1
  289. package/dist/utilities/LEB128.js.map +0 -1
  290. package/dist/utilities/LPVarInt.js.map +0 -1
  291. package/dist/utilities/Queue.js.map +0 -1
  292. package/dist/utilities/WindowedList.js.map +0 -1
  293. package/src/utilities/DynamicUint8Array.ts +0 -39
  294. /package/dist/{utilities → data-structures}/Queue.d.ts +0 -0
  295. /package/dist/{utilities → data-structures}/Queue.js +0 -0
  296. /package/dist/{utilities → data-structures}/WindowedList.d.ts +0 -0
  297. /package/dist/{utilities → data-structures}/WindowedList.js +0 -0
  298. /package/src/{utilities → data-structures}/Queue.ts +0 -0
  299. /package/src/{utilities → data-structures}/WindowedList.ts +0 -0
@@ -0,0 +1,182 @@
1
+ import { decibelsToGainFactor, RawAudio } from '../audio/AudioUtilities.js'
2
+
3
+ import type * as Onnx from 'onnxruntime-node'
4
+ import { getOnnxSessionOptions, OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
5
+ import { readdir } from '../utilities/FileSystem.js'
6
+ import { joinPath } from '../utilities/PathUtilities.js'
7
+ import { stftr, stiftr } from '../dsp/FFT.js'
8
+ import { clip, concatFloat32Arrays } from '../utilities/Utilities.js'
9
+ import { Logger } from '../utilities/Logger.js'
10
+
11
+ export async function denoiseAudio(rawAudio: RawAudio, options: NSNet2Options) {
12
+ const onnxExecutionProviders: OnnxExecutionProvider[] = options.provider ? [options.provider] : []//['dml', 'cpu']
13
+
14
+ const denoiser = new NSNet2(options.model!, options.modelDirectoryPath!, onnxExecutionProviders, options.maxAttenuation!)
15
+
16
+ const result = await denoiser.denoiseAudio(rawAudio)
17
+
18
+ return result
19
+ }
20
+
21
+ export class NSNet2 {
22
+ session?: Onnx.InferenceSession
23
+
24
+ constructor(
25
+ public readonly modelName: NSNet2ModelName,
26
+ public readonly modelDirectoryPath: string,
27
+ public readonly executionProviders: OnnxExecutionProvider[],
28
+ public readonly maxAttenuation: number) {
29
+ }
30
+
31
+ async denoiseAudio(rawAudio: RawAudio) {
32
+ const logger = new Logger()
33
+
34
+ logger.start(`Initialize ONNX model ${this.modelName}`)
35
+ await this.initializeIfNeeded()
36
+
37
+ let fftSize: number
38
+
39
+ if (this.modelName === 'baseline-48khz') {
40
+ fftSize = 1024
41
+
42
+ if (rawAudio.sampleRate !== 48000) {
43
+ throw new Error(`Denoising model baseline-48khz requires a 48000 Hz signal`)
44
+ }
45
+ } else if (this.modelName === 'baseline-16khz') {
46
+ fftSize = 320
47
+
48
+ if (rawAudio.sampleRate !== 16000) {
49
+ throw new Error(`Denoising model baseline-16khz requires a 16000 Hz signal`)
50
+ }
51
+ } else {
52
+ throw new Error(`Unsupported model name: ${this.modelName}`)
53
+ }
54
+
55
+ const fftHopSize = fftSize / 2
56
+ const fftRealBinCount = (fftSize / 2) + 1
57
+
58
+ logger.start('Compute STFT frames')
59
+ const stftrFrames = await stftr(rawAudio.audioChannels[0], fftSize, fftSize, fftHopSize, 'hann')
60
+
61
+ logger.start('Compute log-power spectogram')
62
+ let logPowerSpectogram: Float32Array[] = []
63
+
64
+ {
65
+ for (const frame of stftrFrames) {
66
+ const logPowerSpectrum = new Float32Array(frame.length / 2)
67
+
68
+ let readOffset = 0
69
+ let writeOffset = 0
70
+
71
+ while (readOffset < frame.length) {
72
+ const real = frame[readOffset++]
73
+ const imaginary = frame[readOffset++]
74
+
75
+ const powerValue = (real ** 2) + (imaginary ** 2)
76
+ const clampedPowerValue = Math.max(powerValue, 1e-12)
77
+ const logPowerValue = Math.log10(clampedPowerValue)
78
+
79
+ logPowerSpectrum[writeOffset++] = logPowerValue
80
+ }
81
+
82
+ logPowerSpectogram.push(logPowerSpectrum)
83
+ }
84
+ }
85
+
86
+ logger.start('Process log-power spectogram using ONNX model')
87
+
88
+ const frameCount = logPowerSpectogram.length
89
+ let flattenedOutputTensor: Float32Array
90
+
91
+ {
92
+ const Onnx = await import('onnxruntime-node')
93
+
94
+ const flattenedFeatures = concatFloat32Arrays(logPowerSpectogram)
95
+
96
+ const inputTensor = new Onnx.Tensor('float32', flattenedFeatures, [1, frameCount, fftRealBinCount])
97
+ const inputs = { input: inputTensor }
98
+
99
+ const result = await this.session!.run(inputs)
100
+
101
+ flattenedOutputTensor = result.output.data as Float32Array
102
+ }
103
+
104
+ {
105
+ logger.start('Apply model output as a filter to original STFT frames')
106
+
107
+ const fftSizeReciprocal = 1 / fftSize
108
+
109
+ const minGainRatio = decibelsToGainFactor(-this.maxAttenuation)
110
+ const maxGainRatio = 1.0
111
+
112
+ let flattenenedOutputTensorReadIndex = 0
113
+
114
+ for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
115
+ const frame = stftrFrames[frameIndex]
116
+
117
+ let frameReadIndex = 0
118
+
119
+ for (let binIndex = 0; binIndex < fftRealBinCount; binIndex++) {
120
+ let gainRatio = flattenedOutputTensor[flattenenedOutputTensorReadIndex++]
121
+ gainRatio = clip(gainRatio, minGainRatio, maxGainRatio)
122
+
123
+ frame[frameReadIndex++] *= gainRatio * fftSizeReciprocal
124
+ frame[frameReadIndex++] *= gainRatio * fftSizeReciprocal
125
+ }
126
+ }
127
+ }
128
+
129
+ // Allow logPowerSpectogram to be garbage collected
130
+ logPowerSpectogram = undefined as any
131
+
132
+ logger.start('Reconstruct filtered signal using inverse STFT')
133
+ const filteredSignal = await stiftr(stftrFrames, fftSize, fftSize, fftHopSize, 'hann')
134
+
135
+ const denoisedAudio: RawAudio = {
136
+ audioChannels: [filteredSignal],
137
+ sampleRate: rawAudio.sampleRate
138
+ }
139
+
140
+ logger.end()
141
+
142
+ return { denoisedAudio }
143
+ }
144
+
145
+ private async initializeIfNeeded() {
146
+ if (this.session) {
147
+ return
148
+ }
149
+
150
+ const filesInModelPath = await readdir(this.modelDirectoryPath)
151
+ const onnxModelFilename = filesInModelPath.find(filename => filename.endsWith('.onnx'))
152
+
153
+ if (!onnxModelFilename) {
154
+ throw new Error(`Couldn't file any ONNX model file in ${this.modelDirectoryPath}`)
155
+ }
156
+
157
+ const onnxModelPath = joinPath(this.modelDirectoryPath, onnxModelFilename)
158
+
159
+ const Onnx = await import('onnxruntime-node')
160
+
161
+ const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
162
+
163
+ this.session = await Onnx.InferenceSession.create(onnxModelPath, onnxSessionOptions)
164
+ }
165
+ }
166
+
167
+ //export type NSNet2ModelName = 'nsnet2-20ms-baseline' | 'nsnet2-20ms-48k-baseline'
168
+ export type NSNet2ModelName = 'baseline-16khz' | 'baseline-48khz'
169
+
170
+ export const defaultNSNet2Options: NSNet2Options = {
171
+ model: 'baseline-48khz',
172
+ modelDirectoryPath: undefined,
173
+ provider: undefined,
174
+ maxAttenuation: 30,
175
+ }
176
+
177
+ export interface NSNet2Options {
178
+ model?: NSNet2ModelName
179
+ modelDirectoryPath?: string
180
+ provider?: OnnxExecutionProvider
181
+ maxAttenuation?: number
182
+ }
@@ -9,11 +9,11 @@ let rnnoiseInstance: any
9
9
  export async function denoiseAudio(rawAudio: RawAudio) {
10
10
  const logger = new Logger()
11
11
  if (rawAudio.sampleRate != 48000) {
12
- throw new Error('Sample rate must be 48000')
12
+ throw new Error(`RNNoise requires a 48000 Hz sample rate (${rawAudio.sampleRate} Hz given)`)
13
13
  }
14
14
 
15
- if (rawAudio.audioChannels.length != 1) {
16
- throw new Error('Channel count must be 1')
15
+ if (rawAudio.audioChannels.length !== 1) {
16
+ throw new Error('RNNoise requires a channel count of 1')
17
17
  }
18
18
 
19
19
  if (rawAudio.audioChannels[0].length == 0) {
package/src/dsp/FFT.ts CHANGED
@@ -226,6 +226,22 @@ export function complexToBinBuffer(complexBins: ComplexNumber[]) {
226
226
  return binBuffer
227
227
  }
228
228
 
229
+ // Convert complex bin to magnitude and phase
230
+ export function complexToMagnitudeAndPhase(real: number, imaginary: number) {
231
+ const magnitude = Math.sqrt((real ** 2) + (imaginary ** 2))
232
+ const phase = Math.atan2(imaginary, real)
233
+
234
+ return { magnitude, phase }
235
+ }
236
+
237
+ // Convert magnitude and phase to complex bin
238
+ export function magnitudeAndPhaseToComplex(magnitude: number, phase: number) {
239
+ const real = magnitude * Math.cos(phase)
240
+ const imaginary = magnitude * Math.sin(phase)
241
+
242
+ return { real, imaginary } as ComplexNumber
243
+ }
244
+
229
245
  // Get window weights for a particular window function
230
246
  export function getWindowWeights(windowType: WindowType, windowSize: number) {
231
247
  const weights = new Float32Array(windowSize)
@@ -237,6 +253,10 @@ export function getWindowWeights(windowType: WindowType, windowSize: number) {
237
253
  //weights[i] = 0.5 * (1 - Math.cos(2 * Math.PI * (i / (windowSize - 1))))
238
254
  weights[i] = 0.5 * (1 - Math.cos(innerFactor * i))
239
255
  }
256
+ } else if (windowType == 'hann-sqrt') {
257
+ for (let i = 0; i < windowSize; i++) {
258
+ weights[i] = Math.sqrt(0.5 * (1 - Math.cos(innerFactor * i)))
259
+ }
240
260
  } else if (windowType == 'hamming') {
241
261
  for (let i = 0; i < windowSize; i++) {
242
262
  //weights[i] = 0.54 - (0.46 * Math.cos(2 * Math.PI * (i / (windowSize - 1))))
@@ -284,4 +304,4 @@ async function getSimdPFFFTInstance() {
284
304
  return pffftSimdInstance
285
305
  }
286
306
 
287
- export type WindowType = 'hann' | 'hamming' | 'povey'
307
+ export type WindowType = 'hann' | 'hann-sqrt' | 'hamming' | 'povey'
@@ -0,0 +1,60 @@
1
+ import { EncodeIntoResult } from "./TextEncodingsCommon.js"
2
+
3
+ export function encodeAscii(asciiString: string) {
4
+ const charCount = asciiString.length
5
+
6
+ const resultArray = new Uint8Array(charCount)
7
+
8
+ const { written } = encodeAsciiInto(asciiString, resultArray)
9
+
10
+ return resultArray.subarray(0, written)
11
+ }
12
+
13
+ export function encodeAsciiInto(asciiString: string, resultBuffer: Uint8Array): EncodeIntoResult {
14
+ const len = asciiString.length
15
+
16
+ if (resultBuffer.length < len) {
17
+ throw new Error(`Result Uint8Array is not large enough to hold the string`)
18
+ }
19
+
20
+ for (let readOffset = 0; readOffset < len; readOffset++) {
21
+ const charCode = asciiString.charCodeAt(readOffset)
22
+
23
+ if (charCode >= 128) {
24
+ throw new Error(`Character '${asciiString[readOffset]}' (code: ${charCode}) can't be encoded as a standard ASCII character`)
25
+ }
26
+
27
+ resultBuffer[readOffset] = charCode
28
+ }
29
+
30
+ return { read: len, written: len }
31
+ }
32
+
33
+ export function decodeAscii(encodedString: Uint8Array) {
34
+ const maxChunkLength = 2 ** 24
35
+
36
+ const decoder = new ChunkedAsciiDecoder()
37
+
38
+ for (let offset = 0; offset < encodedString.length; offset += maxChunkLength) {
39
+ const chunk = encodedString.subarray(offset, offset + maxChunkLength)
40
+
41
+ decoder.writeChunk(chunk)
42
+ }
43
+
44
+ return decoder.toString()
45
+ }
46
+
47
+ export class ChunkedAsciiDecoder {
48
+ private str = ''
49
+ private readonly textDecoder = new TextDecoder('windows-1252')
50
+
51
+ writeChunk(chunk: Uint8Array) {
52
+ const decodedChunk = this.textDecoder.decode(chunk)
53
+
54
+ this.str += decodedChunk
55
+ }
56
+
57
+ toString() {
58
+ return this.str
59
+ }
60
+ }
@@ -0,0 +1,157 @@
1
+ import { decodeAscii } from './Ascii.js';
2
+
3
+ export function encodeBase64(inputBytes: Uint8Array,
4
+ paddingCharacter: string | undefined = '=',
5
+ charCodeMap?: Uint8Array): string {
6
+
7
+ const asciiBuffer = encodeBase64AsAsciiBuffer(inputBytes, undefined, paddingCharacter, charCodeMap)
8
+
9
+ return decodeAscii(asciiBuffer)
10
+ }
11
+
12
+ export function encodeBase64AsAsciiBuffer(
13
+ inputBytes: Uint8Array,
14
+ asciiBuffer?: Uint8Array,
15
+ paddingCharacter: string | undefined = '=',
16
+ charCodeMap?: Uint8Array): Uint8Array {
17
+
18
+ if (!inputBytes || inputBytes.length == 0) {
19
+ return new Uint8Array(0)
20
+ }
21
+
22
+ let paddingCharCode: number
23
+
24
+ if (paddingCharacter == null) {
25
+ paddingCharCode = -1
26
+ } else if (paddingCharacter.length !== 1) {
27
+ throw new Error(`A padding character can only be a single character`)
28
+ } else {
29
+ paddingCharCode = paddingCharacter.charCodeAt(0)
30
+ }
31
+
32
+ if (!charCodeMap) {
33
+ charCodeMap = defaultBase64CharCodeMap
34
+ }
35
+
36
+ let charCodes: Uint8Array
37
+
38
+ if (asciiBuffer) {
39
+ charCodes = asciiBuffer
40
+ } else {
41
+ charCodes = new Uint8Array(Math.floor((inputBytes.length * 4 / 3) + 4))
42
+ }
43
+
44
+ const inputBytesLength = inputBytes.length
45
+
46
+ let writeOffset = 0
47
+ let readOffset = 0
48
+
49
+ while (readOffset <= inputBytesLength - 3) {
50
+ const uint24 =
51
+ inputBytes[readOffset++] << 16 |
52
+ inputBytes[readOffset++] << 8 |
53
+ inputBytes[readOffset++]
54
+
55
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
56
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
57
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 6) & 63]
58
+ charCodes[writeOffset++] = charCodeMap[(uint24) & 63]
59
+ }
60
+
61
+ if (readOffset === inputBytesLength - 2) {
62
+ // If two bytes are left, output 3 encoded characters and one padding character
63
+ const uint24 =
64
+ inputBytes[readOffset++] << 16 |
65
+ inputBytes[readOffset++] << 8
66
+
67
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
68
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
69
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 6) & 63]
70
+
71
+ if (paddingCharCode >= 0) {
72
+ charCodes[writeOffset++] = paddingCharCode
73
+ }
74
+ } else if (readOffset === inputBytesLength - 1) {
75
+ // Arrived at last byte at a position that did not complete a full 3 byte set
76
+ const uint24 =
77
+ inputBytes[readOffset++] << 16
78
+
79
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
80
+ charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
81
+
82
+ if (paddingCharCode >= 0) {
83
+ charCodes[writeOffset++] = paddingCharCode
84
+ charCodes[writeOffset++] = paddingCharCode
85
+ }
86
+ }
87
+
88
+ return charCodes.subarray(0, writeOffset)
89
+ }
90
+
91
+ export function decodeBase64(
92
+ base64String: string,
93
+ outputBuffer?: Uint8Array,
94
+ paddingCharacter = '=',
95
+ reverseCharCodeMap?: Uint8Array): Uint8Array {
96
+
97
+ if (!base64String || base64String.length === 0) {
98
+ return new Uint8Array(0)
99
+ }
100
+
101
+ if (!paddingCharacter || paddingCharacter.length !== 1) {
102
+ throw new Error(`A valid padding character must be provided for Base 64 decoding`)
103
+ }
104
+
105
+ // Add padding if omitted
106
+ const lengthModulo4 = base64String.length % 4
107
+
108
+ if (lengthModulo4 === 1) {
109
+ throw new Error(`Invalid Base64 string: length % 4 == 1`)
110
+ } else if (lengthModulo4 === 2) {
111
+ base64String += paddingCharacter
112
+ base64String += paddingCharacter
113
+ } else if (lengthModulo4 === 3) {
114
+ base64String += paddingCharacter
115
+ }
116
+
117
+ if (!reverseCharCodeMap) {
118
+ reverseCharCodeMap = defaultBase64ReverseCharCodeMap
119
+ }
120
+
121
+ if (!outputBuffer) {
122
+ const capacity = (base64String.length / 4) * 3
123
+
124
+ outputBuffer = new Uint8Array(capacity)
125
+ }
126
+
127
+ const stringLength = base64String.length
128
+
129
+ let readOffset = 0
130
+ let writeOffset = 0
131
+
132
+ while (readOffset < stringLength) {
133
+ const uint24 =
134
+ (reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 18) |
135
+ (reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 12) |
136
+ (reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 6) |
137
+ (reverseCharCodeMap[base64String.charCodeAt(readOffset++)])
138
+
139
+ outputBuffer[writeOffset++] = (uint24 >>> 16) & 255
140
+ outputBuffer[writeOffset++] = (uint24 >>> 8) & 255
141
+ outputBuffer[writeOffset++] = (uint24) & 255
142
+ }
143
+
144
+ // Remove 1 or 2 last bytes if padding characters were added to the string
145
+ if (base64String[stringLength - 1] === paddingCharacter) {
146
+ writeOffset--
147
+ }
148
+
149
+ if (base64String[stringLength - 2] === paddingCharacter) {
150
+ writeOffset--
151
+ }
152
+
153
+ return outputBuffer.subarray(0, writeOffset)
154
+ }
155
+
156
+ export const defaultBase64CharCodeMap: Uint8Array = new Uint8Array([65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47])
157
+ export const defaultBase64ReverseCharCodeMap: Uint8Array = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255])
@@ -0,0 +1,67 @@
1
+ import { decodeAscii } from "./Ascii.js"
2
+
3
+ export function encodeHex(buffer: Uint8Array) {
4
+ const asciiBuffer = encodeHexAsAsciiBuffer(buffer)
5
+
6
+ return decodeAscii(asciiBuffer)
7
+ }
8
+
9
+ export function encodeHexAsAsciiBuffer(buffer: Uint8Array) {
10
+ const bufferLen = buffer.length
11
+
12
+ const charCodes = new Uint8Array(bufferLen * 2)
13
+
14
+ let readOffset = 0
15
+ let writeOffset = 0
16
+
17
+ while (readOffset < bufferLen) {
18
+ const value = buffer[readOffset++]
19
+
20
+ const valueHigh4Bits = (value >>> 4) & 0xf
21
+ const valueLow4Bits = value & 0xf
22
+
23
+ charCodes[writeOffset++] = hexCharCodeLookup[valueHigh4Bits]
24
+ charCodes[writeOffset++] = hexCharCodeLookup[valueLow4Bits]
25
+ }
26
+
27
+ return charCodes
28
+ }
29
+
30
+ export function decodeHex(hexString: string) {
31
+ const hexLength = hexString.length
32
+
33
+ if (hexLength % 2 !== 0) {
34
+ throw new Error(`Hexadecimal string doesn't have an even number of characters`)
35
+ }
36
+
37
+ const buffer = new Uint8Array(hexLength / 2)
38
+
39
+ let readOffset = 0
40
+ let writeOffset = 0
41
+
42
+ while (readOffset < hexLength) {
43
+ const valueHigh4Bits = hexCharCodeToValue(hexString.charCodeAt(readOffset++))
44
+ const valueLow4Bits = hexCharCodeToValue(hexString.charCodeAt(readOffset++))
45
+
46
+ const value = (valueHigh4Bits << 4) | valueLow4Bits
47
+
48
+ buffer[writeOffset++] = value
49
+ }
50
+
51
+ return buffer
52
+ }
53
+
54
+ function hexCharCodeToValue(hexCharCode: number) {
55
+ if (hexCharCode >= 48 && hexCharCode <= 57) { // '0'..'9'
56
+ return hexCharCode - 48
57
+ } else if (hexCharCode >= 97 && hexCharCode <= 102) { // 'a'..'f'
58
+ return 10 + hexCharCode - 97
59
+ } else if (hexCharCode >= 65 && hexCharCode <= 70) { // 'A'..'F'
60
+ return 10 + hexCharCode - 65
61
+ } else {
62
+ throw new Error(`Can't decode character '${String.fromCharCode(hexCharCode)}' (code: ${hexCharCode}) as hexadecimal`)
63
+ }
64
+ }
65
+
66
+ const hexCharLookup: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
67
+ const hexCharCodeLookup = new Uint8Array([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102])
@@ -1,5 +1,5 @@
1
- import { DynamicUint8Array } from "./DynamicUint8Array.js"
2
- import { logToStderr } from "./Utilities.js"
1
+ import { DynamicUint8Array, createDynamicUint8Array } from "../data-structures/DynamicTypedArray.js"
2
+ import { logToStderr } from "../utilities/Utilities.js"
3
3
 
4
4
  ////////////////////////////////////////////////////////////////////////////////////////////////////
5
5
  // Encode unsigned integer
@@ -337,13 +337,13 @@ export interface DecodedValueAndReadOffset {
337
337
  // Tests
338
338
  ////////////////////////////////////////////////////////////////////////////////////
339
339
  export function testLeb128Signed() {
340
- const encodedBytes = new DynamicUint8Array()
340
+ const encodedBytes = createDynamicUint8Array()
341
341
 
342
342
  function runTest(testValue: number) {
343
343
  encodedBytes.clear()
344
344
 
345
345
  encodeSignedInt32Fast(testValue, encodedBytes)
346
- const { decodedValue } = decodeSignedInt32Fast(encodedBytes.data, 0)
346
+ const { decodedValue } = decodeSignedInt32Fast(encodedBytes.elements, 0)
347
347
 
348
348
  if (decodedValue !== testValue) {
349
349
  throw new Error(`Expected ${testValue} but got ${decodedValue}`)
@@ -1,5 +1,5 @@
1
- import { DynamicUint8Array } from "./DynamicUint8Array.js"
2
- import { logToStderr } from "./Utilities.js"
1
+ import { createDynamicUint8Array, DynamicUint8Array } from "../data-structures/DynamicTypedArray.js"
2
+ import { logToStderr } from "../utilities/Utilities.js"
3
3
 
4
4
 
5
5
  ////////////////////////////////////////////////////////////////////////////////////
@@ -242,13 +242,13 @@ export interface DecodedValueAndReadOffset {
242
242
  // Tests
243
243
  ////////////////////////////////////////////////////////////////////////////////////
244
244
  export function testLPVarintSigned() {
245
- const encodedBytes = new DynamicUint8Array()
245
+ const encodedBytes = createDynamicUint8Array()
246
246
 
247
247
  function runTest(testValue: number) {
248
248
  encodedBytes.clear()
249
249
 
250
250
  encodeSignedInt32(testValue, encodedBytes)
251
- const { decodedValue } = decodeSignedInt32(encodedBytes.data, 0)
251
+ const { decodedValue } = decodeSignedInt32(encodedBytes.elements, 0)
252
252
 
253
253
  if (decodedValue !== testValue) {
254
254
  throw new Error(`Expected ${testValue} but got ${decodedValue}`)
@@ -267,13 +267,13 @@ export function testLPVarintSigned() {
267
267
  }
268
268
 
269
269
  export function testLPVarintUnsigned() {
270
- const encodedBytes = new DynamicUint8Array()
270
+ const encodedBytes = createDynamicUint8Array()
271
271
 
272
272
  function runTest(testValue: number) {
273
273
  encodedBytes.clear()
274
274
 
275
275
  encodeUnsignedInt31(testValue, encodedBytes)
276
- const { decodedValue } = decodeUnsignedInt31(encodedBytes.data, 0)
276
+ const { decodedValue } = decodeUnsignedInt31(encodedBytes.elements, 0)
277
277
 
278
278
  if (decodedValue !== testValue) {
279
279
  throw new Error(`Expected ${testValue} but got ${decodedValue}`)
@@ -0,0 +1,4 @@
1
+ export interface EncodeIntoResult {
2
+ read: number
3
+ written: number
4
+ }
@@ -0,0 +1,52 @@
1
+ import { EncodeIntoResult } from "./TextEncodingsCommon.js"
2
+
3
+ export function encodeUtf16(text: string) {
4
+ const resultArray = new Uint16Array(text.length)
5
+
6
+ const { written } = encodeUtf16Into(text, resultArray)
7
+
8
+ return resultArray.subarray(0, written)
9
+ }
10
+
11
+ export function encodeUtf16Into(text: string, resultBuffer: Uint16Array): EncodeIntoResult {
12
+ const len = text.length
13
+
14
+ if (resultBuffer.length < len) {
15
+ throw new Error(`Result Uint16Array is not large enough to hold the string`)
16
+ }
17
+
18
+ for (let readOffset = 0; readOffset < len; readOffset++) {
19
+ resultBuffer[readOffset] = text.charCodeAt(readOffset)
20
+ }
21
+
22
+ return { read: len, written: len }
23
+ }
24
+
25
+ export function decodeUtf16(encodedString: Uint16Array) {
26
+ const maxChunkLength = 2 ** 24
27
+
28
+ const decoder = new ChunkedUtf16Decoder()
29
+
30
+ for (let offset = 0; offset < encodedString.length; offset += maxChunkLength) {
31
+ const chunk = encodedString.subarray(offset, offset + maxChunkLength)
32
+
33
+ decoder.writeChunk(chunk)
34
+ }
35
+
36
+ return decoder.toString()
37
+ }
38
+
39
+ export class ChunkedUtf16Decoder {
40
+ private str = ''
41
+ private readonly textDecoder = new TextDecoder('utf-16le')
42
+
43
+ writeChunk(chunk: Uint16Array) {
44
+ const decodedChunk = this.textDecoder.decode(chunk)
45
+
46
+ this.str += decodedChunk
47
+ }
48
+
49
+ toString() {
50
+ return this.str
51
+ }
52
+ }