echogarden 0.11.12 → 0.11.13

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 (122) hide show
  1. package/data/schemas/options.json +16 -0
  2. package/dist/api/Alignment.js +2 -2
  3. package/dist/api/Alignment.js.map +1 -1
  4. package/dist/api/Recognition.js +2 -2
  5. package/dist/api/Recognition.js.map +1 -1
  6. package/dist/api/Synthesis.js +5 -4
  7. package/dist/api/Synthesis.js.map +1 -1
  8. package/dist/api/Translation.js +2 -2
  9. package/dist/api/Translation.js.map +1 -1
  10. package/dist/audio/AudioUtilities.d.ts +1 -0
  11. package/dist/audio/AudioUtilities.js +25 -7
  12. package/dist/audio/AudioUtilities.js.map +1 -1
  13. package/dist/cli/CLI.js +2 -2
  14. package/dist/cli/CLI.js.map +1 -1
  15. package/dist/recognition/WhisperSTT.js +2 -2
  16. package/dist/recognition/WhisperSTT.js.map +1 -1
  17. package/dist/subtitles/Subtitles.d.ts +10 -7
  18. package/dist/subtitles/Subtitles.js +268 -207
  19. package/dist/subtitles/Subtitles.js.map +1 -1
  20. package/docs/Options.md +4 -2
  21. package/package.json +7 -6
  22. package/src/alignment/DTWMfccSequenceAlignment.ts +43 -0
  23. package/src/alignment/DTWSequenceAlignment.ts +121 -0
  24. package/src/alignment/DTWSequenceAlignmentWindowed.ts +210 -0
  25. package/src/alignment/LevenshteinSequenceAlignment.ts +126 -0
  26. package/src/alignment/SpeechAlignment.ts +488 -0
  27. package/src/api/API.ts +12 -0
  28. package/src/api/APIOptions.ts +15 -0
  29. package/src/api/Alignment.ts +329 -0
  30. package/src/api/Common.ts +16 -0
  31. package/src/api/Denoising.ts +120 -0
  32. package/src/api/LanguageDetection.ts +286 -0
  33. package/src/api/Recognition.ts +344 -0
  34. package/src/api/Synthesis.ts +1735 -0
  35. package/src/api/Translation.ts +143 -0
  36. package/src/api/Vad.ts +172 -0
  37. package/src/audio/AudioBufferConversion.ts +248 -0
  38. package/src/audio/AudioPlayer.ts +358 -0
  39. package/src/audio/AudioRecorder.ts +91 -0
  40. package/src/audio/AudioUtilities.ts +392 -0
  41. package/src/audio/SoxPath.ts +24 -0
  42. package/src/cli/CLI.ts +1360 -0
  43. package/src/cli/CLIConfigFile.ts +91 -0
  44. package/src/cli/CLILauncher.ts +26 -0
  45. package/src/cli/CLIOptionsSchema.ts +54 -0
  46. package/src/cli/CLIParser.ts +41 -0
  47. package/src/cli/CLIStarter.ts +40 -0
  48. package/src/codecs/FFMpegTranscoder.ts +214 -0
  49. package/src/codecs/TIMITCodec.ts +17 -0
  50. package/src/codecs/WaveCodec.ts +260 -0
  51. package/src/denoising/RNNoise.ts +95 -0
  52. package/src/dsp/BiquadFilter.ts +488 -0
  53. package/src/dsp/FFT.ts +187 -0
  54. package/src/dsp/MFCC.ts +227 -0
  55. package/src/dsp/MelSpectogram.ts +145 -0
  56. package/src/dsp/Rubberband.ts +249 -0
  57. package/src/dsp/Sonic.ts +59 -0
  58. package/src/dsp/SpeexResampler.ts +79 -0
  59. package/src/math/VectorMath.ts +812 -0
  60. package/src/nlp/ChineseSegmentation.ts +68 -0
  61. package/src/nlp/CompromiseNLP.ts +113 -0
  62. package/src/nlp/EspeakPhonemizer.ts +168 -0
  63. package/src/nlp/IPA.ts +139 -0
  64. package/src/nlp/JapaneseSegmentation.ts +53 -0
  65. package/src/nlp/Lexicon.ts +119 -0
  66. package/src/nlp/PhoneConversion.ts +508 -0
  67. package/src/nlp/Segmentation.ts +237 -0
  68. package/src/nlp/TextNormalizer.ts +160 -0
  69. package/src/recognition/AmazonTranscribeSTT.ts +112 -0
  70. package/src/recognition/AzureCognitiveServicesSTT.ts +76 -0
  71. package/src/recognition/GoogleCloudSTT.ts +92 -0
  72. package/src/recognition/SileroSTT.ts +173 -0
  73. package/src/recognition/VoskSTT.ts +112 -0
  74. package/src/recognition/WhisperSTT.ts +1518 -0
  75. package/src/server/Client.ts +297 -0
  76. package/src/server/Server.ts +178 -0
  77. package/src/server/ServerStarter.ts +12 -0
  78. package/src/server/Worker.ts +400 -0
  79. package/src/server/WorkerStarter.ts +38 -0
  80. package/src/speech-language-detection/SileroLanguageDetection.ts +105 -0
  81. package/src/subtitles/Subtitles.ts +478 -0
  82. package/src/synthesis/AwsPollyTTS.ts +78 -0
  83. package/src/synthesis/AzureCognitiveServicesTTS.ts +146 -0
  84. package/src/synthesis/CoquiServerTTS.ts +29 -0
  85. package/src/synthesis/ElevenLabsTTS.ts +104 -0
  86. package/src/synthesis/EspeakTTS.ts +552 -0
  87. package/src/synthesis/FliteTTS.ts +387 -0
  88. package/src/synthesis/GoogleCloudTTS.ts +112 -0
  89. package/src/synthesis/GoogleTranslateTTS.ts +210 -0
  90. package/src/synthesis/MicrosoftEdgeTTS.ts +298 -0
  91. package/src/synthesis/SamTTS.ts +30 -0
  92. package/src/synthesis/SapiTTS.ts +222 -0
  93. package/src/synthesis/StreamlabsPollyTTS.ts +114 -0
  94. package/src/synthesis/SvoxPicoTTS.ts +318 -0
  95. package/src/synthesis/VitsTTS.ts +734 -0
  96. package/src/tests/Test.ts +24 -0
  97. package/src/text-language-detection/FastTextLanguageDetection.ts +53 -0
  98. package/src/text-language-detection/TinyLDLanguageDetection.ts +16 -0
  99. package/src/typings/Fillers.d.ts +41 -0
  100. package/src/utilities/BinaryArrayConversion.ts +159 -0
  101. package/src/utilities/Compression.ts +91 -0
  102. package/src/utilities/FileDownloader.ts +201 -0
  103. package/src/utilities/FileSystem.ts +265 -0
  104. package/src/utilities/Hashing.ts +230 -0
  105. package/src/utilities/Locale.ts +119 -0
  106. package/src/utilities/Logger.ts +72 -0
  107. package/src/utilities/NdArrayUtilities.ts +31 -0
  108. package/src/utilities/ObjectUtilities.ts +169 -0
  109. package/src/utilities/OpenPromise.ts +13 -0
  110. package/src/utilities/PackageManager.ts +97 -0
  111. package/src/utilities/Queue.ts +17 -0
  112. package/src/utilities/RandomGenerator.ts +237 -0
  113. package/src/utilities/SignalChannel.ts +22 -0
  114. package/src/utilities/TarballMaker.ts +68 -0
  115. package/src/utilities/Timeline.ts +231 -0
  116. package/src/utilities/Timer.ts +93 -0
  117. package/src/utilities/Utilities.ts +574 -0
  118. package/src/utilities/WasmMemoryManager.ts +516 -0
  119. package/src/utilities/WebReader.ts +55 -0
  120. package/src/utilities/WikipediaReader.ts +41 -0
  121. package/src/voice-activity-detection/SileroVAD.ts +86 -0
  122. package/src/voice-activity-detection/WebRtcVAD.ts +76 -0
