echogarden 1.8.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/README.md +23 -18
  2. package/data/schemas/options.json +52 -47
  3. package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
  4. package/dist/alignment/DTWSequenceAlignment.js +5 -5
  5. package/dist/alignment/DTWSequenceAlignment.js.map +1 -1
  6. package/dist/alignment/SpeechAlignment.js +6 -6
  7. package/dist/alignment/SpeechAlignment.js.map +1 -1
  8. package/dist/api/Alignment.d.ts +1 -1
  9. package/dist/api/Alignment.js +49 -11
  10. package/dist/api/Alignment.js.map +1 -1
  11. package/dist/api/Denoising.d.ts +4 -2
  12. package/dist/api/Denoising.js +65 -13
  13. package/dist/api/Denoising.js.map +1 -1
  14. package/dist/api/SourceSeparation.js +9 -6
  15. package/dist/api/SourceSeparation.js.map +1 -1
  16. package/dist/api/SpeechLanguageDetection.js +4 -4
  17. package/dist/api/SpeechLanguageDetection.js.map +1 -1
  18. package/dist/api/Synthesis.d.ts +2 -2
  19. package/dist/api/Synthesis.js +10 -7
  20. package/dist/api/Synthesis.js.map +1 -1
  21. package/dist/api/VoiceActivityDetection.js +2 -2
  22. package/dist/api/VoiceActivityDetection.js.map +1 -1
  23. package/dist/audio/AudioBufferConversion.d.ts +2 -2
  24. package/dist/audio/AudioBufferConversion.js +77 -43
  25. package/dist/audio/AudioBufferConversion.js.map +1 -1
  26. package/dist/audio/AudioPlayer.d.ts +7 -5
  27. package/dist/audio/AudioPlayer.js +135 -49
  28. package/dist/audio/AudioPlayer.js.map +1 -1
  29. package/dist/audio/AudioUtilities.d.ts +4 -3
  30. package/dist/audio/AudioUtilities.js +30 -15
  31. package/dist/audio/AudioUtilities.js.map +1 -1
  32. package/dist/audio/SoxPath.js +3 -3
  33. package/dist/audio/SoxPath.js.map +1 -1
  34. package/dist/build-tools/MakeTarballsForInstalledPackages.js +3 -3
  35. package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -1
  36. package/dist/cli/CLI.js +30 -36
  37. package/dist/cli/CLI.js.map +1 -1
  38. package/dist/cli/CLIConfigFile.js +2 -2
  39. package/dist/cli/CLIConfigFile.js.map +1 -1
  40. package/dist/cli/CLIOptions.d.ts +2 -0
  41. package/dist/cli/CLIOptions.js +1 -1
  42. package/dist/cli/CLIOptions.js.map +1 -1
  43. package/dist/codecs/FFMpegTranscoder.d.ts +3 -3
  44. package/dist/codecs/FFMpegTranscoder.js +6 -6
  45. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  46. package/dist/codecs/TIMITCodec.d.ts +1 -1
  47. package/dist/codecs/TIMITCodec.js +4 -3
  48. package/dist/codecs/TIMITCodec.js.map +1 -1
  49. package/dist/codecs/WaveCodec.d.ts +3 -3
  50. package/dist/codecs/WaveCodec.js +37 -34
  51. package/dist/codecs/WaveCodec.js.map +1 -1
  52. package/dist/data-structures/DynamicTypedArray.d.ts +17 -0
  53. package/dist/data-structures/DynamicTypedArray.js +47 -0
  54. package/dist/data-structures/DynamicTypedArray.js.map +1 -0
  55. package/dist/data-structures/Queue.js.map +1 -0
  56. package/dist/data-structures/WindowedList.js.map +1 -0
  57. package/dist/denoising/NSNet2.d.ts +26 -0
  58. package/dist/denoising/NSNet2.js +128 -0
  59. package/dist/denoising/NSNet2.js.map +1 -0
  60. package/dist/denoising/RNNoise.js +3 -3
  61. package/dist/denoising/RNNoise.js.map +1 -1
  62. package/dist/dsp/FFT.d.ts +6 -1
  63. package/dist/dsp/FFT.js +17 -0
  64. package/dist/dsp/FFT.js.map +1 -1
  65. package/dist/encodings/Ascii.d.ts +10 -0
  66. package/dist/encodings/Ascii.js +41 -0
  67. package/dist/encodings/Ascii.js.map +1 -0
  68. package/dist/encodings/Base64.d.ts +5 -0
  69. package/dist/encodings/Base64.js +114 -0
  70. package/dist/encodings/Base64.js.map +1 -0
  71. package/dist/encodings/Hex.d.ts +3 -0
  72. package/dist/encodings/Hex.js +52 -0
  73. package/dist/encodings/Hex.js.map +1 -0
  74. package/dist/{utilities → encodings}/LEB128.d.ts +1 -1
  75. package/dist/{utilities → encodings}/LEB128.js +4 -4
  76. package/dist/encodings/LEB128.js.map +1 -0
  77. package/dist/{utilities → encodings}/LPVarInt.d.ts +1 -1
  78. package/dist/{utilities → encodings}/LPVarInt.js +6 -6
  79. package/dist/encodings/LPVarInt.js.map +1 -0
  80. package/dist/encodings/TextEncodingsCommon.d.ts +4 -0
  81. package/dist/encodings/TextEncodingsCommon.js +2 -0
  82. package/dist/encodings/TextEncodingsCommon.js.map +1 -0
  83. package/dist/encodings/Utf16.d.ts +10 -0
  84. package/dist/encodings/Utf16.js +36 -0
  85. package/dist/encodings/Utf16.js.map +1 -0
  86. package/dist/encodings/Utf32.d.ts +9 -0
  87. package/dist/encodings/Utf32.js +44 -0
  88. package/dist/encodings/Utf32.js.map +1 -0
  89. package/dist/encodings/Utf8.d.ts +10 -0
  90. package/dist/encodings/Utf8.js +97 -0
  91. package/dist/encodings/Utf8.js.map +1 -0
  92. package/dist/math/MedianFilter.js.map +1 -1
  93. package/dist/nlp/JapaneseSegmentation.js +2 -2
  94. package/dist/nlp/JapaneseSegmentation.js.map +1 -1
  95. package/dist/recognition/GoogleCloudSTT.js +2 -1
  96. package/dist/recognition/GoogleCloudSTT.js.map +1 -1
  97. package/dist/recognition/SileroSTT.js +3 -3
  98. package/dist/recognition/SileroSTT.js.map +1 -1
  99. package/dist/recognition/VoskSTT.js +3 -3
  100. package/dist/recognition/VoskSTT.js.map +1 -1
  101. package/dist/recognition/WhisperCppSTT.js +4 -5
  102. package/dist/recognition/WhisperCppSTT.js.map +1 -1
  103. package/dist/recognition/WhisperSTT.js +8 -7
  104. package/dist/recognition/WhisperSTT.js.map +1 -1
  105. package/dist/server/Client.d.ts +1 -1
  106. package/dist/server/Client.js +2 -1
  107. package/dist/server/Client.js.map +1 -1
  108. package/dist/server/Server.js +5 -4
  109. package/dist/server/Server.js.map +1 -1
  110. package/dist/server/Worker.js +1 -1
  111. package/dist/server/Worker.js.map +1 -1
  112. package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
  113. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  114. package/dist/speech-search/DTWSpeechSearch.d.ts +1 -1
  115. package/dist/speech-search/DTWSpeechSearch.js +25 -6
  116. package/dist/speech-search/DTWSpeechSearch.js.map +1 -1
  117. package/dist/subtitles/Subtitles.js +2 -2
  118. package/dist/subtitles/Subtitles.js.map +1 -1
  119. package/dist/synthesis/AzureCognitiveServicesTTS.js +17 -18
  120. package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
  121. package/dist/synthesis/CoquiServerTTS.js +1 -1
  122. package/dist/synthesis/CoquiServerTTS.js.map +1 -1
  123. package/dist/synthesis/ElevenlabsTTS.js +1 -1
  124. package/dist/synthesis/ElevenlabsTTS.js.map +1 -1
  125. package/dist/synthesis/EspeakTTS.d.ts +0 -1
  126. package/dist/synthesis/EspeakTTS.js +0 -9
  127. package/dist/synthesis/EspeakTTS.js.map +1 -1
  128. package/dist/synthesis/FliteTTS.js +7 -8
  129. package/dist/synthesis/FliteTTS.js.map +1 -1
  130. package/dist/synthesis/GoogleCloudTTS.d.ts +1 -1
  131. package/dist/synthesis/GoogleCloudTTS.js +2 -1
  132. package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
  133. package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
  134. package/dist/synthesis/GoogleTranslateTTS.js +4 -3
  135. package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
  136. package/dist/synthesis/MicrosoftEdgeTTS.js +32 -7
  137. package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
  138. package/dist/synthesis/SapiTTS.js +1 -1
  139. package/dist/synthesis/SapiTTS.js.map +1 -1
  140. package/dist/synthesis/StreamlabsPollyTTS.d.ts +1 -1
  141. package/dist/synthesis/StreamlabsPollyTTS.js +1 -1
  142. package/dist/synthesis/StreamlabsPollyTTS.js.map +1 -1
  143. package/dist/synthesis/SvoxPicoTTS.js +6 -6
  144. package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
  145. package/dist/synthesis/VitsTTS.js +2 -2
  146. package/dist/synthesis/VitsTTS.js.map +1 -1
  147. package/dist/tests/Test.js +1 -47
  148. package/dist/tests/Test.js.map +1 -1
  149. package/dist/text-language-detection/FastTextLanguageDetection.js +2 -2
  150. package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
  151. package/dist/typings/TypedArray.d.ts +4 -0
  152. package/dist/typings/TypedArray.js +2 -0
  153. package/dist/typings/TypedArray.js.map +1 -0
  154. package/dist/utilities/BinaryArrayConversion.d.ts +12 -22
  155. package/dist/utilities/BinaryArrayConversion.js +40 -90
  156. package/dist/utilities/BinaryArrayConversion.js.map +1 -1
  157. package/dist/utilities/BinaryUtilities.d.ts +13 -0
  158. package/dist/utilities/BinaryUtilities.js +113 -0
  159. package/dist/utilities/BinaryUtilities.js.map +1 -0
  160. package/dist/utilities/Compression.js +7 -6
  161. package/dist/utilities/Compression.js.map +1 -1
  162. package/dist/utilities/FileDownloader.js +26 -47
  163. package/dist/utilities/FileDownloader.js.map +1 -1
  164. package/dist/utilities/FileReader.d.ts +14 -0
  165. package/dist/utilities/FileReader.js +71 -0
  166. package/dist/utilities/FileReader.js.map +1 -0
  167. package/dist/utilities/FileSystem.d.ts +19 -16
  168. package/dist/utilities/FileSystem.js +170 -109
  169. package/dist/utilities/FileSystem.js.map +1 -1
  170. package/dist/utilities/FileWriter.d.ts +12 -0
  171. package/dist/utilities/FileWriter.js +60 -0
  172. package/dist/utilities/FileWriter.js.map +1 -0
  173. package/dist/utilities/NpmUtilities.d.ts +1 -0
  174. package/dist/utilities/NpmUtilities.js +14 -0
  175. package/dist/utilities/NpmUtilities.js.map +1 -0
  176. package/dist/utilities/PackageManager.js +7 -5
  177. package/dist/utilities/PackageManager.js.map +1 -1
  178. package/dist/utilities/PathUtilities.d.ts +8 -0
  179. package/dist/utilities/PathUtilities.js +28 -7
  180. package/dist/utilities/PathUtilities.js.map +1 -1
  181. package/dist/utilities/SignalChannel.d.ts +3 -1
  182. package/dist/utilities/SignalChannel.js +9 -5
  183. package/dist/utilities/SignalChannel.js.map +1 -1
  184. package/dist/utilities/StringBuilder.d.ts +10 -0
  185. package/dist/utilities/StringBuilder.js +39 -0
  186. package/dist/utilities/StringBuilder.js.map +1 -0
  187. package/dist/utilities/StringUtilities.js.map +1 -1
  188. package/dist/utilities/TarballMaker.js +6 -7
  189. package/dist/utilities/TarballMaker.js.map +1 -1
  190. package/dist/utilities/Timer.js +2 -2
  191. package/dist/utilities/Timer.js.map +1 -1
  192. package/dist/utilities/Utilities.d.ts +11 -5
  193. package/dist/utilities/Utilities.js +69 -33
  194. package/dist/utilities/Utilities.js.map +1 -1
  195. package/dist/utilities/VirtualFileReadStream.d.ts +3 -3
  196. package/dist/utilities/VirtualFileReadStream.js.map +1 -1
  197. package/dist/utilities/WasmMemoryManager.d.ts +5 -2
  198. package/dist/utilities/WasmMemoryManager.js +15 -4
  199. package/dist/utilities/WasmMemoryManager.js.map +1 -1
  200. package/docs/API.md +1 -1
  201. package/docs/Licenses.md +3 -0
  202. package/docs/Options.md +9 -3
  203. package/docs/Tasklist.md +0 -1
  204. package/docs/Technical.md +2 -2
  205. package/package.json +20 -22
  206. package/src/alignment/DTWSequenceAlignment.ts +5 -5
  207. package/src/alignment/SpeechAlignment.ts +6 -6
  208. package/src/api/Alignment.ts +65 -12
  209. package/src/api/Denoising.ts +97 -17
  210. package/src/api/SourceSeparation.ts +11 -8
  211. package/src/api/SpeechLanguageDetection.ts +4 -4
  212. package/src/api/Synthesis.ts +15 -11
  213. package/src/api/VoiceActivityDetection.ts +2 -2
  214. package/src/audio/AudioBufferConversion.ts +84 -45
  215. package/src/audio/AudioPlayer.ts +155 -53
  216. package/src/audio/AudioUtilities.ts +38 -22
  217. package/src/audio/SoxPath.ts +3 -3
  218. package/src/build-tools/MakeTarballsForInstalledPackages.ts +3 -3
  219. package/src/cli/CLI.ts +30 -36
  220. package/src/cli/CLIConfigFile.ts +2 -2
  221. package/src/cli/CLIOptions.ts +4 -1
  222. package/src/codecs/FFMpegTranscoder.ts +11 -11
  223. package/src/codecs/TIMITCodec.ts +5 -4
  224. package/src/codecs/WaveCodec.ts +42 -39
  225. package/src/data-structures/DynamicTypedArray.ts +64 -0
  226. package/src/denoising/NSNet2.ts +182 -0
  227. package/src/denoising/RNNoise.ts +3 -3
  228. package/src/dsp/FFT.ts +21 -1
  229. package/src/encodings/Ascii.ts +60 -0
  230. package/src/encodings/Base64.ts +157 -0
  231. package/src/encodings/Hex.ts +67 -0
  232. package/src/{utilities → encodings}/LEB128.ts +4 -4
  233. package/src/{utilities → encodings}/LPVarInt.ts +6 -6
  234. package/src/encodings/TextEncodingsCommon.ts +4 -0
  235. package/src/encodings/Utf16.ts +52 -0
  236. package/src/encodings/Utf32.ts +62 -0
  237. package/src/encodings/Utf8.ts +117 -0
  238. package/src/math/MedianFilter.ts +0 -2
  239. package/src/nlp/JapaneseSegmentation.ts +2 -2
  240. package/src/recognition/GoogleCloudSTT.ts +2 -1
  241. package/src/recognition/SileroSTT.ts +3 -3
  242. package/src/recognition/VoskSTT.ts +3 -3
  243. package/src/recognition/WhisperCppSTT.ts +4 -5
  244. package/src/recognition/WhisperSTT.ts +8 -7
  245. package/src/server/Client.ts +4 -3
  246. package/src/server/Server.ts +6 -5
  247. package/src/server/Worker.ts +1 -1
  248. package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
  249. package/src/speech-search/DTWSpeechSearch.ts +36 -7
  250. package/src/subtitles/Subtitles.ts +3 -3
  251. package/src/synthesis/AzureCognitiveServicesTTS.ts +18 -15
  252. package/src/synthesis/CoquiServerTTS.ts +2 -2
  253. package/src/synthesis/ElevenlabsTTS.ts +1 -1
  254. package/src/synthesis/EspeakTTS.ts +0 -15
  255. package/src/synthesis/FliteTTS.ts +7 -8
  256. package/src/synthesis/GoogleCloudTTS.ts +3 -2
  257. package/src/synthesis/GoogleTranslateTTS.ts +5 -4
  258. package/src/synthesis/MicrosoftEdgeTTS.ts +47 -15
  259. package/src/synthesis/SapiTTS.ts +1 -1
  260. package/src/synthesis/StreamlabsPollyTTS.ts +1 -1
  261. package/src/synthesis/SvoxPicoTTS.ts +8 -8
  262. package/src/synthesis/VitsTTS.ts +2 -2
  263. package/src/tests/Test.ts +1 -60
  264. package/src/text-language-detection/FastTextLanguageDetection.ts +2 -2
  265. package/src/typings/Fillers.d.ts +2 -4
  266. package/src/typings/TypedArray.ts +5 -0
  267. package/src/utilities/BinaryArrayConversion.ts +51 -125
  268. package/src/utilities/BinaryUtilities.ts +138 -0
  269. package/src/utilities/Compression.ts +7 -6
  270. package/src/utilities/FileDownloader.ts +27 -52
  271. package/src/utilities/FileReader.ts +89 -0
  272. package/src/utilities/FileSystem.ts +213 -120
  273. package/src/utilities/FileWriter.ts +72 -0
  274. package/src/utilities/NpmUtilities.ts +23 -0
  275. package/src/utilities/PackageManager.ts +8 -5
  276. package/src/utilities/PathUtilities.ts +36 -7
  277. package/src/utilities/SignalChannel.ts +14 -7
  278. package/src/utilities/StringBuilder.ts +45 -0
  279. package/src/utilities/StringUtilities.ts +2 -0
  280. package/src/utilities/TarballMaker.ts +6 -7
  281. package/src/utilities/Timer.ts +4 -2
  282. package/src/utilities/Utilities.ts +79 -45
  283. package/src/utilities/VirtualFileReadStream.ts +5 -5
  284. package/src/utilities/WasmMemoryManager.ts +20 -6
  285. package/tsconfig.json +96 -0
  286. package/dist/utilities/DynamicUint8Array.d.ts +0 -9
  287. package/dist/utilities/DynamicUint8Array.js +0 -31
  288. package/dist/utilities/DynamicUint8Array.js.map +0 -1
  289. package/dist/utilities/LEB128.js.map +0 -1
  290. package/dist/utilities/LPVarInt.js.map +0 -1
  291. package/dist/utilities/Queue.js.map +0 -1
  292. package/dist/utilities/WindowedList.js.map +0 -1
  293. package/src/utilities/DynamicUint8Array.ts +0 -39
  294. /package/dist/{utilities → data-structures}/Queue.d.ts +0 -0
  295. /package/dist/{utilities → data-structures}/Queue.js +0 -0
  296. /package/dist/{utilities → data-structures}/WindowedList.d.ts +0 -0
  297. /package/dist/{utilities → data-structures}/WindowedList.js +0 -0
  298. /package/src/{utilities → data-structures}/Queue.ts +0 -0
  299. /package/src/{utilities → data-structures}/WindowedList.ts +0 -0
