Magpie-TTS Multilingual

NVIDIA Magpie-TTS Multilingual 357M en Swift sobre Apple Silicon: un modelo TTS autoregresivo multi-codebook sobre el Nano-Codec de 22.05 kHz de NeMo. Nueve idiomas (inglés, español, alemán, francés, italiano, vietnamita, hindi, mandarín, japonés) con cinco identidades de hablante preconfiguradas. Cuantizado a INT4 (~247 MB) o INT8 (~411 MB). Listo para streaming, ~120 ms de latencia del primer paquete.

Cuándo elegir Magpie

Magpie es la opción correcta cuando necesitas un único paquete pequeño que hable nueve idiomas con una voz consistente. Los cinco hablantes preconfigurados mantienen su identidad estable entre idiomas, útil para asistentes multilingües, apps educativas o narración de audiolibros con cambio de código. Para clonación de voz zero-shot usa CosyVoice3, Qwen3-TTS Base o VoxCPM2.

Arquitectura

Magpie es una pipeline MLX de 4 paquetes: codificador de texto → decodificador con cross-attention → cabezal de codebook LocalTransformer → códec de audio Causal HiFi-GAN. Los paquetes comparten pesos del decodificador entre los puntos de entrada de prefill y step para mantener compatibilidad con el layout CoreML de FluidInference upstream.

EtapaMóduloDetalles
1. TokenizaciónMagpieTokenizerG2P por idioma (diccionario IPA / bytes byT5 / pinyin / katakana), vocabulario compartido de 2360 tokens con offsets por tokenizador, EOS siempre añadido
2. Codificador de textoMagpieTextEncoder6 capas Transformer causales, d=768, FFN conv k=3
3. Decoder prefillMagpieDecoder12 capas causales con cross-attention. Inicializa la caché KV con el contexto de 110 frames del hablante preconfigurado + BOS.
4. LocalTransformerMagpieLocalTransformerCabezal AR de codebook de 1 capa, d=256. Muestrea los 8 codebooks por frame secuencialmente dado el hidden del decodificador.
5. Decoder stepMagpieDecoderUn paso AR por frame hasta EOS o el límite de 500 frames (~23 s).
6. NanoCodecMagpieNanoCodecInversa de FSQ → HiFi-GAN causal → forma de onda mono a 22.05 kHz.

Idiomas y G2P

Los nueve idiomas hacen round-trip a través de Qwen3-ASR en el testMultilingualRoundTrip del SDK. Cada uno tiene una pipeline adaptada:

IdiomaCódigoPipeline G2P
InglésenDiccionario CMU IPA (125 k entradas, incluido)
EspañolesDiccionario IPA español (incluido)
AlemándeDiccionario IPA alemán (incluido)
FrancésfrCodificador de bytes UTF-8 byT5
ItalianoitCodificador de bytes UTF-8 byT5
VietnamitaviCodificador de bytes UTF-8 byT5
HindihiBúsqueda de codepoint devanagari + sub-vocabulario last-wins
MandarínzhSegmentación de palabras NLTokenizer(.simplifiedChinese) + Apple .mandarinToLatin + diccionario pinyin → IPA incluido + marcadores de tono #N
JaponésjaLectura kanji con CFStringTokenizer + dakuten preservado por NFC + marcadores de tono heiban + overrides de partículas/saludos

El vocabulario compartido de 2360 tokens concatena cada sub-tokenizador con un offset por idioma (registrado en MagpieSubVocab). El text-embedding añade dos filas extra después del vocab para BOS/EOS; eos_id = 2361 se añade a cada secuencia de entrada.

Hablantes preconfigurados

El checkpoint embebe cinco contextos de hablante (110 frames × 768 dims cada uno) usados como prefijo de cada decodificación AR. La identidad del hablante es consistente en los nueve idiomas.

ÍndiceNombre CLIIdentidad
0sofiaSofia (por defecto)
1ariaAria
2jasonJason
3leoLeo
4johnJohn Van Stan

Variantes del modelo

VarianteDiscoRAM (carga + decode)HuggingFace
INT4 (por defecto)~247 MB~1.3 GBaufklarer/Magpie-TTS-Multilingual-357M-MLX-4bit
INT8~411 MB~1.6 GBaufklarer/Magpie-TTS-Multilingual-357M-MLX-8bit

Ambos paquetes usan cuantización flat affine de MLX (mlx_affine_flat, group size 64) y se descuantizan a FP32 al cargar — las activaciones en runtime son de precisión completa. INT4 e INT8 son indistinguibles auditivamente para este modelo; elige INT4 salvo que tengas espacio de sobra.

Uso de CLI

# Inglés, decodificación greedy
speech speak "Hello, world." --engine magpie --magpie-speaker aria \
    --magpie-temperature 0 -o out.wav

# Español (cualquiera de los 9 idiomas — elige con --language)
speech speak "Hola, mundo." --engine magpie --language es \
    --magpie-speaker aria -o out.wav

