Skip to content

Repository files navigation

zonos2.cpp

ZONOS2


zonos2.cpp is a standalone ggml/GGUF C++ port of ZONOS2, Zyphra's ~7.6B-param MoE text-to-speech model. The entire pipeline — ECAPA-TDNN speaker encoder, the MoE language-model backbone, and the DAC-44kHz vocoder — runs as native C++ linking only libggml + gguf. No Python, no PyTorch, no CUDA-only kernels at inference time. It runs on CPU, CUDA, Apple Metal, and Vulkan from the same GGUF files, in real time on GPU, and quantizes down to 4.9 GB (Q4_K) with audio quality within eval noise of F16.

An inference overview can be seen below.

ZONOS2 inference overview

zonos2.cpp ships a high-performance HTTP server (zonos2-server) that mirrors the reference FastAPI server — low-latency streaming PCM, an OpenAI-compatible /v1/audio/speech route, in-process voice cloning, and a browser UI — plus a CLI (zonos2-cli) for offline synthesis. Every stage is numerically validated against the PyTorch reference — the speaker encoder and DAC decoder bit-exact, the backbone to cosine ≥ 0.9999.

For more details and speech samples, check out the blog.

A hosted version is available at cloud.zyphra.com/audio-playground.


Quick Start

Platform Support: Linux x64 (CPU / Vulkan), macOS arm64 (Metal), and Windows x64 (Vulkan) ship prebuilt. For CUDA (sm_90 / H100 by default), build from source.

1. Download & extract

Grab the archive for your OS from the Releases page (a .tar.gz, or a .zip on Windows — extract it anywhere). Each archive is self-contained: the start-zonos2 launcher, zonos2-server + the web/ UI, and the zonos2-cli / spk-encoder-cli / dac-cli / quantize-cli tools — no installer, no shared libraries.

First run on macOS / Windows: the release binaries are unsigned (built by CI, with no code-signing certificate), so the OS may block them the first time you run one. This is expected — the warning is about the missing signature, not the binary. Building from source avoids it entirely.

Clearing the OS security warning on the prebuilt binaries
  • macOS (Gatekeeper) — you'll see "…cannot be opened because the developer cannot be verified" (or "Apple could not verify … is free of malware" on Sequoia). macOS flags every file in a downloaded archive with a quarantine attribute — including start-zonos2.command; strip it from the folder you extracted into, then run the tools normally:

    xattr -dr com.apple.quarantine /path/to/extracted-folder

    Alternatively, after the first blocked launch, allow it via System Settings → Privacy & Security → Open Anyway (or right-click the .commandOpen). If the double-click stays blocked, run it from a terminal instead: bash start-zonos2.command.

  • Windows (SmartScreen / Defender)"Windows protected your PC" appears the first time you launch start-zonos2.bat or one of the .exes. Click More info → Run anyway. To clear the block before extracting, unblock the downloaded archive (right-click → Properties → Unblock → OK, or in PowerShell):

    Unblock-File .\zonos2-windows-x64-vulkan.zip

    If Microsoft Defender quarantines the unrecognized .exe, restore it from Protection History or add a Defender exclusion for the folder. On enterprise machines where PowerShell scripts are locked down entirely, launch the server by hand instead — see Manual & advanced setup.

  • Linux — no signing prompt. If a binary won't start, it usually just needs the execute bit:

    chmod +x start-zonos2.sh zonos2-cli zonos2-server

2. Run the start script

OS Do this
Linux ./start-zonos2.sh
macOS double-click start-zonos2.command (or ./start-zonos2.sh)
Windows double-click start-zonos2.bat

The first run downloads the models (~7.1 GB — the Q6_K backbone plus the DAC vocoder and speaker encoder) into models/ next to the script; downloads resume if interrupted. It then launches zonos2-server and opens the web UI at http://127.0.0.1:1919/. Later runs skip straight to launch. The Vulkan/Metal archives default to GPU, the CPU archive to CPU. Close the window (or Ctrl-C) to stop the server.

For voice cloning, a static ffmpeg (used only to decode your reference audio — plain TTS never needs it) is fetched into models/bin/ on first run unless one is already on your PATH. Linux/Windows use the BtbN LGPL build; macOS uses a pinned static arm64 build (GPL — nothing is redistributed here, your machine downloads it from the provider, and it runs as a separate process). The desktop app fetches its own copy the same way. Set ZONOS2_FFMPEG=/path/to/ffmpeg to point at your own instead.

