echogarden 0.12.2 → 1.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 (334) hide show
  1. package/README.md +15 -14
  2. package/data/schemas/options.json +398 -111
  3. package/dist/alignment/DTWMfccSequenceAlignment.d.ts +1 -1
  4. package/dist/alignment/DTWMfccSequenceAlignment.js +8 -8
  5. package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
  6. package/dist/alignment/DTWSequenceAlignment.js +1 -1
  7. package/dist/alignment/DTWSequenceAlignmentWindowed.d.ts +1 -1
  8. package/dist/alignment/DTWSequenceAlignmentWindowed.js +2 -2
  9. package/dist/alignment/LevenshteinSequenceAlignment.d.ts +1 -1
  10. package/dist/alignment/LevenshteinSequenceAlignment.js +1 -1
  11. package/dist/alignment/SpeechAlignment.d.ts +9 -10
  12. package/dist/alignment/SpeechAlignment.js +136 -105
  13. package/dist/alignment/SpeechAlignment.js.map +1 -1
  14. package/dist/api/API.d.ts +13 -12
  15. package/dist/api/API.js +14 -13
  16. package/dist/api/API.js.map +1 -1
  17. package/dist/api/APIOptions.d.ts +5 -4
  18. package/dist/api/Alignment.d.ts +15 -9
  19. package/dist/api/Alignment.js +88 -74
  20. package/dist/api/Alignment.js.map +1 -1
  21. package/dist/api/Common.js +1 -1
  22. package/dist/api/Denoising.d.ts +6 -6
  23. package/dist/api/Denoising.js +23 -23
  24. package/dist/api/Denoising.js.map +1 -1
  25. package/dist/api/LanguageDetection.d.ts +19 -12
  26. package/dist/api/LanguageDetection.js +88 -38
  27. package/dist/api/LanguageDetection.js.map +1 -1
  28. package/dist/api/Recognition.d.ts +16 -6
  29. package/dist/api/Recognition.js +129 -55
  30. package/dist/api/Recognition.js.map +1 -1
  31. package/dist/api/SourceSeparation.d.ts +17 -0
  32. package/dist/api/SourceSeparation.js +61 -0
  33. package/dist/api/SourceSeparation.js.map +1 -0
  34. package/dist/api/Synthesis.d.ts +18 -18
  35. package/dist/api/Synthesis.js +191 -164
  36. package/dist/api/Synthesis.js.map +1 -1
  37. package/dist/api/Translation.d.ts +19 -8
  38. package/dist/api/Translation.js +132 -35
  39. package/dist/api/Translation.js.map +1 -1
  40. package/dist/api/Vad.d.ts +10 -5
  41. package/dist/api/Vad.js +76 -38
  42. package/dist/api/Vad.js.map +1 -1
  43. package/dist/audio/AudioBufferConversion.d.ts +1 -1
  44. package/dist/audio/AudioBufferConversion.js +4 -4
  45. package/dist/audio/AudioPlayer.d.ts +1 -1
  46. package/dist/audio/AudioPlayer.js +26 -26
  47. package/dist/audio/AudioPlayer.js.map +1 -1
  48. package/dist/audio/AudioRecorder.d.ts +1 -1
  49. package/dist/audio/AudioRecorder.js +5 -5
  50. package/dist/audio/AudioUtilities.d.ts +13 -9
  51. package/dist/audio/AudioUtilities.js +86 -24
  52. package/dist/audio/AudioUtilities.js.map +1 -1
  53. package/dist/cli/CLI.d.ts +3 -3
  54. package/dist/cli/CLI.js +271 -162
  55. package/dist/cli/CLI.js.map +1 -1
  56. package/dist/cli/CLIConfigFile.js +8 -8
  57. package/dist/cli/CLILauncher.js +6 -6
  58. package/dist/cli/CLIOptionsSchema.js +2 -2
  59. package/dist/cli/CLIParser.js +5 -5
  60. package/dist/cli/CLIStarter.js +4 -4
  61. package/dist/codecs/FFMpegTranscoder.d.ts +2 -2
  62. package/dist/codecs/FFMpegTranscoder.js +37 -37
  63. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  64. package/dist/codecs/TIMITCodec.js +5 -5
  65. package/dist/codecs/WaveCodec.d.ts +1 -1
  66. package/dist/codecs/WaveCodec.js +22 -22
  67. package/dist/denoising/RNNoise.d.ts +1 -1
  68. package/dist/denoising/RNNoise.js +9 -9
  69. package/dist/dsp/BiquadFilter.d.ts +3 -2
  70. package/dist/dsp/BiquadFilter.js +18 -11
  71. package/dist/dsp/BiquadFilter.js.map +1 -1
  72. package/dist/dsp/DecayingPeakEstimator.d.ts +16 -0
  73. package/dist/dsp/DecayingPeakEstimator.js +23 -0
  74. package/dist/dsp/DecayingPeakEstimator.js.map +1 -0
  75. package/dist/dsp/FFT.d.ts +8 -4
  76. package/dist/dsp/FFT.js +76 -30
  77. package/dist/dsp/FFT.js.map +1 -1
  78. package/dist/dsp/KWeightingFilter.d.ts +9 -0
  79. package/dist/dsp/KWeightingFilter.js +40 -0
  80. package/dist/dsp/KWeightingFilter.js.map +1 -0
  81. package/dist/dsp/LoudnessEstimator.d.ts +21 -0
  82. package/dist/dsp/LoudnessEstimator.js +47 -0
  83. package/dist/dsp/LoudnessEstimator.js.map +1 -0
  84. package/dist/dsp/MFCC.d.ts +2 -2
  85. package/dist/dsp/MFCC.js +15 -15
  86. package/dist/dsp/MelSpectogram.d.ts +1 -1
  87. package/dist/dsp/MelSpectogram.js +6 -6
  88. package/dist/dsp/Rubberband.d.ts +11 -11
  89. package/dist/dsp/Rubberband.js +27 -27
  90. package/dist/dsp/Sonic.d.ts +1 -1
  91. package/dist/dsp/Sonic.js +3 -3
  92. package/dist/dsp/SpeexResampler.d.ts +1 -1
  93. package/dist/dsp/SpeexResampler.js +2 -2
  94. package/dist/math/VectorMath.d.ts +12 -8
  95. package/dist/math/VectorMath.js +35 -32
  96. package/dist/math/VectorMath.js.map +1 -1
  97. package/dist/nlp/ChineseSegmentation.js +2 -2
  98. package/dist/nlp/CompromiseNLP.js +3 -3
  99. package/dist/nlp/EspeakPhonemizer.js +30 -30
  100. package/dist/nlp/IPA.js +20 -20
  101. package/dist/nlp/JapaneseSegmentation.js +6 -6
  102. package/dist/nlp/Lexicon.d.ts +1 -1
  103. package/dist/nlp/Lexicon.js +7 -7
  104. package/dist/nlp/Segmentation.d.ts +3 -0
  105. package/dist/nlp/Segmentation.js +21 -14
  106. package/dist/nlp/Segmentation.js.map +1 -1
  107. package/dist/nlp/TextNormalizer.js +16 -16
  108. package/dist/recognition/AmazonTranscribeSTT.d.ts +2 -2
  109. package/dist/recognition/AmazonTranscribeSTT.js +13 -14
  110. package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
  111. package/dist/recognition/AzureCognitiveServicesSTT.js +5 -6
  112. package/dist/recognition/AzureCognitiveServicesSTT.js.map +1 -1
  113. package/dist/recognition/GoogleCloudSTT.d.ts +3 -3
  114. package/dist/recognition/GoogleCloudSTT.js +18 -18
  115. package/dist/recognition/OpenAICloudSTT.d.ts +19 -0
  116. package/dist/recognition/OpenAICloudSTT.js +81 -0
  117. package/dist/recognition/OpenAICloudSTT.js.map +1 -0
  118. package/dist/recognition/SileroSTT.d.ts +2 -2
  119. package/dist/recognition/SileroSTT.js +25 -25
  120. package/dist/recognition/VoskSTT.d.ts +2 -2
  121. package/dist/recognition/VoskSTT.js +8 -8
  122. package/dist/recognition/WhisperCppSTT.d.ts +88 -0
  123. package/dist/recognition/WhisperCppSTT.js +332 -0
  124. package/dist/recognition/WhisperCppSTT.js.map +1 -0
  125. package/dist/recognition/WhisperSTT.d.ts +49 -25
  126. package/dist/recognition/WhisperSTT.js +626 -481
  127. package/dist/recognition/WhisperSTT.js.map +1 -1
  128. package/dist/server/Client.d.ts +1 -1
  129. package/dist/server/Client.js +22 -22
  130. package/dist/server/Server.js +9 -9
  131. package/dist/server/Server.js.map +1 -1
  132. package/dist/server/Worker.d.ts +22 -22
  133. package/dist/server/Worker.js +36 -36
  134. package/dist/server/Worker.js.map +1 -1
  135. package/dist/server/WorkerStarter.js +2 -2
  136. package/dist/source-separation/MDXNetSourceSeparation.d.ts +11 -0
  137. package/dist/source-separation/MDXNetSourceSeparation.js +161 -0
  138. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -0
  139. package/dist/speech-language-detection/SileroLanguageDetection.d.ts +1 -1
  140. package/dist/speech-language-detection/SileroLanguageDetection.js +7 -7
  141. package/dist/subtitles/Subtitles.d.ts +10 -0
  142. package/dist/subtitles/Subtitles.js +2 -2
  143. package/dist/subtitles/Subtitles.js.map +1 -1
  144. package/dist/synthesis/AwsPollyTTS.d.ts +1 -1
  145. package/dist/synthesis/AwsPollyTTS.js +12 -12
  146. package/dist/synthesis/AzureCognitiveServicesTTS.js +7 -7
  147. package/dist/synthesis/CoquiServerTTS.js +10 -10
  148. package/dist/synthesis/CoquiServerTTS.js.map +1 -1
  149. package/dist/synthesis/ElevenlabsTTS.d.ts +23 -0
  150. package/dist/synthesis/ElevenlabsTTS.js +103 -0
  151. package/dist/synthesis/ElevenlabsTTS.js.map +1 -0
  152. package/dist/synthesis/EspeakTTS.d.ts +6 -5
  153. package/dist/synthesis/EspeakTTS.js +81 -69
  154. package/dist/synthesis/EspeakTTS.js.map +1 -1
  155. package/dist/synthesis/FliteTTS.d.ts +3 -3
  156. package/dist/synthesis/FliteTTS.js +154 -154
  157. package/dist/synthesis/FliteTTS.js.map +1 -1
  158. package/dist/synthesis/GoogleCloudTTS.d.ts +3 -3
  159. package/dist/synthesis/GoogleCloudTTS.js +17 -17
  160. package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
  161. package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
  162. package/dist/synthesis/GoogleTranslateTTS.js +103 -103
  163. package/dist/synthesis/MicrosoftEdgeTTS.d.ts +2 -2
  164. package/dist/synthesis/MicrosoftEdgeTTS.js +74 -74
  165. package/dist/synthesis/OpenAICloudTTS.d.ts +13 -0
  166. package/dist/synthesis/OpenAICloudTTS.js +169 -0
  167. package/dist/synthesis/OpenAICloudTTS.js.map +1 -0
  168. package/dist/synthesis/SamTTS.js +3 -3
  169. package/dist/synthesis/SapiTTS.d.ts +3 -3
  170. package/dist/synthesis/SapiTTS.js +26 -26
  171. package/dist/synthesis/StreamlabsPollyTTS.d.ts +2 -2
  172. package/dist/synthesis/StreamlabsPollyTTS.js +27 -27
  173. package/dist/synthesis/SvoxPicoTTS.d.ts +2 -2
  174. package/dist/synthesis/SvoxPicoTTS.js +65 -65
  175. package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
  176. package/dist/synthesis/VitsTTS.d.ts +3 -3
  177. package/dist/synthesis/VitsTTS.js +378 -378
  178. package/dist/synthesis/VitsTTS.js.map +1 -1
  179. package/dist/tests/Test.js +2 -2
  180. package/dist/utilities/Compression.d.ts +5 -0
  181. package/dist/utilities/Compression.js +29 -13
  182. package/dist/utilities/Compression.js.map +1 -1
  183. package/dist/utilities/FileDownloader.d.ts +1 -1
  184. package/dist/utilities/FileDownloader.js +16 -16
  185. package/dist/utilities/FileSystem.js +7 -7
  186. package/dist/utilities/Locale.d.ts +7 -7
  187. package/dist/utilities/Locale.js +15 -15
  188. package/dist/utilities/Logger.js +3 -3
  189. package/dist/utilities/ObjectUtilities.js +19 -19
  190. package/dist/utilities/OpenPromise.js +2 -2
  191. package/dist/utilities/OpenPromise.js.map +1 -1
  192. package/dist/utilities/PackageManager.js +31 -0
  193. package/dist/utilities/PackageManager.js.map +1 -1
  194. package/dist/utilities/PathUtilities.js +8 -8
  195. package/dist/utilities/RandomGenerator.js +2 -2
  196. package/dist/utilities/SmoothEstimator.d.ts +8 -0
  197. package/dist/utilities/SmoothEstimator.js +25 -0
  198. package/dist/utilities/SmoothEstimator.js.map +1 -0
  199. package/dist/utilities/TarballMaker.js +8 -8
  200. package/dist/utilities/Timeline.d.ts +3 -2
  201. package/dist/utilities/Timeline.js +11 -11
  202. package/dist/utilities/Timeline.js.map +1 -1
  203. package/dist/utilities/Timer.js +4 -4
  204. package/dist/utilities/Utilities.d.ts +4 -0
  205. package/dist/utilities/Utilities.js +38 -15
  206. package/dist/utilities/Utilities.js.map +1 -1
  207. package/dist/utilities/WasmMemoryManager.js +7 -7
  208. package/dist/utilities/WebReader.js +23 -23
  209. package/dist/utilities/WikipediaReader.js +2 -2
  210. package/dist/voice-activity-detection/AdaptiveGateVAD.d.ts +28 -0
  211. package/dist/voice-activity-detection/AdaptiveGateVAD.js +138 -0
  212. package/dist/voice-activity-detection/AdaptiveGateVAD.js.map +1 -0
  213. package/dist/voice-activity-detection/SileroVAD.d.ts +1 -1
  214. package/dist/voice-activity-detection/SileroVAD.js +5 -5
  215. package/dist/voice-activity-detection/SileroVAD.js.map +1 -1
  216. package/dist/voice-activity-detection/WebRtcVAD.d.ts +1 -1
  217. package/dist/voice-activity-detection/WebRtcVAD.js +4 -4
  218. package/docs/API.md +29 -11
  219. package/docs/CLI.md +31 -7
  220. package/docs/Contributing.md +38 -0
  221. package/docs/Development.md +93 -19
  222. package/docs/Engines.md +28 -16
  223. package/docs/Licenses.md +4 -1
  224. package/docs/Options.md +158 -78
  225. package/docs/Releases.md +262 -0
  226. package/docs/Server.md +7 -7
  227. package/docs/Tasklist.md +95 -76
  228. package/docs/Technical.md +4 -4
  229. package/package.json +13 -14
  230. package/src/alignment/DTWMfccSequenceAlignment.ts +9 -9
  231. package/src/alignment/DTWSequenceAlignment.ts +2 -2
  232. package/src/alignment/DTWSequenceAlignmentWindowed.ts +3 -3
  233. package/src/alignment/LevenshteinSequenceAlignment.ts +2 -2
  234. package/src/alignment/SpeechAlignment.ts +204 -119
  235. package/src/api/API.ts +14 -13
  236. package/src/api/APIOptions.ts +12 -11
  237. package/src/api/Alignment.ts +147 -90
  238. package/src/api/Common.ts +1 -1
  239. package/src/api/Denoising.ts +28 -28
  240. package/src/api/LanguageDetection.ts +135 -48
  241. package/src/api/Recognition.ts +198 -59
  242. package/src/api/SourceSeparation.ts +99 -0
  243. package/src/api/Synthesis.ts +217 -181
  244. package/src/api/Translation.ts +193 -40
  245. package/src/api/Vad.ts +110 -41
  246. package/src/audio/AudioBufferConversion.ts +4 -4
  247. package/src/audio/AudioPlayer.ts +27 -27
  248. package/src/audio/AudioRecorder.ts +5 -5
  249. package/src/audio/AudioUtilities.ts +107 -24
  250. package/src/cli/CLI.ts +313 -164
  251. package/src/cli/CLIConfigFile.ts +8 -8
  252. package/src/cli/CLILauncher.ts +6 -6
  253. package/src/cli/CLIOptionsSchema.ts +2 -2
  254. package/src/cli/CLIParser.ts +5 -5
  255. package/src/cli/CLIStarter.ts +4 -4
  256. package/src/codecs/FFMpegTranscoder.ts +38 -38
  257. package/src/codecs/TIMITCodec.ts +5 -5
  258. package/src/codecs/WaveCodec.ts +22 -22
  259. package/src/denoising/RNNoise.ts +9 -9
  260. package/src/dsp/BiquadFilter.ts +19 -11
  261. package/src/dsp/DecayingPeakEstimator.ts +35 -0
  262. package/src/dsp/FFT.ts +103 -35
  263. package/src/dsp/KWeightingFilter.ts +43 -0
  264. package/src/dsp/LoudnessEstimator.ts +74 -0
  265. package/src/dsp/MFCC.ts +15 -15
  266. package/src/dsp/MelSpectogram.ts +7 -7
  267. package/src/dsp/Rubberband.ts +38 -38
  268. package/src/dsp/Sonic.ts +4 -4
  269. package/src/dsp/SpeexResampler.ts +2 -2
  270. package/src/math/VectorMath.ts +42 -33
  271. package/src/nlp/ChineseSegmentation.ts +3 -3
  272. package/src/nlp/CompromiseNLP.ts +3 -3
  273. package/src/nlp/EspeakPhonemizer.ts +30 -30
  274. package/src/nlp/IPA.ts +20 -20
  275. package/src/nlp/JapaneseSegmentation.ts +6 -6
  276. package/src/nlp/Lexicon.ts +8 -8
  277. package/src/nlp/Segmentation.ts +23 -14
  278. package/src/nlp/TextNormalizer.ts +16 -16
  279. package/src/recognition/AmazonTranscribeSTT.ts +16 -17
  280. package/src/recognition/AzureCognitiveServicesSTT.ts +8 -6
  281. package/src/recognition/GoogleCloudSTT.ts +21 -21
  282. package/src/recognition/OpenAICloudSTT.ts +142 -0
  283. package/src/recognition/SileroSTT.ts +26 -26
  284. package/src/recognition/VoskSTT.ts +10 -10
  285. package/src/recognition/WhisperCppSTT.ts +555 -0
  286. package/src/recognition/WhisperSTT.ts +760 -507
  287. package/src/server/Client.ts +23 -23
  288. package/src/server/Server.ts +9 -9
  289. package/src/server/Worker.ts +53 -53
  290. package/src/server/WorkerStarter.ts +2 -2
  291. package/src/source-separation/MDXNetSourceSeparation.ts +228 -0
  292. package/src/speech-language-detection/SileroLanguageDetection.ts +8 -8
  293. package/src/subtitles/Subtitles.ts +3 -3
  294. package/src/synthesis/AwsPollyTTS.ts +14 -14
  295. package/src/synthesis/AzureCognitiveServicesTTS.ts +10 -10
  296. package/src/synthesis/CoquiServerTTS.ts +10 -10
  297. package/src/synthesis/ElevenlabsTTS.ts +137 -0
  298. package/src/synthesis/EspeakTTS.ts +90 -71
  299. package/src/synthesis/FliteTTS.ts +157 -157
  300. package/src/synthesis/GoogleCloudTTS.ts +19 -19
  301. package/src/synthesis/GoogleTranslateTTS.ts +104 -104
  302. package/src/synthesis/MicrosoftEdgeTTS.ts +80 -80
  303. package/src/synthesis/OpenAICloudTTS.ts +196 -0
  304. package/src/synthesis/SamTTS.ts +3 -3
  305. package/src/synthesis/SapiTTS.ts +29 -29
  306. package/src/synthesis/StreamlabsPollyTTS.ts +29 -29
  307. package/src/synthesis/SvoxPicoTTS.ts +67 -67
  308. package/src/synthesis/VitsTTS.ts +380 -380
  309. package/src/tests/Test.ts +4 -4
  310. package/src/utilities/Compression.ts +34 -13
  311. package/src/utilities/FileDownloader.ts +19 -19
  312. package/src/utilities/FileSystem.ts +7 -7
  313. package/src/utilities/Locale.ts +22 -22
  314. package/src/utilities/Logger.ts +4 -4
  315. package/src/utilities/ObjectUtilities.ts +19 -19
  316. package/src/utilities/OpenPromise.ts +2 -2
  317. package/src/utilities/PackageManager.ts +40 -0
  318. package/src/utilities/PathUtilities.ts +8 -8
  319. package/src/utilities/RandomGenerator.ts +3 -3
  320. package/src/utilities/SmoothEstimator.ts +35 -0
  321. package/src/utilities/TarballMaker.ts +9 -9
  322. package/src/utilities/Timeline.ts +15 -13
  323. package/src/utilities/Timer.ts +4 -4
  324. package/src/utilities/Utilities.ts +49 -15
  325. package/src/utilities/WasmMemoryManager.ts +7 -7
  326. package/src/utilities/WebReader.ts +23 -23
  327. package/src/utilities/WikipediaReader.ts +2 -2
  328. package/src/voice-activity-detection/AdaptiveGateVAD.ts +202 -0
  329. package/src/voice-activity-detection/SileroVAD.ts +5 -5
  330. package/src/voice-activity-detection/WebRtcVAD.ts +5 -5
  331. package/dist/synthesis/ElevenLabsTTS.d.ts +0 -8
  332. package/dist/synthesis/ElevenLabsTTS.js +0 -82
  333. package/dist/synthesis/ElevenLabsTTS.js.map +0 -1
  334. package/src/synthesis/ElevenLabsTTS.ts +0 -104