@@ -0,0 +1,318 @@
1
+ import { SynthesisVoice } from "../api/API.js"
2
+ import { decodeToChannels } from "../audio/AudioBufferConversion.js"
3
+ import { SampleFormat } from "../codecs/WaveCodec.js"
4
+ import { bandwidthToQFactor } from "../dsp/BiquadFilter.js"
5
+ import { Logger } from "../utilities/Logger.js"
6
+ import { WasmMemoryManager } from "../utilities/WasmMemoryManager.js"
7
+ import { RawAudio } from "../audio/AudioUtilities.js"
8
+ import { readFile } from "../utilities/FileSystem.js"
9
+
10
+ let svoxPicoInstance: any
11
+
12
+ export async function synthesize(text: string, textAnalysisFilePath: string, signalGenerationFilePath: string, postprocessOutput = true) {
13
+ const logger = new Logger()
14
+ logger.start("Get pico WASM instance")
15
+
16
+ const m = await getInstance()
17
+
18
+ logger.start("Initialize pico engine")
19
+
20
+ const wasmMemory = new WasmMemoryManager(m)
21
+
22
+ const pico_initialize = m._pico_initialize
23
+ const picoext_setTraceLevel = m._picoext_setTraceLevel
24
+ const pico_loadResource = m._pico_loadResource
25
+ const pico_getResourceName = m._pico_getResourceName
26
+ const pico_createVoiceDefinition = m._pico_createVoiceDefinition
27
+ const pico_addResourceToVoiceDefinition = m._pico_addResourceToVoiceDefinition
28
+ const pico_newEngine = m._pico_newEngine
29
+ const pico_putTextUtf8 = m._pico_putTextUtf8
30
+ const pico_getData = m._pico_getData
31
+
32
+ const pico_getSystemStatusMessage = m._pico_getSystemStatusMessage
33
+
34
+ const pico_disposeEngine = m._pico_disposeEngine
35
+ const pico_terminate = m._pico_terminate
36
+ const pico_releaseVoiceDefinition = m._pico_releaseVoiceDefinition
37
+ const pico_unloadResource = m._pico_unloadResource
38
+
39
+ const picoMemSize = 2500000
40
+ const picoMemAreaRef = wasmMemory.allocUint8Array(picoMemSize)
41
+
42
+ const systemPtrRef = wasmMemory.allocPointer()
43
+
44
+ let resultCode = pico_initialize(picoMemAreaRef.address, picoMemAreaRef.length, systemPtrRef.address)
45
+ const systemPtr = systemPtrRef.value
46
+
47
+ throwErrorIfFailed(resultCode, "Failed Pico initialization.")
48
+
49
+ picoext_setTraceLevel(systemPtr, 5)
50
+
51
+ async function loadResource(localFilePath: string) {
52
+ const virtualFilePath = "." + localFilePath.substring(localFilePath.lastIndexOf("/"))
53
+
54
+ const fileData = await readFile(localFilePath)
55
+ m.FS.writeFile(virtualFilePath, fileData)
56
+
57
+ const virtualFilePathRef = wasmMemory.allocNullTerminatedUtf8String(virtualFilePath)
58
+ const resourcePtrRef = wasmMemory.allocPointer()
59
+
60
+ resultCode = pico_loadResource(systemPtr, virtualFilePathRef.address, resourcePtrRef.address)
61
+ const resourcePtr = resourcePtrRef.value
62
+
63
+ throwErrorIfFailed(resultCode, `Failed loading Pico resource ${localFilePath}.`)
64
+
65
+ return { resourcePtr, resourcePtrRef }
66
+ }
67
+
68
+ const { resourcePtr: textAnalysisResourcePtr, resourcePtrRef: textAnalysisResourcePtrRef } = await loadResource(textAnalysisFilePath)
69
+ const { resourcePtr: signalGenerationResourcePtr, resourcePtrRef: signalGenerationResourcePtrRef } = await loadResource(signalGenerationFilePath)
70
+
71
+ function getResourceName(resourcePtr: number) {
72
+ const resourceNameRef = wasmMemory.allocUint8Array(32)
73
+ resultCode = pico_getResourceName(systemPtr, resourcePtr, resourceNameRef.address)
74
+
75
+ throwErrorIfFailed(resultCode, `Failed getting Pico resource name.`)
76
+
77
+ const resourceName = resourceNameRef.readAsNullTerminatedUtf8String()
78
+
79
+ return { resourceName, resourceNameRef }
80
+ }
81
+
82
+ const { resourceName: textAnalysisResourceName, resourceNameRef: textAnalysisResourceNameRef } = getResourceName(textAnalysisResourcePtr)
83
+ const { resourceName: signalGenerationResourceName, resourceNameRef: signalGenerationResourceNameRef } = getResourceName(signalGenerationResourcePtr)
84
+
85
+ const voiceNameRef = wasmMemory.allocNullTerminatedUtf8String("PicoVoice")
86
+
87
+ resultCode = pico_createVoiceDefinition(systemPtr, voiceNameRef.address)
88
+
89
+ function addResourceToVoiceDefinition(resourceNamePtr: number) {
90
+ resultCode = pico_addResourceToVoiceDefinition(systemPtr, voiceNameRef.address, resourceNamePtr)
91
+
92
+ throwErrorIfFailed(resultCode, `Failed adding resource to voice definition.`)
93
+ }
94
+
95
+ addResourceToVoiceDefinition(textAnalysisResourceNameRef.address)
96
+ addResourceToVoiceDefinition(signalGenerationResourceNameRef.address)
97
+
98
+ const enginePtrRef = wasmMemory.allocPointer()
99
+ resultCode = pico_newEngine(systemPtr, voiceNameRef.address, enginePtrRef.address)
100
+
101
+ throwErrorIfFailed(resultCode, `Failed creating new engine.`)
102
+
103
+ const enginePtr = enginePtrRef.value
104
+
105
+ logger.start("Synthesize with pico")
106
+
107
+ const textRef = wasmMemory.allocNullTerminatedUtf8String(text)
108
+
109
+ const bytesWrittenRef = wasmMemory.allocInt32()
110
+
111
+ const audioParts: Buffer[] = []
112
+
113
+ for (let textByteOffset = 0; textByteOffset < textRef.length;) {
114
+ bytesWrittenRef.value = 0
115
+ resultCode = pico_putTextUtf8(enginePtr, textRef.address + textByteOffset, textRef.length - textByteOffset, bytesWrittenRef.address)
116
+ const bytesWritten = bytesWrittenRef.value
117
+
118
+ throwErrorIfFailed(resultCode, `Failed writing text to engine.`)
119
+
120
+ const audioPart = readAudioDataFromEngine()
121
+ audioParts.push(audioPart)
122
+
123
+ textByteOffset += bytesWritten
124
+ }
125
+
126
+ const audioData = Buffer.concat(audioParts)
127
+
128
+ function readAudioDataFromEngine() {
129
+ const outBuffers: Buffer[] = []
130
+
131
+ const outBufferLength = 16384
132
+ const outBufferRef = wasmMemory.allocUint8Array(outBufferLength)
133
+
134
+ const outByteCountRef = wasmMemory.allocInt16()
135
+ const outDataTypeRef = wasmMemory.allocInt16()
136
+
137
+ while (true) {
138
+ resultCode = pico_getData(enginePtr, outBufferRef.address, outBufferRef.length, outByteCountRef.address, outDataTypeRef.address)
139
+
140
+ throwErrorIfFailed(resultCode, `Failed getting audio data from engine.`, [200, 201])
141
+
142
+ const outByteCount = outByteCountRef.value
143
+ const outDataType = outDataTypeRef.value
144
+
145
+ if (resultCode == 200) {
146
+ break
147
+ }
148
+
149
+ if (outByteCount > 0) {
150
+ outBuffers.push(Buffer.from(outBufferRef.slice(0, outByteCount)))
151
+ }
152
+ }
153
+
154
+ return Buffer.concat(outBuffers)
155
+ }
156
+
157
+ dispose()
158
+
159
+ function dispose() {
160
+ if (!systemPtr) {
161
+ return
162
+ }
163
+
164
+ if (enginePtrRef) {
165
+ pico_disposeEngine(systemPtr, enginePtrRef.address)
166
+ }
167
+
168
+ if (voiceNameRef) {
169
+ pico_releaseVoiceDefinition(systemPtr, voiceNameRef.address)
170
+ }
171
+
172
+ if (textAnalysisResourcePtrRef) {
173
+ pico_unloadResource(systemPtr, textAnalysisResourcePtrRef.address)
174
+ }
175
+
176
+ if (signalGenerationResourcePtrRef) {
177
+ pico_unloadResource(systemPtr, signalGenerationResourcePtrRef.address)
178
+ }
179
+
180
+ pico_terminate(systemPtrRef.address)
181
+
182
+ wasmMemory.freeAll()
183
+ }
184
+
185
+ function throwErrorIfFailed(resultCode: number, title: string, successCodes = [0]) {
186
+ if (successCodes.includes(resultCode)) {
187
+ return
188
+ }
189
+
190
+ const picoErrorMessageRef = wasmMemory.allocUint8Array(200)
191
+ pico_getSystemStatusMessage(systemPtr, resultCode, picoErrorMessageRef)
192
+ const picoErrorMessage = picoErrorMessageRef.readAsNullTerminatedUtf8String()
193
+
194
+ dispose()
195
+ throw new Error(`${title} ${picoErrorMessage}`)
196
+ }
197
+
198
+ const audioChannels = decodeToChannels(audioData, 1, 16, SampleFormat.PCM)
199
+ let rawAudio: RawAudio = { audioChannels, sampleRate: 16000 }
200
+
201
+ if (postprocessOutput) {
202
+ logger.start("Apply EQ to synthesized audio")
203
+
204
+ const Biquad = await import("../dsp/BiquadFilter.js")
205
+
206
+ Biquad.createLowshelfFilter(rawAudio.sampleRate, 177, -2.6).apply(rawAudio.audioChannels[0])
207
+ Biquad.createPeakingFilter(rawAudio.sampleRate, 440, bandwidthToQFactor(2), -9.7).apply(rawAudio.audioChannels[0])
208
+ //Biquad.createPeakingFilter(rawAudio.sampleRate, 1639, bandwidthToQFactor(2), 5.2).apply(rawAudio.audioChannels[0])
209
+ Biquad.createHighshelfFilter(rawAudio.sampleRate, 5180, 10.6).apply(rawAudio.audioChannels[0])
210
+ }
211
+
212
+ logger.end()
213
+
214
+ return { rawAudio }
215
+ }
216
+
217
+ export async function getInstance() {
218
+ if (!svoxPicoInstance) {
219
+ const { default: initializer } = await import('@echogarden/svoxpico-wasm')
220
+
221
+ svoxPicoInstance = await initializer()
222
+ }
223
+
224
+ return svoxPicoInstance
225
+ }
226
+
227
+ export function getResourceFilenamesForLanguage(language: string) {
228
+ let textAnalysisFilename: string
229
+ let signalGenerationFilename: string
230
+
231
+ switch (language) {
232
+ case "en-US":
233
+ case "en": {
234
+ textAnalysisFilename = "en-US_ta.bin"
235
+ signalGenerationFilename = "en-US_lh0_sg.bin"
236
+ break
237
+ }
238
+
239
+ case "en-GB": {
240
+ textAnalysisFilename = "en-GB_ta.bin"
241
+ signalGenerationFilename = "en-GB_kh0_sg.bin"
242
+ break
243
+ }
244
+
245
+ case "de-DE":
246
+ case "de": {
247
+ textAnalysisFilename = "de-DE_ta.bin"
248
+ signalGenerationFilename = "de-DE_gl0_sg.bin"
249
+ break
250
+ }
251
+
252
+ case "es-ES":
253
+ case "es": {
254
+ textAnalysisFilename = "es-ES_ta.bin"
255
+ signalGenerationFilename = "es-ES_zl0_sg.bin"
256
+ break
257
+ }
258
+
259
+ case "fr-FR":
260
+ case "fr": {
261
+ textAnalysisFilename = "fr-FR_ta.bin"
262
+ signalGenerationFilename = "fr-FR_nk0_sg.bin"
263
+ break
264
+ }
265
+
266
+ case "it-IT":
267
+ case "it": {
268
+ textAnalysisFilename = "it-IT_ta.bin"
269
+ signalGenerationFilename = "it-IT_cm0_sg.bin"
270
+ break
271
+ }
272
+
273
+ default: {
274
+ throw new Error(`Unsupported languge: ${language}`)
275
+ }
276
+ }
277
+
278
+ return { textAnalysisFilename, signalGenerationFilename }
279
+ }
280
+
281
+ export const voiceList: SynthesisVoice[] = [
282
+ {
283
+ name: "en-US",
284
+ languages: ["en-US", "en"],
285
+ gender: "female",
286
+ packageName: "pico-en-US"
287
+ },
288
+ {
289
+ name: "en-GB",
290
+ languages: ["en-GB", "en"],
291
+ gender: "female",
292
+ packageName: "pico-en-GB"
293
+ },
294
+ {
295
+ name: "de-DE",
296
+ languages: ["de-DE", "de"],
297
+ gender: "female",
298
+ packageName: "pico-de-DE"
299
+ },
300
+ {
301
+ name: "es-ES",
302
+ languages: ["es-ES", "es"],
303
+ gender: "female",
304
+ packageName: "pico-es-ES"
305
+ },
306
+ {
307
+ name: "fr-FR",
308
+ languages: ["fr-FR", "fr"],
309
+ gender: "female",
310
+ packageName: "pico-fr-FR"
311
+ },
312
+ {
313
+ name: "it-IT",
314
+ languages: ["it-IT", "it"],
315
+ gender: "female",
316
+ packageName: "pico-it-IT"
317
+ },
318
+ ]