| # Inflect AX TTS C++ SDK |
|
|
| `owensong/Inflect-Micro-v2` Encoder/Decoder 两段式 AXMODEL 的 C++ 推理 SDK,面向 **AX620E / AX637** 板端。直接链接 AX Engine 运行时(`ax_engine` + `ax_sys`,AX620E BSP 惯例)。两套 axmodel 接口一致,通过模型路径切换目标。 |
|
|
| ## 范围说明 |
|
|
| - **包含**:encoder/decoder 推理封装(`AxRunner`)、完整 Host 链(时长取整、`generate_path` 对齐、prior 扩展、噪声注入、Tp=512 分块 crossfade、edge fade、clip、WAV 写出)——纯 C++17,无 Eigen/第三方依赖;`generate_path` 为纯整数逻辑,扩展 matmul 由 0/1 对齐性质等价实现为逐帧 gather(与 matmul 逐位一致,有自测)。 |
| - **不包含**:eSpeak 文本前端(文本 → 音素 id)。C++ 侧 API 接收音素 id 序列;文本前端请用 Python SDK(`../python`)离线生成 id,或在板端自行集成 eSpeak-ng 后按模型仓库 `runtime/text/symbols.py` 映射。 |
| - **seed**:C++ 用 `std::mt19937_64 + normal_distribution`,SDK 内可复现;与 PyTorch 参考及 Python SDK(numpy PCG64)均不逐位一致。 |
|
|
| ## 目录 |
|
|
| ``` |
| src/ax_runner.{h,cpp} AX Engine 运行时封装(AX_RUNTIME_ROOT 未设时为 stub) |
| src/host_chain.{h,cpp} Host 链:expand_priors / inject_noise / 分块 crossfade / edge fade |
| src/inflect_tts.{h,cpp} InflectTTS 类:synthesize_tokens(token_ids, speed, variation, seed) |
| src/wav_writer.{h,cpp} 16-bit PCM WAV 写出 |
| src/main.cpp inflect_tts_cli 示例 + --selftest |
| cmake/aarch64-linux-gnu.toolchain.cmake |
| ``` |
|
|
| ## 构建 |
|
|
| ### 本机 configure / 构建检查(无 BSP,stub 引擎) |
|
|
| ```bash |
| cd package/cpp |
| cmake -B build . |
| cmake --build build -j |
| ./build/inflect_tts_cli --selftest # Host 链自测(无需 AX 运行时) |
| ``` |
|
|
| ### 板端 aarch64 交叉编译(AX620E) |
|
|
| ```bash |
| cd package/cpp |
| cmake -B build-aarch64 \ |
| -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-linux-gnu.toolchain.cmake \ |
| -DAX_RUNTIME_ROOT=/opt/ax620e_bsp/runtime \ |
| . |
| cmake --build build-aarch64 -j |
| ``` |
|
|
| `AX_RUNTIME_ROOT` 指向 AX620E BSP SDK 的运行时目录(示例写 `/opt/ax620e_bsp/runtime`,按实际 BSP 安装位置替换),需含 `include/ax_engine_api.h`、`include/ax_sys_api.h` 与 `lib/libax_engine.so`、`lib/libax_sys.so`。板内原生编译去掉 toolchain 行、保留 `-DAX_RUNTIME_ROOT` 即可。AX637 同一份代码,仅 axmodel 与 BSP 库不同。 |
|
|
| ## 板端部署与运行 |
|
|
| ```bash |
| # 目标机(示例 IP 192.168.1.10,按实际板地址替换) |
| scp build-aarch64/inflect_tts_cli root@192.168.1.10:/opt/inflect/ |
| scp ../models/ax620e/encoder.axmodel ../models/ax620e/decoder.axmodel root@192.168.1.10:/opt/inflect/ |
| |
| # 板上(dummy 音素 id,对应文本 "ðə kwɪk") |
| ./inflect_tts_cli \ |
| --encoder encoder.axmodel --decoder decoder.axmodel \ |
| --tokens 81,83,16,53,65,102,53 \ |
| --output out.wav --speed 1.0 --variation 0.667 --seed 0 |
| ``` |
|
|
| ## API |
|
|
| ```cpp |
| #include "inflect_tts.h" |
| #include "wav_writer.h" |
| |
| InflectTTS tts("encoder.axmodel", "decoder.axmodel"); |
| std::vector<int64_t> ids = {81, 83, 16, 53, 65, 102, 53}; // 音素 id(未 intersperse) |
| std::vector<float> wav = tts.synthesize_tokens(ids, /*speed*/1.0f, |
| /*variation*/0.667f, /*seed*/0); |
| write_wav("out.wav", wav, 24000); |
| ``` |
|
|
| - `token_ids`:音素 id(**未** intersperse;SDK 内部插 blank,长度上限 127 音素 → 255 tokens,对应 encoder 静态 T=256)。 |
| - 返回 24 kHz mono float32,[-1,1],已做 5 ms edge fade。 |
|
|
| ## I/O 契约(与 Python SDK 一致) |
|
|
| - encoder in:`tokens` int32 [1,256](0 右补齐;**注意 axmodel 运行时输入为 S32**,S64 input_processors 已在编译期折叠)、`x_lengths` int32 [1];out:`m_p`/`logs_p` fp32 [1,192,256]、`logw` fp32 [1,1,256](按输出名寻址,取前 x_lengths 帧)。 |
| - decoder in:`z_p` fp32 [1,192,512](右补零);out:`wav` fp32 [1,1,131072],按有效帧裁剪、块间 64 帧 crossfade。 |
| - Host 链限制:decoder 右缘 padding 会经卷积感受野倒灌污染末段帧(实测 T'=51 时约最后 12 帧;SDK 以 5 ms edge fade 缓解);多块(T'>512)crossfade 路径未做数值门禁验证。 |
|
|
| ## 已知限制 |
|
|
| - 本仓库构建机上 **未做交叉编译与板端运行验证**(无 aarch64 工具链/无板):仅验证本机 configure + 构建 + `--selftest` 通过。`ax_runner.cpp` 的 AX Engine 调用按 AX620E BSP 惯例编写,首次板端构建如遇到 API 差异以 BSP 头文件为准。 |
| - 文本前端不在 C++ 范围内(见"范围说明")。 |
|
|