多语言 G2P(Grapheme-to-Phoneme)库 + Kokoro-82M 加速 TTS 引擎(ggml encoder + ncnn Vulkan 四段 decoder,无 ONNX Runtime 依赖),C++ 从零复刻 misaki(hexgrad/misaki)的 en/zh 前端,支持中英文混读。英文 OOD 词由运行时 espeak-ng 兜底。
整个引擎可编译为链接库
kokoro_ncnn.dll/kokoro_ncnn.lib,对外提供纯 C API:文本输入直接产出音频,decoder 走 ncnn Vulkan 四段加速管线(decoder 稳态 RTF ≈ 0.53,13 s 音频约 6.9 s;ggml encoder 经 AVX2 / 图缓存 / F0-N 并行优化后单句约 0.25 s,短句全链路 RTF ≈ 0.670.70;均受核显限频与后台 GPU 负载影响,实测 0.50.8 波动)。接口说明见 docs/kokoro_api.md。
原版 kokoro-decoder.onnx(约 213 MB,CPU 实时性差)被拆成四段混合管线,GPU 承担重活;原 kokoro-encoder.onnx(107 MB,ORT)已移植为 ggml 图(models/encoder-ggml.bin,约 106 MB):
flowchart LR
T["文本"] --> G["G2P 音素"] --> E["ggml · encoder<br/>encoder-ggml.bin"]
E --> F["asr / F0 / N / style_dec"]
F --> S1["Seg1 · C++ 内联<br/>lsin 正弦源+噪声"]
S1 --> S2["Seg2 · ncnn Vulkan net-A<br/>STFT 激发"]
S2 --> S3["Seg3 · C++ 内联<br/>where 相位回绕"]
S3 --> S4["Seg4 · ncnn Vulkan net-B<br/>backbone + iSTFT"]
S4 --> A["24 kHz 音频"]
| 段 | 执行器 | 模型 | 说明 |
|---|---|---|---|
| Seg1 | C++(lsin_runtime) | —(lsin_graph 生成) |
F0 → 正弦源 / 噪声 / 清浊掩码 |
| Seg2 | ncnn Vulkan | dec_A2.param/.bin |
源 → STFT 实部/虚部 |
| Seg3 | C++(lsin_runtime) | —(RunWhereCpu) |
相位 ±π 回绕 |
| Seg4 | ncnn Vulkan | dec_B4.param/.bin |
backbone + iSTFT → 音频 |
关键点:两网全 fp32(fp16 舍入会使 Seg3 的 atan2 在 ±π 边界翻转 → Seg4 NaN);Vulkan shader 首次编译 7~10 s,已在 create 内置 warmup;稳态推理以 net-B(Seg4)为绝对大头(L=1040 约 6.2 s)。
flowchart TD
IN["文本输入"] --> ROUTE["MixedG2P::convert 统一后端路由"]
ROUTE --> D{"含中文?"}
D -- "否:纯英文" --> EN["EnglishG2P · 纯英文路径"]
D -- "是:含中文" --> ZH["ZHG2P · 含中文路径"]
subgraph EN_LANE["EnglishG2P"]
T1["Tokenize:标点/缩写/数字切分"]
T2["Word() 特殊词→词典→NNP→词干<br/>Number() 数字→英文"]
T3["subtokenize 窗口搜索<br/>失败 → espeak-ng 运行时兜底"]
EN --> T1 --> T2 --> T3
end
subgraph ZH_LANE["ZHG2P"]
Z1["预处理:数字/标点映射"]
Z2["v1.0 → legacy_call(IPA 路径)<br/>v1.1 → ZHFrontend(注音符号)"]
Z3["中文段:jieba+拼音+声调/儿化<br/>英文段 → EnglishG2P"]
ZH --> Z1 --> Z2 --> Z3
end
T3 --> OUT["音素串"]
Z3 --> OUT
第三方源码依赖通过 git submodule 管理:
git submodule update --init # 拉取 ncnn / cppjieba / ggml| 路径 | 来源 | 说明 |
|---|---|---|
third_party/ncnn/ |
Tencent/ncnn @ 20250503 |
推理库源码;本地 Vulkan 编译产物在 build-vk-mt/(不入库,需自行编译) |
third_party/ggml/ |
ggml-org/ggml(v0.9.9 附近) | encoder 推理库源码;本地 CPU 编译产物在 build-cpu/(不入库,需自行编译) |
third_party/cppjieba/ |
yanyiwu/cppjieba @ v5.6.7 |
中文分词头文件库(limonp 依赖头在 cppjieba/deps/limonp,随 --recursive 拉取) |
third_party/espeak-ng/ |
预编译运行时(DLL + 数据) | 随仓库提交;缺失时 G2P 自动降级为纯词典兜底 |
ncnn 的
build-vk-mt/与 ggml 的build-cpu/编译产物由本地编译生成(ggml 需GGML_CPU_ALL_VARIANTS=OFF或默认配置),构建脚本引用third_party\ggml\build-cpu\src\Release\*.lib与third_party\ncnn\build-vk-mt\src\Release\ncnn.lib。
.\compile_kokoro_dll.bat # 产物:kokoro_ncnn.dll / kokoro_ncnn.lib# Python (ctypes) 直接合成:文本 → 24 kHz float32 音频
python scripts\test_dll.pyC / C++ 调用方链接 kokoro_ncnn.lib(需 /MT),API 与示例见 docs/kokoro_api.md。
.\compile_g2p.bat # g2p_cli.exe —— 项目自带 G2P(zh/en)
# G2P:文本 → 音素
.\g2p_cli.exe dict\zh\dict.bin "Hello world" # → həlˈO wˈɜɹld
# 动态库端到端(ggml encoder + ncnn 四段管线):文本 → 24 kHz 音频
python scripts\test_dll.py# 1) 端到端回归:G2P + ggml encoder + ncnn 四段 decoder,与 ORT 参考对比(corr ≈ 0.98)
python scripts\test_dll.py
# 2) decoder-only RTF 基准(预热后稳态,L=128/256/512/1040)
python scripts\bench_decode.pyespeak-ng 依赖 third_party/espeak-ng/(DLL + 数据),缺失时自动降级为纯词典兜底。
| 项 | 结果 |
|---|---|
| 拆分管线 vs ORT 原版(同特征) | corr ≈ 0.98,无 NaN |
| 稳态 RTF(Vulkan,fp32,L=1040) | ≈ 0.51(13 s 音频约 6.6 s 推理);GPU 频率受核显电源/温度节流影响,波动 0.50~0.57 |
| 英文 G2P(vs misaki,200 句) | words 99.2%(无空输出词) |
| 中文 G2P(v1.0/v1.1,各 3 测试集) | 100% 逐 token 一致 |
| espeak-ng 兜底 | 与 misaki EspeakFallback 逐字节一致 |