基于科大讯飞语音云windows平台开发

前记:

前段时间公司没事干,突发奇想想做一个语音识别系统,看起来应该很简单的,但做起来却是各种问题,这个对电气毕业的我,却是挺为难的。谷姐已经离我们而去,感谢度娘,感谢CSDN各位大神,好歹也做的是那么回事了,虽然还是不好用,但基本功能实现了。

该软件使用VS2008C++/CLR开发,由于科大讯飞提供的是C的API接口,结果到这边就是各种不兼容,CLR是基于托管堆运行的,而这个API有是非托管堆的,使用了各种指针,原本打算使用C#来做,最后门外汉的我也没能做到C#和C指针完美结合,真怀恋单片机写代码的年代啊。还有录音方面需要directX是的支持。软件下载地址:http://download.csdn.net/detail/liucheng5037/7509003

软件运行界面如下图所示:


左边实现文字转语音,需要在文本框中输入文字,然后根据需要配置好声音,音量,速度选项,点击播放,软件会先通过讯飞的API获取语音,然后以设定的方式播放出来。

右边实现语音转文字,直接按住button说话,松开后软件通过讯飞的API将语音信息传递给语音云,最后返回文字显示在文本框。

看起来很简单的东西折腾了我不少时间啊!!!

系统组成

该系统由4部分组成:讯飞云、语音录入、语音播放、系统控制。语音播放和讯飞云封装在一个类XunFeiSDK里面,语音录入使用的是网上找的基于DirectX的类SoundRecord,基于C#写的,本想把录入也写到讯飞云那个类里去,结果说什么非托管的类不能有基于托管堆的成员,无奈只有单独出来,作为一个dll文件存在。系统控制是在form类里面。

讯飞语音云:

        (先复制一段官方说法)

讯飞移动语音平台是基于讯飞公司已有的ISP 和IMS 产品,开发出的一款符合移动互联网用户使用的语音应用开发平台,提供语音合成、语音听写、语音识别、声纹识别等服务,为语音应用开发爱好者提供方便易用的开发接口,使得用户能够基于该开发接口进行多种语音应用开发。其主要功能有:

1)实现基于HTTP 协议的语音应用服务器,集成讯飞公司最新的语音引擎,支持语音合成、语音听写、语音识别、声纹识别等服务;

2)提供基于移动平台和PC 上的语音客户端子系统,内部集成音频处理和音频编解码模块,提供关于语音合成、语音听写、语音识别和声纹识别完善的API。

(复制完毕)

由于只想写的玩玩,没有太多时间,故直接把官方C语言写的demo复制过来,转变成一个类。官方提供了一个dll文件一个lib文件还有一堆H文件。具体执行的代码时封装在dll文件里的,我们看不到,我们需要引入lib文件来间接调用语音函数。引入lib的方式如下:

[cpp]  view plain
  1. #ifdef _WIN64  
  2. #pragma comment(lib,"../lib/msc_x64.lib")//x64  
  3. #else  
  4. #pragma comment(lib,"../lib/msc.lib")//x86  
  5. #endif  

然后需要include下面几个H文件:

[cpp]  view plain
  1. #include "../include/qisr.h"  
  2. #include "../include/qtts.h"  
  3. #include "../include/msp_cmn.h"  
  4. #include "../include/msp_errors.h"  

类XunFeiSDK不能使用ref来修饰,不然又是各种托管堆和非托管堆不能互通之类的报错。讯飞语音一个转换来回如下:

讯飞语音详细的说明可以到这里下载http://open.voicecloud.cn/index.php/services/voicebase?type=tts&tab_index=1

选择windowsSDK开发包,里面有一些简单的demo和说明,不过需要事先注册才能下载。

有一点要注意的是,语音返回的音频格式是PCM这种格式和wav很像,一般支持WAV的播放器都支持PCM。不同的语音播放方式如普通话女声和东北话使用的语音引擎不同,具体可参考类SoundType。

登录可以在软件打开时执行,登出可以在软件关闭时执行,中间的转换每次需要执行一次,因为每次执行的sessionID不一样,每次需要重新发起会话。


语音录入:

这一部分花的时间比较长,刚开始时什么都不知道啊,一点录入的概念都没有,完全不知道该调用什么API,用什么控件,只有到处百度,试了各种办法,最后,果然CSDN是大神出没的地方,被我找到了,地址如下:C#中使用DirectSound录音

