Magpie-TTS Multilingual

NVIDIA Magpie-TTS Multilingual 357M em Swift no Apple Silicon — um modelo TTS autorregressivo multi-codebook sobre o Nano-Codec de 22.05 kHz da NeMo. Nove idiomas (inglês, espanhol, alemão, francês, italiano, vietnamita, hindi, mandarim, japonês) com cinco identidades de orador predefinidas. Quantizado em INT4 (~247 MB) ou INT8 (~411 MB). Pronto para streaming, latência do primeiro pacote ~120 ms.

Quando escolher Magpie

Magpie é a escolha certa quando precisas de um único bundle pequeno que fale nove idiomas com uma voz consistente. Os cinco oradores predefinidos mantêm a identidade estável entre idiomas — útil para assistentes multilíngues, apps educacionais ou narração de audiolivros com alternância de código. Para clonagem zero-shot usa CosyVoice3, Qwen3-TTS Base ou VoxCPM2.

Arquitetura

Magpie é uma pipeline MLX de 4 bundles: codificador de texto → decodificador com cross-attention → cabeça codebook LocalTransformer → codec de áudio Causal HiFi-GAN. Os bundles partilham pesos do decodificador entre os pontos de entrada prefill e step para manter compatibilidade com o layout CoreML do FluidInference upstream.

EtapaMóduloDetalhes
1. TokenizaçãoMagpieTokenizerG2P por idioma (dicionário IPA / bytes byT5 / pinyin / katakana), vocabulário partilhado de 2360 tokens + offsets por tokenizador, EOS sempre anexado
2. Codificador de textoMagpieTextEncoder6 camadas Transformer causais, d=768, FFN conv k=3
3. Decoder prefillMagpieDecoder12 camadas causais com cross-attention. Semeia a cache KV com o contexto de 110 frames do orador predefinido + BOS.
4. LocalTransformerMagpieLocalTransformerCabeça AR de codebook de 1 camada, d=256. Amostra os 8 codebooks por frame sequencialmente a partir do hidden do decodificador.
5. Decoder stepMagpieDecoderUm passo AR por frame até EOS ou o limite de 500 frames (~23 s).
6. NanoCodecMagpieNanoCodecInversa FSQ → HiFi-GAN causal → forma de onda mono a 22.05 kHz.

Idiomas e G2P

Os nove idiomas fazem ida-e-volta através do Qwen3-ASR no testMultilingualRoundTrip do SDK. Cada um tem uma pipeline adaptada:

IdiomaCódigoPipeline G2P
InglêsenDicionário CMU IPA (125k entradas, embutido)
EspanholesDicionário IPA espanhol (embutido)
AlemãodeDicionário IPA alemão (embutido)
FrancêsfrCodificador de bytes UTF-8 byT5
ItalianoitCodificador de bytes UTF-8 byT5
VietnamitaviCodificador de bytes UTF-8 byT5
HindihiLookup de codepoint devanagari + sub-vocab last-wins
MandarimzhSegmentação de palavras NLTokenizer(.simplifiedChinese) + Apple .mandarinToLatin + dicionário pinyin → IPA embutido + marcadores de tom #N
JaponêsjaLeitura kanji via CFStringTokenizer + dakuten preservado por NFC + marcadores de pitch heiban + overrides de partículas/saudações

O vocab partilhado de 2360 tokens concatena os sub-tokenizadores de cada idioma com um offset por idioma (registado em MagpieSubVocab). O text-embedding adiciona duas linhas extra após o vocab para BOS/EOS; eos_id = 2361 é anexado a cada sequência de entrada.

Oradores predefinidos

O checkpoint embute cinco contextos de orador (110 frames × 768 dims cada) usados como prefixo de cada decodificação AR. A identidade do orador é consistente nos nove idiomas.

ÍndiceNome CLIIdentidade
0sofiaSofia (padrão)
1ariaAria
2jasonJason
3leoLeo
4johnJohn Van Stan

Variantes do modelo

VarianteDiscoRAM (carregamento + decode)HuggingFace
INT4 (padrão)~247 MB~1.3 GBaufklarer/Magpie-TTS-Multilingual-357M-MLX-4bit
INT8~411 MB~1.6 GBaufklarer/Magpie-TTS-Multilingual-357M-MLX-8bit

Ambos os bundles usam quantização flat affine MLX (mlx_affine_flat, group size 64) e são dequantizados para FP32 no carregamento — as activações em runtime são de precisão total. INT4 e INT8 são indistinguíveis ao ouvido para este modelo; escolhe INT4 a menos que tenhas armazenamento de sobra.

