智能语音计算器(三)

这边来说界面的实现,个人觉得该模块实现有点乱,因为其中包括了录音功能,还需要改进。

#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);
这个问题困扰了我好长时间,因为语音引擎返回的是中文,而我计算引擎中对字符串的处理都是英文,所以这里需要处理一些从语音引擎得到的结果。
这种方法我也是在博客上看到的,所有还是要感谢乐于分享知识的人们。
如果代码没有看明白,可以私信联系我,互相学习。
原文地址:https://www.cnblogs.com/wzqstudy/p/10076770.html