我的程序时基于科大讯飞的语音识别库开发的,你能开发出什么样的产品,当然依赖你得到的库。
如果你的库只是试用版,只能添加30个词条,识别率在20%以下,等等你是开发不了好的产品的,我要介绍的程序是用的是试用版的库,添加的词条少,识别率低。还有要注意的就是,你必须有他们的很多头文件,还有线程,词条处理的两个执行cpp文件
下面我介绍下 我的功能需求,开发过程和具体细节。。。
主要是 1语音库初始化。 2.添加语音词条设置场景, 3.语音录入处理, 4识别结果输出,,
1.语音库的初始化,
对象创建需要调用API“EsrCreate”,如下ivStatus ivCall EsrCreate (ivHandle ivPtr phEsrObj,ivPCUserOS pUserOS);
参数1,是定义一个空句柄,在ivDefine.h文件中(这是一个库内定义的参数,不许管,只要包含了头文件,就可以用了。大概需要这些头文件,ivDefine.h ivEsrDefine.h ivESR.h ivEsrDefine.h ivPlatform.h ivErrorCode.h 线程执行文件 Thread.h Thread.cpp记录文件 Record.h Record.cpp)
参数2 ,库内定义的参数,在ivEsrDefine.h文件总,主要语音库的初始化是针对此对象的初始化,属性很多。。
初始化的具体过程 (回调函数全在下面。。) /* Aitalk对象句柄 */ivHandle m_hEsrObj; /* 用户回调参数 */TUserData m_tUserData;/* 识别服务线程句柄 */HANDLE m_hESRThread;
//开始
TUserOS tUserOS;
memset(&tUserOS, 0, sizeof(TUserOS));
@ 1 //对象大小 序列号(必填)
tUserOS.nSize = sizeof(TUserOS);
tUserOS.lpszLicence =(ivStrA)"你得到的库的序列号,否则库是没法使用的";
@ 2 //用户平台是否支持动态内存分配
tUserOS.lpfnRealloc = CBRealloc; //不支持 tUserSys.lpfnRealloc = ivNull;
tUserOS.lpfnFree= CBFree; //不支持 tUserSys.lpfnFree = ivNull;
@ 3 //用户必须实现的回调函数
其中CBOpenFile、CBCloseFile和CBReadFile是需要用户实现的打开、关闭和读取文件的回调函数,以Windows平台unicode字符集为例
tUserOS.lpfnReadFile = CBReadFile;
tUserOS.lpfnOpenFile = CBOpenFile;
tUserOS.lpfnCloseFile = CBCloseFile;
@ 4 //用户软件平台是否支持写文件操作?
tUserOS.pPersisRAM = ivNull; //不支持tUserSys.pRAM = USER_WORKBUFFER_ADDRESS;
tUserOS.nPersisRAMSize = 0; //不支持tUserSys.nRAMSize = USER_WORKBUFFER_BYTES;
tUserOS.lpfnWriteFile = CBWriteFile; //tUserSys.lpfnWriteFile = ivNull;
//USER_WORKBUFFER_ADDRESS 表示静态分配的Work Buffer的地址;
//USER_WORKBUFFER_BYTES 表示静态分配的Work Buffer的尺寸(字节数);
@ 5//用户是否希望进行资源数据校验?
希望:
tUserSys.bCheckResource = ivTrue; // 希望:
tUserSys.bCheckResource = ivFalse; //不希望:
tUserOS.lpfnMsgProc = CBMsgProc; //消息回调函数
m_tUserData.fpLog = _tfopen(_T("Aitalk4.0Log.esl"), _T("wb"));
m_tUserData.pThis = this;
tUserOS.pUser = (ivPointer)&m_tUserData;
ivStatus iStatus;
iStatus = EsrCreate(&m_hEsrObj, &tUserOS);
_ASSERT(ivErr_OK == iStatus);
用户必须实现的回调函数
/* 内存分配回调函数 */
ivPointer ivCall CBRealloc(ivPointer pUser, ivPointer p,ivSize nSize)
{
return realloc(p,nSize);
}
/* 内存释放回调函数 */
void ivCall CBFree(ivPointer pUser, ivPointer p)
{
free(p);
}
/* 打开文件回调函数 */
ivHandle ivCall CBOpenFile(ivPointer pUser, ivCStr lpFileName,ivInt enMod,ivInt enType)
{
FILE* pf;
TCHAR szFileName[MAX_PATH];
TCHAR* lpszMod;
if(ivResFile == enType){
_stprintf(szFileName, _T("%s"), _T(".\\Resource\\"));
}
else{
_stprintf(szFileName, _T("%s"), _T(".\\"));
}
_tcscat(szFileName,(TCHAR *)lpFileName);
if(ivModWrite == enMod){
lpszMod = _T("wb");
}
else{
lpszMod = _T("rb");
}
pf = _tfopen(szFileName,lpszMod);
return (ivHandle)pf;
}
/* 关闭文件回调函数 */
ivBool ivCall CBCloseFile(ivPointer pUser, ivHandle hFile)
{
return (0 == fclose((FILE*)hFile));
}
/* 读文件回调函数 */
ivBool ivCall CBReadFile(ivPointer pUser, ivHandle hFile,ivPByte pBuffer,ivUInt32 iPos,ivSize nSize)
{
FILE* pf = (FILE*)hFile;
ivSize nRead;
/* 注意:当iPos值为FILE_POS_CURRENT时表示文件当前位置,不能调用fseek类函数 */
if(FILE_POS_CURRENT != iPos){
fseek(pf,iPos,SEEK_SET);
}
nRead = fread(pBuffer,1,nSize,pf);
_ASSERT(nRead == nSize);
return nRead == nSize;
}
/* 写文件回调函数 */
ivBool ivCall CBWriteFile(ivPointer pUser, ivHandle hFile,ivPCByte pBuffer,ivUInt32 iPos,ivSize nSize)
{
FILE* pf = (FILE*)hFile;
ivSize nWrite;
/* 注意:当iPos值为FILE_POS_CURRENT时表示文件当前位置,不能调用fseek类函数 */
if(FILE_POS_CURRENT != iPos){
fseek(pf,iPos,SEEK_SET);
}
nWrite = fwrite(pBuffer,1,nSize,pf);
_ASSERT(nWrite == nSize);
return nWrite == nSize;
}
/* 消息回调函数 */
ivStatus ivCall CBMsgProc(ivPointer pUser, ivHandle hObj,ivUInt32 uMsg,ivUInt32 wParam,ivCPointer lParam)
{
PUserData pUser1 = (PUserData)EsrGetUserData(hObj);
RRESULT err;
CAitalkSample *pThis = (CAitalkSample *)pUser1->pThis;
switch(uMsg)
{
case ivMsg_ToSleep:
Sleep(wParam);
break;
case ivMsg_Create:
InitializeCriticalSection(&pUser1->tCriticalSection);
break;
case ivMsg_Destroy:
DeleteCriticalSection(&pUser1->tCriticalSection);
break;
case ivMsg_ToEnterCriticalSection:
/* 调用EnterCriticalSection时用户需保证其参数的有效性 */
EnterCriticalSection(&pUser1->tCriticalSection);
break;
case ivMsg_ToLeaveCriticalSection:
/* 调用LeaveCriticalSection时用户需保证其参数的有效性 */
LeaveCriticalSection(&pUser1->tCriticalSection);
break;
case ivMsg_SpeechStart:
pThis->OnSpeechStart();
break;
case ivMsg_SpeechEnd:
break;
case ivMsg_SpeechFlushEnd:
break;
case ivMsg_NoSpeechDetected:
break;
case ivMsg_ResponseTimeout:
pThis->OnResponseTimeOut();
break;
case ivMsg_SpeechTimeout:
pThis->OnSpeechTimeOut();
break;
case ivMsg_ToStartAudioRec:
err = pThis->StartRecord();
if(err != RECORD_ERR_OK){
return ivErr_FALSE;
}
break;
case ivMsg_ToStopAudioRec:
err = pThis->StopRecord();
if(err != RECORD_ERR_OK){
return ivErr_FALSE;
}
break;
case ivMsg_Result:
pThis->OnResult((WPARAM)wParam, (LPARAM)lParam);
break;
case ivMsg_LOG:
fwrite(lParam, wParam, 1, pUser1->fpLog);
fflush(pUser1->fpLog);
return ivErr_FALSE;
}
return ivErr_OK;
}
/* “语音开始”消息处理函数 */
void CAitalkSample::OnSpeechStart()
{
printf("%s\r\n", "Speech started!");
}
/* “反应超时”消息处理函数 */
void CAitalkSample::OnResponseTimeOut()
{
printf("%s\r\n", "Response time out!");
EsrExitService(m_hEsrObj);
}
/* “语音超时”消息处理函数 */
void CAitalkSample::OnSpeechTimeOut()
{
printf("%s\r\n", "Speech time out!");
EsrExitService(m_hEsrObj);
}
/* “有识别结果”消息处理函数 */
void CAitalkSample::OnResult(WPARAM wParam, LPARAM lParam)
{
printf("%s\r\n", "Results arrive!");
PCEsrResult pResult = (PCEsrResult)lParam;
ivUInt32 nBest = (ivUInt32)wParam;
ivUInt32 i, j, k;
FILE *fp;
//只发一条消息
ivCStrW pText1;
setlocale(LC_ALL, "chs");
/* 将结果输出到Result.txt文件中 */
fp = _tfopen(_T("Result.txt"), _T("wb"));
ivUInt32 n = 0xfeff;
fwrite(&n, 2, 1, fp);
for(i = 0; i < nBest; ++ i){
fwprintf(fp, L"第%d候选 Best:\r\n", i + 1);
for(j = 0; j < pResult->nSlot; j ++){
for(k = 0; k < pResult->pSlots[j].nItem; ++ k){
ivCStrW pText = pResult->pSlots[j].pItems[k].pText;
fwprintf(fp, L"%s", (TCHAR*)pText); //(TCHAR *)pText
pText1=pText;
}
}
fwprintf(fp, L"\r\n");
pResult ++;
}
//发送出数据
//sendMsg(pText1);
fclose(fp);
EsrExitService(m_hEsrObj);
}
按照上述过程会实现对语音库的初始化, 为后续的添加词条添加场景,创造条件。。。