• 【正点原子Linux连载】第二十五章 语音识别项目 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2


    1)实验平台:正点原子阿尔法Linux开发板
    2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434
    3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
    4)对正点原子Linux感兴趣的同学可以加群讨论:935446741

    第二十五章 语音识别项目

    我们知道AI智能音箱已经在我们生活中不少见,也许我们都玩过,智能化非常高,功能强大,与我们平常玩的那种蓝牙音箱,Wifi音箱有很大的区别,AI智能在哪里呢?语音识别技术和云端技术,主要由主控芯片,麦克风阵列,功率放大,codec,触控电路,LED阵列组成。
    AI音箱对传统音箱主要有两大块的技术区别,一块是语音信号的前处理,包括回声消除、波速成型、音源定位、降噪、去混响、自动语音电平控制这块是偏硬件的控制。还有一块是智能语音交互,包括语音关键词搜索、本地语音识别、声纹识别、语音合成。
    AI智能音箱的芯片方案商:联发科,全志科技,瑞芯微等等,语音识别都有现成的方案商。他们的麦克风阵列方案,有2麦,4麦,6麦,7 + 1麦等等。
    写上面这些是让读者了解一下专业AI音箱方案与我们在正点原子Linux开发板想实现语音识别的差别在哪里。我们在正点原子Linux开发板上实现语音识别项目(功能),就不能与专业的AI音箱对比了。硬件资源有限,开发板只有一个麦头(咪头座),没有那些硬件控制消除回声,降噪等等。不过编者在上面调用百度语音API识别语音,识别率还是挺高的。
    下面就与大家一起在正点原子Linux IMX6U开发板上实现语音识别功能吧!注意:正点原子MINI I.MX6U开发板没有音频芯片,不支持此实验,只有正点原子I.MX6U ALPHA开发板支持。
    本章简介如下:
    介绍百度语音技术账号申请,及简单介绍调用流程。
    用Qt编写示例程序。流程如下,录制音频后,发送调用百度语音识别API接口,识别并返回结果。支持语音控制正点原子I.MX6U开发板上的LED控制,其他设备可以自行拓展。

    25.1 语音识别产品申请帐号

    语音识别技术产品,有讯飞,百度等厂家,我们可以购买或者免费试用他们的产品。可以直接到他们的官网上查看,有使用技术文档。下面我们以百度语音识别技术产品为例子。可以在浏览器输入搜索“百度语音识别”,就可以找到百度AI开放平台。
    在这里插入图片描述

    点击进去就可以看到他的技术文档链接位置。如下图。
    
    • 1

    在这里插入图片描述

    或者直接打开https://ai.baidu.com/ai-doc/SPEECH/Ek39uxgre就可以跳转到百度AI开放平台》帮助文档》语音技术页面。如下图。
    
    • 1

    在这里插入图片描述

    请仔细阅读百度语音技术的文档,里面写的非常详细,还有例子下载参考。
    编者阅读总结,想要使用百度语音识别接口,需要根据上面图中的新手指南注册百度帐号,领取免费额度及创建中文普通话应用(创建前先领取免费额度(180天免费额度,可调用约5万次左右,详细请看免费额度说明))。记住自己的密钥。请自行完成及创建百度帐号,按照百度帮助文档里的步骤,领取免费额度及创建中文普通话应用,获取密钥!程序里需要用到自己的密钥。编者提供的密钥是百度语音识别例程里的,如果开发次数超了可能就不能使用了。程序中只需要API Key与Secret Key。注意获取Access Token时有效期为30天,到期后需要在程序里重新获取新的token。
    
    • 1
    • 2

    在这里插入图片描述

    更多参考请查看百度AI接入指南。
    注意,帮助文档里提及SDK包,有LinuxC++SDK包支持,但是目前仅支持 X64(x86-64) CPU架构的 Linux 操作系统。LinuxSDK 仅支持在线语音识别,固定长语音模式。简单的说就是还不支持ARM架构的SDK包。
    
    • 1
    • 2

    25.2 百度语音识别流程及示例简介

    在百度AI帮助文档里可以看见如下重要信息。
    在这里插入图片描述

    请认真阅读调用流程,了解操作过程,对下面理解编者编写Qt调用百度语音API的例子会有一定的帮助。
    总结:调用流程需要仔细阅读,百度提供了示例Demo代码,可以看到里面支持很多种编程语言编写的API请求相关示例demo代码。没有直接C++相关的代码。C语言是C++语言的子集,我们可以直接参考C语言编写的例子(请自行查阅及参考百度提供的C语言编写的API请求相关示例demo代码)来编写Qt调用语音识别API。(备注:其他语言编写的例子不在我们教程范围。)识别的音频格式支持如上,我们可以知道一些重要的信息是支持采样率16000、8000的固定值,16bit深的单声道,音频长度最长60秒。格式支持wav,恰好正点原子Linux I.MX6U开发板系统支持wav格式播放及录制(详细请看【正点原子】I.MX6U用户快速体验V1.x.pdf测试音频部分)。
    备注:由于百度语音识别的API例子放在github(开源网站),国外网站的原因,可能打开失败,请多次尝试,如果一直无法访问,那么我们直接往下看使用编者编写Qt的示例吧。不能访问的话,编者也没办法的。
    
    • 1
    • 2
    • 3

    25.3 百度短语音识别API接口

    源码路径为4/02_asr_demo/asr/asr.h,内容如下。asr是语音识别功能demo,(asr译作自动语音识别技术即automatic speech recognition)

        /******************************************************************
        Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
        * @projectName   asr
        * @brief         asr.h
        * @author        Deng Zhimao
        * @email         1252699831@qq.com
        * @net            www.openedv.com
        * @date           2021-06-03
        *******************************************************************/
    1   #ifndef ASR_H
    2   #define ASR_H
    3 
    4   #include <QWidget>
    5 
    6   #include <QNetworkAccessManager>
    7   #include <QNetworkReply>
    8 
    9   #include <QJsonDocument>
    10  #include <QJsonParseError>
    11  #include <QJsonObject>
    12  #include <QJsonArray>
    13  #include <QHostInfo>
    14
    15  #include <QFile>
    16
    17  class Asr : public QWidget
    18  {
    19      Q_OBJECT
    20
    21  public:
    22      Asr(QWidget *parent = nullptr);
    23      ~Asr();
    24
    25      /* 请求网络 */
    26      void requestNetwork(QString, QByteArray);
    27
    28      /* 获取识别结果 */
    29      void getTheResult(QString fileName);
    30
    31  private:
    32      /* 存储获取tokenUrl地址 */
    33      QString tokenUrl;
    34
    35      /* 存储serverapi地址 */
    36      QString serverApiUrl;
    37
    38      /* 最终需要访问token的地址 */
    39      QString accessToken;
    40
    41      /* 获取token的接口*/
    42      const QString token_org = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2&";
    43
    44      /* 填写网页上申请的appkey 如 g_api_key="g8eBUMSokVB1BHGmgxxxxxx" */
    45      const QString api_key = "kVcnfD9iW2XVZSMaLMrtLYIz";
    46
    47      /* 填写网页上申请的APP SECRET 如 $secretKey="94dc99566550d87f8fa8ece112xxxxx" */
    48      const QString secret_key = "O9o1O213UgG5LFn0bDGNtoRN3VWl2du6";
    49
    50      /* 百度服务器API接口,发送语音可返回识别结果 */
    51      const QString server_api = "http://vop.baidu.com/server_api?dev_pid=1537&cuid=%1&token=%2";
    52
    53      /* 网络管理 */
    54      QNetworkAccessManager *networkAccessManager;
    55
    56      QString getJsonValue(QByteArray ba, QString key);
    57
    58      QFile file;
    59
    60  private slots:
    61
    62      /* 准备读取响应返回来的数据 */
    63      void readyReadData();
    64
    65      /* 响应完成处理 */
    66      void replyFinished();
    67
    68  signals:
    69      void asrReadyData(QString);
    70
    71  };
    72  #endif // ASR_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    第45行,请填写读者自己在网页上申请的API Key。以防万一示例中的API Key过期不可用!
    第47行,请填写读者在网页上申请的Secret Key。以防万一示例中的Secret Key过期不可用!
    其他地址由来是见百度给出的Demo示例,及百度的帮助文档。这里就不详细说了。原理与上一章原子云API接口相似。不过百度语音识别需要通过自己的帐号,指定地址获取访问的Token源地址,然后将得到的Access Token地址与语音识别服务器地址拼接,发送语音到服务器,就可以返回识别的结果了。详细请参考源码4/02_asr_demo/asr/asr.cpp。
    
    • 1
    • 2
    • 3

    25.4 录制wav音频

    在12.5小节,已经介绍过开发板如何录制音频文件了,详细请看12.5小节,就不详细介绍了,注意需要修改的地方如下。因为百度语音识别支持采样率16000、8000的固定值,16bit深的单声道,音频长度最长60秒。格式支持wav,pcm等格式。我们需要修改录制音频格式为wav格式,通道为单声道,采样率为16000,源码如下,已用红色字体标出。录制的音频文件保存为本地16k.wav文件。
    源码路径为4/02_asr_demo/audiorecorder/audiorecorder.cpp。

        /******************************************************************
        Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
        * @projectName   audiorecorder
        * @brief         audiorecorder.cpp
        * @author        Deng Zhimao
        * @email         1252699831@qq.com
        * @net            www.openedv.com
        * @date           2021-06-04
        *******************************************************************/
    1   #include "audiorecorder.h"
    2   #include <QDebug>
    3   #include <QUrl>
    4   #include <QDateTime>
    5   #include <QDir>
    6   #include <QCoreApplication>
    7  
    8   static qreal getPeakValue(const QAudioFormat &format);
    9   static QVector<qreal> getBufferLevels(const QAudioBuffer &buffer);
    10 
    11  template <class T>
    12  static QVector<qreal> getBufferLevels(const T *buffer, int frames, int channels);
    13 
    14  AudioRecorder::AudioRecorder(QWidget *parent)
    15  {
    16      Q_UNUSED(parent);
    17 
    18      /* 录制音频的类 */
    19      m_audioRecorder = new QAudioRecorder(this);
    20 
    21      /* 用于探测缓冲区的数据 */
    22      m_probe = new QAudioProbe(this);
    23 
    24      /* 信号槽连接,更新录音level显示 */
    25      connect(m_probe, &QAudioProbe::audioBufferProbed,
    26              this, &AudioRecorder::processBuffer);
    27 
    28      /* 设置探测的对象 */
    29      m_probe->setSource(m_audioRecorder);
    30 
    31      /* 扫描本地声卡设备 */
    32      devicesVar.append(QVariant(QString()));
    33      for (auto &device: m_audioRecorder->audioInputs()) {
    34          devicesVar.append(QVariant(device));
    35          //qDebug()<<"本地声卡设备:"<
    36      }
    37 
    38      /* 音频编码 */
    39      codecsVar.append(QVariant(QString()));
    40      for (auto &codecName: m_audioRecorder->supportedAudioCodecs()) {
    41          codecsVar.append(QVariant(codecName));
    42          //qDebug()<<"音频编码:"<
    43      }
    44 
    45      /* 容器/支持的格式 */
    46      containersVar.append(QVariant(QString()));
    47      for (auto &containerName: m_audioRecorder->supportedContainers()) {
    48          containersVar.append(QVariant(containerName));
    49          //qDebug()<<"支持的格式:"<
    50      }
    51 
    52      /* 采样率 */
    53      sampleRateVar.append(QVariant(0));
    54      /* 百度语音识别只支持8000、 16000采样率 */
    55      sampleRateVar.append(QVariant(8000));
    56      sampleRateVar.append(QVariant(16000));
    57      for (int sampleRate: m_audioRecorder->supportedAudioSampleRates()) {
    58          sampleRateVar.append(QVariant(sampleRate));
    59          //qDebug()<<"采样率:"<
    60      }
    61 
    62 
    63      /* 通道 */
    64      channelsVar.append(QVariant(-1));
    65      channelsVar.append(QVariant(1));
    66      channelsVar.append(QVariant(2));
    67      channelsVar.append(QVariant(4));
    68 
    69      /* 质量 */
    70      qualityVar.append(QVariant(int(QMultimedia::LowQuality)));
    71      qualityVar.append(QVariant(int(QMultimedia::NormalQuality)));
    72      qualityVar.append(QVariant(int(QMultimedia::HighQuality)));
    73 
    74      /* 比特率 */
    75      bitratesVar.append(QVariant(0));
    76      bitratesVar.append(QVariant(32000));
    77      bitratesVar.append(QVariant(64000));
    78      bitratesVar.append(QVariant(96000));
    79      bitratesVar.append(QVariant(128000));
    80 
    81      /* 录音类信号槽连接 */
    82      connect(m_audioRecorder, &QAudioRecorder::durationChanged,
    83              this, &AudioRecorder::updateProgress);
    84  }
    85 
    86  AudioRecorder::~AudioRecorder()
    87  {
    88  }
    89 
    90 
    91  void AudioRecorder::startRecorder()
    92  {
    93      /* 备注:录音需要设置成16000 采样率和通道数为1,
    94       * 保存为wav文件需要设置成audio/x-wav(container文件格式) */
    95 
    96      /* 如果录音已经停止,则开始录音 */
    97      if (m_audioRecorder->state() == QMediaRecorder::StoppedState) {
    98          /* 设置默认的录音设备 */
    99          m_audioRecorder->setAudioInput(devicesVar.at(0).toString());
    100
    101         /* 下面的是录音设置 */
    102         QAudioEncoderSettings settings;
    103         settings.setCodec(codecsVar.at(0).toString());
    104         settings.setSampleRate(sampleRateVar[2].toInt());
    105         settings.setBitRate(bitratesVar[0].toInt());
    106         settings.setChannelCount(channelsVar[1].toInt());
    107         settings.setQuality(QMultimedia::EncodingQuality(
    108                                 qualityVar[0].toInt()));
    109
    110         /* 以恒定的质量录制,可选恒定的比特率 */
    111         settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);
    112
    113         /* I.MX6ULL第20个支持的格式为 audio/x-wav */
    114         QString container = containersVar.at(20).toString();
    115
    116         /* 使用配置 */
    117         m_audioRecorder->setEncodingSettings(settings,
    118                                              QVideoEncoderSettings(),
    119                                              container);
    120         /* 录音保存为16k.wav文件 */
    121         m_audioRecorder->setOutputLocation(QUrl::fromLocalFile(tr("./16k.wav")));
    122
    123         /* 开始录音 */
    124         m_audioRecorder->record();
    125     }
    126 }
    127
    128 void AudioRecorder::stopRecorder()
    129 {
    130     /* 停止录音 */
    131     m_audioRecorder->stop();
    132 }
    133
    134
    135 void AudioRecorder::updateProgress(qint64 duration)
    136 {
    137     Q_UNUSED(duration);
    138
    139     if (m_audioRecorder->error()
    140             != QMediaRecorder::NoError)
    141         return;
    142
    143     /* 打印录制时长 */
    144     //qDebug()<
    145 }
    146
    147
    148 void AudioRecorder::clearAudioLevels()
    149 {
    150     //...
    151 }
    152
    153 // This function returns the maximum possible sample value for a given audio format
    154 qreal getPeakValue(const QAudioFormat& format)
    155 {
    156     // Note: Only the most common sample formats are supported
    157     if (!format.isValid())
    158         return qreal(0);
    159
    160     if (format.codec() != "audio/pcm")
    161         return qreal(0);
    162
    163     switch (format.sampleType()) {
    164     case QAudioFormat::Unknown:
    165         break;
    166     case QAudioFormat::Float:
    167         if (format.sampleSize() != 32) // other sample formats are not supported
    168             return qreal(0);
    169         return qreal(1.00003);
    170     case QAudioFormat::SignedInt:
    171         if (format.sampleSize() == 32)
    172             return qreal(INT_MAX);
    173         if (format.sampleSize() == 16)
    174             return qreal(SHRT_MAX);
    175         if (format.sampleSize() == 8)
    176             return qreal(CHAR_MAX);
    177         break;
    178     case QAudioFormat::UnSignedInt:
    179         if (format.sampleSize() == 32)
    180             return qreal(UINT_MAX);
    181         if (format.sampleSize() == 16)
    182             return qreal(USHRT_MAX);
    183         if (format.sampleSize() == 8)
    184             return qreal(UCHAR_MAX);
    185         break;
    186     }
    187
    188     return qreal(0);
    189 }
    190
    191 // returns the audio level for each channel
    192 QVector<qreal> getBufferLevels(const QAudioBuffer& buffer)
    193 {
    194     QVector<qreal> values;
    195
    196     if (!buffer.format().isValid() || buffer.format().byteOrder() != QAudioFormat::LittleEndian)
    197         return values;
    198
    199     if (buffer.format().codec() != "audio/pcm")
    200         return values;
    201
    202     int channelCount = buffer.format().channelCount();
    203     values.fill(0, channelCount);
    204     qreal peak_value = getPeakValue(buffer.format());
    205     if (qFuzzyCompare(peak_value, qreal(0)))
    206         return values;
    207
    208     switch (buffer.format().sampleType()) {
    209     case QAudioFormat::Unknown:
    210     case QAudioFormat::UnSignedInt:
    211         if (buffer.format().sampleSize() == 32)
    212             values = getBufferLevels(buffer.constData<quint32>(), buffer.frameCount(), channelCount);
    213         if (buffer.format().sampleSize() == 16)
    214             values = getBufferLevels(buffer.constData<quint16>(), buffer.frameCount(), channelCount);
    215         if (buffer.format().sampleSize() == 8)
    216             values = getBufferLevels(buffer.constData<quint8>(), buffer.frameCount(), channelCount);
    217         for (int i = 0; i < values.size(); ++i)
    218             values[i] = qAbs(values.at(i) - peak_value / 2) / (peak_value / 2);
    219         break;
    220     case QAudioFormat::Float:
    221         if (buffer.format().sampleSize() == 32) {
    222             values = getBufferLevels(buffer.constData<float>(), buffer.frameCount(), channelCount);
    223             for (int i = 0; i < values.size(); ++i)
    224                 values[i] /= peak_value;
    225         }
    226         break;
    227     case QAudioFormat::SignedInt:
    228         if (buffer.format().sampleSize() == 32)
    229             values = getBufferLevels(buffer.constData<qint32>(), buffer.frameCount(), channelCount);
    230         if (buffer.format().sampleSize() == 16)
    231             values = getBufferLevels(buffer.constData<qint16>(), buffer.frameCount(), channelCount);
    232         if (buffer.format().sampleSize() == 8)
    233             values = getBufferLevels(buffer.constData<qint8>(), buffer.frameCount(), channelCount);
    234         for (int i = 0; i < values.size(); ++i)
    235             values[i] /= peak_value;
    236         break;
    237     }
    238
    239     return values;
    240 }
    241
    242 template <class T>
    243 QVector<qreal> getBufferLevels(const T *buffer, int frames, int channels)
    244 {
    245     QVector<qreal> max_values;
    246     max_values.fill(0, channels);
    247
    248     for (int i = 0; i < frames; ++i) {
    249         for (int j = 0; j < channels; ++j) {
    250             qreal value = qAbs(qreal(buffer[i * channels + j]));
    251             if (value > max_values.at(j))
    252                 max_values.replace(j, value);
    253         }
    254     }
    255
    256     return max_values;
    257 }
    258
    259 void AudioRecorder::processBuffer(const QAudioBuffer& buffer)
    260 {
    261     /* 根据通道数目需要显示count个level */
    262     int count = buffer.format().channelCount();
    263     /* 打印通道数 */
    264     Q_UNUSED(count);
    265     // qDebug()<<"通道数"<
    266
    267     /* 设置level的值 */
    268     QVector<qreal> levels = getBufferLevels(buffer);
    269     for (int i = 0; i < levels.count(); ++i) {
    270         /* 打印音量等级 */
    271         // qDebug()<<"音量等级"<
    272     }
    273 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    4/02_asr_demo/audiorecorder/audiorecorder.cpp主要提供了一个startRecorder()和stopRecorder()的接口,录音保存的文件为可执行程序当前路径下的16k.wav文件。startRecorder()和stopRecorder()分别是开始录音和停止录音。
    第54~56行,增加8000和16000的支持项。
    第104行,设置为下标为2的项,也就是16000采样率。
    第106行,设置通道数下标为1的项,也就是单通道。
    第114行,设置文件容器/格式,为audio/x-wav格式(项的下标为20)。设置此格式会保存wav后缀的文件。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    25.5 语音界面UI开发

    项目路径为4/02_asr_demo/02_asr_demo/02_asr_demo.pro,先看项目界面。项目界面如下,界面简洁大气,界面中间用了一个立体的素材,点击后可以旋转,给人一种智能化的感觉,点击时还会有音效提示,文本提示“请点击,开始说话…”,点击后,提示“正在听您说话,请继续…”,录制8s左右的音频,等待返回识别结果即可。编写设计完成的效果不错!请自行查阅源码,掌握了本教程前面第七章的内容,就可以理解这个界面是如何设计的。
    在这里插入图片描述

    25.6 语音识别项目综合测试

    打开4/02_asr_demo/02_asr_demo/02_asr_demo.pro项目,此项目为语音识别UI界面。
    打开项目如下图。
    在这里插入图片描述

    项目文件夹下内容解释:
    02_asr_demo项目下:
    
    • 1
    • 2

    asr文件夹为语音识别的应用程序,主要用来与将录制的音频发送到百度云语音识别服务器上,然后返回识别结果。
    aduiorecorder文件夹为录制wav音频的文件夹。主要是用来录制wav音频。
    led文件夹为I.MX6U开发板控制LED的接口程序。
    Headers文件夹为界面设计的头文件。
    Sources文件夹为界面设计的源文件。

    25.6.1 Ubuntu上运行

    Ubuntu运行后界面如下,注意,Ubuntu需要联网!Ubuntu上理论上是能录制音频识别返回结果的,但是教程主要写正点原子I.MX6U开发板上的语音识别项目。限于编者手上没有可用电脑麦克风,估计读者也没有,电脑配置麦克风输入后可以自行测试。运行之后可以看到下面的界面。Windows不作讲解!请到下面小节使用正点原子I.MX6U ALPHA开发板运行体验识别效果!
    在这里插入图片描述

    25.6.2 ALPHA开发板上运行

    本例适用于正点原子I.MX6U ALPHA开发板!请使用正点原子I.MX6U的出厂系统进行测试!
    请使用正点原子的I.MX6U的出厂时的系统测试!
    请使用正点原子的I.MX6U的出厂时的系统测试!
    请使用正点原子的I.MX6U的出厂时的系统测试!
    重要的事情是说三遍!
    开始录音前,需要根据正点原子I.MX6U用户快速体验手册,第3.15小节进行测试板子的录音功能。确保能正常录音,再交叉编译此Qt应用程序到开发板上运行。如何交叉编译Qt应用程序到开发板,请看【正点原子】I.MX6U 出厂系统Qt交叉编译环境搭建V1.x版本。
    在正点原子I.MX6U开发板上运行此录音程序,需要先配置是麦克风(板子上的麦头)。
    麦头录音,则在板子上运行开启麦头录音的脚本。

    /home/root/shell/audio/mic_in_config.sh
    
    • 1
    交叉编译到开发板上运行效果如下。下面的图都是开发板上的截图。
    程序初始化时。(注意开发板先插上网线联网!确保能上网!)
    
    • 1
    • 2

    在这里插入图片描述

    点击中间的图标后,注意,请在点击1.5~2s后再说话,点击时有音效提醒,避免把音效录进去。整个录音过程是8s左右。
    
    • 1

    在这里插入图片描述

    识别返回结果的过程很快,识别率也挺高,如下图,编者说了一句“正点原子”,语音识别返回“正点原子”的结果。注意,识别是中文标准普通话。请尽量说一些日常话语,避免说生僻语句,特殊的方言等。识别常见问题请查看百度AI开发平台的帮助文档。
    
    • 1

    在这里插入图片描述

    再点击,再次进行语音识别,话语中,包含“开灯”,那么即可点亮板子上的LED。点亮后,再次进行语音识别,话语中包含“关灯”,即可熄灭板子上的LED。
    “开灯”识别结果。
    
    • 1
    • 2

    在这里插入图片描述

    “关灯”识别结果。
    
    • 1

    在这里插入图片描述

    本示例仅供学习参考使用,如需要用到开发上,请购买百度或其他开放平台的语音识别产品。
    
    • 1
  • 相关阅读:
    vuex状态管理(二)超级详细使用教程(包含辅助函数map的使用),一看就会,一学就懂
    H5圣诞特效单页源码
    高可用架构,去中心化有多重要?
    Redis
    Ubuntu18.04 系统没有声音输出的解决过程
    弘玑Cyclone荣登2022「Cloud 100 China」榜单
    给你的 SpringBoot 工程部署的 jar 包瘦瘦身吧!
    一次完整的支付链路
    Go语言进阶,详解并发中的通道机制
    【知识点】深入浅出STL标准模板库
  • 原文地址:https://blog.csdn.net/weixin_55796564/article/details/125891891