Common knobs (./start-zonos2.sh --help / start-zonos2.bat -Help lists everything):

Linux/macOS Windows
Backbone quant (q4_k 4.9 GB · q5_k 5.8 GB · q6_k 6.8 GB · q8_0 8.5 GB · f16 15.3 GB) --quant q4_k -Quant q4_k
Force backend --cpu / --gpu -Cpu / -Gpu
Port --port 8080 -Port 8080
Skip download prompt / browser -y, --no-browser -Yes, -NoBrowser
Extra zonos2-server flags -- --batch 16 appended verbatim

Large model files download over several parallel connections (~2× faster than a single stream on Hugging Face); tune with ZONOS2_DL_CONNECTIONS (default 8). Model dir, download URL, and more can be overridden via ZONOS2_* environment variables (see --help). Prefer to launch the server by hand, or want CUDA? See Manual & advanced setup.

3. Generate Speech

curl:

# stream raw float32 PCM @ 44.1 kHz
curl -X POST http://localhost:1919/tts/generate \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello world", "stream": true, "seed": 1}' \
  --output output.pcm

# convert to WAV
ffmpeg -f f32le -ar 44100 -ac 1 -i output.pcm output.wav

# or get a buffered WAV directly
curl -s http://localhost:1919/tts/generate \
  -d '{"text":"Hi.","stream":false,"format":"wav","seed":1}' -o out.wav

Web UI: Open http://localhost:1919/ in your browser.

Desktop App (zonos2-app)

The same server and web UI, packaged as a native window (a saucer webview: WebView2 / WKWebView / WebKitGTK). First launch opens a setup page: pick a model quality and click Download & Launch and it fetches the model files for you (into ~/.config/zonos2/models, or the platform equivalent) — same one-click path as the launcher scripts, no terminal needed. If you already have the .gguf files, "I already have the model files" reveals native file pickers instead. The choice is saved (~/.config/zonos2/app.json, or the platform equivalent) and later launches boot straight into the UI. The embedded server binds an ephemeral 127.0.0.1 port and its whole HTTP API stays reachable while the app runs; closing the window shuts it down. Release tags ship prebuilt bundles: zonos2-linux-x64-app.tar.gz, zonos2-macos-arm64-app.zip (a Zonos2.app), and zonos2-app.exe inside the Windows zonos2-windows-x64-vulkan.zip.

Building it is opt-in — saucer needs a much newer toolchain than the rest of the project (CMake ≥ 3.31 and a C++23 compiler: GCC ≥ 14 / Clang ≥ 20 / Xcode ≥ 16.3 / MSVC ≥ 19.44):

# Linux additionally needs: libgtk-4-dev (>= 4.12, i.e. Ubuntu 24.04+), libwebkitgtk-6.0-dev,
# libadwaita-1-dev, libjson-glib-dev
cmake -B build -DZONOS2_APP=ON
cmake --build build --target zonos2-app

./build/zonos2-app                 # setup page on first run, saved config afterwards
./build/zonos2-app --setup         # reopen the setup page
./build/zonos2-app out/zonos2-q8_0.gguf --dac out/dac.gguf --gpu   # or pass zonos2-server args through

Emotion Control

Emotion control nudges a cloned speaker voice with shipped direction vectors: named sliders (happy, sad, angry, surprised) plus valence and arousal axes. It requires a speaker embedding from an uploaded/cached voice or CLI --speaker / --clone.

curl -X POST http://localhost:1919/tts/generate \
  -H "Content-Type: application/json" \
  -d '{
        "text": "I cannot believe you did that!",
        "speaker_embedding_id": "spk_...",
        "emotion_enabled": true,
        "emotion_sliders": {"happy": 1.0},
        "accurate_mode": false,
        "emotion_cfg_scale": 1.5,
        "stream": true
      }' \
  --output happy.pcm

GET /tts/capabilities reports emotion_enabled, emotion_names, emotion_axes, and emotion_calibrated. emotion_strength is a multiplier on the loaded calibration when calibration.json is present.

CLI (offline inference)

You can also synthesize directly from the command line, without starting a server. One command turns text into a 44.1 kHz WAV:

zonos2-cli out/zonos2-q8_0.gguf --tts "Hello, world." out.wav \
    --dac out/dac.gguf --gpu --seed 1

Clone a voice in-process by pointing --clone at any reference audio. The standalone zonos2-cli resolves ffmpeg from $ZONOS2_FFMPEG, then next to the binary, then PATH (unlike the start script / desktop app, it does not auto-download one — install ffmpeg or point ZONOS2_FFMPEG at one):

