echogarden 1.8.7 → 2.0.1
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/encodings/HtmlEscape.d.ts +1 -0
- package/dist/encodings/HtmlEscape.js +30 -0
- package/dist/encodings/HtmlEscape.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 +4 -0
- package/dist/encodings/Utf32.js +32 -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.d.ts +0 -1
- package/dist/math/MedianFilter.js +0 -10
- 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 +19 -20
- 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 +2 -11
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.js +8 -9
- 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 +34 -9
- 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/text-translation/GoogleTranslateTextTranslation.js +1 -1
- package/dist/text-translation/GoogleTranslateTextTranslation.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/CLI.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 +22 -25
- 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/encodings/HtmlEscape.ts +39 -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 +44 -0
- package/src/encodings/Utf8.ts +117 -0
- package/src/math/MedianFilter.ts +0 -16
- 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 +20 -18
- package/src/synthesis/CoquiServerTTS.ts +2 -2
- package/src/synthesis/ElevenlabsTTS.ts +1 -1
- package/src/synthesis/EspeakTTS.ts +2 -18
- package/src/synthesis/FliteTTS.ts +8 -10
- package/src/synthesis/GoogleCloudTTS.ts +3 -2
- package/src/synthesis/GoogleTranslateTTS.ts +5 -4
- package/src/synthesis/MicrosoftEdgeTTS.ts +49 -18
- 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/text-translation/GoogleTranslateTextTranslation.ts +1 -1
- package/src/typings/Fillers.d.ts +2 -10
- 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 +80 -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/AudioPlayer.ts
CHANGED
|
@@ -2,37 +2,36 @@ import { parentPort } from 'node:worker_threads'
|
|
|
2
2
|
|
|
3
3
|
import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
|
|
4
4
|
|
|
5
|
-
import { RawAudio, encodeRawAudioToWave, fadeAudioInOut, getRawAudioDuration, sliceRawAudioByTime } from './AudioUtilities.js'
|
|
6
|
-
import * as AudioBufferConversion from './AudioBufferConversion.js'
|
|
5
|
+
import { RawAudio, encodeRawAudioToWave, fadeAudioInOut, getRawAudioDuration, sliceAudioChannels, sliceRawAudioByTime } from './AudioUtilities.js'
|
|
7
6
|
import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
|
|
8
7
|
|
|
9
8
|
import { Timer } from '../utilities/Timer.js'
|
|
10
|
-
import { getRandomHexString, waitTimeout, writeToStderr } from '../utilities/Utilities.js'
|
|
11
|
-
import { encodeToAudioBuffer } from './AudioBufferConversion.js'
|
|
9
|
+
import { clip, getRandomHexString, waitTimeout, writeToStderr } from '../utilities/Utilities.js'
|
|
10
|
+
import { encodeToAudioBuffer, float32ToInt16Pcm, interleaveChannels } from './AudioBufferConversion.js'
|
|
12
11
|
import { OpenPromise } from '../utilities/OpenPromise.js'
|
|
13
12
|
import { Timeline, addWordTextOffsetsToTimeline } from '../utilities/Timeline.js'
|
|
14
|
-
import { readAndParseJsonFile,
|
|
13
|
+
import { readAndParseJsonFile, readFileAsUtf8, remove, writeFile } from '../utilities/FileSystem.js'
|
|
15
14
|
import { tryResolvingSoxPath } from './SoxPath.js'
|
|
16
15
|
import { SignalChannel } from '../utilities/SignalChannel.js'
|
|
17
16
|
import { deepClone } from '../utilities/ObjectUtilities.js'
|
|
18
17
|
import { appName } from '../api/Common.js'
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
18
|
+
import { getAppTempDir, joinPath } from '../utilities/PathUtilities.js'
|
|
19
|
+
import { type AudioOutput } from '@echogarden/audio-io'
|
|
21
20
|
|
|
22
|
-
export async function playAudioFileWithTimelineFile(audioFilename: string, timelineFileName: string, transcriptFileName?: string) {
|
|
21
|
+
export async function playAudioFileWithTimelineFile(audioFilename: string, timelineFileName: string, transcriptFileName?: string, player?: AudioPlayerID) {
|
|
23
22
|
const rawAudio = await FFMpegTranscoder.decodeToChannels(audioFilename, 48000, 1)
|
|
24
23
|
|
|
25
24
|
const timeline = await readAndParseJsonFile(timelineFileName)
|
|
26
25
|
|
|
27
26
|
let transcript: string | undefined
|
|
28
27
|
if (transcriptFileName) {
|
|
29
|
-
transcript = await
|
|
28
|
+
transcript = await readFileAsUtf8(transcriptFileName)
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
await playAudioWithWordTimeline(rawAudio, timeline, transcript)
|
|
31
|
+
await playAudioWithWordTimeline(rawAudio, timeline, transcript, player)
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline: Timeline, transcript?: string) {
|
|
34
|
+
export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline: Timeline, transcript?: string, player?: AudioPlayerID) {
|
|
36
35
|
if (!transcript) {
|
|
37
36
|
transcript = wordTimeline.map(entry => entry.text).join(' ')
|
|
38
37
|
}
|
|
@@ -82,77 +81,178 @@ export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline
|
|
|
82
81
|
const keypressListenerStartTimestamp = Date.now()
|
|
83
82
|
|
|
84
83
|
function keypressHandler(message: any) {
|
|
85
|
-
if (message.name
|
|
86
|
-
message.key.name
|
|
87
|
-
message.timestamp >= keypressListenerStartTimestamp) {
|
|
84
|
+
if (message.name === 'keypress') {
|
|
85
|
+
//console.log(`Keypress: ${message.key.name}`)
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
if (message.timestamp < keypressListenerStartTimestamp) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const keyName = message.key.name
|
|
92
|
+
|
|
93
|
+
if (keyName === 'return') {
|
|
94
|
+
signalChannel.send('abort')
|
|
95
|
+
} else if (keyName === 'left') {
|
|
96
|
+
signalChannel.send('skip', -1)
|
|
97
|
+
} else if (keyName === 'right') {
|
|
98
|
+
signalChannel.send('skip', 1)
|
|
99
|
+
|
|
100
|
+
if (false) {
|
|
101
|
+
const nextTimelineEntryIndex = timelineEntryIndex
|
|
102
|
+
|
|
103
|
+
if (nextTimelineEntryIndex < wordTimeline.length) {
|
|
104
|
+
//signalChannel.send('skip', 5)
|
|
105
|
+
const targetTime = wordTimeline[nextTimelineEntryIndex].startTime
|
|
106
|
+
|
|
107
|
+
signalChannel.send('seek', targetTime)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} else if (keyName === 'space') {
|
|
111
|
+
signalChannel.send('togglePause')
|
|
112
|
+
}
|
|
90
113
|
}
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
parentPort?.on('message', keypressHandler)
|
|
94
117
|
|
|
95
|
-
await playAudioSamples(rawAudio, onTimePosition, signalChannel)
|
|
118
|
+
await playAudioSamples(rawAudio, onTimePosition, signalChannel, player)
|
|
96
119
|
|
|
97
120
|
parentPort?.off('message', keypressHandler)
|
|
98
121
|
|
|
99
122
|
writeToStderr('\n')
|
|
100
123
|
}
|
|
101
124
|
|
|
102
|
-
export async function
|
|
103
|
-
|
|
104
|
-
let phoneIndex = 0
|
|
125
|
+
export async function playAudioSamplesWithKeyboardControls(rawAudio: RawAudio, player?: AudioPlayerID) {
|
|
126
|
+
const signalChannel = new SignalChannel()
|
|
105
127
|
|
|
106
|
-
|
|
107
|
-
for (; wordIndex < timeline.length; wordIndex++) {
|
|
108
|
-
const wordEntry = timeline[wordIndex]
|
|
109
|
-
const phoneTimeline = wordEntry.timeline!
|
|
128
|
+
const keypressListenerStartTimestamp = Date.now()
|
|
110
129
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
130
|
+
function keypressHandler(message: any) {
|
|
131
|
+
if (message.name === 'keypress') {
|
|
132
|
+
//console.log(`Keypress: ${message.key.name}`)
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
if (message.timestamp < keypressListenerStartTimestamp) {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
117
137
|
|
|
118
|
-
|
|
119
|
-
return
|
|
120
|
-
}
|
|
138
|
+
const keyName = message.key.name
|
|
121
139
|
|
|
122
|
-
|
|
140
|
+
if (keyName === 'return') {
|
|
141
|
+
signalChannel.send('abort')
|
|
142
|
+
} else if (keyName === 'left') {
|
|
143
|
+
signalChannel.send('skip', -1)
|
|
144
|
+
} else if (keyName === 'right') {
|
|
145
|
+
signalChannel.send('skip', 1)
|
|
146
|
+
} else if (keyName === 'space') {
|
|
147
|
+
signalChannel.send('togglePause')
|
|
123
148
|
}
|
|
124
|
-
|
|
125
|
-
writeToStderr(`| `)
|
|
126
|
-
phoneIndex = 0
|
|
127
149
|
}
|
|
128
150
|
}
|
|
129
151
|
|
|
130
|
-
|
|
152
|
+
parentPort?.on('message', keypressHandler)
|
|
131
153
|
|
|
132
|
-
await playAudioSamples(rawAudio,
|
|
154
|
+
await playAudioSamples(rawAudio, undefined, signalChannel, player)
|
|
133
155
|
|
|
134
|
-
|
|
156
|
+
parentPort?.off('message', keypressHandler)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosition: number) => void, signalChannel?: SignalChannel, player?: AudioPlayerID) {
|
|
160
|
+
if (!player) {
|
|
161
|
+
player = 'audio-io'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (player === 'audio-io') {
|
|
165
|
+
return playAudioSamples_AudioIO(rawAudio, onTimePosition, signalChannel)
|
|
166
|
+
} else if (player === 'sox') {
|
|
167
|
+
return playAudioSamples_Sox(rawAudio, onTimePosition, signalChannel)
|
|
168
|
+
} else {
|
|
169
|
+
throw new Error(`Unsupported audio player ID: ${player}`)
|
|
170
|
+
}
|
|
135
171
|
}
|
|
136
172
|
|
|
173
|
+
export async function playAudioSamples_AudioIO(rawAudio: RawAudio, onTimePosition?: (timePosition: number) => void, signalChannel?: SignalChannel) {
|
|
174
|
+
const openPromise = new OpenPromise()
|
|
175
|
+
|
|
176
|
+
const sampleRate = rawAudio.sampleRate
|
|
177
|
+
const channelCount = rawAudio.audioChannels.length
|
|
178
|
+
const bufferDuration = 100.0
|
|
179
|
+
const audioFrameCount = rawAudio.audioChannels[0].length
|
|
180
|
+
const audioDuration = getRawAudioDuration(rawAudio)
|
|
181
|
+
|
|
182
|
+
const { createAudioOutput } = await import('@echogarden/audio-io')
|
|
183
|
+
|
|
184
|
+
let frameOffset = 0
|
|
185
|
+
let audioOutput: AudioOutput
|
|
186
|
+
let abortRequested = false
|
|
187
|
+
let ended = false
|
|
188
|
+
|
|
189
|
+
let isPaused = false
|
|
190
|
+
|
|
191
|
+
// Define an audio output handler function
|
|
192
|
+
async function audioOutputHandler(outputBuffer: Int16Array) {
|
|
193
|
+
if (ended) {
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (onTimePosition) {
|
|
198
|
+
const audioTime = Math.min(frameOffset / sampleRate, audioDuration)
|
|
199
|
+
|
|
200
|
+
onTimePosition(audioTime)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (isPaused) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const chunkFrameCount = outputBuffer.length / channelCount
|
|
208
|
+
|
|
209
|
+
const floatAudioChunk = sliceAudioChannels(rawAudio.audioChannels, frameOffset, frameOffset + chunkFrameCount)
|
|
210
|
+
const interleavedFloatAudioChunk = interleaveChannels(floatAudioChunk)
|
|
211
|
+
const int16AudioChunk = float32ToInt16Pcm(interleavedFloatAudioChunk)
|
|
137
212
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
213
|
+
outputBuffer.set(int16AudioChunk)
|
|
214
|
+
|
|
215
|
+
frameOffset += chunkFrameCount
|
|
216
|
+
|
|
217
|
+
if (abortRequested || int16AudioChunk.length < outputBuffer.length) {
|
|
218
|
+
ended = true
|
|
219
|
+
|
|
220
|
+
await audioOutput.dispose()
|
|
221
|
+
openPromise.resolve()
|
|
222
|
+
}
|
|
141
223
|
}
|
|
142
224
|
|
|
143
|
-
|
|
144
|
-
|
|
225
|
+
if (signalChannel) {
|
|
226
|
+
signalChannel.on('abort', () => {
|
|
227
|
+
abortRequested = true
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
signalChannel.on('skip', (durationToSkip: number) => {
|
|
231
|
+
frameOffset += durationToSkip * sampleRate
|
|
232
|
+
frameOffset = Math.floor(frameOffset)
|
|
233
|
+
frameOffset = clip(frameOffset, 0, audioFrameCount)
|
|
234
|
+
})
|
|
145
235
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
236
|
+
signalChannel.on('seek', (timeToSeekTo: number) => {
|
|
237
|
+
frameOffset = Math.floor(timeToSeekTo * sampleRate)
|
|
238
|
+
frameOffset = clip(frameOffset, 0, audioFrameCount)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
signalChannel.on('togglePause', () => {
|
|
242
|
+
isPaused = !isPaused
|
|
243
|
+
})
|
|
150
244
|
}
|
|
151
245
|
|
|
152
|
-
|
|
246
|
+
audioOutput = await createAudioOutput({
|
|
247
|
+
sampleRate, // Sample rate in Hz, should be an integer like 44100, 22050, 8000
|
|
248
|
+
channelCount, // Channel count, likely 1 (mono), or 2 (stereo)
|
|
249
|
+
bufferDuration, // Target buffer duration, in milliseconds. Defaults to 100.0
|
|
250
|
+
}, audioOutputHandler)
|
|
251
|
+
|
|
252
|
+
return openPromise.promise
|
|
153
253
|
}
|
|
154
254
|
|
|
155
|
-
export function
|
|
255
|
+
export function playAudioSamples_Sox(rawAudio: RawAudio, onTimePosition?: (timePosition: number) => void, signalChannel?: SignalChannel, microFadeInOut = true) {
|
|
156
256
|
return new Promise<void>(async (resolve, reject) => {
|
|
157
257
|
if (microFadeInOut) {
|
|
158
258
|
rawAudio = fadeAudioInOut(rawAudio, 0.0025)
|
|
@@ -180,7 +280,7 @@ export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosit
|
|
|
180
280
|
}
|
|
181
281
|
|
|
182
282
|
let tempFilePath: string | undefined
|
|
183
|
-
let audioBuffer:
|
|
283
|
+
let audioBuffer: Uint8Array | undefined
|
|
184
284
|
|
|
185
285
|
async function cleanup() {
|
|
186
286
|
if (tempFilePath) {
|
|
@@ -199,7 +299,7 @@ export function playAudioSamples(rawAudio: RawAudio, onTimePosition?: (timePosit
|
|
|
199
299
|
{}
|
|
200
300
|
)
|
|
201
301
|
} else {
|
|
202
|
-
tempFilePath =
|
|
302
|
+
tempFilePath = joinPath(getAppTempDir(appName), `${getRandomHexString(16)}.wav`)
|
|
203
303
|
const waveFileBuffer = encodeRawAudioToWave(rawAudio)
|
|
204
304
|
await writeFile(tempFilePath, waveFileBuffer)
|
|
205
305
|
|
|
@@ -282,7 +382,7 @@ export function playAudioSamples_Speaker(rawAudio: RawAudio, onTimePosition?: (t
|
|
|
282
382
|
}
|
|
283
383
|
|
|
284
384
|
const channelCount = rawAudio.audioChannels.length
|
|
285
|
-
let audioData =
|
|
385
|
+
let audioData = encodeToAudioBuffer(rawAudio.audioChannels)
|
|
286
386
|
|
|
287
387
|
const { default: Speaker } = await import('speaker')
|
|
288
388
|
|
|
@@ -315,7 +415,7 @@ export function playAudioSamples_Speaker(rawAudio: RawAudio, onTimePosition?: (t
|
|
|
315
415
|
mpg123AudioBufferSize = bytesPerSecond * mpg123AudioBufferDuration
|
|
316
416
|
}
|
|
317
417
|
|
|
318
|
-
audioData =
|
|
418
|
+
audioData = concatUint8Arrays([audioData, new Uint8Array(mpg123AudioBufferSize)])
|
|
319
419
|
|
|
320
420
|
const maxChunkSize = mpg123AudioBufferSize
|
|
321
421
|
|
|
@@ -363,3 +463,5 @@ export const charactersToWriteAhead = [
|
|
|
363
463
|
')', ']', '}', `"`, `'`, '”', '’',
|
|
364
464
|
'-', '—', '»', '،', '؟'
|
|
365
465
|
]
|
|
466
|
+
|
|
467
|
+
export type AudioPlayerID = 'audio-io' | 'sox'
|
|
@@ -11,7 +11,7 @@ export function encodeRawAudioToWave(rawAudio: RawAudio, bitDepth: BitDepth = 16
|
|
|
11
11
|
return encodeWave(rawAudio, bitDepth, sampleFormat, speakerPositionMask)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function decodeWaveToRawAudio(waveFileBuffer:
|
|
14
|
+
export function decodeWaveToRawAudio(waveFileBuffer: Uint8Array, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
|
|
15
15
|
return decodeWave(waveFileBuffer, ignoreTruncatedChunks, ignoreOverflowingDataChunks)
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -401,33 +401,25 @@ export function getRawAudioDuration(rawAudio: RawAudio) {
|
|
|
401
401
|
export async function ensureRawAudio(input: AudioSourceParam, outSampleRate?: number, outChannelCount?: number) {
|
|
402
402
|
let inputAsRawAudio: RawAudio = input as RawAudio
|
|
403
403
|
|
|
404
|
-
if (
|
|
404
|
+
if (isRawAudio(input)) {
|
|
405
405
|
const inputAudioChannelCount = inputAsRawAudio.audioChannels.length
|
|
406
406
|
|
|
407
407
|
if (outChannelCount == 1 && inputAudioChannelCount > 1) {
|
|
408
408
|
inputAsRawAudio = downmixToMono(inputAsRawAudio)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (outChannelCount == 2 && inputAudioChannelCount == 1) {
|
|
409
|
+
} else if (outChannelCount == 2 && inputAudioChannelCount == 1) {
|
|
412
410
|
inputAsRawAudio = cloneRawAudio(inputAsRawAudio)
|
|
413
411
|
inputAsRawAudio.audioChannels.push(inputAsRawAudio.audioChannels[0].slice())
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (outChannelCount != null && outChannelCount > 2 && outChannelCount != inputAudioChannelCount) {
|
|
412
|
+
} else if (outChannelCount != null && outChannelCount > 2 && outChannelCount != inputAudioChannelCount) {
|
|
417
413
|
throw new Error(`Can't convert ${inputAudioChannelCount} channels to ${outChannelCount} channels. Channel conversion of raw audio currently only supports mono and stereo inputs.`)
|
|
418
414
|
}
|
|
419
415
|
|
|
420
|
-
if (outSampleRate && inputAsRawAudio.sampleRate
|
|
416
|
+
if (outSampleRate && inputAsRawAudio.sampleRate !== outSampleRate) {
|
|
421
417
|
inputAsRawAudio = await resampleAudioSpeex(inputAsRawAudio, outSampleRate)
|
|
422
418
|
}
|
|
423
419
|
} else if (typeof input == 'string' || input instanceof Uint8Array) {
|
|
424
|
-
|
|
425
|
-
input = Buffer.from(input)
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const inputAsStringOrBuffer = input as string | Buffer
|
|
420
|
+
const inputAsStringOrUint8Array = input as string | Uint8Array
|
|
429
421
|
|
|
430
|
-
inputAsRawAudio = await FFMpegTranscoder.decodeToChannels(
|
|
422
|
+
inputAsRawAudio = await FFMpegTranscoder.decodeToChannels(inputAsStringOrUint8Array, outSampleRate, outChannelCount)
|
|
431
423
|
} else {
|
|
432
424
|
throw new Error('Received an invalid input audio data type.')
|
|
433
425
|
}
|
|
@@ -436,21 +428,45 @@ export async function ensureRawAudio(input: AudioSourceParam, outSampleRate?: nu
|
|
|
436
428
|
}
|
|
437
429
|
|
|
438
430
|
export function subtractAudio(audio1: RawAudio, audio2: RawAudio) {
|
|
439
|
-
|
|
431
|
+
if (audio1.sampleRate !== audio2.sampleRate) {
|
|
432
|
+
throw new Error(`Audio sequences have different sample rates`)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (audio1.audioChannels.length !== audio2.audioChannels.length) {
|
|
436
|
+
throw new Error(`Audio sequences have different channel counts`)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const sampleRate = audio1.sampleRate
|
|
440
|
+
const channelCount = audio1.audioChannels.length
|
|
441
|
+
const sampleCount = Math.min(audio1.audioChannels[0].length, audio2.audioChannels[0].length)
|
|
442
|
+
|
|
443
|
+
const subtractedAudioChannels: Float32Array[] = []
|
|
444
|
+
|
|
445
|
+
for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
|
|
446
|
+
const subtractedSamples = new Float32Array(sampleCount)
|
|
440
447
|
|
|
441
|
-
|
|
448
|
+
const samples1 = audio1.audioChannels[channelIndex]
|
|
449
|
+
const samples2 = audio2.audioChannels[channelIndex]
|
|
442
450
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
subtractedAudioChannels[channelIndex][i] = audio1.audioChannels[channelIndex][i] - audio2.audioChannels[channelIndex][i]
|
|
451
|
+
for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
|
|
452
|
+
subtractedSamples[sampleIndex] = samples1[sampleIndex] - samples2[sampleIndex]
|
|
446
453
|
}
|
|
454
|
+
|
|
455
|
+
subtractedAudioChannels.push(subtractedSamples)
|
|
447
456
|
}
|
|
448
457
|
|
|
449
|
-
const subtractedRawAudio: RawAudio = {
|
|
458
|
+
const subtractedRawAudio: RawAudio = {
|
|
459
|
+
audioChannels: subtractedAudioChannels,
|
|
460
|
+
sampleRate: sampleRate
|
|
461
|
+
}
|
|
450
462
|
|
|
451
463
|
return subtractedRawAudio
|
|
452
464
|
}
|
|
453
465
|
|
|
466
|
+
export function isRawAudio(obj: any): obj is RawAudio {
|
|
467
|
+
return typeof obj === 'object' && typeof obj.sampleRate === 'number' && Array.isArray(obj.audioChannels)
|
|
468
|
+
}
|
|
469
|
+
|
|
454
470
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
455
471
|
// Unit conversion
|
|
456
472
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -492,4 +508,4 @@ export type AudioEncoding = {
|
|
|
492
508
|
bitrate?: number
|
|
493
509
|
}
|
|
494
510
|
|
|
495
|
-
export type AudioSourceParam = string |
|
|
511
|
+
export type AudioSourceParam = string | Uint8Array | RawAudio
|
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
|
}
|