【漂移菌】犀牛派X1-aidVoice SDK 小白摸爬滚打保姆级教程连载(中篇) MeloTTS-Chinese初体验

根据官方教程,我摸索出了一些规律,就是根据模型安装后端,qnn版本对齐就行。

我根据我实际情况构建了一个目录环境,然后下载了中文和英文的模型

下载命令都是一个套路的,我下载后解压到model目录里面,创建了中文zh目录和英文en目录。

下载命令非常简单:

mms login 
cd models/
mms get -m MeloTTS-Chinese -p FP16 -b qnn2.31 -c qcs8550 -d ./
unzip MeloTTS-Chinese_qcs8550_fp16.zip -d ./zh/
unzip MeloTTS-English_qcs8550_fp16.zip -d ./en/ 
cp -r /usr/local/share/aidvoice/examples  ../
cd ../examples/tts/cpp/ 
mkdir build && cd build && cmake ../ && make -j $(nproc) 
./test_tts -m ../../../../models/zh/models/QCS8550/FP16/  

就生成了一个wav文件,播放了一下,有那么点儿味道。然后我就打开examples里面的代码开始分析代码的内容,下面是我的一些发现:

首先, 这不是 MeloTTS 的开源实现仓库,而是 AidLux AidVoice 闭源 SDK 的示例工程包

  • TTS 引擎本体在系统库 /usr/local/lib/libaidvoice_speech.so源码不可见

  • 唯一的公开接口头文件:/usr/local/include/aidlux/aidvoice/aidvoice_speech.hpp

  • 本仓库只包含:模型文件 + C++/Python 示例代码 + 说明文档;

  • 推理后端是 AidLite + 高通 QNN(HTP/NPU),不是 OpenVINO 也不是 onnxruntime;

  • 模型格式为 .aidem(FP16),跑在 NPU 上,速度嘎嘎快。

最原始拉下来的模型目录结构:

melotts-english/
├── models/QCS8550/FP16/
│ ├── config.json # {“type”: “TYPE_MELOTTS_ENGLISH”},SDK 据此识别模型类型
│ ├── encoder_htp.bin.aidem # 17MB 文本编码器(含 BERT)
│ ├── flow_htp.bin.aidem # 28MB Flow(VITS 流模型,声学建模)
│ ├── decoder_htp.bin.aidem # 21MB 解码器/声码器(输出波形)
│ └── assets/
│ ├── tokenizer.json # BERT WordPiece 词表(英文,30522 词)
│ ├── config.json # BertForMaskedLM 配置
│ ├── cmudict_cache.txt # CMU 英文发音词典(G2P 用)
│ └── punc.dic # 标点字典
└── examples/
├── tts/cpp/
│ ├── CMakeLists.txt
│ ├── readme.txt
│ ├── test_tts.cpp # 示例1:硬编码一句话 → 合成 + 播放 + 存 wav
│ ├── test_file.cpp # 示例2:读 txt 文件 → 分片合成 + 播放
│ ├── text_file.txt # 示例输入文本
│ └── build/ # 你当前的编译输出目录(test_tts / test_file 已编译好)
├── tts/python/test_tts.py # Python 版示例(功能更全,支持命令行直接传文本)
└── asr/ # ASR 语音识别示例(与 TTS 无关)

我根据实际情况改了一下,你们也可以根据自己的情况修改。只要能找到目录所在目录就行。

构建流程

依赖(已装则跳过):

aid-pkg install aidlite-sdk
aid-pkg install aidlite-qnn236
sudo apt install libpulse-dev libasound2-dev   # 音频播放

编译:

cd /home/aidlux/melotts-english/examples/tts/cpp
mkdir -p build && cd build
cmake .. && make        # 生成 test_tts 和 test_file

CMakeLists.txt 固定引用 /usr/local/include/usr/local/lib,链接 aidvoice_speech 库,无需额外配置。

然后看了readme.md 后对两个示例程序的区别与用法有点儿自己的见解。

常用命令:

# 列出可用的播放设备(扬声器)id
sudo ./test_tts -c

# 播放模式运行(-i 是播放设备 id,不是麦克风)
sudo ./test_tts -m /home/aidlux/melotts-english/models/QCS8550/FP16 -i <设备id>

# 读文件合成
sudo ./test_file -m /home/aidlux/melotts-english/models/QCS8550/FP16 -i <设备id> -f <文本路径>

注意:

  • 必须带 -m:代码里默认模型路径指向 /home/aidlux/model_farm_melotts_en_woman_...,本机不存在,因为我改了目录了。

  • readme.txt 里 cmake.. 是笔误,应为 cmake .. ,另外有个sudo写成了suduo了,望修复一下。

  • 播放需要 sudo(访问音频设备);只生成 wav 不播放可不带 -i 试试。