zonos2-cli out/zonos2-q8_0.gguf --tts "Cloned voice demo." out.wav \
    --dac out/dac.gguf --clone voice.mp3 --spk-encoder out/spk-encoder.gguf --gpu --seed 1

CLI emotion example:

zonos2-cli out/zonos2-q8_0.gguf --tts "That was incredible." out.wav \
    --dac out/dac.gguf --speaker voice.npy --emotion happy=1 \
    --emotion-strength 1 --emotion-cfg-scale 1.5 --gpu --seed 1

When dac.gguf / spk-encoder.gguf sit next to the backbone GGUF (as the start script arranges in models/), --dac and --spk-encoder are found automatically and can be dropped:

zonos2-cli models/zonos2-q6_k.gguf --tts "Hello, world." out.wav --gpu --seed 1

Manual & advanced setup

Download models by hand

The launcher just fetches from Zyphra/ZONOS2-GGUF; you can do the same with the HF CLI (or plain curl):

hf download Zyphra/ZONOS2-GGUF dac.gguf spk-encoder.gguf --local-dir out
# pick a backbone: Q8_0 is effectively lossless, Q4_K is the smallest that holds quality
hf download Zyphra/ZONOS2-GGUF zonos2-q8_0.gguf --local-dir out   # 8.5 GB
hf download Zyphra/ZONOS2-GGUF zonos2-q4_k.gguf --local-dir out   # 4.9 GB

(You can also convert the original checkpoints and make any quant yourself — see docs/INTERNALS.md.)

Launch the server by hand

zonos2-server out/zonos2-q8_0.gguf --dac out/dac.gguf --spk out/spk-encoder.gguf \
    --host 0.0.0.0 --port 1919 --gpu --tts-default-voices-dir default_voices

The server starts on http://localhost:1919 by default. It loads the backbone + DAC (+ speaker encoder) once and serves the reference TTS API: streaming float32 PCM, the OpenAI-compatible /v1/audio/speech route, audio-upload voice cloning, cached/default speakers, and SLERP speaker blending. --spk (alias --spk-encoder) enables cloning from uploaded reference audio and default voice audio files; drop --gpu for CPU. As with the CLI, --dac/--spk are auto-detected when the GGUFs sit next to the backbone. Emotion direction files in ./emotion_directions/ are autoloaded when present; use --tts-emotion-directions-dir <dir> to point elsewhere or pass an empty directory string to disable emotion controls. Default voices are scanned from default_voices/ by default; use --tts-default-voices-dir <dir> to point elsewhere or pass an empty string to disable them. zonos2-server with no arguments prints all options (--host, --batch, streaming knobs, …).

Text normalization is available through the reference NeMo/Pynini helper when launched with a Python environment that has pynini installed:

zonos2-server out/zonos2-q8_0.gguf --dac out/dac.gguf --spk out/spk-encoder.gguf \
    --gpu --text-normalizer-python .venv-tts-norm/bin/python

Without --text-normalizer-python, the server keeps the pure byte-level tokenizer path and reports text_normalization_enabled:false.

Build from source

git clone --recurse-submodules https://github.com/Zyphra/zonos2.cpp.git && cd zonos2.cpp

# CPU
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j

# CUDA (H100 = sm_90; pass -DCMAKE_CUDA_ARCHITECTURES=<n> for other GPUs)
cmake -B build-cuda -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build-cuda -j

Vulkan and Metal build the same way (-DGGML_VULKAN=ON; Metal is on by default on macOS).

Under the Hood

zonos2.cpp is a faithful, numerically-validated port. For the full conversion flow, the quantization ladder (F16 spine + K-quant experts, with WER / SpkSim / UTMOS evals), performance (H100 and Apple Silicon), the validation harness, and the architecture spec, see docs/INTERNALS.md.

Credits

  • ggml — the tensor library / GGUF format.
  • Zyphra/ZONOS2 — the original model and PyTorch reference this port mirrors and is validated against.
  • Descript Audio Codec — the DAC vocoder.

Citation

If you find this model useful in an academic context please cite as:

@misc{zyphra2025zonos,
  title     = {Zonos V2 Technical Report},
  author    = {Gabriel Clark, Sofian Mejjoute, Mohamed Osman, George Close, Beren Millidge},
  year      = {2026},
}

About

ggml inference code for ZONOS2

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages