本项目做出的产品是一个Windows下的增强现实系统,系统很庞大,产品功能已经基本完善,考虑到给用户带来更好的体验,故综合评估后采用讯飞语音识别方案进行嫁接。

项目介绍:

1)打开系统时启动语音识别,检测到用户说出关键词(如:上一步,下一步,结束等)时,系统自动进行相应的操作;

2)不需要按任何按键进行连续的语音识别控制,延迟为2秒左右;

3)可以识别词语,句子,中文,英文数字字母通吃,不限语速。并且语句结束判断机制很智能;

3)离线!离线!现在做一个基于windows的离线的语音识别系统在网络上还真没谁,讯飞自己也还没有推出这款SDK,我是在讯飞的离线命令词识别SDK开发包上开发出的介于两者之间功能的系统。

为什么用讯飞:

之前使用过语音识别开发版,用驻极体采集声音,通过串口传输信号来进行识别,只能讲开发版只适合用来做个课程设计啥的玩玩,做产品还是太LOW,识别率地下并且识别范围窄,貌似只能识别数字字母;之后调查过汉语语音识别库如Sphinx,Julius,百度语音等。去网上问,很多人推荐这些方案的,我没试过,不过一个SDK也只有自己正真开发过才知道好不好用强不强大,说的再牛逼也是在别人手上玩的转,到你这就不一定了。我用讯飞就是看上它的鲁棒,免费,毕竟是久经考验的平台,讯飞有一个开发者论坛,开发别人的SDK有个社区很重要,不然有问题没地方问。

项目开发经验与源码如下:

一、跑通讯飞离线命令词识别SDK

首先去讯飞官网下载相应SDK,要注册登录,绑定产品才能下载,下载后跑一跑给的demo,跑不通的话去讯飞的论坛找答案。

我用的demo是asr_record_demo,这个demo可以实现的功能是按下R键从mic中录制缓冲音频并按下S键后进行识别。

稍微看一看这个demo中的东西吧,把该删的东西删了,该修整的修整,玩转了demo才能进一步做移植。

二、文件分析与移植

把SDK包中的需要的.lib  .h  .c和所需要的其余文件拷贝到项目相应的文件夹去,最好是分个类,看起来比较清楚。它比较重要的几个文件有以下几个:

msc.lib   讯飞语音离线命令词识别所依赖的库(X64版本为msc_x64.lib)才15KB就能有如此强大的功能。

call.bnf    采用巴科斯范式语法规则的自定义语法库(call是根据自己需要命名的),用来编写语音识别过程中的语法规则,这个语法写的好语音识别更智能。

speech_recognizer.c  基于录音接口和MSC接口封装一个MIC录音识别的模块,SDK的主要文件

winrec.c  封装windows录音,Windows平台下SDK的主要文件

好了,既然demo已经知道怎么用了,把demo所依赖的所有文件和库照搬进自己的项目去,就可以在自己的项目中调用讯飞的函数了(注意头文件和库文件的路径问题)。

三、使用讲解

先看看我的语法文件

call.bnf:

巴科斯范式语法语法文件怎么写在讯飞的论坛里有很多资源自己去看吧,我写的比较简单,写得好的语法可以更加智能。

大致讲讲源码:

为了看起来简洁,我在speech_recognizer.h中做了一个类SR,把主文件中的一些函数定义和一些宏搬进去。

speech_recognizer.h:

class SR {
public:const char * ASR_RES_PATH = "fo|res/asr/common.jet";  //离线语法识别资源路径
#ifdef _WIN64const char * GRM_BUILD_PATH = "res/asr/GrmBuilld_x64";  //构建离线语法识别网络生成数据保存路径
#elseconst char * GRM_BUILD_PATH = "res/asr/GrmBuilld";  //构建离线语法识别网络生成数据保存路径
#endifconst char * GRM_FILE = "call.bnf"; //构建离线识别语法网络所用的语法文件int build_grammar(UserData *udata);//构建语法int run_asr(UserData *udata);//启动引擎};

speech_recognizer.c:

#pragma comment(lib,"../../lib/msc_x64.lib") //x64
#else
#pragma comment(lib,"XXXXXX/lib/msc.lib") //x86
#endif

这里的库目录要注意,用相对路径可能找不到文件,可以使用绝对路径

#ifdef _WIN64
<pre name="code" class="cpp">static int update_format_from_sessionparam(const char * session_para, WAVEFORMATEX *wavefmt)
{char *s;/*if ((s = strstr(session_para, "sample_rate"))) {if (s = strstr(s, "=")) {s = skip_space(s);if (s && *s) {wavefmt->nSamplesPerSec = atoi(s);wavefmt->nAvgBytesPerSec = wavefmt->nBlockAlign * wavefmt->nSamplesPerSec;}}elsereturn -1;}else {return -1;}*/return 0;
}

如果加到讯飞提供的demo使用的是VS2010如果放到VS2015中就会出一些语法上的错,自己看着改一改,比如上面这个函数,是更新用户词典用的,我不需要但是又存在语法错误,就把它的内容直接注释掉得了。

我的项目的主文件中:

首先定义几个宏:

UserData asr_data;//语音识别用户配置
speech_rec asr;//麦克风输入存储结构体
SR sr;//语音识别实体
string SPEAKER="";//用于缓存语音识别内容

在程序初始化处配置如下:

openVoiceRecognizer = true;//语音识别开关if (openVoiceRecognizer){const char *login_config = "appid = XXXXX"; //登录参数int ret = 0;ret = MSPLogin(NULL, NULL, login_config); //第一个参数为用户名,第二个参数为密码,传NULL即可,第三个参数是登录参数if (MSP_SUCCESS != ret) {printf("登录失败:%d\n", ret);openVoiceRecognizer = false;}memset(&asr_data, 0, sizeof(UserData));printf("构建离线识别语法网络...\n");ret = sr.build_grammar(&asr_data);  //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建if (MSP_SUCCESS != ret) {printf("构建语法调用失败!\n");openVoiceRecognizer = false;}while (1 != asr_data.build_fini)_sleep(300);if (MSP_SUCCESS != asr_data.errcode)_sleep(300);printf("离线识别语法网络构建完成,开始识别...\n");ret = sr.run_asr(&asr_data);//预启动语音识别引擎}

在初始化这里我修改了 sr.run_asr(&asr_data);这个函数,我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。

void recognize_mic(const char* session_begin_params)  //根据自己项目需要写的语音识别预热函数
{int errcode;HANDLE helper_thread = NULL;struct speech_rec_notifier recnotifier = {on_result,on_speech_begin,on_speech_end};errcode = sr_init(&asr, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);if (errcode) {printf("speech recognizer init failed\n");return;}/*    while (1) {errcode = sr_start_listening(&asr);//我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。}exit:sr_uninit(&asr);*/
}int SR::run_asr(UserData *udata)
{char asr_params[MAX_PARAMS_LEN] = { NULL };const char *rec_rslt = NULL;const char *session_id = NULL;const char *asr_audiof = NULL;FILE *f_pcm = NULL;char *pcm_data = NULL;long pcm_count = 0;long pcm_size = 0;int last_audio = 0;int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;int ep_status = MSP_EP_LOOKING_FOR_SPEECH;int rec_status = MSP_REC_STATUS_INCOMPLETE;int rss_status = MSP_REC_STATUS_INCOMPLETE;int errcode = -1;int aud_src = 0;//离线语法识别参数设置_snprintf(asr_params, MAX_PARAMS_LEN - 1,         //<span style="font-family: Arial, Helvetica, sans-serif;">离线语法识别参数根据自己的需要进行更改</span>"engine_type = local, \asr_res_path = %s, sample_rate = %d, \grm_build_path = %s, local_grammar = %s, ",sr.ASR_RES_PATH,SAMPLE_RATE_16K,sr.GRM_BUILD_PATH,udata->grammar_id);recognize_mic(asr_params);return 0;
}

而后是三个语音识别的中间过程和结果处理的函数:

void on_result(const char *result, char is_last)   //根据自己的需要写结果处理
{char *p = "上一步";char *pq = "下一步";char *q = "扫频仪操作演示";char *end1 = "结束";char *end2 = "退出";if (strstr(result, p)) {SPEAKER = "上一步";    }else if (strstr(result, pq)) {SPEAKER = "下一步";}else if (strstr(result, q)) {SPEAKER = "扫频仪操作演示";}else if (strstr(result,end1)|| strstr(result, end2)) {SPEAKER = "退出";}cout << SPEAKER << endl;
}
void on_speech_begin()
{if (g_result){free(g_result);}g_result = (char*)malloc(BUFFER_SIZE);g_buffersize = BUFFER_SIZE;memset(g_result, 0, g_buffersize);printf("Start Listening...\n");
}
void on_speech_end(int reason)
{if (reason == END_REASON_VAD_DETECT)printf("\nSpeaking done \n");elseprintf("\nRecognizer error %d\n", reason);
}

最后就是在自己项目哪里需要语音识别就在哪里抛出缓冲线程启动识别引擎:

if (openVoiceRecognizer) {sr_start_listening(&asr);//抛出缓冲线程进行语音识别if (SPEAKER=="下一步") {keyPressed(' ');}else if (SPEAKER == "上一步") {keyPressed('b');}else if (SPEAKER == "扫频仪操作演示") {keyPressed('1');}else if (SPEAKER=="退出") {std::exit(0);}SPEAKER = "";}

上面代码中的关键就是sr_start_listening(&asr);这个函数,前面也说了这是从run_asr()调用的方法中抽离出来的,抽离出来后run_asr()就变成了预热函数,只需在程序初始化的时候调用它后面的语音识别就不要重复调用了,节省资源。

必须要说说这个关键函数sr_start_listening(&asr);

这是讯飞这款SDK中不需要动的最后一个封装好的函数,里面的东西不要动,前面的东西配置好一调用它就可以进行语音识别了,这个函数中的东西是这款SDK的精华,实现过程很复杂不需要管,但是要记住它的几个特性:

1)一调用它就相当于抛出了一个带缓冲的新线程,这个线程独立进行语音的识别可以不干扰项目的主循环的进行。

2)这个线程寿命是自动的,程序一开始启动到这里调用这个函数后启动线程,当程序的主循环又回来这里不会重复启动这个线程,而是该线程识别完用户的语音判断语句结束机制触发后才待命,等待下一次循环的启动。这句话有些费解,用我的项目解释下:我的项目在update()函数中调用sr_start_listening(&asr); 我的update()函数每100毫秒循环一次,第一次循环启动这个函数,抛出线程进行语音识别,语音识别用了10秒结束,在这10秒过程中update()循环了100次,但是只启动该函数一次,第101次循环的时候就可以第二次启动该函数了,同时在上面代码片中我用SPEAKER转存的字符串的判断条件已经成立,就可以进行相应的操作了,在这里我触发了不同的按键来代替各种操作。

