echogarden 1.4.4 → 1.6.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 (240) hide show
  1. package/data/schemas/options.json +310 -25
  2. package/dist/alignment/DTWMfccSequenceAlignment.d.ts +1 -1
  3. package/dist/alignment/DTWMfccSequenceAlignment.js +5 -5
  4. package/dist/alignment/DTWSequenceAlignmentWindowed.js +1 -3
  5. package/dist/alignment/DTWSequenceAlignmentWindowed.js.map +1 -1
  6. package/dist/alignment/{TextAlignment.d.ts → SemanticTextAlignment.d.ts} +4 -2
  7. package/dist/alignment/SemanticTextAlignment.js +336 -0
  8. package/dist/alignment/SemanticTextAlignment.js.map +1 -0
  9. package/dist/alignment/SpeechAlignment.d.ts +4 -3
  10. package/dist/alignment/SpeechAlignment.js +130 -39
  11. package/dist/alignment/SpeechAlignment.js.map +1 -1
  12. package/dist/api/API.d.ts +7 -3
  13. package/dist/api/API.js +7 -2
  14. package/dist/api/API.js.map +1 -1
  15. package/dist/api/APIOptions.d.ts +4 -1
  16. package/dist/api/Alignment.d.ts +1 -1
  17. package/dist/api/Alignment.js +13 -5
  18. package/dist/api/Alignment.js.map +1 -1
  19. package/dist/api/LanguageDetectionCommon.d.ts +6 -0
  20. package/dist/api/LanguageDetectionCommon.js +2 -0
  21. package/dist/api/LanguageDetectionCommon.js.map +1 -0
  22. package/dist/api/Recognition.js.map +1 -1
  23. package/dist/api/{LanguageDetection.d.ts → SpeechLanguageDetection.d.ts} +1 -25
  24. package/dist/api/{LanguageDetection.js → SpeechLanguageDetection.js} +1 -68
  25. package/dist/api/SpeechLanguageDetection.js.map +1 -0
  26. package/dist/api/{Translation.js → SpeechTranslation.js} +3 -3
  27. package/dist/api/SpeechTranslation.js.map +1 -0
  28. package/dist/api/Synthesis.d.ts +0 -1
  29. package/dist/api/Synthesis.js +4 -4
  30. package/dist/api/TextLanguageDetection.d.ts +21 -0
  31. package/dist/api/TextLanguageDetection.js +67 -0
  32. package/dist/api/TextLanguageDetection.js.map +1 -0
  33. package/dist/api/TextTranslation.d.ts +25 -0
  34. package/dist/api/TextTranslation.js +101 -0
  35. package/dist/api/TextTranslation.js.map +1 -0
  36. package/dist/api/TimelineTranslationAlignment.d.ts +23 -0
  37. package/dist/api/TimelineTranslationAlignment.js +92 -0
  38. package/dist/api/TimelineTranslationAlignment.js.map +1 -0
  39. package/dist/api/TranscriptAndTranslationAlignment.d.ts +35 -0
  40. package/dist/api/TranscriptAndTranslationAlignment.js +78 -0
  41. package/dist/api/TranscriptAndTranslationAlignment.js.map +1 -0
  42. package/dist/api/TranslationAlignment.d.ts +4 -3
  43. package/dist/api/TranslationAlignment.js +9 -8
  44. package/dist/api/TranslationAlignment.js.map +1 -1
  45. package/dist/api/VoiceActivityDetection.js +16 -1
  46. package/dist/api/VoiceActivityDetection.js.map +1 -1
  47. package/dist/audio/AudioBufferConversion.d.ts +0 -1
  48. package/dist/audio/AudioPlayer.d.ts +0 -1
  49. package/dist/audio/AudioPlayer.js +62 -41
  50. package/dist/audio/AudioPlayer.js.map +1 -1
  51. package/dist/audio/AudioUtilities.d.ts +0 -1
  52. package/dist/cli/CLI.d.ts +28 -7
  53. package/dist/cli/CLI.js +265 -37
  54. package/dist/cli/CLI.js.map +1 -1
  55. package/dist/codecs/FFMpegTranscoder.d.ts +0 -1
  56. package/dist/codecs/FFMpegTranscoder.js +7 -0
  57. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  58. package/dist/codecs/TIMITCodec.d.ts +0 -1
  59. package/dist/codecs/WaveCodec.d.ts +0 -1
  60. package/dist/dsp/FFT.d.ts +1 -1
  61. package/dist/dsp/FFT.js +6 -0
  62. package/dist/dsp/FFT.js.map +1 -1
  63. package/dist/dsp/KWeightingFilter.js +1 -1
  64. package/dist/dsp/KWeightingFilter.js.map +1 -1
  65. package/dist/dsp/MelSpectogram.d.ts +3 -2
  66. package/dist/dsp/MelSpectogram.js +14 -8
  67. package/dist/dsp/MelSpectogram.js.map +1 -1
  68. package/dist/math/VectorMath.d.ts +9 -9
  69. package/dist/math/VectorMath.js +10 -10
  70. package/dist/math/VectorMath.js.map +1 -1
  71. package/dist/nlp/ChineseSegmentation.js +4 -4
  72. package/dist/nlp/ChineseSegmentation.js.map +1 -1
  73. package/dist/nlp/Segmentation.d.ts +2 -2
  74. package/dist/nlp/Segmentation.js +20 -13
  75. package/dist/nlp/Segmentation.js.map +1 -1
  76. package/dist/recognition/OpenAICloudSTT.d.ts +2 -1
  77. package/dist/recognition/OpenAICloudSTT.js +30 -19
  78. package/dist/recognition/OpenAICloudSTT.js.map +1 -1
  79. package/dist/recognition/SileroSTT.d.ts +0 -1
  80. package/dist/recognition/WhisperCppSTT.d.ts +3 -3
  81. package/dist/recognition/WhisperCppSTT.js +21 -9
  82. package/dist/recognition/WhisperCppSTT.js.map +1 -1
  83. package/dist/recognition/WhisperSTT.d.ts +9 -6
  84. package/dist/recognition/WhisperSTT.js +227 -46
  85. package/dist/recognition/WhisperSTT.js.map +1 -1
  86. package/dist/server/Client.d.ts +3 -4
  87. package/dist/server/Client.js.map +1 -1
  88. package/dist/server/Worker.d.ts +3 -3
  89. package/dist/server/Worker.js +3 -2
  90. package/dist/server/Worker.js.map +1 -1
  91. package/dist/source-separation/MDXNetSourceSeparation.d.ts +0 -1
  92. package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
  93. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  94. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.d.ts +12 -0
  95. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js +68 -0
  96. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js.map +1 -0
  97. package/dist/speech-language-detection/SileroLanguageDetection.d.ts +1 -2
  98. package/dist/speech-language-detection/SileroLanguageDetection.js +1 -1
  99. package/dist/speech-language-detection/SileroLanguageDetection.js.map +1 -1
  100. package/dist/subtitles/Subtitles.js +2 -2
  101. package/dist/subtitles/Subtitles.js.map +1 -1
  102. package/dist/synthesis/GoogleCloudTTS.d.ts +0 -1
  103. package/dist/synthesis/GoogleTranslateTTS.d.ts +0 -1
  104. package/dist/synthesis/GoogleTranslateTTS.js +6 -21
  105. package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
  106. package/dist/synthesis/StreamlabsPollyTTS.d.ts +0 -1
  107. package/dist/synthesis/VitsTTS.d.ts +0 -1
  108. package/dist/synthesis/VitsTTS.js +30 -0
  109. package/dist/synthesis/VitsTTS.js.map +1 -1
  110. package/dist/tests/Test.js +0 -31
  111. package/dist/tests/Test.js.map +1 -1
  112. package/dist/text-language-detection/FastTextLanguageDetection.d.ts +1 -1
  113. package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
  114. package/dist/text-language-detection/TinyLDLanguageDetection.d.ts +1 -1
  115. package/dist/text-language-detection/TinyLDLanguageDetection.js.map +1 -1
  116. package/dist/text-translation/DeepLTextTranslation.d.ts +2 -0
  117. package/dist/text-translation/DeepLTextTranslation.js +67 -0
  118. package/dist/text-translation/DeepLTextTranslation.js.map +1 -0
  119. package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +10 -0
  120. package/dist/text-translation/GoogleTranslateTextTranslation.js +554 -0
  121. package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -0
  122. package/dist/text-translation/NLLBTextTranslation.d.ts +2 -1
  123. package/dist/text-translation/NLLBTextTranslation.js +249 -19
  124. package/dist/text-translation/NLLBTextTranslation.js.map +1 -1
  125. package/dist/utilities/BinaryArrayConversion.d.ts +0 -1
  126. package/dist/utilities/BrowserRequestHeaders.d.ts +6 -0
  127. package/dist/utilities/BrowserRequestHeaders.js +52 -0
  128. package/dist/utilities/BrowserRequestHeaders.js.map +1 -0
  129. package/dist/utilities/BufferFileReadStream.d.ts +20 -0
  130. package/dist/utilities/BufferFileReadStream.js +81 -0
  131. package/dist/utilities/BufferFileReadStream.js.map +1 -0
  132. package/dist/utilities/DynamicUint8Array.d.ts +9 -0
  133. package/dist/utilities/DynamicUint8Array.js +31 -0
  134. package/dist/utilities/DynamicUint8Array.js.map +1 -0
  135. package/dist/utilities/FileSystem.d.ts +0 -2
  136. package/dist/utilities/Hashing.d.ts +3 -10
  137. package/dist/utilities/Hashing.js +10 -127
  138. package/dist/utilities/Hashing.js.map +1 -1
  139. package/dist/utilities/LEB128.d.ts +15 -5
  140. package/dist/utilities/LEB128.js +199 -119
  141. package/dist/utilities/LEB128.js.map +1 -1
  142. package/dist/utilities/LPVarInt.d.ts +11 -0
  143. package/dist/utilities/LPVarInt.js +187 -0
  144. package/dist/utilities/LPVarInt.js.map +1 -0
  145. package/dist/utilities/Locale.d.ts +1 -1
  146. package/dist/utilities/Locale.js +1 -1
  147. package/dist/utilities/OnnxUtilities.d.ts +1 -2
  148. package/dist/utilities/PVarInt.d.ts +4 -0
  149. package/dist/utilities/PVarInt.js +166 -0
  150. package/dist/utilities/PVarInt.js.map +1 -0
  151. package/dist/utilities/PackageManager.js +48 -25
  152. package/dist/utilities/PackageManager.js.map +1 -1
  153. package/dist/utilities/RandomGenerator.d.ts +3 -17
  154. package/dist/utilities/RandomGenerator.js +12 -81
  155. package/dist/utilities/RandomGenerator.js.map +1 -1
  156. package/dist/utilities/Timeline.d.ts +2 -0
  157. package/dist/utilities/Timeline.js +129 -20
  158. package/dist/utilities/Timeline.js.map +1 -1
  159. package/dist/utilities/Utilities.d.ts +1 -3
  160. package/dist/utilities/Utilities.js +30 -3
  161. package/dist/utilities/Utilities.js.map +1 -1
  162. package/dist/utilities/VarInt.d.ts +4 -0
  163. package/dist/utilities/VarInt.js +166 -0
  164. package/dist/utilities/VarInt.js.map +1 -0
  165. package/dist/utilities/VirtualFileReadStream.d.ts +20 -0
  166. package/dist/utilities/VirtualFileReadStream.js +79 -0
  167. package/dist/utilities/VirtualFileReadStream.js.map +1 -0
  168. package/dist/utilities/WebReader.js +7 -23
  169. package/dist/utilities/WebReader.js.map +1 -1
  170. package/dist/voice-activity-detection/SileroVAD.d.ts +0 -1
  171. package/docs/API.md +105 -3
  172. package/docs/CLI.md +51 -1
  173. package/docs/Engines.md +32 -3
  174. package/docs/Options.md +53 -12
  175. package/docs/Tasklist.md +1 -13
  176. package/package.json +20 -24
  177. package/src/alignment/DTWMfccSequenceAlignment.ts +5 -5
  178. package/src/alignment/DTWSequenceAlignmentWindowed.ts +1 -3
  179. package/src/alignment/SemanticTextAlignment.ts +467 -0
  180. package/src/alignment/SpeechAlignment.ts +214 -56
  181. package/src/api/API.ts +18 -2
  182. package/src/api/APIOptions.ts +14 -1
  183. package/src/api/Alignment.ts +31 -9
  184. package/src/api/LanguageDetectionCommon.ts +7 -0
  185. package/src/api/Recognition.ts +2 -0
  186. package/src/api/{LanguageDetection.ts → SpeechLanguageDetection.ts} +1 -119
  187. package/src/api/{Translation.ts → SpeechTranslation.ts} +2 -2
  188. package/src/api/Synthesis.ts +4 -4
  189. package/src/api/TextLanguageDetection.ts +116 -0
  190. package/src/api/TextTranslation.ts +177 -0
  191. package/src/api/TimelineTranslationAlignment.ts +162 -0
  192. package/src/api/TranscriptAndTranslationAlignment.ts +164 -0
  193. package/src/api/TranslationAlignment.ts +12 -10
  194. package/src/api/VoiceActivityDetection.ts +24 -3
  195. package/src/audio/AudioPlayer.ts +2 -0
  196. package/src/cli/CLI.ts +376 -40
  197. package/src/codecs/FFMpegTranscoder.ts +6 -0
  198. package/src/dsp/FFT.ts +8 -2
  199. package/src/dsp/KWeightingFilter.ts +1 -1
  200. package/src/dsp/MelSpectogram.ts +17 -8
  201. package/src/math/VectorMath.ts +15 -15
  202. package/src/nlp/ChineseSegmentation.ts +6 -4
  203. package/src/nlp/Segmentation.ts +18 -13
  204. package/src/recognition/OpenAICloudSTT.ts +47 -29
  205. package/src/recognition/WhisperCppSTT.ts +26 -11
  206. package/src/recognition/WhisperSTT.ts +364 -49
  207. package/src/server/Client.ts +3 -2
  208. package/src/server/Worker.ts +3 -2
  209. package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
  210. package/src/speech-embeddings/WavToVec2BertFeatureEmbeddings.ts +107 -0
  211. package/src/speech-language-detection/SileroLanguageDetection.ts +2 -1
  212. package/src/subtitles/Subtitles.ts +2 -2
  213. package/src/synthesis/GoogleTranslateTTS.ts +7 -21
  214. package/src/synthesis/VitsTTS.ts +31 -3
  215. package/src/tests/Test.ts +1 -38
  216. package/src/text-language-detection/FastTextLanguageDetection.ts +1 -1
  217. package/src/text-language-detection/TinyLDLanguageDetection.ts +1 -1
  218. package/src/text-translation/DeepLTextTranslation.ts +88 -0
  219. package/src/text-translation/GoogleTranslateTextTranslation.ts +667 -0
  220. package/src/text-translation/NLLBTextTranslation.ts +261 -21
  221. package/src/typings/Fillers.d.ts +25 -2
  222. package/src/utilities/BrowserRequestHeaders.ts +59 -0
  223. package/src/utilities/DynamicUint8Array.ts +39 -0
  224. package/src/utilities/Hashing.ts +14 -167
  225. package/src/utilities/LEB128.ts +273 -148
  226. package/src/utilities/LPVarInt.ts +292 -0
  227. package/src/utilities/Locale.ts +1 -1
  228. package/src/utilities/OnnxUtilities.ts +1 -1
  229. package/src/utilities/PackageManager.ts +51 -30
  230. package/src/utilities/RandomGenerator.ts +12 -113
  231. package/src/utilities/Timeline.ts +162 -23
  232. package/src/utilities/Utilities.ts +40 -3
  233. package/src/utilities/VirtualFileReadStream.ts +109 -0
  234. package/src/utilities/WebReader.ts +9 -23
  235. package/dist/alignment/TextAlignment.js +0 -156
  236. package/dist/alignment/TextAlignment.js.map +0 -1
  237. package/dist/api/LanguageDetection.js.map +0 -1
  238. package/dist/api/Translation.js.map +0 -1
  239. package/src/alignment/TextAlignment.ts +0 -234
  240. /package/dist/api/{Translation.d.ts → SpeechTranslation.d.ts} +0 -0
