智能语音计算器(三)
这边来说界面的实现,个人觉得该模块实现有点乱,因为其中包括了录音功能,还需要改进。
#ifndef CALCULATORUI_H #define CALCULATORUI_H #include <qt5/QtWidgets/QWidget> #include <qt5/QtWidgets/QLineEdit> #include <qt5/QtWidgets/QPushButton> #include <qt5/QtCore/QFile> #include <qt5/QtMultimedia/QAudioInput> #include <qt5/QtCore/QDebug> #include <qt5/QtCore/QProcess> #include <qt5/QtCore/QString> #include <iostream> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <qt5/QtCore/QString> #include "ICalculator.h" #include "CalculatorASR.h" #include <unistd.h> using namespace std; #define RET_SIZE 100 /* QT += core gui QT += widgets QT += multimedia LIBS += -L./libs/x64 -lmsc */ class CalculatorUI : public QWidget { Q_OBJECT public: static CalculatorUI* newInstance(); ~CalculatorUI(); void show(); void setCalculator(ICalculator* cal); ICalculator *getCalculator(); qint64 addWavHeader(QString catheFileName,QString wavFileName); void startASR(); void getResult(); string changeResult(string &str); private: CalculatorUI(); bool Construct(); private slots: void onCalculate(); void onRecording(); private: QLineEdit *m_edit; QPushButton *m_start_record; QPushButton *m_buttons[20]; ICalculator *m_cal; QAudioInput *m_audioInput; bool m_isRecord; QFile destinationFile; QProcess *caller; CalculatorASR *cal_asr=NULL; string ASRret; }; #endif
界面是手写代码实现的,没有选择用designer设计器。
原因之一是界面不是很复杂,还有就是因为connect时更简洁。
#include "CalculatorUI.h" #include <qt5/QtWidgets/QMessageBox> #define RAW_RECORD_FIKENAME "./audio/test.raw" //录音文件名 #define WAV_RECORD_FIKENAME "./audio/test.wav" //录音文件转wav格式文件名 const qint64 TIME_TRANSFORM = 1000 * 1000; //微秒转秒 struct WAVFILEHEADER { char RiffName[4]; unsigned long nRiffLength; char WavName[4]; char FmtName[4]; unsigned long nFmtLength; unsigned short nAudioFormat; unsigned short nChannleNumber; unsigned long nSampleRate; unsigned long nBytesPerSecond; unsigned short nBytesPerSample; unsigned short nBitsPerSample; char DATANAME[4]; unsigned long nDataLength; }; CalculatorUI::CalculatorUI() : QWidget() { m_cal = NULL; m_audioInput = NULL; m_isRecord = false; cal_asr = new CalculatorASR(); if(cal_asr!=NULL) { cal_asr->myLogin(); } } CalculatorUI* CalculatorUI::newInstance() { CalculatorUI *ret = new CalculatorUI(); if(NULL == ret || !ret->Construct()) { delete ret; ret = NULL; } return ret; } CalculatorUI::~CalculatorUI() { cal_asr->myLogOut(); } void CalculatorUI::show() { QWidget::show(); setFixedSize(width(),height()); } bool CalculatorUI::Construct() { bool ret = true; m_edit = new QLineEdit(this); if(m_edit!=NULL) { m_edit->move(10,10); m_edit->resize(200,30); m_edit->setReadOnly(true); } else { ret = false; } m_start_record = new QPushButton(this); if(m_start_record!=NULL) { m_start_record->move(210,10); m_start_record->resize(40,30); m_start_record->setText("录音"); connect(m_start_record,SIGNAL(clicked()),this,SLOT(onRecording())); } else { ret = false; } const char* buttontext[20] = { "7","8","9","+","(", "4","5","6","-",")", "1","2","3","*","<-", "0",".","=","/","C" }; for(int i = 0;(i<4)&&ret;i++) { for(int j = 0;(j<5)&&ret;j++) { m_buttons[5*i + j] = new QPushButton(this); if(m_buttons[5*i + j]!=NULL) { m_buttons[5*i + j]->move(10 + (10 + 40)*j,50 + (10 + 40)*i); m_buttons[5*i + j]->resize(40,40); m_buttons[5*i + j]->setText(buttontext[5*i + j]); connect(m_buttons[5*i + j],SIGNAL(clicked()),this,SLOT(onCalculate())); } else { ret = false; } } } return ret; } void CalculatorUI::setCalculator(ICalculator* cal) { m_cal = cal; } ICalculator* CalculatorUI::getCalculator() { return m_cal; } void CalculatorUI::onCalculate() { QPushButton* button = dynamic_cast<QPushButton*>(sender()); if(button!=NULL) { QString buttontext = button->text(); if(buttontext == "<-") { QString text = m_edit->text(); if(text.length() > 0) { text.remove(text.length()-1,1); m_edit->setText(text); } } else if(buttontext == "C") { m_edit->setText(""); } else if(buttontext =="=") { if(m_cal != NULL) { m_cal->expression(m_edit->text()); m_edit->setText(m_cal->result()); } } else { m_edit->setText(m_edit->text() + buttontext); } } } qint64 CalculatorUI::addWavHeader(QString catheFileName,QString wavFileName) { //开始设置WAV的头文件 WAVFILEHEADER WavFileHeader; qstrcpy(WavFileHeader.RiffName,"RIFF"); qstrcpy(WavFileHeader.WavName,"WAVE"); qstrcpy(WavFileHeader.FmtName,"fmt"); qstrcpy(WavFileHeader.DATANAME,"data"); WavFileHeader.nFmtLength = 16; WavFileHeader.nAudioFormat = 1; WavFileHeader.nChannleNumber =1; WavFileHeader.nSampleRate = 8000; WavFileHeader.nBytesPerSample = 2; WavFileHeader.nBytesPerSecond = 16000; WavFileHeader.nBitsPerSample = 16; QFile cacheFile(catheFileName); QFile wavFile(wavFileName); if(!cacheFile.open(QIODevice::ReadWrite)) { return -1; } if(!wavFile.open(QIODevice::WriteOnly)) { return -2; } int nSize = sizeof(WavFileHeader); qint64 nFileLen = cacheFile.bytesAvailable(); WavFileHeader.nRiffLength = nFileLen - 8 + nSize; WavFileHeader.nDataLength = nFileLen; wavFile.write((char *)&WavFileHeader,nSize); wavFile.write(cacheFile.readAll()); cacheFile.close(); wavFile.close(); return nFileLen; } void CalculatorUI::onRecording() { //如果当前没有开始录音则允许录音 if(!m_isRecord) { m_isRecord = true; m_start_record->setText("结束"); //判断本地设备是否支持该格式 QAudioDeviceInfo audioDeveiceInfo = QAudioDeviceInfo::defaultInputDevice(); //判断本地是否有录音设备 if(!audioDeveiceInfo.isNull()) { m_isRecord = true; destinationFile.setFileName(RAW_RECORD_FIKENAME); destinationFile.open(QIODevice::WriteOnly | QIODevice::Truncate); //设置音频文件格式 QAudioFormat format; format.setSampleRate(8000); format.setChannelCount(1); format.setSampleSize(16); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); //判断当前设备是否支持该音频格式 if(!audioDeveiceInfo.isFormatSupported(format)) { qDebug() << "Default format not supported,trying to use the nearest."; format = audioDeveiceInfo.nearestFormat(format); } //开始录音 m_audioInput = new QAudioInput(format,this); m_audioInput->start(&destinationFile); } else { //没有录音设备 QMessageBox::information(NULL,tr("Record"),tr("Current No Record Device")); } } else { m_isRecord = false; m_start_record->setText("录音"); if(m_audioInput!=NULL) { m_audioInput->stop(); destinationFile.close(); delete m_audioInput; m_audioInput = NULL; } //将生成的.raw文件转成.wav格式文件: if(addWavHeader(RAW_RECORD_FIKENAME,WAV_RECORD_FIKENAME)>0) { // QMessageBox::information(NULL,tr("save"),tr("RecordFile Save Success")); } //启动语音识别引擎 startASR(); //获取识别结果 getResult(); m_edit->setText(QString::fromStdString(ASRret)); if(m_cal != NULL) { m_cal->expression(m_edit->text()); m_edit->setText(m_edit->text() + "=" + m_cal->result()); } } } void CalculatorUI::startASR() { const char* session_begin_params = "sub = iat, domain = iat, language = zh_cn, accent = mandarin, sample_rate = 16000, result_type = plain, result_encoding = utf8"; cal_asr->run_iat(WAV_RECORD_FIKENAME, session_begin_params); } void CalculatorUI::getResult() { string str = cal_asr->getResult(); CalculatorUI::ASRret = changeResult(str); std::cout << ASRret << endl; } string CalculatorUI::changeResult(string &str) { string ret; int num = str.size(); int i = 0; while(i<num) { int size = 1; if(str[i] & 0x80) { char temp = str[i]; temp <<= 1; do { temp <<= 1; ++size; }while(temp & 0x80); } string subWord; subWord = str.substr(i,size); if(subWord == "÷") ret += "/"; else if(subWord == "×") ret += "*"; else if(subWord == "。") ; else ret += subWord; i += size; } return ret; }
这里重点说一下
string CalculatorUI::changeResult(string &str);
这个问题困扰了我好长时间,因为语音引擎返回的是中文,而我计算引擎中对字符串的处理都是英文,所以这里需要处理一些从语音引擎得到的结果。
这种方法我也是在博客上看到的,所有还是要感谢乐于分享知识的人们。
如果代码没有看明白,可以私信联系我,互相学习。