File size: 4,401 Bytes
5eee449
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 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++ 范围内(见"范围说明")。