Magpie-TTS Multilingual

NVIDIA Magpie-TTS Multilingual 357M en Swift sur Apple Silicon — un modèle TTS auto-régressif multi-codebook sur le Nano-Codec 22.05 kHz de NeMo. Neuf langues (anglais, espagnol, allemand, français, italien, vietnamien, hindi, mandarin, japonais) avec cinq identités de voix prédéfinies. Quantifié en INT4 (~247 Mo) ou INT8 (~411 Mo). Streaming, latence du premier paquet ~120 ms.

Quand choisir Magpie

Magpie est le bon choix quand tu as besoin d'un seul petit bundle qui parle neuf langues avec une voix cohérente. Les cinq voix prédéfinies restent stables en identité d'une langue à l'autre — utile pour les assistants multilingues, les apps éducatives ou la narration de livres audio avec code-switching. Pour le clonage zero-shot utilise CosyVoice3, Qwen3-TTS Base ou VoxCPM2.

Architecture

Magpie est un pipeline MLX à 4 bundles : encodeur de texte → décodeur avec cross-attention → tête codebook LocalTransformer → codec audio Causal HiFi-GAN. Les bundles partagent les poids du décodeur entre les points d'entrée prefill et step pour rester compatibles avec le layout CoreML de FluidInference upstream.

ÉtapeModuleDétails
1. TokenisationMagpieTokenizerG2P par langue (dict IPA / bytes byT5 / pinyin / katakana), vocab partagé 2360 tokens + offsets par tokenizer, EOS toujours ajouté
2. Encodeur de texteMagpieTextEncoder6 couches Transformer causales, d=768, FFN conv k=3
3. Decoder prefillMagpieDecoder12 couches causales avec cross-attention. Amorce le cache KV avec le contexte 110 frames de la voix prédéfinie + BOS.
4. LocalTransformerMagpieLocalTransformerTête AR codebook 1 couche, d=256. Échantillonne les 8 codebooks par frame séquentiellement à partir du hidden décodeur.
5. Decoder stepMagpieDecoderUn pas AR par frame jusqu'à EOS ou la limite de 500 frames (~23 s).
6. NanoCodecMagpieNanoCodecInverse FSQ → HiFi-GAN causal → forme d'onde mono 22.05 kHz.

Langues et G2P

Les neuf langues font l'aller-retour à travers Qwen3-ASR dans le testMultilingualRoundTrip du SDK. Chacune a un pipeline adapté :

LangueCodePipeline G2P
AnglaisenDictionnaire CMU IPA (125k entrées, embarqué)
EspagnolesDictionnaire IPA espagnol (embarqué)
AllemanddeDictionnaire IPA allemand (embarqué)
FrançaisfrEncodeur de bytes UTF-8 byT5
ItalienitEncodeur de bytes UTF-8 byT5
VietnamienviEncodeur de bytes UTF-8 byT5
HindihiLookup de codepoint devanagari + sous-vocab last-wins
MandarinzhSegmentation de mots NLTokenizer(.simplifiedChinese) + Apple .mandarinToLatin + dictionnaire pinyin → IPA embarqué + marqueurs de ton #N
JaponaisjaLecture kanji via CFStringTokenizer + dakuten préservé par NFC + marqueurs de pitch heiban + overrides de particules/salutations

Le vocab partagé 2360 tokens concatène les sous-tokenizers de chaque langue avec un offset par langue (enregistré dans MagpieSubVocab). Le text-embedding ajoute deux lignes au-delà du vocab pour BOS/EOS ; eos_id = 2361 est ajouté à chaque séquence d'entrée.

Voix prédéfinies

Le checkpoint embarque cinq contextes de voix (110 frames × 768 dims chacun) utilisés en préfixe de chaque décodage AR. L'identité de la voix est cohérente sur les neuf langues.

IndexNom CLIIdentité
0sofiaSofia (par défaut)
1ariaAria
2jasonJason
3leoLeo
4johnJohn Van Stan

Variantes du modèle

VarianteDisqueRAM (chargement + decode)HuggingFace
INT4 (par défaut)~247 Mo~1.3 Goaufklarer/Magpie-TTS-Multilingual-357M-MLX-4bit
INT8~411 Mo~1.6 Goaufklarer/Magpie-TTS-Multilingual-357M-MLX-8bit

Les deux bundles utilisent la quantisation flat affine MLX (mlx_affine_flat, group size 64) et sont déquantifiés en FP32 au chargement — les activations runtime sont en pleine précision. INT4 et INT8 sont indistinguables à l'oreille pour ce modèle ; choisis INT4 sauf si tu as du stockage à revendre.