@@ -2,11 +2,11 @@ import { parentPort } from 'node:worker_threads'
2
2
 
3
3
  import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
4
4
 
5
- import { RawAudio, encodeWaveBuffer, fadeAudioInOut, getRawAudioDuration, sliceRawAudioByTime } from "./AudioUtilities.js"
5
+ import { RawAudio, encodeRawAudioToWave, fadeAudioInOut, getRawAudioDuration, sliceRawAudioByTime } from './AudioUtilities.js'
6
6
  import * as AudioBufferConversion from './AudioBufferConversion.js'
7
- import * as FFMpegTranscoder from "../codecs/FFMpegTranscoder.js"
7
+ import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
8
8
 
9
- import { Timer } from "../utilities/Timer.js"
9
+ import { Timer } from '../utilities/Timer.js'
10
10
  import { getRandomHexString, waitTimeout, writeToStderr } from '../utilities/Utilities.js'
11
11
  import { encodeToAudioBuffer } from './AudioBufferConversion.js'
12
12
  import { OpenPromise } from '../utilities/OpenPromise.js'
@@ -26,7 +26,7 @@ export async function playAudioFileWithTimelineFile(audioFilename: string, timel
26
26
 
27
27
  let transcript: string | undefined
28
28
  if (transcriptFileName) {
29
- transcript = await readFile(transcriptFileName, "utf8")
29
+ transcript = await readFile(transcriptFileName, 'utf8')
30
30
  }
31
31
 
32
32
  await playAudioWithWordTimeline(rawAudio, timeline, transcript)
@@ -58,7 +58,7 @@ export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline
58
58
  let wordEndOffset = entry.endOffsetUtf16
59
59
 
60
60
  if (wordStartOffset == null || wordEndOffset == null) {
61
- //writeToStderr(` [No offset availble for '${entry.text}'] `)
61
+ //writeToStderr(` [No offset available for '${entry.text}'] `)
62
62
 
63
63
  continue
64
64
  }
@@ -75,18 +75,18 @@ export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline
75
75
  }
