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