我猜测文本到wav的内部流程可能是下面的内容,不确定,不过有大佬知道的话,请批评指正哈!

虽然SDK 闭源,但从模型文件和接口可还原完整链路(即 MeloTTS 的 VITS 三段结构):

首先是输入文本
然后到→ 文本规整 / 标点处理(punc.dic)
这里英文版本的话它是使用BERT做分词的→ BERT WordPiece 分词(assets/tokenizer.json)
→ G2P 字素转音素(英文查 CMU 词典 cmudict_cache.txt)
→ encoder_htp.bin.aidem (文本/BERT 编码,NPU)
→ flow_htp.bin.aidem (VITS Flow 声学建模,NPU)
→ decoder_htp.bin.aidem (声码器,输出波形,NPU)
→ 回调 onResult 返回 float PCM(48kHz / 16bit / 单声道)
→ 落盘 wav 和/或实时播放

所以看程序的aidvoice_speech.hpp`头文件就可以发现,只需要跟5个api打交道就行。

API 作用
create_tts(FeatureConfig) 创建实例(配置模型路径等)
set_mode() TYPE_WHOLE 整句 / TYPE_FRAGMENT 分片
set_callback() 注册回调,接收合成结果
init() 加载模型(只调一次,之后可反复 write)
write(vector<string>) 送入文本,触发合成
stop() / tts_destroy() 停止、销毁

这里TYPE_FRAGEMENT我用的时候发现一段文字会生成N多个wav片段,后面需要把所有wav整合到一起的。

回调结构 TTSResult 里有:audio_data(PCM 数据)、audio_name(wav 文件名)、audio_time(时长)、seq(分片序号)、statusTYPE_PARTIAL 分片中 / TYPE_FINAL 最后一片)。

我的文档是mytest.txt 我晚上随便抄了一段内容。

如何用 mytest.txt 生成 wav —— 怎么做,有什么坑呢?你听我娓娓道来!

直接可用的命令

test_file 已支持任意文本文件,不用改代码

cd /home/aidlux/melotts-english/examples/tts/cpp/build
./test_file -m /home/aidlux/melotts-english/models/QCS8550/FP16 -f ./mytest.txt

坑 1:mytest.txt 是中文,我根据官方说明下载的模型是英文专用,哈哈,自己坑了自己一把。

当前模型包(config.jsonTYPE_MELOTTS_ENGLISH)的 G2P 用的是英文 CMU 词典,BERT 词表也是英文的。直接喂中文文本大概率合成失败或输出乱音。两个解决方案:

  • 方案 A(简单):把 mytest.txt 内容改成英文,例如把之前准备的文档翻译成英文再合成;

  • 方案 B(换模型):SDK 支持中文(头文件里有 TYPE_MELOTTS_CHINESE 枚举),获取中文 MeloTTS 模型包后 -m 指向它即可,代码一行都不用改(SDK 按模型目录的 config.json 自动切换分词和 G2P 管线)。我就把模型都下载了。

坑 2:test_file 默认不保存 wav

test_file.cpp 没有调用 set_out_audio_path(),它面向"播放"场景。要存储为 wav,改一行:

test_file.cpp 第 134 行附近(set_mode 调用处),参照 test_tts.cpp:112 补上:

tts->set_out_audio_path("./");   // wav 输出到当前目录

然后重新 make 即可。

如果要改test_tt合成的文本的话,就去修改 test_tts.cpp:119 的str_vec:


然后重新编译就行。

后续我想试试看:
做交互式应用:LLM 文本 → TTS → 实时播放

我感觉应该完全可行,SDK 的设计就支持这个场景。想要实现的描述的链路(图片 → LLM 解析出文字描述 → 文字合成语音 → 实时播放)
因为我看代码里面init() 一次加载模型,之后反复调 write() 合成,不用每次重新加载——这是交互式应用的基础,不用每次加载模型浪费时间,第二,就是TYPE_FRAGMENT 分片模式下,SDK 把长文本切片,每合成一片就触发一次 onResult 回调(带 seq 序号),你可以一边合成一边播放,不用等整段话合成完,更加自然流畅了。

  • 两种播放方式
      1. 代码里面可以调 set_play_audio(设备id),SDK 内部直接播(好像需要 sudo权限,我试过没sudo不让操作硬件);
      1. 回调里自己拿 audio_data(float PCM)喂给你自己的播放器/网络流, 你可以直接推流到你的设备上,例如让树莓派接个蓝牙音箱,然后推流过去给树莓派,让树莓派播放。反正走网络你想怎么搞怎么搞了,哈哈,下一篇我就准备实时交互式应用哈哈。敬请期待。
3 个赞

打卡加一

在线催更

哈哈,想看下篇啊?

想!(举爪~) :nerd_face:

嗯,在加紧时间测试和准备了,敬请期待哈哈

1 个赞