Skip to content

Commit 419a82c

Browse files
committed
Add Kokoro and Qwen3 TTS backends
1 parent 8514d54 commit 419a82c

16 files changed

Lines changed: 1519 additions & 45 deletions

README.md

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Vox.cpp
22

3-
Local voice-to-voice experiments in C++. ASR can run through either the existing `whisper.cpp` path or a llama.cpp/libmtmd Qwen3-ASR path; translation uses `llama.cpp`; TTS can synthesize translated text with a native CosyVoice3 GGUF runtime.
3+
Local voice-to-voice experiments in C++. ASR can run through either the existing `whisper.cpp` path or a llama.cpp/libmtmd Qwen3-ASR path; translation uses `llama.cpp`; TTS can synthesize translated text with native CosyVoice3, Kokoro, or Qwen3-TTS GGUF runtimes.
44

55
## Current Target
66

7-
`asr/` contains streaming ASR components that accept mono float32 PCM at 16 kHz. `StreamingQwenAsr` is the default ASR path and drives Qwen3-ASR GGUF models through llama.cpp `libmtmd`; `StreamingWhisper` keeps the existing Whisper fallback path. `translate/` is a llama.cpp translation component for GGUF translation models. `tts/` links the CosyVoice3 GGUF runtime from the CrispASR submodule in-process. `apps/vox.cpp` is the main program entry; it captures microphone audio, feeds ASR, optionally translates transcripts, and can synthesize translated text to wav files.
7+
`asr/` contains streaming ASR components that accept mono float32 PCM at 16 kHz. `StreamingQwenAsr` is the default ASR path and drives Qwen3-ASR GGUF models through llama.cpp `libmtmd`; `StreamingWhisper` keeps the existing Whisper fallback path. `translate/` is a llama.cpp translation component for GGUF translation models. `tts/` links CrispASR's CosyVoice3, Kokoro, and Qwen3-TTS GGUF runtimes in-process. `apps/vox.cpp` is the main program entry; it captures microphone audio, feeds ASR, optionally translates transcripts, and can synthesize translated text to wav files.
88

99
No network service is used at runtime. You need local model files under `models/`.
1010

@@ -120,9 +120,11 @@ The component builds the same translation prompt text and applies the GGUF chat
120120
Tencent's model card recommends `top_k=20`, `top_p=0.6`, `temperature=0.7`, and `repeat_penalty=1.05`; these are the component defaults.
121121
Check the Tencent HY Community License before distributing a product that includes this model.
122122

123-
### CosyVoice3 TTS
123+
### TTS
124124

125-
The TTS integration calls CrispASR's CosyVoice3 C ABI directly from the `external/CrispASR` submodule. It does not shell out to the `crispasr` executable; model loading, voice lookup, synthesis, and WAV writing failures are surfaced directly in-process.
125+
The TTS integration calls CrispASR C ABIs directly from the `external/CrispASR` submodule. It does not shell out to the `crispasr` executable; model loading, voice lookup, synthesis, and WAV writing failures are surfaced directly in-process.
126+
127+
CosyVoice3 remains the default TTS engine.
126128

127129
Download the minimum baked-voice CosyVoice3 GGUF set:
128130

@@ -141,6 +143,48 @@ models/tts/cosyvoice3/cosyvoice3-voices.gguf
141143

142144
Pass the LLM GGUF with `--tts-model`. The runtime auto-discovers sibling flow, HiFT, and voices files when they are in the same directory. If they live elsewhere, pass `--tts-flow-model`, `--tts-hift-model`, and `--tts-voices-model`.
143145

146+
Kokoro-82M is available with `--tts-engine kokoro`:
147+
148+
```sh
149+
scripts/download-kokoro-tts-gguf.sh
150+
```
151+
152+
On Windows PowerShell:
153+
154+
```powershell
155+
powershell -ExecutionPolicy Bypass -File scripts/download-kokoro-tts-gguf.ps1
156+
```
157+
158+
That creates:
159+
160+
```text
161+
models/tts/kokoro/kokoro-82m-q8_0.gguf
162+
models/tts/kokoro/kokoro-voice-af_heart.gguf
163+
```
164+
165+
Pass the Kokoro model with `--tts-model`. The runtime auto-discovers `kokoro-voice-af_heart.gguf` in the same directory, or use `--tts-voice-model PATH`. Kokoro uses espeak-ng for phonemization; install espeak-ng or keep the `espeak-ng` executable on PATH. Use `--tts-language LANG` to override the espeak-ng voice, otherwise the ASR language is reused and `auto` becomes `en-us`.
166+
167+
Qwen3-TTS 0.6B is available with `--tts-engine qwen3-tts`. The recommended quick-test path is CustomVoice Q8_0 because it has built-in speakers and does not need a reference WAV:
168+
169+
```sh
170+
scripts/download-qwen3-tts-gguf.sh
171+
```
172+
173+
On Windows PowerShell:
174+
175+
```powershell
176+
powershell -ExecutionPolicy Bypass -File scripts/download-qwen3-tts-gguf.ps1
177+
```
178+
179+
That creates:
180+
181+
```text
182+
models/tts/qwen3-tts-0.6b-customvoice/qwen3-tts-12hz-0.6b-customvoice-q8_0.gguf
183+
models/tts/qwen3-tts-0.6b-customvoice/qwen3-tts-tokenizer-12hz.gguf
184+
```
185+
186+
Pass the talker GGUF with `--tts-model`. The runtime auto-discovers `qwen3-tts-tokenizer-12hz.gguf` in the same directory, or use `--tts-codec-model PATH`. CustomVoice speakers include `aiden`, `dylan`, `eric`, `ono_anna`, `ryan`, `serena`, `sohee`, `uncle_fu`, and `vivian`; use `dylan` or `eric` for Chinese output tests. The Base variant can also be downloaded with `scripts/download-qwen3-tts-gguf.sh models/tts/qwen3-tts-0.6b-base base q8_0`; it requires `--tts-voice-model` pointing to a baked voice GGUF or a reference WAV plus `--tts-ref-text`.
187+
144188
## Run
145189

