1. 工程.pro 配置:
QT += multimedia texttospeech network
2.用windows上可用的麦克风进行录音:
audio.h 文件:
#ifndef AUDIO_H
#define AUDIO_H#include <QObject>#include <QAudioDeviceInfo> //查询音频设备
#include <QAudioInput> //音频输入
#include <QAudioFormat> //音频存储#include <QFile>#include <speech.h>#include <QMessageBox>
#include <QDebug>class Audio : public QObject
{Q_OBJECT
public:explicit Audio(QObject *parent = nullptr);signals:public slots:public:void startAudio(QString fileName);//初始化void stopAudio();//停止录音QString startSpeech();//开始录音并识别private:QString AudioFileName;//用于记录音频文件名QFile *AudioFile;//用于操作音频文件QAudioInput *AudioDevice;//音频设备对象Speech *speech;//语音识别对象};#endif // AUDIO_H
audio.cpp文件:
#include "audio.h"Audio::Audio(QObject *parent) : QObject(parent)
{speech = new Speech(this);
}void Audio::startAudio(QString fileName)
{if(fileName.isEmpty()){QMessageBox::warning(NULL,"警告(Audio)","无音频文件名");return;}QAudioDeviceInfo device = QAudioDeviceInfo::defaultInputDevice();//用于检测音频设备状态信息if(device.isNull()){QMessageBox::warning(NULL,"警告(Audio)","无音频设备");}else{/* 记录录音文件 */AudioFileName = fileName;/* 音频编码要求 */QAudioFormat m_format;/* 设置采样频率 */m_format.setSampleRate(16000);/* 设置通道数 */m_format.setChannelCount(1);/* 设置位深 */m_format.setSampleSize(16);/* 设置编码格式 */m_format.setCodec("audio/pcm");//http上传推荐pcm格式;也可封装成json上传/* 判断设备是否支持该格式 */if(!device.isFormatSupported(m_format)){/* 寻找最接近的格式 */m_format = device.nearestFormat(m_format);}//打开文件,创建一个音频文件AudioFile = new QFile;AudioFile->setFileName(fileName);AudioFile->open(QIODevice::WriteOnly);/* 创建录音对象 */AudioDevice = new QAudioInput(m_format,this);AudioDevice->start(AudioFile);}}QString Audio::startSpeech()
{if(AudioFileName.isEmpty())//检查录音文件是否存在{QMessageBox::warning(NULL,"警告","文件不存在");return QString("");}return speech->speechIdentify(AudioFileName); //语音识别,并返回识别后的结果,调用speech中的函数
}void Audio::stopAudio()
{/* 停止录音 */AudioDevice->stop();/* 关闭文件 */AudioFile->close();/* 删除文件对象指针并置空 */delete AudioFile;AudioFile = nullptr;}
3. 通过把录音文件 通过http请求百度云语音库的方式 ,进行语音转文字
http.h文件:
#ifndef HTTP_H
#define HTTP_H#include <QObject>#include <QNetworkAccessManager> //发送请求
#include <QNetworkRequest> //请求内容
#include <QNetworkReply> //返回的结果#include <QEventLoop>class Http : public QObject
{Q_OBJECT
public:explicit Http(QObject *parent = nullptr);signals:public slots:static bool http_postRequst(QString Url, QMap<QString,QString>header, QByteArray &requestData, QByteArray &replyData);
};#endif // HTTP_H
http.cpp文件:
#include "http.h"Http::Http(QObject *parent) : QObject(parent)
{}
bool Http::http_postRequst(QString Url, QMap<QString, QString> header, QByteArray &requestData, QByteArray &replyData)
{QNetworkAccessManager manager; //请求者QNetworkRequest request; //请求内容request.setUrl(Url); //获取token值时,参数只需要url和接收token值即可QMapIterator<QString, QString> it(header);while (it.hasNext()) {//判断header中是否有内容,并读取it.next();request.setRawHeader(it.key().toLatin1(),it.value().toLatin1());}/* 发送请求等待响应 */QNetworkReply *Reply = manager.post(request,requestData);//发送请求QEventLoop l;connect(Reply,&QNetworkReply::finished,&l,&QEventLoop::quit); //等待响应l.exec();//阻塞等待响应if(Reply != nullptr && Reply->error() == QNetworkReply::NoError){replyData = Reply->readAll();//读取http请求后的结果return true;}return false;
}
请求语句的实现与replyData的解析 :
speech.h文件:
#ifndef SPEECH_H
#define SPEECH_H#include <QObject>#include "http.h"#include <QFile>#include <QMap>#include <QByteArray>
#include <QMessageBox>#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>#include <QHostInfo>#include <QDebug>#include <QMessageBox>const QString BaiduSpeechUrl = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2"; //获取token请求的Url,注册百度语音识别可获得,免费180天
const QString BaiduSpeechClientID = "5VAJlZ5OMInnkkfzLlaWDktx"; //AK
const QString BaiduSpeechClientSecret = "JWNha3VuBFpotrXBag2Tf3ALWUCOwFuO"; //SK//语音识别的Url
//const QString BaiduSpeechSatrtUrl = "https://vop.baidu.com/server_api?dev_pid=80001&cuid=%1&token=%2";//短语音识别极速版
const QString BaiduSpeechSatrtUrl = "https://vop.baidu.com/server_api?dev_pid=1537&cuid=%1&token=%2"; //短语音识别标准版
//80001识别普通话 %1:本机唯一标识(本机标识) %2:获取的tokenclass Speech : public QObject
{Q_OBJECT
public:explicit Speech(QObject *parent = nullptr);signals:public slots:public:QString speechIdentify(QString audioFile);private:QString getJsonValue(QByteArray &data, QString &key);private:QString accessToken;};#endif // SPEECH_H
speech.cpp文件:
#include "speech.h"Speech::Speech(QObject *parent) : QObject(parent)
{}QString Speech::speechIdentify(QString audioFile)
{if(audioFile.isEmpty()){QMessageBox::warning(NULL,"警告(speech)","文件不存在");return QString("");}/* 组装access token的Url */QString TokenUrl = QString(BaiduSpeechUrl).arg(BaiduSpeechClientID).arg(BaiduSpeechClientSecret);/**************获取token值时不用参数,但自定义http函数需要传入**************/QMap<QString, QString>header; header.insert(QString("Content-Type"),QString("audio/pcm;rate=16000"));//Content-Type: audio/pcm;rate=16000键值对 PCM方式上传音频QByteArray requestData;//用于存放上传的数据,即录音信息QByteArray replyData;//定义存放Http请求结果的字节数组/**************获取token值不用的参数,但自定义http_postRequst函数需要传入**************///获取token值,获取一次使用30天if(accessToken.isEmpty() == true)//如果还未获取token值{bool ret = Http::http_postRequst(TokenUrl, header, requestData, replyData);if(ret){QString key = "access_token";accessToken = getJsonValue(replyData,key);replyData.clear();qDebug() << "获取的token ——" << accessToken;//调试}}/* 识别语音请求 将获取的token值组装到新的url中用于发送语音识别请求*/QString speechUrl = QString(BaiduSpeechSatrtUrl).arg(QHostInfo::localHostName()).arg(accessToken);qDebug()<<"speechUrl"<<speechUrl;/* 把录音文件转换成QByteArray */QFile file;file.setFileName(audioFile);//获取保存的录音文件file.open(QIODevice::ReadOnly);requestData = file.readAll();//读取录音文件中的内容file.close();if(requestData.isEmpty()){return QString("语音数据为空");}/* 再次发送请求 语音识别请求 */bool ret = Http::http_postRequst(speechUrl, header, requestData, replyData);if(ret){QString key = "result";//解析获取的json信息为QStringqDebug()<<"hello xjh "<<replyData;QString text = getJsonValue(replyData,key);//自定义函数,下方return text;//返回识别后的结果}else{QMessageBox::warning(NULL,"警告(speech)","识别失败");}return QString("");
}QString Speech::getJsonValue(QByteArray &data, QString &key) //自定义json解析函数
{QJsonParseError parseError;//json错误判定对象QJsonDocument jsonDocument = QJsonDocument::fromJson(data,&parseError);//转换成json文档QString retStr = "";if(parseError.error == QJsonParseError::NoError)//判断无误{if(jsonDocument.isObject()){/* 将jsonDocument 转换成json对象 */QJsonObject jsonObj = jsonDocument.object();if(jsonObj.contains(key)){QJsonValue jsonVal = jsonObj.value(key);if(jsonVal.isString()){return jsonVal.toString();}else if(jsonVal.isArray())//检查是否为数组{QJsonArray arr = jsonVal.toArray();for(int index = 0; index<arr.size(); index++){QJsonValue subValue = arr.at(index);if(subValue.isString()){retStr += subValue.toString()+" ";}}return retStr;}}else{qDebug() << "不包含关键字:" << key;}//contains(key)}else{qDebug() << "不是json对象";}//isObject}else{qDebug() << "未成功解析JSON";}//NoErrorqDebug() << "未成功解析JSON:" << data.data();return QString("");
}
4.主窗体上实现申明调用:
头文件:
#include <QTextToSpeech>
#include <QVoice>
#include "audio.h"//语音识别
申明:
Audio *my_audio;
QTextToSpeech *my_say;
初始化:
my_audio = new Audio;//语音识别对象my_say = new QTextToSpeech;//文字转语音 播放
按键实现调用:
void MainWindow::on_btnStartSpeak_clicked()
{if(speakStatus==false)//开始
{
ui->btnStartSpeak->setText("结束语音");
ui->btnStartSpeak->setStyleSheet(ui->btnStartSpeak->styleSheet()+ "QToolButton{ color: red;}");
speakStatus=true;
my_audio->startAudio("audiofile");
ui->textEditReco->setText("");
}
else
{
ui->btnStartSpeak->setText("开始语音");
ui->btnStartSpeak->setStyleSheet(ui->btnStartSpeak->styleSheet()+ "QToolButton{color: blue;}");
speakStatus=false;my_audio->stopAudio();
QString retStr = my_audio->startSpeech();//识别结果my_say->say(retStr);//播放出来
qDebug() << retStr;ui->textEditReco->setText(retStr);//显示出来
}
}
实验效果: