Instructions to use franckverrot/vovo with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use franckverrot/vovo with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir vovo franckverrot/vovo
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Vovo
An English text-to-speech model built from scratch in Swift with hand-written Metal kernels — its own tensor engine, autograd, optimizer, data pipeline and trainer, no PyTorch anywhere. It was trained on one M2 Max.
Vovo2-21M is the current version: 110 voices, steerable prosody, 20.7 M parameters.
Which one to take
Both live in this repo, at different revisions. Same architecture, same size, different training data — and Vovo2 is not strictly better.
Vovo2-21M (main) |
Vovo1.5-21M | Vovo1-20M | |
|---|---|---|---|
| voices | 110 | 1 | 1 |
| word error rate | 10.0 % | 3.7 % | 2.1 % |
| pitch error | 107 cents | 74 cents | — (no pitch control) |
| prosody knobs + SSML | yes | yes | no |
| revision | vovo2-21m |
vovo1.5-21m |
vovo1-20m |
Take Vovo2 to choose a voice, an accent or a pitch range. Take Vovo1.5 if you want one voice and the cleanest speech — 21 M parameters split across 110 voices leave less for any single one, and the word error rate says so.
Use
pip install vovo-mlx
vovo-mlx voices # all 110, with each voice's pitch
vovo-mlx say "The quick brown fox." --speaker p226 -o fox.wav
from vovo_mlx import VovoTTS, SAMPLE_RATE
from vovo_mlx.audio import write_wav
tts = VovoTTS.from_pretrained("franckverrot/vovo") # Vovo2, 110 voices
write_wav("a.wav", tts.say("Hello.", speaker="p226"), SAMPLE_RATE)
write_wav("b.wav", tts.say("Hello.", speaker="ljspeech", pitch_shift=2), SAMPLE_RATE)
one_voice = VovoTTS.from_pretrained("franckverrot/vovo", revision="vovo1.5-21m")
Delivery is steerable per utterance (pitch_shift in semitones, pitch_scale for range, energy_shift in
dB) or per word with SSML — <prosody>, <emphasis>, <break>, <sub> — which is detected automatically:
tts.say('<speak>I said <emphasis level="strong">red</emphasis>,'
'<break time="700ms"/>not <prosody pitch="+4st">blue</prosody>.</speak>')
Swift is the reference implementation: vovo-core. The Python/MLX port (vovo-mlx) matches it numerically.
Files
| file | what |
|---|---|
model.safetensors |
acoustic model, EMA weights, config in the safetensors metadata |
vocoder.safetensors |
Vocos mel-24kHz, fine-tuned on Vovo's own predicted mels (PyTorch key layout) |
vocoder_base.safetensors |
the unmodified Vocos weights, for comparison |
Mel convention: 24 kHz, n_fft 1024, hop 256, 100 HTK mel bands, log(clamp(x, 1e-7)).
How it works
Text → normalizer → lexicon G2P → 67 phone symbols → conv prenet and a 6-layer RoPE transformer (d=192) → a per-phone mel prior and log-durations → length regulation → a 6-layer flow-matching DiT decoder (d=384, adaLN-zero) sampled in 16 Euler steps with classifier-free guidance → Vocos. Alignment is learned during training by monotonic alignment search, so no hand-labelled durations. A variance adaptor predicts pitch and energy per phone, which is what the prosody controls steer, and a mel-domain discriminator sharpens the decoder's output where the flow-matching loss would otherwise settle for a blurry average.
How it was trained
Not in one sitting. Each version starts from the previous one's weights, so the cost accumulates:
| what changed | steps | time |
|---|---|---|
| one voice, long run | 30,000 | 63 min |
| a discriminator on the decoder | 4,000 | 18 min |
| 109 more voices added to the mix | 30,000 | 60 min |
| the original voice weighted back up | 8,000 | 37 min |
| total | 72,000 | ≈ 3 hours |
The first release of this model trained in thirteen minutes; that is long behind us. The interesting part is which hour bought what: the extra voices produced the single biggest gain in pitch accuracy, cutting the error by a third, after further training on one voice alone had stopped helping. More data, not more steps.
Limitations
English only, no streaming. Out-of-vocabulary words are spelled by rule, so unusual names come out odd. Pitch is predicted from text alone, so the model guesses a reading — the prosody controls exist for when it guesses wrong. Intelligible, not studio-clean.
License
MIT (code and weights). Lexicon: ipa-dict (MIT). Vocoder derived from Vocos (MIT). Data: LJSpeech (public domain) and VCTK (CC-BY-4.0).
Quantized