146190
Default Qwen3-ASR model and auto language:
@@ -252,7 +296,7 @@ The same translation path with Whisper ASR is:
252296

253297
The app translates ASR updates on a worker thread so llama.cpp inference does not block microphone capture. If translation falls behind, pending partial ASR updates are coalesced to the latest text; final results are always processed.
254298

255-
Enable TTS for translated final results by adding `--tts-model`. This writes one wav per synthesized result under `tts-output/`:
299+
Enable TTS for translated final results by adding `--tts-model`. This writes one wav per synthesized result under `tts-output/`. CosyVoice3 is the default engine:
256300

257301
```sh
258302
./build/bin/vox --final-only \
@@ -263,6 +307,49 @@ Enable TTS for translated final results by adding `--tts-model`. This writes one
263307
English
264308
```
265309

310+
Kokoro-82M uses the same pipeline with `--tts-engine kokoro`:
311+
312+
```sh
313+
./build/bin/vox --final-only \
314+
--tts-engine kokoro \
315+
--tts-no-gpu \
316+
--tts-model models/tts/kokoro/kokoro-82m-q8_0.gguf \
317+
models/asr/qwen3-asr-1.7b/Qwen3-ASR-1.7B-Q8_0.gguf \
318+
auto \
319+
models/translate/HY-MT1.5-1.8B-Q4_K_M.gguf \
320+
English
321+
```
322+
323+
On macOS, keep `--tts-no-gpu` for Kokoro if Metal output sounds like high-frequency noise. ASR can still use GPU with this option.
324+
325+
Qwen3-TTS 0.6B CustomVoice can synthesize without a reference WAV. For English speech translated to Chinese, use a Chinese speaker such as `dylan`:
326+
327+
```sh
328+
./build/bin/vox --final-only \
329+
--tts-engine qwen3-tts \
330+
--tts-model models/tts/qwen3-tts-0.6b-customvoice/qwen3-tts-12hz-0.6b-customvoice-q8_0.gguf \
331+
--tts-voice dylan \
332+
--tts-language Chinese \
333+
models/asr/qwen3-asr-1.7b/Qwen3-ASR-1.7B-Q8_0.gguf \
334+
en \
335+
models/translate/HY-MT1.5-1.8B-Q4_K_M.gguf \
336+
Chinese
337+
```
338+
339+
For Chinese speech translated to English, pick an English speaker:
340+
341+
```sh
342+
./build/bin/vox --final-only \
343+
--tts-engine qwen3-tts \
344+
--tts-model models/tts/qwen3-tts-0.6b-customvoice/qwen3-tts-12hz-0.6b-customvoice-q8_0.gguf \
345+
--tts-voice vivian \
346+
--tts-language English \
347+
models/asr/qwen3-asr-1.7b/Qwen3-ASR-1.7B-Q8_0.gguf \
348+
zh \
349+
models/translate/HY-MT1.5-1.8B-Q4_K_M.gguf \
350+
English
351+
```
352+
266353
To play each generated wav after synthesis on macOS:
267354

268355
```sh
@@ -287,6 +374,8 @@ TTS synthesis on CPU is dominated by the flow-matching stage. `--tts-flow-steps
287374
English
288375
```
289376

377+
For Kokoro, `--tts-length-scale N` controls duration. Values above `1.0` speak slower; values below `1.0` speak faster.
378+
290379
The app intentionally has no CLI framework yet. The reusable ASR behavior lives in `vox::asr::StreamingWhisper` and `vox::asr::StreamingQwenAsr`; SDL microphone capture is an app-layer adapter. The reusable scheduling behavior lives in `vox::pipeline::AsyncTranscriptTranslator` and `vox::pipeline::AsyncTextToSpeech`.
291380

292381
## ASR Stream API
@@ -312,7 +401,7 @@ Qwen3-ASR uses the same streaming shape, with a `StreamingQwenAsrConfig` that in
312401
The Whisper ASR test uses `external/whisper.cpp/samples/jfk.wav` as a local fixture and `models/ggml-base.bin` as the model.
313402
The Qwen3-ASR config test does not load a model; it covers language option normalization for the llama.cpp path. The Qwen3-ASR smoke test uses `tests/fixtures/asr_en.wav` plus the default Qwen3-ASR 1.7B Q8_0 model and mmproj; if either model is missing, the test is skipped. The smoke test runs on CPU by default; set `VOX_TEST_QWEN_USE_GPU=1` to exercise the GPU path.
314403
The HY-MT test loads `models/translate/HY-MT1.5-1.8B-Q4_K_M.gguf`; if it is missing, the test is skipped.
315-
The TTS WAV writer test does not load a model; it validates the local WAV output path used by the CosyVoice3 synthesizer.
404+
The TTS WAV writer test does not load a model; it validates the local WAV output path shared by the TTS synthesizers.
316405
317406
```sh
318407
ctest --test-dir build --output-on-failure

0 commit comments

Comments
 (0)