@@ -1,7 +1,7 @@
1
- import path from 'path'
2
1
  import { loadPackage } from '../utilities/PackageManager.js'
3
2
  import { commandExists } from '../utilities/Utilities.js'
4
3
  import { getGlobalOption } from '../api/GlobalOptions.js'
4
+ import { joinPath } from '../utilities/PathUtilities.js'
5
5
 
6
6
  export async function tryResolvingSoxPath() {
7
7
  if (getGlobalOption('soxPath')) {
@@ -14,7 +14,7 @@ export async function tryResolvingSoxPath() {
14
14
  if (platform === 'win32') {
15
15
  const soxPackagePath = await loadPackage('sox-14.4.1a-win32')
16
16
 
17
- return path.join(soxPackagePath, 'sox.exe')
17
+ return joinPath(soxPackagePath, 'sox.exe')
18
18
  }
19
19
 
20
20
  if (await commandExists('sox')) {
@@ -24,7 +24,7 @@ export async function tryResolvingSoxPath() {
24
24
  if (platform === 'linux' && arch === 'x64') {
25
25
  const soxPackagePath = await loadPackage('sox-14.4.2-linux-minimal')
26
26
 
27
- return path.join(soxPackagePath, 'sox')
27
+ return joinPath(soxPackagePath, 'sox')
28
28
  }
29
29
 
30
30
  return undefined
@@ -1,6 +1,6 @@
1
- import path from 'path'
2
1
  import { existsSync, readdir } from '../utilities/FileSystem.js'
3
2
  import { ensureAndGetPackagesDir } from '../utilities/PackageManager.js'
3
+ import { joinPath } from '../utilities/PathUtilities.js'
4
4
  import { createNamedTarball } from '../utilities/TarballMaker.js'
5
5
  import { setupProgramTerminationListeners } from '../utilities/Utilities.js'
6
6
 
@@ -9,11 +9,11 @@ async function makeTarballsForInstalledPackages(tarballDir: string, skipIfExists
9
9
  const packageList = await readdir(packagesDir)
10
10
 
11
11
  for (const packageName of packageList) {
12
- if (skipIfExists && existsSync(path.join(tarballDir, `${packageName}.tar.gz`))) {
12
+ if (skipIfExists && existsSync(joinPath(tarballDir, `${packageName}.tar.gz`))) {
13
13
  continue
14
14
  }
15
15
 
16
- const packagePath = path.join(packagesDir, packageName)
16
+ const packagePath = joinPath(packagesDir, packageName)
17
17
  await createNamedTarball(packagePath, packageName, tarballDir)
18
18
  }
19
19
  }
package/src/cli/CLI.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as API from '../api/API.js'
2
2
  import { parseCLIArguments } from './CLIParser.js'
3
- import { getWithDefault, logToStderr, setupUnhandledExceptionListeners, splitFilenameOnExtendedExtension, stringifyAndFormatJson } from '../utilities/Utilities.js'
3
+ import { parseJSONAndGetType, getWithDefault, logToStderr, parseJson, 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
 
@@ -10,12 +10,11 @@ import { SubtitlesConfig, subtitlesToText, timelineToSubtitles } from '../subtit
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'
13
- import path, { parse as parsePath } from 'node:path'
14
13
  import { splitToParagraphs, splitToWords, wordCharacterPattern } from '../nlp/Segmentation.js'
15
- import { playAudioSamples, playAudioWithWordTimeline } from '../audio/AudioPlayer.js'
14
+ import { playAudioSamplesWithKeyboardControls, playAudioWithWordTimeline } from '../audio/AudioPlayer.js'
16
15
  import { extendDeep } from '../utilities/ObjectUtilities.js'
17
16
  import { Timeline, TimelineEntry, addTimeOffsetToTimeline, addWordTextOffsetsToTimeline, roundTimelineProperties } from '../utilities/Timeline.js'
18
- import { ensureDir, existsSync, readAndParseJsonFile, readFile, readdir, writeFileSafe } from '../utilities/FileSystem.js'
17
+ import { ensureDir, existsSync, readAndParseJsonFile, readdir, readFileAsUtf8, writeFileSafe } from '../utilities/FileSystem.js'
19
18
  import { formatLanguageCodeWithName, getShortLanguageCode } from '../utilities/Locale.js'
20
19
  import { APIOptions } from '../api/APIOptions.js'
21
20
  import { ensureAndGetPackagesDir, getVersionTagFromPackageName, loadPackage, resolveVersionTagForUnversionedPackageName } from '../utilities/PackageManager.js'
@@ -23,8 +22,7 @@ import { removePackage } from '../utilities/PackageManager.js'
23
22
  import { appName } from '../api/Common.js'
24
23
  import { ServerOptions, startServer } from '../server/Server.js'
25
24
  import { OpenPromise } from '../utilities/OpenPromise.js'
26
- import JSON5 from 'json5'
27
- import { getLowercaseFileExtension, resolveToModuleRootDir } from '../utilities/PathUtilities.js'
25
+ import { getLowercaseFileExtension, joinPath, parsePath, resolveToModuleRootDir } from '../utilities/PathUtilities.js'
28
26
  import { CLIOptions, CLIOptionsKeys } from './CLIOptions.js'
29
27
  import { convertHtmlToText, formatIntegerWithLeadingZeros, formatListWithQuotedElements } from '../utilities/StringUtilities.js'
30
28
 
@@ -431,7 +429,7 @@ export async function speak(operationData: CLIOperationData) {
431
429
  }
432
430
 
433
431
  const sourceFileExtension = getLowercaseFileExtension(sourceFile)
434
- const fileContent = await readFile(sourceFile, { encoding: 'utf-8' })
432
+ const fileContent = await readFileAsUtf8(sourceFile)
435
433
 
436
434
  if (options.ssml && sourceFileExtension != 'xml' && sourceFileExtension != 'ssml') {
437
435
  throw new Error(`SSML option is set, but source file doesn't have an 'xml' or 'ssml' extension.`)
@@ -445,7 +443,7 @@ export async function speak(operationData: CLIOperationData) {
445
443
  const textContent = await convertHtmlToText(fileContent)
446
444
  textSegments = splitToParagraphs(textContent, 'single', 'preserve')
447
445
  } else if (sourceFileExtension == 'srt' || sourceFileExtension == 'vtt') {
448
- const fileContent = await readFile(sourceFile, { encoding: 'utf-8' })
446
+ const fileContent = await readFileAsUtf8(sourceFile)
449
447
  //textSegments = subtitlesToTimeline(fileContent).map(entry => entry.text)
450
448
  textSegments = [subtitlesToText(fileContent)]
451
449
  } else if (sourceFileExtension == 'xml' || sourceFileExtension == 'ssml') {
@@ -500,7 +498,7 @@ export async function speak(operationData: CLIOperationData) {
500
498
  const audioWithAddedGain = applyGainDecibels(segmentData.audio as RawAudio, gainAmount)
501
499
  const segmentWordTimeline = segmentData.timeline.flatMap(sentenceTimeline => sentenceTimeline.timeline!)
502
500
 
503
- await playAudioWithWordTimeline(audioWithAddedGain, segmentWordTimeline, segmentData.transcript)
501
+ await playAudioWithWordTimeline(audioWithAddedGain, segmentWordTimeline, segmentData.transcript, cliOptions.player)
504
502
  }
505
503
  }
506
504
 
@@ -590,7 +588,7 @@ export async function transcribe(operationData: CLIOperationData) {
590
588
 
591
589
  const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
592
590
 
593
- await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, transcript)
591
+ await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, transcript, cliOptions.player)
594
592
  }
595
593
  }
596
594
 
@@ -621,7 +619,7 @@ export async function align(operationData: CLIOperationData) {
621
619
  }
622
620
 
623
621
  const referenceFileExtension = getLowercaseFileExtension(alignmentReferenceFile)
624
- const fileContent = await readFile(alignmentReferenceFile, { encoding: 'utf-8' })
622
+ const fileContent = await readFileAsUtf8(alignmentReferenceFile)
625
623
 
626
624
  let text: string
627
625
 
@@ -686,7 +684,7 @@ export async function align(operationData: CLIOperationData) {
686
684
 
687
685
  const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
688
686
 
689
- await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, transcript)
687
+ await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, transcript, cliOptions.player)
690
688
  }
691
689
  }
692
690
 
@@ -717,7 +715,7 @@ export async function alignTranslation(operationData: CLIOperationData) {
717
715
  }
718
716
 
719
717
  const referenceFileExtension = getLowercaseFileExtension(alignmentReferenceFile)
720
- const fileContent = await readFile(alignmentReferenceFile, { encoding: 'utf-8' })
718
+ const fileContent = await readFileAsUtf8(alignmentReferenceFile)
721
719
 
722
720
  let text: string
723
721
 
@@ -791,7 +789,7 @@ export async function alignTranslation(operationData: CLIOperationData) {
791
789
 
792
790
  const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
793
791
 
794
- await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, translatedTranscript)
792
+ await playAudioWithWordTimeline(normalizedAudioToPlay, wordTimeline, translatedTranscript, cliOptions.player)
795
793
  }
796
794
  }