package/src/cli/CLI.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import * as API from '../api/API.js'
2
2
  import { parseCLIArguments } from './CLIParser.js'
3
- import { clip, convertHtmlToText, formatIntegerWithLeadingZeros, formatListWithQuotedElements, getWithDefault, logToStderr, setupUnhandledExceptionListeners, splitFilenameOnExtendedExtension, stringifyAndFormatJson } from '../utilities/Utilities.js'
3
+ import { convertHtmlToText, formatIntegerWithLeadingZeros, formatListWithQuotedElements, getWithDefault, logToStderr, setupUnhandledExceptionListeners, splitFilenameOnExtendedExtension, stringifyAndFormatJson } from '../utilities/Utilities.js'
4
4
  import { getOptionTypeFromSchema, SchemaTypeDefinition } from './CLIOptionsSchema.js'
5
5
  import { ParsedConfigFile, parseConfigFile, parseJSONConfigFile } from './CLIConfigFile.js'
6
6
 
7
7
  import chalk from 'chalk'
8
8
  import { RawAudio, applyGainDecibels, encodeRawAudioToWave, getEmptyRawAudio, getRawAudioDuration, normalizeAudioLevel, sliceRawAudioByTime } from '../audio/AudioUtilities.js'
9
- import { SubtitlesConfig, subtitlesToText, subtitlesToTimeline, timelineToSubtitles } from '../subtitles/Subtitles.js'
9
+ import { SubtitlesConfig, subtitlesToText, timelineToSubtitles } from '../subtitles/Subtitles.js'
10
10
  import { Logger, resetActiveLogger } from '../utilities/Logger.js'
