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
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ParagraphBreakType, WhitespaceProcessing } from
|
|
2
|
-
import { isWordOrSymbolWord, splitToParagraphs, splitToSentences } from
|
|
3
|
-
import { deepClone } from
|
|
4
|
-
import { getUTF32Chars, roundToDigits } from
|
|
1
|
+
import { ParagraphBreakType, WhitespaceProcessing } from '../api/Common.js'
|
|
2
|
+
import { isWordOrSymbolWord, splitToParagraphs, splitToSentences } from '../nlp/Segmentation.js'
|
|
3
|
+
import { deepClone } from './ObjectUtilities.js'
|
|
4
|
+
import { getUTF32Chars, roundToDigits } from './Utilities.js'
|
|
5
5
|
|
|
6
6
|
export function addTimeOffsetToTimeline(targetTimeline: Timeline, timeOffset: number) {
|
|
7
7
|
if (!targetTimeline) {
|
|
@@ -62,14 +62,14 @@ export function roundTimelineProperties(targetTimeline: Timeline, decimalDigits
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeline, transcript: string, language: string, paragraphBreaks: ParagraphBreakType = 'double', whitespace: WhitespaceProcessing = 'collapse') {
|
|
65
|
-
const paragraphs =
|
|
65
|
+
const paragraphs = splitToParagraphs(transcript, paragraphBreaks, whitespace)
|
|
66
66
|
|
|
67
67
|
const segments = paragraphs
|
|
68
68
|
.map(segment =>
|
|
69
69
|
splitToSentences(segment, language).map(sentence =>
|
|
70
70
|
sentence.trim()))
|
|
71
71
|
|
|
72
|
-
let text =
|
|
72
|
+
let text = ''
|
|
73
73
|
const charIndexToSentenceEntryMapping: TimelineEntry[] = []
|
|
74
74
|
|
|
75
75
|
const segmentTimeline: Timeline = []
|
|
@@ -78,8 +78,8 @@ export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeli
|
|
|
78
78
|
const sentencesInSegment: Timeline = []
|
|
79
79
|
|
|
80
80
|
const segmentEntry: TimelineEntry = {
|
|
81
|
-
type:
|
|
82
|
-
text:
|
|
81
|
+
type: 'segment',
|
|
82
|
+
text: '',
|
|
83
83
|
startTime: -1,
|
|
84
84
|
endTime: -1,
|
|
85
85
|
timeline: sentencesInSegment
|
|
@@ -87,14 +87,14 @@ export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeli
|
|
|
87
87
|
|
|
88
88
|
for (const sentence of segment) {
|
|
89
89
|
const sentenceEntry: TimelineEntry = {
|
|
90
|
-
type:
|
|
90
|
+
type: 'sentence',
|
|
91
91
|
text: sentence,
|
|
92
92
|
startTime: -1,
|
|
93
93
|
endTime: -1,
|
|
94
94
|
timeline: []
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
for (const char of sentence +
|
|
97
|
+
for (const char of sentence + ' ') {
|
|
98
98
|
text += char
|
|
99
99
|
charIndexToSentenceEntryMapping.push(sentenceEntry)
|
|
100
100
|
}
|
|
@@ -122,7 +122,7 @@ export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeli
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
const targetSentenceEntry = charIndexToSentenceEntryMapping[indexOfWordInText]
|
|
125
|
-
targetSentenceEntry.timeline!.push(wordEntry)
|
|
125
|
+
targetSentenceEntry.timeline!.push(deepClone(wordEntry))
|
|
126
126
|
|
|
127
127
|
wordSearchStartOffset = indexOfWordInText + wordText.length
|
|
128
128
|
}
|
|
@@ -151,7 +151,7 @@ export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeli
|
|
|
151
151
|
continue
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
segmentEntry.text = newSentenceTimeline.map(sentenceEntry => sentenceEntry.text).join(
|
|
154
|
+
segmentEntry.text = newSentenceTimeline.map(sentenceEntry => sentenceEntry.text).join(' ')
|
|
155
155
|
|
|
156
156
|
segmentEntry.startTime = newSentenceTimeline[0].startTime
|
|
157
157
|
segmentEntry.endTime = newSentenceTimeline[newSentenceTimeline.length - 1].endTime
|
|
@@ -207,7 +207,7 @@ export function addWordTextOffsetsToTimeline(timeline: Timeline, text: string, c
|
|
|
207
207
|
return currentOffset
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
export type TimelineEntryType =
|
|
210
|
+
export type TimelineEntryType = 'segment' | 'paragraph' | 'sentence' | 'clause' | 'phrase' | 'word' | 'token' | 'letter' | 'phone' | 'subphone'
|
|
211
211
|
|
|
212
212
|
export type TimelineEntry = {
|
|
213
213
|
type: TimelineEntryType
|
|
@@ -225,6 +225,8 @@ export type TimelineEntry = {
|
|
|
225
225
|
|
|
226
226
|
confidence?: number
|
|
227
227
|
|
|
228
|
+
id?: number
|
|
229
|
+
|
|
228
230
|
timeline?: Timeline
|
|
229
231
|
}
|
|
230
232
|
|
package/src/utilities/Timer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { roundToDigits, writeToStderr } from
|
|
1
|
+
import { roundToDigits, writeToStderr } from './Utilities.js'
|
|
2
2
|
|
|
3
3
|
declare const chrome: any
|
|
4
4
|
declare const process: any
|
|
@@ -56,7 +56,7 @@ export class Timer {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
private static createGlobalTimestampFunction() {
|
|
59
|
-
if (typeof process ===
|
|
59
|
+
if (typeof process === 'object' && typeof process.hrtime === 'function') {
|
|
60
60
|
let baseTimestamp = 0
|
|
61
61
|
|
|
62
62
|
this.timestampFunc = () => {
|
|
@@ -68,7 +68,7 @@ export class Timer {
|
|
|
68
68
|
|
|
69
69
|
baseTimestamp = Date.now() - this.timestampFunc()
|
|
70
70
|
}
|
|
71
|
-
else if (typeof chrome ===
|
|
71
|
+
else if (typeof chrome === 'object' && chrome.Interval) {
|
|
72
72
|
const baseTimestamp = Date.now()
|
|
73
73
|
|
|
74
74
|
const chromeIntervalObject = new chrome.Interval()
|
|
@@ -76,7 +76,7 @@ export class Timer {
|
|
|
76
76
|
|
|
77
77
|
this.timestampFunc = () => baseTimestamp + chromeIntervalObject.microseconds() / 1000
|
|
78
78
|
}
|
|
79
|
-
else if (typeof performance ===
|
|
79
|
+
else if (typeof performance === 'object' && performance.now) {
|
|
80
80
|
const baseTimestamp = Date.now() - performance.now()
|
|
81
81
|
|
|
82
82
|
this.timestampFunc = () => baseTimestamp + performance.now()
|
|
@@ -5,6 +5,7 @@ import { inspect } from 'node:util'
|
|
|
5
5
|
import { RandomGenerator } from './RandomGenerator.js'
|
|
6
6
|
import { randomUUID, randomBytes } from 'node:crypto'
|
|
7
7
|
import { Logger } from './Logger.js'
|
|
8
|
+
import { ChildProcessWithoutNullStreams } from 'node:child_process'
|
|
8
9
|
|
|
9
10
|
const log = logToStderr
|
|
10
11
|
|
|
@@ -84,7 +85,7 @@ export function printToStderr(message: any) {
|
|
|
84
85
|
|
|
85
86
|
export function logToStderr(message: any) {
|
|
86
87
|
printToStderr(message)
|
|
87
|
-
writeToStderr(
|
|
88
|
+
writeToStderr('\n')
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
export function objToString(obj: any) {
|
|
@@ -105,7 +106,7 @@ export function getRandomHexString(charCount = 32, upperCase = false) {
|
|
|
105
106
|
throw new Error(`'charCount' must be an even number`)
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
let hex = randomBytes(charCount / 2).toString(
|
|
109
|
+
let hex = randomBytes(charCount / 2).toString('hex')
|
|
109
110
|
|
|
110
111
|
if (upperCase) {
|
|
111
112
|
hex = hex.toUpperCase()
|
|
@@ -118,7 +119,7 @@ export function getRandomUUID(dashes = true) {
|
|
|
118
119
|
let uuid = randomUUID() as string
|
|
119
120
|
|
|
120
121
|
if (dashes == false) {
|
|
121
|
-
uuid = uuid.replaceAll(
|
|
122
|
+
uuid = uuid.replaceAll('-', '')
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
return uuid
|
|
@@ -181,7 +182,7 @@ export function printMatrix(matrix: Float32Array[]) {
|
|
|
181
182
|
const rowCount = matrix.length
|
|
182
183
|
|
|
183
184
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
184
|
-
log(matrix[rowIndex].join(
|
|
185
|
+
log(matrix[rowIndex].join(', '))
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
|
|
@@ -212,11 +213,11 @@ export function secondsToMS(totalSeconds: number) {
|
|
|
212
213
|
return { minutes: (hours * 60) + minutes, seconds, milliseconds }
|
|
213
214
|
}
|
|
214
215
|
|
|
215
|
-
export function formatHMS(timeHMS: { hours: number, minutes: number, seconds: number, milliseconds: number }, decimalSeparator =
|
|
216
|
+
export function formatHMS(timeHMS: { hours: number, minutes: number, seconds: number, milliseconds: number }, decimalSeparator = '.') {
|
|
216
217
|
return `${formatIntegerWithLeadingZeros(timeHMS.hours, 2)}:${formatIntegerWithLeadingZeros(timeHMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeHMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeHMS.milliseconds, 3)}`
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
export function formatMS(timeMS: { minutes: number, seconds: number, milliseconds: number }, decimalSeparator =
|
|
220
|
+
export function formatMS(timeMS: { minutes: number, seconds: number, milliseconds: number }, decimalSeparator = '.') {
|
|
220
221
|
return `${formatIntegerWithLeadingZeros(timeMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeMS.milliseconds, 3)}`
|
|
221
222
|
}
|
|
222
223
|
|
|
@@ -356,15 +357,15 @@ export function readBinaryIncomingMessage(incomingMessage: IncomingMessage) {
|
|
|
356
357
|
return new Promise<Buffer>((resolve, reject) => {
|
|
357
358
|
const chunks: Buffer[] = []
|
|
358
359
|
|
|
359
|
-
incomingMessage.on(
|
|
360
|
+
incomingMessage.on('data', (chunk) => {
|
|
360
361
|
chunks.push(Buffer.from(chunk))
|
|
361
362
|
})
|
|
362
363
|
|
|
363
|
-
incomingMessage.on(
|
|
364
|
+
incomingMessage.on('end', () => {
|
|
364
365
|
resolve(Buffer.concat(chunks))
|
|
365
366
|
})
|
|
366
367
|
|
|
367
|
-
incomingMessage.on(
|
|
368
|
+
incomingMessage.on('error', (e) => {
|
|
368
369
|
reject(e)
|
|
369
370
|
})
|
|
370
371
|
})
|
|
@@ -388,7 +389,7 @@ export async function sha256AsHex(input: string) {
|
|
|
388
389
|
}
|
|
389
390
|
|
|
390
391
|
export async function commandExists(command: string) {
|
|
391
|
-
const { default: commandExists } = await import(
|
|
392
|
+
const { default: commandExists } = await import('command-exists')
|
|
392
393
|
|
|
393
394
|
try {
|
|
394
395
|
await commandExists(command)
|
|
@@ -415,11 +416,11 @@ export async function convertHtmlToText(html: string) {
|
|
|
415
416
|
]
|
|
416
417
|
})
|
|
417
418
|
|
|
418
|
-
return text ||
|
|
419
|
+
return text || ''
|
|
419
420
|
}
|
|
420
421
|
|
|
421
422
|
export function formatListWithQuotedElements(strings: string[], quoteSymbol = `'`) {
|
|
422
|
-
return strings.map(str => `${quoteSymbol}${str}${quoteSymbol}`).join(
|
|
423
|
+
return strings.map(str => `${quoteSymbol}${str}${quoteSymbol}`).join(', ')
|
|
423
424
|
}
|
|
424
425
|
|
|
425
426
|
export async function resolveModuleMainPath(moduleName: string) {
|
|
@@ -441,7 +442,7 @@ export function splitFilenameOnExtendedExtension(filenameWithExtension: string)
|
|
|
441
442
|
let splitPoint = filenameWithExtension.length
|
|
442
443
|
|
|
443
444
|
for (let i = filenameWithExtension.length - 1; i >= 0; i--) {
|
|
444
|
-
if (filenameWithExtension[i] ==
|
|
445
|
+
if (filenameWithExtension[i] == '.') {
|
|
445
446
|
if (/^[a-zA-Z0-9\.]+$/.test(filenameWithExtension.slice(i + 1))) {
|
|
446
447
|
splitPoint = i
|
|
447
448
|
|
|
@@ -577,7 +578,7 @@ export async function resolveModuleScriptPath(moduleName: string) {
|
|
|
577
578
|
export async function runOperationWithRetries<R>(
|
|
578
579
|
operationFunc: () => Promise<R>,
|
|
579
580
|
logger: Logger,
|
|
580
|
-
opreationName =
|
|
581
|
+
opreationName = 'Operation',
|
|
581
582
|
delayBetweenRetries = 2000,
|
|
582
583
|
maxRetries = 200) {
|
|
583
584
|
|
|
@@ -592,7 +593,7 @@ export async function runOperationWithRetries<R>(
|
|
|
592
593
|
const { shouldCancelCurrentTask } = await import('../server/Worker.js')
|
|
593
594
|
|
|
594
595
|
if (shouldCancelCurrentTask()) {
|
|
595
|
-
throw new Error(
|
|
596
|
+
throw new Error('Canceled')
|
|
596
597
|
}
|
|
597
598
|
|
|
598
599
|
logger.setAsActiveLogger()
|
|
@@ -613,3 +614,36 @@ export async function runOperationWithRetries<R>(
|
|
|
613
614
|
|
|
614
615
|
throw new Error(`${opreationName} failed after ${maxRetries} retry attempts`)
|
|
615
616
|
}
|
|
617
|
+
|
|
618
|
+
export function writeToStdinInChunks(process: ChildProcessWithoutNullStreams, buffer: Buffer, chunkSize: number) {
|
|
619
|
+
const writeChunk = (chunkOffset: number) => {
|
|
620
|
+
if (chunkOffset >= buffer.length) {
|
|
621
|
+
process.stdin.end() // End the stream after writing all chunks
|
|
622
|
+
|
|
623
|
+
return
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const startOffset = chunkOffset
|
|
627
|
+
const endOffset = Math.min(chunkOffset + chunkSize, buffer.length)
|
|
628
|
+
|
|
629
|
+
const chunk = buffer.subarray(startOffset, endOffset)
|
|
630
|
+
|
|
631
|
+
if (!process.stdin.writable) {
|
|
632
|
+
return
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
process.stdin.write(chunk, () => writeChunk(endOffset))
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
writeChunk(0)
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export function getIntegerRange(start: number, end: number): number[] {
|
|
642
|
+
const result = []
|
|
643
|
+
|
|
644
|
+
for (let i = start; i < end; i++) {
|
|
645
|
+
result.push(i)
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return result
|
|
649
|
+
}
|
|
@@ -196,7 +196,7 @@ export class WasmMemoryManager {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
allocNullTerminatedUtf8String(str: string) {
|
|
199
|
-
const strBuffer = Buffer.concat([Buffer.from(str,
|
|
199
|
+
const strBuffer = Buffer.concat([Buffer.from(str, 'utf8'), Buffer.alloc(1)])
|
|
200
200
|
const ref = this.allocUint8Array(strBuffer.length)
|
|
201
201
|
ref.view.set(strBuffer)
|
|
202
202
|
return ref
|
|
@@ -266,7 +266,7 @@ abstract class ValueRef<T extends number | string> {
|
|
|
266
266
|
if (typeof this.value == 'number') {
|
|
267
267
|
this.value = 0 as any
|
|
268
268
|
} else if (typeof this.value == 'string') {
|
|
269
|
-
throw new Error(
|
|
269
|
+
throw new Error('Unimplemented')
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
return this
|
|
@@ -284,7 +284,7 @@ abstract class ValueRef<T extends number | string> {
|
|
|
284
284
|
|
|
285
285
|
protected assertNotFreed() {
|
|
286
286
|
if (this.isFreed) {
|
|
287
|
-
throw new Error(
|
|
287
|
+
throw new Error('Attempt to read a freed WASM value reference.')
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
}
|
|
@@ -381,13 +381,13 @@ export class NullTerminatedUtf8StringRef extends ValueRef<string> {
|
|
|
381
381
|
|
|
382
382
|
const strBytes = heapU8.subarray(ptr, ptr + endByteOffset)
|
|
383
383
|
|
|
384
|
-
const str = Buffer.from(strBytes).toString(
|
|
384
|
+
const str = Buffer.from(strBytes).toString('utf8')
|
|
385
385
|
|
|
386
386
|
return str
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
setValue(newValue: string) {
|
|
390
|
-
throw new Error(
|
|
390
|
+
throw new Error('Unimplemented')
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
|
|
@@ -437,7 +437,7 @@ abstract class TypedArrayRef<T extends TypedArray> {
|
|
|
437
437
|
|
|
438
438
|
protected assertNotFreed() {
|
|
439
439
|
if (this.isFreed) {
|
|
440
|
-
throw new Error(
|
|
440
|
+
throw new Error('Attempt to read a freed WASM typed array reference.')
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
}
|
|
@@ -464,7 +464,7 @@ export class Uint8ArrayRef extends TypedArrayRef<Uint8Array> {
|
|
|
464
464
|
strBytes = strBytes.subarray(0, indexOfFirstZero)
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
const str = Buffer.from(strBytes).toString(
|
|
467
|
+
const str = Buffer.from(strBytes).toString('utf8')
|
|
468
468
|
|
|
469
469
|
return str
|
|
470
470
|
}
|
|
@@ -10,29 +10,29 @@ export async function fetchDocumentText(url: string) {
|
|
|
10
10
|
|
|
11
11
|
const response = await request<string>({
|
|
12
12
|
url,
|
|
13
|
-
responseType:
|
|
13
|
+
responseType: 'text',
|
|
14
14
|
headers: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
'sec-ch-ua': `".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"`,
|
|
16
|
+
'x-same-domain': '1',
|
|
17
|
+
'dnt': '1',
|
|
18
|
+
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
19
|
+
'sec-ch-ua-mobile': '?0',
|
|
20
|
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
|
|
21
|
+
'sec-ch-ua-arch': 'x86',
|
|
22
|
+
'sec-ch-ua-full-version': '103.0.5060.114',
|
|
23
|
+
'sec-ch-ua-platform-version': '10.0.0',
|
|
24
|
+
'sec-ch-ua-full-version-list': `".Not/A)Brand";v="99.0.0.0", "Google Chrome";v="103.0.5060.114", "Chromium";v="103.0.5060.114"`,
|
|
25
|
+
'sec-ch-ua-bitness': '64',
|
|
26
|
+
'sec-ch-ua-model': '',
|
|
27
|
+
'sec-ch-ua-platform': 'Windows',
|
|
28
|
+
'accept': '*/*',
|
|
29
|
+
//'origin': 'https://www.google.com/',
|
|
30
|
+
'sec-fetch-site': 'same-origin',
|
|
31
|
+
'sec-fetch-mode': 'cors',
|
|
32
|
+
'sec-fetch-dest': 'empty',
|
|
33
|
+
'referer': 'https://www.google.com/',
|
|
34
|
+
'accept-encoding': 'gzip, deflate, br',
|
|
35
|
+
'accept-language': 'en-US,en;q=0.9',
|
|
36
36
|
},
|
|
37
37
|
})
|
|
38
38
|
|
|
@@ -47,7 +47,7 @@ export async function fetchDocumentText(url: string) {
|
|
|
47
47
|
|
|
48
48
|
const article = reader.parse()
|
|
49
49
|
|
|
50
|
-
const text: string = await convertHtmlToText(article?.content ||
|
|
50
|
+
const text: string = await convertHtmlToText(article?.content || '')
|
|
51
51
|
|
|
52
52
|
progressLogger.end()
|
|
53
53
|
|
|
@@ -4,14 +4,14 @@ import { Logger } from './Logger.js'
|
|
|
4
4
|
export async function parseWikipediaArticle(articleName: string, language: string) {
|
|
5
5
|
const logger = new Logger()
|
|
6
6
|
|
|
7
|
-
logger.startAsync(
|
|
7
|
+
logger.startAsync('Fetching Wikipedia article')
|
|
8
8
|
|
|
9
9
|
const { default: wtf } = await import('wtf_wikipedia')
|
|
10
10
|
|
|
11
11
|
const document = await wtf.fetch(articleName, language)
|
|
12
12
|
|
|
13
13
|
if (!document) {
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error('Error fetching Wikipedia article')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const sections = document.sections()
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { RawAudio, getRawAudioDuration } from '../audio/AudioUtilities.js';
|
|
2
|
+
import { BiquadFilter, createHighpassFilter, createLowpassFilter } from '../dsp/BiquadFilter.js';
|
|
3
|
+
import { DecayingPeakEstimator } from '../dsp/DecayingPeakEstimator.js';
|
|
4
|
+
import { LoudnessEstimator } from '../dsp/LoudnessEstimator.js';
|
|
5
|
+
import { extendDeep } from '../utilities/ObjectUtilities.js';
|
|
6
|
+
import { Timeline } from '../utilities/Timeline.js';
|
|
7
|
+
import { logToStderr } from '../utilities/Utilities.js';
|
|
8
|
+
|
|
9
|
+
const log = logToStderr
|
|
10
|
+
|
|
11
|
+
export async function detectVoiceActivity(rawAudio: RawAudio, options: AdaptiveGateVADOptions) {
|
|
12
|
+
const channelCount = rawAudio.audioChannels.length
|
|
13
|
+
const sampleCount = rawAudio.audioChannels[0].length
|
|
14
|
+
const sampleRate = rawAudio.sampleRate
|
|
15
|
+
|
|
16
|
+
const audioDuration = getRawAudioDuration(rawAudio)
|
|
17
|
+
|
|
18
|
+
options = extendDeep(defaultAdaptiveGateOptions, options)
|
|
19
|
+
|
|
20
|
+
const gateVAD = new AdaptiveGateVAD(sampleRate, channelCount, options)
|
|
21
|
+
|
|
22
|
+
type FrameRecord = {
|
|
23
|
+
timePosition: number
|
|
24
|
+
loudness: number
|
|
25
|
+
minimumLoudness: number
|
|
26
|
+
maximumLoudness: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const frameDuration = 0.01
|
|
30
|
+
|
|
31
|
+
const frameRecords: FrameRecord[] = []
|
|
32
|
+
|
|
33
|
+
for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
|
|
34
|
+
const timePosition = sampleIndex / sampleRate
|
|
35
|
+
|
|
36
|
+
for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
|
|
37
|
+
const sample = rawAudio.audioChannels[channelIndex][sampleIndex]
|
|
38
|
+
|
|
39
|
+
gateVAD.process(sample, channelIndex)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
frameRecords.length == 0 ||
|
|
44
|
+
timePosition > frameRecords[frameRecords.length - 1].timePosition + frameDuration) {
|
|
45
|
+
|
|
46
|
+
const record: FrameRecord = {
|
|
47
|
+
timePosition,
|
|
48
|
+
loudness: gateVAD.loudnessEstimator.currentLoudness,
|
|
49
|
+
minimumLoudness: gateVAD.minimumLoudnessEstimator.currentPeak,
|
|
50
|
+
maximumLoudness: gateVAD.maximumLoudnessEstimator.currentPeak,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
frameRecords.push(record)
|
|
54
|
+
|
|
55
|
+
//log(`${timePosition.toFixed(3)}: loudness: ${record.loudness.toFixed(2)}dB, min: ${record.minimumLoudness.toFixed(2)}dB, max: ${record.maximumLoudness.toFixed(2)}dB dynamic range: ${record.dynamicRange.toFixed(2)}dB`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const frameActive: boolean[] = []
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < frameRecords.length; i++) {
|
|
62
|
+
frameActive[i] = false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
{
|
|
66
|
+
const backwardExtensionFrameCount = Math.floor(options.backwardExtensionDuration! / frameDuration)
|
|
67
|
+
const relativeThreshold = options.relativeThreshold!
|
|
68
|
+
|
|
69
|
+
let extendedActivityStartIndex = frameRecords.length
|
|
70
|
+
|
|
71
|
+
for (let i = frameRecords.length - 1; i >= 0; i--) {
|
|
72
|
+
const record = frameRecords[i]
|
|
73
|
+
const referenceLoudness = Math.max(record.maximumLoudness, -30)
|
|
74
|
+
|
|
75
|
+
let isActive = false
|
|
76
|
+
|
|
77
|
+
if (i >= extendedActivityStartIndex) {
|
|
78
|
+
isActive = true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (record.loudness >= referenceLoudness + relativeThreshold) {
|
|
82
|
+
isActive = true
|
|
83
|
+
|
|
84
|
+
extendedActivityStartIndex = Math.max(i - backwardExtensionFrameCount, 0)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
frameActive[i] = isActive
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const timeline: Timeline = []
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < frameRecords.length; i++) {
|
|
94
|
+
const record = frameRecords[i]
|
|
95
|
+
const isActive = frameActive[i]
|
|
96
|
+
const activityText = isActive ? 'active' : 'inactive'
|
|
97
|
+
const startTime = record.timePosition
|
|
98
|
+
const endTime = Math.min(startTime + frameDuration, audioDuration)
|
|
99
|
+
|
|
100
|
+
if (timeline.length == 0 || timeline[timeline.length - 1].text != activityText) {
|
|
101
|
+
timeline.push({
|
|
102
|
+
type: 'segment',
|
|
103
|
+
text: activityText,
|
|
104
|
+
startTime,
|
|
105
|
+
endTime,
|
|
106
|
+
})
|
|
107
|
+
} else {
|
|
108
|
+
timeline[timeline.length - 1].endTime = endTime
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return timeline
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class AdaptiveGateVAD {
|
|
116
|
+
channelHighpassFilters: BiquadFilter[]
|
|
117
|
+
channelLowpassFilters: BiquadFilter[]
|
|
118
|
+
|
|
119
|
+
loudnessEstimator: LoudnessEstimator
|
|
120
|
+
|
|
121
|
+
minimumLoudnessEstimator: DecayingPeakEstimator
|
|
122
|
+
maximumLoudnessEstimator: DecayingPeakEstimator
|
|
123
|
+
|
|
124
|
+
constructor(
|
|
125
|
+
public readonly sampleRate: number,
|
|
126
|
+
public readonly channelCount: number,
|
|
127
|
+
public readonly options: AdaptiveGateVADOptions) {
|
|
128
|
+
|
|
129
|
+
this.channelHighpassFilters = []
|
|
130
|
+
this.channelLowpassFilters = []
|
|
131
|
+
|
|
132
|
+
for (let i = 0; i < this.channelCount; i++) {
|
|
133
|
+
this.channelHighpassFilters.push(createHighpassFilter(this.sampleRate, options.lowCutoff!))
|
|
134
|
+
this.channelLowpassFilters.push(createLowpassFilter(this.sampleRate, options.highCutoff!))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.loudnessEstimator = new LoudnessEstimator({
|
|
138
|
+
sampleRate: this.sampleRate,
|
|
139
|
+
channelCount: this.channelCount,
|
|
140
|
+
positiveAdaptationRate: options.positiveAdaptationRate!,
|
|
141
|
+
negativeAdaptationRate: options.negativeAdaptationRate!,
|
|
142
|
+
initialEstimate: -60,
|
|
143
|
+
minimumLoudness: -60,
|
|
144
|
+
applyKWeighting: false,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const ticksPerSecond = this.sampleRate * this.channelCount
|
|
148
|
+
|
|
149
|
+
this.minimumLoudnessEstimator = new DecayingPeakEstimator({
|
|
150
|
+
kind: 'minimum',
|
|
151
|
+
decayPerSecond: options.peakLoudnessDecay!,
|
|
152
|
+
initialPeak: -60,
|
|
153
|
+
}, ticksPerSecond)
|
|
154
|
+
|
|
155
|
+
this.maximumLoudnessEstimator = new DecayingPeakEstimator({
|
|
156
|
+
kind: 'maximum',
|
|
157
|
+
decayPerSecond: options.peakLoudnessDecay!,
|
|
158
|
+
initialPeak: -60,
|
|
159
|
+
}, ticksPerSecond)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
process(sample: number, channelIndex: number) {
|
|
163
|
+
sample = this.channelHighpassFilters[channelIndex].filter(sample)
|
|
164
|
+
sample = this.channelLowpassFilters[channelIndex].filter(sample)
|
|
165
|
+
|
|
166
|
+
this.loudnessEstimator.process(sample, channelIndex)
|
|
167
|
+
|
|
168
|
+
const currentLoudness = this.loudnessEstimator.currentLoudness
|
|
169
|
+
|
|
170
|
+
this.minimumLoudnessEstimator.process(currentLoudness)
|
|
171
|
+
|
|
172
|
+
if (currentLoudness >= -60) {
|
|
173
|
+
this.maximumLoudnessEstimator.process(currentLoudness)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface AdaptiveGateVADOptions {
|
|
179
|
+
lowCutoff?: number
|
|
180
|
+
highCutoff?: number
|
|
181
|
+
|
|
182
|
+
positiveAdaptationRate?: number,
|
|
183
|
+
negativeAdaptationRate?: number,
|
|
184
|
+
|
|
185
|
+
peakLoudnessDecay?: number,
|
|
186
|
+
|
|
187
|
+
backwardExtensionDuration?: number
|
|
188
|
+
relativeThreshold?: number
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const defaultAdaptiveGateOptions: AdaptiveGateVADOptions = {
|
|
192
|
+
lowCutoff: 100,
|
|
193
|
+
highCutoff: 1000,
|
|
194
|
+
|
|
195
|
+
positiveAdaptationRate: 400.0,
|
|
196
|
+
negativeAdaptationRate: 10.0,
|
|
197
|
+
|
|
198
|
+
peakLoudnessDecay: 4.0,
|
|
199
|
+
|
|
200
|
+
backwardExtensionDuration: 0.2,
|
|
201
|
+
relativeThreshold: -15,
|
|
202
|
+
}
|
|
@@ -5,9 +5,9 @@ import { RawAudio } from '../audio/AudioUtilities.js'
|
|
|
5
5
|
|
|
6
6
|
let sileroVad: SileroVAD
|
|
7
7
|
|
|
8
|
-
export async function detectVoiceActivity(rawAudio: RawAudio, modelPath: string, frameDuration: 30 | 60 | 90
|
|
8
|
+
export async function detectVoiceActivity(rawAudio: RawAudio, modelPath: string, frameDuration: 30 | 60 | 90) {
|
|
9
9
|
if (rawAudio.sampleRate != 16000) {
|
|
10
|
-
throw new Error(
|
|
10
|
+
throw new Error('Audio sample rate must be 16KHz')
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const audioSamples = rawAudio.audioChannels[0]
|
|
@@ -68,10 +68,10 @@ export class SileroVAD {
|
|
|
68
68
|
|
|
69
69
|
const results = await this.session!.run(inputs)
|
|
70
70
|
|
|
71
|
-
const probability = results[
|
|
71
|
+
const probability = results['output'].data[0] as number
|
|
72
72
|
|
|
73
|
-
this.modelStateH = results[
|
|
74
|
-
this.modelStateC = results[
|
|
73
|
+
this.modelStateH = results['hn']
|
|
74
|
+
this.modelStateC = results['cn']
|
|
75
75
|
|
|
76
76
|
return probability
|
|
77
77
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as AudioBufferConversion from
|
|
2
|
-
import { RawAudio } from
|
|
3
|
-
import { WasmMemoryManager } from
|
|
1
|
+
import * as AudioBufferConversion from '../audio/AudioBufferConversion.js'
|
|
2
|
+
import { RawAudio } from '../audio/AudioUtilities.js'
|
|
3
|
+
import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
|
|
4
4
|
|
|
5
5
|
export async function detectVoiceActivity(rawAudio: RawAudio, frameDuration: 10 | 20 | 30 = 10, mode: 0 | 1 | 2 | 3 = 0) {
|
|
6
6
|
if (rawAudio.sampleRate != 16000) {
|
|
7
|
-
throw new Error(
|
|
7
|
+
throw new Error('Audio sample rate must be 16KHz')
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const frameClassifications: (0 | 1)[] = await fvad(AudioBufferConversion.float32ToInt16Pcm(rawAudio.audioChannels[0]), rawAudio.sampleRate, frameDuration, mode)
|
|
@@ -52,7 +52,7 @@ export async function fvad(samples: Int16Array, sampleRate: number, frameDuratio
|
|
|
52
52
|
const fvadResult = fvad_process(instancePtr, frameSamplesRef.address, frameSampleCount)
|
|
53
53
|
|
|
54
54
|
if (fvadResult == -1) {
|
|
55
|
-
throw new Error(
|
|
55
|
+
throw new Error('fvad_process failed')
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
result.push(fvadResult)
|