797
795
 
@@ -835,7 +833,7 @@ export async function alignTranscriptAndTranslation(operationData: CLIOperationD
835
833
 
836
834
  {
837
835
  const nativeTranscriptFileExtension = getLowercaseFileExtension(nativeTranscriptFilePath)
838
- const fileContent = await readFile(nativeTranscriptFilePath, { encoding: 'utf-8' })
836
+ const fileContent = await readFileAsUtf8(nativeTranscriptFilePath)
839
837
 
840
838
 
841
839
  if (nativeTranscriptFileExtension == 'txt') {
@@ -853,7 +851,7 @@ export async function alignTranscriptAndTranslation(operationData: CLIOperationD
853
851
 
854
852
  {
855
853
  const translatedTranscriptFileExtension = getLowercaseFileExtension(translatedTranscriptFilePath)
856
- const fileContent = await readFile(translatedTranscriptFilePath, { encoding: 'utf-8' })
854
+ const fileContent = await readFileAsUtf8(translatedTranscriptFilePath)
857
855
 
858
856
  if (translatedTranscriptFileExtension == 'txt') {
859
857
  translatedTranscript = fileContent
@@ -930,7 +928,7 @@ export async function alignTranscriptAndTranslation(operationData: CLIOperationD
930
928
 
931
929
  const normalizedAudioToPlay = normalizeAudioLevel(audioToPlay)
932
930
 
933
- await playAudioWithWordTimeline(normalizedAudioToPlay, translatedWordTimeline, translatedTranscript)
931
+ await playAudioWithWordTimeline(normalizedAudioToPlay, translatedWordTimeline, translatedTranscript, cliOptions.player)
934
932
  }
935
933
  }
936
934
 
@@ -967,7 +965,7 @@ export async function alignTimelineTranslation(operationData: CLIOperationData)
967
965
  }
968
966
 
969
967
  const translationFileExtension = getLowercaseFileExtension(translationFilePath)
970
- const translationFileContent = await readFile(translationFilePath, { encoding: 'utf-8' })
968
+ const translationFileContent = await readFileAsUtf8(translationFilePath)
971
969
 
972
970
  let translationText: string
973
971
 
@@ -1018,7 +1016,7 @@ export async function alignTimelineTranslation(operationData: CLIOperationData)
1018
1016
  transcriptToPlay = translationText
1019
1017
  timelineToPlay = translationWordTimeline
1020
1018
 
1021
- await playAudioWithWordTimeline(normalizedAudioToPlay, timelineToPlay, transcriptToPlay)
1019
+ await playAudioWithWordTimeline(normalizedAudioToPlay, timelineToPlay, transcriptToPlay, cliOptions.player)
1022
1020
  }
1023
1021
  }
1024
1022
 
@@ -1039,7 +1037,7 @@ export async function translateText(operationData: CLIOperationData) {
1039
1037
  }
1040
1038
 
1041
1039
  const inputFileExtension = getLowercaseFileExtension(inputFilename)
1042
- const inputFileContent = await readFile(inputFilename, { encoding: 'utf-8' })
1040
+ const inputFileContent = await readFileAsUtf8(inputFilename)
1043
1041
 
1044
1042
  let inputText: string
1045
1043
 
@@ -1186,7 +1184,7 @@ export async function translateSpeech(operationData: CLIOperationData) {
1186
1184
  transcriptToPlay = transcriptToPlay.trim()
1187
1185
  }
1188
1186
 
1189
- await playAudioWithWordTimeline(normalizedAudioToPlay, timelineToPlay, transcriptToPlay)
1187
+ await playAudioWithWordTimeline(normalizedAudioToPlay, timelineToPlay, transcriptToPlay, cliOptions.player)
1190
1188
  }
1191
1189
  }