3)举个栗子,我在update()中可以在每一次循环时画一帧图片的方式实现一个视频的播放,而在这里面调用语音引擎sr_start_listening(&asr);,在引擎识别的过程中会不会中断视频的播放或者视频出现卡帧或迟滞呢?答案是不会,上面也解释了,这个函数抛出一个独立的线程,不影响主函数的循环。所以可以用这种方法实现用语音控制视频的播放:快进、后退、暂停、截屏、全屏、音量加大、切换到高清......是不是很酷!

上面的几个源码文件我打了个包,下载看可能更清楚:

http://download.csdn.net/detail/sac761/9647029

四、总结

我用这个方案实现了离线的语音控制系统,语音识别率达到百分之九十以上,而且词语句子中英文通吃,实时性强,系统鲁棒。

畅想一下用这个方法加方案开发这几个产品:

语音控制的媒体播放器,功能在上面也讲了,很酷的!

语音控制的PPT遥控器

语音控制的AR/VR系统

语音交互智能眼镜

.............

利用讯飞语音识别技术开发离线语音控制系统(Windows平台)相关推荐

  1. 语音识别技术原理是什么 讯飞语音识别技术特点介绍【详解】

    语音识别技术原理简介 自动语音识别技术(Auto Speech Recognize,简称ASR)所要解决的问题是让计算机能够"听懂"人类的语音,将语音中包含的文字信息"提 ...

  2. 让计算机开口说话教案,生活创客系列教学设计:第十三节 利用讯飞语音合成技术让掌控板开口说话 —掌控板与讯飞语音合成...

    一.项目内容 项目背景:在同学们的作品中,都用到了物联网.同学们又提出了问题:联网后,同伴发来了文字信息,但我们不可能长期看着掌控板的屏幕,咋办?能否让掌控板把文字朗读出来? 可以!今天,我们就一起尝 ...

  3. 【Demo】iOS平台上的讯飞语音识别语音合成开发

    官方文档:http://www.xfyun.cn/doccenter/iOS 目前开放的服务: 准备工作 需要到讯飞官网注册一个开发账号,注册后登录并创建一个新的应用,添加需要的服务(语音听写.语音合 ...

  4. 集成讯飞SDK,实现离线命令词、离线语音合成、离线唤醒,语音在线/离线听写

    关于讯飞开发平台的注册以及SDK下载:## ##请参考: http://blog.csdn.net/weixin_39923324/article/details/78924892 强烈推荐 分享一个 ...

  5. 讯飞语音识别和唤醒开发示例

    讯飞语音识别和唤醒开发示例 最近需要用到讯飞的语音识别和语音唤醒的功能,就对这方面进行了一下简单研究. 本文帮助大家简单入门,并且提供几个代码示例给大家参考. 讯飞开发者网址:https://www. ...

  6. 讯飞语音识别_赛诺语音输入法报告 搜狗、讯飞、百度AI语音输入哪家强

    哪款输入法最好用?这是一个不同人不同答案的问题.如今生活节奏加快,使用手机打字格外追求效率.因此,输入速度和准确率成为用户考量输入法好用程度最关键因素.目前,语音输入成为有效提高用户沟通效率的一大突破 ...

  7. html语音输入功能讯飞,win10系统利用讯飞语音输入法实现电脑语音输入的方案介绍...

    有关win10系统利用讯飞语音输入法实现电脑语音输入的操作方法想必大家有所耳闻.但是能够对win10系统利用讯飞语音输入法实现电脑语音输入进行实际操作的人却不多.其实解决win10系统利用讯飞语音输入 ...

  8. python实时语音智能聊天<讯飞语音识别+青云客机器人>

    python基于 讯飞语音识别实现语音智能聊天 GitHub项目链接:https://github.com/superzhangjc/python-Voice_chat.git

  9. 让图片说出声音来(利用讯飞API实现图片转文字和文字转语音)

    k思路:调用讯飞的图片识别和语音输出的API实现图片转文字和语音 **APPID,APIKey,APISecret自己在讯飞网站注册即可**,免费使用的,填在img_audio.php文件最后对应的位 ...

  10. 腾讯、百度、讯飞 语音识别

    一.腾讯语音识别-一句话语音识别 1.账号申请 (1)搜索腾讯云官网 https://cloud.tencent.com/?fromSource=gwzcw.2212127.2212127.22121 ...