Utilisation CLI

# Anglais, décodage greedy
speech speak "Hello, world." --engine magpie --magpie-speaker aria \
    --magpie-temperature 0 -o out.wav

# Espagnol (l'une des 9 langues — choisi avec --language)
speech speak "Hola, mundo." --engine magpie --language es \
    --magpie-speaker aria -o out.wav

# Japonais — décodage stochastique requis (greedy se bloque sur la première phrase)
speech speak "こんにちは世界、これは音声合成システムです。" \
    --engine magpie --language ja --magpie-temperature 0.6 \
    --magpie-top-k 80 --seed 42 -o out.wav

# Synthèse en streaming avec lecture
speech speak "Streaming test" --engine magpie --stream --play

# Lister les 5 voix prédéfinies
speech speak --engine magpie --list-speakers

# IPA pré-phonémisé contourne le G2P par langue
speech speak "həˈloʊ" --engine magpie --magpie-prephonemized -o out.wav

Options

OptionDéfautDescription
--magpie-variantint4Variante de quantisation : int4 ou int8
--magpie-speakersofiaVoix prédéfinie : sofia, aria, jason, leo, john
--magpie-temperature0.6Température d'échantillonnage (0 = greedy)
--magpie-top-k80Filtre top-k pour l'échantillonnage
--magpie-max-frames500Plafond strict des frames codec (~23 s)
--magpie-min-frames4Frames minimum avant que l'EOS soit autorisé
--magpie-prephonemizedoffTraite l'entrée comme flux IPA/phonème ; contourne le G2P par langue
--languageenglishSélectionne le tokenizer par langue
--streamoffÉmet AsyncStream<AudioChunk> au lieu d'un seul WAV
--seedÉchantillonnage Gumbel reproductible
Astuce d'échantillonnage japonais

Les entrées japonaises plus longues qu'un mot nécessitent un décodage stochastique (--magpie-temperature 0.6 --magpie-top-k 80 --seed 42 reflète le test de référence NeMo). Greedy se bloque sur la première phrase parce que l'heuristique de pitch heiban dévie de la vérité mot à mot.

Clonage vocal — non pris en charge

Magpie n'a pas de conditionnement zero-shot du locuteur dans le modèle ; seules les 5 identités prédéfinies sont incluses. La CLI rejette les flags partagés --voice-sample, --speaker et --instruct avec une erreur actionnable qui pointe vers --magpie-speaker ou les engines qui supportent le clonage (Qwen3-TTS Base, CosyVoice3, VoxCPM2).

Performance (M4 Pro)

ConfigurationAudioTemps réelRTF
Batch, INT4, greedy, prompt court2.8 s0.88 s0.32
Batch, INT4, greedy, phrase5.8 s1.35 s0.23
Batch, INT4, sampled, sortie 23 s23 s5.6 s0.24
Streaming, INT4, sampled23 s21.6 s0.93

La latence du premier paquet en mode streaming est ≈120 ms après chargement du modèle. Le RTF de streaming est plus élevé parce que le codec est re-invoqué sur le buffer de codes complet à chaque chunk émis (une révision future peut cacher l'état du codec).

API Swift

import MagpieTTS

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

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

// Japonais — utiliser l'échantillonnage stochastique
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 est du Float32 mono 22.05 kHz
}

Backend CoreML (--engine magpie-coreml)

En plus du bundle MLX, Magpie livre un bundle CoreML (aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit, ~342 Mo INT8). Quatre paquets .mlmodelctext_encoder, decoder_prefill, decoder_step, nanocodec_decoder — tournent sur ANE / GPU ; un inverse FSQ côté Swift transforme les codes échantillonnés en latents 32 dimensions que le codec consomme.

# 8 langues (sans japonais), 5 voix prédéfinies
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 automatiquement vers le backend MLX (note stderr)
speech speak "こんにちは" --engine magpie-coreml --language ja -o ja.wav

Réserves par rapport à --engine magpie :

L'ordre des voix correspond au speaker_info.json du bundle CoreML (0=John, 1=Sofia, 2=Aria, 3=Jason, 4=Leo — différent de MLX) ; l'enum de voix mappe en interne pour que les noms CLI fonctionnent pour les deux moteurs.

Notes d'implémentation

Trois bugs à connaître lors du portage de TTS multilingue style NeMo :

Les trois corrections sont documentées inline dans le module Swift.

Source

Licence