echogarden 2.5.0 → 2.5.2
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/data/lexicons/heteronyms.en.json +4 -4
- package/data/lexicons/words.en.json +240 -0
- package/dist/cli/CLI.js +10 -4
- package/dist/cli/CLI.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.js +10 -5
- package/dist/codecs/FFMpegTranscoder.js.map +1 -1
- package/dist/nlp/PhoneConversion.js +4 -3
- package/dist/nlp/PhoneConversion.js.map +1 -1
- package/dist/nlp/TextNormalizer.d.ts +1 -1
- package/dist/nlp/TextNormalizer.js +30 -25
- package/dist/nlp/TextNormalizer.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +28 -15
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/utilities/WasmMemoryManager.d.ts +1 -1
- package/package.json +12 -12
- package/src/cli/CLI.ts +11 -5
- package/src/codecs/FFMpegTranscoder.ts +9 -5
- package/src/nlp/PhoneConversion.ts +4 -3
- package/src/nlp/TextNormalizer.ts +36 -25
- package/src/synthesis/EspeakTTS.ts +31 -16
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { getShortLanguageCode } from '../utilities/Locale.js'
|
|
2
2
|
import { substituteCharactersUsingLookup } from '../utilities/StringUtilities.js'
|
|
3
3
|
|
|
4
|
-
export function getNormalizedFragmentsForSpeech(
|
|
4
|
+
export function getNormalizedFragmentsForSpeech(
|
|
5
|
+
words: string[],
|
|
6
|
+
nonWhitespaceWords: string[],
|
|
7
|
+
nonWhitespaceWordOriginalIndex: number[],
|
|
8
|
+
language: string) {
|
|
9
|
+
|
|
5
10
|
language = getShortLanguageCode(language)
|
|
6
11
|
|
|
7
12
|
if (language != 'en') {
|
|
8
|
-
return { normalizedFragments: [...
|
|
13
|
+
return { normalizedFragments: [...nonWhitespaceWords], referenceFragments: [...nonWhitespaceWords] }
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
const numberPattern = /^[0-9][0-9\,\.]*$/
|
|
@@ -41,73 +46,79 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
|
|
|
41
46
|
const normalizedFragments: string[] = []
|
|
42
47
|
const referenceFragments: string[] = []
|
|
43
48
|
|
|
44
|
-
for (let wordIndex = 0; wordIndex <
|
|
45
|
-
const word =
|
|
49
|
+
for (let wordIndex = 0; wordIndex < nonWhitespaceWords.length; wordIndex++) {
|
|
50
|
+
const word = nonWhitespaceWords[wordIndex]
|
|
46
51
|
const lowerCaseWord = word.toLowerCase()
|
|
47
52
|
|
|
48
|
-
const
|
|
49
|
-
const
|
|
53
|
+
const nextNonWhitespaceWords = nonWhitespaceWords.slice(wordIndex + 1)
|
|
54
|
+
const nextNonWhitespaceWord = nextNonWhitespaceWords[0]
|
|
55
|
+
|
|
56
|
+
const originalWordIndex = nonWhitespaceWordOriginalIndex[wordIndex]
|
|
57
|
+
const isFollowedByWhitespace = words[originalWordIndex + 1]?.trim().length === 0
|
|
50
58
|
|
|
51
59
|
if ( // Normalize a four digit year pattern, e.g. 'in 1995'.
|
|
52
60
|
wordsPrecedingAYear.includes(lowerCaseWord) &&
|
|
53
|
-
|
|
61
|
+
isFollowedByWhitespace &&
|
|
62
|
+
fourDigitYearPattern.test(nextNonWhitespaceWord)) {
|
|
54
63
|
|
|
55
|
-
const normalizedString = normalizeFourDigitYearString(
|
|
64
|
+
const normalizedString = normalizeFourDigitYearString(nextNonWhitespaceWord)
|
|
56
65
|
|
|
57
66
|
normalizedFragments.push(word)
|
|
58
67
|
referenceFragments.push(word)
|
|
59
68
|
|
|
60
69
|
normalizedFragments.push(normalizedString)
|
|
61
|
-
referenceFragments.push(
|
|
70
|
+
referenceFragments.push(nextNonWhitespaceWord)
|
|
62
71
|
|
|
63
72
|
wordIndex += 1
|
|
64
73
|
} else if ( // Normalize a four digit decade pattern, e.g. 'the 1980s'.
|
|
65
74
|
wordsPrecedingADecade.includes(lowerCaseWord) &&
|
|
66
|
-
|
|
75
|
+
isFollowedByWhitespace &&
|
|
76
|
+
fourDigitDecadePattern.test(nextNonWhitespaceWord)) {
|
|
67
77
|
|
|
68
|
-
const normalizedString = normalizeFourDigitDecadeString(
|
|
78
|
+
const normalizedString = normalizeFourDigitDecadeString(nextNonWhitespaceWord)
|
|
69
79
|
|
|
70
80
|
normalizedFragments.push(word)
|
|
71
81
|
referenceFragments.push(word)
|
|
72
82
|
|
|
73
83
|
normalizedFragments.push(normalizedString)
|
|
74
|
-
referenceFragments.push(
|
|
84
|
+
referenceFragments.push(nextNonWhitespaceWord)
|
|
75
85
|
|
|
76
86
|
wordIndex += 1
|
|
77
|
-
} else if ( // Normalize a year range pattern, e.g. '1835-1896'
|
|
78
|
-
fourDigitYearRangePattern.test(words.slice(
|
|
87
|
+
} else if ( // Normalize a year range pattern, e.g. '1835-1896', ensure there are no spaces between words
|
|
88
|
+
fourDigitYearRangePattern.test(words.slice(originalWordIndex, originalWordIndex + 3).join(''))) {
|
|
79
89
|
|
|
80
|
-
normalizedFragments.push(normalizeFourDigitYearString(
|
|
81
|
-
referenceFragments.push(
|
|
90
|
+
normalizedFragments.push(normalizeFourDigitYearString(nonWhitespaceWords[wordIndex]))
|
|
91
|
+
referenceFragments.push(nonWhitespaceWords[wordIndex])
|
|
82
92
|
|
|
83
93
|
normalizedFragments.push('to')
|
|
84
|
-
referenceFragments.push(
|
|
94
|
+
referenceFragments.push(nonWhitespaceWords[wordIndex + 1])
|
|
85
95
|
|
|
86
|
-
normalizedFragments.push(normalizeFourDigitYearString(
|
|
87
|
-
referenceFragments.push(
|
|
96
|
+
normalizedFragments.push(normalizeFourDigitYearString(nonWhitespaceWords[wordIndex + 2]))
|
|
97
|
+
referenceFragments.push(nonWhitespaceWords[wordIndex + 2])
|
|
88
98
|
|
|
89
99
|
wordIndex += 2
|
|
90
100
|
} else if ( // Normalize a currency pattern, e.g. '$53.1 million', '€3.53'
|
|
91
101
|
symbolsPrecedingACurrency.includes(lowerCaseWord) &&
|
|
92
|
-
|
|
102
|
+
!isFollowedByWhitespace &&
|
|
103
|
+
numberPattern.test(nextNonWhitespaceWord)) {
|
|
93
104
|
|
|
94
105
|
let currencyWord = symbolsPrecedingACurrencyAsWords[symbolsPrecedingACurrency.indexOf(lowerCaseWord)]
|
|
95
106
|
|
|
96
|
-
if (wordsSucceedingACurrency.includes(
|
|
97
|
-
const normalizedString = `${
|
|
107
|
+
if (wordsSucceedingACurrency.includes(nextNonWhitespaceWords[1]?.toLowerCase())) {
|
|
108
|
+
const normalizedString = `${nextNonWhitespaceWord} ${nextNonWhitespaceWords[1]} ${currencyWord}`
|
|
98
109
|
|
|
99
110
|
normalizedFragments.push(normalizedString)
|
|
100
111
|
|
|
101
|
-
const referenceString = `${word}${
|
|
112
|
+
const referenceString = `${word}${nextNonWhitespaceWord} ${nextNonWhitespaceWords[1]}`
|
|
102
113
|
referenceFragments.push(referenceString)
|
|
103
114
|
|
|
104
115
|
wordIndex += 2
|
|
105
116
|
} else {
|
|
106
|
-
const normalizedString = `${
|
|
117
|
+
const normalizedString = `${nextNonWhitespaceWord} ${currencyWord}`
|
|
107
118
|
|
|
108
119
|
normalizedFragments.push(normalizedString)
|
|
109
120
|
|
|
110
|
-
const referenceString = `${word}${
|
|
121
|
+
const referenceString = `${word}${nextNonWhitespaceWord}`
|
|
111
122
|
referenceFragments.push(referenceString)
|
|
112
123
|
|
|
113
124
|
wordIndex += 1
|
|
@@ -40,30 +40,45 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
40
40
|
let words = await splitToWords(text, language)
|
|
41
41
|
|
|
42
42
|
// Merge repeating non-words to a single word to work around eSpeak bug
|
|
43
|
-
|
|
43
|
+
{
|
|
44
|
+
const wordsWithMerges: string[] = []
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
for (let i = 0; i < words.length; i++) {
|
|
47
|
+
const currentWord = words[i]
|
|
48
|
+
const previousWord = words[i - 1]
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if (
|
|
51
|
+
i > 0 &&
|
|
52
|
+
currentWord === previousWord &&
|
|
53
|
+
!['[', ']'].includes(currentWord) && // Work around eSpeak-NG marker bug with repeating squared brackets
|
|
54
|
+
!wordCharacterPattern.test(currentWord)) {
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
wordsWithMerges[wordsWithMerges.length - 1] += currentWord
|
|
57
|
+
} else {
|
|
58
|
+
wordsWithMerges.push(currentWord)
|
|
59
|
+
}
|
|
58
60
|
}
|
|
61
|
+
|
|
62
|
+
words = wordsWithMerges
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
words
|
|
65
|
+
// Remove words containing only whitespace
|
|
66
|
+
const nonWhitespaceWords: string[] = []
|
|
67
|
+
const nonWhitespaceWordsOriginalIndex: number[] = []
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
{
|
|
70
|
+
for (let i = 0; i < words.length; i++) {
|
|
71
|
+
const word = words[i]
|
|
72
|
+
const wordIsWhitespace = word.trim().length === 0
|
|
73
|
+
|
|
74
|
+
if (!wordIsWhitespace) {
|
|
75
|
+
nonWhitespaceWords.push(word)
|
|
76
|
+
nonWhitespaceWordsOriginalIndex.push(i)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
65
80
|
|
|
66
|
-
const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, language)
|
|
81
|
+
const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, nonWhitespaceWords, nonWhitespaceWordsOriginalIndex, language)
|
|
67
82
|
|
|
68
83
|
const simplifiedFragments = normalizedFragments.map(word => simplifyPunctuationCharacters(word).toLocaleLowerCase())
|
|
69
84
|
|