这个类封装的很好,就只有3个函数。

SetFileName():录音文件存放位置和名称

RecStart():开始录音

RecStop():结束录音

整个录音过程是在一个单独线程上运行的,不会影响主程序运行。

C#DLL文件移植到C++的方法:

1、使用#using把文件包含进来#using "SoundRecord.dll";

2、增加命名空间usingnamespace VoiceRecord;

3、声明一个对象,注意类名不可以和命名空间名一致,这样虽然声称dll时不会出错,但编译会出错, SoundRecord^ recorder;

语音播放

该部分比较简单,直接使用了System::Media命名空间下的类SoundPlayer,在使用时直接gcnew一个对象,然后load(),然后play(),当然,load可以不要的。这个play可以支持播放PCM和WAV格式语音,其他格式未试验。

系统控制部分

在这一部分声明了一个静态的XunFeiSDK类指针,还有一个录音类的托管对象,还有转换进程等。

[cpp]  view plain
  1. static XunFeiSDK* xunfei;  
  2. static SoundRecord^ recorder;  
  3. Thread^ xunfei_thread;  

音频转文字部分采用了单独线程,由于子线程不可以访问主线程的form控件,无奈又加了个定时器和标志位来检测子线程是否完成,网上说可以采用委托的方式来访问控件,但本人实在弄不懂委托,只有放弃,这一部分做的很单片机的style。

在文字转语音部分没有采用进程,会有在这里卡一会。

知识点

1、由于使用的是讯飞的C库,又用到了C++/CLR的form,托管堆和非托管堆的鸿沟很麻烦。

本程序使用了微软提供的转换函数。需要include的内容:


[cpp]  view plain
  1. #include <windows.h>  
  2. #include <string>  
  3. #include <iostream>  
  4. #include <sstream>  
  5. include <msclr\marshal.h>  

a、std::string转const char *

const char *strp=str.c_str();

b、System::String^转 string 和 const char*

Stringstd_str = (constchar*)(Marshal::StringToHGlobalAnsi(nowTime.ToString(Sys_str))).ToPointer();

c、char* 转 System::String^

Sys_str = Marshal::PtrToStringAnsi((IntPtr)char_str);

d、int 转 std::String

ostringstreamoss1;

oss1<<int_num;

std_str = oss1.str();

2、同一文件下,若一个类需要使用另一个类,则需要在前面声明一下,这和C函数类似。

Eg:refclass SoundType;

3、在非托管类下,不能使用托管类作为成员;实例化托管对象需要使用gcnew,实例化非托管对象直接使用new。

4、对List之类的对象,可以直接添加任何对象,包括form上的List,比如ComboBox,显示是显示该对象的ToString方法。

TOString方法重载:


[cpp]  view plain
  1. virtual System::String^ ToString() override//重载ToString方法  
  2.     {  
  3.         return voice;  
  4.     }  

5、switchcase 不支持string类型的值输入。

 

部分源代码如下:

