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.
- package/README.md +23 -18
- package/data/schemas/options.json +52 -47
- package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
- package/dist/alignment/DTWSequenceAlignment.js +5 -5
- package/dist/alignment/DTWSequenceAlignment.js.map +1 -1
- package/dist/alignment/SpeechAlignment.js +6 -6
- package/dist/alignment/SpeechAlignment.js.map +1 -1
- package/dist/api/Alignment.d.ts +1 -1
- package/dist/api/Alignment.js +49 -11
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Denoising.d.ts +4 -2
- package/dist/api/Denoising.js +65 -13
- package/dist/api/Denoising.js.map +1 -1
- package/dist/api/SourceSeparation.js +9 -6
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/SpeechLanguageDetection.js +4 -4
- package/dist/api/SpeechLanguageDetection.js.map +1 -1
- package/dist/api/Synthesis.d.ts +2 -2
- package/dist/api/Synthesis.js +10 -7
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/VoiceActivityDetection.js +2 -2
- package/dist/api/VoiceActivityDetection.js.map +1 -1
- package/dist/audio/AudioBufferConversion.d.ts +2 -2
- package/dist/audio/AudioBufferConversion.js +77 -43
- package/dist/audio/AudioBufferConversion.js.map +1 -1
- package/dist/audio/AudioPlayer.d.ts +7 -5
- package/dist/audio/AudioPlayer.js +135 -49
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +4 -3
- package/dist/audio/AudioUtilities.js +30 -15
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/audio/SoxPath.js +3 -3
- package/dist/audio/SoxPath.js.map +1 -1
- package/dist/build-tools/MakeTarballsForInstalledPackages.js +3 -3
- package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -1
- package/dist/cli/CLI.js +30 -36
- package/dist/cli/CLI.js.map +1 -1
- package/dist/cli/CLIConfigFile.js +2 -2
- package/dist/cli/CLIConfigFile.js.map +1 -1
- package/dist/cli/CLIOptions.d.ts +2 -0
- package/dist/cli/CLIOptions.js +1 -1
- package/dist/cli/CLIOptions.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.d.ts +3 -3
- package/dist/codecs/FFMpegTranscoder.js +6 -6
- package/dist/codecs/FFMpegTranscoder.js.map +1 -1
- package/dist/codecs/TIMITCodec.d.ts +1 -1
- package/dist/codecs/TIMITCodec.js +4 -3
- package/dist/codecs/TIMITCodec.js.map +1 -1
- package/dist/codecs/WaveCodec.d.ts +3 -3
- package/dist/codecs/WaveCodec.js +37 -34
- package/dist/codecs/WaveCodec.js.map +1 -1
- package/dist/data-structures/DynamicTypedArray.d.ts +17 -0
- package/dist/data-structures/DynamicTypedArray.js +47 -0
- package/dist/data-structures/DynamicTypedArray.js.map +1 -0
- package/dist/data-structures/Queue.js.map +1 -0
- package/dist/data-structures/WindowedList.js.map +1 -0
- package/dist/denoising/NSNet2.d.ts +26 -0
- package/dist/denoising/NSNet2.js +128 -0
- package/dist/denoising/NSNet2.js.map +1 -0
- package/dist/denoising/RNNoise.js +3 -3
- package/dist/denoising/RNNoise.js.map +1 -1
- package/dist/dsp/FFT.d.ts +6 -1
- package/dist/dsp/FFT.js +17 -0
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/encodings/Ascii.d.ts +10 -0
- package/dist/encodings/Ascii.js +41 -0
- package/dist/encodings/Ascii.js.map +1 -0
- package/dist/encodings/Base64.d.ts +5 -0
- package/dist/encodings/Base64.js +114 -0
- package/dist/encodings/Base64.js.map +1 -0
- package/dist/encodings/Hex.d.ts +3 -0
- package/dist/encodings/Hex.js +52 -0
- package/dist/encodings/Hex.js.map +1 -0
- package/dist/{utilities → encodings}/LEB128.d.ts +1 -1
- package/dist/{utilities → encodings}/LEB128.js +4 -4
- package/dist/encodings/LEB128.js.map +1 -0
- package/dist/{utilities → encodings}/LPVarInt.d.ts +1 -1
- package/dist/{utilities → encodings}/LPVarInt.js +6 -6
- package/dist/encodings/LPVarInt.js.map +1 -0
- package/dist/encodings/TextEncodingsCommon.d.ts +4 -0
- package/dist/encodings/TextEncodingsCommon.js +2 -0
- package/dist/encodings/TextEncodingsCommon.js.map +1 -0
- package/dist/encodings/Utf16.d.ts +10 -0
- package/dist/encodings/Utf16.js +36 -0
- package/dist/encodings/Utf16.js.map +1 -0
- package/dist/encodings/Utf32.d.ts +9 -0
- package/dist/encodings/Utf32.js +44 -0
- package/dist/encodings/Utf32.js.map +1 -0
- package/dist/encodings/Utf8.d.ts +10 -0
- package/dist/encodings/Utf8.js +97 -0
- package/dist/encodings/Utf8.js.map +1 -0
- package/dist/math/MedianFilter.js.map +1 -1
- package/dist/nlp/JapaneseSegmentation.js +2 -2
- package/dist/nlp/JapaneseSegmentation.js.map +1 -1
- package/dist/recognition/GoogleCloudSTT.js +2 -1
- package/dist/recognition/GoogleCloudSTT.js.map +1 -1
- package/dist/recognition/SileroSTT.js +3 -3
- package/dist/recognition/SileroSTT.js.map +1 -1
- package/dist/recognition/VoskSTT.js +3 -3
- package/dist/recognition/VoskSTT.js.map +1 -1
- package/dist/recognition/WhisperCppSTT.js +4 -5
- package/dist/recognition/WhisperCppSTT.js.map +1 -1
- package/dist/recognition/WhisperSTT.js +8 -7
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/server/Client.d.ts +1 -1
- package/dist/server/Client.js +2 -1
- package/dist/server/Client.js.map +1 -1
- package/dist/server/Server.js +5 -4
- package/dist/server/Server.js.map +1 -1
- package/dist/server/Worker.js +1 -1
- package/dist/server/Worker.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/speech-search/DTWSpeechSearch.d.ts +1 -1
- package/dist/speech-search/DTWSpeechSearch.js +25 -6
- package/dist/speech-search/DTWSpeechSearch.js.map +1 -1
- package/dist/subtitles/Subtitles.js +2 -2
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.js +17 -18
- package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
- package/dist/synthesis/CoquiServerTTS.js +1 -1
- package/dist/synthesis/CoquiServerTTS.js.map +1 -1
- package/dist/synthesis/ElevenlabsTTS.js +1 -1
- package/dist/synthesis/ElevenlabsTTS.js.map +1 -1
- package/dist/synthesis/EspeakTTS.d.ts +0 -1
- package/dist/synthesis/EspeakTTS.js +0 -9
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.js +7 -8
- package/dist/synthesis/FliteTTS.js.map +1 -1
- package/dist/synthesis/GoogleCloudTTS.d.ts +1 -1
- package/dist/synthesis/GoogleCloudTTS.js +2 -1
- package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
- package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
- package/dist/synthesis/GoogleTranslateTTS.js +4 -3
- package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js +32 -7
- package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
- package/dist/synthesis/SapiTTS.js +1 -1
- package/dist/synthesis/SapiTTS.js.map +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.d.ts +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.js +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.js.map +1 -1
- package/dist/synthesis/SvoxPicoTTS.js +6 -6
- package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.js +2 -2
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/tests/Test.js +1 -47
- package/dist/tests/Test.js.map +1 -1
- package/dist/text-language-detection/FastTextLanguageDetection.js +2 -2
- package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
- package/dist/typings/TypedArray.d.ts +4 -0
- package/dist/typings/TypedArray.js +2 -0
- package/dist/typings/TypedArray.js.map +1 -0
- package/dist/utilities/BinaryArrayConversion.d.ts +12 -22
- package/dist/utilities/BinaryArrayConversion.js +40 -90
- package/dist/utilities/BinaryArrayConversion.js.map +1 -1
- package/dist/utilities/BinaryUtilities.d.ts +13 -0
- package/dist/utilities/BinaryUtilities.js +113 -0
- package/dist/utilities/BinaryUtilities.js.map +1 -0
- package/dist/utilities/Compression.js +7 -6
- package/dist/utilities/Compression.js.map +1 -1
- package/dist/utilities/FileDownloader.js +26 -47
- package/dist/utilities/FileDownloader.js.map +1 -1
- package/dist/utilities/FileReader.d.ts +14 -0
- package/dist/utilities/FileReader.js +71 -0
- package/dist/utilities/FileReader.js.map +1 -0
- package/dist/utilities/FileSystem.d.ts +19 -16
- package/dist/utilities/FileSystem.js +170 -109
- package/dist/utilities/FileSystem.js.map +1 -1
- package/dist/utilities/FileWriter.d.ts +12 -0
- package/dist/utilities/FileWriter.js +60 -0
- package/dist/utilities/FileWriter.js.map +1 -0
- package/dist/utilities/NpmUtilities.d.ts +1 -0
- package/dist/utilities/NpmUtilities.js +14 -0
- package/dist/utilities/NpmUtilities.js.map +1 -0
- package/dist/utilities/PackageManager.js +7 -5
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/PathUtilities.d.ts +8 -0
- package/dist/utilities/PathUtilities.js +28 -7
- package/dist/utilities/PathUtilities.js.map +1 -1
- package/dist/utilities/SignalChannel.d.ts +3 -1
- package/dist/utilities/SignalChannel.js +9 -5
- package/dist/utilities/SignalChannel.js.map +1 -1
- package/dist/utilities/StringBuilder.d.ts +10 -0
- package/dist/utilities/StringBuilder.js +39 -0
- package/dist/utilities/StringBuilder.js.map +1 -0
- package/dist/utilities/StringUtilities.js.map +1 -1
- package/dist/utilities/TarballMaker.js +6 -7
- package/dist/utilities/TarballMaker.js.map +1 -1
- package/dist/utilities/Timer.js +2 -2
- package/dist/utilities/Timer.js.map +1 -1
- package/dist/utilities/Utilities.d.ts +11 -5
- package/dist/utilities/Utilities.js +69 -33
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/VirtualFileReadStream.d.ts +3 -3
- package/dist/utilities/VirtualFileReadStream.js.map +1 -1
- package/dist/utilities/WasmMemoryManager.d.ts +5 -2
- package/dist/utilities/WasmMemoryManager.js +15 -4
- package/dist/utilities/WasmMemoryManager.js.map +1 -1
- package/docs/API.md +1 -1
- package/docs/Licenses.md +3 -0
- package/docs/Options.md +9 -3
- package/docs/Tasklist.md +0 -1
- package/docs/Technical.md +2 -2
- package/package.json +20 -22
- package/src/alignment/DTWSequenceAlignment.ts +5 -5
- package/src/alignment/SpeechAlignment.ts +6 -6
- package/src/api/Alignment.ts +65 -12
- package/src/api/Denoising.ts +97 -17
- package/src/api/SourceSeparation.ts +11 -8
- package/src/api/SpeechLanguageDetection.ts +4 -4
- package/src/api/Synthesis.ts +15 -11
- package/src/api/VoiceActivityDetection.ts +2 -2
- package/src/audio/AudioBufferConversion.ts +84 -45
- package/src/audio/AudioPlayer.ts +155 -53
- package/src/audio/AudioUtilities.ts +38 -22
- package/src/audio/SoxPath.ts +3 -3
- package/src/build-tools/MakeTarballsForInstalledPackages.ts +3 -3
- package/src/cli/CLI.ts +30 -36
- package/src/cli/CLIConfigFile.ts +2 -2
- package/src/cli/CLIOptions.ts +4 -1
- package/src/codecs/FFMpegTranscoder.ts +11 -11
- package/src/codecs/TIMITCodec.ts +5 -4
- package/src/codecs/WaveCodec.ts +42 -39
- package/src/data-structures/DynamicTypedArray.ts +64 -0
- package/src/denoising/NSNet2.ts +182 -0
- package/src/denoising/RNNoise.ts +3 -3
- package/src/dsp/FFT.ts +21 -1
- package/src/encodings/Ascii.ts +60 -0
- package/src/encodings/Base64.ts +157 -0
- package/src/encodings/Hex.ts +67 -0
- package/src/{utilities → encodings}/LEB128.ts +4 -4
- package/src/{utilities → encodings}/LPVarInt.ts +6 -6
- package/src/encodings/TextEncodingsCommon.ts +4 -0
- package/src/encodings/Utf16.ts +52 -0
- package/src/encodings/Utf32.ts +62 -0
- package/src/encodings/Utf8.ts +117 -0
- package/src/math/MedianFilter.ts +0 -2
- package/src/nlp/JapaneseSegmentation.ts +2 -2
- package/src/recognition/GoogleCloudSTT.ts +2 -1
- package/src/recognition/SileroSTT.ts +3 -3
- package/src/recognition/VoskSTT.ts +3 -3
- package/src/recognition/WhisperCppSTT.ts +4 -5
- package/src/recognition/WhisperSTT.ts +8 -7
- package/src/server/Client.ts +4 -3
- package/src/server/Server.ts +6 -5
- package/src/server/Worker.ts +1 -1
- package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
- package/src/speech-search/DTWSpeechSearch.ts +36 -7
- package/src/subtitles/Subtitles.ts +3 -3
- package/src/synthesis/AzureCognitiveServicesTTS.ts +18 -15
- package/src/synthesis/CoquiServerTTS.ts +2 -2
- package/src/synthesis/ElevenlabsTTS.ts +1 -1
- package/src/synthesis/EspeakTTS.ts +0 -15
- package/src/synthesis/FliteTTS.ts +7 -8
- package/src/synthesis/GoogleCloudTTS.ts +3 -2
- package/src/synthesis/GoogleTranslateTTS.ts +5 -4
- package/src/synthesis/MicrosoftEdgeTTS.ts +47 -15
- package/src/synthesis/SapiTTS.ts +1 -1
- package/src/synthesis/StreamlabsPollyTTS.ts +1 -1
- package/src/synthesis/SvoxPicoTTS.ts +8 -8
- package/src/synthesis/VitsTTS.ts +2 -2
- package/src/tests/Test.ts +1 -60
- package/src/text-language-detection/FastTextLanguageDetection.ts +2 -2
- package/src/typings/Fillers.d.ts +2 -4
- package/src/typings/TypedArray.ts +5 -0
- package/src/utilities/BinaryArrayConversion.ts +51 -125
- package/src/utilities/BinaryUtilities.ts +138 -0
- package/src/utilities/Compression.ts +7 -6
- package/src/utilities/FileDownloader.ts +27 -52
- package/src/utilities/FileReader.ts +89 -0
- package/src/utilities/FileSystem.ts +213 -120
- package/src/utilities/FileWriter.ts +72 -0
- package/src/utilities/NpmUtilities.ts +23 -0
- package/src/utilities/PackageManager.ts +8 -5
- package/src/utilities/PathUtilities.ts +36 -7
- package/src/utilities/SignalChannel.ts +14 -7
- package/src/utilities/StringBuilder.ts +45 -0
- package/src/utilities/StringUtilities.ts +2 -0
- package/src/utilities/TarballMaker.ts +6 -7
- package/src/utilities/Timer.ts +4 -2
- package/src/utilities/Utilities.ts +79 -45
- package/src/utilities/VirtualFileReadStream.ts +5 -5
- package/src/utilities/WasmMemoryManager.ts +20 -6
- package/tsconfig.json +96 -0
- package/dist/utilities/DynamicUint8Array.d.ts +0 -9
- package/dist/utilities/DynamicUint8Array.js +0 -31
- package/dist/utilities/DynamicUint8Array.js.map +0 -1
- package/dist/utilities/LEB128.js.map +0 -1
- package/dist/utilities/LPVarInt.js.map +0 -1
- package/dist/utilities/Queue.js.map +0 -1
- package/dist/utilities/WindowedList.js.map +0 -1
- package/src/utilities/DynamicUint8Array.ts +0 -39
- /package/dist/{utilities → data-structures}/Queue.d.ts +0 -0
- /package/dist/{utilities → data-structures}/Queue.js +0 -0
- /package/dist/{utilities → data-structures}/WindowedList.d.ts +0 -0
- /package/dist/{utilities → data-structures}/WindowedList.js +0 -0
- /package/src/{utilities → data-structures}/Queue.ts +0 -0
- /package/src/{utilities → data-structures}/WindowedList.ts +0 -0
package/src/audio/SoxPath.ts
CHANGED
|
@@ -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
|
|
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
|
|
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(
|
|
12
|
+
if (skipIfExists && existsSync(joinPath(tarballDir, `${packageName}.tar.gz`))) {
|
|
13
13
|
continue
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const packagePath =
|
|
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 {
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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 (
|
|
1821
|
-
parsedValue =
|
|
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 =
|
|
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
|
|
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) => {
|
package/src/cli/CLIConfigFile.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { readAndParseJsonFile,
|
|
1
|
+
import { readAndParseJsonFile, readFileAsUtf8 } from '../utilities/FileSystem.js'
|
|
2
2
|
|
|
3
3
|
export async function parseConfigFile(path: string): Promise<ParsedConfigFile> {
|
|
4
|
-
const fileContent = await
|
|
4
|
+
const fileContent = await readFileAsUtf8(path)
|
|
5
5
|
|
|
6
6
|
const lines = fileContent
|
|
7
7
|
.split(/\r?\n/g)
|
package/src/cli/CLIOptions.ts
CHANGED
|
@@ -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,
|
|
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 |
|
|
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 |
|
|
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 |
|
|
61
|
-
return new Promise<
|
|
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(
|
|
65
|
+
const args = buildCommandLineArguments(isUint8Array(input) ? '-' : input, outputOptions)
|
|
66
66
|
|
|
67
67
|
const process = spawn(ffmpegCommand, args)
|
|
68
68
|
|
|
69
|
-
if (
|
|
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:
|
|
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 =
|
|
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
|
|
209
|
+
return joinPath(ffmpegPackagePath, filename)
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
export function getDefaultFFMpegOptionsForSpeech(fileExtension: string, customBitrate?: number) {
|
package/src/codecs/TIMITCodec.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { decodeToChannels } from '../audio/AudioBufferConversion.js'
|
|
2
|
-
import {
|
|
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
|
|
7
|
+
return decodeTimitAudio(await readFileAsBinary(filename))
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export function decodeTimitAudio(data:
|
|
10
|
-
if (data.subarray(0, 16)
|
|
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
|
|
package/src/codecs/WaveCodec.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as AudioBufferConversion from '../audio/AudioBufferConversion.js'
|
|
2
2
|
import { RawAudio } from '../audio/AudioUtilities.js'
|
|
3
|
-
import {
|
|
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 =
|
|
20
|
-
dataSubChunkBuffer
|
|
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
|
-
|
|
25
|
+
writeUint32LE(dataSubChunkBuffer, dataChunkLength, 4)
|
|
23
26
|
dataSubChunkBuffer.set(audioBuffer, 8)
|
|
24
27
|
|
|
25
|
-
const riffChunkHeaderBuffer =
|
|
26
|
-
riffChunkHeaderBuffer
|
|
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
|
-
|
|
29
|
-
riffChunkHeaderBuffer
|
|
31
|
+
writeUint32LE(riffChunkHeaderBuffer, riffChunkLength, 4)
|
|
32
|
+
writeAscii(riffChunkHeaderBuffer, 'WAVE', 8)
|
|
30
33
|
|
|
31
|
-
return
|
|
34
|
+
return concatUint8Arrays([riffChunkHeaderBuffer, formatSubChunkBuffer, dataSubChunkBuffer])
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
export function decodeWave(waveData:
|
|
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)
|
|
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
|
|
48
|
+
let riffChunkSize = readUint32LE(waveData, readOffset)
|
|
46
49
|
|
|
47
50
|
readOffset += 4
|
|
48
51
|
|
|
49
|
-
const waveId = waveData.subarray(readOffset, readOffset + 4)
|
|
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:
|
|
70
|
-
const dataBuffers:
|
|
72
|
+
let formatSubChunkBodyBuffer: Uint8Array | undefined
|
|
73
|
+
const dataBuffers: Uint8Array[] = []
|
|
71
74
|
|
|
72
75
|
while (true) {
|
|
73
|
-
const subChunkIdentifier = waveData.subarray(readOffset, readOffset + 4)
|
|
76
|
+
const subChunkIdentifier = decodeAscii(waveData.subarray(readOffset, readOffset + 4))
|
|
74
77
|
readOffset += 4
|
|
75
78
|
|
|
76
|
-
let subChunkSize = waveData
|
|
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 =
|
|
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:
|
|
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 =
|
|
183
|
+
const result = new Uint8Array(serializedSize)
|
|
181
184
|
|
|
182
|
-
result
|
|
183
|
-
|
|
185
|
+
writeAscii(result, 'fmt ', 0) // + 4
|
|
186
|
+
writeUint32LE(result, serializedSize - 8, 4) // + 4
|
|
184
187
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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(
|
|
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:
|
|
208
|
-
let sampleFormat =
|
|
209
|
-
const channelCount =
|
|
210
|
-
const sampleRate =
|
|
211
|
-
const bitDepth =
|
|
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 =
|
|
222
|
+
speakerPositionMask = readUint16LE(formatChunkBody, 20)
|
|
220
223
|
|
|
221
|
-
const guid = formatChunkBody.subarray(24, 40)
|
|
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>
|