echogarden 1.8.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -18
- package/data/schemas/options.json +52 -47
- package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
- package/dist/alignment/DTWSequenceAlignment.js +5 -5
- package/dist/alignment/DTWSequenceAlignment.js.map +1 -1
- package/dist/alignment/SpeechAlignment.js +6 -6
- package/dist/alignment/SpeechAlignment.js.map +1 -1
- package/dist/api/Alignment.d.ts +1 -1
- package/dist/api/Alignment.js +49 -11
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Denoising.d.ts +4 -2
- package/dist/api/Denoising.js +65 -13
- package/dist/api/Denoising.js.map +1 -1
- package/dist/api/SourceSeparation.js +9 -6
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/SpeechLanguageDetection.js +4 -4
- package/dist/api/SpeechLanguageDetection.js.map +1 -1
- package/dist/api/Synthesis.d.ts +2 -2
- package/dist/api/Synthesis.js +10 -7
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/VoiceActivityDetection.js +2 -2
- package/dist/api/VoiceActivityDetection.js.map +1 -1
- package/dist/audio/AudioBufferConversion.d.ts +2 -2
- package/dist/audio/AudioBufferConversion.js +77 -43
- package/dist/audio/AudioBufferConversion.js.map +1 -1
- package/dist/audio/AudioPlayer.d.ts +7 -5
- package/dist/audio/AudioPlayer.js +135 -49
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +4 -3
- package/dist/audio/AudioUtilities.js +30 -15
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/audio/SoxPath.js +3 -3
- package/dist/audio/SoxPath.js.map +1 -1
- package/dist/build-tools/MakeTarballsForInstalledPackages.js +3 -3
- package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -1
- package/dist/cli/CLI.js +30 -36
- package/dist/cli/CLI.js.map +1 -1
- package/dist/cli/CLIConfigFile.js +2 -2
- package/dist/cli/CLIConfigFile.js.map +1 -1
- package/dist/cli/CLIOptions.d.ts +2 -0
- package/dist/cli/CLIOptions.js +1 -1
- package/dist/cli/CLIOptions.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.d.ts +3 -3
- package/dist/codecs/FFMpegTranscoder.js +6 -6
- package/dist/codecs/FFMpegTranscoder.js.map +1 -1
- package/dist/codecs/TIMITCodec.d.ts +1 -1
- package/dist/codecs/TIMITCodec.js +4 -3
- package/dist/codecs/TIMITCodec.js.map +1 -1
- package/dist/codecs/WaveCodec.d.ts +3 -3
- package/dist/codecs/WaveCodec.js +37 -34
- package/dist/codecs/WaveCodec.js.map +1 -1
- package/dist/data-structures/DynamicTypedArray.d.ts +17 -0
- package/dist/data-structures/DynamicTypedArray.js +47 -0
- package/dist/data-structures/DynamicTypedArray.js.map +1 -0
- package/dist/data-structures/Queue.js.map +1 -0
- package/dist/data-structures/WindowedList.js.map +1 -0
- package/dist/denoising/NSNet2.d.ts +26 -0
- package/dist/denoising/NSNet2.js +128 -0
- package/dist/denoising/NSNet2.js.map +1 -0
- package/dist/denoising/RNNoise.js +3 -3
- package/dist/denoising/RNNoise.js.map +1 -1
- package/dist/dsp/FFT.d.ts +6 -1
- package/dist/dsp/FFT.js +17 -0
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/encodings/Ascii.d.ts +10 -0
- package/dist/encodings/Ascii.js +41 -0
- package/dist/encodings/Ascii.js.map +1 -0
- package/dist/encodings/Base64.d.ts +5 -0
- package/dist/encodings/Base64.js +114 -0
- package/dist/encodings/Base64.js.map +1 -0
- package/dist/encodings/Hex.d.ts +3 -0
- package/dist/encodings/Hex.js +52 -0
- package/dist/encodings/Hex.js.map +1 -0
- package/dist/{utilities → encodings}/LEB128.d.ts +1 -1
- package/dist/{utilities → encodings}/LEB128.js +4 -4
- package/dist/encodings/LEB128.js.map +1 -0
- package/dist/{utilities → encodings}/LPVarInt.d.ts +1 -1
- package/dist/{utilities → encodings}/LPVarInt.js +6 -6
- package/dist/encodings/LPVarInt.js.map +1 -0
- package/dist/encodings/TextEncodingsCommon.d.ts +4 -0
- package/dist/encodings/TextEncodingsCommon.js +2 -0
- package/dist/encodings/TextEncodingsCommon.js.map +1 -0
- package/dist/encodings/Utf16.d.ts +10 -0
- package/dist/encodings/Utf16.js +36 -0
- package/dist/encodings/Utf16.js.map +1 -0
- package/dist/encodings/Utf32.d.ts +9 -0
- package/dist/encodings/Utf32.js +44 -0
- package/dist/encodings/Utf32.js.map +1 -0
- package/dist/encodings/Utf8.d.ts +10 -0
- package/dist/encodings/Utf8.js +97 -0
- package/dist/encodings/Utf8.js.map +1 -0
- package/dist/math/MedianFilter.js.map +1 -1
- package/dist/nlp/JapaneseSegmentation.js +2 -2
- package/dist/nlp/JapaneseSegmentation.js.map +1 -1
- package/dist/recognition/GoogleCloudSTT.js +2 -1
- package/dist/recognition/GoogleCloudSTT.js.map +1 -1
- package/dist/recognition/SileroSTT.js +3 -3
- package/dist/recognition/SileroSTT.js.map +1 -1
- package/dist/recognition/VoskSTT.js +3 -3
- package/dist/recognition/VoskSTT.js.map +1 -1
- package/dist/recognition/WhisperCppSTT.js +4 -5
- package/dist/recognition/WhisperCppSTT.js.map +1 -1
- package/dist/recognition/WhisperSTT.js +8 -7
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/server/Client.d.ts +1 -1
- package/dist/server/Client.js +2 -1
- package/dist/server/Client.js.map +1 -1
- package/dist/server/Server.js +5 -4
- package/dist/server/Server.js.map +1 -1
- package/dist/server/Worker.js +1 -1
- package/dist/server/Worker.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/speech-search/DTWSpeechSearch.d.ts +1 -1
- package/dist/speech-search/DTWSpeechSearch.js +25 -6
- package/dist/speech-search/DTWSpeechSearch.js.map +1 -1
- package/dist/subtitles/Subtitles.js +2 -2
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.js +17 -18
- package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
- package/dist/synthesis/CoquiServerTTS.js +1 -1
- package/dist/synthesis/CoquiServerTTS.js.map +1 -1
- package/dist/synthesis/ElevenlabsTTS.js +1 -1
- package/dist/synthesis/ElevenlabsTTS.js.map +1 -1
- package/dist/synthesis/EspeakTTS.d.ts +0 -1
- package/dist/synthesis/EspeakTTS.js +0 -9
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.js +7 -8
- package/dist/synthesis/FliteTTS.js.map +1 -1
- package/dist/synthesis/GoogleCloudTTS.d.ts +1 -1
- package/dist/synthesis/GoogleCloudTTS.js +2 -1
- package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
- package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
- package/dist/synthesis/GoogleTranslateTTS.js +4 -3
- package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js +32 -7
- package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
- package/dist/synthesis/SapiTTS.js +1 -1
- package/dist/synthesis/SapiTTS.js.map +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.d.ts +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.js +1 -1
- package/dist/synthesis/StreamlabsPollyTTS.js.map +1 -1
- package/dist/synthesis/SvoxPicoTTS.js +6 -6
- package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.js +2 -2
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/tests/Test.js +1 -47
- package/dist/tests/Test.js.map +1 -1
- package/dist/text-language-detection/FastTextLanguageDetection.js +2 -2
- package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
- package/dist/typings/TypedArray.d.ts +4 -0
- package/dist/typings/TypedArray.js +2 -0
- package/dist/typings/TypedArray.js.map +1 -0
- package/dist/utilities/BinaryArrayConversion.d.ts +12 -22
- package/dist/utilities/BinaryArrayConversion.js +40 -90
- package/dist/utilities/BinaryArrayConversion.js.map +1 -1
- package/dist/utilities/BinaryUtilities.d.ts +13 -0
- package/dist/utilities/BinaryUtilities.js +113 -0
- package/dist/utilities/BinaryUtilities.js.map +1 -0
- package/dist/utilities/Compression.js +7 -6
- package/dist/utilities/Compression.js.map +1 -1
- package/dist/utilities/FileDownloader.js +26 -47
- package/dist/utilities/FileDownloader.js.map +1 -1
- package/dist/utilities/FileReader.d.ts +14 -0
- package/dist/utilities/FileReader.js +71 -0
- package/dist/utilities/FileReader.js.map +1 -0
- package/dist/utilities/FileSystem.d.ts +19 -16
- package/dist/utilities/FileSystem.js +170 -109
- package/dist/utilities/FileSystem.js.map +1 -1
- package/dist/utilities/FileWriter.d.ts +12 -0
- package/dist/utilities/FileWriter.js +60 -0
- package/dist/utilities/FileWriter.js.map +1 -0
- package/dist/utilities/NpmUtilities.d.ts +1 -0
- package/dist/utilities/NpmUtilities.js +14 -0
- package/dist/utilities/NpmUtilities.js.map +1 -0
- package/dist/utilities/PackageManager.js +7 -5
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/PathUtilities.d.ts +8 -0
- package/dist/utilities/PathUtilities.js +28 -7
- package/dist/utilities/PathUtilities.js.map +1 -1
- package/dist/utilities/SignalChannel.d.ts +3 -1
- package/dist/utilities/SignalChannel.js +9 -5
- package/dist/utilities/SignalChannel.js.map +1 -1
- package/dist/utilities/StringBuilder.d.ts +10 -0
- package/dist/utilities/StringBuilder.js +39 -0
- package/dist/utilities/StringBuilder.js.map +1 -0
- package/dist/utilities/StringUtilities.js.map +1 -1
- package/dist/utilities/TarballMaker.js +6 -7
- package/dist/utilities/TarballMaker.js.map +1 -1
- package/dist/utilities/Timer.js +2 -2
- package/dist/utilities/Timer.js.map +1 -1
- package/dist/utilities/Utilities.d.ts +11 -5
- package/dist/utilities/Utilities.js +69 -33
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/VirtualFileReadStream.d.ts +3 -3
- package/dist/utilities/VirtualFileReadStream.js.map +1 -1
- package/dist/utilities/WasmMemoryManager.d.ts +5 -2
- package/dist/utilities/WasmMemoryManager.js +15 -4
- package/dist/utilities/WasmMemoryManager.js.map +1 -1
- package/docs/API.md +1 -1
- package/docs/Licenses.md +3 -0
- package/docs/Options.md +9 -3
- package/docs/Tasklist.md +0 -1
- package/docs/Technical.md +2 -2
- package/package.json +20 -22
- package/src/alignment/DTWSequenceAlignment.ts +5 -5
- package/src/alignment/SpeechAlignment.ts +6 -6
- package/src/api/Alignment.ts +65 -12
- package/src/api/Denoising.ts +97 -17
- package/src/api/SourceSeparation.ts +11 -8
- package/src/api/SpeechLanguageDetection.ts +4 -4
- package/src/api/Synthesis.ts +15 -11
- package/src/api/VoiceActivityDetection.ts +2 -2
- package/src/audio/AudioBufferConversion.ts +84 -45
- package/src/audio/AudioPlayer.ts +155 -53
- package/src/audio/AudioUtilities.ts +38 -22
- package/src/audio/SoxPath.ts +3 -3
- package/src/build-tools/MakeTarballsForInstalledPackages.ts +3 -3
- package/src/cli/CLI.ts +30 -36
- package/src/cli/CLIConfigFile.ts +2 -2
- package/src/cli/CLIOptions.ts +4 -1
- package/src/codecs/FFMpegTranscoder.ts +11 -11
- package/src/codecs/TIMITCodec.ts +5 -4
- package/src/codecs/WaveCodec.ts +42 -39
- package/src/data-structures/DynamicTypedArray.ts +64 -0
- package/src/denoising/NSNet2.ts +182 -0
- package/src/denoising/RNNoise.ts +3 -3
- package/src/dsp/FFT.ts +21 -1
- package/src/encodings/Ascii.ts +60 -0
- package/src/encodings/Base64.ts +157 -0
- package/src/encodings/Hex.ts +67 -0
- package/src/{utilities → encodings}/LEB128.ts +4 -4
- package/src/{utilities → encodings}/LPVarInt.ts +6 -6
- package/src/encodings/TextEncodingsCommon.ts +4 -0
- package/src/encodings/Utf16.ts +52 -0
- package/src/encodings/Utf32.ts +62 -0
- package/src/encodings/Utf8.ts +117 -0
- package/src/math/MedianFilter.ts +0 -2
- package/src/nlp/JapaneseSegmentation.ts +2 -2
- package/src/recognition/GoogleCloudSTT.ts +2 -1
- package/src/recognition/SileroSTT.ts +3 -3
- package/src/recognition/VoskSTT.ts +3 -3
- package/src/recognition/WhisperCppSTT.ts +4 -5
- package/src/recognition/WhisperSTT.ts +8 -7
- package/src/server/Client.ts +4 -3
- package/src/server/Server.ts +6 -5
- package/src/server/Worker.ts +1 -1
- package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
- package/src/speech-search/DTWSpeechSearch.ts +36 -7
- package/src/subtitles/Subtitles.ts +3 -3
- package/src/synthesis/AzureCognitiveServicesTTS.ts +18 -15
- package/src/synthesis/CoquiServerTTS.ts +2 -2
- package/src/synthesis/ElevenlabsTTS.ts +1 -1
- package/src/synthesis/EspeakTTS.ts +0 -15
- package/src/synthesis/FliteTTS.ts +7 -8
- package/src/synthesis/GoogleCloudTTS.ts +3 -2
- package/src/synthesis/GoogleTranslateTTS.ts +5 -4
- package/src/synthesis/MicrosoftEdgeTTS.ts +47 -15
- package/src/synthesis/SapiTTS.ts +1 -1
- package/src/synthesis/StreamlabsPollyTTS.ts +1 -1
- package/src/synthesis/SvoxPicoTTS.ts +8 -8
- package/src/synthesis/VitsTTS.ts +2 -2
- package/src/tests/Test.ts +1 -60
- package/src/text-language-detection/FastTextLanguageDetection.ts +2 -2
- package/src/typings/Fillers.d.ts +2 -4
- package/src/typings/TypedArray.ts +5 -0
- package/src/utilities/BinaryArrayConversion.ts +51 -125
- package/src/utilities/BinaryUtilities.ts +138 -0
- package/src/utilities/Compression.ts +7 -6
- package/src/utilities/FileDownloader.ts +27 -52
- package/src/utilities/FileReader.ts +89 -0
- package/src/utilities/FileSystem.ts +213 -120
- package/src/utilities/FileWriter.ts +72 -0
- package/src/utilities/NpmUtilities.ts +23 -0
- package/src/utilities/PackageManager.ts +8 -5
- package/src/utilities/PathUtilities.ts +36 -7
- package/src/utilities/SignalChannel.ts +14 -7
- package/src/utilities/StringBuilder.ts +45 -0
- package/src/utilities/StringUtilities.ts +2 -0
- package/src/utilities/TarballMaker.ts +6 -7
- package/src/utilities/Timer.ts +4 -2
- package/src/utilities/Utilities.ts +79 -45
- package/src/utilities/VirtualFileReadStream.ts +5 -5
- package/src/utilities/WasmMemoryManager.ts +20 -6
- package/tsconfig.json +96 -0
- package/dist/utilities/DynamicUint8Array.d.ts +0 -9
- package/dist/utilities/DynamicUint8Array.js +0 -31
- package/dist/utilities/DynamicUint8Array.js.map +0 -1
- package/dist/utilities/LEB128.js.map +0 -1
- package/dist/utilities/LPVarInt.js.map +0 -1
- package/dist/utilities/Queue.js.map +0 -1
- package/dist/utilities/WindowedList.js.map +0 -1
- package/src/utilities/DynamicUint8Array.ts +0 -39
- /package/dist/{utilities → data-structures}/Queue.d.ts +0 -0
- /package/dist/{utilities → data-structures}/Queue.js +0 -0
- /package/dist/{utilities → data-structures}/WindowedList.d.ts +0 -0
- /package/dist/{utilities → data-structures}/WindowedList.js +0 -0
- /package/src/{utilities → data-structures}/Queue.ts +0 -0
- /package/src/{utilities → data-structures}/WindowedList.ts +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { decibelsToGainFactor, RawAudio } from '../audio/AudioUtilities.js'
|
|
2
|
+
|
|
3
|
+
import type * as Onnx from 'onnxruntime-node'
|
|
4
|
+
import { getOnnxSessionOptions, OnnxExecutionProvider } from '../utilities/OnnxUtilities.js'
|
|
5
|
+
import { readdir } from '../utilities/FileSystem.js'
|
|
6
|
+
import { joinPath } from '../utilities/PathUtilities.js'
|
|
7
|
+
import { stftr, stiftr } from '../dsp/FFT.js'
|
|
8
|
+
import { clip, concatFloat32Arrays } from '../utilities/Utilities.js'
|
|
9
|
+
import { Logger } from '../utilities/Logger.js'
|
|
10
|
+
|
|
11
|
+
export async function denoiseAudio(rawAudio: RawAudio, options: NSNet2Options) {
|
|
12
|
+
const onnxExecutionProviders: OnnxExecutionProvider[] = options.provider ? [options.provider] : []//['dml', 'cpu']
|
|
13
|
+
|
|
14
|
+
const denoiser = new NSNet2(options.model!, options.modelDirectoryPath!, onnxExecutionProviders, options.maxAttenuation!)
|
|
15
|
+
|
|
16
|
+
const result = await denoiser.denoiseAudio(rawAudio)
|
|
17
|
+
|
|
18
|
+
return result
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class NSNet2 {
|
|
22
|
+
session?: Onnx.InferenceSession
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
public readonly modelName: NSNet2ModelName,
|
|
26
|
+
public readonly modelDirectoryPath: string,
|
|
27
|
+
public readonly executionProviders: OnnxExecutionProvider[],
|
|
28
|
+
public readonly maxAttenuation: number) {
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async denoiseAudio(rawAudio: RawAudio) {
|
|
32
|
+
const logger = new Logger()
|
|
33
|
+
|
|
34
|
+
logger.start(`Initialize ONNX model ${this.modelName}`)
|
|
35
|
+
await this.initializeIfNeeded()
|
|
36
|
+
|
|
37
|
+
let fftSize: number
|
|
38
|
+
|
|
39
|
+
if (this.modelName === 'baseline-48khz') {
|
|
40
|
+
fftSize = 1024
|
|
41
|
+
|
|
42
|
+
if (rawAudio.sampleRate !== 48000) {
|
|
43
|
+
throw new Error(`Denoising model baseline-48khz requires a 48000 Hz signal`)
|
|
44
|
+
}
|
|
45
|
+
} else if (this.modelName === 'baseline-16khz') {
|
|
46
|
+
fftSize = 320
|
|
47
|
+
|
|
48
|
+
if (rawAudio.sampleRate !== 16000) {
|
|
49
|
+
throw new Error(`Denoising model baseline-16khz requires a 16000 Hz signal`)
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error(`Unsupported model name: ${this.modelName}`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const fftHopSize = fftSize / 2
|
|
56
|
+
const fftRealBinCount = (fftSize / 2) + 1
|
|
57
|
+
|
|
58
|
+
logger.start('Compute STFT frames')
|
|
59
|
+
const stftrFrames = await stftr(rawAudio.audioChannels[0], fftSize, fftSize, fftHopSize, 'hann')
|
|
60
|
+
|
|
61
|
+
logger.start('Compute log-power spectogram')
|
|
62
|
+
let logPowerSpectogram: Float32Array[] = []
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
for (const frame of stftrFrames) {
|
|
66
|
+
const logPowerSpectrum = new Float32Array(frame.length / 2)
|
|
67
|
+
|
|
68
|
+
let readOffset = 0
|
|
69
|
+
let writeOffset = 0
|
|
70
|
+
|
|
71
|
+
while (readOffset < frame.length) {
|
|
72
|
+
const real = frame[readOffset++]
|
|
73
|
+
const imaginary = frame[readOffset++]
|
|
74
|
+
|
|
75
|
+
const powerValue = (real ** 2) + (imaginary ** 2)
|
|
76
|
+
const clampedPowerValue = Math.max(powerValue, 1e-12)
|
|
77
|
+
const logPowerValue = Math.log10(clampedPowerValue)
|
|
78
|
+
|
|
79
|
+
logPowerSpectrum[writeOffset++] = logPowerValue
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logPowerSpectogram.push(logPowerSpectrum)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logger.start('Process log-power spectogram using ONNX model')
|
|
87
|
+
|
|
88
|
+
const frameCount = logPowerSpectogram.length
|
|
89
|
+
let flattenedOutputTensor: Float32Array
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
const Onnx = await import('onnxruntime-node')
|
|
93
|
+
|
|
94
|
+
const flattenedFeatures = concatFloat32Arrays(logPowerSpectogram)
|
|
95
|
+
|
|
96
|
+
const inputTensor = new Onnx.Tensor('float32', flattenedFeatures, [1, frameCount, fftRealBinCount])
|
|
97
|
+
const inputs = { input: inputTensor }
|
|
98
|
+
|
|
99
|
+
const result = await this.session!.run(inputs)
|
|
100
|
+
|
|
101
|
+
flattenedOutputTensor = result.output.data as Float32Array
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
{
|
|
105
|
+
logger.start('Apply model output as a filter to original STFT frames')
|
|
106
|
+
|
|
107
|
+
const fftSizeReciprocal = 1 / fftSize
|
|
108
|
+
|
|
109
|
+
const minGainRatio = decibelsToGainFactor(-this.maxAttenuation)
|
|
110
|
+
const maxGainRatio = 1.0
|
|
111
|
+
|
|
112
|
+
let flattenenedOutputTensorReadIndex = 0
|
|
113
|
+
|
|
114
|
+
for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
115
|
+
const frame = stftrFrames[frameIndex]
|
|
116
|
+
|
|
117
|
+
let frameReadIndex = 0
|
|
118
|
+
|
|
119
|
+
for (let binIndex = 0; binIndex < fftRealBinCount; binIndex++) {
|
|
120
|
+
let gainRatio = flattenedOutputTensor[flattenenedOutputTensorReadIndex++]
|
|
121
|
+
gainRatio = clip(gainRatio, minGainRatio, maxGainRatio)
|
|
122
|
+
|
|
123
|
+
frame[frameReadIndex++] *= gainRatio * fftSizeReciprocal
|
|
124
|
+
frame[frameReadIndex++] *= gainRatio * fftSizeReciprocal
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Allow logPowerSpectogram to be garbage collected
|
|
130
|
+
logPowerSpectogram = undefined as any
|
|
131
|
+
|
|
132
|
+
logger.start('Reconstruct filtered signal using inverse STFT')
|
|
133
|
+
const filteredSignal = await stiftr(stftrFrames, fftSize, fftSize, fftHopSize, 'hann')
|
|
134
|
+
|
|
135
|
+
const denoisedAudio: RawAudio = {
|
|
136
|
+
audioChannels: [filteredSignal],
|
|
137
|
+
sampleRate: rawAudio.sampleRate
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
logger.end()
|
|
141
|
+
|
|
142
|
+
return { denoisedAudio }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private async initializeIfNeeded() {
|
|
146
|
+
if (this.session) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const filesInModelPath = await readdir(this.modelDirectoryPath)
|
|
151
|
+
const onnxModelFilename = filesInModelPath.find(filename => filename.endsWith('.onnx'))
|
|
152
|
+
|
|
153
|
+
if (!onnxModelFilename) {
|
|
154
|
+
throw new Error(`Couldn't file any ONNX model file in ${this.modelDirectoryPath}`)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const onnxModelPath = joinPath(this.modelDirectoryPath, onnxModelFilename)
|
|
158
|
+
|
|
159
|
+
const Onnx = await import('onnxruntime-node')
|
|
160
|
+
|
|
161
|
+
const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
|
|
162
|
+
|
|
163
|
+
this.session = await Onnx.InferenceSession.create(onnxModelPath, onnxSessionOptions)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//export type NSNet2ModelName = 'nsnet2-20ms-baseline' | 'nsnet2-20ms-48k-baseline'
|
|
168
|
+
export type NSNet2ModelName = 'baseline-16khz' | 'baseline-48khz'
|
|
169
|
+
|
|
170
|
+
export const defaultNSNet2Options: NSNet2Options = {
|
|
171
|
+
model: 'baseline-48khz',
|
|
172
|
+
modelDirectoryPath: undefined,
|
|
173
|
+
provider: undefined,
|
|
174
|
+
maxAttenuation: 30,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface NSNet2Options {
|
|
178
|
+
model?: NSNet2ModelName
|
|
179
|
+
modelDirectoryPath?: string
|
|
180
|
+
provider?: OnnxExecutionProvider
|
|
181
|
+
maxAttenuation?: number
|
|
182
|
+
}
|
package/src/denoising/RNNoise.ts
CHANGED
|
@@ -9,11 +9,11 @@ let rnnoiseInstance: any
|
|
|
9
9
|
export async function denoiseAudio(rawAudio: RawAudio) {
|
|
10
10
|
const logger = new Logger()
|
|
11
11
|
if (rawAudio.sampleRate != 48000) {
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error(`RNNoise requires a 48000 Hz sample rate (${rawAudio.sampleRate} Hz given)`)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
if (rawAudio.audioChannels.length
|
|
16
|
-
throw new Error('
|
|
15
|
+
if (rawAudio.audioChannels.length !== 1) {
|
|
16
|
+
throw new Error('RNNoise requires a channel count of 1')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
if (rawAudio.audioChannels[0].length == 0) {
|
package/src/dsp/FFT.ts
CHANGED
|
@@ -226,6 +226,22 @@ export function complexToBinBuffer(complexBins: ComplexNumber[]) {
|
|
|
226
226
|
return binBuffer
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
// Convert complex bin to magnitude and phase
|
|
230
|
+
export function complexToMagnitudeAndPhase(real: number, imaginary: number) {
|
|
231
|
+
const magnitude = Math.sqrt((real ** 2) + (imaginary ** 2))
|
|
232
|
+
const phase = Math.atan2(imaginary, real)
|
|
233
|
+
|
|
234
|
+
return { magnitude, phase }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Convert magnitude and phase to complex bin
|
|
238
|
+
export function magnitudeAndPhaseToComplex(magnitude: number, phase: number) {
|
|
239
|
+
const real = magnitude * Math.cos(phase)
|
|
240
|
+
const imaginary = magnitude * Math.sin(phase)
|
|
241
|
+
|
|
242
|
+
return { real, imaginary } as ComplexNumber
|
|
243
|
+
}
|
|
244
|
+
|
|
229
245
|
// Get window weights for a particular window function
|
|
230
246
|
export function getWindowWeights(windowType: WindowType, windowSize: number) {
|
|
231
247
|
const weights = new Float32Array(windowSize)
|
|
@@ -237,6 +253,10 @@ export function getWindowWeights(windowType: WindowType, windowSize: number) {
|
|
|
237
253
|
//weights[i] = 0.5 * (1 - Math.cos(2 * Math.PI * (i / (windowSize - 1))))
|
|
238
254
|
weights[i] = 0.5 * (1 - Math.cos(innerFactor * i))
|
|
239
255
|
}
|
|
256
|
+
} else if (windowType == 'hann-sqrt') {
|
|
257
|
+
for (let i = 0; i < windowSize; i++) {
|
|
258
|
+
weights[i] = Math.sqrt(0.5 * (1 - Math.cos(innerFactor * i)))
|
|
259
|
+
}
|
|
240
260
|
} else if (windowType == 'hamming') {
|
|
241
261
|
for (let i = 0; i < windowSize; i++) {
|
|
242
262
|
//weights[i] = 0.54 - (0.46 * Math.cos(2 * Math.PI * (i / (windowSize - 1))))
|
|
@@ -284,4 +304,4 @@ async function getSimdPFFFTInstance() {
|
|
|
284
304
|
return pffftSimdInstance
|
|
285
305
|
}
|
|
286
306
|
|
|
287
|
-
export type WindowType = 'hann' | 'hamming' | 'povey'
|
|
307
|
+
export type WindowType = 'hann' | 'hann-sqrt' | 'hamming' | 'povey'
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { EncodeIntoResult } from "./TextEncodingsCommon.js"
|
|
2
|
+
|
|
3
|
+
export function encodeAscii(asciiString: string) {
|
|
4
|
+
const charCount = asciiString.length
|
|
5
|
+
|
|
6
|
+
const resultArray = new Uint8Array(charCount)
|
|
7
|
+
|
|
8
|
+
const { written } = encodeAsciiInto(asciiString, resultArray)
|
|
9
|
+
|
|
10
|
+
return resultArray.subarray(0, written)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function encodeAsciiInto(asciiString: string, resultBuffer: Uint8Array): EncodeIntoResult {
|
|
14
|
+
const len = asciiString.length
|
|
15
|
+
|
|
16
|
+
if (resultBuffer.length < len) {
|
|
17
|
+
throw new Error(`Result Uint8Array is not large enough to hold the string`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (let readOffset = 0; readOffset < len; readOffset++) {
|
|
21
|
+
const charCode = asciiString.charCodeAt(readOffset)
|
|
22
|
+
|
|
23
|
+
if (charCode >= 128) {
|
|
24
|
+
throw new Error(`Character '${asciiString[readOffset]}' (code: ${charCode}) can't be encoded as a standard ASCII character`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
resultBuffer[readOffset] = charCode
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { read: len, written: len }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function decodeAscii(encodedString: Uint8Array) {
|
|
34
|
+
const maxChunkLength = 2 ** 24
|
|
35
|
+
|
|
36
|
+
const decoder = new ChunkedAsciiDecoder()
|
|
37
|
+
|
|
38
|
+
for (let offset = 0; offset < encodedString.length; offset += maxChunkLength) {
|
|
39
|
+
const chunk = encodedString.subarray(offset, offset + maxChunkLength)
|
|
40
|
+
|
|
41
|
+
decoder.writeChunk(chunk)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return decoder.toString()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class ChunkedAsciiDecoder {
|
|
48
|
+
private str = ''
|
|
49
|
+
private readonly textDecoder = new TextDecoder('windows-1252')
|
|
50
|
+
|
|
51
|
+
writeChunk(chunk: Uint8Array) {
|
|
52
|
+
const decodedChunk = this.textDecoder.decode(chunk)
|
|
53
|
+
|
|
54
|
+
this.str += decodedChunk
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
toString() {
|
|
58
|
+
return this.str
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { decodeAscii } from './Ascii.js';
|
|
2
|
+
|
|
3
|
+
export function encodeBase64(inputBytes: Uint8Array,
|
|
4
|
+
paddingCharacter: string | undefined = '=',
|
|
5
|
+
charCodeMap?: Uint8Array): string {
|
|
6
|
+
|
|
7
|
+
const asciiBuffer = encodeBase64AsAsciiBuffer(inputBytes, undefined, paddingCharacter, charCodeMap)
|
|
8
|
+
|
|
9
|
+
return decodeAscii(asciiBuffer)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function encodeBase64AsAsciiBuffer(
|
|
13
|
+
inputBytes: Uint8Array,
|
|
14
|
+
asciiBuffer?: Uint8Array,
|
|
15
|
+
paddingCharacter: string | undefined = '=',
|
|
16
|
+
charCodeMap?: Uint8Array): Uint8Array {
|
|
17
|
+
|
|
18
|
+
if (!inputBytes || inputBytes.length == 0) {
|
|
19
|
+
return new Uint8Array(0)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let paddingCharCode: number
|
|
23
|
+
|
|
24
|
+
if (paddingCharacter == null) {
|
|
25
|
+
paddingCharCode = -1
|
|
26
|
+
} else if (paddingCharacter.length !== 1) {
|
|
27
|
+
throw new Error(`A padding character can only be a single character`)
|
|
28
|
+
} else {
|
|
29
|
+
paddingCharCode = paddingCharacter.charCodeAt(0)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!charCodeMap) {
|
|
33
|
+
charCodeMap = defaultBase64CharCodeMap
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let charCodes: Uint8Array
|
|
37
|
+
|
|
38
|
+
if (asciiBuffer) {
|
|
39
|
+
charCodes = asciiBuffer
|
|
40
|
+
} else {
|
|
41
|
+
charCodes = new Uint8Array(Math.floor((inputBytes.length * 4 / 3) + 4))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const inputBytesLength = inputBytes.length
|
|
45
|
+
|
|
46
|
+
let writeOffset = 0
|
|
47
|
+
let readOffset = 0
|
|
48
|
+
|
|
49
|
+
while (readOffset <= inputBytesLength - 3) {
|
|
50
|
+
const uint24 =
|
|
51
|
+
inputBytes[readOffset++] << 16 |
|
|
52
|
+
inputBytes[readOffset++] << 8 |
|
|
53
|
+
inputBytes[readOffset++]
|
|
54
|
+
|
|
55
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
|
|
56
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
|
|
57
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 6) & 63]
|
|
58
|
+
charCodes[writeOffset++] = charCodeMap[(uint24) & 63]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (readOffset === inputBytesLength - 2) {
|
|
62
|
+
// If two bytes are left, output 3 encoded characters and one padding character
|
|
63
|
+
const uint24 =
|
|
64
|
+
inputBytes[readOffset++] << 16 |
|
|
65
|
+
inputBytes[readOffset++] << 8
|
|
66
|
+
|
|
67
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
|
|
68
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
|
|
69
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 6) & 63]
|
|
70
|
+
|
|
71
|
+
if (paddingCharCode >= 0) {
|
|
72
|
+
charCodes[writeOffset++] = paddingCharCode
|
|
73
|
+
}
|
|
74
|
+
} else if (readOffset === inputBytesLength - 1) {
|
|
75
|
+
// Arrived at last byte at a position that did not complete a full 3 byte set
|
|
76
|
+
const uint24 =
|
|
77
|
+
inputBytes[readOffset++] << 16
|
|
78
|
+
|
|
79
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 18) & 63]
|
|
80
|
+
charCodes[writeOffset++] = charCodeMap[(uint24 >>> 12) & 63]
|
|
81
|
+
|
|
82
|
+
if (paddingCharCode >= 0) {
|
|
83
|
+
charCodes[writeOffset++] = paddingCharCode
|
|
84
|
+
charCodes[writeOffset++] = paddingCharCode
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return charCodes.subarray(0, writeOffset)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function decodeBase64(
|
|
92
|
+
base64String: string,
|
|
93
|
+
outputBuffer?: Uint8Array,
|
|
94
|
+
paddingCharacter = '=',
|
|
95
|
+
reverseCharCodeMap?: Uint8Array): Uint8Array {
|
|
96
|
+
|
|
97
|
+
if (!base64String || base64String.length === 0) {
|
|
98
|
+
return new Uint8Array(0)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!paddingCharacter || paddingCharacter.length !== 1) {
|
|
102
|
+
throw new Error(`A valid padding character must be provided for Base 64 decoding`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Add padding if omitted
|
|
106
|
+
const lengthModulo4 = base64String.length % 4
|
|
107
|
+
|
|
108
|
+
if (lengthModulo4 === 1) {
|
|
109
|
+
throw new Error(`Invalid Base64 string: length % 4 == 1`)
|
|
110
|
+
} else if (lengthModulo4 === 2) {
|
|
111
|
+
base64String += paddingCharacter
|
|
112
|
+
base64String += paddingCharacter
|
|
113
|
+
} else if (lengthModulo4 === 3) {
|
|
114
|
+
base64String += paddingCharacter
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!reverseCharCodeMap) {
|
|
118
|
+
reverseCharCodeMap = defaultBase64ReverseCharCodeMap
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!outputBuffer) {
|
|
122
|
+
const capacity = (base64String.length / 4) * 3
|
|
123
|
+
|
|
124
|
+
outputBuffer = new Uint8Array(capacity)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const stringLength = base64String.length
|
|
128
|
+
|
|
129
|
+
let readOffset = 0
|
|
130
|
+
let writeOffset = 0
|
|
131
|
+
|
|
132
|
+
while (readOffset < stringLength) {
|
|
133
|
+
const uint24 =
|
|
134
|
+
(reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 18) |
|
|
135
|
+
(reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 12) |
|
|
136
|
+
(reverseCharCodeMap[base64String.charCodeAt(readOffset++)] << 6) |
|
|
137
|
+
(reverseCharCodeMap[base64String.charCodeAt(readOffset++)])
|
|
138
|
+
|
|
139
|
+
outputBuffer[writeOffset++] = (uint24 >>> 16) & 255
|
|
140
|
+
outputBuffer[writeOffset++] = (uint24 >>> 8) & 255
|
|
141
|
+
outputBuffer[writeOffset++] = (uint24) & 255
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Remove 1 or 2 last bytes if padding characters were added to the string
|
|
145
|
+
if (base64String[stringLength - 1] === paddingCharacter) {
|
|
146
|
+
writeOffset--
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (base64String[stringLength - 2] === paddingCharacter) {
|
|
150
|
+
writeOffset--
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return outputBuffer.subarray(0, writeOffset)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const defaultBase64CharCodeMap: Uint8Array = new Uint8Array([65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47])
|
|
157
|
+
export const defaultBase64ReverseCharCodeMap: Uint8Array = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255])
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { decodeAscii } from "./Ascii.js"
|
|
2
|
+
|
|
3
|
+
export function encodeHex(buffer: Uint8Array) {
|
|
4
|
+
const asciiBuffer = encodeHexAsAsciiBuffer(buffer)
|
|
5
|
+
|
|
6
|
+
return decodeAscii(asciiBuffer)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function encodeHexAsAsciiBuffer(buffer: Uint8Array) {
|
|
10
|
+
const bufferLen = buffer.length
|
|
11
|
+
|
|
12
|
+
const charCodes = new Uint8Array(bufferLen * 2)
|
|
13
|
+
|
|
14
|
+
let readOffset = 0
|
|
15
|
+
let writeOffset = 0
|
|
16
|
+
|
|
17
|
+
while (readOffset < bufferLen) {
|
|
18
|
+
const value = buffer[readOffset++]
|
|
19
|
+
|
|
20
|
+
const valueHigh4Bits = (value >>> 4) & 0xf
|
|
21
|
+
const valueLow4Bits = value & 0xf
|
|
22
|
+
|
|
23
|
+
charCodes[writeOffset++] = hexCharCodeLookup[valueHigh4Bits]
|
|
24
|
+
charCodes[writeOffset++] = hexCharCodeLookup[valueLow4Bits]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return charCodes
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function decodeHex(hexString: string) {
|
|
31
|
+
const hexLength = hexString.length
|
|
32
|
+
|
|
33
|
+
if (hexLength % 2 !== 0) {
|
|
34
|
+
throw new Error(`Hexadecimal string doesn't have an even number of characters`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const buffer = new Uint8Array(hexLength / 2)
|
|
38
|
+
|
|
39
|
+
let readOffset = 0
|
|
40
|
+
let writeOffset = 0
|
|
41
|
+
|
|
42
|
+
while (readOffset < hexLength) {
|
|
43
|
+
const valueHigh4Bits = hexCharCodeToValue(hexString.charCodeAt(readOffset++))
|
|
44
|
+
const valueLow4Bits = hexCharCodeToValue(hexString.charCodeAt(readOffset++))
|
|
45
|
+
|
|
46
|
+
const value = (valueHigh4Bits << 4) | valueLow4Bits
|
|
47
|
+
|
|
48
|
+
buffer[writeOffset++] = value
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return buffer
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function hexCharCodeToValue(hexCharCode: number) {
|
|
55
|
+
if (hexCharCode >= 48 && hexCharCode <= 57) { // '0'..'9'
|
|
56
|
+
return hexCharCode - 48
|
|
57
|
+
} else if (hexCharCode >= 97 && hexCharCode <= 102) { // 'a'..'f'
|
|
58
|
+
return 10 + hexCharCode - 97
|
|
59
|
+
} else if (hexCharCode >= 65 && hexCharCode <= 70) { // 'A'..'F'
|
|
60
|
+
return 10 + hexCharCode - 65
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error(`Can't decode character '${String.fromCharCode(hexCharCode)}' (code: ${hexCharCode}) as hexadecimal`)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const hexCharLookup: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
|
|
67
|
+
const hexCharCodeLookup = new Uint8Array([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102])
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DynamicUint8Array } from "
|
|
2
|
-
import { logToStderr } from "
|
|
1
|
+
import { DynamicUint8Array, createDynamicUint8Array } from "../data-structures/DynamicTypedArray.js"
|
|
2
|
+
import { logToStderr } from "../utilities/Utilities.js"
|
|
3
3
|
|
|
4
4
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
5
5
|
// Encode unsigned integer
|
|
@@ -337,13 +337,13 @@ export interface DecodedValueAndReadOffset {
|
|
|
337
337
|
// Tests
|
|
338
338
|
////////////////////////////////////////////////////////////////////////////////////
|
|
339
339
|
export function testLeb128Signed() {
|
|
340
|
-
const encodedBytes =
|
|
340
|
+
const encodedBytes = createDynamicUint8Array()
|
|
341
341
|
|
|
342
342
|
function runTest(testValue: number) {
|
|
343
343
|
encodedBytes.clear()
|
|
344
344
|
|
|
345
345
|
encodeSignedInt32Fast(testValue, encodedBytes)
|
|
346
|
-
const { decodedValue } = decodeSignedInt32Fast(encodedBytes.
|
|
346
|
+
const { decodedValue } = decodeSignedInt32Fast(encodedBytes.elements, 0)
|
|
347
347
|
|
|
348
348
|
if (decodedValue !== testValue) {
|
|
349
349
|
throw new Error(`Expected ${testValue} but got ${decodedValue}`)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DynamicUint8Array } from "
|
|
2
|
-
import { logToStderr } from "
|
|
1
|
+
import { createDynamicUint8Array, DynamicUint8Array } from "../data-structures/DynamicTypedArray.js"
|
|
2
|
+
import { logToStderr } from "../utilities/Utilities.js"
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -242,13 +242,13 @@ export interface DecodedValueAndReadOffset {
|
|
|
242
242
|
// Tests
|
|
243
243
|
////////////////////////////////////////////////////////////////////////////////////
|
|
244
244
|
export function testLPVarintSigned() {
|
|
245
|
-
const encodedBytes =
|
|
245
|
+
const encodedBytes = createDynamicUint8Array()
|
|
246
246
|
|
|
247
247
|
function runTest(testValue: number) {
|
|
248
248
|
encodedBytes.clear()
|
|
249
249
|
|
|
250
250
|
encodeSignedInt32(testValue, encodedBytes)
|
|
251
|
-
const { decodedValue } = decodeSignedInt32(encodedBytes.
|
|
251
|
+
const { decodedValue } = decodeSignedInt32(encodedBytes.elements, 0)
|
|
252
252
|
|
|
253
253
|
if (decodedValue !== testValue) {
|
|
254
254
|
throw new Error(`Expected ${testValue} but got ${decodedValue}`)
|
|
@@ -267,13 +267,13 @@ export function testLPVarintSigned() {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
export function testLPVarintUnsigned() {
|
|
270
|
-
const encodedBytes =
|
|
270
|
+
const encodedBytes = createDynamicUint8Array()
|
|
271
271
|
|
|
272
272
|
function runTest(testValue: number) {
|
|
273
273
|
encodedBytes.clear()
|
|
274
274
|
|
|
275
275
|
encodeUnsignedInt31(testValue, encodedBytes)
|
|
276
|
-
const { decodedValue } = decodeUnsignedInt31(encodedBytes.
|
|
276
|
+
const { decodedValue } = decodeUnsignedInt31(encodedBytes.elements, 0)
|
|
277
277
|
|
|
278
278
|
if (decodedValue !== testValue) {
|
|
279
279
|
throw new Error(`Expected ${testValue} but got ${decodedValue}`)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EncodeIntoResult } from "./TextEncodingsCommon.js"
|
|
2
|
+
|
|
3
|
+
export function encodeUtf16(text: string) {
|
|
4
|
+
const resultArray = new Uint16Array(text.length)
|
|
5
|
+
|
|
6
|
+
const { written } = encodeUtf16Into(text, resultArray)
|
|
7
|
+
|
|
8
|
+
return resultArray.subarray(0, written)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function encodeUtf16Into(text: string, resultBuffer: Uint16Array): EncodeIntoResult {
|
|
12
|
+
const len = text.length
|
|
13
|
+
|
|
14
|
+
if (resultBuffer.length < len) {
|
|
15
|
+
throw new Error(`Result Uint16Array is not large enough to hold the string`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for (let readOffset = 0; readOffset < len; readOffset++) {
|
|
19
|
+
resultBuffer[readOffset] = text.charCodeAt(readOffset)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { read: len, written: len }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function decodeUtf16(encodedString: Uint16Array) {
|
|
26
|
+
const maxChunkLength = 2 ** 24
|
|
27
|
+
|
|
28
|
+
const decoder = new ChunkedUtf16Decoder()
|
|
29
|
+
|
|
30
|
+
for (let offset = 0; offset < encodedString.length; offset += maxChunkLength) {
|
|
31
|
+
const chunk = encodedString.subarray(offset, offset + maxChunkLength)
|
|
32
|
+
|
|
33
|
+
decoder.writeChunk(chunk)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return decoder.toString()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class ChunkedUtf16Decoder {
|
|
40
|
+
private str = ''
|
|
41
|
+
private readonly textDecoder = new TextDecoder('utf-16le')
|
|
42
|
+
|
|
43
|
+
writeChunk(chunk: Uint16Array) {
|
|
44
|
+
const decodedChunk = this.textDecoder.decode(chunk)
|
|
45
|
+
|
|
46
|
+
this.str += decodedChunk
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toString() {
|
|
50
|
+
return this.str
|
|
51
|
+
}
|
|
52
|
+
}
|