AI 语音处理 - 文字合成语音功能
- 2022 年 3 月 11 日
本文字数:4192 字
阅读完需:约 14 分钟
1. 前言
语音合成技术在生活中用越来越广泛,阅读听书、订单播报、智能硬件、语音导航 很多场景下都加入了语音播报功能。语音合成基于深度神经网络技术,提供高度拟人、流畅自然的语音合成服务,可以模拟出不同人的声音,让应用 APP、设备开口说话,还能智能化训练个性语音。
这篇文章就介绍华为云提供的语音合成服务使用方法,利用提供的 API 接口完成语音合成功能,将合成的语音下载下来。
2. 开通功能
华为云的提供的语音合成,是一种将文本转换成逼真语音的服务。用户通过实时访问和调用 API 获取语音合成结果,将用户输入的文字合成为音频。通过音色选择、自定义音量、语速,为企业和个人提供个性化的发音服务。
2.1 语音交互服务
**地址:**https://console.huaweicloud.com/sis/?region=cn-north-4#/sis/stts
2.2 帮助文档
地址: https://support.huaweicloud.com/api-sis/sis_03_0111.html
(1)请求 Header 参数:
请求头里的 X-Auth-Token 字段在之前的文章已经介绍过,获取方法看这里: https://bbs.huaweicloud.com/blogs/317759 翻到 2.3 小节。
(2)请求 Body 参数:
(3)TtsConfig 的配置参数:
(4)普通发音人 property 取值范围:
(5)精品发音人 property 取值范围:
(6)响应的 Body 参数
状态码: 200
(7)CustomResult 参数
2.3 在线调试接口
通过在线调试接口,可以快速调试接口参数,请求方式,返回结果等信息。
地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=SIS&api=RunTts
还可以在线填入测试参数,进行测试效果。
2.4 请求接口总结
请求地址格式: POST /v1/{project_id}/tts
完整请求地址:
https://sis-ext.cn-north-4.myhuaweicloud.com/v1/0e5957be8a00f53c2fa7c0045e4d8fbf/tts
请求体:
{
"text": "请注意坐姿",
"config": {
"audio_format": "wav",
"sample_rate": "16000",
"property": "chinese_xiaoqi_common",
"speed": 0,
"pitch": 0,
"volume": 0
}
}
请求头:
{
"X-Auth-Token": "******",
"Content-Type": "application/json;charset=UTF-8"
}
响应体:
{"result":{"data":xxxxxxxx"}}
这个xxxx就是返回的Base64编码语音数据,可以解码后保存成文件即可。
3. 实现源码
软件采用 QT 设计的,核心部分主要是用到了 HTTP 请求相关的操作。
3.1 文字转语音源码
//文本转语音
void Widget::TextToAudio(QString text)
{
function_select=1;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//请求地址
requestUrl = QString("https://sis-ext.%1.myhuaweicloud.com/v1/%2/tts")
.arg(SERVER_ID)
.arg(PROJECT_ID);
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
//设置token
request.setRawHeader("X-Auth-Token",Token);
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
QString post_param=QString
("{"
"\"text\": \"%1\","
"\"config\": {"
"\"audio_format\": \"%2\","
"\"sample_rate\": \"%3\","
"\"property\": \"%4\","
"\"speed\": %5,"
"\"pitch\": 0,"
"\"volume\": %6"
"}"
"}").arg(text).arg(ui->comboBox_formt->currentText())
.arg(ui->comboBox_cai_yang_lv->currentText())
.arg(ui->comboBox_fa_yin_ren->currentText())
.arg(ui->spinBox_audio_speed->value())
.arg(ui->spinBox_yin_liang->value());
//发送请求
manager->post(request, post_param.toUtf8());
}
//生成语音
void Widget::on_pushButton_to_audio_clicked()
{
QString text=ui->lineEdit->text();
if(text.isEmpty())
{
QMessageBox::information(this,"提示","请输入文本",
QMessageBox::Ok,QMessageBox::Ok);
return;
}
qDebug()<<"text:"<<text;
TextToAudio(text);
}
3.2 获取 token
/*
功能: 获取token
*/
void Widget::GetToken()
{
//表示获取token
function_select=3;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//获取token请求地址
requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
.arg(SERVER_ID);
//自己创建的TCP服务器,测试用
//requestUrl="http://10.0.0.6:8080";
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
QString text =QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
"{\"user\":{\"domain\": {"
"\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
"\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
.arg(MAIN_USER)
.arg(IAM_USER)
.arg(IAM_PASSWORD)
.arg(SERVER_ID);
//发送请求
manager->post(request, text.toUtf8());
}
3.3 解析返回值
//解析反馈结果
void Widget::replyFinished(QNetworkReply *reply)
{
QString displayInfo="";
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
//读取所有数据
QByteArray replyData = reply->readAll();
qDebug()<<"状态码:"<<statusCode;
qDebug()<<"反馈的数据:"<<QString(replyData);
//更新token
if(function_select==3)
{
displayInfo="token 更新失败.";
//读取HTTP响应头的数据
QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs();
qDebug()<<"HTTP响应头数量:"<<RawHeader.size();
for(int i=0;i<RawHeader.size();i++)
{
QString first=RawHeader.at(i).first;
QString second=RawHeader.at(i).second;
if(first=="X-Subject-Token")
{
Token=second.toUtf8();
displayInfo="token 更新成功.";
//保存到文件
SaveDataToFile(Token);
break;
}
}
QMessageBox::information(this,"提示",displayInfo,
QMessageBox::Ok,QMessageBox::Ok);
return;
}
//判断状态码
if(200 != statusCode)
{
//解析数据
QJsonParseError json_error;
QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
if(json_error.error == QJsonParseError::NoError)
{
//判断是否是对象,然后开始解析数据
if(document.isObject())
{
QString error_str="";
QJsonObject obj = document.object();
QString error_code;
//解析错误代码
if(obj.contains("error_code"))
{
error_code=obj.take("error_code").toString();
error_str+="错误代码:";
error_str+=error_code;
error_str+="\n";
}
if(obj.contains("error_msg"))
{
error_str+="错误消息:";
error_str+=obj.take("error_msg").toString();
error_str+="\n";
}
QMessageBox::information(this,"提示",error_str,
QMessageBox::Ok,QMessageBox::Ok);
}
}
return;
}
else if(function_select==1) //语音合成
{
//解析数据
QJsonParseError json_error;
QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
if(json_error.error == QJsonParseError::NoError)
{
//判断是否是对象,然后开始解析数据
if(document.isObject())
{
QJsonObject obj = document.object();
//解析错误代码
if(obj.contains("result"))
{
QJsonObject obj1=obj.take("result").toObject();
if(obj1.contains("data"))
{
QString data=obj1.take("data").toString();
QByteArray d2=QByteArray::fromBase64(data.toUtf8());
qDebug()<<"数据获取成功..";
QStringList path_list=QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
//保存到文件
QString filename=QFileDialog::getSaveFileName(this,"保存音频文件",path_list.at(0),tr("*.wav *.mp3 *.pcm"));
if(filename.isEmpty())
{
filename=path_list.at(0)+"/123.wmv";
}
QFile::remove(filename);
QFile file_2(filename);
file_2.open(QIODevice::WriteOnly);
file_2.write(d2); //写入数据
file_2.close();
}
}
}
}
}
}
版权声明: 本文为 InfoQ 作者【DS小龙哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/fcea27c10e56abfb45935e817】。文章转载请联系作者。
DS小龙哥
之所以觉得累,是因为说的比做的多。 2022.01.06 加入
熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域
评论