echogarden 1.6.2 → 1.8.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 (115) hide show
  1. package/data/schemas/options.json +50 -12
  2. package/dist/api/Alignment.js +2 -2
  3. package/dist/api/Alignment.js.map +1 -1
  4. package/dist/api/Denoising.js +5 -4
  5. package/dist/api/Denoising.js.map +1 -1
  6. package/dist/api/Recognition.js +2 -2
  7. package/dist/api/Recognition.js.map +1 -1
  8. package/dist/api/SourceSeparation.d.ts +2 -5
  9. package/dist/api/SourceSeparation.js +14 -13
  10. package/dist/api/SourceSeparation.js.map +1 -1
  11. package/dist/api/SpeechLanguageDetection.js +2 -2
  12. package/dist/api/SpeechLanguageDetection.js.map +1 -1
  13. package/dist/api/SpeechTranslation.js +2 -2
  14. package/dist/api/SpeechTranslation.js.map +1 -1
  15. package/dist/api/Synthesis.js +8 -6
  16. package/dist/api/Synthesis.js.map +1 -1
  17. package/dist/api/TextTranslation.d.ts +3 -1
  18. package/dist/api/TextTranslation.js +12 -6
  19. package/dist/api/TextTranslation.js.map +1 -1
  20. package/dist/api/TranslationAlignment.js +2 -2
  21. package/dist/api/TranslationAlignment.js.map +1 -1
  22. package/dist/audio/AudioUtilities.d.ts +5 -3
  23. package/dist/audio/AudioUtilities.js +39 -25
  24. package/dist/audio/AudioUtilities.js.map +1 -1
  25. package/dist/build-tools/MakeTarballsForInstalledPackages.d.ts +1 -0
  26. package/dist/build-tools/MakeTarballsForInstalledPackages.js +20 -0
  27. package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -0
  28. package/dist/cli/CLI.js +4 -3
  29. package/dist/cli/CLI.js.map +1 -1
  30. package/dist/dsp/FFT.d.ts +3 -3
  31. package/dist/dsp/FFT.js +55 -34
  32. package/dist/dsp/FFT.js.map +1 -1
  33. package/dist/nlp/IPA.d.ts +3 -3
  34. package/dist/nlp/Segmentation.js +2 -1
  35. package/dist/nlp/Segmentation.js.map +1 -1
  36. package/dist/nlp/TextNormalizer.d.ts +2 -0
  37. package/dist/nlp/TextNormalizer.js +51 -0
  38. package/dist/nlp/TextNormalizer.js.map +1 -1
  39. package/dist/recognition/WhisperSTT.d.ts +5 -0
  40. package/dist/recognition/WhisperSTT.js +19 -11
  41. package/dist/recognition/WhisperSTT.js.map +1 -1
  42. package/dist/source-separation/MDXNetSourceSeparation.d.ts +26 -3
  43. package/dist/source-separation/MDXNetSourceSeparation.js +159 -79
  44. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  45. package/dist/subtitles/Subtitles.js +2 -1
  46. package/dist/subtitles/Subtitles.js.map +1 -1
  47. package/dist/synthesis/EspeakTTS.js +5 -5
  48. package/dist/synthesis/EspeakTTS.js.map +1 -1
  49. package/dist/tests/Test.js +0 -1
  50. package/dist/tests/Test.js.map +1 -1
  51. package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +9 -3
  52. package/dist/text-translation/GoogleTranslateTextTranslation.js +59 -29
  53. package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -1
  54. package/dist/utilities/OnnxUtilities.d.ts +1 -0
  55. package/dist/utilities/OnnxUtilities.js +5 -5
  56. package/dist/utilities/OnnxUtilities.js.map +1 -1
  57. package/dist/utilities/PackageManager.js +6 -6
  58. package/dist/utilities/PackageManager.js.map +1 -1
  59. package/dist/utilities/StringUtilities.d.ts +28 -0
  60. package/dist/utilities/StringUtilities.js +150 -0
  61. package/dist/utilities/StringUtilities.js.map +1 -0
  62. package/dist/utilities/TarballMaker.d.ts +3 -4
  63. package/dist/utilities/TarballMaker.js +6 -19
  64. package/dist/utilities/TarballMaker.js.map +1 -1
  65. package/dist/utilities/Timeline.js +2 -1
  66. package/dist/utilities/Timeline.js.map +1 -1
  67. package/dist/utilities/Utilities.d.ts +1 -33
  68. package/dist/utilities/Utilities.js +3 -176
  69. package/dist/utilities/Utilities.js.map +1 -1
  70. package/dist/utilities/WasmMemoryManager.d.ts +9 -1
  71. package/dist/utilities/WasmMemoryManager.js +24 -3
  72. package/dist/utilities/WasmMemoryManager.js.map +1 -1
  73. package/dist/utilities/WebReader.js +1 -1
  74. package/dist/utilities/WebReader.js.map +1 -1
  75. package/dist/utilities/WikipediaReader.js +1 -1
  76. package/dist/utilities/WikipediaReader.js.map +1 -1
  77. package/dist/utilities/WindowedList.d.ts +10 -0
  78. package/dist/utilities/WindowedList.js +36 -0
  79. package/dist/utilities/WindowedList.js.map +1 -0
  80. package/docs/Engines.md +1 -1
  81. package/docs/Options.md +16 -10
  82. package/package.json +11 -11
  83. package/src/alignment/SpeechAlignment.ts +1 -1
  84. package/src/api/Alignment.ts +2 -2
  85. package/src/api/Denoising.ts +5 -4
  86. package/src/api/Recognition.ts +3 -3
  87. package/src/api/SourceSeparation.ts +20 -19
  88. package/src/api/SpeechLanguageDetection.ts +2 -2
  89. package/src/api/SpeechTranslation.ts +2 -2
  90. package/src/api/Synthesis.ts +8 -6
  91. package/src/api/TextTranslation.ts +17 -9
  92. package/src/api/TranslationAlignment.ts +2 -2
  93. package/src/audio/AudioUtilities.ts +53 -33
  94. package/src/build-tools/MakeTarballsForInstalledPackages.ts +25 -0
  95. package/src/cli/CLI.ts +4 -3
  96. package/src/dsp/FFT.ts +65 -42
  97. package/src/nlp/Segmentation.ts +2 -1
  98. package/src/nlp/TextNormalizer.ts +60 -0
  99. package/src/recognition/WhisperSTT.ts +25 -12
  100. package/src/source-separation/MDXNetSourceSeparation.ts +218 -88
  101. package/src/subtitles/Subtitles.ts +2 -1
  102. package/src/synthesis/EspeakTTS.ts +5 -5
  103. package/src/tests/Test.ts +0 -4
  104. package/src/text-translation/GoogleTranslateTextTranslation.ts +91 -30
  105. package/src/typings/Fillers.d.ts +2 -0
  106. package/src/utilities/OnnxUtilities.ts +7 -8
  107. package/src/utilities/PackageManager.ts +6 -7
  108. package/src/utilities/StringUtilities.ts +203 -0
  109. package/src/utilities/TarballMaker.ts +6 -23
  110. package/src/utilities/Timeline.ts +2 -1
  111. package/src/utilities/Utilities.ts +4 -237
  112. package/src/utilities/WasmMemoryManager.ts +38 -4
  113. package/src/utilities/WebReader.ts +1 -1
  114. package/src/utilities/WikipediaReader.ts +1 -1
  115. package/src/utilities/WindowedList.ts +45 -0
