Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3167697
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: 嵌入式

2015-02-26 18:51:34

原文地址:http://blog.csdn.net/littlethunder/article/details/17047663

我之前发过我的贪吃蛇的代码,我想把它变成语音控制上下左右的,于是选择科大讯飞的SDK,官方有一些文档,但有一些细节还是会让在linux下开发的孩子们产生困惑比如我,现在总结在此~

        首先下载科大讯飞的SDK-linux版本,需要注册先。。。在下载下来的include文件夹下,有四个文件:msp_errors.h  msp_types.h  qisr.h  qtts.h。前两个是通用的一些数据结构,剩下的qisr.h是语音识别用的头文件,qtts.h是语音合成用的头文件,因为我之需要语音识别的功能,只要在我的代码中include进qisr.h头文件就OK啦。在bin文件夹下比较乱,但主要就是libmsc.so和libspeex.so两个动态库,我直接把这两个动态库拷到/usr/lib里面。

         在bin文件夹下注意到一个asr_keywords_utf8.txt的文件,这个SDK的思路是这样:把自己想识别的文字写到asr_keywords_utf8.txt中,然后上传到讯飞的服务器上,然后返回一个GrammarID,据说上传一次“终身有效”,意思就是不让重复上传占用服务器空间,反正有了这个GrammarID以后在不同的程序中想识别相同的文字就直接用好了,比如我想识别“左,右,上,下,图书馆,独自”,把这些汉字写到asr_keywords_utf8.txt中,而且必须是utf-8的格式,当然在linux下默认如此。下面是我写的上传这个txt并获得GrammarID的代码:


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. #include   
  7.   
  8. #define TRUE 1  
  9. #define FALSE 0  
  10.   
  11. int main()  
  12. {  
  13.     int ret = QISRInit("appid=xxxxxxx");  
  14.     if(ret != MSP_SUCCESS)  
  15.     {  
  16.         printf("QISRInit with errorCode: %d \n", ret);  
  17.         return 0;  
  18.     }  
  19.     char GrammarID[128];  
  20.     memset(GrammarID, 0, sizeof(GrammarID));  
  21.     const int MAX_KEYWORD_LEN = 4096;  
  22.     ret = MSP_SUCCESS;  
  23.     const char * sessionID = NULL;  
  24.       
  25.     sessionID = QISRSessionBegin(NULL, "ssm=1,sub=asr", &ret);  
  26.     if(ret != MSP_SUCCESS)  
  27.     {  
  28.         printf("QISRSessionBegin with errorCode: %d \n", ret);  
  29.         return ret;  
  30.     }  
  31.   
  32.     char UserData[MAX_KEYWORD_LEN];  
  33.     memset(UserData, 0, MAX_KEYWORD_LEN);  
  34.     FILE* fp = fopen("asr_keywords_utf8.txt""rb");  
  35.     if (fp == NULL)  
  36.     {  
  37.         printf("keyword file cannot open\n");  
  38.         return -1;  
  39.     }  
  40.     unsigned int len = (unsigned int)fread(UserData, 1, MAX_KEYWORD_LEN, fp);  
  41.     UserData[len] = 0;  
  42.     fclose(fp);  
  43.     const char* testID = QISRUploadData(sessionID, "contact", UserData, len, "dtt=keylist", &ret);  
  44.     if(ret != MSP_SUCCESS)  
  45.     {  
  46.         printf("QISRUploadData with errorCode: %d \n", ret);  
  47.         return ret;  
  48.     }  
  49.     memcpy((void*)GrammarID, testID, strlen(testID));  
  50.     printf("GrammarID: \"%s\" \n", GrammarID);  
  51.   
  52.     QISRSessionEnd(sessionID, "normal");  
  53.     return 0;  
  54. }  

        这样GrammarID会输出到终端中,记下来就妥了。然后是录制要识别的音频文件,原来不知道要求,直接用ubuntu自带的录音机录了一段,发现总也识别不了,在bbs上问了问题才搞明白,讯飞语音对语音的要求如下:采样率16K或8KHz,采样位是16位,单声道,格式是PCM或WAV。自带的录音软件都是默认32位采样,只能用ffmpeg或自己写代码录制,ffmpeg命令如下:



