magpie-tts.cpp

July 24, 2026 ยท View on GitHub

Brought to you by the LocalAI team, the folks behind LocalAI, the open-source AI engine that runs any model (LLMs, vision, voice, image, video) on any hardware, no GPU required.

Model on Hugging Face License LocalAI

A from-scratch C++17/ggml port of NVIDIA's Magpie TTS Multilingual 357M text-to-speech model, including its NanoCodec neural audio codec. One self-contained GGUF file (model, codec, tokenizer, G2P dictionaries), no Python, PyTorch, NeMo, or CUDA toolkit at inference. Numerically parity-gated against NeMo per component, and orders of magnitude faster than the NeMo reference pipeline on CPU.

magpie-tts.cpp vs NeMo on CPU: same text, ggml finishes first

The same sentence, side by side: equivalent speech, magpie-tts.cpp gets there first (full clip).

You get 22.05 kHz mono speech in 5 voices (Aria, Jason, John, Leo, Sofia) across 9 languages today (en, es, de, fr, it, pt-BR, hi, vi, ko, plus 3 Arabic variants), from a CLI, a C++ library, or a flat C API loadable via dlopen/FFI from Go, Rust, or anything else.

What it does

  • Text to speech: encoder + autoregressive decoder over NanoCodec tokens, with classifier-free guidance, inference-time attention prior, local transformer codebook refinement, and the NanoCodec decoder to PCM, all in ggml graphs.
  • Tokenization in C++: the full NeMo aggregated tokenizer replicated, IPA G2P with the dictionaries embedded in the GGUF (en, es, de, pt-BR, hi), byte-level for fr/it/vi/ko, Arabic character sets. Mandarin and Japanese are not supported yet (they need jieba/pyopenjtalk segmentation).
  • Deterministic sampling: seeded top-k/temperature sampling; same seed, same audio.

Supported models

ModelTaskSize (f32 / q8_0 / q4_k)ParitySource
magpie_tts_multilingual_357mTTS, 9+ languages, 5 voices1294 / 624 / 541 MBteacher-forced logit replay max abs diff 3.6e-5 vs NeMo; ASR round-trip exact on all quantsnvidia/magpie_tts_multilingual_357m

The GGUF also embeds the NanoCodec decoder (bit-exact FSQ, waveform max abs diff 3.3e-6 vs NeMo).

Performance

Measured on a Ryzen 9 9950X3D, CPU only. The NeMo reference pipeline (as shipped, no decoder KV cache) needs about 17 s per decoder step on the same machine; magpie-tts.cpp runs the same step KV-cached in tens of milliseconds.

EngineLoadAR decodeCodecTotalAudioTime per audio second
NeMo reference (PyTorch CPU, f32)101.9 s~17 s/step(incl.)805.7 s4.23 s190.5 s
magpie-tts.cpp f320.32 s103 ms/step6.8 s12.1 s3.99 s3.0 s (63x faster)
magpie-tts.cpp q8_00.16 s65 ms/step6.8 s9.5 s3.67 s2.6 s (73x faster)

Medians over 3 runs of magpie-cli bench, same sentence, seed 1234.

