1. 程式人生 > >智能語音計算器(三)

智能語音計算器(三)

其中 edi tca n) 啟動 head number del +=

這邊來說界面的實現,個人覺得該模塊實現有點亂,因為其中包括了錄音功能,還需要改進。

#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);
這個問題困擾了我好長時間,因為語音引擎返回的是中文,而我計算引擎中對字符串的處理都是英文,所以這裏需要處理一些從語音引擎得到的結果。
這種方法我也是在博客上看到的,所有還是要感謝樂於分享知識的人們。
如果代碼沒有看明白,可以私信聯系我,互相學習。

智能語音計算器(三)