[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ffmpeg -f alsa -i hw:0 -ar 16000 -ac 1 lib.wav  

        我用普通话录了2秒的“图书馆”音频,下面是识别的代码:



  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. #include   
  7.   
  8. #define TRUE 1  
  9. #define FALSE 0  
  10.   
  11. int run_asr(const char* asrfile);  
  12.   
  13. const int BUFFER_NUM = 4096;  
  14. const int MAX_KEYWORD_LEN = 4096;  
  15.   
  16. int main(int argc, char* argv[])  
  17. {  
  18.     int ret = MSP_SUCCESS;  
  19.     const char* asrfile ="lib.wav";  
  20.     ret = QISRInit("appid=xxxxxx");  
  21.     if(ret != MSP_SUCCESS)  
  22.     {  
  23.         printf("QISRInit with errorCode: %d \n", ret);  
  24.         return 0;  
  25.     }  
  26.   
  27.     ret = run_asr(asrfile);  
  28.     QISRFini();  
  29.     char key = getchar();  
  30.     return 0;  
  31. }  
  32.   
  33.   
  34. int run_asr(const char* asrfile)  
  35. {  
  36.     int ret = MSP_SUCCESS;  
  37.     int i = 0;  
  38.     FILE* fp = NULL;  
  39.     char buff[BUFFER_NUM];  
  40.     unsigned int len;  
  41.     int status = MSP_AUDIO_SAMPLE_CONTINUE, ep_status = -1, rec_status = -1, rslt_status = -1;  
  42.   
  43.     //const char* GrammarID="e7eb1a443ee143d5e7ac52cb794810fe";  
  44.     const char *GrammarID="c66d4eecd37d4fe1c8274a2224b832d5";  
  45.     const char* param = "rst=json,sub=asr,ssm=1,aue=speex,auf=audio/L16;rate=16000";//注意sub=asr  
  46.     const char* sess_id = QISRSessionBegin(GrammarID, param, &ret);  
  47.     if ( MSP_SUCCESS != ret )  
  48.     {  
  49.         printf("QISRSessionBegin err %d\n", ret);     
  50.         return ret;  
  51.     }  
  52.   
  53.     fp = fopen( asrfile , "rb");  
  54.     if ( NULL == fp )  
  55.     {  
  56.         printf("failed to open file,please check the file.\n");  
  57.         QISRSessionEnd(sess_id, "normal");  
  58.         return -1;  
  59.     }  
  60.   
  61.     printf("writing audio...\n");  
  62.     //  
  63.     int count=0;  
  64.     //  
  65.     while ( !feof(fp) )  
  66.     {  
  67.         len = (unsigned int)fread(buff, 1, BUFFER_NUM, fp);  
  68.         feof(fp) ? status = MSP_AUDIO_SAMPLE_LAST : status = MSP_AUDIO_SAMPLE_CONTINUE;  
  69.         if(status==MSP_AUDIO_SAMPLE_LAST)      
  70.             printf("MSP_AUDIO_SAMPLE_LAST\n");  
  71.         if(status==MSP_AUDIO_SAMPLE_CONTINUE)  
  72.             printf("MSP_AUDIO_SAMPLE_CONTINUE\n");  
  73.         //  
  74.         ret = QISRAudioWrite(sess_id, buff, len, status, &ep_status, &rec_status);  
  75.         if ( ret != MSP_SUCCESS )  
  76.         {  
  77.             printf("\nQISRAudioWrite err %d\n", ret);  
  78.             break;  
  79.         }  
  80.         //  
  81.         printf("%d\n",count++);  
  82.         //  
  83.         if ( rec_status == MSP_REC_STATUS_SUCCESS )  
  84.         {  
  85.             const char* result = QISRGetResult(sess_id, &rslt_status, 0, &ret);  
  86.             if (ret != MSP_SUCCESS )  
  87.             {  
  88.                 printf("error code: %d\n", ret);  
  89.                 break;  
  90.             }  
  91.             else if( rslt_status == MSP_REC_STATUS_NO_MATCH )  
  92.                 printf("get result nomatch\n");  
  93.             else  
  94.             {  
  95.                 if ( result != NULL )  
  96.                     printf("get result[%d/%d]:len:%d\n %s\n", ret, rslt_status,strlen(result), result);  
  97.             }  
  98.         }  
  99.         printf(".");  
  100.     }  
  101.     printf("\n");  
  102.   
  103.     if (ret == MSP_SUCCESS)  
  104.     {     
  105.         printf("get reuslt~~~~~~~\n");  
  106.         char asr_result[1024] = "";  
  107.         unsigned int pos_of_result = 0;  
  108.         int loop_count = 0;  
  109.         do   
  110.         {  
  111.             const char* result = QISRGetResult(sess_id, &rslt_status, 0, &ret);  
  112.             if ( ret != 0 )  
  113.             {  
  114.                 printf("QISRGetResult err %d\n", ret);  
  115.                 break;  
  116.             }  
  117.   
  118.             if( rslt_status == MSP_REC_STATUS_NO_MATCH )  
  119.             {  
  120.                 printf("get result nomatch\n");  
  121.             }  
  122.             else if ( result != NULL )  
  123.             {  
  124.                 //  
  125.                 FILE*f=fopen("data.txt","wb");  
  126.                 printf("~~~%d\n",strlen(result));  
  127.                 fwrite(result,1,strlen(result),f);  
  128.                 fclose(f);  
  129.                 //  
  130.                 printf("[%d]:get result[%d/%d]: %s\n", (loop_count), ret, rslt_status, result);  
  131.                 strcpy(asr_result+pos_of_result,result);  
  132.                 pos_of_result += (unsigned int)strlen(result);  
  133.             }  
  134.             else  
  135.             {  
  136.                 printf("[%d]:get result[%d/%d]\n",(loop_count), ret, rslt_status);  
  137.             }  
  138.             usleep(500000);  
  139.         } while (rslt_status != MSP_REC_STATUS_COMPLETE && loop_count++ < 30);  
  140.         if (strcmp(asr_result,"")==0)  
  141.         {  
  142.             printf("no result\n");  
  143.         }  
  144.   
  145.     }  
  146.   
  147.     QISRSessionEnd(sess_id, NULL);  
  148.     printf("QISRSessionEnd.\n");  
  149.     fclose(fp);   
  150.   
  151.     return 0;  
  152. }  

输出结果如下:



[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. kl@kl-Latitude:~/xunfeiSDK$ ./a.out   
  2. writing audio...  
  3. MSP_AUDIO_SAMPLE_CONTINUE  
  4. 0  
  5. .MSP_AUDIO_SAMPLE_CONTINUE  
  6. 1  
  7. .MSP_AUDIO_SAMPLE_CONTINUE  
  8. 2  
  9. .MSP_AUDIO_SAMPLE_CONTINUE  
  10. 3  
  11. .MSP_AUDIO_SAMPLE_CONTINUE  
  12. 4  
  13. .MSP_AUDIO_SAMPLE_CONTINUE  
  14. 5  
  15. .MSP_AUDIO_SAMPLE_CONTINUE  
  16. 6  
  17. .MSP_AUDIO_SAMPLE_CONTINUE  
  18. 7  
  19. .MSP_AUDIO_SAMPLE_CONTINUE  
  20. 8  
  21. .MSP_AUDIO_SAMPLE_CONTINUE  
  22. 9  
  23. .MSP_AUDIO_SAMPLE_CONTINUE  
  24. 10  
  25. .MSP_AUDIO_SAMPLE_CONTINUE  
  26. 11  
  27. .MSP_AUDIO_SAMPLE_CONTINUE  
  28. 12  
  29. .MSP_AUDIO_SAMPLE_CONTINUE  
  30. 13  
  31. .MSP_AUDIO_SAMPLE_CONTINUE  
  32. 14  
  33. .MSP_AUDIO_SAMPLE_CONTINUE  
  34. 15  
  35. .MSP_AUDIO_SAMPLE_CONTINUE  
  36. 16  
  37. .MSP_AUDIO_SAMPLE_CONTINUE  
  38. 17  
  39. .MSP_AUDIO_SAMPLE_CONTINUE  
  40. 18  
  41. .MSP_AUDIO_SAMPLE_CONTINUE  
  42. 19  
  43. .MSP_AUDIO_SAMPLE_CONTINUE  
  44. 20  
  45. .MSP_AUDIO_SAMPLE_CONTINUE  
  46. 21  
  47. .MSP_AUDIO_SAMPLE_CONTINUE  
  48. 22  
  49. .MSP_AUDIO_SAMPLE_LAST  
  50. 23  
  51. .  
  52. get reuslt~~~~~~~  
  53. [0]:get result[0/2]  
  54. ~~~123  
  55. [1]:get result[0/5]: {"sn":1,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"sc":"85","gm":"0","w":"图书馆","mn":[{"contact":"图书馆"}]}]}]}  
  56. QISRSessionEnd.  

        这个输出格式是个坑,因为官方的例子默认是直接输出识别的结果,但是结果是GB2312格式的,在linux终端下是乱码,后来才搞明白,在QISRSessionBegin()函数初始化的时候第二个参数param中的rst改成json,就是按照json格式把所有结果全输出来后,是utf8格式的汉字,之后再用json模块来解就妥妥的了~整体代码很清晰,简单说一下:


1.先要调用QISRInit()函数,参数是自己的appid,每个SDK都是注册才能下载的,所以是唯一的,用来区分用户的,不同级别的用户每天可以使用SDK的次数有限制,毕竟人用的多了语音识别的性能肯定会下降;

2.之后就是把GrammarID,输入输出的参数param和调用状态返回值ret作为参数传入QISRSessionBegin()函数中进行初始化,返回值是sessionID,这个是后面所有函数的主要参数之一;

3.打开自己的音频文件,调用QISRAudioWrite()函数写入,可以分段也可以一次,第一个参数是sessionID,上面初始化函数返回的值,第二个参数是音频数据头指针,第三个参数是音频文件大小,第四个参数是音频发送的状态,表示发送完了没有,剩下两个是服务器端检测语音状态和识别状态的返回值;

4.调用QISRGetResult()函数获取识别的结果,第一个参数还是sessionID,第二个参数是输出识别的状态,第三个参数是与服务器交互的间隔时间,官方建议5000,我取为0,第四个参数是调用状态返回值ret,最后这个函数的返回值就是上面结果的json数据了;

5.最后的收尾清理工作,毕竟是C语言,不是java~哈哈



阅读(2506) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~