76
76
  }
77
77
 
78
- writeToStderr("\n")
78
+ writeToStderr('\n')
79
79
 
80
80
  const signalChannel = new SignalChannel()
81
81
 
82
82
  const keypressListenerStartTimestamp = Date.now()
83
83
 
84
84
  function keypressHandler(message: any) {
85
- if (message.name == "keypress" &&
85
+ if (message.name == 'keypress' &&
86
86
  message.key.name == 'return' &&
87
87
  message.timestamp >= keypressListenerStartTimestamp) {
88
88
 
89
- signalChannel.send("abort")
89
+ signalChannel.send('abort')
90
90
  }
91
91
  }
92
92
 
@@ -96,7 +96,7 @@ export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline
96
96
 
97
97
  parentPort?.off('message', keypressHandler)
98
98
 
99
- writeToStderr("\n")
99
+ writeToStderr('\n')
100
100
  }
101
101
 
102
102
  export async function playAudioWithTimelinePhones(rawAudio: RawAudio, timeline: Timeline) {
@@ -108,7 +108,7 @@ export async function playAudioWithTimelinePhones(rawAudio: RawAudio, timeline:
108
108
  const wordEntry = timeline[wordIndex]
109
109
  const phoneTimeline = wordEntry.timeline!
110
110
 
111
- if (phoneTimeline.every(phoneEntry => phoneEntry.text == "")) {
111
+ if (phoneTimeline.every(phoneEntry => phoneEntry.text == '')) {
112
112
  continue
113
113
  }
114
114
 
@@ -127,17 +127,17 @@ export async function playAudioWithTimelinePhones(rawAudio: RawAudio, timeline:
127
127
  }
128
128
  }
129
129
 
130
- writeToStderr("\n")
130
+ writeToStderr('\n')
131
131
 
132
132
  await playAudioSamples(rawAudio, onTimePosition)
133
133
 
134
- writeToStderr("\n")
134
+ writeToStderr('\n')
135
135
  }
136
136
 
137
137
 
138
138
  export async function playAudioPairWithTimelineInterleaved(rawAudio1: RawAudio, rawAudio2: RawAudio, timeline1: Timeline, timeline2: Timeline) {
139
139
  if (timeline1.length != timeline2.length) {
140
- throw new Error("Timelines have different lengths")
140
+ throw new Error('Timelines have different lengths')
141
141
  }
142
142
 
143
143
  for (let i = 0; i < timeline1.length; i++) {
@@ -149,7 +149,7 @@ export async function playAudioPairWithTimelineInterleaved(rawAudio1: RawAudio,
149
149
  await waitTimeout(500)
150
150
  }
151
151
 
152
- writeToStderr("\n")
152
+ writeToStderr('\n')
153
153
  }
154
154
 
155
155
  export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosition: number) => void, signalChannel?: SignalChannel, microFadeInOut = true) {
@@ -167,15 +167,15 @@ export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosit
167
167
 
168
168
  const soxPath = await tryResolvingSoxPath()
169
169
 
170
- let aborted = false
171
-
172
170
  if (!soxPath) {
173
171
  throw new Error(`Couldn't find or install the SoX utility. Please install the SoX utility on your system path to enable audio playback.`)
174
172
  }
175
173
 
174
+ let aborted = false
175
+
176
176
  let streamToStdin = true
177
177
 
178
- if (process.platform == "darwin") {
178
+ if (process.platform == 'darwin') {
179
179
  streamToStdin = false
180
180
  }
181
181
 
@@ -200,7 +200,7 @@ export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosit
200
200
  )
201
201
  } else {
202
202
  tempFilePath = path.join(getAppTempDir(appName), `${getRandomHexString(16)}.wav`)
203
- const waveFileBuffer = encodeWaveBuffer(rawAudio)
203
+ const waveFileBuffer = encodeRawAudioToWave(rawAudio)
204
204
  await outputFile(tempFilePath, waveFileBuffer)
205
205
 
206
206
  playerProcess = spawn(
@@ -211,32 +211,32 @@ export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosit
211
211
  }
212
212
 
213
213
  if (signalChannel) {
214
- signalChannel.on("abort", () => {
214
+ signalChannel.on('abort', () => {
215
215
  aborted = true
216
216
  playerProcess.kill('SIGKILL')
217
217
  })
218
218
  }
219
219
 
220
220
  // Required to work around SoX bug:
221
- playerProcess.stderr.on("data", (data) => {
221
+ playerProcess.stderr.on('data', (data) => {
222
222
  //writeToStderr(data.toString('utf-8'))
223
223
  })
224
224
 
225
- playerProcess.stdout.on("data", (data) => {
225
+ playerProcess.stdout.on('data', (data) => {
226
226
  //writeToStderr(data.toString('utf-8'))
227
227
  })
228
228
 
229
- playerProcess.once("spawn", () => {
229
+ playerProcess.once('spawn', () => {
230
230
  if (audioBuffer != undefined) {
231
231
  playerProcess.stdin!.write(audioBuffer)
232
232
  playerProcess.stdin!.end()
233
- playerProcess.stdin!.on("error", () => { })
233
+ playerProcess.stdin!.on('error', () => { })
234
234
  }
235
235
 
236
236
  playerSpawnedOpenPromise.resolve(null)
237
237
  })
238
238
 
239
- playerProcess.once("error", async (e) => {
239
+ playerProcess.once('error', async (e) => {
240
240
  await cleanup()
241
241
  playerProcessClosed = true
242
242
 
@@ -291,7 +291,7 @@ export function playAudioSamples_Speaker(rawAudio: RawAudio, onTimePosition?: (t
291
291
  sampleRate: rawAudio.sampleRate,
292
292
  })
293
293
 
294
- speaker.on("error", (e: any) => {
294
+ speaker.on('error', (e: any) => {
295
295
  reject(e)
296
296
  })
297
297
 
@@ -306,7 +306,7 @@ export function playAudioSamples_Speaker(rawAudio: RawAudio, onTimePosition?: (t
306
306
  let mpg123AudioBufferSize: number
307
307
  let mpg123AudioBufferDuration: number
308
308
 
309
- if (process.platform == "win32") {
309
+ if (process.platform == 'win32') {
310
310
  mpg123AudioBufferSize = 65536
311
311
  mpg123AudioBufferDuration = byteCountToDuration(mpg123AudioBufferSize)
312
312
  } else {
@@ -356,4 +356,4 @@ export function playAudioSamples_Speaker(rawAudio: RawAudio, onTimePosition?: (t
356
356
  }
357
357
 
358
358
  export const charactersToWriteAhead =
359
- [",", ".", "", "", "", "", "", ":", ";", "?", "!", ")", "]", "}", "\"", "'", "", "", "-", "", "»"]
359
+ [',', '.', '', '', '', '', '', ':', ';', '?', '!', ')', ']', '}', `"`, `'`, '', '', '-', '', '»']
@@ -1,9 +1,9 @@
1
1
  import { spawn } from 'child_process'
2
2
 
3
- import { RawAudio, concatAudioSegments } from "./AudioUtilities.js"
3
+ import { RawAudio, concatAudioSegments } from './AudioUtilities.js'
4
4
  import * as AudioBufferConversion from './AudioBufferConversion.js'
5
5
 
6
- import { Timer } from "../utilities/Timer.js"
6
+ import { Timer } from '../utilities/Timer.js'
7
7
  import { logToStderr } from '../utilities/Utilities.js'
8
8
  import { OpenPromise } from '../utilities/OpenPromise.js'
9
9
  import { SampleFormat } from '../codecs/WaveCodec.js'
@@ -37,7 +37,7 @@ export function captureAudioInput(channelCount = 1, sampleRate = 48000, maxTime
37
37
  const soxPath = await tryResolvingSoxPath()
38
38
 
39
39
  if (!soxPath) {
40
- throw new Error("Could not resolve a SoX executable")
40
+ throw new Error('Could not resolve a SoX executable')
41
41
  }
42
42
 
43
43
  let args: string[]
@@ -51,7 +51,7 @@ export function captureAudioInput(channelCount = 1, sampleRate = 48000, maxTime
51
51
  '-c', `${channelCount}`, '-r', `${sampleRate}`, '-e', 'signed',
52
52
  '-t', 'raw', '-']
53
53
  } else {
54
- throw new Error("")
54
+ throw new Error('')
55
55
  }
56
56
 
57
57
  const recorder = spawn(
@@ -60,7 +60,7 @@ export function captureAudioInput(channelCount = 1, sampleRate = 48000, maxTime
60
60
  {}
61
61
  )
62
62
 
63
- recorder.once("spawn", () => {
63
+ recorder.once('spawn', () => {
64
64
  recorderSpawnedOpenPromise.resolve(null)
65
65
  timer.restart()
66
66
  })
@@ -1,16 +1,17 @@
1
- import * as FFMpegTranscoder from "../codecs/FFMpegTranscoder.js"
2
- import { SampleFormat, encodeWave, decodeWave, BitDepth } from "../codecs/WaveCodec.js"
3
- import { resampleAudioSpeex } from "../dsp/SpeexResampler.js"
1
+ import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
2
+ import { SampleFormat, encodeWave, decodeWave, BitDepth } from '../codecs/WaveCodec.js'
3
+ import { resampleAudioSpeex } from '../dsp/SpeexResampler.js'
4
+ import { Timeline } from '../utilities/Timeline.js'
4
5
  import { concatFloat32Arrays } from '../utilities/Utilities.js'
5
6
 
6
7
  ////////////////////////////////////////////////////////////////////////////////////////////////
7
8
  // Wave encoding and decoding
8
9
  ////////////////////////////////////////////////////////////////////////////////////////////////
9
- export function encodeWaveBuffer(rawAudio: RawAudio, bitDepth: BitDepth = 16, sampleFormat: SampleFormat = SampleFormat.PCM, speakerPositionMask = 0) {
10
+ export function encodeRawAudioToWave(rawAudio: RawAudio, bitDepth: BitDepth = 16, sampleFormat: SampleFormat = SampleFormat.PCM, speakerPositionMask = 0) {
10
11
  return encodeWave(rawAudio, bitDepth, sampleFormat, speakerPositionMask)
11
12
  }
12
13
 
13
- export function decodeWaveBuffer(waveFileBuffer: Buffer, ignoreTruncatedChunks = false) {
14
+ export function decodeWaveToRawAudio(waveFileBuffer: Buffer, ignoreTruncatedChunks = false) {
14
15
  return decodeWave(waveFileBuffer, ignoreTruncatedChunks)
15
16
  }
16
17
 
@@ -31,6 +32,10 @@ export function trimAudioStart(audioSamples: Float32Array, targetStartSilentSamp
31
32
  }
32
33
 
33
34
  export function trimAudioEnd(audioSamples: Float32Array, targetEndSilentSampleCount = 0, amplitudeThresholdDecibels = defaultSilenceThresholdDecibels) {
35
+ if (audioSamples.length === 0) {
36
+ return new Float32Array(0)
37
+ }
38
+
34
39
  const silentSampleCount = getEndingSilentSampleCount(audioSamples, amplitudeThresholdDecibels)
35
40
 
36
41
  const trimmedAudio = audioSamples.subarray(0, audioSamples.length - silentSampleCount)
@@ -76,21 +81,25 @@ export function getEndingSilentSampleCount(audioSamples: Float32Array, amplitude
76
81
  ////////////////////////////////////////////////////////////////////////////////////////////////
77
82
  // Gain, normalization, mixing, and channel downmixing
78
83
  ////////////////////////////////////////////////////////////////////////////////////////////////
79
- export function downmixToMonoAndNormalize(rawAudio: RawAudio, targetPeakDb = -3) {
80
- return normalizeAudioLevel(downmixToMono(rawAudio), targetPeakDb)
84
+ export function downmixToMonoAndNormalize(rawAudio: RawAudio, targetPeakDecibels = -3) {
85
+ return normalizeAudioLevel(downmixToMono(rawAudio), targetPeakDecibels)
81
86
  }
82
87
 
83
- export function normalizeAudioLevel(rawAudio: RawAudio, targetPeakDb = -3, maxIncreaseDb = 30): RawAudio {
88
+ export function attenuateIfClipping(rawAudio: RawAudio) {
89
+ return normalizeAudioLevel(rawAudio, -0.1, 0)
90
+ }
91
+
92
+ export function normalizeAudioLevel(rawAudio: RawAudio, targetPeakDecibels = -3, maxGainIncreaseDecibels = 30): RawAudio {
84
93
  //rawAudio = correctDCBias(rawAudio)
85
94
 
86
- const targetPeakAmplitude = decibelsToGainFactor(targetPeakDb)
87
- const maxGainFactor = decibelsToGainFactor(maxIncreaseDb)
95
+ const targetPeakAmplitude = decibelsToGainFactor(targetPeakDecibels)
96
+ const maxGainFactor = decibelsToGainFactor(maxGainIncreaseDecibels)
88
97
 
89
- const peakAmplitude = getAudioPeakAmplitude(rawAudio.audioChannels)
98
+ const peakAmplitude = getSamplePeakAmplitude(rawAudio.audioChannels)
90
99
 
91
100
  const gainFactor = Math.min(targetPeakAmplitude / peakAmplitude, maxGainFactor)
92
101
 
93
- return applyGain(rawAudio, gainFactor)
102
+ return applyGainFactor(rawAudio, gainFactor)
94
103
  }
95
104
 
96
105
  export function correctDCBias(rawAudio: RawAudio): RawAudio {
@@ -119,11 +128,11 @@ export function correctDCBias(rawAudio: RawAudio): RawAudio {
119
128
  return { audioChannels: outputAudioChannels, sampleRate: rawAudio.sampleRate } as RawAudio
120
129
  }
121
130
 
122
- export function applyGainDecibels(rawAudio: RawAudio, decibelGain: number): RawAudio {
123
- return applyGain(rawAudio, decibelsToGainFactor(decibelGain))
131
+ export function applyGainDecibels(rawAudio: RawAudio, gainDecibels: number): RawAudio {
132
+ return applyGainFactor(rawAudio, decibelsToGainFactor(gainDecibels))
124
133
  }
125
134
 
126
- export function applyGain(rawAudio: RawAudio, gainFactor: number): RawAudio {
135
+ export function applyGainFactor(rawAudio: RawAudio, gainFactor: number): RawAudio {
127
136
  const outputAudioChannels: Float32Array[] = []
128
137
 
129
138
  for (const channelSamples of rawAudio.audioChannels) {
@@ -142,8 +151,13 @@ export function applyGain(rawAudio: RawAudio, gainFactor: number): RawAudio {
142
151
  }
143
152
 
144
153
  export function downmixToMono(rawAudio: RawAudio): RawAudio {
154
+ const channelCount = rawAudio.audioChannels.length
145
155
  const sampleCount = rawAudio.audioChannels[0].length
146
156
 
157
+ if (channelCount === 1) {
158
+ return cloneRawAudio(rawAudio)
159
+ }
160
+
147
161
  const downmixedAudio = new Float32Array(sampleCount)
148
162
 
149
163
  for (const channelSamples of rawAudio.audioChannels) {
@@ -152,14 +166,20 @@ export function downmixToMono(rawAudio: RawAudio): RawAudio {
152
166
  }
153
167
  }
154
168
 
169
+ if (channelCount > 1) {
170
+ for (let i = 0; i < sampleCount; i++) {
171
+ downmixedAudio[i] /= channelCount
172
+ }
173
+ }
174
+
155
175
  return { audioChannels: [downmixedAudio], sampleRate: rawAudio.sampleRate } as RawAudio
156
176
  }
157
177
 
158
- export function getAudioPeakDecibels(audioChannels: Float32Array[]) {
159
- return gainFactorToDecibels(getAudioPeakAmplitude(audioChannels))
178
+ export function getSamplePeakDecibels(audioChannels: Float32Array[]) {
179
+ return gainFactorToDecibels(getSamplePeakAmplitude(audioChannels))
160
180
  }
161
181
 
162
- export function getAudioPeakAmplitude(audioChannels: Float32Array[]) {
182
+ export function getSamplePeakAmplitude(audioChannels: Float32Array[]) {
163
183
  let maxAmplitude = 0.00001
164
184
 
165
185
  for (const channelSamples of audioChannels) {
@@ -173,11 +193,11 @@ export function getAudioPeakAmplitude(audioChannels: Float32Array[]) {
173
193
 
174
194
  export function mixAudio(rawAudio1: RawAudio, rawAudio2: RawAudio) {
175
195
  if (rawAudio1.audioChannels.length != rawAudio2.audioChannels.length) {
176
- throw new Error("Can't mix audio of unequal channel counts")
196
+ throw new Error(`Can't mix audio of unequal channel counts`)
177
197
  }
178
198
 
179
199
  if (rawAudio1.sampleRate != rawAudio2.sampleRate) {
180
- throw new Error("Can't mix audio of different sample rates")
200
+ throw new Error(`Can't mix audio of different sample rates`)
181
201
  }
182
202
 
183
203
  const mixedAudioChannels: Float32Array[] = []
@@ -217,6 +237,14 @@ export function sliceRawAudio(rawAudio: RawAudio, startSampleIndex: number, endS
217
237
  }
218
238
 
219
239
  export function sliceAudioChannels(audioChannels: Float32Array[], startSampleIndex: number, endSampleIndex: number) {
240
+ if (audioChannels.length === 0) {
241
+ throw new Error('audioChannels array is empty')
242
+ }
243
+
244
+ if (startSampleIndex > endSampleIndex) {
245
+ throw new Error('startSampleIndex must be less or equal to endSampleIndex')
246
+ }
247
+
220
248
  const channelCount = audioChannels.length
221
249
 
222
250
  const outAudioChannels: Float32Array[] = []
@@ -246,6 +274,40 @@ export function concatAudioSegments(audioSegments: Float32Array[][]) {
246
274
  return outAudioChannels
247
275
  }
248
276
 
277
+ export function cropToTimeline(rawAudio: RawAudio, timeline: Timeline) {
278
+ const sampleRate = rawAudio.sampleRate
279
+ const channelCount = rawAudio.audioChannels.length
280
+ const sampleCount = rawAudio.audioChannels[0].length
281
+
282
+ const audioSegments: Float32Array[][] = []
283
+
284
+ for (let i = 0; i < timeline.length; i++) {
285
+ const entry = timeline[i]
286
+ const startTime = entry.startTime
287
+ const endTime = entry.endTime
288
+
289
+ const startSampleOffset = Math.max(Math.floor(startTime * sampleRate), 0)
290
+ const endSampleOffset = Math.min(Math.floor(endTime * sampleRate), sampleCount)
291
+
292
+ const segment: Float32Array[] = []
293
+
294
+ for (let c = 0; c < channelCount; c++) {
295
+ segment.push(rawAudio.audioChannels[c].subarray(startSampleOffset, endSampleOffset))
296
+ }
297
+
298
+ audioSegments.push(segment)
299
+ }
300
+
301
+ if (audioSegments.length > 0) {
302
+ const croppedAudioChannels = concatAudioSegments(audioSegments)
303
+ const croppedRawAudio: RawAudio = { audioChannels: croppedAudioChannels, sampleRate: rawAudio.sampleRate }
304
+
305
+ return croppedRawAudio
306
+ } else {
307
+ return getEmptyRawAudio(channelCount, sampleRate)
308
+ }
309
+ }
310
+
249
311
  export function fadeAudioInOut(rawAudio: RawAudio, fadeTime: number): RawAudio {
250
312
  const fadeSampleCount = Math.floor(rawAudio.sampleRate * fadeTime)
251
313
  const gainReductionPerFrameDecibels = -60 / fadeSampleCount
@@ -326,14 +388,19 @@ export async function ensureRawAudio(input: AudioSourceParam, outSampleRate?: nu
326
388
  inputAsRawAudio = downmixToMono(inputAsRawAudio)
327
389
  }
328
390
 
329
- if (outChannelCount != null && outChannelCount >= 2 && outChannelCount != inputAudioChannelCount) {
330
- throw new Error(`Can't convert ${inputAudioChannelCount} channels to ${outChannelCount} channels. Channel conversion of raw audio currently only supports downmixing to mono.`)
391
+ if (outChannelCount == 2 && inputAudioChannelCount == 1) {
392
+ inputAsRawAudio = cloneRawAudio(inputAsRawAudio)
393
+ inputAsRawAudio.audioChannels.push(inputAsRawAudio.audioChannels[0].slice())
394
+ }
395
+
396
+ if (outChannelCount != null && outChannelCount > 2 && outChannelCount != inputAudioChannelCount) {
397
+ throw new Error(`Can't convert ${inputAudioChannelCount} channels to ${outChannelCount} channels. Channel conversion of raw audio currently only supports mono and stereo inputs.`)
331
398
  }
332
399
 
333
400
  if (outSampleRate && inputAsRawAudio.sampleRate != outSampleRate) {
334
401
  inputAsRawAudio = await resampleAudioSpeex(inputAsRawAudio, outSampleRate)
335
402
  }
336
- } else if (typeof input == "string" || input instanceof Uint8Array) {
403
+ } else if (typeof input == 'string' || input instanceof Uint8Array) {
337
404
  if (input instanceof Uint8Array && !Buffer.isBuffer(input)) {
338
405
  input = Buffer.from(input)
339
406
  }
@@ -342,12 +409,28 @@ export async function ensureRawAudio(input: AudioSourceParam, outSampleRate?: nu
342
409
 
343
410
  inputAsRawAudio = await FFMpegTranscoder.decodeToChannels(inputAsStringOrBuffer, outSampleRate, outChannelCount)
344
411
  } else {
345
- throw new Error("Received an invalid input audio data type.")
412
+ throw new Error('Received an invalid input audio data type.')
346
413
  }
347
414
 
348
415
  return inputAsRawAudio
349
416
  }
350
417
 
418
+ export function subtractAudio(audio1: RawAudio, audio2: RawAudio) {
419
+ const sampleCount = audio1.audioChannels[0].length
420
+
421
+ const subtractedAudioChannels = [new Float32Array(sampleCount), new Float32Array(sampleCount)]
422
+
423
+ for (let i = 0; i < sampleCount; i++) {
424
+ for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
425
+ subtractedAudioChannels[channelIndex][i] = audio1.audioChannels[channelIndex][i] - audio2.audioChannels[channelIndex][i]
426
+ }
427
+ }
428
+
429
+ const subtractedRawAudio: RawAudio = { audioChannels: subtractedAudioChannels, sampleRate: audio1.sampleRate }
430
+
431
+ return subtractedRawAudio
432
+ }
433
+
351
434
  ////////////////////////////////////////////////////////////////////////////////////////////////
352
435
  // Unit conversion
353
436
  ////////////////////////////////////////////////////////////////////////////////////////////////