@@ -0,0 +1,36 @@
1
+ export class WindowedList {
2
+ maxWindowLength;
3
+ elements = [];
4
+ startOffset = 0;
5
+ constructor(maxWindowLength) {
6
+ this.maxWindowLength = maxWindowLength;
7
+ }
8
+ add(value) {
9
+ if (this.elements.length === this.maxWindowLength) {
10
+ this.elements.shift();
11
+ this.startOffset += 1;
12
+ }
13
+ this.elements.push(value);
14
+ }
15
+ get(index) {
16
+ if (index < this.startOffset) {
17
+ throw new Error(`Index is smaller than to window start offset.`);
18
+ }
19
+ if (index >= this.endOffset) {
20
+ throw new Error(`Index is beyond window end offset.`);
21
+ }
22
+ return this.elements[index - this.startOffset];
23
+ }
24
+ slice(startIndex, endIndex) {
25
+ const result = [];
26
+ endIndex = Math.min(endIndex, this.endOffset);
27
+ for (let i = startIndex; i < endIndex; i++) {
28
+ result.push(this.get(i));
29
+ }
30
+ return result;
31
+ }
32
+ get endOffset() {
33
+ return this.startOffset + this.elements.length;
34
+ }
35
+ }
36
+ //# sourceMappingURL=WindowedList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WindowedList.js","sourceRoot":"","sources":["../../src/utilities/WindowedList.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,YAAY;IAII;IAH5B,QAAQ,GAAQ,EAAE,CAAA;IAClB,WAAW,GAAG,CAAC,CAAA;IAEf,YAA4B,eAAuB;QAAvB,oBAAe,GAAf,eAAe,CAAQ;IACnD,CAAC;IAED,GAAG,CAAC,KAAQ;QACX,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC;YACnD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;YAErB,IAAI,CAAC,WAAW,IAAI,CAAC,CAAA;QACtB,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,GAAG,CAAC,KAAa;QAChB,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QACjE,CAAC;QAED,IAAI,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACtD,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAA;IAC/C,CAAC;IAED,KAAK,CAAC,UAAkB,EAAE,QAAgB;QACzC,MAAM,MAAM,GAAQ,EAAE,CAAA;QAEtB,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAE7C,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACzB,CAAC;QAED,OAAO,MAAM,CAAA;IACd,CAAC;IAED,IAAI,SAAS;QACZ,OAAO,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;IAC/C,CAAC;CACD"}
package/docs/Engines.md CHANGED
@@ -81,7 +81,7 @@ These engines' goal is to match (or "align") a given spoken recording with a giv
81
81
 
82
82
  **Cloud services (unofficial)**:
83
83
 
