原文:https://blog.csdn.net/huanrx/article/details/147047543
目的:
C++项目中接入Sherpa-onnx实现文字转语音功能
开发环境
Windows、VS2022
步骤:
1.创建C++空项目,位置放到合适的地方即可。


2.下载Sherpa-onnx动态库。
选择动态库是因为能够避免一些配置上的bug。
方法一:
库文件地址:https://huggingface.co/csukuangfj/sherpa-onnx-libs/tree/main 里边有各个平台的库文件,选择最新版本的window 64bit shared下载。

方法二:
git地址:https://github.com/makdi76/sherpa-onnx
sherpa-onnx教程地址:sherpa-onnx --- sherpa 1.3 documentation。如下图:

点击后进入

进入后点击Installation------>Windows 64bit Windows(x64)

进入后是一下界面,选择64-bit Windows(shared lib),点击下载

3.导入动态库
创建third_party文件夹,将上一步下载的压缩包解压到third_party文件夹。
创建models文件夹,用来放模型文件,暂时先不管

解压缩后目录如下图:

4.动态库设置
打开解决方案窗口,右击项目名"Sherpa_onnx" ------> 点击"属性"

打开界面:

修改内容:
1.C++标准改为 17,如图:

2.配置属性 → VC++目录 → 包含目录:添加目录
E:\VS\Sherpa_onnx\third_party\sherpa-onnx-v1.11.2-win-x64-shared\include
E:\VS\Sherpa_onnx\third_party\sherpa-onnx-v1.11.2-win-x64-shared\include\sherpa-onnx\c-api
自己添加的时候把目录替换成自己工程的,主要是添加动态库的include和c-api这两个文件夹路径

3.链接器 → 常规 → 附加库目录:添加
E:\VS\Sherpa_onnx\third_party\sherpa-onnx-v1.11.2-win-x64-shared\lib
替换成自己的解压的动态库 lib 文件夹路径

3.链接器 → 输入 → 附加依赖项:添加
cargs.lib
sherpa-onnx-c-api.lib
sherpa-onnx-cxx-api.lib

5.下载语言模型
从下边地址能找到预训练模型,我工程里用了kokoro-multi-lang-v1_0和vits-melo-tts-zh_en模型做测试。下载模型后解压到工程目录的models文件夹下。(models是在步骤3导入动态库的时候一并创建的)

模型地址:
https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/rtf.html

点击上图对应的模型回跳转到教程中对应模型的位置,由对应模型的下载地址,直接复制下载即可。地址位置如下图:


6.创建Main.cpp
在解决方案中:右击 源文件→添加→新建项→改文件名