# Japonés — requiere decodificación estocástica (greedy se atasca en la primera frase)
speech speak "こんにちは世界、これは音声合成システムです。" \
    --engine magpie --language ja --magpie-temperature 0.6 \
    --magpie-top-k 80 --seed 42 -o out.wav

# Síntesis en streaming con reproducción
speech speak "Streaming test" --engine magpie --stream --play

# Listar los 5 hablantes preconfigurados
speech speak --engine magpie --list-speakers

# IPA pre-fonemizado omite el G2P por idioma
speech speak "həˈloʊ" --engine magpie --magpie-prephonemized -o out.wav

Opciones

OpciónPor defectoDescripción
--magpie-variantint4Variante de cuantización: int4 o int8
--magpie-speakersofiaHablante preconfigurado: sofia, aria, jason, leo, john
--magpie-temperature0.6Temperatura de muestreo (0 = greedy)
--magpie-top-k80Filtro top-k para muestreo
--magpie-max-frames500Tope duro de frames de códec (~23 s)
--magpie-min-frames4Frames mínimos antes de permitir EOS
--magpie-prephonemizedoffTrata la entrada como flujo IPA/fonema; omite el G2P por idioma
--languageenglishSelecciona el tokenizador por idioma
--streamoffEmite AsyncStream<AudioChunk> en vez de un único WAV
--seedMuestreo Gumbel reproducible
Consejo de muestreo japonés

Las entradas en japonés de más de una palabra necesitan decodificación estocástica (--magpie-temperature 0.6 --magpie-top-k 80 --seed 42 espeja el test de referencia de NeMo). Greedy se atasca en la primera frase porque la heurística de pitch heiban se desvía de la verdad por palabra.

Clonación de voz — no soportada

Magpie no tiene condicionamiento zero-shot de hablante en el modelo; solo las 5 identidades preconfiguradas están incluidas. La CLI rechaza los flags compartidos --voice-sample, --speaker e --instruct con un error accionable que apunta a --magpie-speaker o a los motores que sí soportan clonación (Qwen3-TTS Base, CosyVoice3, VoxCPM2).

Rendimiento (M4 Pro)

ConfiguraciónAudioTiempo realRTF
Batch, INT4, greedy, prompt corto2.8 s0.88 s0.32
Batch, INT4, greedy, oración5.8 s1.35 s0.23
Batch, INT4, sampled, salida 23 s23 s5.6 s0.24
Streaming, INT4, sampled23 s21.6 s0.93

La latencia del primer paquete en streaming es ≈120 ms tras cargar el modelo. El RTF en streaming es mayor porque el códec se re-invoca sobre el buffer de códigos completo en cada chunk (una versión futura puede cachear el estado del códec).

API de Swift

import MagpieTTS

let model = try await MagpieTTS.fromPretrained(variant: .int4)

// Síntesis batch (en/es/de/fr/it/vi/hi/zh — greedy funciona)
let audio = try model.synthesize(
    text: "Hello, world.",
    speaker: .aria,
    language: .english,
    params: MagpieTTSParams(temperature: 0, topK: 1, maxSteps: 500))

// Japonés — usa muestreo estocástico
let audioJA = try model.synthesize(
    text: "こんにちは世界、これは音声合成システムです。",
    speaker: .aria,
    language: .japanese,
    params: MagpieTTSParams(temperature: 0.6, topK: 80,
                              maxSteps: 300, seed: 42))

// Streaming (AsyncStream<AudioChunk>)
let stream = model.synthesizeStream(
    text: "Streaming text",
    speaker: .aria,
    language: .english,
    firstChunkFrames: 8,
    framesPerChunk: 25)
for try await chunk in stream {
    // chunk.samples es Float32 mono a 22.05 kHz
}

Backend CoreML (--engine magpie-coreml)

Junto al bundle MLX, Magpie envía un bundle CoreML (aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit, ~342 MB INT8). Cuatro paquetes .mlmodelctext_encoder, decoder_prefill, decoder_step, nanocodec_decoder — corren en ANE / GPU; un FSQ inverso en Swift convierte los códigos muestreados en los latentes de 32 dimensiones que consume el codec.

# 8 idiomas (sin japonés), 5 hablantes predefinidos
speech speak "Hello world." --engine magpie-coreml --magpie-speaker aria -o hi.wav
speech speak "Hola mundo." --engine magpie-coreml --language es --magpie-speaker leo -o es.wav

# --language ja redirige automáticamente al backend MLX (aviso en stderr)
speech speak "こんにちは" --engine magpie-coreml --language ja -o ja.wav

Salvedades respecto a --engine magpie:

El orden de hablantes coincide con el speaker_info.json del bundle CoreML (0=John, 1=Sofia, 2=Aria, 3=Jason, 4=Leo — diferente de MLX); el enum de hablantes mapea internamente para que los nombres CLI funcionen en ambos engines.

Notas de implementación

Tres bugs que vale la pena conocer al portar TTS multilingüe estilo NeMo:

Las tres correcciones están documentadas inline en el módulo Swift.

Fuente

Licencia