zoukankan      html  css  js  c++  java
  • 智能语音计算器(三)

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

    #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);
    这个问题困扰了我好长时间,因为语音引擎返回的是中文,而我计算引擎中对字符串的处理都是英文,所以这里需要处理一些从语音引擎得到的结果。
    这种方法我也是在博客上看到的,所有还是要感谢乐于分享知识的人们。
    如果代码没有看明白,可以私信联系我,互相学习。
  • 相关阅读:
    控件不能与用户交互的情况
    iOS常见的延时执行有2种方式
    网络-URLConnection & URLSession
    多线程-相关定义
    单例模式
    Targeted Resumes How to Write a Targeted Resume By Alison Doyle
    Email Cover Letter Format
    什么是目标、度量、KPI、维度和细分
    在美国公司架构中,LLC、LLP 和 Corporation 的区别何在?
    (转)给明年依然年轻的我们:欲望、外界、标签、天才、时间、人生目标、现实、后悔、和经历(500强高管力荐)
  • 原文地址:https://www.cnblogs.com/wzqstudy/p/10076770.html
Copyright © 2011-2022 走看看