[cpp]  view plain
  1. //类XunFeiSDK  
  2. /* 
  3.  string str("hello"); 
  4.  const char *strp=str.c_str();    string转const char* 
  5. */  
  6. //#using "Microsoft.DirectX.DirectSound.dll"  
  7. //#using "Microsoft.DirectX.dll"  
  8.   
  9. #include "../SoundTest/stdafx.h"  
  10. //#include "stdafx.h"  
  11. #include "stdlib.h"  
  12. #include "stdio.h"  
  13. #include <windows.h>  
  14. #include <conio.h>  
  15. #include <errno.h>  
  16. #include <iostream>  
  17. #include <sstream>  
  18. #include <fstream>  
  19. #include <time.h>  
  20. #include <string>  
  21. #include <msclr\marshal.h>  
  22.   
  23. using namespace std;  
  24.   
  25. #include "../include/qisr.h"  
  26. #include "../include/qtts.h"  
  27. #include "../include/msp_cmn.h"  
  28. #include "../include/msp_errors.h"  
  29.   
  30.   
  31.   
  32. #ifdef _WIN64  
  33. #pragma comment(lib,"../lib/msc_x64.lib")//x64  
  34. #else  
  35. #pragma comment(lib,"../lib/msc.lib")//x86  
  36. #endif  
  37.   
  38. #define DebugPrint(str_x,msg_y) fprintf(out_file,(str_x),(msg_y))  
  39.   
  40. typedef int SR_DWORD;  
  41. typedef short int SR_WORD ;  
  42.   
  43. //音频头部格式  
  44. struct wave_pcm_hdr  
  45. {  
  46.     char            riff[4];                        // = "RIFF"  
  47.     SR_DWORD        size_8;                         // = FileSize - 8  
  48.     char            wave[4];                        // = "WAVE"  
  49.     char            fmt[4];                         // = "fmt "  
  50.     SR_DWORD        dwFmtSize;                      // = 下一个结构体的大小: 16  
  51.   
  52.     SR_WORD         format_tag;              // = PCM : 1  
  53.     SR_WORD         channels;                       // = 通道数: 1  
  54.     SR_DWORD        samples_per_sec;        // = 采样率: 8000 | 6000 | 11025 | 16000  
  55.     SR_DWORD        avg_bytes_per_sec;      // = 每秒字节数: dwSamplesPerSec * wBitsPerSample / 8  
  56.     SR_WORD         block_align;            // = 每采样点字节数: wBitsPerSample / 8  
  57.     SR_WORD         bits_per_sample;         // = 量化比特数: 8 | 16  
  58.   
  59.     char            data[4];                        // = "data";  
  60.     SR_DWORD        data_size;                // = 纯数据长度: FileSize - 44   
  61. } ;  
  62.   
  63. //默认音频头部数据  
  64. const struct wave_pcm_hdr default_pcmwavhdr =   
  65. {  
  66.     { 'R''I''F''F' },  
  67.     0,  
  68.     {'W''A''V''E'},  
  69.     {'f''m''t'' '},  
  70.     16,  
  71.     1,  
  72.     1,  
  73.     16000,  
  74.     32000,  
  75.     2,  
  76.     16,  
  77.     {'d''a''t''a'},  
  78.     0    
  79. };  
  80.   
  81. namespace SoundTest {  
  82.     using namespace System;  
  83.     using namespace System::Runtime::InteropServices;  
  84.     using namespace System::Media;  
  85.     using namespace msclr::interop;  
  86.     ref class SoundType;  
  87.   
  88.     public class XunFeiSDK{  
  89.       
  90.     privateFILE* out_file;//输出log文件  
  91.              string appid;  
  92.              int ret;  
  93.              string pcm_path;//存储音频文件的文件名  
  94.              string user;  
  95.              string password;  
  96.              string voice_type;//语言类型  
  97.              string volunm;//音量0-10  
  98.              string engin;//引擎  
  99.              string voice_speed;//语速-10  
  100.                
  101.     public: XunFeiSDK()  
  102.             {  
  103.                 DateTime nowTime = DateTime::Now;  
  104.                 string nowTimes = (const char*)(Marshal::StringToHGlobalAnsi(nowTime.ToString("yyyy-MM-dd HH:mm:ss"))).ToPointer();  
  105.                 fopen_s(&out_file,"log.txt","at+");  
  106.                 if(out_file == NULL)  
  107.                 {  
  108.                     ret = -1;  
  109.                     return;  
  110.                 }  
  111.                 fseek(out_file, 0, 2);  
  112.                 fprintf(out_file,"begin Time:%s \n",nowTimes.c_str());  
  113.   
  114.                 appid = "";  
  115.                 user = "";  
  116.                 password = "53954218";//可以上官网注册专属自己的ID   
  117.                 pcm_path = "PCM_SPEED.pcm";  
  118.                 voice_type = "xiaoyan";  
  119.                 volunm = "7";  
  120.                 voice_speed = "5";  
  121.                 engin = "intp65";  
  122.             }  
  123.              ~XunFeiSDK()  
  124.             {  
  125.                 string nowTimes = (const char*)(Marshal::StringToHGlobalAnsi(DateTime::Now.ToString("yyyy-MM-dd HH:mm:ss"))).ToPointer();  
  126.                 fprintf(out_file,"Time:%s end\n",nowTimes.c_str());  
  127.                 fclose(out_file);  
  128.             }  
  129.   
  130.     publicint status()  
  131.             {  
  132.                 return ret;  
  133.             }  
  134.   
  135.             bool Login()//登录  
  136.             {  
  137.                 string logins = "appid = " + appid + ",work_dir =   .  ";  
  138.                 ret = MSPLogin(user.c_str(), password.c_str(), logins.c_str());  
  139.                 if ( ret != MSP_SUCCESS )  
  140.                 {  
  141.                     fprintf(out_file,"MSPLogin failed , Error code %d.\n",ret);  
  142.                     return false;  
  143.                 }  
  144.                 return true;  
  145.             }  
  146.   
  147.             void Logout()  
  148.             {  
  149.                 MSPLogout();//退出登录  
  150.             }  
  151.   
  152.             int TextToSpeed(System::String^ Ssrc_text)//字符串转音频,音频存放在PCM_SPEED.pcm下  
  153.             {  
  154.                 #pragma region 字符串转音频  
  155.                 struct wave_pcm_hdr pcmwavhdr = default_pcmwavhdr;  
  156.                 const char* sess_id = NULL;  
  157.                 unsigned int text_len = 0;  
  158.                 char* audio_data = NULL;  
  159.                 unsigned int audio_len = 0;  
  160.                 int synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA;  
  161.                 FILE* fp = NULL;  
  162.                 string params = "vcn=xiaoyan, spd = 50, vol = 50";//参数可参考可设置参数列表  
  163.                 ret = -1;//失败  
  164.                 //参数配置  
  165.                 params = "vcn=" + voice_type + ", spd = " + voice_speed + ", vol = " + volunm + ", ent = "+engin;  
  166.                 const char* src_text = (const char*)(Marshal::StringToHGlobalAnsi(Ssrc_text)).ToPointer();  
  167.   
  168.                 pcm_path = "PCM_SPEED.pcm";  
  169.   
  170.                 fprintf(out_file,"begin to synth source = %s\n",src_text);  
  171.                 if (NULL == src_text)  
  172.                 {  
  173.                     fprintf(out_file,"params is null!\n");  
  174.                     return ret;  
  175.                 }  
  176.                 text_len = strlen(src_text);//获取文本长度  
  177.                   
  178.                 fopen_s(&fp,pcm_path.c_str(),"wb");//打开PCM文件  
  179.                 if (NULL == fp)  
  180.                 {  
  181.                     fprintf(out_file,"open PCM file %s error\n",pcm_path);  
  182.                     return ret;  
  183.                 }  
  184.   
  185.                 sess_id = QTTSSessionBegin(params.c_str(), &ret);//开始一个会话                 
  186.                 if ( ret != MSP_SUCCESS )  
  187.                 {  
  188.                     fprintf(out_file,"QTTSSessionBegin: qtts begin session failed Error code %d.\n",ret);  
  189.                     return ret;  
  190.                 }  
  191.                 fprintf(out_file,"sess_id = %s\n",sess_id);  
  192.                 ret = QTTSTextPut(sess_id, src_text, text_len, NULL );//发送txt信息  
  193.                 if ( ret != MSP_SUCCESS )  
  194.                 {  
  195.                     fprintf(out_file,"QTTSTextPut: qtts put text failed Error code %d.\n",ret);  
  196.                     QTTSSessionEnd(sess_id, "TextPutError");//异常,结束  
  197.                     return ret;  
  198.                 }  
  199.                 fwrite(&pcmwavhdr, sizeof(pcmwavhdr) ,1, fp);//把开始文件写到最前面  
  200.   
  201.                 while (1)//循环读取音频文件并存储  
  202.                 {  
  203.                     const void *data = QTTSAudioGet(sess_id, &audio_len, &synth_status, &ret);  
  204.                     if (NULL != data)  
  205.                     {  
  206.                         fwrite(data, audio_len, 1, fp);  
  207.                         pcmwavhdr.data_size += audio_len;//修正pcm数据的大小  
  208.                     }  
  209.                     if (synth_status == MSP_TTS_FLAG_DATA_END || ret != 0)   
  210.                         break;  
  211.                 }//合成状态synth_status取值可参考开发文档  
  212.   
  213.                 //修正pcm文件头数据的大小  
  214.                 pcmwavhdr.size_8 += pcmwavhdr.data_size + 36;  
  215.   
  216.                 //将修正过的数据写回文件头部  
  217.                 fseek(fp, 4, 0);  
  218.                 fwrite(&pcmwavhdr.size_8,sizeof(pcmwavhdr.size_8), 1, fp);  
  219.                 fseek(fp, 40, 0);  
  220.                 fwrite(&pcmwavhdr.data_size,sizeof(pcmwavhdr.data_size), 1, fp);  
  221.                 fclose(fp);  
  222.   
  223.                 ret = QTTSSessionEnd(sess_id, NULL);  
  224.                 if ( ret != MSP_SUCCESS )  
  225.                 {  
  226.                     fprintf(out_file,"QTTSSessionEnd: qtts end failed Error code %d.\n",ret);  
  227.                 }  
  228.                 fprintf(out_file,"program end");  
  229.                 return ret;  
  230.                 #pragma endregion  
  231.             }  
  232.   
  233.             System::String^ GetPcmName()//获取音频文件路径  
  234.             {  
  235.                 return gcnew String(pcm_path.c_str());  
  236.             }  
  237.               
  238.             int Play(System::String^ text)//播放音频文件  
  239.             {  
  240.                 if(text == ""return -1;  
  241.                 SoundPlayer^ player = (gcnew SoundPlayer(text));//音频播放器  
  242.                 player->SoundLocation = text;  
  243.                 player->Load();  
  244.                 player->Play();  
  245.                 return 0;  
  246.             }  
  247.   
  248.             int StartRecord()//开始录音  
  249.             {  
  250.               
  251.             }  
  252.   
  253.             int EndRecord()//结束录音  
  254.             {  
  255.               
  256.             }  
  257.   
  258.             System::String^ SpeedToText(System::String^ text)//语音转文字,输入语音文件名,返回文字信息  
  259.             {  
  260.                 System::String^ Sys_value = "No data return";  
  261.                 const char* src_wav_filename = (const char*)(Marshal::StringToHGlobalAnsi(text)).ToPointer();  
  262.                 //test = Marshal::PtrToStringAnsi((IntPtr)(char *)src_text);  
  263.                 //return test;  
  264.                 char rec_result[1024] = {0};//存放返回结果  
  265.                 const char *sessionID = NULL;  
  266.                 FILE *f_pcm = NULL;//  
  267.                 char *pPCM = NULL;//存放音频文件缓存  
  268.                 int lastAudio = 0 ;  
  269.                 int audStat = MSP_AUDIO_SAMPLE_CONTINUE ;  
  270.                 int epStatus = MSP_EP_LOOKING_FOR_SPEECH;  
  271.                 int recStatus = MSP_REC_STATUS_SUCCESS ;  
  272.                 long pcmCount = 0;  
  273.                 long pcmSize = 0;//音频文件大小  
  274.                 int errCode = 10 ;  
  275.                 string param = "sub=iat,auf=audio/L16;rate=16000,aue=speex-wb,ent=sms16k,rst=plain,rse=gb2312";  
  276.   
  277.                 fprintf(out_file,"Start iat...\n");  
  278.                 sessionID = QISRSessionBegin(NULL, param.c_str(), &errCode);//开始一路会话  
  279.                 fopen_s(&f_pcm,src_wav_filename, "rb");  
  280.                 if (NULL != f_pcm) {  
  281.                     fseek(f_pcm, 0, SEEK_END);  
  282.                     pcmSize = ftell(f_pcm);//获取音频大小  
  283.                     fseek(f_pcm, 0, SEEK_SET);  
  284.                     pPCM = (char *)malloc(pcmSize);//分配内存存放音频  
  285.                     fread((void *)pPCM, pcmSize, 1, f_pcm);  
  286.                     fclose(f_pcm);  
  287.                     f_pcm = NULL;  
  288.                 }//读取音频文件,读到pPCM中  
  289.                 else  
  290.                 {  
  291.                     fprintf(out_file,"media %s not found\n",src_wav_filename);  
  292.                     return Sys_value;  
  293.                 }  
  294.   
  295.                 while (1) {//开始往服务器写音频数据  
  296.                 unsigned int len = 6400;  
  297.                 int ret = 0;  
  298.                 if (pcmSize < 12800) {  
  299.                     len = pcmSize;  
  300.                     lastAudio = 1;//音频长度小于  
  301.                 }  
  302.                 audStat = MSP_AUDIO_SAMPLE_CONTINUE;//有后继音频  
  303.                 if (pcmCount == 0)  
  304.                     audStat = MSP_AUDIO_SAMPLE_FIRST;  
  305.                 if (len<=0)  
  306.                 {  
  307.                     break;  
  308.                 }  
  309.                 fprintf(out_file,"csid=%s,count=%d,aus=%d,",sessionID,pcmCount/len,audStat);  
  310.                 ret = QISRAudioWrite(sessionID, (const void *)&pPCM[pcmCount], len, audStat, &epStatus, &recStatus);//写音频  
  311.                 fprintf(out_file,"eps=%d,rss=%d,ret=%d\n",epStatus,recStatus,errCode);  
  312.                 if (ret != 0)  
  313.                 break;  
  314.                 pcmCount += (long)len;  
  315.                 pcmSize -= (long)len;  
  316.                 if (recStatus == MSP_REC_STATUS_SUCCESS) {  
  317.                     const char *rslt = QISRGetResult(sessionID, &recStatus, 0, &errCode);//服务端已经有识别结果,可以获取  
  318.                     fprintf(out_file,"csid=%s,rss=%d,ret=%d\n",sessionID,recStatus,errCode);  
  319.                     if (NULL != rslt)  
  320.                         strcat_s(rec_result,rslt);  
  321.                 }  
  322.                 if (epStatus == MSP_EP_AFTER_SPEECH)  
  323.                     break;  
  324.                 Sleep(150);//模拟人说话时间间隙  
  325.                 }  
  326.                 QISRAudioWrite(sessionID, (const void *)NULL, 0, MSP_AUDIO_SAMPLE_LAST, &epStatus, &recStatus);//写入结束  
  327.                 free(pPCM);  
  328.                 pPCM = NULL;  
  329.                 while (recStatus != MSP_REC_STATUS_COMPLETE && 0 == errCode) {  
  330.                     const char *rslt = QISRGetResult(sessionID, &recStatus, 0, &errCode);//获取结果  
  331.                     fprintf(out_file,"csid=%s,rss=%d,ret=%d\n",sessionID,recStatus,errCode);  
  332.                     if (NULL != rslt)  
  333.                     {  
  334.                         strcat_s(rec_result,rslt);  
  335.                     }  
  336.                     Sleep(150);  
  337.                 }  
  338.                 QISRSessionEnd(sessionID, NULL);  
  339.                 fprintf(out_file,"The result is: %s\n",rec_result);  
  340.                 if(NULL != rec_result)//不为空时返回正确值  
  341.                 Sys_value = Marshal::PtrToStringAnsi((IntPtr)rec_result);//数值转换  
  342.   
  343.                 return Sys_value;  
  344.             }  
  345.   
  346.             void set_tts_params(System::String^ e_voice_type , System::String^ e_engin , int e_volunm , int e_speed)  
  347.             {  
  348.                 const char* src_text = (const char*)(Marshal::StringToHGlobalAnsi(e_voice_type)).ToPointer();  
  349.                 voice_type = src_text;  
  350.                 src_text = (const char*)(Marshal::StringToHGlobalAnsi(e_engin)).ToPointer();  
  351.                 engin = src_text;  
  352.                 ostringstream oss1;  
  353.                 ostringstream oss2;  
  354.                 oss1<<e_volunm;  
  355.                 volunm = oss1.str();//音量  
  356.                 oss2<<e_speed;  
  357.                 voice_speed = oss2.str();//语速  
  358.             }  
  359.               
  360.     };  
  361.   
  362.     public ref class SoundType{  
  363.     public: System::String^ engin;//语音引擎  
  364.             System::String^ voice_type;//说话类型  
  365.             System::String^ voice;//显示  
  366.   
  367.             SoundType(System::String^ e_voice)//switch case 不支持string的输入  
  368.             {  
  369.                 voice = e_voice;  
  370.   
  371.                 if (e_voice == "普通话女声") {engin = "intp65";voice_type = "xiaoyan";}  
  372.                 else if(e_voice == "普通话男声") {engin = "intp65";voice_type = "xiaoyu";}  
  373.                 else if(e_voice == "英文女声") {engin = "intp65_en";voice_type = "Catherine";}  
  374.                 else if(e_voice == "英文男声") {engin = "intp65_en";voice_type = "henry";}  
  375.                 else if(e_voice == "粤语") {engin = "vivi21";voice_type = "vixm";}  
  376.                 else if(e_voice == "台湾话") {engin = "vivi21";voice_type = "vixl";}  
  377.                 else if(e_voice == "四川话") {engin = "vivi21";voice_type = "vixr";}  
  378.                 else if(e_voice == "东北话") {engin = "vivi21";voice_type = "vixyun";}  
  379.                 else {engin = "intp65";voice_type = "xiaoyan";voice = "普通话女声";}  
  380.   
  381.             }  
  382.             SoundType()  
  383.             {  
  384.                 engin = "intp65";voice_type = "xiaoyan";voice = "普通话女声";  
  385.             }  
  386.   
  387.             virtual System::String^ ToString() override//重载ToString方法  
  388.             {  
  389.                 return voice;  
  390.             }  
  391.   
  392.     };  
  393.   
  394. }  


FORM类:

局部变量:

[cpp]  view plain
  1. privatestatic XunFeiSDK* xunfei;  
  2. private: Thread^ xunfei_thread;  
  3.          static int end_flag;  
  4.          static String^ end_result;  
  5.          ArrayList^ voice_types;  
  6. privatestatic SoundRecord^ recorder;  

[cpp]  view plain
  1. #pragma region 控件触发函数  
  2.     private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {  
  3.                  xunfei = (new XunFeiSDK());  
  4.                  end_flag = 0;  
  5.                  if(-1 == xunfei->status())  
  6.               {  
  7.                   MessageBox::Show("初始化失败");  
  8.                   this->Close();//关闭窗体  
  9.                   return;                 
  10.               }  
  11.                  if(!(xunfei->Login()))  
  12.               {  
  13.                   MessageBox::Show("登录失败");  
  14.                   this->Close();//关闭窗体  
  15.                   return;  
  16.               }  
  17.                  volunm_lab->Text = "音量 " + volunm_bar->Value;  
  18.                  speed_lab->Text = "速度 " + speed_bar->Value;  
  19.              }  
  20.     private: System::Void Form1_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) {  
  21.                  xunfei->Logout();//登出  
  22.                  delete xunfei;//必须释放才会调用析构函数  
  23.                  delete recorder;  
  24.              }  
  25.   
  26.     private: System::Void play_tts_btn_Click(System::Object^  sender, System::EventArgs^  e) {  
  27.                 // tts_status_lab->Text = "先转换,再播放语音";  
  28.                  set_xunfei_param();//参数设置  
  29.                  if(-1 == xunfei->TextToSpeed(txt_speak->Text))  
  30.                  {  
  31.                      MessageBox::Show("转换失败");  
  32.                  }  
  33.                  else  
  34.                  {  
  35.                      xunfei->Play(xunfei->GetPcmName());  
  36.                  }         
  37.              }  
  38.   
  39.     private: System::Void speak_btn_MouseDown(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {  
  40.                  StartRecord();//开始录音线程  
  41.                  status_lab->Text = "录音中.....";  
  42.              }  
  43.   
  44.     private: System::Void speak_btn_MouseUp(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {  
  45.                  status_lab->Text = "结束录音,转换中...";  
  46.                  xunfei_thread = (gcnew Thread(gcnew ThreadStart(EndRecord)));  
  47.                  xunfei_thread->Start();  
  48.              }  
  49.     private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {  
  50.                  if(1 == end_flag)  
  51.                  {  
  52.                      end_flag = 0;  
  53.                      result_box->Text = end_result;  
  54.                      status_lab->Text = "转换结束";  
  55.                  }  
  56.              }  
  57.     private: System::Void volunm_bar_Scroll(System::Object^  sender, System::EventArgs^  e) {  
  58.                  volunm_lab->Text = "音量 " + volunm_bar->Value;  
  59.              }  
  60.     private: System::Void speed_bar_Scroll(System::Object^  sender, System::EventArgs^  e) {  
  61.                  speed_lab->Text = "速度 " + speed_bar->Value;  
  62.              }  
  63. #pragma endregion   
  64.   
  65. #pragma region 自定义函数  
  66.     privatevoid set_xunfei_param()//讯飞语音参数设置  
  67.              {  
  68.                  SoundType^ sound_type;  
  69.   
  70.                  sound_type = (SoundType^)(voice_type->SelectedItem);//获取选中的对象  
  71.                  xunfei->set_tts_params(sound_type->voice_type , sound_type->engin , volunm_bar->Value , speed_bar->Value);        
  72.              }  
  73.     privatestatic void StartRecord()  
  74.              {  
  75.                  recorder = (gcnew SoundRecord());  
  76.                  recorder->SetFileName("record.wav");  
  77.                  recorder->RecStart();   //开始录音          
  78.              }  
  79.   
  80.     private:static void EndRecord()  
  81.             {  
  82.                 //  String text;  
  83.                 recorder->RecStop();  
  84.                 delete recorder;  
  85.                 end_result = xunfei->SpeedToText("record.wav");//录音结束,显示语音转换结果                     
  86.                 end_flag = 1;  
  87.             }  
  88. #pragma endregion   


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值