84
- * Google Translate (`google-translate`): uses the [Google Translate mobile web UI](https://translate.google.com/m) to translate text from and to any one of its supported languages.
84
+ * Google Translate (`google-translate`): uses the [Google Translate mobile web UI](https://translate.google.com/m) to translate text from and to any one of its 243 supported languages.
85
85
 
86
86
  ## Speech-to-translated-transcript alignment
87
87
 
package/docs/Options.md CHANGED
@@ -47,7 +47,7 @@ Applies to CLI operations: `speak`, `speak-file`, `speak-url`, `speak-wikipedia`
47
47
 
48
48
  **VITS**:
49
49
  * `vits.speakerId`: speaker ID, for VITS models that support multiple speakers. Defaults to `0`
50
- * `vits.provider`: ONNX execution provider to use. Can be `cpu` or `dml` (https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only). Using GPU acceleration for VITS may or may not be faster than CPU, depending on your hardware. Defaults to `cpu`
50
+ * `vits.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Using GPU acceleration for VITS may or may not be faster than CPU, depending on your hardware. Defaults to `cpu`
51
51
 
52
52
  **eSpeak**:
53
53
  * `espeak.rate`: speech rate, in eSpeak units. Overrides `speed` when set
@@ -151,8 +151,8 @@ Applies to CLI operation: `transcribe`, API method: `recognize`
151
151
  * `whisper.suppressRepetition`: attempt to suppress decoding of repeating token patterns. Defaults to `true`
152
152
  * `whisper.repetitionThreshold`: minimal repetition / compressibility score to cause a part not to be auto-prompted to the next part. Defaults to `2.4`
153
153
  * `whisper.decodeTimestampTokens`: enable/disable decoding of timestamp tokens. Setting to `false` can reduce the occurrence of hallucinations and token repetition loops, possibly due to the overall reduction in the number of tokens decoded. This has no impact on the accuracy of timestamps, since they are derived independently using cross-attention weights. However, there are cases where this can cause the model to end a part prematurely, especially in singing and less speech-like voice segments, or when there are multiple speakers. Defaults to `true`
154
- * `whisper.encoderProvider`: identifier for the ONNX execution provider to use with the encoder model. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only) or `cuda` (Linux only). In general, GPU-based encoding should be significantly faster. Defaults to `cpu`, or `dml` if available
155
- * `whisper.decoderProvider`: identifier for the ONNX execution provider to use with the decoder model. Can be `cpu`, `dml` (Windows only) or `cuda` (Linux only). Using GPU acceleration for the decoder may be faster than CPU, especially for larger models, but that depends on your particular combination of CPU and GPU. Defaults to `cpu`, and on Windows, `dml` if available for larger models (`small`, `medium`, `large`)
154
+ * `whisper.encoderProvider`: identifier for the ONNX execution provider to use with the encoder model. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). In general, GPU-based encoding should be significantly faster. Defaults to `cpu`, or `dml` if available
155
+ * `whisper.decoderProvider`: identifier for the ONNX execution provider to use with the decoder model. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Using GPU acceleration for the decoder may be faster than CPU, especially for larger models, but that depends on your particular combination of CPU and GPU. Defaults to `cpu`, and on Windows, `dml` if available for larger models (`small`, `medium`, `large`)
156
156
  * `whisper.seed`: provide a custom random seed for token selection when temperature is greater than 0. Uses a constant seed by default to ensure reproducibility
157
157
 
158
158
  **Whisper.cpp**:
@@ -174,7 +174,7 @@ Applies to CLI operation: `transcribe`, API method: `recognize`
174
174
 
175
175
  **Silero**:
176
176
  * `silero.modelPath`: path to a Silero model. Note that latest `en`, `de`, `fr` and `uk` models are automatically installed when needed based on the selected language. This should only be used to manually specify a different model, otherwise specify `language` instead
177
- * `silero.provider`: ONNX execution provider to use. Can be `cpu` or `dml` (Windows only). Defaults to `cpu`, or `dml` if available
177
+ * `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Defaults to `cpu`, or `dml` if available
178
178
 
179
179
  **Google Cloud**:
180
180
  * `googleCloud.apiKey`: Google Cloud API key (required)
@@ -234,11 +234,11 @@ Applies to CLI operation: `align`, API method: `align`
234
234
  Applies to the `whisper` engine only. To provide Whisper options for `dtw-ra`, use `recognition.whisper` instead.
235
235
 
236
236
  * `whisper.model`: Whisper model to use. Defaults to `tiny` or `tiny.en`
237
- * `whisper.endTokenThreshold`: minimal probability to accept an end-of-text token for a recognized part. The probability is measured via the softmax between the end-of-text token's logit and the second highest logit. You can try to adjust this threshold in cases the model is ending a part with too few, or many tokens decoded. Defaults to `0.9`. On the last audio part, it is always effectively set to `Infinity`, to ensure the remaining transcript tokens are decoded in full
237
+ * `whisper.endTokenThreshold`: minimal probability to accept an end token for a recognized part. The probability is measured via the softmax between the end token's logit and the second highest logit. You can try to adjust this threshold in cases the model is ending a part with too few, or many tokens decoded. Defaults to `0.9`. On the last audio part, it is always effectively set to `Infinity`, to ensure the remaining transcript tokens are decoded in full
238
+ * `whisper.maxTokensPerPart`: maximum number of tokens to decode per part. Should help avoid edge cases where the model never reaches an end token for the part, which otherwise may cause the model to decode too many tokens and eventually crash. Defaults to 250
238
239
  * `whisper.encoderProvider`: encoder ONNX provider. See details in recognition section above
239
240
  * `whisper.decoderProvider`: decoder ONNX provider. See details in recognition section above
240
241
 
241
-
242
242
  ## Speech-to-text translation
243
243
 
244
244
  Applies to CLI operation: `translate-speech`, API method: `translateSpeech`
@@ -269,10 +269,16 @@ Applies to CLI operation: `translate-speech`, API method: `translateSpeech`
269
269
 
270
270
  Applies to CLI operation: `translate-text`, API method: `translateText`
271
271
 
272
+ **General**:
272
273
  * `engine`: only `google-translate` supported
273
274
  * `sourceLanguage`: the source language code for the input text. Auto-detected if not set
274
275
  * `targetLanguage`: the target language code for the output text. Required
275
276
  * `languageDetection`: language detection options. Optional
277
+ * `plainText`: plain text processing options. Optional
278
+
279
+ **Google Translate**:
280
+ * `googleTranslate.tld`: top-level domain to request from. Defaults to `com`
281
+ * `googleTranslate.maxCharactersPerPart`: maximum number of characters in each part requested from the server. Defaults to 2000
276
282
 
277
283
  ## Speech-to-translated-transcript alignment
278
284
 
@@ -345,7 +351,7 @@ Applies to CLI operation: `detect-speech-langauge`, API method: `detectSpeechLan
345
351
  * `whisper.decoderProvider`: decoder ONNX execution provider. See details in recognition section above
346
352
 
347
353
  **Silero**:
348
- * `silero.provider`: ONNX execution provider to use. Can be `cpu` or `dml` (Windows only). Using GPU may be faster, but the initialization overhead is larger. **Note**: `dml` provider seems to be unstable at the moment for this model. Defaults to `cpu`
354
+ * `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Using GPU may be faster, but the initialization overhead is larger. **Note**: `dml` provider seems to be unstable at the moment for this model. Defaults to `cpu`
349
355
 
350
356
  ### Text language detection
351
357
 
@@ -370,7 +376,7 @@ Applies to CLI operation: `detect-voice-activity`, API method: `detectVoiceActiv
370
376
 
371
377
  **Silero**:
372
378
  * `silero.frameDuration`: Silero frame duration (ms). Can be `30`, `60` or `90`. Defaults to `90`
373
- * `silero.provider`: ONNX provider to use. Can be `cpu` or `dml` (Windows only). Using GPU is likely to be slower than CPU due to inference being independently executed on each audio frame. Defaults to `cpu` (recommended)
379
+ * `silero.provider`: ONNX provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Using GPU is likely to be slower than CPU due to inference being independently executed on each audio frame. Defaults to `cpu` (recommended)
374
380
 
375
381
  ## Speech denoising
376
382
 
@@ -395,8 +401,8 @@ Applies to CLI operation: `isolate`, API method: `isolate`
395
401
 
396
402
  **MDX-NET**:
397
403
 
398
- * `mdxNet.model`: model to use. Currently available models are `UVR_MDXNET_1_9703`, `UVR_MDXNET_2_9682`, `UVR_MDXNET_3_9662`, `UVR_MDXNET_KARA`. Defaults to `UVR_MDXNET_1_9703`
399
- * `mdxNet.provider`: ONNX execution provider to use. Can be `cpu` or `dml` ([DirectML](https://microsoft.github.io/DirectML/), Windows only). **Note**: `dml` provider seems to be unstable with MDX-NET models at the moment. Defaults to `cpu`
404
+ * `mdxNet.model`: model to use. Currently available models are `UVR_MDXNET_1_9703`, `UVR_MDXNET_2_9682`, `UVR_MDXNET_3_9662`, `UVR_MDXNET_KARA`, and higher quality models `UVR_MDXNET_Main` and `Kim_Vocal_2`. Defaults to `UVR_MDXNET_1_9703`
405
+ * `mdxNet.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration - Windows only), or `cuda` (Linux only - requires [CUDA Toolkit 12.x](https://developer.nvidia.com/cuda-downloads) and [cuDNN 9.x](https://developer.nvidia.com/cudnn-downloads) to be installed). Defaults to `dml` if available (Windows) or `cpu` (other platforms)
400
406
 
401
407
  # Common options
402
408
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "echogarden",
3
- "version": "1.6.2",
3
+ "version": "1.8.0",
4
4
  "description": "An easy-to-use speech toolset. Includes tools for synthesis, recognition, alignment, speech translation, language detection, source separation and more.",
5
5
  "author": "Rotem Dan",
6
6
  "license": "GPL-3.0",
@@ -46,22 +46,22 @@
46
46
  "LICENSE.md"
47
47
  ],
48
48
  "scripts": {
49
- "cli": "node --experimental-wasi-unstable-preview1 --no-warnings ./dist/cli/CLIStarter.js",
50
- "server": "node --experimental-wasi-unstable-preview1 --no-warnings ./dist/server/ServerStarter.js",
51
49
  "test": "node --experimental-wasi-unstable-preview1 --no-warnings --trace-uncaught ./dist/tests/Test.js",
52
- "generate-options-schema": "npx ts-json-schema-generator --path ./src/api/APIOptions.ts --unstable --type APIOptions --tsconfig ./tsconfig.json --out ./data/schemas/options.json"
50
+ "generate-options-schema": "npx ts-json-schema-generator --path ./src/api/APIOptions.ts --unstable --type APIOptions --tsconfig ./tsconfig.json --out ./data/schemas/options.json",
51
+ "make-tarballs": "node --no-warnings ./dist/build-tools/MakeTarballsForInstalledPackages.js"
53
52
  },
54
53
  "bin": {
55
54
  "echogarden": "./dist/cli/CLILauncher.js"
56
55
  },
57
56
  "dependencies": {
58
- "@aws-sdk/client-polly": "^3.665.0",
59
- "@aws-sdk/client-transcribe-streaming": "^3.665.0",
57
+ "@aws-sdk/client-polly": "^3.669.0",
58
+ "@aws-sdk/client-transcribe-streaming": "^3.669.0",
60
59
  "@echogarden/espeak-ng-emscripten": "^0.1.2",
61
60
  "@echogarden/fasttext-wasm": "^0.1.0",
62
61
  "@echogarden/flite-wasi": "^0.1.1",
63
62
  "@echogarden/fvad-wasm": "^0.1.2",
64
63
  "@echogarden/kissfft-wasm": "^0.1.1",
64
+ "@echogarden/pffft-wasm": "^0.3.0",
65
65
  "@echogarden/rnnoise-wasm": "^0.1.1",
66
66
  "@echogarden/rubberband-wasm": "^0.1.1",
67
67
  "@echogarden/sonic-wasm": "^0.1.1",
@@ -74,14 +74,14 @@
74
74
  "chalk": "^5.3.0",
75
75
  "cldr-segmentation": "^2.2.1",
76
76
  "command-exists": "^1.2.9",
77
- "compromise": "^14.14.1",
77
+ "compromise": "^14.14.2",
78
78
  "fs-extra": "^11.2.0",
79
79
  "gaxios": "^6.7.1",
80
80
  "graceful-fs": "^4.2.11",
81
81
  "html-escaper": "^3.0.3",
82
82
  "html-to-text": "^9.0.5",
83
83
  "import-meta-resolve": "^4.1.0",
84
- "jieba-wasm": "^2.1.1",
84
+ "jieba-wasm": "^2.2.0",
85
85
  "jsdom": "^25.0.1",
86
86
  "json5": "^2.2.3",
87
87
  "kuromoji": "^0.1.2",
@@ -89,7 +89,7 @@
89
89
  "moving-median": "^1.0.0",
90
90
  "msgpack-lite": "^0.1.26",
91
91
  "onnxruntime-node": "^1.19.2",
92
- "openai": "^4.67.1",
92
+ "openai": "^4.67.3",
93
93
  "sam-js": "^0.3.1",
94
94
  "strip-ansi": "^7.1.0",
95
95
  "tar": "^7.4.3",
@@ -116,11 +116,11 @@
116
116
  "@types/graceful-fs": "^4.1.9",
117
117
  "@types/jsdom": "^21.1.7",
118
118
  "@types/msgpack-lite": "^0.1.11",
119
- "@types/node": "^22.7.4",
119
+ "@types/node": "^22.7.5",
120
120
  "@types/recursive-readdir": "^2.2.4",
121
121
  "@types/tar": "^6.1.13",
122
122
  "@types/ws": "^8.5.12",
123
123
  "ts-json-schema-generator": "^2.3.0",
124
- "typescript": "^5.6.2"
124
+ "typescript": "^5.6.3"
125
125
  }
126
126
  }
@@ -589,7 +589,7 @@ export async function createAlignmentReferenceUsingEspeakForFragments(fragments:
589
589
  {
590
590
  // Split fragments to chunks, process each chunk individually,
591
591
  // and incrementally merge the chunks to the final result.
592
-
592
+
593
593
  const maxCharactersInChunk = 1000
594
594
 
595
595
  let timeOffset = 0
@@ -1,7 +1,7 @@
1
1
  import { extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
3
  import { logToStderr } from '../utilities/Utilities.js'
4
- import { AudioSourceParam, RawAudio, ensureRawAudio, getRawAudioDuration, normalizeAudioLevel, trimAudioEnd } from '../audio/AudioUtilities.js'
4
+ import { AudioSourceParam, RawAudio, ensureRawAudio, getRawAudioDuration, normalizeAudioLevelInPlace, trimAudioEnd } from '../audio/AudioUtilities.js'
5
5
  import { Logger } from '../utilities/Logger.js'
6
6
 
7
7
  import * as API from './API.js'
@@ -56,7 +56,7 @@ export async function align(input: AudioSourceParam, transcript: string, options
56
56
 
57
57
  logger.start('Normalize and trim audio')
58
58
 
59
- sourceRawAudio = normalizeAudioLevel(sourceRawAudio)
59
+ normalizeAudioLevelInPlace(sourceRawAudio)
60
60
  sourceRawAudio.audioChannels[0] = trimAudioEnd(sourceRawAudio.audioChannels[0])
61
61
 
62
62
  logger.end()
@@ -1,6 +1,6 @@
1
1
  import { extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
- import { AudioSourceParam, RawAudio, applyGainDecibels, ensureRawAudio, getSamplePeakDecibels, mixAudio, normalizeAudioLevel } from '../audio/AudioUtilities.js'
3
+ import { AudioSourceParam, RawAudio, applyGainDecibelsInPlace, ensureRawAudio, getSamplePeakDecibels, mixAudio, normalizeAudioLevelInPlace } from '../audio/AudioUtilities.js'
4
4
  import { Logger } from '../utilities/Logger.js'
5
5
 
6
6
  import { logToStderr } from '../utilities/Utilities.js'
@@ -59,13 +59,14 @@ export async function denoise(input: AudioSourceParam, options: DenoisingOptions
59
59
  const dryMixGainDecibels = options.postProcessing!.dryMixGain!
60
60
 
61
61
  const preMixPeakDecibels = getSamplePeakDecibels(denoisedAudio.audioChannels)
62
- denoisedAudio = mixAudio(denoisedAudio, applyGainDecibels(resampledRawAudio, dryMixGainDecibels))
62
+ applyGainDecibelsInPlace(resampledRawAudio, dryMixGainDecibels)
63
+ denoisedAudio = mixAudio(denoisedAudio, resampledRawAudio)
63
64
  const postMixPeakDecibels = getSamplePeakDecibels(denoisedAudio.audioChannels)
64
65
 
65
66
  if (shouldNormalize) {
66
- denoisedAudio = normalizeAudioLevel(denoisedAudio, targetPeakDecibels, maxGainIncreaseDecibels)
67
+ normalizeAudioLevelInPlace(denoisedAudio, targetPeakDecibels, maxGainIncreaseDecibels)
67
68
  } else {
68
- denoisedAudio = applyGainDecibels(denoisedAudio, preMixPeakDecibels - postMixPeakDecibels)
69
+ applyGainDecibelsInPlace(denoisedAudio, preMixPeakDecibels - postMixPeakDecibels)
69
70
  }
70
71
 
71
72
  logger.end()
@@ -1,7 +1,7 @@
1
1
  import { extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
3
  import { logToStderr } from '../utilities/Utilities.js'
4
- import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevel, trimAudioEnd } from '../audio/AudioUtilities.js'
4
+ import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace, trimAudioEnd } from '../audio/AudioUtilities.js'
5
5
  import { Logger } from '../utilities/Logger.js'
6
6
 
7
7
  import * as API from './API.js'
@@ -59,7 +59,7 @@ export async function recognize(input: AudioSourceParam, options: RecognitionOpt
59
59
 
60
60
  logger.start('Normalize and trim audio')
61
61
 
62
- sourceRawAudio = normalizeAudioLevel(sourceRawAudio)
62
+ normalizeAudioLevelInPlace(sourceRawAudio)
63
63
  sourceRawAudio.audioChannels[0] = trimAudioEnd(sourceRawAudio.audioChannels[0])
64
64
 
65
65
  const engine = options.engine!
@@ -322,7 +322,7 @@ export interface RecognitionResult {
322
322
 
323
323
  timeline: Timeline
324
324
  wordTimeline: Timeline
325
-
325
+
326
326
  language: string
327
327
 
328
328
  inputRawAudio: RawAudio
@@ -1,4 +1,4 @@
1
- import { AudioSourceParam, RawAudio, ensureRawAudio, subtractAudio } from '../audio/AudioUtilities.js';
1
+ import { AudioSourceParam, RawAudio, attenuateIfClippingInPlace, ensureRawAudio, subtractAudio } from '../audio/AudioUtilities.js';
2
2
  import { Logger } from '../utilities/Logger.js';
3
3
  import { extendDeep } from '../utilities/ObjectUtilities.js';
4
4
  import { loadPackage } from '../utilities/PackageManager.js';
@@ -6,13 +6,13 @@ import { EngineMetadata } from './Common.js';
6
6
  import chalk from 'chalk';
7
7
  import { readdir } from '../utilities/FileSystem.js';
8
8
  import path from 'node:path';
9
- import { OnnxExecutionProvider } from '../utilities/OnnxUtilities.js';
9
+ import { defaultMDXNetOptions, getProfileForMDXNetModelName, MDXNetOptions } from '../source-separation/MDXNetSourceSeparation.js';
10
10
 
11
11
  export async function isolate(input: AudioSourceParam, options: SourceSeparationOptions): Promise<SourceSeparationResult> {
12
12
  const logger = new Logger()
13
13
  const startTimestamp = logger.getTimestamp()
14
14
 
15
- logger.start('Prepare for source separation')
15
+ await logger.startAsync('Prepare for source separation')
16
16
 
17
17
  const inputRawAudio = await ensureRawAudio(input)
18
18
 
@@ -27,8 +27,6 @@ export async function isolate(input: AudioSourceParam, options: SourceSeparation
27
27
 
28
28
  const mdxNetOptions = options.mdxNet!
29
29
 
30
- const executionProviders: OnnxExecutionProvider[] = mdxNetOptions.executionProvider ? [mdxNetOptions.executionProvider] : []
31
-
32
30
  const packageDir = await loadPackage(`mdxnet-${mdxNetOptions.model!}`)
33
31
  const modelFilename = (await readdir(packageDir)).filter(name => name.endsWith('onnx'))[0]
34
32
 
@@ -38,16 +36,20 @@ export async function isolate(input: AudioSourceParam, options: SourceSeparation
38
36
 
39
37
  const modelPath = path.join(packageDir, modelFilename)
40
38
 
39
+ await logger.startAsync(`Convert audio to 44.1 kHz stereo`)
40
+
41
+ const inputRawAudio44100Stereo = await ensureRawAudio(inputRawAudio, 44100, 2)
42
+
41
43
  logger.end()
42
44
 
43
- const audioStereo44100 = await ensureRawAudio(inputRawAudio, 44100, 2)
45
+ const modelProfile = getProfileForMDXNetModelName(mdxNetOptions.model!)
44
46
 
45
- isolatedRawAudio = await MDXNetSourceSeparation.isolate(audioStereo44100, modelPath, executionProviders)
47
+ isolatedRawAudio = await MDXNetSourceSeparation.isolate(inputRawAudio44100Stereo, modelPath, modelProfile, mdxNetOptions)
46
48
 
47
49
  logger.end()
48
50
 
49
- logger.start(`Subtract from original waveform to extract background audio`)
50
- backgroundRawAudio = subtractAudio(audioStereo44100, isolatedRawAudio)
51
+ await logger.startAsync(`Subtract from original waveform to extract background audio`)
52
+ backgroundRawAudio = subtractAudio(inputRawAudio44100Stereo, isolatedRawAudio)
51
53
 
52
54
  break
53
55
  }
@@ -57,8 +59,13 @@ export async function isolate(input: AudioSourceParam, options: SourceSeparation
57
59
  }
58
60
  }
59
61
 
62
+ await logger.startAsync(`Postprocess audio`)
63
+
64
+ attenuateIfClippingInPlace(isolatedRawAudio)
65
+ attenuateIfClippingInPlace(backgroundRawAudio)
66
+
60
67
  logger.end()
61
- logger.log('')
68
+
62
69
  logger.logDuration(`Total source separation time`, startTimestamp, chalk.magentaBright)
63
70
 
64
71
  return {
@@ -73,19 +80,13 @@ export type SourceSeparationEngine = 'mdx-net'
73
80
  export interface SourceSeparationOptions {
74
81
  engine?: SourceSeparationEngine
75
82
 
76
- mdxNet?: {
77
- model?: string
78
- executionProvider?: OnnxExecutionProvider
79
- }
83
+ mdxNet?: MDXNetOptions
80
84
  }
81
85
 
82
86
  export const defaultSourceSeparationOptions: SourceSeparationOptions = {
83
87
  engine: 'mdx-net',
84
88
 
85
- mdxNet: {
86
- model: 'UVR_MDXNET_1_9703',
87
- executionProvider: undefined,
88
- }
89
+ mdxNet: defaultMDXNetOptions,
89
90
  }
90
91
 
91
92
  export interface SourceSeparationResult {
@@ -98,7 +99,7 @@ export const sourceSeparationEngines: EngineMetadata[] = [
98
99
  {
99
100
  id: 'mdx-net',
100
101
  name: 'MDX-NET',
101
- description: 'Deep learning source separation architecture by KUIELAB (Korea University).',
102
+ description: 'Deep learning audio source separation architecture by KUIELAB (Korea University).',
102
103
  type: 'local'
103
104
  },
104
105
  ]
@@ -1,6 +1,6 @@
1
1
  import { deepClone, extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
- import { AudioSourceParam, RawAudio, ensureRawAudio, getRawAudioDuration, normalizeAudioLevel, sliceRawAudioByTime, trimAudioEnd } from '../audio/AudioUtilities.js'
3
+ import { AudioSourceParam, RawAudio, ensureRawAudio, getRawAudioDuration, normalizeAudioLevelInPlace, sliceRawAudioByTime, trimAudioEnd } from '../audio/AudioUtilities.js'
4
4
  import { Logger } from '../utilities/Logger.js'
5
5
 
6
6
  import * as API from './API.js'
@@ -28,7 +28,7 @@ export async function detectSpeechLanguage(input: AudioSourceParam, options: Spe
28
28
 
29
29
  logger.start(`Resample audio to 16kHz mono`)
30
30
  let sourceRawAudio = await ensureRawAudio(inputRawAudio, 16000, 1)
31
- sourceRawAudio = normalizeAudioLevel(sourceRawAudio)
31
+ normalizeAudioLevelInPlace(sourceRawAudio)
32
32
  sourceRawAudio.audioChannels[0] = trimAudioEnd(sourceRawAudio.audioChannels[0])
33
33
 
34
34
  if (options.crop) {
@@ -1,7 +1,7 @@
1
1
  import { extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
3
  import { logToStderr } from '../utilities/Utilities.js'
4
- import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevel, trimAudioEnd } from '../audio/AudioUtilities.js'
4
+ import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace, trimAudioEnd } from '../audio/AudioUtilities.js'
5
5
  import { Logger } from '../utilities/Logger.js'
6
6
 
7
7
  import { Timeline, addWordTextOffsetsToTimeline, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
@@ -61,7 +61,7 @@ export async function translateSpeech(input: AudioSourceParam, options: SpeechTr
61
61
 
62
62
  logger.start('Normalize and trim audio')
63
63
 
64
- sourceRawAudio = normalizeAudioLevel(sourceRawAudio)
64
+ normalizeAudioLevelInPlace(sourceRawAudio)
65
65
  sourceRawAudio.audioChannels[0] = trimAudioEnd(sourceRawAudio.audioChannels[0])
66
66
 
67
67
  if (options.sourceLanguage) {
@@ -4,8 +4,8 @@ import { deepClone, extendDeep } from '../utilities/ObjectUtilities.js'
4
4
 
5
5
  import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
6
6
 
7
- import { clip, convertHtmlToText, sha256AsHex, simplifyPunctuationCharacters, stringifyAndFormatJson, logToStderr, yieldToEventLoop, runOperationWithRetries } from '../utilities/Utilities.js'
8
- import { RawAudio, attenuateIfClipping, concatAudioSegments, downmixToMono, encodeRawAudioToWave, getSamplePeakDecibels, getEmptyRawAudio, getRawAudioDuration, normalizeAudioLevel, trimAudioEnd, trimAudioStart } from '../audio/AudioUtilities.js'
7
+ import { clip, sha256AsHex, stringifyAndFormatJson, logToStderr, yieldToEventLoop, runOperationWithRetries } from '../utilities/Utilities.js'
8
+ import { RawAudio, concatAudioSegments, downmixToMono, encodeRawAudioToWave, getSamplePeakDecibels, getEmptyRawAudio, getRawAudioDuration, trimAudioEnd, trimAudioStart, attenuateIfClippingInPlace, normalizeAudioLevelInPlace } from '../audio/AudioUtilities.js'
9
9
  import { Logger } from '../utilities/Logger.js'
10
10
 
11
11
  import { isWordOrSymbolWord, splitToParagraphs, splitToSentences } from '../nlp/Segmentation.js'
@@ -25,6 +25,8 @@ import { type EspeakOptions } from '../synthesis/EspeakTTS.js'
25
25
  import { type OpenAICloudTTSOptions } from '../synthesis/OpenAICloudTTS.js'
26
26
  import { type ElevenlabsTTSOptions } from '../synthesis/ElevenlabsTTS.js'
27
27
  import { OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
28
+ import { simplifyPunctuationCharacters } from '../nlp/TextNormalizer.js'
29
+ import { convertHtmlToText } from '../utilities/StringUtilities.js'
28
30
 
29
31
  const log = logToStderr
30
32
 
@@ -248,9 +250,9 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
248
250
  resultRawAudio = { audioChannels: joinedAudioBuffers, sampleRate: segmentsRawAudio[0].sampleRate }
249
251
 
250
252
  if (options.postProcessing!.normalizeAudio) {
251
- resultRawAudio = normalizeAudioLevel(resultRawAudio, options.postProcessing!.targetPeak, options.postProcessing!.maxGainIncrease)
253
+ normalizeAudioLevelInPlace(resultRawAudio, options.postProcessing!.targetPeak, options.postProcessing!.maxGainIncrease)
252
254
  } else {
253
- resultRawAudio = attenuateIfClipping(resultRawAudio)
255
+ attenuateIfClippingInPlace(resultRawAudio)
254
256
  }
255
257
  } else {
256
258
  resultRawAudio = getEmptyRawAudio(1, 24000)
@@ -864,9 +866,9 @@ async function synthesizeSegment(text: string, options: SynthesisOptions) {
864
866
  synthesizedAudio = downmixToMono(synthesizedAudio)
865
867
 
866
868
  if (options.postProcessing!.normalizeAudio) {
867
- synthesizedAudio = normalizeAudioLevel(synthesizedAudio, options.postProcessing!.targetPeak!, options.postProcessing!.maxGainIncrease!)
869
+ normalizeAudioLevelInPlace(synthesizedAudio, options.postProcessing!.targetPeak!, options.postProcessing!.maxGainIncrease!)
868
870
  } else {
869
- synthesizedAudio = attenuateIfClipping(synthesizedAudio)
871
+ attenuateIfClippingInPlace(synthesizedAudio)
870
872
  }
871
873
 
872
874
  const preTrimSampleCount = synthesizedAudio.audioChannels[0].length
@@ -3,6 +3,7 @@ import { formatLanguageCodeWithName, normalizeIdentifierToLanguageCode, parseLan
3
3
  import { Logger } from '../utilities/Logger.js'
4
4
  import { extendDeep } from '../utilities/ObjectUtilities.js'
5
5
  import * as API from './API.js'
6
+ import { defaultGoogleTranslateTextTranslationOptions, type GoogleTranslateTextTranslationOptions } from '../text-translation/GoogleTranslateTextTranslation.js'
6
7
 
7
8
  export async function translateText(inputText: string, options: TextTranslationOptions): Promise<TextTranslationResult> {
8
9
  const logger = new Logger()
@@ -43,7 +44,7 @@ export async function translateText(inputText: string, options: TextTranslationO
43
44
 
44
45
  logger.end()
45
46
 
46
- logger.logTitledMessage(`Warning`, `The nllb engine is currently an early prototype implementation and doesn't work correctly.`, chalk.yellow, 'warning')
47
+ logger.logTitledMessage(`Warning`, `The nllb text translation engine is currently a work-in-progress and doesn't work correctly.`, chalk.yellow, 'warning')
47
48
 
48
49
  translationPairs = await NLLBTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage)
49
50
 
@@ -63,9 +64,11 @@ export async function translateText(inputText: string, options: TextTranslationO
63
64
  case 'google-translate': {
64
65
  const GoogleTranslateTextTranslation = await import('../text-translation/GoogleTranslateTextTranslation.js')
65
66
 
67
+ const googleTranslateOptions = options.googleTranslate!
68
+
66
69
  logger.end();
67
70
 
68
- ({ translationPairs, translatedText } = await GoogleTranslateTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage))
71
+ ({ translationPairs, translatedText } = await GoogleTranslateTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage, options.plainText!, googleTranslateOptions))
69
72
 
70
73
  break
71
74
  }
@@ -75,7 +78,7 @@ export async function translateText(inputText: string, options: TextTranslationO
75
78
 
76
79
  logger.end()
77
80
 
78
- logger.logTitledMessage(`Warning`, `The deepl engine is currently an early prototype implementation and doesn't work correctly.`, chalk.yellow, 'warning')
81
+ logger.logTitledMessage(`Warning`, `The deepl text translation engine is currently a work-in-progress and doesn't work correctly.`, chalk.yellow, 'warning')
79
82
 
80
83
  translationPairs = await DeepLTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage)
81
84
  translatedText = ''
@@ -113,11 +116,12 @@ export interface TextTranslationOptions {
113
116
 
114
117
  languageDetection?: API.TextLanguageDetectionOptions
115
118
 
119
+ plainText?: API.PlainTextOptions
120
+
116
121
  nllb?: {
117
122
  },
118
123
 
119
- googleTranslate?: {
120
- },
124
+ googleTranslate?: GoogleTranslateTextTranslationOptions,
121
125
 
122
126
  deepl?: {
123
127
  },
@@ -148,12 +152,16 @@ export const defaultTextTranslationOptions: TextTranslationOptions = {
148
152
 
149
153
  languageDetection: undefined,
150
154
 
151
- nllb: {
155
+ plainText: {
156
+ paragraphBreaks: 'double',
157
+ whitespace: 'preserve'
152
158
  },
153
159
 
154
- googleTranslate: {
160
+ nllb: {
155
161
  },
156
162
 
163
+ googleTranslate: defaultGoogleTranslateTextTranslationOptions,
164
+
157
165
  deepl: {
158
166
  },
159
167
  }
@@ -162,7 +170,7 @@ export const textTranslationEngines: API.EngineMetadata[] = [
162
170
  {
163
171
  id: 'nllb',
164
172
  name: 'NLLB',
165
- description: 'No Language Left Behind (NLLB) is a deep learning machine translation model by Facebook Research (early prototype implementation).',
173
+ description: 'No Language Left Behind (NLLB) is a deep learning machine translation model by Facebook Research (work-in-progress, do not use).',
166
174
  type: 'local'
167
175
  },
168
176
  {
@@ -174,7 +182,7 @@ export const textTranslationEngines: API.EngineMetadata[] = [
174
182
  {
175
183
  id: 'deepl',
176
184
  name: 'DeepL',
177
- description: 'Unoffical text translation API used by the DeepL web interface (early prototype implementation).',
185
+ description: 'Unoffical text translation API used by the DeepL web interface (work-in-progress, do not use).',
178
186
  type: 'cloud'
179
187
  },
180
188
  ]
@@ -1,7 +1,7 @@
1
1
  import { extendDeep } from '../utilities/ObjectUtilities.js'
2
2
 
3
3
  import { logToStderr } from '../utilities/Utilities.js'
4
- import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevel, trimAudioEnd } from '../audio/AudioUtilities.js'
4
+ import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace, trimAudioEnd } from '../audio/AudioUtilities.js'
5
5
  import { Logger } from '../utilities/Logger.js'
6
6
 
7
7
  import * as API from './API.js'
@@ -53,7 +53,7 @@ export async function alignTranslation(input: AudioSourceParam, translatedTransc
53
53
 
54
54
  logger.start('Normalize and trim audio')
55
55
 
56
- sourceRawAudio = normalizeAudioLevel(sourceRawAudio)
56
+ normalizeAudioLevelInPlace(sourceRawAudio)
57
57
  sourceRawAudio.audioChannels[0] = trimAudioEnd(sourceRawAudio.audioChannels[0])
58
58
 
59
59
  logger.end()