1192
1190
 
@@ -1223,7 +1221,7 @@ export async function detectLanguage(operationData: CLIOperationData, mode: 'spe
1223
1221
 
1224
1222
  await checkOutputFilenames(outputFilenames, false, true, false)
1225
1223
 
1226
- let text = await readFile(inputFilePath, { encoding: 'utf-8' })
1224
+ let text = await readFileAsUtf8(inputFilePath)
1227
1225
 
1228
1226
  if (inputFileExtension == 'srt' || inputFileExtension == 'vtt') {
1229
1227
  text = subtitlesToText(text)
@@ -1332,7 +1330,7 @@ export async function detectVoiceActivity(operationData: CLIOperationData) {
1332
1330
  return { ...entry, type: 'word' } as TimelineEntry
1333
1331
  })
1334
1332
 
1335
- await playAudioWithWordTimeline(normalizedAudio, timelineToPlay)
1333
+ await playAudioWithWordTimeline(normalizedAudio, timelineToPlay, cliOptions.player)
1336
1334
  }
1337
1335
  }
1338
1336
 
@@ -1377,7 +1375,7 @@ export async function denoise(operationData: CLIOperationData) {
1377
1375
  logger.end()
1378
1376
 
1379
1377
  if (cliOptions.play) {
1380
- await playAudioSamples(denoisedAudio)
1378
+ await playAudioSamplesWithKeyboardControls(denoisedAudio, cliOptions.player)
1381
1379
  }
1382
1380
  }