Honest notes: the largest single factor is that the NeMo reference recomputes the whole sequence every decoder step while this port uses a KV cache (an approximation NeMo ships support for but leaves off in this checkpoint's config -- measured use_kv_cache_for_inference = False on both CPU and GPU); the remaining gap comes from ggml graphs, f32 im2col paths, and no framework overhead. Quantized variants decode roughly 1.6 to 1.8 times faster than f32. See benchmarks/BENCHMARK.md for methodology and full numbers.

See it run

./build/examples/cli/magpie-cli say \
  --model models/magpie-tts-multilingual-357m-q8_0.gguf \
  --text "Hello world, this is a test of the text to speech system." \
  --lang en --speaker Aria --seed 1234 --output hello.wav

Build

git clone --recursive https://github.com/mudler/magpie-tts.cpp
cd magpie-tts.cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j

CMake options

OptionDefaultMeaning
MAGPIE_BUILD_CLIONbuild magpie-cli
MAGPIE_BUILD_TESTSONbuild parity tests
MAGPIE_SHAREDOFFbuild libmagpie-tts.so (for LocalAI / FFI)
MAGPIE_GGML_CUDA / METAL / VULKAN / HIPOFFggml GPU backends

GPU

Build with -DMAGPIE_GGML_CUDA=ON and select the device at runtime with the MAGPIE_DEVICE environment variable: unset or cpu keeps the CPU path (default, byte-identical to a CPU-only build), cuda/gpu/auto picks the first GPU in the ggml registry, or pass an explicit registry name like CUDA0. Weights, KV cache and every graph then live on the device; ops the backend does not support fall back to CPU per graph (logged, none on CUDA). GPU numbers in benchmarks/BENCHMARK.md.

MAGPIE_DEVICE=cuda ./build/examples/cli/magpie-cli say --model ... --text "..."

Get the model

Prebuilt GGUFs: huggingface.co/mudler/magpie-tts.cpp-gguf (f32, f16, q8_0, q6_k, q5_k, q4_k).

To convert from the original checkpoints yourself, see docs/conversion.md.

Quantization

Selective, allowlist-driven: only weights consumed by ggml_mul_mat are quantized; everything the engine reads as raw floats (norms, position embeddings, baked speaker context, codec convolutions, codebook embeddings) stays f32. All six variants pass an ASR round-trip check (a parakeet.cpp transcription of the generated audio matches the input text exactly). Details and drift numbers in docs/quantization.md.

.venv/bin/python scripts/quantize_gguf.py \
  models/magpie-tts-multilingual-357m-f32.gguf q8_0

CLI

magpie-cli info  --model <model.gguf>
magpie-cli say   --model <model.gguf> --text "..." [--lang en] [--speaker Aria|0] [--seed N] [--output out.wav] [--threads N]
magpie-cli bench --model <model.gguf> [--runs 3] [--json]

Speakers: Aria, Jason, John, Leo, Sofia (or indices 0 to 4). Languages: en, es, de, fr, it, pt-BR, hi, vi, ko, ar-AE, ar-SA, ar-MSA.

Library / C API

C++: include/magpie_tts.h (magpie_tts_load, magpie_tts_synthesize, options for language, speaker, temperature, top-k, CFG scale, seed).

C ABI for dlopen/purego/FFI: include/magpie_tts_capi.h

magpie_tts_ctx *ctx = magpie_tts_capi_load("model.gguf");
int n = 0;
float *pcm = magpie_tts_capi_synthesize(ctx, "Hello!", "en", 0, &n);
/* 22050 Hz mono f32; on error: NULL, see magpie_tts_capi_last_error(ctx) */
magpie_tts_capi_free_audio(pcm);
magpie_tts_capi_free(ctx);

Exceptions never cross the boundary; magpie_tts_capi_abi_version() gates compatibility.

Use it from LocalAI

A LocalAI backend is planned; the shared-library build (-DMAGPIE_SHARED=ON, ggml statically linked) is the artifact LocalAI loads via purego. Watch the LocalAI repo for the gallery entry.

Verification / Parity

Every component is gated numerically against tensors dumped from the reference NeMo implementation (see docs/architecture-magpietts.md and tests/):

GateResult
Tokenizer (9 languages)exact ids; 540/540 randomized sentences match NeMo
Text encodermax abs diff 2.9e-6
Decoder step (CFG, cross-attn, prior)logits 1.2e-5; priors and attended positions bitwise
Local transformer (16 heads)rel err about 3e-6
NanoCodec FSQbit-exact
NanoCodec decoderwaveform max abs diff 3.3e-6
Full 42-step decode loop (teacher-forced replay)logits max abs diff 3.6e-5

Run them yourself: MAGPIE_MODEL=<f32.gguf> MAGPIE_REF_DUMP=<dump.gguf> ctest --test-dir build.

Why magpie-tts.cpp

  • One file, no runtime dependencies: model + codec + tokenizer + G2P dictionaries in a single GGUF.
  • Proven numerics, not vibes: per-component parity gates against the reference, honest quantization notes.
  • Small and portable: 541 MB at q4_k, CPU-first, any ggml backend.
  • Embeddable: static or shared library, flat C ABI, deterministic output.

Credit where due: the model and codec are by NVIDIA (NeMo team), released under the NVIDIA Open Model License. This repo is an independent inference implementation; the GGUF weights keep NVIDIA's license.

Citation

@software{magpie_tts_cpp,
  title  = {magpie-tts.cpp: a C++/ggml inference engine for Magpie TTS},
  author = {Di Giacinto, Ettore},
  url    = {https://github.com/mudler/magpie-tts.cpp},
  year   = {2026}
}

Author

Ettore Di Giacinto (@mudler)

License

MIT (see LICENSE). Model weights: NVIDIA Open Model License.


Built by the LocalAI team. If you want to run text to speech (and LLMs, vision, voice, image, and video models) locally on any hardware with an OpenAI-compatible API, give LocalAI a star.