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,15 +1,15 @@
|
|
|
1
|
-
import { concatFloat32Arrays, logToStderr, objToString, simplifyPunctuationCharacters } from
|
|
2
|
-
import { int16PcmToFloat32 } from
|
|
1
|
+
import { concatFloat32Arrays, logToStderr, objToString, simplifyPunctuationCharacters } from '../utilities/Utilities.js'
|
|
2
|
+
import { int16PcmToFloat32 } from '../audio/AudioBufferConversion.js'
|
|
3
3
|
import { Logger } from '../utilities/Logger.js'
|
|
4
|
-
import { WasmMemoryManager } from
|
|
5
|
-
import { RawAudio, getEmptyRawAudio } from
|
|
6
|
-
import { playAudioWithTimelinePhones } from
|
|
7
|
-
import { getNormalizedFragmentsForSpeech } from
|
|
8
|
-
import { ipaPhoneToKirshenbaum } from
|
|
9
|
-
import { splitToWords, wordCharacterPattern } from
|
|
10
|
-
import { Lexicon, tryGetFirstLexiconSubstitution } from
|
|
11
|
-
import { phonemizeSentence } from
|
|
12
|
-
import { Timeline, TimelineEntry } from
|
|
4
|
+
import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
|
|
5
|
+
import { RawAudio, getEmptyRawAudio } from '../audio/AudioUtilities.js'
|
|
6
|
+
import { playAudioWithTimelinePhones } from '../audio/AudioPlayer.js'
|
|
7
|
+
import { getNormalizedFragmentsForSpeech } from '../nlp/TextNormalizer.js'
|
|
8
|
+
import { ipaPhoneToKirshenbaum } from '../nlp/PhoneConversion.js'
|
|
9
|
+
import { splitToWords, wordCharacterPattern } from '../nlp/Segmentation.js'
|
|
10
|
+
import { Lexicon, tryGetFirstLexiconSubstitution } from '../nlp/Lexicon.js'
|
|
11
|
+
import { phonemizeSentence } from '../nlp/EspeakPhonemizer.js'
|
|
12
|
+
import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
|
|
13
13
|
|
|
14
14
|
const log = logToStderr
|
|
15
15
|
|
|
@@ -19,12 +19,12 @@ let espeakModule: any
|
|
|
19
19
|
export async function preprocessAndSynthesize(text: string, language: string, espeakOptions: EspeakOptions, lexicons: Lexicon[] = []) {
|
|
20
20
|
const logger = new Logger()
|
|
21
21
|
|
|
22
|
-
await logger.startAsync(
|
|
22
|
+
await logger.startAsync('Tokenize and analyze text')
|
|
23
23
|
|
|
24
24
|
let lowerCaseLanguageCode = language.toLowerCase()
|
|
25
25
|
|
|
26
|
-
if (lowerCaseLanguageCode ==
|
|
27
|
-
lowerCaseLanguageCode =
|
|
26
|
+
if (lowerCaseLanguageCode == 'en-gb') {
|
|
27
|
+
lowerCaseLanguageCode = 'en-gb-x-rp'
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
let fragments: string[]
|
|
@@ -53,7 +53,7 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
53
53
|
words = wordsWithMerges
|
|
54
54
|
|
|
55
55
|
// Remove words containing only whitespace
|
|
56
|
-
words = words.filter(word => word.trim() !=
|
|
56
|
+
words = words.filter(word => word.trim() != '')
|
|
57
57
|
|
|
58
58
|
const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, language)
|
|
59
59
|
|
|
@@ -69,12 +69,12 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
phonemizedFragmentsSubstitutions.set(fragmentIndex, substitutionPhonemes)
|
|
72
|
-
const referenceIPA = (await textToPhonemes(fragment, espeakOptions.voice, true)).replaceAll(
|
|
73
|
-
const referenceKirshenbaum = (await textToPhonemes(fragment, espeakOptions.voice, false)).replaceAll(
|
|
72
|
+
const referenceIPA = (await textToPhonemes(fragment, espeakOptions.voice, true)).replaceAll('_', ' ')
|
|
73
|
+
const referenceKirshenbaum = (await textToPhonemes(fragment, espeakOptions.voice, false)).replaceAll('_', '')
|
|
74
74
|
|
|
75
|
-
const kirshenbaumPhonemes = substitutionPhonemes.map(phone => ipaPhoneToKirshenbaum(phone)).join(
|
|
75
|
+
const kirshenbaumPhonemes = substitutionPhonemes.map(phone => ipaPhoneToKirshenbaum(phone)).join('')
|
|
76
76
|
|
|
77
|
-
logger.logTitledMessage(`\nLexicon substitution for '${fragment}'`, `IPA: ${substitutionPhonemes.join(
|
|
77
|
+
logger.logTitledMessage(`\nLexicon substitution for '${fragment}'`, `IPA: ${substitutionPhonemes.join(' ')} (original: ${referenceIPA}), Kirshenbaum: ${kirshenbaumPhonemes} (reference: ${referenceKirshenbaum})`)
|
|
78
78
|
|
|
79
79
|
const substitutionPhonemesFragment = ` [[${kirshenbaumPhonemes}]] `
|
|
80
80
|
|
|
@@ -84,11 +84,11 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
84
84
|
fragments = referenceFragments
|
|
85
85
|
preprocessedFragments = normalizedFragments
|
|
86
86
|
|
|
87
|
-
logger.start(
|
|
87
|
+
logger.start('Synthesize preprocessed fragments with eSpeak')
|
|
88
88
|
|
|
89
89
|
const { rawAudio: referenceSynthesizedAudio, timeline: referenceTimeline } = await synthesizeFragments(preprocessedFragments, espeakOptions)
|
|
90
90
|
|
|
91
|
-
await logger.startAsync(
|
|
91
|
+
await logger.startAsync('Build phonemized tokens')
|
|
92
92
|
|
|
93
93
|
const phonemizedSentence: string[][][] = []
|
|
94
94
|
|
|
@@ -125,19 +125,19 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
logger.log(phonemizedSentence.map(phrase => phrase.map(word => word.join(
|
|
128
|
+
logger.log(phonemizedSentence.map(phrase => phrase.map(word => word.join(' ')).join(' | ')).join(' || '))
|
|
129
129
|
|
|
130
130
|
logger.end()
|
|
131
131
|
|
|
132
132
|
return { referenceSynthesizedAudio, referenceTimeline, fragments, preprocessedFragments, phonemizedFragmentsSubstitutions, phonemizedSentence }
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
export async function synthesizeFragments(fragments: string[], espeakOptions: EspeakOptions
|
|
135
|
+
export async function synthesizeFragments(fragments: string[], espeakOptions: EspeakOptions) {
|
|
136
136
|
const logger = new Logger()
|
|
137
137
|
|
|
138
138
|
const sampleRate = await getSampleRate()
|
|
139
139
|
|
|
140
|
-
//fragments = fragments.filter(fragment => fragment.trim() !=
|
|
140
|
+
//fragments = fragments.filter(fragment => fragment.trim() != '')
|
|
141
141
|
|
|
142
142
|
if (fragments.length == 0) {
|
|
143
143
|
return {
|
|
@@ -155,17 +155,16 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
155
155
|
fragment = simplifyPunctuationCharacters(fragment)
|
|
156
156
|
|
|
157
157
|
fragment = fragment
|
|
158
|
-
.replaceAll(
|
|
159
|
-
.replaceAll(
|
|
158
|
+
.replaceAll('<', '<')
|
|
159
|
+
.replaceAll('>', '>')
|
|
160
160
|
|
|
161
|
-
if (insertSeparators) {
|
|
162
|
-
|
|
163
|
-
// which breaks this approach
|
|
161
|
+
if (espeakOptions.insertSeparators) {
|
|
162
|
+
const separator = ` | `
|
|
164
163
|
|
|
165
|
-
textWithMarkers += `<mark name="s-${i}"
|
|
164
|
+
textWithMarkers += `<mark name="s-${i}"/>${separator}${fragment}${separator}<mark name="e-${i}"/>`
|
|
166
165
|
} else {
|
|
167
|
-
if (fragment.endsWith(
|
|
168
|
-
fragment +=
|
|
166
|
+
if (fragment.endsWith('.')) {
|
|
167
|
+
fragment += ' ()'
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
textWithMarkers += `<mark name="s-${i}"/>${fragment}<mark name="e-${i}"/> `
|
|
@@ -178,13 +177,13 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
178
177
|
|
|
179
178
|
// Build word timeline from events
|
|
180
179
|
const wordTimeline: Timeline = fragments.map(word => ({
|
|
181
|
-
type:
|
|
180
|
+
type: 'word',
|
|
182
181
|
text: word,
|
|
183
182
|
startTime: -1,
|
|
184
183
|
endTime: -1,
|
|
185
184
|
timeline: [{
|
|
186
|
-
type:
|
|
187
|
-
text:
|
|
185
|
+
type: 'token',
|
|
186
|
+
text: '',
|
|
188
187
|
startTime: -1,
|
|
189
188
|
endTime: -1,
|
|
190
189
|
timeline: []
|
|
@@ -210,7 +209,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
210
209
|
lastPhoneEntry.endTime = eventTime
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
if (event.type ==
|
|
212
|
+
if (event.type == 'word') {
|
|
214
213
|
if (!event.id || currentPhoneTimeline.length == 0) {
|
|
215
214
|
continue
|
|
216
215
|
}
|
|
@@ -220,21 +219,21 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
220
219
|
}
|
|
221
220
|
|
|
222
221
|
currentTokenTimeline.push({
|
|
223
|
-
type:
|
|
224
|
-
text:
|
|
222
|
+
type: 'token',
|
|
223
|
+
text: '',
|
|
225
224
|
startTime: eventTime,
|
|
226
225
|
endTime: -1,
|
|
227
226
|
timeline: []
|
|
228
227
|
})
|
|
229
|
-
} else if (event.type ==
|
|
228
|
+
} else if (event.type == 'phoneme') {
|
|
230
229
|
const phoneText = event.id as string
|
|
231
230
|
|
|
232
|
-
if (!phoneText || phoneText.startsWith(
|
|
231
|
+
if (!phoneText || phoneText.startsWith('(')) {
|
|
233
232
|
continue
|
|
234
233
|
}
|
|
235
234
|
|
|
236
235
|
currentPhoneTimeline.push({
|
|
237
|
-
type:
|
|
236
|
+
type: 'phone',
|
|
238
237
|
text: phoneText,
|
|
239
238
|
startTime: eventTime,
|
|
240
239
|
endTime: -1
|
|
@@ -242,10 +241,10 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
242
241
|
|
|
243
242
|
currentTokenEntry.text += phoneText
|
|
244
243
|
currentTokenEntry.startTime = currentPhoneTimeline[0].startTime
|
|
245
|
-
} else if (event.type ==
|
|
244
|
+
} else if (event.type == 'mark') {
|
|
246
245
|
const markerName = event.id! as string
|
|
247
246
|
|
|
248
|
-
if (markerName.startsWith(
|
|
247
|
+
if (markerName.startsWith('s-')) {
|
|
249
248
|
const markerIndex = parseInt(markerName.substring(2))
|
|
250
249
|
|
|
251
250
|
if (markerIndex != wordIndex) {
|
|
@@ -258,7 +257,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
258
257
|
|
|
259
258
|
currentWordEntry.startTime = eventTime
|
|
260
259
|
currentTokenEntry.startTime = eventTime
|
|
261
|
-
} else if (markerName.startsWith(
|
|
260
|
+
} else if (markerName.startsWith('e-')) {
|
|
262
261
|
const markerIndex = parseInt(markerName.substring(2))
|
|
263
262
|
|
|
264
263
|
if (markerIndex != wordIndex) {
|
|
@@ -278,7 +277,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
278
277
|
} else {
|
|
279
278
|
continue
|
|
280
279
|
}
|
|
281
|
-
} else if (event.type ==
|
|
280
|
+
} else if (event.type == 'end') {
|
|
282
281
|
clauseEndIndexes.push(wordIndex)
|
|
283
282
|
}
|
|
284
283
|
}
|
|
@@ -294,22 +293,22 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
294
293
|
}
|
|
295
294
|
|
|
296
295
|
if (!tokenTimeline || tokenTimeline.length == 0) {
|
|
297
|
-
throw new Error(
|
|
296
|
+
throw new Error('Unexpected: token timeline should exist and have at least one token')
|
|
298
297
|
}
|
|
299
298
|
|
|
300
|
-
if (tokenTimeline[0].text != '') {
|
|
299
|
+
if (tokenTimeline.length !== 1 && tokenTimeline[0].text != '') {
|
|
301
300
|
continue
|
|
302
301
|
}
|
|
303
302
|
|
|
304
|
-
const wordReferencePhonemes = (await textToPhonemes(wordEntry.text, espeakOptions.voice, true)).split(
|
|
303
|
+
const wordReferencePhonemes = (await textToPhonemes(wordEntry.text, espeakOptions.voice, true)).split('_')
|
|
305
304
|
|
|
306
|
-
const wordReferenceIPA = wordReferencePhonemes.join(
|
|
305
|
+
const wordReferenceIPA = wordReferencePhonemes.join(' ')
|
|
307
306
|
|
|
308
307
|
if (wordReferenceIPA.trim().length == 0) {
|
|
309
308
|
continue
|
|
310
309
|
}
|
|
311
310
|
|
|
312
|
-
const wordReferenceIPAWithoutStress = wordReferenceIPA.replaceAll(
|
|
311
|
+
const wordReferenceIPAWithoutStress = wordReferenceIPA.replaceAll('ˈ', '').replaceAll('ˌ', '')
|
|
313
312
|
|
|
314
313
|
const previousWordEntry = wordTimeline[index - 1]
|
|
315
314
|
|
|
@@ -317,13 +316,31 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
317
316
|
continue
|
|
318
317
|
}
|
|
319
318
|
|
|
320
|
-
const previousWordTokenEntry = previousWordEntry.timeline[
|
|
319
|
+
const previousWordTokenEntry = previousWordEntry.timeline[previousWordEntry.timeline.length - 1]
|
|
321
320
|
|
|
322
|
-
if (!previousWordTokenEntry.timeline
|
|
321
|
+
if (!previousWordTokenEntry.timeline) {
|
|
323
322
|
continue
|
|
324
323
|
}
|
|
325
324
|
|
|
326
|
-
const previousWordTokenIPAWithoutStress = previousWordTokenEntry.timeline.map(phoneEntry => phoneEntry.text.replaceAll(
|
|
325
|
+
const previousWordTokenIPAWithoutStress = previousWordTokenEntry.timeline.map(phoneEntry => phoneEntry.text.replaceAll('ˈ', '').replaceAll('ˌ', '')).join(' ')
|
|
326
|
+
|
|
327
|
+
if (previousWordEntry.timeline.length > 1 && previousWordTokenIPAWithoutStress === wordReferenceIPAWithoutStress) {
|
|
328
|
+
tokenTimeline.pop()
|
|
329
|
+
|
|
330
|
+
const tokenEntryToInsert = previousWordEntry.timeline.pop()!
|
|
331
|
+
tokenTimeline.push(tokenEntryToInsert)
|
|
332
|
+
|
|
333
|
+
previousWordEntry.endTime = previousWordEntry.timeline[previousWordEntry.timeline.length - 1].endTime
|
|
334
|
+
|
|
335
|
+
wordEntry.startTime = tokenEntryToInsert.startTime
|
|
336
|
+
wordEntry.endTime = tokenEntryToInsert.endTime
|
|
337
|
+
|
|
338
|
+
continue
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (previousWordTokenEntry.timeline.length <= wordReferencePhonemes.length) {
|
|
342
|
+
continue
|
|
343
|
+
}
|
|
327
344
|
|
|
328
345
|
if (!previousWordTokenIPAWithoutStress.endsWith(wordReferenceIPAWithoutStress)) {
|
|
329
346
|
continue
|
|
@@ -332,14 +349,14 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
332
349
|
const tokenEntry = tokenTimeline[0]
|
|
333
350
|
|
|
334
351
|
tokenEntry.timeline = previousWordTokenEntry.timeline.splice(previousWordTokenEntry.timeline.length - wordReferencePhonemes.length)
|
|
335
|
-
tokenEntry.text = tokenEntry.timeline.map(phoneEntry => phoneEntry.text).join(
|
|
352
|
+
tokenEntry.text = tokenEntry.timeline.map(phoneEntry => phoneEntry.text).join('')
|
|
336
353
|
|
|
337
354
|
tokenEntry.startTime = tokenEntry.timeline[0].startTime
|
|
338
355
|
tokenEntry.endTime = tokenEntry.timeline[tokenEntry.timeline.length - 1].endTime
|
|
339
356
|
wordEntry.startTime = tokenEntry.startTime
|
|
340
357
|
wordEntry.endTime = tokenEntry.endTime
|
|
341
358
|
|
|
342
|
-
previousWordTokenEntry.text = previousWordTokenEntry.timeline.map(phoneEntry => phoneEntry.text).join(
|
|
359
|
+
previousWordTokenEntry.text = previousWordTokenEntry.timeline.map(phoneEntry => phoneEntry.text).join('')
|
|
343
360
|
previousWordTokenEntry.endTime = previousWordTokenEntry.timeline[previousWordTokenEntry.timeline.length - 1].endTime
|
|
344
361
|
previousWordEntry.endTime = previousWordTokenEntry.endTime
|
|
345
362
|
}
|
|
@@ -351,8 +368,8 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
351
368
|
|
|
352
369
|
for (const clauseEndIndex of clauseEndIndexes) {
|
|
353
370
|
const newClause: TimelineEntry = {
|
|
354
|
-
type:
|
|
355
|
-
text:
|
|
371
|
+
type: 'clause',
|
|
372
|
+
text: '',
|
|
356
373
|
startTime: -1,
|
|
357
374
|
endTime: -1,
|
|
358
375
|
timeline: []
|
|
@@ -382,7 +399,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
382
399
|
|
|
383
400
|
export async function synthesize(text: string, espeakOptions: EspeakOptions) {
|
|
384
401
|
const logger = new Logger()
|
|
385
|
-
logger.start(
|
|
402
|
+
logger.start('Get eSpeak Emscripten instance')
|
|
386
403
|
|
|
387
404
|
if (!espeakOptions.ssml) {
|
|
388
405
|
const { escape } = await import('html-escaper')
|
|
@@ -395,7 +412,7 @@ export async function synthesize(text: string, espeakOptions: EspeakOptions) {
|
|
|
395
412
|
const sampleChunks: Float32Array[] = []
|
|
396
413
|
const allEvents: EspeakEvent[] = []
|
|
397
414
|
|
|
398
|
-
logger.start(
|
|
415
|
+
logger.start('Synthesize with eSpeak')
|
|
399
416
|
|
|
400
417
|
if (espeakOptions.useKlatt) {
|
|
401
418
|
await setVoice(`${espeakOptions.voice}+klatt6`)
|
|
@@ -413,9 +430,9 @@ export async function synthesize(text: string, espeakOptions: EspeakOptions) {
|
|
|
413
430
|
}
|
|
414
431
|
|
|
415
432
|
for (const event of events) {
|
|
416
|
-
if (event.type ==
|
|
433
|
+
if (event.type == 'word') {
|
|
417
434
|
const textPosition = event.text_position - 1;
|
|
418
|
-
(event as any)[
|
|
435
|
+
(event as any)['text'] = text.substring(textPosition, textPosition + event.word_length)
|
|
419
436
|
}
|
|
420
437
|
}
|
|
421
438
|
|
|
@@ -515,7 +532,7 @@ async function getEspeakInstance() {
|
|
|
515
532
|
return { instance: espeakInstance, module: espeakModule }
|
|
516
533
|
}
|
|
517
534
|
|
|
518
|
-
export type EspeakEventType =
|
|
535
|
+
export type EspeakEventType = 'sentence' | 'word' | 'phoneme' | 'end' | 'mark' | 'play' | 'msg_terminated' | 'list_terminated' | 'samplerate'
|
|
519
536
|
|
|
520
537
|
export interface EspeakEvent {
|
|
521
538
|
audio_position: number
|
|
@@ -531,6 +548,7 @@ export interface EspeakOptions {
|
|
|
531
548
|
pitch: number
|
|
532
549
|
pitchRange: number
|
|
533
550
|
useKlatt: boolean
|
|
551
|
+
insertSeparators: boolean
|
|
534
552
|
}
|
|
535
553
|
|
|
536
554
|
export const defaultEspeakOptions: EspeakOptions = {
|
|
@@ -539,17 +557,18 @@ export const defaultEspeakOptions: EspeakOptions = {
|
|
|
539
557
|
rate: 1.0,
|
|
540
558
|
pitch: 1.0,
|
|
541
559
|
pitchRange: 1.0,
|
|
542
|
-
useKlatt: false
|
|
560
|
+
useKlatt: false,
|
|
561
|
+
insertSeparators: false
|
|
543
562
|
}
|
|
544
563
|
|
|
545
564
|
export async function testEspeakSynthesisWithPrePhonemizedInputs(text: string) {
|
|
546
|
-
const ipaPhonemizedSentence = (await phonemizeSentence(text,
|
|
547
|
-
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text,
|
|
565
|
+
const ipaPhonemizedSentence = (await phonemizeSentence(text, 'en-us')).flatMap(clause => clause)
|
|
566
|
+
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text, 'en-us', undefined, false)).flatMap(clause => clause)
|
|
548
567
|
log(kirshenbaumPhonemizedSentence)
|
|
549
568
|
|
|
550
569
|
const fragments = ipaPhonemizedSentence.map(word =>
|
|
551
570
|
word.map(phoneme =>
|
|
552
|
-
ipaPhoneToKirshenbaum(phoneme)).join(
|
|
571
|
+
ipaPhoneToKirshenbaum(phoneme)).join('')).map(word => ` [[${word}]] `)
|
|
553
572
|
|
|
554
573
|
const { rawAudio, timeline } = await synthesizeFragments(fragments, defaultEspeakOptions)
|
|
555
574
|
|
|
@@ -557,16 +576,16 @@ export async function testEspeakSynthesisWithPrePhonemizedInputs(text: string) {
|
|
|
557
576
|
}
|
|
558
577
|
|
|
559
578
|
export async function testKirshenbaumPhonemization(text: string) {
|
|
560
|
-
const ipaPhonemizedSentence = (await phonemizeSentence(text,
|
|
561
|
-
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text,
|
|
579
|
+
const ipaPhonemizedSentence = (await phonemizeSentence(text, 'en-us')).flatMap(clause => clause)
|
|
580
|
+
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text, 'en-us', undefined, false)).flatMap(clause => clause)
|
|
562
581
|
|
|
563
|
-
const ipaFragments = ipaPhonemizedSentence.map(word => word.join(
|
|
582
|
+
const ipaFragments = ipaPhonemizedSentence.map(word => word.join(''))
|
|
564
583
|
|
|
565
|
-
const kirshenbaumFragments = kirshenbaumPhonemizedSentence.map(word => word.join(
|
|
584
|
+
const kirshenbaumFragments = kirshenbaumPhonemizedSentence.map(word => word.join(''))
|
|
566
585
|
|
|
567
586
|
const fragments = ipaPhonemizedSentence.map(word =>
|
|
568
587
|
word.map(phoneme =>
|
|
569
|
-
ipaPhoneToKirshenbaum(phoneme)).join(
|
|
588
|
+
ipaPhoneToKirshenbaum(phoneme)).join(''))
|
|
570
589
|
|
|
571
590
|
for (let i = 0; i < fragments.length; i++) {
|
|
572
591
|
log(`IPA: ${ipaFragments[i]} | converted: ${fragments[i]} | ground truth: ${kirshenbaumFragments[i]}`)
|