1383
1381
 
@@ -1420,7 +1418,7 @@ export async function isolate(operationData: CLIOperationData) {
1420
1418
  logger.end()
1421
1419
 
1422
1420
  if (cliOptions.play) {
1423
- await playAudioSamples(isolatedRawAudio)
1421
+ await playAudioSamplesWithKeyboardControls(isolatedRawAudio, cliOptions.player)
1424
1422
  }
1425
1423
  }
1426
1424
 
@@ -1806,19 +1804,15 @@ async function optionsLookupToTypedObject<K extends keyof APIOptions>(cliOptions
1806
1804
  throw new Error(`The property '${key}' is not a Boolean, and cannot be negated using the 'not-' prefix.`)
1807
1805
  } else if (optionType == 'array' || optionType == 'object') {
1808
1806
  try {
1809
- const { default: JSON5 } = await import('json5')
1810
- parsedValue = JSON5.parse(value)
1807
+ parsedValue = await parseJson(value, true)
1811
1808
  } catch (e) {
1812
1809
  parsedValue = value
1813
1810
  }
1814
1811
  } else if (optionIsUnion) {
1815
- const isArrayJSON = value.startsWith('[') && value.endsWith(']')
1816
- const isObjectJSON = value.startsWith('{') && value.endsWith('}')
1817
- const isNumberJSON = !isNaN(Number.parseFloat(value))
1818
- const isBooleanJSON = value == 'true' || value == 'false'
1812
+ const { parsedValue: json5ParsedValue, jsonType } = await parseJSONAndGetType(value, true)
1819
1813
 
1820
- if (isArrayJSON || isObjectJSON || isNumberJSON || isBooleanJSON) {
1821
- parsedValue = JSON5.parse(value)
1814
+ if (jsonType === 'number' || jsonType === 'boolean' || jsonType === 'array' || jsonType === 'object') {
1815
+ parsedValue = json5ParsedValue
1822
1816
  } else {
1823
1817
  parsedValue = value
1824
1818
  }
@@ -1941,7 +1935,7 @@ function getFileSaver(outputFilePath: string, allowOverwrite: boolean): FileSave
1941
1935
  const filenameParts = splitFilenameOnExtendedExtension(parsedPath.base)
1942
1936
 
1943
1937
  for (let i = 1; existsSync(outputFilePath); i++) {
1944
- outputFilePath = path.join(parsedPath.dir, `${filenameParts[0]}_${formatIntegerWithLeadingZeros(i, 3)}`)
1938
+ outputFilePath = joinPath(parsedPath.dir, `${filenameParts[0]}_${formatIntegerWithLeadingZeros(i, 3)}`)
1945
1939
 
1946
1940
  if (filenameParts[1]) {
1947
1941
  outputFilePath += `.${filenameParts[1]}`
@@ -1956,14 +1950,14 @@ function getFileSaver(outputFilePath: string, allowOverwrite: boolean): FileSave
1956
1950
  if (fileExtension == 'txt') {
1957
1951
  fileSaver = async (audio, timeline, text) => {
1958
1952
  await ensureDir(fileDir)
1959
- return writeFileSafe(outputFilePath, text, { encoding: 'utf-8' })
1953
+ return writeFileSafe(outputFilePath, text)
1960
1954
  }
1961
1955
  } else if (fileExtension == 'json') {
1962
1956
  fileSaver = async (audio, timeline, text) => {
1963
1957
  await ensureDir(fileDir)
1964
1958
 
1965
1959
  const roundedTimeline = roundTimelineProperties(timeline)
1966
- return writeFileSafe(outputFilePath, stringifyAndFormatJson(roundedTimeline))
1960
+ return writeFileSafe(outputFilePath, await stringifyAndFormatJson(roundedTimeline))
1967
1961
  }
1968
1962
  } else if (fileExtension == 'srt') {
1969
1963
  fileSaver = async (audio, timeline, text, subtitlesConfig) => {
@@ -1,7 +1,7 @@
1
- import { readAndParseJsonFile, readFile } from '../utilities/FileSystem.js'
1
+ import { readAndParseJsonFile, readFileAsUtf8 } from '../utilities/FileSystem.js'
2
2
 
3
3
  export async function parseConfigFile(path: string): Promise<ParsedConfigFile> {
4
- const fileContent = await readFile(path, { encoding: 'utf-8' })
4
+ const fileContent = await readFileAsUtf8(path)
5
5
 
6
6
  const lines = fileContent
7
7
  .split(/\r?\n/g)
@@ -1,8 +1,11 @@
1
+ import { type AudioPlayerID } from "../audio/AudioPlayer.js"
2
+
1
3
  export interface CLIOptions {
2
4
  play?: boolean
5
+ player?: AudioPlayerID
3
6
  overwrite?: boolean
4
7
  debug?: boolean
5
8
  config?: string
6
9
  }
7
10
 
8
- export const CLIOptionsKeys: (keyof CLIOptions)[] = ['play', 'overwrite', 'debug', 'config']
11
+ export const CLIOptionsKeys: (keyof CLIOptions)[] = ['play', 'player', 'overwrite', 'debug', 'config']
@@ -3,11 +3,11 @@ import { spawn } from 'child_process'
3
3
  import { encodeRawAudioToWave, decodeWaveToRawAudio, RawAudio } from '../audio/AudioUtilities.js'
4
4
 
5
5
  import { Logger } from '../utilities/Logger.js'
6
- import { commandExists, concatBuffers, logToStderr } from '../utilities/Utilities.js'
7
- import path from 'node:path'
6
+ import { commandExists, concatUint8Arrays, isUint8Array, logToStderr } from '../utilities/Utilities.js'
8
7
  import { loadPackage } from '../utilities/PackageManager.js'
9
8
  import { getGlobalOption } from '../api/GlobalOptions.js'
10
9
  import { existsSync } from '../utilities/FileSystem.js'
10
+ import { joinPath } from '../utilities/PathUtilities.js'
11
11
 
12
12
  const log = logToStderr
13
13
 
@@ -27,7 +27,7 @@ export async function encodeFromChannels(rawAudio: RawAudio, outputOptions: FFMp
27
27
  return transcode(encodeRawAudioToWave(rawAudio), outputOptions)
28
28
  }
29
29
 
30
- export async function decodeToChannels(input: string | Buffer, outSampleRate?: number, outChannelCount?: number) {
30
+ export async function decodeToChannels(input: string | Uint8Array, outSampleRate?: number, outChannelCount?: number) {
31
31
  const outputOptions: FFMpegOutputOptions = {
32
32
  codec: 'pcm_f32le',
33
33
  format: 'wav',
@@ -47,7 +47,7 @@ export async function decodeToChannels(input: string | Buffer, outSampleRate?: n
47
47
  return rawAudio
48
48
  }
49
49
 
50
- export async function transcode(input: string | Buffer, outputOptions: FFMpegOutputOptions) {
50
+ export async function transcode(input: string | Uint8Array, outputOptions: FFMpegOutputOptions) {
51
51
  const executablePath = await getFFMpegExecutablePath()
52
52
 
53
53
  if (!executablePath) {
@@ -57,16 +57,16 @@ export async function transcode(input: string | Buffer, outputOptions: FFMpegOut
57
57
  return transcode_CLI(executablePath, input, outputOptions)
58
58
  }
59
59
 
60
- async function transcode_CLI(ffmpegCommand: string, input: string | Buffer, outputOptions: FFMpegOutputOptions) {
61
- return new Promise<Buffer>((resolve, reject) => {
60
+ async function transcode_CLI(ffmpegCommand: string, input: string | Uint8Array, outputOptions: FFMpegOutputOptions) {
61
+ return new Promise<Uint8Array>((resolve, reject) => {
62
62
  const logger = new Logger()
63
63
  logger.start('Transcode with command-line ffmpeg')
64
64
 
65
- const args = buildCommandLineArguments(Buffer.isBuffer(input) ? '-' : input, outputOptions)
65
+ const args = buildCommandLineArguments(isUint8Array(input) ? '-' : input, outputOptions)
66
66
 
67
67
  const process = spawn(ffmpegCommand, args)
68
68
 
69
- if (Buffer.isBuffer(input)) {
69
+ if (isUint8Array(input)) {
70
70
  process.stdin.end(input)
71
71
  } else if (typeof input === 'string') {
72
72
  if (!existsSync(input)) {
@@ -75,7 +75,7 @@ async function transcode_CLI(ffmpegCommand: string, input: string | Buffer, outp
75
75
  }
76
76
  }
77
77
 
78
- const stdoutChunks: Buffer[] = []
78
+ const stdoutChunks: Uint8Array[] = []
79
79
  let stderrOutput = ''
80
80
 
81
81
  process.stdout.on('data', (data) => {
@@ -94,7 +94,7 @@ async function transcode_CLI(ffmpegCommand: string, input: string | Buffer, outp
94
94
 
95
95
  process.on('close', (exitCode) => {
96
96
  if (exitCode == 0) {
97
- const concatenatedChunks = concatBuffers(stdoutChunks)
97
+ const concatenatedChunks = concatUint8Arrays(stdoutChunks)
98
98
 
99
99
  resolve(concatenatedChunks)
100
100
  } else {
@@ -206,7 +206,7 @@ async function getFFMpegExecutablePath() {
206
206
  filename += '.exe'
207
207
  }
208
208
 
209
- return path.join(ffmpegPackagePath, filename)
209
+ return joinPath(ffmpegPackagePath, filename)
210
210
  }
211
211
 
212
212
  export function getDefaultFFMpegOptionsForSpeech(fileExtension: string, customBitrate?: number) {
@@ -1,13 +1,14 @@
1
1
  import { decodeToChannels } from '../audio/AudioBufferConversion.js'
2
- import { readFile } from '../utilities/FileSystem.js'
2
+ import { decodeAscii } from '../encodings/Ascii.js'
3
+ import { readFileAsBinary } from '../utilities/FileSystem.js'
3
4
  import { SampleFormat } from './WaveCodec.js'
4
5
 
5
6
  export async function decodeTimitAudioFile(filename: string) {
6
- return decodeTimitAudio(await readFile(filename))
7
+ return decodeTimitAudio(await readFileAsBinary(filename))
7
8
  }
8
9
 
9
- export function decodeTimitAudio(data: Buffer) {
10
- if (data.subarray(0, 16).toString('ascii') != 'NIST_1A\n 1024\n') {
10
+ export function decodeTimitAudio(data: Uint8Array) {
11
+ if (decodeAscii(data.subarray(0, 16)) != 'NIST_1A\n 1024\n') {
11
12
  throw new Error('Data is not a valid TIMIT audio file')
12
13
  }
13
14
 
@@ -1,6 +1,9 @@
1
1
  import * as AudioBufferConversion from '../audio/AudioBufferConversion.js'
2
2
  import { RawAudio } from '../audio/AudioUtilities.js'
3
- import { concatBuffers, logToStderr } from '../utilities/Utilities.js'
3
+ import { readUint16LE, readUint32LE, writeAscii, writeUint16LE, writeUint32LE } from '../utilities/BinaryUtilities.js'
4
+ import { encodeHex, decodeHex } from '../encodings/Hex.js'
5
+ import { concatUint8Arrays, logToStderr } from '../utilities/Utilities.js'
6
+ import { decodeAscii } from '../encodings/Ascii.js'
4
7
 
5
8
  const log = logToStderr
6
9
 
@@ -16,25 +19,25 @@ export function encodeWave(rawAudio: RawAudio, bitDepth: BitDepth = 16, sampleFo
16
19
  const formatSubChunk = new WaveFormat(audioChannels.length, sampleRate, bitDepth, sampleFormat, speakerPositionMask)
17
20
  const formatSubChunkBuffer = formatSubChunk.serialize(shouldUseExtensibleFormat)
18
21
 
19
- const dataSubChunkBuffer = Buffer.alloc(4 + 4 + audioDataLength)
20
- dataSubChunkBuffer.write('data', 0, 'ascii')
22
+ const dataSubChunkBuffer = new Uint8Array(4 + 4 + audioDataLength)
23
+ writeAscii(dataSubChunkBuffer, 'data', 0)
21
24
  const dataChunkLength = Math.min(audioDataLength, 4294967295) // Ensure large data chunk length is clipped to max
22
- dataSubChunkBuffer.writeUint32LE(dataChunkLength, 4)
25
+ writeUint32LE(dataSubChunkBuffer, dataChunkLength, 4)
23
26
  dataSubChunkBuffer.set(audioBuffer, 8)
24
27
 
25
- const riffChunkHeaderBuffer = Buffer.alloc(12)
26
- riffChunkHeaderBuffer.write('RIFF', 0, 'ascii')
28
+ const riffChunkHeaderBuffer = new Uint8Array(12)
29
+ writeAscii(riffChunkHeaderBuffer, 'RIFF', 0)
27
30
  const riffChunkLength = Math.min(4 + formatSubChunkBuffer.length + dataSubChunkBuffer.length, 4294967295) // Ensure large RIFF chunk length is clipped to max
28
- riffChunkHeaderBuffer.writeUint32LE(riffChunkLength, 4)
29
- riffChunkHeaderBuffer.write('WAVE', 8, 'ascii')
31
+ writeUint32LE(riffChunkHeaderBuffer, riffChunkLength, 4)
32
+ writeAscii(riffChunkHeaderBuffer, 'WAVE', 8)
30
33
 
31
- return concatBuffers([riffChunkHeaderBuffer, formatSubChunkBuffer, dataSubChunkBuffer])
34
+ return concatUint8Arrays([riffChunkHeaderBuffer, formatSubChunkBuffer, dataSubChunkBuffer])
32
35
  }
33
36
 
34
- export function decodeWave(waveData: Buffer, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
37
+ export function decodeWave(waveData: Uint8Array, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
35
38
  let readOffset = 0
36
39
 
37
- const riffId = waveData.subarray(readOffset, readOffset + 4).toString('ascii')
40
+ const riffId = decodeAscii(waveData.subarray(readOffset, readOffset + 4))
38
41
 
39
42
  if (riffId != 'RIFF') {
40
43
  throw new Error('Not a valid wave file. No RIFF id found at offset 0.')
@@ -42,11 +45,11 @@ export function decodeWave(waveData: Buffer, ignoreTruncatedChunks = true, ignor
42
45
 
43
46
  readOffset += 4
44
47
 
45
- let riffChunkSize = waveData.readUInt32LE(readOffset)
48
+ let riffChunkSize = readUint32LE(waveData, readOffset)
46
49
 
47
50
  readOffset += 4
48
51
 
49
- const waveId = waveData.subarray(readOffset, readOffset + 4).toString('ascii')
52
+ const waveId = decodeAscii(waveData.subarray(readOffset, readOffset + 4))
50
53
 
51
54
  if (waveId != 'WAVE') {
52
55
  throw new Error('Not a valid wave file. No WAVE id found at offset 8.')
@@ -66,14 +69,14 @@ export function decodeWave(waveData: Buffer, ignoreTruncatedChunks = true, ignor
66
69
 
67
70
  readOffset += 4
68
71
 
69
- let formatSubChunkBodyBuffer: Buffer | undefined
70
- const dataBuffers: Buffer[] = []
72
+ let formatSubChunkBodyBuffer: Uint8Array | undefined
73
+ const dataBuffers: Uint8Array[] = []
71
74
 
72
75
  while (true) {
73
- const subChunkIdentifier = waveData.subarray(readOffset, readOffset + 4).toString('ascii')
76
+ const subChunkIdentifier = decodeAscii(waveData.subarray(readOffset, readOffset + 4))
74
77
  readOffset += 4
75
78
 
76
- let subChunkSize = waveData.readUInt32LE(readOffset)
79
+ let subChunkSize = readUint32LE(waveData, readOffset)
77
80
  readOffset += 4
78
81
 
79
82
  if (!ignoreTruncatedChunks && subChunkSize > waveData.length - readOffset) {
@@ -125,7 +128,7 @@ export function decodeWave(waveData: Buffer, ignoreTruncatedChunks = true, ignor
125
128
  const bitDepth = waveFormat.bitDepth
126
129
  const speakerPositionMask = waveFormat.speakerPositionMask
127
130
 
128
- const concatenatedDataBuffers = concatBuffers(dataBuffers)
131
+ const concatenatedDataBuffers = concatUint8Arrays(dataBuffers)
129
132
  dataBuffers.length = 0 // Allow the garbage collector to free up memory held by the data buffers
130
133
 
131
134
  const audioChannels = AudioBufferConversion.decodeToChannels(concatenatedDataBuffers, channelCount, bitDepth, sampleFormat)
@@ -139,7 +142,7 @@ export function decodeWave(waveData: Buffer, ignoreTruncatedChunks = true, ignor
139
142
  }
140
143
  }
141
144
 
142
- export function repairWave(waveData: Buffer) {
145
+ export function repairWave(waveData: Uint8Array) {
143
146
  const { rawAudio, sourceSampleFormat, sourceBitDepth } = decodeWave(waveData)
144
147
 
145
148
  return encodeWave(rawAudio, sourceBitDepth, sourceSampleFormat)
@@ -177,25 +180,25 @@ class WaveFormat { // 24 bytes total for PCM, 26 for float
177
180
 
178
181
  const serializedSize = sampleFormatToSerializedSize[sampleFormatId]
179
182
 
180
- const result = Buffer.alloc(serializedSize)
183
+ const result = new Uint8Array(serializedSize)
181
184
 
182
- result.write('fmt ', 0, 'ascii') // + 4
183
- result.writeUint32LE(serializedSize - 8, 4) // + 4
185
+ writeAscii(result, 'fmt ', 0) // + 4
186
+ writeUint32LE(result, serializedSize - 8, 4) // + 4
184
187
 
185
- result.writeUint16LE(sampleFormatId, 8) // + 2
186
- result.writeUint16LE(this.channelCount, 10) // + 2
187
- result.writeUint32LE(this.sampleRate, 12) // + 4
188
- result.writeUint32LE(this.byteRate, 16) // + 4
189
- result.writeUint16LE(this.blockAlign, 20) // + 2
190
- result.writeUint16LE(this.bitDepth, 22) // + 2
188
+ writeUint16LE(result, sampleFormatId, 8) // + 2
189
+ writeUint16LE(result, this.channelCount, 10) // + 2
190
+ writeUint32LE(result, this.sampleRate, 12) // + 4
191
+ writeUint32LE(result, this.byteRate, 16) // + 4
192
+ writeUint16LE(result, this.blockAlign, 20) // + 2
193
+ writeUint16LE(result, this.bitDepth, 22) // + 2
191
194
 
192
195
  if (useExtensibleFormat) {
193
- result.writeUint16LE(serializedSize - 26, 24) // + 2 (extension size)
194
- result.writeUint16LE(this.bitDepth, 26) // + 2 (valid bits per sample)
195
- result.writeUint32LE(this.speakerPositionMask, 28) // + 2 (speaker position mask)
196
+ writeUint16LE(result, serializedSize - 26, 24) // + 2 (extension size)
197
+ writeUint16LE(result, this.bitDepth, 26) // + 2 (valid bits per sample)
198
+ writeUint32LE(result, this.speakerPositionMask, 28) // + 2 (speaker position mask)
196
199
 
197
200
  if (this.sampleFormat == SampleFormat.PCM || this.sampleFormat == SampleFormat.Float) {
198
- result.set(Buffer.from(this.guid, 'hex'), 32)
201
+ result.set(decodeHex(this.guid), 32)
199
202
  } else {
200
203
  throw new Error(`Extensible format is not supported for sample format ${this.sampleFormat}`)
201
204
  }
@@ -204,11 +207,11 @@ class WaveFormat { // 24 bytes total for PCM, 26 for float
204
207
  return result
205
208
  }
206
209
 
207
- static deserializeFrom(formatChunkBody: Buffer) { // chunkBody should not include the first 8 bytes
208
- let sampleFormat = formatChunkBody.readUint16LE(0) // + 2
209
- const channelCount = formatChunkBody.readUint16LE(2) // + 2
210
- const sampleRate = formatChunkBody.readUint32LE(4) // + 4
211
- const bitDepth = formatChunkBody.readUint16LE(14)
210
+ static deserializeFrom(formatChunkBody: Uint8Array) { // chunkBody should not include the first 8 bytes
211
+ let sampleFormat = readUint16LE(formatChunkBody, 0) // + 2
212
+ const channelCount = readUint16LE(formatChunkBody, 2) // + 2
213
+ const sampleRate = readUint32LE(formatChunkBody, 4) // + 4
214
+ const bitDepth = readUint16LE(formatChunkBody, 14)
212
215
  let speakerPositionMask = 0
213
216
 
214
217
  if (sampleFormat == 65534) {
@@ -216,9 +219,9 @@ class WaveFormat { // 24 bytes total for PCM, 26 for float
216
219
  throw new Error(`Format subchunk specifies a format id of 65534 (extensible) but its body size is ${formatChunkBody.length} bytes, which is smaller than the minimum expected of 40 bytes`)
217
220
  }
218
221
 
219
- speakerPositionMask = formatChunkBody.readUint16LE(20)
222
+ speakerPositionMask = readUint16LE(formatChunkBody, 20)
220
223
 
221
- const guid = formatChunkBody.subarray(24, 40).toString('hex')
224
+ const guid = encodeHex(formatChunkBody.subarray(24, 40))
222
225
 
223
226
  if (guid == sampleFormatToGuid[SampleFormat.PCM]) {
224
227
  sampleFormat = SampleFormat.PCM
@@ -0,0 +1,64 @@
1
+ import { TypedArray, TypedArrayConstructor } from "../typings/TypedArray.js"
2
+
3
+ export class DynamicTypedArray<T extends TypedArray> {
4
+ elements: TypedArray
5
+ length = 0
6
+
7
+ constructor(private TypedArrayConstructor: TypedArrayConstructor<T>, initialCapacity = 4) {
8
+ this.elements = new TypedArrayConstructor(initialCapacity)
9
+ }
10
+
11
+ add(newElement: number) {
12
+ const length = this.length
13
+
14
+ if (length === this.elements.length) {
15
+ this.ensureCapacity(length + 1)
16
+ }
17
+
18
+ this.elements[length] = newElement
19
+ this.length += 1
20
+ }
21
+
22
+ addMany(...newElements: number[]) {
23
+ this.addArray(newElements)
24
+ }
25
+
26
+ addArray(newElements: ArrayLike<number>) {
27
+ const addedCount = newElements.length
28
+
29
+ this.ensureCapacity(this.length + addedCount)
30
+
31
+ this.elements.set(newElements, this.length)
32
+ this.length += addedCount
33
+ }
34
+
35
+ ensureCapacity(requiredCapacity: number) {
36
+ if (requiredCapacity > this.elements.length) {
37
+ const newCapacity = requiredCapacity * 2
38
+
39
+ const newElements = new this.TypedArrayConstructor(newCapacity)
40
+ newElements.set(this.toTypedArray())
41
+
42
+ this.elements = newElements
43
+ }
44
+ }
45
+
46
+ toTypedArray() {
47
+ return this.elements.subarray(0, this.length) as T
48
+ }
49
+
50
+ clear() {
51
+ this.length = 0
52
+ }
53
+ }
54
+
55
+ export function createDynamicUint8Array(initialCapacity?: number): DynamicUint8Array {
56
+ return new DynamicTypedArray<Uint8Array>(Uint8Array, initialCapacity)
57
+ }
58
+
59
+ export function createDynamicUint16Array(initialCapacity?: number): DynamicUint16Array {
60
+ return new DynamicTypedArray<Uint16Array>(Uint16Array, initialCapacity)
61
+ }
62
+
63
+ export type DynamicUint8Array = DynamicTypedArray<Uint8Array>
64
+ export type DynamicUint16Array = DynamicTypedArray<Uint16Array>