【平头哥RVB2601创意应用开发】 八、RVB2601之声音识别代码分析
[复制链接]
一直想完成评测项目的语音识别,但实际操作中不是这个困难,就是这个困难。尤其是每周一篇的评测文章,如果是自己掌握的技术感觉还好,要是学习新的技术,这个压力就太大了,毕竟还是有正式工作的。
网上看了平头哥OCC论坛的语音识别案例,云语音识别
https://occ.t-head.cn/community/post/detail?spm=a2c6h.12873639.article-detail.5.41b02ed0x0yJaQ&id=4018742358014234624
|
用的自建网站,在自建的网站中将RVB2601录制的PCM音频通过ffmep,调整大小端,然后转换WAV格式后,再通过腾讯云的API进行语音识别,转换成TXT文本。
作者开源了项目,再Github上, 。
核心代码主要是音频录制和语音识别
录音部分是根据ch2601_ft_demo修改的
static void cmd_mic_handler()
{
//函数主要来源还是ch2601_ft_demo
csi_error_t ret;
csi_codec_input_config_t input_config;
ret = csi_codec_init(&codec, 0);
if (ret != CSI_OK)
{
printf("csi_codec_init error\n");
return;
}
//一些设置codec相关的变量,以及录音的参数,采样率8000,宽度16
codec_input_ch.ring_buf = &input_ring_buffer;
csi_codec_input_open(&codec, &codec_input_ch, 0);
/* input ch config */
csi_codec_input_attach_callback(&codec_input_ch, codec_input_event_cb_fun, NULL);
input_config.bit_width = 16;
input_config.sample_rate = 8000;
input_config.buffer = input_buf;
input_config.buffer_size = INPUT_BUF_SIZE;
input_config.period = 1024;
input_config.mode = CODEC_INPUT_DIFFERENCE;
csi_codec_input_config(&codec_input_ch, &input_config);
csi_codec_input_analog_gain(&codec_input_ch, 0xbf);
csi_codec_input_link_dma(&codec_input_ch, &dma_ch_input_handle);
printf("start recoder\n");
csi_codec_input_start(&codec_input_ch);
// 麦克风录音写入数据 48x1024=49152
//受限于repeater_data_addr的48K大小,每次1K数据,即1024,共48次
while (new_data_flag < 48)
{
if (cb_input_transfer_flag)
{
csi_codec_input_read_async(&codec_input_ch, repeater_data_addr + (new_data_flag * 1024), 1024);
cb_input_transfer_flag = 0U; // 回调函数将其置 1
new_data_flag++;
}
}
new_data_flag = 0;
printf("stop recoder\n");
csi_codec_input_stop(&codec_input_ch);
csi_codec_input_link_dma(&codec_input_ch, NULL);
csi_codec_input_detach_callback(&codec_input_ch);
csi_codec_uninit(&codec);
return;
}
语音识别部分,是PHP代码完成的
<?php
// 调用腾讯云 SDK 省略
$uploads_dir = 'ch2601_recordings';
if ($_FILES['file']['error'] == UPLOAD_ERR_OK)
{
$tmp_name = $_FILES['file']['tmp_name'];
// $name = $_FILES['file']['name'];
$date_str=date('YmdHis');
move_uploaded_file($tmp_name, "$uploads_dir/$date_str".'-b2.pcm');
// 用 ffmpeg 转码,先转大小端并压缩为 1 通道,再转为 wav 格式
exec('ffmpeg -f s16be -ar 8000 -ac 2 -i '."$uploads_dir/$date_str".'-b2.pcm'.' -f s16le -ar 8000 -ac 1 '."$uploads_dir/$date_str".'-l1.pcm');
exec('ffmpeg -f s16le -ar 8000 -ac 1 -i '."$uploads_dir/$date_str".'-l1.pcm '."$uploads_dir/$date_str".'-l1.wav');
try {
// api 调用部分,省略……
$resp = $client->SentenceRecognition($req);
$result_str=$resp->getResult();
$result_file=fopen("$uploads_dir/$date_str".'.txt',"a");
fwrite($result_file,$result_str);
fclose($result_file);
echo $result_str;
}
catch(TencentCloudSDKException $e) {
echo $e;
}
}
由于缺乏必要的http服务器,这个例程没法完成,于是又在开源网站上找了个基于百度的语音识别项目,SmartSpeaker
分析后,得知语音识别是通过百度API进行的
主要语音识别是调用语音文件,传输到百度openapi.baidu.com进行识别
#include "ff.h"
//语音文件的文件指针(不使用动态分配)
static FIL redAu_fp = {0};
//每次读取的文件大小
static uint32_t ulrByte = 0;
//语音的文件大小的字符串
static char pcConLen[16] = {0};
uint8_t ucNet_Audio2Text(const char *pcfile)
{
if (f_open(&redAu_fp, pcfile, FA_READ) == FR_OK)
{
memset(pcConLen, 0, sizeof(pcConLen));
snprintf(pcConLen, sizeof(pcConLen)-1, "%lld", f_size(&redAu_fp));
memset((char *)pNET_SEND_BUF0, 0, NET_BUFFER_SIZE);
sprintf((char *)pNET_SEND_BUF0, __audio2text, pcTokenBuf, pcConLen);
xSemaphoreTake(xNetLsn_RecBinary, 0);
ucEsp_CIPSTART("TCP", "vop.baidu.com", 80);
//因为涉及到大文件的传输,使用透传会发生数据丢失
ucEsp_CIPMODE(0);
ucEsp_CIPSEND(0xFF, strlen((char *)pNET_SEND_BUF0));
vNet_SendBuf((char *)pNET_SEND_BUF0, strlen((char *)pNET_SEND_BUF0));
if (ucEsp_WaitSendOK())
{
f_close(&redAu_fp);
ucEsp_CIPCLOSE();
return 2;
}
for (;;)
{
memset(pNET_SEND_BUF0, 0, NET_BUFFER_SIZE);
f_read(&redAu_fp, pNET_SEND_BUF0, NET_BUFFER_SIZE, &ulrByte);
ucEsp_CIPSENDBUF(0xFF, ulrByte);
vNet_SendBuf((char *)pNET_SEND_BUF0, ulrByte);
if (ucEsp_WaitSendOK())
{
f_close(&redAu_fp);
ucEsp_CIPCLOSE();
return 2;
}
if(ulrByte < NET_BUFFER_SIZE)
{
break;
}
}
vNet_LsnStart(10000);
f_close(&redAu_fp);
xSemaphoreTake(xNetLsn_RecBinary, portMAX_DELAY);
ucEsp_CIPCLOSE();
return 0;
}
else
{
ts_printf("文件系统异常,请检查!");
f_close(&redAu_fp);
return 1;
}
}
前提是需要开通百度语音识别账号
//请注册百度语音开发者账号,将下面的xxxxxxxx替换为自己申请的ID。
static const char __get_token[] =
{
"GET /oauth/2.0/token?\
grant_type=client_credentials\
&client_id=xxxxxxxxxxxxxx\
&client_secret=xxxxxxxxxxxxxxxx \
HTTP/1.1\r\nHost: openapi.baidu.com\r\n\r\n"
};
static const char __audio2text[] =
{
"POST /server_api?\
lan=zh\
&cuid=xxxxxxxx\
&token=%s \
HTTP/1.1\r\nHost: vop.baidu.com\r\n\
Content-Type: wav;rate=8000\r\nContent-Length: %s\r\n\r\n"
};
转换令牌还需要一定 的步骤
void vNet_ReacquireToken(void)
{
//连接证书服务器
ucEsp_CIPSTART("TCP", "openapi.baidu.com", 80);
//开启透传模式
ucEsp_CIPMODE(1);
//准备发送数据
ucEsp_CIPSEND(0,0);
//把信号量置零
xSemaphoreTake(xNetLsn_RecBinary, 0);
vNet_SendBuf(__get_token, sizeof (__get_token));
vNet_LsnStart(10000);
//等待数据接收完毕
xSemaphoreTake(xNetLsn_RecBinary, portMAX_DELAY);
//发送关闭监听信号量
vNetLsn_Close();
//退出透传模式
ucEsp_BreakSEND();
//关闭透传
ucEsp_CIPMODE(0);
//断开和服务器的连接
ucEsp_CIPCLOSE();
}
原代码用的是ESP8266进行WiFi数据传输的
本来想尝试这个识别的,到百度控制台一看,免费资格应为前面项目申请但未进行,期限过了。
目前打算在讯飞平台或者阿里云平台学习后再进行语音识别项目了。由于评测的每周发表测文要求,就先应付一番了,后面看看是不是先评测GUI方面的?只是这个GUI不在自己提交的评测计划中。
|