最新文章

  1. java程序猿必读的学习书籍,良心推荐!
  2. 再见面试官:你能说说 Spring 框架中 Bean 的生命周期吗?
  3. jQuery的三种$()
  4. 什么是长连接和短连接?(长链接、短链接)什么时候使用长连接、短链接?
  5. 哈佛大学计算机与科学,Harvard的CS「哈佛大学计算机科学专业」
  6. RabbitMQ队列持久化
  7. java工程师试卷,Java工程师试卷A
  8. 一些非常值得人深思的段子 .
  9. 107 岁的 IBM 以 340 亿美元吞下了 25 岁的“小”红帽!
  10. 【转】Dubbo架构设计详解
  11. scala 偏函数与 map/collect
  12. 缺陷检测算法matlab,MATLAB 基于模板匹配的玻璃瓶口缺陷检测
  13. python描述_Python描述符(Descriptor)入门
  14. JCreator Error : Invalid path
  15. 编写VTK文件,导入paraview显示
  16. android自定义网络请求框架,安卓快速开发框架(十九)XBaseAndroid Http网络请求
  17. 上海互联网整体沉沦:盛大巨人全没落 8年没出一个马云
  18. 怎样用计算机传输文件,如何在两台电脑之间传输几百G的文件?教你一招
  19. docker 清理磁盘
  20. Typora添加参考文献

热门文章

  1. 计算机窗口的基本组成部分组成部分,windows7窗口的主要组成部分有哪些
  2. re2正则表达式引擎学习(四)
  3. AI产品经理,如何面对数据挖掘?
  4. docker安装gamit_科学网—ubuntu下安装gamit 安装 - 贺小星的博文
  5. 亿佰特Wifi模块、蓝牙模块和Zigbee模块协议在物联网智能家居上的应用指南
  6. 液化石油气(LPG)的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  7. canvas抖音八卦时钟,轻喷
  8. wps的广告怎么彻底关闭
  9. Elixir Meetup 相关不相关的一些感触
  10. python三大神器之一装饰器