echogarden 0.11.12 → 0.11.13
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/schemas/options.json +16 -0
- package/dist/api/Alignment.js +2 -2
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Recognition.js +2 -2
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/Synthesis.js +5 -4
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/Translation.js +2 -2
- package/dist/api/Translation.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +1 -0
- package/dist/audio/AudioUtilities.js +25 -7
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/cli/CLI.js +2 -2
- package/dist/cli/CLI.js.map +1 -1
- package/dist/recognition/WhisperSTT.js +2 -2
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/subtitles/Subtitles.d.ts +10 -7
- package/dist/subtitles/Subtitles.js +268 -207
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/docs/Options.md +4 -2
- package/package.json +7 -6
- package/src/alignment/DTWMfccSequenceAlignment.ts +43 -0
- package/src/alignment/DTWSequenceAlignment.ts +121 -0
- package/src/alignment/DTWSequenceAlignmentWindowed.ts +210 -0
- package/src/alignment/LevenshteinSequenceAlignment.ts +126 -0
- package/src/alignment/SpeechAlignment.ts +488 -0
- package/src/api/API.ts +12 -0
- package/src/api/APIOptions.ts +15 -0
- package/src/api/Alignment.ts +329 -0
- package/src/api/Common.ts +16 -0
- package/src/api/Denoising.ts +120 -0
- package/src/api/LanguageDetection.ts +286 -0
- package/src/api/Recognition.ts +344 -0
- package/src/api/Synthesis.ts +1735 -0
- package/src/api/Translation.ts +143 -0
- package/src/api/Vad.ts +172 -0
- package/src/audio/AudioBufferConversion.ts +248 -0
- package/src/audio/AudioPlayer.ts +358 -0
- package/src/audio/AudioRecorder.ts +91 -0
- package/src/audio/AudioUtilities.ts +392 -0
- package/src/audio/SoxPath.ts +24 -0
- package/src/cli/CLI.ts +1360 -0
- package/src/cli/CLIConfigFile.ts +91 -0
- package/src/cli/CLILauncher.ts +26 -0
- package/src/cli/CLIOptionsSchema.ts +54 -0
- package/src/cli/CLIParser.ts +41 -0
- package/src/cli/CLIStarter.ts +40 -0
- package/src/codecs/FFMpegTranscoder.ts +214 -0
- package/src/codecs/TIMITCodec.ts +17 -0
- package/src/codecs/WaveCodec.ts +260 -0
- package/src/denoising/RNNoise.ts +95 -0
- package/src/dsp/BiquadFilter.ts +488 -0
- package/src/dsp/FFT.ts +187 -0
- package/src/dsp/MFCC.ts +227 -0
- package/src/dsp/MelSpectogram.ts +145 -0
- package/src/dsp/Rubberband.ts +249 -0
- package/src/dsp/Sonic.ts +59 -0
- package/src/dsp/SpeexResampler.ts +79 -0
- package/src/math/VectorMath.ts +812 -0
- package/src/nlp/ChineseSegmentation.ts +68 -0
- package/src/nlp/CompromiseNLP.ts +113 -0
- package/src/nlp/EspeakPhonemizer.ts +168 -0
- package/src/nlp/IPA.ts +139 -0
- package/src/nlp/JapaneseSegmentation.ts +53 -0
- package/src/nlp/Lexicon.ts +119 -0
- package/src/nlp/PhoneConversion.ts +508 -0
- package/src/nlp/Segmentation.ts +237 -0
- package/src/nlp/TextNormalizer.ts +160 -0
- package/src/recognition/AmazonTranscribeSTT.ts +112 -0
- package/src/recognition/AzureCognitiveServicesSTT.ts +76 -0
- package/src/recognition/GoogleCloudSTT.ts +92 -0
- package/src/recognition/SileroSTT.ts +173 -0
- package/src/recognition/VoskSTT.ts +112 -0
- package/src/recognition/WhisperSTT.ts +1518 -0
- package/src/server/Client.ts +297 -0
- package/src/server/Server.ts +178 -0
- package/src/server/ServerStarter.ts +12 -0
- package/src/server/Worker.ts +400 -0
- package/src/server/WorkerStarter.ts +38 -0
- package/src/speech-language-detection/SileroLanguageDetection.ts +105 -0
- package/src/subtitles/Subtitles.ts +478 -0
- package/src/synthesis/AwsPollyTTS.ts +78 -0
- package/src/synthesis/AzureCognitiveServicesTTS.ts +146 -0
- package/src/synthesis/CoquiServerTTS.ts +29 -0
- package/src/synthesis/ElevenLabsTTS.ts +104 -0
- package/src/synthesis/EspeakTTS.ts +552 -0
- package/src/synthesis/FliteTTS.ts +387 -0
- package/src/synthesis/GoogleCloudTTS.ts +112 -0
- package/src/synthesis/GoogleTranslateTTS.ts +210 -0
- package/src/synthesis/MicrosoftEdgeTTS.ts +298 -0
- package/src/synthesis/SamTTS.ts +30 -0
- package/src/synthesis/SapiTTS.ts +222 -0
- package/src/synthesis/StreamlabsPollyTTS.ts +114 -0
- package/src/synthesis/SvoxPicoTTS.ts +318 -0
- package/src/synthesis/VitsTTS.ts +734 -0
- package/src/tests/Test.ts +24 -0
- package/src/text-language-detection/FastTextLanguageDetection.ts +53 -0
- package/src/text-language-detection/TinyLDLanguageDetection.ts +16 -0
- package/src/typings/Fillers.d.ts +41 -0
- package/src/utilities/BinaryArrayConversion.ts +159 -0
- package/src/utilities/Compression.ts +91 -0
- package/src/utilities/FileDownloader.ts +201 -0
- package/src/utilities/FileSystem.ts +265 -0
- package/src/utilities/Hashing.ts +230 -0
- package/src/utilities/Locale.ts +119 -0
- package/src/utilities/Logger.ts +72 -0
- package/src/utilities/NdArrayUtilities.ts +31 -0
- package/src/utilities/ObjectUtilities.ts +169 -0
- package/src/utilities/OpenPromise.ts +13 -0
- package/src/utilities/PackageManager.ts +97 -0
- package/src/utilities/Queue.ts +17 -0
- package/src/utilities/RandomGenerator.ts +237 -0
- package/src/utilities/SignalChannel.ts +22 -0
- package/src/utilities/TarballMaker.ts +68 -0
- package/src/utilities/Timeline.ts +231 -0
- package/src/utilities/Timer.ts +93 -0
- package/src/utilities/Utilities.ts +574 -0
- package/src/utilities/WasmMemoryManager.ts +516 -0
- package/src/utilities/WebReader.ts +55 -0
- package/src/utilities/WikipediaReader.ts +41 -0
- package/src/voice-activity-detection/SileroVAD.ts +86 -0
- package/src/voice-activity-detection/WebRtcVAD.ts +76 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { SynthesisVoice } from "../api/API.js"
|
|
2
|
+
import { decodeToChannels } from "../audio/AudioBufferConversion.js"
|
|
3
|
+
import { SampleFormat } from "../codecs/WaveCodec.js"
|
|
4
|
+
import { bandwidthToQFactor } from "../dsp/BiquadFilter.js"
|
|
5
|
+
import { Logger } from "../utilities/Logger.js"
|
|
6
|
+
import { WasmMemoryManager } from "../utilities/WasmMemoryManager.js"
|
|
7
|
+
import { RawAudio } from "../audio/AudioUtilities.js"
|
|
8
|
+
import { readFile } from "../utilities/FileSystem.js"
|
|
9
|
+
|
|
10
|
+
let svoxPicoInstance: any
|
|
11
|
+
|
|
12
|
+
export async function synthesize(text: string, textAnalysisFilePath: string, signalGenerationFilePath: string, postprocessOutput = true) {
|
|
13
|
+
const logger = new Logger()
|
|
14
|
+
logger.start("Get pico WASM instance")
|
|
15
|
+
|
|
16
|
+
const m = await getInstance()
|
|
17
|
+
|
|
18
|
+
logger.start("Initialize pico engine")
|
|
19
|
+
|
|
20
|
+
const wasmMemory = new WasmMemoryManager(m)
|
|
21
|
+
|
|
22
|
+
const pico_initialize = m._pico_initialize
|
|
23
|
+
const picoext_setTraceLevel = m._picoext_setTraceLevel
|
|
24
|
+
const pico_loadResource = m._pico_loadResource
|
|
25
|
+
const pico_getResourceName = m._pico_getResourceName
|
|
26
|
+
const pico_createVoiceDefinition = m._pico_createVoiceDefinition
|
|
27
|
+
const pico_addResourceToVoiceDefinition = m._pico_addResourceToVoiceDefinition
|
|
28
|
+
const pico_newEngine = m._pico_newEngine
|
|
29
|
+
const pico_putTextUtf8 = m._pico_putTextUtf8
|
|
30
|
+
const pico_getData = m._pico_getData
|
|
31
|
+
|
|
32
|
+
const pico_getSystemStatusMessage = m._pico_getSystemStatusMessage
|
|
33
|
+
|
|
34
|
+
const pico_disposeEngine = m._pico_disposeEngine
|
|
35
|
+
const pico_terminate = m._pico_terminate
|
|
36
|
+
const pico_releaseVoiceDefinition = m._pico_releaseVoiceDefinition
|
|
37
|
+
const pico_unloadResource = m._pico_unloadResource
|
|
38
|
+
|
|
39
|
+
const picoMemSize = 2500000
|
|
40
|
+
const picoMemAreaRef = wasmMemory.allocUint8Array(picoMemSize)
|
|
41
|
+
|
|
42
|
+
const systemPtrRef = wasmMemory.allocPointer()
|
|
43
|
+
|
|
44
|
+
let resultCode = pico_initialize(picoMemAreaRef.address, picoMemAreaRef.length, systemPtrRef.address)
|
|
45
|
+
const systemPtr = systemPtrRef.value
|
|
46
|
+
|
|
47
|
+
throwErrorIfFailed(resultCode, "Failed Pico initialization.")
|
|
48
|
+
|
|
49
|
+
picoext_setTraceLevel(systemPtr, 5)
|
|
50
|
+
|
|
51
|
+
async function loadResource(localFilePath: string) {
|
|
52
|
+
const virtualFilePath = "." + localFilePath.substring(localFilePath.lastIndexOf("/"))
|
|
53
|
+
|
|
54
|
+
const fileData = await readFile(localFilePath)
|
|
55
|
+
m.FS.writeFile(virtualFilePath, fileData)
|
|
56
|
+
|
|
57
|
+
const virtualFilePathRef = wasmMemory.allocNullTerminatedUtf8String(virtualFilePath)
|
|
58
|
+
const resourcePtrRef = wasmMemory.allocPointer()
|
|
59
|
+
|
|
60
|
+
resultCode = pico_loadResource(systemPtr, virtualFilePathRef.address, resourcePtrRef.address)
|
|
61
|
+
const resourcePtr = resourcePtrRef.value
|
|
62
|
+
|
|
63
|
+
throwErrorIfFailed(resultCode, `Failed loading Pico resource ${localFilePath}.`)
|
|
64
|
+
|
|
65
|
+
return { resourcePtr, resourcePtrRef }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { resourcePtr: textAnalysisResourcePtr, resourcePtrRef: textAnalysisResourcePtrRef } = await loadResource(textAnalysisFilePath)
|
|
69
|
+
const { resourcePtr: signalGenerationResourcePtr, resourcePtrRef: signalGenerationResourcePtrRef } = await loadResource(signalGenerationFilePath)
|
|
70
|
+
|
|
71
|
+
function getResourceName(resourcePtr: number) {
|
|
72
|
+
const resourceNameRef = wasmMemory.allocUint8Array(32)
|
|
73
|
+
resultCode = pico_getResourceName(systemPtr, resourcePtr, resourceNameRef.address)
|
|
74
|
+
|
|
75
|
+
throwErrorIfFailed(resultCode, `Failed getting Pico resource name.`)
|
|
76
|
+
|
|
77
|
+
const resourceName = resourceNameRef.readAsNullTerminatedUtf8String()
|
|
78
|
+
|
|
79
|
+
return { resourceName, resourceNameRef }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { resourceName: textAnalysisResourceName, resourceNameRef: textAnalysisResourceNameRef } = getResourceName(textAnalysisResourcePtr)
|
|
83
|
+
const { resourceName: signalGenerationResourceName, resourceNameRef: signalGenerationResourceNameRef } = getResourceName(signalGenerationResourcePtr)
|
|
84
|
+
|
|
85
|
+
const voiceNameRef = wasmMemory.allocNullTerminatedUtf8String("PicoVoice")
|
|
86
|
+
|
|
87
|
+
resultCode = pico_createVoiceDefinition(systemPtr, voiceNameRef.address)
|
|
88
|
+
|
|
89
|
+
function addResourceToVoiceDefinition(resourceNamePtr: number) {
|
|
90
|
+
resultCode = pico_addResourceToVoiceDefinition(systemPtr, voiceNameRef.address, resourceNamePtr)
|
|
91
|
+
|
|
92
|
+
throwErrorIfFailed(resultCode, `Failed adding resource to voice definition.`)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
addResourceToVoiceDefinition(textAnalysisResourceNameRef.address)
|
|
96
|
+
addResourceToVoiceDefinition(signalGenerationResourceNameRef.address)
|
|
97
|
+
|
|
98
|
+
const enginePtrRef = wasmMemory.allocPointer()
|
|
99
|
+
resultCode = pico_newEngine(systemPtr, voiceNameRef.address, enginePtrRef.address)
|
|
100
|
+
|
|
101
|
+
throwErrorIfFailed(resultCode, `Failed creating new engine.`)
|
|
102
|
+
|
|
103
|
+
const enginePtr = enginePtrRef.value
|
|
104
|
+
|
|
105
|
+
logger.start("Synthesize with pico")
|
|
106
|
+
|
|
107
|
+
const textRef = wasmMemory.allocNullTerminatedUtf8String(text)
|
|
108
|
+
|
|
109
|
+
const bytesWrittenRef = wasmMemory.allocInt32()
|
|
110
|
+
|
|
111
|
+
const audioParts: Buffer[] = []
|
|
112
|
+
|
|
113
|
+
for (let textByteOffset = 0; textByteOffset < textRef.length;) {
|
|
114
|
+
bytesWrittenRef.value = 0
|
|
115
|
+
resultCode = pico_putTextUtf8(enginePtr, textRef.address + textByteOffset, textRef.length - textByteOffset, bytesWrittenRef.address)
|
|
116
|
+
const bytesWritten = bytesWrittenRef.value
|
|
117
|
+
|
|
118
|
+
throwErrorIfFailed(resultCode, `Failed writing text to engine.`)
|
|
119
|
+
|
|
120
|
+
const audioPart = readAudioDataFromEngine()
|
|
121
|
+
audioParts.push(audioPart)
|
|
122
|
+
|
|
123
|
+
textByteOffset += bytesWritten
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const audioData = Buffer.concat(audioParts)
|
|
127
|
+
|
|
128
|
+
function readAudioDataFromEngine() {
|
|
129
|
+
const outBuffers: Buffer[] = []
|
|
130
|
+
|
|
131
|
+
const outBufferLength = 16384
|
|
132
|
+
const outBufferRef = wasmMemory.allocUint8Array(outBufferLength)
|
|
133
|
+
|
|
134
|
+
const outByteCountRef = wasmMemory.allocInt16()
|
|
135
|
+
const outDataTypeRef = wasmMemory.allocInt16()
|
|
136
|
+
|
|
137
|
+
while (true) {
|
|
138
|
+
resultCode = pico_getData(enginePtr, outBufferRef.address, outBufferRef.length, outByteCountRef.address, outDataTypeRef.address)
|
|
139
|
+
|
|
140
|
+
throwErrorIfFailed(resultCode, `Failed getting audio data from engine.`, [200, 201])
|
|
141
|
+
|
|
142
|
+
const outByteCount = outByteCountRef.value
|
|
143
|
+
const outDataType = outDataTypeRef.value
|
|
144
|
+
|
|
145
|
+
if (resultCode == 200) {
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (outByteCount > 0) {
|
|
150
|
+
outBuffers.push(Buffer.from(outBufferRef.slice(0, outByteCount)))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return Buffer.concat(outBuffers)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
dispose()
|
|
158
|
+
|
|
159
|
+
function dispose() {
|
|
160
|
+
if (!systemPtr) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (enginePtrRef) {
|
|
165
|
+
pico_disposeEngine(systemPtr, enginePtrRef.address)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (voiceNameRef) {
|
|
169
|
+
pico_releaseVoiceDefinition(systemPtr, voiceNameRef.address)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (textAnalysisResourcePtrRef) {
|
|
173
|
+
pico_unloadResource(systemPtr, textAnalysisResourcePtrRef.address)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (signalGenerationResourcePtrRef) {
|
|
177
|
+
pico_unloadResource(systemPtr, signalGenerationResourcePtrRef.address)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
pico_terminate(systemPtrRef.address)
|
|
181
|
+
|
|
182
|
+
wasmMemory.freeAll()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function throwErrorIfFailed(resultCode: number, title: string, successCodes = [0]) {
|
|
186
|
+
if (successCodes.includes(resultCode)) {
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const picoErrorMessageRef = wasmMemory.allocUint8Array(200)
|
|
191
|
+
pico_getSystemStatusMessage(systemPtr, resultCode, picoErrorMessageRef)
|
|
192
|
+
const picoErrorMessage = picoErrorMessageRef.readAsNullTerminatedUtf8String()
|
|
193
|
+
|
|
194
|
+
dispose()
|
|
195
|
+
throw new Error(`${title} ${picoErrorMessage}`)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const audioChannels = decodeToChannels(audioData, 1, 16, SampleFormat.PCM)
|
|
199
|
+
let rawAudio: RawAudio = { audioChannels, sampleRate: 16000 }
|
|
200
|
+
|
|
201
|
+
if (postprocessOutput) {
|
|
202
|
+
logger.start("Apply EQ to synthesized audio")
|
|
203
|
+
|
|
204
|
+
const Biquad = await import("../dsp/BiquadFilter.js")
|
|
205
|
+
|
|
206
|
+
Biquad.createLowshelfFilter(rawAudio.sampleRate, 177, -2.6).apply(rawAudio.audioChannels[0])
|
|
207
|
+
Biquad.createPeakingFilter(rawAudio.sampleRate, 440, bandwidthToQFactor(2), -9.7).apply(rawAudio.audioChannels[0])
|
|
208
|
+
//Biquad.createPeakingFilter(rawAudio.sampleRate, 1639, bandwidthToQFactor(2), 5.2).apply(rawAudio.audioChannels[0])
|
|
209
|
+
Biquad.createHighshelfFilter(rawAudio.sampleRate, 5180, 10.6).apply(rawAudio.audioChannels[0])
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
logger.end()
|
|
213
|
+
|
|
214
|
+
return { rawAudio }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export async function getInstance() {
|
|
218
|
+
if (!svoxPicoInstance) {
|
|
219
|
+
const { default: initializer } = await import('@echogarden/svoxpico-wasm')
|
|
220
|
+
|
|
221
|
+
svoxPicoInstance = await initializer()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return svoxPicoInstance
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function getResourceFilenamesForLanguage(language: string) {
|
|
228
|
+
let textAnalysisFilename: string
|
|
229
|
+
let signalGenerationFilename: string
|
|
230
|
+
|
|
231
|
+
switch (language) {
|
|
232
|
+
case "en-US":
|
|
233
|
+
case "en": {
|
|
234
|
+
textAnalysisFilename = "en-US_ta.bin"
|
|
235
|
+
signalGenerationFilename = "en-US_lh0_sg.bin"
|
|
236
|
+
break
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
case "en-GB": {
|
|
240
|
+
textAnalysisFilename = "en-GB_ta.bin"
|
|
241
|
+
signalGenerationFilename = "en-GB_kh0_sg.bin"
|
|
242
|
+
break
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
case "de-DE":
|
|
246
|
+
case "de": {
|
|
247
|
+
textAnalysisFilename = "de-DE_ta.bin"
|
|
248
|
+
signalGenerationFilename = "de-DE_gl0_sg.bin"
|
|
249
|
+
break
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
case "es-ES":
|
|
253
|
+
case "es": {
|
|
254
|
+
textAnalysisFilename = "es-ES_ta.bin"
|
|
255
|
+
signalGenerationFilename = "es-ES_zl0_sg.bin"
|
|
256
|
+
break
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
case "fr-FR":
|
|
260
|
+
case "fr": {
|
|
261
|
+
textAnalysisFilename = "fr-FR_ta.bin"
|
|
262
|
+
signalGenerationFilename = "fr-FR_nk0_sg.bin"
|
|
263
|
+
break
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
case "it-IT":
|
|
267
|
+
case "it": {
|
|
268
|
+
textAnalysisFilename = "it-IT_ta.bin"
|
|
269
|
+
signalGenerationFilename = "it-IT_cm0_sg.bin"
|
|
270
|
+
break
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
default: {
|
|
274
|
+
throw new Error(`Unsupported languge: ${language}`)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return { textAnalysisFilename, signalGenerationFilename }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const voiceList: SynthesisVoice[] = [
|
|
282
|
+
{
|
|
283
|
+
name: "en-US",
|
|
284
|
+
languages: ["en-US", "en"],
|
|
285
|
+
gender: "female",
|
|
286
|
+
packageName: "pico-en-US"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
name: "en-GB",
|
|
290
|
+
languages: ["en-GB", "en"],
|
|
291
|
+
gender: "female",
|
|
292
|
+
packageName: "pico-en-GB"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
name: "de-DE",
|
|
296
|
+
languages: ["de-DE", "de"],
|
|
297
|
+
gender: "female",
|
|
298
|
+
packageName: "pico-de-DE"
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: "es-ES",
|
|
302
|
+
languages: ["es-ES", "es"],
|
|
303
|
+
gender: "female",
|
|
304
|
+
packageName: "pico-es-ES"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: "fr-FR",
|
|
308
|
+
languages: ["fr-FR", "fr"],
|
|
309
|
+
gender: "female",
|
|
310
|
+
packageName: "pico-fr-FR"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: "it-IT",
|
|
314
|
+
languages: ["it-IT", "it"],
|
|
315
|
+
gender: "female",
|
|
316
|
+
packageName: "pico-it-IT"
|
|
317
|
+
},
|
|
318
|
+
]
|