Uso CLI

# Inglês, decodificação greedy
speech speak "Hello, world." --engine magpie --magpie-speaker aria \
    --magpie-temperature 0 -o out.wav

# Espanhol (qualquer um dos 9 idiomas — escolhe com --language)
speech speak "Hola, mundo." --engine magpie --language es \
    --magpie-speaker aria -o out.wav

# Japonês — precisa de decodificação estocástica (greedy fica preso na primeira frase)
speech speak "こんにちは世界、これは音声合成システムです。" \
    --engine magpie --language ja --magpie-temperature 0.6 \
    --magpie-top-k 80 --seed 42 -o out.wav

# Síntese streaming com reprodução
speech speak "Streaming test" --engine magpie --stream --play

# Listar os 5 oradores predefinidos
speech speak --engine magpie --list-speakers

# IPA pré-fonemizado ignora o G2P por idioma
speech speak "həˈloʊ" --engine magpie --magpie-prephonemized -o out.wav

Opções

OpçãoPadrãoDescrição
--magpie-variantint4Variante de quantização: int4 ou int8
--magpie-speakersofiaOrador predefinido: sofia, aria, jason, leo, john
--magpie-temperature0.6Temperatura de amostragem (0 = greedy)
--magpie-top-k80Filtro top-k para amostragem
--magpie-max-frames500Limite rígido de frames do codec (~23 s)
--magpie-min-frames4Frames mínimos antes de permitir EOS
--magpie-prephonemizedoffTrata a entrada como fluxo IPA/fonema; ignora o G2P por idioma
--languageenglishSeleciona o tokenizador por idioma
--streamoffEmite AsyncStream<AudioChunk> em vez de um único WAV
--seedAmostragem Gumbel reproduzível
Dica de amostragem japonesa

Entradas japonesas com mais de uma palavra precisam de decodificação estocástica (--magpie-temperature 0.6 --magpie-top-k 80 --seed 42 espelha o teste de referência da NeMo). Greedy fica preso na primeira frase porque a heurística de pitch heiban desvia-se da verdade por palavra.

Clonagem de voz — não suportada

Magpie não tem condicionamento zero-shot de orador no modelo; apenas as 5 identidades predefinidas estão incluídas no bundle. A CLI rejeita os flags partilhados --voice-sample, --speaker e --instruct com um erro acionável que aponta para --magpie-speaker ou para os engines que suportam clonagem (Qwen3-TTS Base, CosyVoice3, VoxCPM2).

Desempenho (M4 Pro)

ConfiguraçãoÁudioTempo realRTF
Batch, INT4, greedy, prompt curto2.8 s0.88 s0.32
Batch, INT4, greedy, frase5.8 s1.35 s0.23
Batch, INT4, sampled, saída 23 s23 s5.6 s0.24
Streaming, INT4, sampled23 s21.6 s0.93

A latência do primeiro pacote em streaming é ≈120 ms após carregar o modelo. O RTF de streaming é maior porque o codec é re-invocado sobre o buffer completo de códigos a cada chunk emitido (uma revisão futura pode cachear o estado do codec).

API Swift

import MagpieTTS

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

// Síntese 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 — usar amostragem estocástica
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 é Float32 mono a 22.05 kHz
}

Backend CoreML (--engine magpie-coreml)

Junto com o bundle MLX, o Magpie envia um bundle CoreML (aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit, ~342 MB INT8). Quatro pacotes .mlmodelctext_encoder, decoder_prefill, decoder_step, nanocodec_decoder — rodam em ANE / GPU; uma FSQ inversa em Swift transforma os códigos amostrados nos latentes de 32 dimensões que o codec consome.

# 8 idiomas (sem japonês), 5 oradores 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 roteia automaticamente para o backend MLX (aviso em stderr)
speech speak "こんにちは" --engine magpie-coreml --language ja -o ja.wav

Ressalvas vs. --engine magpie:

A ordem dos oradores corresponde ao speaker_info.json do bundle CoreML (0=John, 1=Sofia, 2=Aria, 3=Jason, 4=Leo — diferente do MLX); o enum de oradores mapeia internamente para que os nomes CLI funcionem nos dois engines.

Notas de implementação

Três bugs a conhecer ao portar TTS multilíngue estilo NeMo:

As três correções estão documentadas inline no módulo Swift.

Fonte

Licença