7.写代码
代码可以查看sherp-onnx中的C++示例代码,下边是根据示例代码写的Kokoro模型和Vits模型。
在Main方法中调用对应方法即可生成对应的音频文件。
cpp
#include <iostream>
#include <memory>
#include <c-api.h>
#include <cxx-api.h>
#include <filesystem>
int CheckModelFile(std::string model_path) {
std::filesystem::path path(model_path);
if (std::filesystem::exists(path)) {
std::cout << "Model file exists at: " << model_path << std::endl;
return 0;
}
else {
std::cerr << "Model file does not exist at: " << model_path << std::endl;
return 1;
}
}
int Kokoro() {
using namespace sherpa_onnx::cxx;
OfflineTtsConfig config;
config.model.kokoro.model = "../models/kokoro-multi-lang-v1_0/model.onnx";
config.model.kokoro.voices = "../models/kokoro-multi-lang-v1_0/voices.bin";
config.model.kokoro.tokens = "../models/kokoro-multi-lang-v1_0/tokens.txt";
config.model.kokoro.data_dir = "../models/kokoro-multi-lang-v1_0/espeak-ng-data";
config.model.kokoro.dict_dir = "../models/kokoro-multi-lang-v1_0/dict";
config.model.kokoro.lexicon =
"../models/kokoro-multi-lang-v1_0/lexicon-us-en.txt,../models/kokoro-multi-lang-v1_0/lexicon-zh.txt";
config.model.num_threads = 2;
CheckModelFile(config.model.kokoro.model);
CheckModelFile(config.model.kokoro.voices);
CheckModelFile(config.model.kokoro.tokens);
CheckModelFile(config.model.kokoro.data_dir);
CheckModelFile(config.model.kokoro.dict_dir);
// If you don't want to see debug messages, please set it to 0
config.model.debug = 1;
std::string filename = "./generated-kokoro-zh-en-cxx.wav";
std::string text =
"中英文语音合成测试。This is generated by next generation Kaldi using "
"Kokoro without Misaki. 你觉得中英文说的如何呢?";
auto tts = OfflineTts::Create(config);
int32_t sid = 50;
float speed = 1.0; // larger -> faster in speech speed
GeneratedAudio audio = tts.Generate(text, sid, speed);
#if 0
// If you don't want to use a callback, then please enable this branch
GeneratedAudio audio = tts.Generate(text, sid, speed);
#else
//GeneratedAudio audio = tts.Generate(text, sid, speed, ProgressCallback);
#endif
WriteWave(filename, { audio.samples, audio.sample_rate });
fprintf(stderr, "Input text is: %s\n", text.c_str());
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename.c_str());
return 0;
}
int Vits() {
using namespace sherpa_onnx::cxx;
OfflineTtsConfig config;
config.model.vits.model = "../models/vits-melo-tts-zh_en/model.onnx";
config.model.vits.lexicon = "../models/vits-melo-tts-zh_en/lexicon.txt";
config.model.vits.tokens = "../models/vits-melo-tts-zh_en/tokens.txt";
config.model.vits.dict_dir = "../models/vits-melo-tts-zh_en/dict";
config.model.num_threads = 1; // 线程数
config.model.debug = 1; // 是否启用调试输出
//config.model.provider = "cpu"; // 使用CPU或CUDA
CheckModelFile(config.model.vits.model);
CheckModelFile(config.model.vits.lexicon);
CheckModelFile(config.model.vits.tokens);
CheckModelFile(config.model.vits.dict_dir);
std::string filename = "./generated-vits-zh-en-cxx.wav";
std::string text =
"中英文语音合成测试。This is generated by next generation Kaldi using "
"Kokoro without Misaki. 你觉得中英文说的如何呢?";
auto tts = OfflineTts::Create(config);
int32_t sid = 0;
float speed = 1.0; // larger -> faster in speech speed
GeneratedAudio audio = tts.Generate(text, sid, speed);
#if 0
// If you don't want to use a callback, then please enable this branch
GeneratedAudio audio = tts.Generate(text, sid, speed);
#else
//GeneratedAudio audio = tts.Generate(text, sid, speed, ProgressCallback);
#endif
WriteWave(filename, { audio.samples, audio.sample_rate });
fprintf(stderr, "Input text is: %s\n", text.c_str());
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename.c_str());
return 0;
}
int main() {
return Kokoro();
}
8.编译运行程序
运行程序 管理器配置 Release x64
可能报错:
1.sherpa_onnx.exe系统错误,找不到 ××××××.dll ,如下图:

解决方法: 将找不到的dll文件复制到sherpa_onnx.exe同级目录下。
sherpa-onnx-cxx-api.dll文件是我们的动态库文件,在项目内\third_party\sherpa-onnx-v1.11.2-win-x64-shared\lib文件夹下。
sherpa_onnx.exe是生成的可执行文件,在项目内\x64\Release文件夹下。
复制后如图:

2.遇到下图 0x00007FFFDACF6F4E (sherpa-onnx-c-api.dll)处(位于 Sherpa_onnx.exe 中)引发的异常: 0xC0000005: 读取位置 0x0000000000000000 时发生访问冲突问题,需要结合控制台输出查看,分为两种情况。
第一种:动态链接库问题
下图控制台第一行:The given version [17] is not supported, only version 1 to 10 is supported in this build.
此信息是动态链接库版本不匹配 问题,是onnxruntime.dll 版本冲突系统中存在多个版本的 onnxruntime.dll,程序运行时错误加载了低版本库(如系统目录 /Windows/System32 中的旧版本)。

解决方法:
把动态库文件目录(\third_party\sherpa-onnx-v1.11.2-win-x64-shared\lib文件夹)下的onnxruntime_providers_shared.dll和onnxruntime.dll从动态库目录复制到sherpa_onnx.exe同级目录(\x64\Release)下。
第二种:代码中指定的模型地址不对

解决方法:

或

调用模型的地址修改为正确的路径地址即可。
(此处有点疑问:相对路径究竟是从哪开始的?
最初的工程配置的地址是正常运行了,但在写文章重新建工程时,原本的路径写法是第二张图的,运行报错。修改为第一种写法运行正常。
查问题是相对路径应该是相对于exe文件的,但是两个工程的相对路径的起始位置在变化,导致文件读取失败。)
9.生成音频文件
出现图中 Saved to: ./×××.wav 文件即成功生成

文件位置:

嗯嗯嗯。。 从此处文件生成位置来看,他的根目录位置是工程下的Sherpa_onnx文件夹。嗯。所以这个相对目录目前还比较迷。待之后再查查资料再看。
以上就是接入的全部内容。C++菜鸡,全流程靠ai和网上信息实现......