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/api/Denoising.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
2
2
|
|
|
3
|
-
import { AudioSourceParam, RawAudio, applyGainDecibelsInPlace, ensureRawAudio, getSamplePeakDecibels, mixAudio, normalizeAudioLevelInPlace } from '../audio/AudioUtilities.js'
|
|
3
|
+
import { AudioSourceParam, RawAudio, applyGainDecibels, applyGainDecibelsInPlace, attenuateIfClippingInPlace, ensureRawAudio, getSamplePeakDecibels, mixAudio, normalizeAudioLevelInPlace } from '../audio/AudioUtilities.js'
|
|
4
4
|
import { Logger } from '../utilities/Logger.js'
|
|
5
5
|
|
|
6
6
|
import { logToStderr } from '../utilities/Utilities.js'
|
|
7
7
|
import { resampleAudioSpeex } from '../dsp/SpeexResampler.js'
|
|
8
8
|
import { EngineMetadata } from './Common.js'
|
|
9
9
|
import chalk from 'chalk'
|
|
10
|
+
import { defaultNSNet2Options, NSNet2Options } from '../denoising/NSNet2.js'
|
|
11
|
+
import { loadPackage } from '../utilities/PackageManager.js'
|
|
10
12
|
|
|
11
13
|
const log = logToStderr
|
|
12
14
|
|
|
@@ -18,26 +20,34 @@ export async function denoise(input: AudioSourceParam, options: DenoisingOptions
|
|
|
18
20
|
|
|
19
21
|
const inputRawAudio = await ensureRawAudio(input)
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
logger.start(`Resample audio to ${processingSampleRate} Hz`)
|
|
24
|
-
const resampledRawAudio = await resampleAudioSpeex(inputRawAudio, processingSampleRate, 3)
|
|
25
|
-
|
|
26
|
-
logger.start(`Initialize ${options.method} module`)
|
|
23
|
+
logger.start(`Initialize ${options.engine} module`)
|
|
27
24
|
|
|
28
25
|
let denoisedAudio: RawAudio
|
|
29
26
|
|
|
30
|
-
switch (options.
|
|
27
|
+
switch (options.engine) {
|
|
31
28
|
case 'rnnoise': {
|
|
32
29
|
const RNNoise = await import('../denoising/RNNoise.js')
|
|
33
30
|
logger.end()
|
|
34
31
|
|
|
32
|
+
const processingSampleRate = 48000
|
|
33
|
+
|
|
34
|
+
logger.start(`Resample audio to ${processingSampleRate} Hz`)
|
|
35
|
+
const inputRawAudioResampled = await resampleAudioSpeex(inputRawAudio, processingSampleRate, 0)
|
|
36
|
+
|
|
35
37
|
const denoisedAudioChannels: Float32Array[] = []
|
|
36
38
|
|
|
37
|
-
for (
|
|
39
|
+
for (let channelIndex = 0; channelIndex < inputRawAudioResampled.audioChannels.length; channelIndex++) {
|
|
40
|
+
const audioChannel = inputRawAudioResampled.audioChannels[channelIndex]
|
|
41
|
+
|
|
38
42
|
const audioChannelRawAudio: RawAudio = { audioChannels: [audioChannel], sampleRate: processingSampleRate }
|
|
39
43
|
|
|
44
|
+
logger.end()
|
|
45
|
+
logger.logTitledMessage(`Denoise audio channel`, `${channelIndex}`, chalk.magentaBright)
|
|
46
|
+
|
|
40
47
|
const { denoisedRawAudio, frameVadProbabilities } = await RNNoise.denoiseAudio(audioChannelRawAudio)
|
|
48
|
+
|
|
49
|
+
logger.end()
|
|
50
|
+
|
|
41
51
|
denoisedAudioChannels.push(denoisedRawAudio.audioChannels[0])
|
|
42
52
|
}
|
|
43
53
|
|
|
@@ -46,11 +56,68 @@ export async function denoise(input: AudioSourceParam, options: DenoisingOptions
|
|
|
46
56
|
break
|
|
47
57
|
}
|
|
48
58
|
|
|
59
|
+
case 'nsnet2': {
|
|
60
|
+
const NSNet2 = await import('../denoising/NSNet2.js')
|
|
61
|
+
logger.end()
|
|
62
|
+
|
|
63
|
+
const nsnet2Options = options.nsnet2!
|
|
64
|
+
|
|
65
|
+
let processingSampleRate: number
|
|
66
|
+
let packageName: string
|
|
67
|
+
|
|
68
|
+
if (nsnet2Options.model === 'baseline-16khz') {
|
|
69
|
+
processingSampleRate = 16000
|
|
70
|
+
|
|
71
|
+
packageName = 'nsnet2-20ms-baseline'
|
|
72
|
+
} else if (nsnet2Options.model === 'baseline-48khz') {
|
|
73
|
+
processingSampleRate = 48000
|
|
74
|
+
|
|
75
|
+
packageName = 'nsnet2-20ms-48k-baseline'
|
|
76
|
+
} else {
|
|
77
|
+
throw new Error(`Unknown model name: ${nsnet2Options.model}`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!nsnet2Options.modelDirectoryPath) {
|
|
81
|
+
nsnet2Options.modelDirectoryPath = await loadPackage(packageName)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
logger.start(`Resample audio to ${processingSampleRate} Hz`)
|
|
85
|
+
const inputRawAudioResampled = await resampleAudioSpeex(inputRawAudio, processingSampleRate, 0)
|
|
86
|
+
|
|
87
|
+
const denoisedAudioChannels: Float32Array[] = []
|
|
88
|
+
|
|
89
|
+
for (let channelIndex = 0; channelIndex < inputRawAudioResampled.audioChannels.length; channelIndex++) {
|
|
90
|
+
const audioChannel = inputRawAudioResampled.audioChannels[channelIndex]
|
|
91
|
+
|
|
92
|
+
const audioChannelRawAudio: RawAudio = { audioChannels: [audioChannel], sampleRate: processingSampleRate }
|
|
93
|
+
|
|
94
|
+
logger.end()
|
|
95
|
+
|
|
96
|
+
logger.logTitledMessage(`Denoise audio channel`, `${channelIndex}`, chalk.magentaBright)
|
|
97
|
+
|
|
98
|
+
const { denoisedAudio } = await NSNet2.denoiseAudio(audioChannelRawAudio, nsnet2Options)
|
|
99
|
+
|
|
100
|
+
logger.end()
|
|
101
|
+
|
|
102
|
+
denoisedAudioChannels.push(denoisedAudio.audioChannels[0])
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
denoisedAudio = { audioChannels: denoisedAudioChannels, sampleRate: processingSampleRate }
|
|
106
|
+
|
|
107
|
+
break
|
|
108
|
+
}
|
|
109
|
+
|
|
49
110
|
default: {
|
|
50
|
-
throw new Error(`
|
|
111
|
+
throw new Error(`Engine '${options.engine}' is not recognized.`)
|
|
51
112
|
}
|
|
52
113
|
}
|
|
53
114
|
|
|
115
|
+
logger.logTitledMessage(`Postprocess`, ``, chalk.magentaBright)
|
|
116
|
+
|
|
117
|
+
logger.start(`Resample denoised audio (${denoisedAudio.sampleRate} Hz) back to original sample rate (${inputRawAudio.sampleRate} Hz)`)
|
|
118
|
+
|
|
119
|
+
denoisedAudio = await ensureRawAudio(denoisedAudio, inputRawAudio.sampleRate, inputRawAudio.audioChannels.length)
|
|
120
|
+
|
|
54
121
|
logger.start('Postprocess audio')
|
|
55
122
|
|
|
56
123
|
const shouldNormalize = options.postProcessing!.normalizeAudio!
|
|
@@ -58,9 +125,11 @@ export async function denoise(input: AudioSourceParam, options: DenoisingOptions
|
|
|
58
125
|
const maxGainIncreaseDecibels = options.postProcessing!.maxGainIncrease!
|
|
59
126
|
const dryMixGainDecibels = options.postProcessing!.dryMixGain!
|
|
60
127
|
|
|
128
|
+
attenuateIfClippingInPlace(denoisedAudio)
|
|
129
|
+
|
|
61
130
|
const preMixPeakDecibels = getSamplePeakDecibels(denoisedAudio.audioChannels)
|
|
62
|
-
|
|
63
|
-
denoisedAudio = mixAudio(denoisedAudio,
|
|
131
|
+
const inputRawAudioWithGain = applyGainDecibels(inputRawAudio, dryMixGainDecibels)
|
|
132
|
+
denoisedAudio = mixAudio(denoisedAudio, inputRawAudioWithGain)
|
|
64
133
|
const postMixPeakDecibels = getSamplePeakDecibels(denoisedAudio.audioChannels)
|
|
65
134
|
|
|
66
135
|
if (shouldNormalize) {
|
|
@@ -85,10 +154,11 @@ export interface DenoisingResult {
|
|
|
85
154
|
inputRawAudio: RawAudio
|
|
86
155
|
}
|
|
87
156
|
|
|
88
|
-
export type
|
|
157
|
+
export type DenoisingEngine = 'rnnoise' | 'nsnet2'
|
|
89
158
|
|
|
90
159
|
export interface DenoisingOptions {
|
|
91
|
-
|
|
160
|
+
engine?: DenoisingEngine,
|
|
161
|
+
|
|
92
162
|
postProcessing?: {
|
|
93
163
|
normalizeAudio: boolean
|
|
94
164
|
targetPeak: number
|
|
@@ -96,17 +166,21 @@ export interface DenoisingOptions {
|
|
|
96
166
|
|
|
97
167
|
dryMixGain?: number
|
|
98
168
|
}
|
|
169
|
+
|
|
170
|
+
nsnet2?: NSNet2Options
|
|
99
171
|
}
|
|
100
172
|
|
|
101
173
|
export const defaultDenoisingOptions: DenoisingOptions = {
|
|
102
|
-
|
|
174
|
+
engine: 'rnnoise',
|
|
103
175
|
|
|
104
176
|
postProcessing: {
|
|
105
177
|
normalizeAudio: false,
|
|
106
178
|
targetPeak: -3,
|
|
107
179
|
maxGainIncrease: 30,
|
|
108
|
-
dryMixGain: -
|
|
109
|
-
}
|
|
180
|
+
dryMixGain: -100,
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
nsnet2: defaultNSNet2Options,
|
|
110
184
|
}
|
|
111
185
|
|
|
112
186
|
export const denoisingEngines: EngineMetadata[] = [
|
|
@@ -115,5 +189,11 @@ export const denoisingEngines: EngineMetadata[] = [
|
|
|
115
189
|
name: 'RNNoise',
|
|
116
190
|
description: 'A noise suppression library based on a recurrent neural network.',
|
|
117
191
|
type: 'local'
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'nsnet2',
|
|
195
|
+
name: 'Noise Suppression Net 2',
|
|
196
|
+
description: 'Noise suppression models used as baselines for the ICASSP 2021 Deep Noise Suppression challenge.',
|
|
197
|
+
type: 'local'
|
|
118
198
|
}
|
|
119
199
|
]
|
|
@@ -5,15 +5,13 @@ import { loadPackage } from '../utilities/PackageManager.js';
|
|
|
5
5
|
import { EngineMetadata } from './Common.js';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { readdir } from '../utilities/FileSystem.js';
|
|
8
|
-
import path from 'node:path';
|
|
9
8
|
import { defaultMDXNetOptions, getProfileForMDXNetModelName, MDXNetOptions } from '../source-separation/MDXNetSourceSeparation.js';
|
|
9
|
+
import { joinPath } from '../utilities/PathUtilities.js';
|
|
10
10
|
|
|
11
11
|
export async function isolate(input: AudioSourceParam, options: SourceSeparationOptions): Promise<SourceSeparationResult> {
|
|
12
12
|
const logger = new Logger()
|
|
13
13
|
const startTimestamp = logger.getTimestamp()
|
|
14
14
|
|
|
15
|
-
await logger.startAsync('Prepare for source separation')
|
|
16
|
-
|
|
17
15
|
const inputRawAudio = await ensureRawAudio(input)
|
|
18
16
|
|
|
19
17
|
let isolatedRawAudio: RawAudio
|
|
@@ -34,22 +32,27 @@ export async function isolate(input: AudioSourceParam, options: SourceSeparation
|
|
|
34
32
|
throw new Error(`Couldn't find an ONNX model file in package directory`)
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
const modelPath =
|
|
35
|
+
const modelPath = joinPath(packageDir, modelFilename)
|
|
38
36
|
|
|
39
37
|
await logger.startAsync(`Convert audio to 44.1 kHz stereo`)
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
let inputRawAudioAs44100Stereo: RawAudio | undefined = await ensureRawAudio(inputRawAudio, 44100, 2)
|
|
42
40
|
|
|
43
41
|
logger.end()
|
|
44
42
|
|
|
45
43
|
const modelProfile = getProfileForMDXNetModelName(mdxNetOptions.model!)
|
|
46
44
|
|
|
47
|
-
isolatedRawAudio = await MDXNetSourceSeparation.isolate(
|
|
48
|
-
|
|
45
|
+
isolatedRawAudio = await MDXNetSourceSeparation.isolate(inputRawAudioAs44100Stereo, modelPath, modelProfile, mdxNetOptions)
|
|
49
46
|
logger.end()
|
|
50
47
|
|
|
48
|
+
// Release memory for the converted input audio since it's not needed anymore
|
|
49
|
+
inputRawAudioAs44100Stereo = undefined
|
|
50
|
+
|
|
51
|
+
await logger.startAsync(`Convert isolated audio to back original sample rate (${inputRawAudio.sampleRate} Hz) and channel count (${inputRawAudio.audioChannels.length})`)
|
|
52
|
+
isolatedRawAudio = await ensureRawAudio(isolatedRawAudio, inputRawAudio.sampleRate, inputRawAudio.audioChannels.length)
|
|
53
|
+
|
|
51
54
|
await logger.startAsync(`Subtract from original waveform to extract background audio`)
|
|
52
|
-
backgroundRawAudio = subtractAudio(
|
|
55
|
+
backgroundRawAudio = subtractAudio(inputRawAudio, isolatedRawAudio)
|
|
53
56
|
|
|
54
57
|
break
|
|
55
58
|
}
|
|
@@ -5,7 +5,6 @@ import { Logger } from '../utilities/Logger.js'
|
|
|
5
5
|
|
|
6
6
|
import * as API from './API.js'
|
|
7
7
|
import { logToStderr } from '../utilities/Utilities.js'
|
|
8
|
-
import path from 'path'
|
|
9
8
|
import { type WhisperLanguageDetectionOptions } from '../recognition/WhisperSTT.js'
|
|
10
9
|
import { formatLanguageCodeWithName, languageCodeToName } from '../utilities/Locale.js'
|
|
11
10
|
import { loadPackage } from '../utilities/PackageManager.js'
|
|
@@ -14,6 +13,7 @@ import { type WhisperCppOptions } from '../recognition/WhisperCppSTT.js'
|
|
|
14
13
|
import { type SileroLanguageDetectionOptions } from '../speech-language-detection/SileroLanguageDetection.js'
|
|
15
14
|
import { OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
|
|
16
15
|
import { LanguageDetectionResults } from './LanguageDetectionCommon.js'
|
|
16
|
+
import { joinPath } from '../utilities/PathUtilities.js'
|
|
17
17
|
|
|
18
18
|
const log = logToStderr
|
|
19
19
|
|
|
@@ -55,9 +55,9 @@ export async function detectSpeechLanguage(input: AudioSourceParam, options: Spe
|
|
|
55
55
|
|
|
56
56
|
const modelDir = await loadPackage('silero-lang-classifier-95')
|
|
57
57
|
|
|
58
|
-
const modelPath =
|
|
59
|
-
const languageDictionaryPath =
|
|
60
|
-
const languageGroupDictionaryPath =
|
|
58
|
+
const modelPath = joinPath(modelDir, 'lang_classifier_95.onnx')
|
|
59
|
+
const languageDictionaryPath = joinPath(modelDir, 'lang_dict_95.json')
|
|
60
|
+
const languageGroupDictionaryPath = joinPath(modelDir, 'lang_group_dict_95.json')
|
|
61
61
|
const onnxExecutionProviders: OnnxExecutionProvider[] = sileroOptions.provider ? [sileroOptions.provider] : []
|
|
62
62
|
|
|
63
63
|
const languageResults = await SileroLanguageDetection.detectLanguage(
|
package/src/api/Synthesis.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
|
|
3
1
|
import { deepClone, extendDeep } from '../utilities/ObjectUtilities.js'
|
|
4
2
|
|
|
5
3
|
import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
|
|
@@ -27,6 +25,8 @@ import { type ElevenlabsTTSOptions } from '../synthesis/ElevenlabsTTS.js'
|
|
|
27
25
|
import { OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
|
|
28
26
|
import { simplifyPunctuationCharacters } from '../nlp/TextNormalizer.js'
|
|
29
27
|
import { convertHtmlToText } from '../utilities/StringUtilities.js'
|
|
28
|
+
import { joinPath, resolvePath } from '../utilities/PathUtilities.js'
|
|
29
|
+
import { Timer } from '../utilities/Timer.js'
|
|
30
30
|
|
|
31
31
|
const log = logToStderr
|
|
32
32
|
|
|
@@ -55,6 +55,8 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
55
55
|
const logger = new Logger()
|
|
56
56
|
options = extendDeep(defaultSynthesisOptions, options)
|
|
57
57
|
|
|
58
|
+
const totalSynthesisTimeTimer = new Timer()
|
|
59
|
+
|
|
58
60
|
if (!options.language && !options.voice) {
|
|
59
61
|
logger.start('No language or voice specified. Detect language')
|
|
60
62
|
|
|
@@ -261,7 +263,7 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
261
263
|
async function convertToTargetCodecIfNeeded(rawAudio: RawAudio) {
|
|
262
264
|
const targetCodec = options.outputAudioFormat?.codec
|
|
263
265
|
|
|
264
|
-
let output: RawAudio |
|
|
266
|
+
let output: RawAudio | Uint8Array
|
|
265
267
|
|
|
266
268
|
if (targetCodec) {
|
|
267
269
|
logger.start(`Convert to ${targetCodec} codec`)
|
|
@@ -283,6 +285,8 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
283
285
|
|
|
284
286
|
logger.end()
|
|
285
287
|
|
|
288
|
+
logger.logTitledMessage('Total synthesis time', `${totalSynthesisTimeTimer.elapsedTime.toFixed(1)}ms`, chalk.magentaBright)
|
|
289
|
+
|
|
286
290
|
return {
|
|
287
291
|
audio: resultAudio,
|
|
288
292
|
timeline,
|
|
@@ -292,7 +296,7 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
export interface SynthesisResult {
|
|
295
|
-
audio: RawAudio |
|
|
299
|
+
audio: RawAudio | Uint8Array
|
|
296
300
|
timeline: Timeline
|
|
297
301
|
language: string
|
|
298
302
|
voice: string
|
|
@@ -427,8 +431,8 @@ async function synthesizeSegment(text: string, options: SynthesisOptions) {
|
|
|
427
431
|
|
|
428
432
|
const { textAnalysisFilename, signalGenerationFilename } = SvoxPicoTTS.getResourceFilenamesForLanguage(language)
|
|
429
433
|
|
|
430
|
-
const resourceFilePath =
|
|
431
|
-
const signalGenerationFilePath =
|
|
434
|
+
const resourceFilePath = resolvePath(voicePackagePath!, textAnalysisFilename)
|
|
435
|
+
const signalGenerationFilePath = resolvePath(voicePackagePath!, signalGenerationFilename)
|
|
432
436
|
|
|
433
437
|
const { rawAudio } = await SvoxPicoTTS.synthesize(preparedText, resourceFilePath, signalGenerationFilePath)
|
|
434
438
|
|
|
@@ -955,7 +959,7 @@ async function synthesizeSegment(text: string, options: SynthesisOptions) {
|
|
|
955
959
|
|
|
956
960
|
logger.end()
|
|
957
961
|
|
|
958
|
-
logger.logDuration('
|
|
962
|
+
logger.logDuration('Segment synthesis time', startTimestamp, chalk.magentaBright)
|
|
959
963
|
|
|
960
964
|
return { synthesizedAudio, timeline }
|
|
961
965
|
}
|
|
@@ -1273,11 +1277,11 @@ export async function requestVoiceList(options: VoiceListRequestOptions): Promis
|
|
|
1273
1277
|
|
|
1274
1278
|
if (!cacheDir) {
|
|
1275
1279
|
const appDataDir = getAppDataDir(appName)
|
|
1276
|
-
cacheDir =
|
|
1280
|
+
cacheDir = joinPath(appDataDir, 'voice-list-cache')
|
|
1277
1281
|
await ensureDir(cacheDir)
|
|
1278
1282
|
}
|
|
1279
1283
|
|
|
1280
|
-
const cacheFilePath =
|
|
1284
|
+
const cacheFilePath = joinPath(cacheDir, `${options.engine}.voices.json`)
|
|
1281
1285
|
|
|
1282
1286
|
async function loadVoiceList() {
|
|
1283
1287
|
let voiceList: SynthesisVoice[] = []
|
|
@@ -1544,7 +1548,7 @@ export async function requestVoiceList(options: VoiceListRequestOptions): Promis
|
|
|
1544
1548
|
|
|
1545
1549
|
|
|
1546
1550
|
if (cacheFilePath) {
|
|
1547
|
-
await writeFileSafe(cacheFilePath, stringifyAndFormatJson(voiceList))
|
|
1551
|
+
await writeFileSafe(cacheFilePath, await stringifyAndFormatJson(voiceList))
|
|
1548
1552
|
}
|
|
1549
1553
|
|
|
1550
1554
|
return voiceList
|
|
@@ -1671,7 +1675,7 @@ export const defaultVoiceListRequestOptions: VoiceListRequestOptions = {
|
|
|
1671
1675
|
export interface SynthesisSegmentEventData {
|
|
1672
1676
|
index: number
|
|
1673
1677
|
total: number
|
|
1674
|
-
audio: RawAudio |
|
|
1678
|
+
audio: RawAudio | Uint8Array
|
|
1675
1679
|
timeline: Timeline
|
|
1676
1680
|
transcript: string
|
|
1677
1681
|
language: string
|
|
@@ -5,13 +5,13 @@ import { AudioSourceParam, RawAudio, cropToTimeline, ensureRawAudio, } from '../
|
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
|
|
7
7
|
import { Timeline } from '../utilities/Timeline.js'
|
|
8
|
-
import path from 'path'
|
|
9
8
|
import { loadPackage } from '../utilities/PackageManager.js'
|
|
10
9
|
import { EngineMetadata } from './Common.js'
|
|
11
10
|
import chalk from 'chalk'
|
|
12
11
|
import { type AdaptiveGateVADOptions } from '../voice-activity-detection/AdaptiveGateVAD.js'
|
|
13
12
|
import { type WhisperVADOptions } from '../recognition/WhisperSTT.js'
|
|
14
13
|
import { OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
|
|
14
|
+
import { joinPath } from '../utilities/PathUtilities.js'
|
|
15
15
|
|
|
16
16
|
const log = logToStderr
|
|
17
17
|
|
|
@@ -54,7 +54,7 @@ export async function detectVoiceActivity(input: AudioSourceParam, options: VADO
|
|
|
54
54
|
|
|
55
55
|
const modelDir = await loadPackage('silero-vad')
|
|
56
56
|
|
|
57
|
-
const modelPath =
|
|
57
|
+
const modelPath = joinPath(modelDir, 'silero-vad.onnx')
|
|
58
58
|
const frameDuration = sileroOptions.frameDuration!
|
|
59
59
|
|
|
60
60
|
const onnxExecutionProviders: OnnxExecutionProvider[] = sileroOptions.provider ? [sileroOptions.provider] : []
|
|
@@ -5,7 +5,7 @@ import { BitDepth, SampleFormat } from '../codecs/WaveCodec.js'
|
|
|
5
5
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
6
6
|
// Low level audio sample conversions
|
|
7
7
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
8
|
-
export function encodeToAudioBuffer(audioChannels: Float32Array[], targetBitDepth: BitDepth = 16, targetSampleFormat: SampleFormat = SampleFormat.PCM) {
|
|
8
|
+
export function encodeToAudioBuffer(audioChannels: Float32Array[], targetBitDepth: BitDepth = 16, targetSampleFormat: SampleFormat = SampleFormat.PCM): Uint8Array {
|
|
9
9
|
const interleavedChannels = interleaveChannels(audioChannels)
|
|
10
10
|
|
|
11
11
|
audioChannels = [] // Zero the array references to allow the GC to free up memory, if possible
|
|
@@ -32,13 +32,13 @@ export function encodeToAudioBuffer(audioChannels: Float32Array[], targetBitDept
|
|
|
32
32
|
}
|
|
33
33
|
} else if (targetSampleFormat === SampleFormat.Alaw) {
|
|
34
34
|
if (targetBitDepth === 8) {
|
|
35
|
-
return
|
|
35
|
+
return AlawMulaw.alaw.encode(float32ToInt16Pcm(interleavedChannels))
|
|
36
36
|
} else {
|
|
37
37
|
throw new Error(`Unsupported alaw bit depth: ${targetBitDepth}`)
|
|
38
38
|
}
|
|
39
39
|
} else if (targetSampleFormat === SampleFormat.Mulaw) {
|
|
40
40
|
if (targetBitDepth === 8) {
|
|
41
|
-
return
|
|
41
|
+
return AlawMulaw.mulaw.encode(float32ToInt16Pcm(interleavedChannels))
|
|
42
42
|
} else {
|
|
43
43
|
throw new Error(`Unsupported mulaw bit depth: ${targetBitDepth}`)
|
|
44
44
|
}
|
|
@@ -47,7 +47,7 @@ export function encodeToAudioBuffer(audioChannels: Float32Array[], targetBitDept
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function decodeToChannels(audioBuffer:
|
|
50
|
+
export function decodeToChannels(audioBuffer: Uint8Array, channelCount: number, sourceBitDepth: number, sourceSampleFormat: SampleFormat) {
|
|
51
51
|
let interleavedChannels: Float32Array
|
|
52
52
|
|
|
53
53
|
if (sourceSampleFormat === SampleFormat.PCM) {
|
|
@@ -86,29 +86,39 @@ export function decodeToChannels(audioBuffer: Buffer, channelCount: number, sour
|
|
|
86
86
|
throw new Error(`Unsupported audio format: ${sourceSampleFormat}`)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
audioBuffer =
|
|
89
|
+
audioBuffer = new Uint8Array(0) // Zero the buffer reference to allow the GC to free up memory, if possible
|
|
90
90
|
|
|
91
91
|
return deInterleaveChannels(interleavedChannels, channelCount)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// Int8 PCM <-> Float32 conversion
|
|
95
95
|
export function int8PcmToFloat32(input: Int8Array) {
|
|
96
|
-
const
|
|
96
|
+
const sampleCount = input.length
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const output = new Float32Array(sampleCount)
|
|
99
|
+
|
|
100
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
101
|
+
output[i] = input[i] / 128
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
return output
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
export function float32ToInt8Pcm(input: Float32Array) {
|
|
107
|
-
const
|
|
108
|
+
const sampleCount = input.length
|
|
109
|
+
|
|
110
|
+
const output = new Int8Array(sampleCount)
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
113
|
+
const int8Sample = input[i] * 128
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
if (int8Sample < -128) {
|
|
116
|
+
output[i] = -128
|
|
117
|
+
} else if (int8Sample > 127) {
|
|
118
|
+
output[i] = 127
|
|
119
|
+
} else {
|
|
120
|
+
output[i] = int8Sample
|
|
121
|
+
}
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
return output
|
|
@@ -116,22 +126,32 @@ export function float32ToInt8Pcm(input: Float32Array) {
|
|
|
116
126
|
|
|
117
127
|
// Int16 PCM <-> Float32 conversion
|
|
118
128
|
export function int16PcmToFloat32(input: Int16Array) {
|
|
119
|
-
const
|
|
129
|
+
const sampleCount = input.length
|
|
130
|
+
|
|
131
|
+
const output = new Float32Array(sampleCount)
|
|
120
132
|
|
|
121
|
-
for (let i = 0; i <
|
|
122
|
-
|
|
123
|
-
output[i] = sample < 0 ? sample / 32768 : sample / 32767
|
|
133
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
134
|
+
output[i] = input[i] / 32768
|
|
124
135
|
}
|
|
125
136
|
|
|
126
137
|
return output
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
export function float32ToInt16Pcm(input: Float32Array) {
|
|
130
|
-
const
|
|
141
|
+
const sampleCount = input.length
|
|
142
|
+
|
|
143
|
+
const output = new Int16Array(sampleCount)
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
146
|
+
const int16Sample = input[i] * 32768
|
|
131
147
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
148
|
+
if (int16Sample < -32768) {
|
|
149
|
+
output[i] = -32768
|
|
150
|
+
} else if (int16Sample > 32767) {
|
|
151
|
+
output[i] = 32767
|
|
152
|
+
} else {
|
|
153
|
+
output[i] = int16Sample
|
|
154
|
+
}
|
|
135
155
|
}
|
|
136
156
|
|
|
137
157
|
return output
|
|
@@ -139,22 +159,32 @@ export function float32ToInt16Pcm(input: Float32Array) {
|
|
|
139
159
|
|
|
140
160
|
// Int24 PCM <-> Float32 conversion (uses int32 for storage)
|
|
141
161
|
export function int24PcmToFloat32(input: Int32Array) {
|
|
142
|
-
const
|
|
162
|
+
const sampleCount = input.length
|
|
143
163
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
164
|
+
const output = new Float32Array(sampleCount)
|
|
165
|
+
|
|
166
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
167
|
+
output[i] = input[i] / 8388608
|
|
147
168
|
}
|
|
148
169
|
|
|
149
170
|
return output
|
|
150
171
|
}
|
|
151
172
|
|
|
152
173
|
export function float32ToInt24Pcm(input: Float32Array) {
|
|
153
|
-
const
|
|
174
|
+
const sampleCount = input.length
|
|
154
175
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
const output = new Int32Array(sampleCount)
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
179
|
+
const int24Sample = input[i] * 8388608
|
|
180
|
+
|
|
181
|
+
if (int24Sample < -8388608) {
|
|
182
|
+
output[i] = -8388608
|
|
183
|
+
} else if (int24Sample > 8388607) {
|
|
184
|
+
output[i] = 8388607
|
|
185
|
+
} else {
|
|
186
|
+
output[i] = int24Sample
|
|
187
|
+
}
|
|
158
188
|
}
|
|
159
189
|
|
|
160
190
|
return output
|
|
@@ -162,22 +192,32 @@ export function float32ToInt24Pcm(input: Float32Array) {
|
|
|
162
192
|
|
|
163
193
|
// Int32 PCM <-> Float32 conversion
|
|
164
194
|
export function int32PcmToFloat32(input: Int32Array) {
|
|
165
|
-
const
|
|
195
|
+
const sampleCount = input.length
|
|
196
|
+
|
|
197
|
+
const output = new Float32Array(sampleCount)
|
|
166
198
|
|
|
167
|
-
for (let i = 0; i <
|
|
168
|
-
|
|
169
|
-
output[i] = sample < 0 ? sample / 2147483648 : sample / 2147483647
|
|
199
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
200
|
+
output[i] = input[i] / 2147483648
|
|
170
201
|
}
|
|
171
202
|
|
|
172
203
|
return output
|
|
173
204
|
}
|
|
174
205
|
|
|
175
206
|
export function float32ToInt32Pcm(input: Float32Array) {
|
|
176
|
-
const
|
|
207
|
+
const sampleCount = input.length
|
|
208
|
+
|
|
209
|
+
const output = new Int32Array(sampleCount)
|
|
177
210
|
|
|
178
|
-
for (let i = 0; i <
|
|
179
|
-
const
|
|
180
|
-
|
|
211
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
212
|
+
const int32Sample = input[i] * 2147483648
|
|
213
|
+
|
|
214
|
+
if (int32Sample < -2147483648) {
|
|
215
|
+
output[i] = -2147483648
|
|
216
|
+
} else if (int32Sample > 2147483647) {
|
|
217
|
+
output[i] = 2147483647
|
|
218
|
+
} else {
|
|
219
|
+
output[i] = int32Sample
|
|
220
|
+
}
|
|
181
221
|
}
|
|
182
222
|
|
|
183
223
|
return output
|
|
@@ -202,10 +242,9 @@ export function interleaveChannels(channels: Float32Array[]) {
|
|
|
202
242
|
|
|
203
243
|
let writeIndex = 0
|
|
204
244
|
|
|
205
|
-
for (let
|
|
206
|
-
for (let
|
|
207
|
-
result[writeIndex] = channels[
|
|
208
|
-
writeIndex += 1
|
|
245
|
+
for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
|
|
246
|
+
for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
|
|
247
|
+
result[writeIndex++] = channels[channelIndex][sampleIndex]
|
|
209
248
|
}
|
|
210
249
|
}
|
|
211
250
|
|
|
@@ -226,6 +265,7 @@ export function deInterleaveChannels(interleavedChannels: Float32Array, channelC
|
|
|
226
265
|
}
|
|
227
266
|
|
|
228
267
|
const sampleCount = interleavedChannels.length / channelCount
|
|
268
|
+
|
|
229
269
|
const channels: Float32Array[] = []
|
|
230
270
|
|
|
231
271
|
for (let i = 0; i < channelCount; i++) {
|
|
@@ -234,10 +274,9 @@ export function deInterleaveChannels(interleavedChannels: Float32Array, channelC
|
|
|
234
274
|
|
|
235
275
|
let readIndex = 0
|
|
236
276
|
|
|
237
|
-
for (let
|
|
238
|
-
for (let
|
|
239
|
-
channels[
|
|
240
|
-
readIndex += 1
|
|
277
|
+
for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
|
|
278
|
+
for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
|
|
279
|
+
channels[channelIndex][sampleIndex] = interleavedChannels[readIndex++]
|
|
241
280
|
}
|
|
242
281
|
}
|
|
243
282
|
|