11
11
  import { isMainThread, parentPort } from 'node:worker_threads'
12
12
  import { encodeFromChannels, getDefaultFFMpegOptionsForSpeech } from '../codecs/FFMpegTranscoder.js'
@@ -219,19 +219,25 @@ const help = [
219
219
  `${executableName} ${chalk.magentaBright('speak-url')} url [output files...] [options...]`,
220
220
  ` Speak the HTML document on the given URL\n`,
221
221
  `${executableName} ${chalk.magentaBright('speak-wikipedia')} articleName [output files...] [options...]`,
222
- ` Speak the given wikipedia article, language edition can be specified by --language=<langCode>\n`,
222
+ ` Speak the given Wikipedia article. Language edition can be specified by --language=<langCode>\n`,
223
223
  `${executableName} ${chalk.magentaBright('transcribe')} audioFile [output files...] [options...]`,
224
- ` Transcribe audio file\n`,
225
- `${executableName} ${chalk.magentaBright('align')} audioFile referenceFile [output files...] [options...]`,
226
- ` Align audio file to the reference transcript file\n`,
227
- `${executableName} ${chalk.magentaBright('translate-speech')} inputFile [output files...] [options...]`,
228
- ` Transcribe audio file directly to a different language\n`,
229
- `${executableName} ${chalk.magentaBright('align-translation')} audioFile referenceFile [output files...] [options...]`,
230
- ` Align audio file to the reference translated transcript file\n`,
231
- `${executableName} ${chalk.magentaBright('detect-speech-language')} audioFile [output files...] [options...]`,
232
- ` Detect language of audio file\n`,
224
+ ` Transcribe a spoken audio file\n`,
225
+ `${executableName} ${chalk.magentaBright('align')} audioFile transcriptFile [output files...] [options...]`,
226
+ ` Align spoken audio file to its transcript\n`,
227
+ `${executableName} ${chalk.magentaBright('translate-text')} inputFile [output files...] [options...]`,
228
+ ` Translate text to a different language\n`,
229
+ `${executableName} ${chalk.magentaBright('translate-speech')} audioFile [output files...] [options...]`,
230
+ ` Transcribe spoken audio file directly to a different language\n`,
231
+ `${executableName} ${chalk.magentaBright('align-translation')} audioFile translatedTranscriptFile [output files...] [options...]`,
232
+ ` Align spoken audio file to its translated transcript\n`,
233
+ `${executableName} ${chalk.magentaBright('align-transcript-and-translation')} audioFile transcriptFile translatedTranscriptFile [output files...] [options...]`,
234
+ ` Align spoken audio file to both its transcript and its translated transcript using a two-stage approach.\n`,
235
+ `${executableName} ${chalk.magentaBright('align-timeline-translation')} timelineFile translatedFile [output files...] [options...]`,
236
+ ` Align a given timeline file to its translated text\n`,
233
237
  `${executableName} ${chalk.magentaBright('detect-text-language')} inputFile [output files...] [options...]`,
234
238
  ` Detect language of textual file\n`,
239
+ `${executableName} ${chalk.magentaBright('detect-speech-language')} audioFile [output files...] [options...]`,
240
+ ` Detect language of spoken audio file\n`,
235
241
  `${executableName} ${chalk.magentaBright('detect-voice-activity')} audioFile [output files...] [options...]`,
236
242
  ` Detect voice activity in audio file\n`,
237
243
  `${executableName} ${chalk.magentaBright('denoise')} audioFile [output files...] [options...]`,
@@ -275,6 +281,11 @@ async function startWithArgs(operationData: CLIOperationData) {
275
281
  break
276
282
  }
277
283
 
284
+ case 'translate-text': {
285
+ await translateText(operationData)
286
+ break
287
+ }
288
+
278
289
  case 'translate-speech': {
279
290
  await translateSpeech(operationData)
280
291
  break
@@ -285,6 +296,16 @@ async function startWithArgs(operationData: CLIOperationData) {
285
296
  break
286
297
  }
287
298
 
299
+ case 'align-transcript-and-translation': {
300
+ await alignTranscriptAndTranslation(operationData)
301
+ break
302
+ }
303
+
304
+ case 'align-timeline-translation': {
305
+ await alignTimelineTranslation(operationData)
306
+ break
307
+ }
308
+
288
309
  case 'detect-language': {
289
310
  await detectLanguage(operationData, 'auto')
290
311
  break
@@ -352,7 +373,7 @@ async function startWithArgs(operationData: CLIOperationData) {
352
373
  }
353
374
  }
354
375
 
355
- async function speak(operationData: CLIOperationData) {
376
+ export async function speak(operationData: CLIOperationData) {
356
377
  const logger = new Logger()
357
378
 
358
379
  const { operationArgs, operation, operationOptionsLookup, cliOptions } = operationData
@@ -424,8 +445,8 @@ async function speak(operationData: CLIOperationData) {
424
445
  textSegments = splitToParagraphs(textContent, 'single', 'preserve')
425
446
  } else if (sourceFileExtension == 'srt' || sourceFileExtension == 'vtt') {
426
447
  const fileContent = await readFile(sourceFile, { encoding: 'utf-8' })
427
- textSegments = subtitlesToTimeline(fileContent).map(entry => entry.text)
428
- //textSegments = [subtitlesToText(fileContent)]
448
+ //textSegments = subtitlesToTimeline(fileContent).map(entry => entry.text)
449
+ textSegments = [subtitlesToText(fileContent)]
429
450
  } else if (sourceFileExtension == 'xml' || sourceFileExtension == 'ssml') {
430
451
  options.ssml = true
431
452
  textSegments = [fileContent]
@@ -510,7 +531,7 @@ async function speak(operationData: CLIOperationData) {
510
531
  logger.end()
511
532
  }
512
533
 
513
- async function transcribe(operationData: CLIOperationData) {
534
+ export async function transcribe(operationData: CLIOperationData) {
514
535
  const logger = new Logger()
515
536
 
516
537
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -572,7 +593,7 @@ async function transcribe(operationData: CLIOperationData) {
572
593
  }
573
594
  }
574
595
 
575
- async function align(operationData: CLIOperationData) {
596
+ export async function align(operationData: CLIOperationData) {
576
597
  const logger = new Logger()
577
598
 
578
599
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -668,7 +689,7 @@ async function align(operationData: CLIOperationData) {
668
689
  }
669
690
  }
670
691
 
671
- async function alignTranslation(operationData: CLIOperationData) {
692
+ export async function alignTranslation(operationData: CLIOperationData) {
672
693
  const logger = new Logger()
673
694
 
674
695
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -677,7 +698,7 @@ async function alignTranslation(operationData: CLIOperationData) {
677
698
  const outputFilenames = operationArgs.slice(2)
678
699
 
679
700
  if (audioFilename == undefined) {
680
- throw new Error(`align-translation requires an argument containing the audio file path.`)
701
+ throw new Error(`align-translation requires a first argument containing the audio file path.`)
681
702
  }
682
703
 
683
704
  if (!existsSync(audioFilename)) {
@@ -706,7 +727,7 @@ async function alignTranslation(operationData: CLIOperationData) {
706
727
  } else if (referenceFileExtension == 'srt' || referenceFileExtension == 'vtt') {
707
728
  text = subtitlesToText(fileContent)
708
729
  } else {
709
- throw new Error(`align only supports reference files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
730
+ throw new Error(`align-translation only supports reference files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
710
731
  }
711
732
 
712
733
  if (cliOptions.play == null) {
@@ -721,8 +742,9 @@ async function alignTranslation(operationData: CLIOperationData) {
721
742
  const {
722
743
  timeline,
723
744
  wordTimeline,
724
- transcript,
725
- language,
745
+ translatedTranscript,
746
+ sourceLanguage,
747
+ targetLanguage,
726
748
  inputRawAudio,
727
749
  isolatedRawAudio,
728
750
  backgroundRawAudio } = await API.alignTranslation(audioFilename, text, options)
@@ -737,10 +759,139 @@ async function alignTranslation(operationData: CLIOperationData) {
737
759
  const segmentAudio = sliceRawAudioByTime(inputRawAudio, segmentEntry.startTime, segmentEntry.endTime)
738
760
  const sentenceTimeline = addTimeOffsetToTimeline(segmentEntry.timeline!, -segmentEntry.startTime)
739
761
 
740
- await writeOutputFilesForSegment(outputFilenames, segmentIndex, timeline.length, segmentAudio, sentenceTimeline, segmentEntry.text, language, allowOverwrite)
762
+ await writeOutputFilesForSegment(outputFilenames, segmentIndex, timeline.length, segmentAudio, sentenceTimeline, segmentEntry.text, targetLanguage, allowOverwrite)
763
+ }
764
+ }
765
+
766
+ for (const outputFilename of outputFilenames) {
767
+ const partPatternMatch = outputFilename.match(filenamePlaceholderPattern)
768
+
769
+ if (partPatternMatch) {
770
+ continue
771
+ }
772
+
773
+ const fileSaver = getFileSaver(outputFilename, allowOverwrite)
774
+
775
+ await fileSaver(inputRawAudio, timeline, translatedTranscript, options.subtitles)
776
+
777
+ await writeSourceSeparationOutputIfNeeded(outputFilename, isolatedRawAudio, backgroundRawAudio, allowOverwrite, true)
778
+ }
779
+
780
+ logger.end()
781
+
782
+ if (cliOptions.play) {
783
+ let audioToPlay: RawAudio
784
+
785
+ if (isolatedRawAudio) {
786
+ audioToPlay = isolatedRawAudio
787
+ } else {
788
+ audioToPlay = inputRawAudio
789
+ }
790
+
791
+ const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
792
+
793
+ await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, translatedTranscript)
794
+ }
795
+ }
796
+
797
+ export async function alignTranscriptAndTranslation(operationData: CLIOperationData) {
798
+ const logger = new Logger()
799
+
800
+ const { operationArgs, operationOptionsLookup, cliOptions } = operationData
801
+
802
+ const audioFilename = operationArgs[0]
803
+ const outputFilenames = operationArgs.slice(3)
804
+
805
+ if (audioFilename == undefined) {
806
+ throw new Error(`align-transcript-and-translation requires a first argument containing the audio file path.`)
807
+ }
808
+
809
+ if (!existsSync(audioFilename)) {
810
+ throw new Error(`The given source file '${audioFilename}' was not found.`)
811
+ }
812
+
813
+ const nativeTranscriptFilePath = operationArgs[1]
814
+
815
+ if (nativeTranscriptFilePath == undefined) {
816
+ throw new Error(`align-transcript-and-translation requires a second argument containing the native language transcript file path.`)
817
+ }
818
+
819
+ if (!existsSync(nativeTranscriptFilePath)) {
820
+ throw new Error(`The given transcript file '${nativeTranscriptFilePath}' was not found.`)
821
+ }
822
+
823
+ const translatedTranscriptFilePath = operationArgs[2]
824
+
825
+ if (translatedTranscriptFilePath == undefined) {
826
+ throw new Error(`align-transcript-and-translation requires a third argument containing the translated language transcript file path.`)
827
+ }
828
+
829
+ if (!existsSync(translatedTranscriptFilePath)) {
830
+ throw new Error(`The given translated transcript file '${nativeTranscriptFilePath}' was not found.`)
831
+ }
832
+
833
+ let transcript: string
834
+
835
+ {
836
+ const nativeTranscriptFileExtension = getLowercaseFileExtension(nativeTranscriptFilePath)
837
+ const fileContent = await readFile(nativeTranscriptFilePath, { encoding: 'utf-8' })
838
+
839
+
840
+ if (nativeTranscriptFileExtension == 'txt') {
841
+ transcript = fileContent
842
+ } else if (nativeTranscriptFileExtension == 'html' || nativeTranscriptFileExtension == 'htm') {
843
+ transcript = await convertHtmlToText(fileContent)
844
+ } else if (nativeTranscriptFileExtension == 'srt' || nativeTranscriptFileExtension == 'vtt') {
845
+ transcript = subtitlesToText(fileContent)
846
+ } else {
847
+ throw new Error(`align-transcript-and-translation only supports transcript files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
848
+ }
849
+ }
850
+
851
+ let translatedTranscript: string
852
+
853
+ {
854
+ const translatedTranscriptFileExtension = getLowercaseFileExtension(translatedTranscriptFilePath)
855
+ const fileContent = await readFile(translatedTranscriptFilePath, { encoding: 'utf-8' })
856
+
857
+ if (translatedTranscriptFileExtension == 'txt') {
858
+ translatedTranscript = fileContent
859
+ } else if (translatedTranscriptFileExtension == 'html' || translatedTranscriptFileExtension == 'htm') {
860
+ translatedTranscript = await convertHtmlToText(fileContent)
861
+ } else if (translatedTranscriptFileExtension == 'srt' || translatedTranscriptFileExtension == 'vtt') {
862
+ translatedTranscript = subtitlesToText(fileContent)
863
+ } else {
864
+ throw new Error(`align-transcript-and-translation only supports transcript files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
741
865
  }
742
866
  }
743
867
 
868
+ if (cliOptions.play == null) {
869
+ cliOptions.play = outputFilenames.length === 0
870
+ }
871
+
872
+ const options = await optionsLookupToTypedObject(operationOptionsLookup, 'TranscriptAndTranslationAlignmentOptions')
873
+
874
+ const allowOverwrite = getWithDefault(cliOptions.overwrite, overwriteByDefault)
875
+ const { includesPlaceholderPattern } = await checkOutputFilenames(outputFilenames, true, true, true)
876
+
877
+ const {
878
+ timeline,
879
+ wordTimeline,
880
+
881
+ translatedTimeline,
882
+ translatedWordTimeline,
883
+
884
+ sourceLanguage,
885
+ targetLanguage,
886
+
887
+ inputRawAudio,
888
+ isolatedRawAudio,
889
+ backgroundRawAudio } = await API.alignTranscriptAndTranslation(audioFilename, transcript, translatedTranscript, options)
890
+
891
+ if (outputFilenames.length > 0) {
892
+ logger.start('\nWrite output files')
893
+ }
894
+
744
895
  for (const outputFilename of outputFilenames) {
745
896
  const partPatternMatch = outputFilename.match(filenamePlaceholderPattern)
746
897
 
@@ -753,6 +904,16 @@ async function alignTranslation(operationData: CLIOperationData) {
753
904
  await fileSaver(inputRawAudio, timeline, transcript, options.subtitles)
754
905
 
755
906
  await writeSourceSeparationOutputIfNeeded(outputFilename, isolatedRawAudio, backgroundRawAudio, allowOverwrite, true)
907
+
908
+ const fileExtension = getLowercaseFileExtension(outputFilename)
909
+
910
+ if (['json', 'txt', 'srt', 'vtt'].includes(fileExtension)) {
911
+ const pathWithoutExtension = outputFilename.substring(0, outputFilename.lastIndexOf('.'))
912
+ const translatedOutputPath = `${pathWithoutExtension}.translated.${fileExtension}`
913
+
914
+ const translatedFileSaver = getFileSaver(translatedOutputPath, allowOverwrite)
915
+ await translatedFileSaver(inputRawAudio, translatedTimeline, translatedTranscript, options.subtitles)
916
+ }
756
917
  }
757
918
 
758
919
  logger.end()
@@ -768,11 +929,168 @@ async function alignTranslation(operationData: CLIOperationData) {
768
929
 
769
930
  const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
770
931
 
771
- await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, transcript)
932
+ await playAudioWithWordTimeline(normalizedAudioToPlay, translatedWordTimeline, translatedTranscript)
772
933
  }
773
934
  }
774
935
 
775
- async function translateSpeech(operationData: CLIOperationData) {
936
+ export async function alignTimelineTranslation(operationData: CLIOperationData) {
937
+ const logger = new Logger()
938
+
939
+ const { operationArgs, operationOptionsLookup, cliOptions } = operationData
940
+
941
+ const timelineFilename = operationArgs[0]
942
+ const outputFilenames = operationArgs.slice(2)
943
+
944
+ if (timelineFilename == undefined) {
945
+ throw new Error(`align-timeline-translation requires a first argument containing the timeline file path.`)
946
+ }
947
+
948
+ if (getLowercaseFileExtension(timelineFilename) != 'json') {
949
+ throw new Error(`align-timeline-translation only supports timeline files with extension 'json'`)
950
+ }
951
+
952
+ if (!existsSync(timelineFilename)) {
953
+ throw new Error(`The given timeline file '${timelineFilename}' was not found.`)
954
+ }
955
+
956
+ const timeline = await readAndParseJsonFile(timelineFilename) as Timeline
957
+
958
+ const translationFilePath = operationArgs[1]
959
+
960
+ if (translationFilePath == undefined) {
961
+ throw new Error(`align-timeline-translation requires a second argument containing the translated reference file path.`)
962
+ }
963
+
964
+ if (!existsSync(translationFilePath)) {
965
+ throw new Error(`The given reference file '${translationFilePath}' was not found.`)
966
+ }
967
+
968
+ const translationFileExtension = getLowercaseFileExtension(translationFilePath)
969
+ const translationFileContent = await readFile(translationFilePath, { encoding: 'utf-8' })
970
+
971
+ let translationText: string
972
+
973
+ if (translationFileExtension == 'txt') {
974
+ translationText = translationFileContent
975
+ } else if (translationFileExtension == 'html' || translationFileExtension == 'htm') {
976
+ translationText = await convertHtmlToText(translationFileContent)
977
+ } else if (translationFileExtension == 'srt' || translationFileExtension == 'vtt') {
978
+ translationText = subtitlesToText(translationFileContent)
979
+ } else {
980
+ throw new Error(`align only supports reference files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
981
+ }
982
+
983
+ const options = await optionsLookupToTypedObject(operationOptionsLookup, 'TimelineTranslationAlignmentOptions')
984
+
985
+ const {
986
+ timeline: translationTimeline,
987
+ wordTimeline: translationWordTimeline,
988
+ rawAudio
989
+ } = await API.alignTimelineTranslation(timeline, translationText, options)
990
+
991
+ if (outputFilenames.length > 0) {
992
+ logger.start('\nWrite output files')
993
+ }
994
+
995
+ const allowOverwrite = getWithDefault(cliOptions.overwrite, overwriteByDefault)
996
+
997
+ for (const outputFilename of outputFilenames) {
998
+ const partPatternMatch = outputFilename.match(filenamePlaceholderPattern)
999
+
1000
+ if (partPatternMatch) {
1001
+ continue
1002
+ }
1003
+
1004
+ const fileSaver = getFileSaver(outputFilename, allowOverwrite)
1005
+
1006
+ await fileSaver(getEmptyRawAudio(1, 16000), translationTimeline, translationText, options.subtitles)
1007
+ }
1008
+
1009
+ logger.end()
1010
+
1011
+ if (cliOptions.play && rawAudio) {
1012
+ const normalizedAudioToPlay = normalizeAudioLevel(rawAudio)
1013
+
1014
+ let transcriptToPlay: string
1015
+ let timelineToPlay: Timeline
1016
+
1017
+ transcriptToPlay = translationText
1018
+ timelineToPlay = translationWordTimeline
1019
+
1020
+ await playAudioWithWordTimeline(normalizedAudioToPlay, timelineToPlay, transcriptToPlay)
1021
+ }
1022
+ }
1023
+
1024
+ export async function translateText(operationData: CLIOperationData) {
1025
+ const logger = new Logger()
1026
+
1027
+ const { operationArgs, operationOptionsLookup, cliOptions } = operationData
1028
+
1029
+ const inputFilename = operationArgs[0]
1030
+ const outputFilenames = operationArgs.slice(1)
1031
+
1032
+ if (inputFilename == undefined) {
1033
+ throw new Error(`translate-text requires an argument containing the input file path.`)
1034
+ }
1035
+
1036
+ if (!existsSync(inputFilename)) {
1037
+ throw new Error(`The given input file '${inputFilename}' was not found.`)
1038
+ }
1039
+
1040
+ const inputFileExtension = getLowercaseFileExtension(inputFilename)
1041
+ const inputFileContent = await readFile(inputFilename, { encoding: 'utf-8' })
1042
+
1043
+ let inputText: string
1044
+
1045
+ if (inputFileExtension === 'txt') {
1046
+ inputText = inputFileContent
1047
+ } else if (inputFileExtension === 'html' || inputFileExtension === 'htm') {
1048
+ inputText = await convertHtmlToText(inputFileContent)
1049
+ } else if (inputFileExtension == 'srt' || inputFileExtension == 'vtt') {
1050
+ inputText = subtitlesToText(inputFileContent)
1051
+ } else {
1052
+ throw new Error(`align only supports reference files with extensions 'txt', 'html', 'htm', 'srt' or 'vtt'`)
1053
+ }
1054
+
1055
+ const options = await optionsLookupToTypedObject(operationOptionsLookup, 'TextTranslationOptions')
1056
+
1057
+ const allowOverwrite = getWithDefault(cliOptions.overwrite, overwriteByDefault)
1058
+
1059
+ await checkOutputFilenames(outputFilenames, false, true, true)
1060
+
1061
+ const {
1062
+ text,
1063
+ translatedText,
1064
+
1065
+ translationPairs,
1066
+
1067
+ sourceLanguage,
1068
+ targetLanguage,
1069
+ } = await API.translateText(inputFileContent, options)
1070
+
1071
+ if (outputFilenames.length > 0) {
1072
+ logger.start('\nWrite output files')
1073
+
1074
+ for (const outputFilename of outputFilenames) {
1075
+ const partPatternMatch = outputFilename.match(filenamePlaceholderPattern)
1076
+
1077
+ if (partPatternMatch) {
1078
+ continue
1079
+ }
1080
+
1081
+ const fileSaver = getFileSaver(outputFilename, allowOverwrite)
1082
+
1083
+ await fileSaver(getEmptyRawAudio(1, 16000), translationPairs as any as Timeline, translatedText, undefined)
1084
+ }
1085
+
1086
+ logger.end()
1087
+ } else {
1088
+ logger.log(``)
1089
+ logger.log(translatedText)
1090
+ }
1091
+ }
1092
+
1093
+ export async function translateSpeech(operationData: CLIOperationData) {
776
1094
  const logger = new Logger()
777
1095
 
778
1096
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -798,7 +1116,19 @@ async function translateSpeech(operationData: CLIOperationData) {
798
1116
 
799
1117
  await checkOutputFilenames(outputFilenames, true, true, true)
800
1118
 
801
- const { transcript, timeline, wordTimeline, sourceLanguage, targetLanguage, inputRawAudio, isolatedRawAudio, backgroundRawAudio } = await API.translateSpeech(inputFilename, options)
1119
+ const {
1120
+ transcript,
1121
+
1122
+ timeline,
1123
+ wordTimeline,
1124
+
1125
+ sourceLanguage,
1126
+ targetLanguage,
1127
+
1128
+ inputRawAudio,
1129
+ isolatedRawAudio,
1130
+ backgroundRawAudio
1131
+ } = await API.translateSpeech(inputFilename, options)
802
1132
 
803
1133
  if (outputFilenames.length > 0) {
804
1134
  logger.start('\nWrite output files')
@@ -859,7 +1189,7 @@ async function translateSpeech(operationData: CLIOperationData) {
859
1189
  }
860
1190
  }
861
1191
 
862
- async function detectLanguage(operationData: CLIOperationData, mode: 'speech' | 'text' | 'auto') {
1192
+ export async function detectLanguage(operationData: CLIOperationData, mode: 'speech' | 'text' | 'auto') {
863
1193
  const logger = new Logger()
864
1194
 
865
1195
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -936,7 +1266,7 @@ async function detectLanguage(operationData: CLIOperationData, mode: 'speech' |
936
1266
  logger.end()
937
1267
  }
938
1268
 
939
- async function detectVoiceActivity(operationData: CLIOperationData) {
1269
+ export async function detectVoiceActivity(operationData: CLIOperationData) {
940
1270
  const logger = new Logger()
941
1271
 
942
1272
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -1005,7 +1335,7 @@ async function detectVoiceActivity(operationData: CLIOperationData) {
1005
1335
  }
1006
1336
  }
1007
1337
 
1008
- async function denoise(operationData: CLIOperationData) {
1338
+ export async function denoise(operationData: CLIOperationData) {
1009
1339
  const logger = new Logger()
1010
1340
 
1011
1341
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -1050,7 +1380,7 @@ async function denoise(operationData: CLIOperationData) {
1050
1380
  }
1051
1381
  }
1052
1382
 
1053
- async function isolate(operationData: CLIOperationData) {
1383
+ export async function isolate(operationData: CLIOperationData) {
1054
1384
  const logger = new Logger()
1055
1385
 
1056
1386
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -1093,7 +1423,7 @@ async function isolate(operationData: CLIOperationData) {
1093
1423
  }
1094
1424
  }
1095
1425
 
1096
- async function listEngines(operationData: CLIOperationData) {
1426
+ export async function listEngines(operationData: CLIOperationData) {
1097
1427
  const logger = new Logger()
1098
1428
 
1099
1429
  const { operationArgs } = operationData
@@ -1140,6 +1470,12 @@ async function listEngines(operationData: CLIOperationData) {
1140
1470
  break
1141
1471
  }
1142
1472
 
1473
+ case 'translate-text': {
1474
+ engines = API.textTranslationEngines
1475
+
1476
+ break
1477
+ }
1478
+
1143
1479
  case 'translate-speech': {
1144
1480
  engines = API.speechTranslationEngines
1145
1481
 
@@ -1190,7 +1526,7 @@ async function listEngines(operationData: CLIOperationData) {
1190
1526
  }
1191
1527
 
1192
1528
  default: {
1193
- throw new Error(`Unrecognized operation: '${targetOperation}'`)
1529
+ throw new Error(`Unrecognized operation name: '${targetOperation}'`)
1194
1530
  }
1195
1531
  }
1196
1532
 
@@ -1206,7 +1542,7 @@ async function listEngines(operationData: CLIOperationData) {
1206
1542
  }
1207
1543
  }
1208
1544
 
1209
- async function listTTSVoices(operationData: CLIOperationData) {
1545
+ export async function listTTSVoices(operationData: CLIOperationData) {
1210
1546
  const logger = new Logger()
1211
1547
 
1212
1548
  const { operationArgs, operationOptionsLookup, cliOptions } = operationData
@@ -1268,7 +1604,7 @@ async function listTTSVoices(operationData: CLIOperationData) {
1268
1604
  logger.end()
1269
1605
  }
1270
1606
 
1271
- async function installPackages(operationData: CLIOperationData) {
1607
+ export async function installPackages(operationData: CLIOperationData) {
1272
1608
  const logger = new Logger()
1273
1609
 
1274
1610
  const { operationArgs } = operationData
@@ -1299,7 +1635,7 @@ async function installPackages(operationData: CLIOperationData) {
1299
1635
  }
1300
1636
  }
1301
1637
 
1302
- async function uninstallPackages(operationData: CLIOperationData) {
1638
+ export async function uninstallPackages(operationData: CLIOperationData) {
1303
1639
  const logger = new Logger()
1304
1640
 
1305
1641
  const { operationArgs } = operationData
@@ -1326,7 +1662,7 @@ async function uninstallPackages(operationData: CLIOperationData) {
1326
1662
  }
1327
1663
  }
1328
1664
 
1329
- async function listPackages(operationData: CLIOperationData) {
1665
+ export async function listPackages(operationData: CLIOperationData) {
1330
1666
  const logger = new Logger()
1331
1667
 
1332
1668
  const packagesDir = await ensureAndGetPackagesDir()
@@ -1358,7 +1694,7 @@ async function listPackages(operationData: CLIOperationData) {
1358
1694
  logger.log(installedPackageNamesFormatted.join('\n'))
1359
1695
  }
1360
1696
 
1361
- async function serve(operationData: CLIOperationData) {
1697
+ export async function serve(operationData: CLIOperationData) {
1362
1698
  const { operationOptionsLookup } = operationData
1363
1699
 
1364
1700
  const options = await optionsLookupToTypedObject(operationOptionsLookup, 'ServerOptions')
@@ -1500,7 +1836,7 @@ async function optionsLookupToTypedObject<K extends keyof APIOptions>(cliOptions
1500
1836
  }
1501
1837
 
1502
1838
  let cachedOptionsSchema: any
1503
- export async function getOptionsSchema() {
1839
+ async function getOptionsSchema() {
1504
1840
  if (!cachedOptionsSchema) {
1505
1841
  cachedOptionsSchema = await readAndParseJsonFile(resolveToModuleRootDir('data/schemas/options.json'))
1506
1842
  }
@@ -1508,7 +1844,7 @@ export async function getOptionsSchema() {
1508
1844
  return cachedOptionsSchema
1509
1845
  }
1510
1846
 
1511
- export async function checkOutputFilenames(outputFilenames: string[], acceptMediaOutputs: boolean, acceptMetadataOutputs: boolean, acceptSubtitleOutputs: boolean) {
1847
+ async function checkOutputFilenames(outputFilenames: string[], acceptMediaOutputs: boolean, acceptMetadataOutputs: boolean, acceptSubtitleOutputs: boolean) {
1512
1848
  const supportedFileExtensions: string[] = []
1513
1849
 
1514
1850
  if (acceptMediaOutputs) {
@@ -1562,7 +1898,7 @@ export async function checkOutputFilenames(outputFilenames: string[], acceptMedi
1562
1898
  return { includesPlaceholderPattern }
1563
1899
  }
1564
1900
 
1565
- export async function writeOutputFilesForSegment(outputFilenames: string[], index: number, total: number, audio: RawAudio, timeline: Timeline, text: string, language: string, allowOverwrite: boolean) {
1901
+ async function writeOutputFilesForSegment(outputFilenames: string[], index: number, total: number, audio: RawAudio, timeline: Timeline, text: string, language: string, allowOverwrite: boolean) {
1566
1902
  const digitCount = Math.max((total + 1).toString().length, 2)
1567
1903
 
1568
1904
  const segmentWords = (await splitToWords(text, language)).filter(text => wordCharacterPattern.test(text))
@@ -7,6 +7,7 @@ import { commandExists, logToStderr } from '../utilities/Utilities.js'
7
7
  import path from 'node:path'
8
8
  import { loadPackage } from '../utilities/PackageManager.js'
9
9
  import { getGlobalOption } from '../api/GlobalOptions.js'
10
+ import { existsSync } from '../utilities/FileSystem.js'
10
11
 
11
12
  const log = logToStderr
12
13
 
@@ -67,6 +68,11 @@ async function transcode_CLI(ffmpegCommand: string, input: string | Buffer, outp
67
68
 
68
69
  if (Buffer.isBuffer(input)) {
69
70
  process.stdin.end(input)
71
+ } else if (typeof input === 'string') {
72
+ if (!existsSync(input)) {
73
+ reject(`Audio file was not found: ${input}`)
74
+ return
75
+ }
70
76
  }
71
77
 
72
78
  const stdoutChunks: Buffer[] = []
package/src/dsp/FFT.ts CHANGED
@@ -48,7 +48,7 @@ export async function stftr(samples: Float32Array, fftOrder: number, windowSize:
48
48
  }
49
49
 
50
50
  binsBufferRef.clear()
51
-
51
+
52
52
  m._kiss_fftr(statePtr, frameBufferRef.address, binsBufferRef.address)
53
53
 
54
54
  const bins = binsBufferRef.view.slice(0, fftOrder + 2)
@@ -229,6 +229,12 @@ export function getWindowWeights(windowType: WindowType, windowSize: number) {
229
229
  //weights[i] = 0.54 - (0.46 * Math.cos(2 * Math.PI * (i / (windowSize - 1))))
230
230
  weights[i] = 0.54 - (0.46 * Math.cos(innerFactor * i))
231
231
  }
232
+ } else if (windowType == 'povey') {
233
+ const hannWeights = getWindowWeights('hann', windowSize)
234
+
235
+ for (let i = 0; i < windowSize; i++) {
236
+ weights[i] = hannWeights[i] ** 0.85
237
+ }
232
238
  } else {
233
239
  throw new Error(`Unsupported window function type: ${windowType}`)
234
240
  }
@@ -255,4 +261,4 @@ export async function testFFT1(rawAudio: RawAudio) {
255
261
  return recoveredRawAudio
256
262
  }
257
263
 
258
- export type WindowType = 'hann' | 'hamming'
264
+ export type WindowType = 'hann' | 'hamming' | 'povey'