MainFrm.cpp
上传用户:lczygg
上传日期:2007-07-03
资源大小:2947k
文件大小:15k
源码类别:

语音合成与识别

开发平台:

Visual C++

  1. // MainFrm.cpp : implementation of the CMainFrame class
  2. //
  3. #include "stdafx.h"
  4. #include "Bedlamite.h"
  5. #include "MainFrm.h"
  6. #include "direct.h"
  7. #include "CommandEngine.h"
  8. #include "BedlamiteView.h"
  9. #include "staticview.h"
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. /////////////////////////////////////////////////////////////////////////////
  16. #define WAITTIMER 10 // 等待用户提问、回答的定时器
  17. #define OVERTIME 3 // 超时时间
  18. #define OVERTIMES 2 // 超时次数
  19. #define REJECT_NUM 5
  20. #define WRITEPORT 0x378
  21. #define READPORT 0x379
  22. int g_nQNum = ROBOT_ANSWER_COUNT;
  23. int g_nStatus = 0;
  24. extern int g_nDeviceID;
  25. extern BOOL g_bPlayEnd;
  26. extern int PlayFileAsync(int& wDeviceID, char *szWaveFileName, HWND hWnd);
  27. extern int StopPlayFileAsync(int& wDeviceID, HWND hWnd);
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CMainFrame
  30. IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
  31. BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
  32. //{{AFX_MSG_MAP(CMainFrame)
  33. ON_WM_CREATE()
  34. ON_WM_TIMER()
  35. //}}AFX_MSG_MAP
  36. // Global help commands
  37. ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFinder)
  38. ON_COMMAND(ID_HELP, CFrameWnd::OnHelp)
  39. ON_COMMAND(ID_CONTEXT_HELP, CFrameWnd::OnContextHelp)
  40. ON_COMMAND(ID_DEFAULT_HELP, CFrameWnd::OnHelpFinder)
  41. ON_MESSAGE(WM_NEWUTTERANCE, OnBeginUtterance)
  42. ON_MESSAGE(WM_ADDWAVEFRAME, OnAddWaveFrame)
  43. ON_MESSAGE(WM_ENDUTTERANCE, OnEndUtterance)
  44. ON_MESSAGE(WM_DRAGONVOICE_FIRM, OnDragonFirm)
  45. ON_MESSAGE(WM_DRAGONVOICE_GETVOLUME, OnDragonGetVolume)
  46. ON_MESSAGE(MM_MCINOTIFY, OnMyPlayEnd)
  47. ON_MESSAGE(WM_PLAYTIME, OnPlayTime)
  48. END_MESSAGE_MAP()
  49. static UINT indicators[] =
  50. {
  51. ID_SEPARATOR,           // status line indicator
  52. ID_INDICATOR_CAPS,
  53. ID_INDICATOR_NUM,
  54. ID_INDICATOR_SCRL,
  55. };
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CMainFrame construction/destruction
  58. CMainFrame::CMainFrame()
  59. {
  60. m_nOvertime = 0;
  61. m_nGetVol = 0;
  62. m_nLocalH = -1;
  63. m_nDegree = 0;
  64. m_bRun = FALSE;
  65. m_bSection = FALSE;
  66. m_bHave = FALSE;
  67. m_sScroll = "";
  68. m_aryList.RemoveAll();
  69. }
  70. CMainFrame::~CMainFrame()
  71. {
  72. theApp.m_bSetTiemr = FALSE;
  73. StopPlayFileAsync(g_nDeviceID, this->m_hWnd);
  74. g_bPlayEnd = TRUE;
  75. Sleep(100);
  76. FreeResource();
  77. theApp.m_LogTrace.WriteLine("释放资源");
  78. }
  79. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
  80. {
  81. if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
  82. return -1;
  83. if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
  84. | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
  85. !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
  86. {
  87. TRACE0("Failed to create toolbarn");
  88. return -1;      // fail to create
  89. }
  90. //Insert Control of CMD
  91. CRect rc(5, 8, 50, 20);
  92. m_pEditCMD = new CEdit;
  93. m_pEditCMD = (CEdit *)m_wndToolBar.InsertControl(RUNTIME_CLASS(CEdit), 
  94. _T(""), rc, IDC_STATIC_CMD, WS_TABSTOP | ES_READONLY | ES_RIGHT);
  95. m_pEditCMD->SetWindowText("命令集:");
  96. rc = CRect(0,0,100,120);
  97. m_pcmbCMD =(CComboBox *) m_wndToolBar.InsertControl(RUNTIME_CLASS(CComboBox), 
  98. _T(""), rc, IDC_CMD, WS_VSCROLL | CBS_DROPDOWNLIST);
  99. m_pcmbCMD->AddString(_T("Default"));
  100. m_pcmbCMD->AddString(_T("CMDST_CMD1"));
  101. m_pcmbCMD->AddString(_T("CMDST_CMD2"));
  102. m_pcmbCMD->SetCurSel(0);
  103. //Insert Control of AM
  104. /*rc = CRect(5, 8, 65, 20);
  105. m_pEditAM = new CEdit;
  106. m_pEditAM = (CEdit *)m_wndToolBar.InsertControl(RUNTIME_CLASS(CEdit), 
  107. _T(""), rc, ID_CONTEXT_HELP, WS_TABSTOP | ES_READONLY | ES_RIGHT);
  108. m_pEditAM->SetWindowText("00:00:00");
  109. /*rc = CRect(0,0,100,120);
  110. m_pcmbAM =(CComboBox *) m_wndToolBar.InsertControl(RUNTIME_CLASS(CComboBox), 
  111. _T(""), rc, IDC_AM, WS_VSCROLL | CBS_DROPDOWNLIST);
  112. m_pcmbAM->AddString(_T("MALE"));
  113. m_pcmbAM->AddString(_T("FEMALE"));
  114. m_pcmbAM->SetCurSel(0);*/
  115. // 添加音量显示条
  116. rc = CRect(0, 0, 200, 20);
  117. m_pctrlVolume = (CProgressCtrl *)m_wndToolBar.InsertControl(RUNTIME_CLASS(CProgressCtrl), 
  118. _T(""), rc, ID_CTRL_VOLUME, 0);
  119. m_pctrlVolume->SetRange(0, 100);
  120. if (!m_wndStatusBar.Create(this) ||
  121. !m_wndStatusBar.SetIndicators(indicators,
  122.   sizeof(indicators)/sizeof(UINT)))
  123. {
  124. TRACE0("Failed to create status barn");
  125. return -1;      // fail to create
  126. }
  127. m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
  128. EnableDocking(CBRS_ALIGN_ANY);
  129. DockControlBar(&m_wndToolBar);
  130. return 0;
  131. }
  132. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
  133. {
  134. cs.style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX;
  135. if( !CFrameWnd::PreCreateWindow(cs) )
  136. return FALSE;
  137. return TRUE;
  138. }
  139. /////////////////////////////////////////////////////////////////////////////
  140. // CMainFrame diagnostics
  141. #ifdef _DEBUG
  142. void CMainFrame::AssertValid() const
  143. {
  144. CFrameWnd::AssertValid();
  145. }
  146. void CMainFrame::Dump(CDumpContext& dc) const
  147. {
  148. CFrameWnd::Dump(dc);
  149. }
  150. #endif //_DEBUG
  151. /////////////////////////////////////////////////////////////////////////////
  152. // CMainFrame message handlers
  153. // ==============================================================
  154. // 自定义消息响应函数
  155. LRESULT CMainFrame::OnBeginUtterance(WPARAM wParam, LPARAM lParam)
  156. {
  157. return 0L;
  158. }
  159. LRESULT CMainFrame::OnAddWaveFrame(WPARAM wParam, LPARAM lParam)
  160. {
  161. return 0L;
  162. }
  163. LRESULT CMainFrame::OnEndUtterance(WPARAM wParam, LPARAM lParam)
  164. {
  165. return 0L;
  166. }
  167. LRESULT CMainFrame::OnDragonFirm(WPARAM wParam, LPARAM lParam)
  168. {
  169. theApp.m_LogTrace.WriteLine("调用OnDragonFirm");
  170. // 判断是否处理识别结果
  171. //if (!m_bDispose) return 0L;
  172. // 清空识别结果
  173. int  nCount = 5;
  174. for (int i = 0; i < 5; i ++)
  175. {
  176. m_szResult[i][0] = '';
  177. }
  178. SrGetFirmWords(m_szResult, nCount);
  179. CView *pView = GetActiveView();
  180. if (strlen(m_szResult[0]) > 0)
  181. {
  182. // 有识别结果,关闭定时器,播放相应语音文件
  183. //KillTimer(WAITTIMER);
  184. pView->SendMessage(WM_DISPLAYRESULT, (WPARAM)(m_szResult[0]), 0);
  185. for (int j = 0; j < m_aryList.GetSize(); j ++)
  186. {
  187. LPQUESTIONINFO lpInfo = (LPQUESTIONINFO)m_aryList.GetAt(j);
  188. if (strcmp(m_szResult[0], lpInfo->cmdbuf) == 0)
  189. {
  190. // 判断有几部分组成
  191. PlayFileAsync(g_nDeviceID, lpInfo->filename, this->m_hWnd);
  192. if (lpInfo->nP == 3)
  193. {
  194. // 播放数字
  195. CString sPath;
  196. sPath.Format("./Data/Wav/%03d.wav", theApp.m_nCount);
  197. PlayFileAsync(g_nDeviceID, (LPTSTR)(LPCTSTR)sPath, this->m_hWnd);
  198. sPath = "./Data/Wav/19_end.wav";
  199. PlayFileAsync(g_nDeviceID, (LPTSTR)(LPCTSTR)sPath, this->m_hWnd);
  200. }
  201. break;
  202. }
  203. }
  204. theApp.m_LogTrace.WriteLine("处理识别结果");
  205. // 继续识别
  206. StartRecord();
  207. }
  208. else
  209. {
  210. theApp.m_LogTrace.WriteLine("无识别结果");
  211. pView->SendMessage(WM_DISPLAYRESULT, (WPARAM)("无识别结果"), 0);
  212. Sleep(200);
  213. StartRecord();
  214. }
  215. return 0L;
  216. }
  217. LRESULT CMainFrame::OnDragonGetVolume(WPARAM wParam, LPARAM lParam)
  218. {
  219. int nVol = SrGetAudioVolume();
  220. nVol *= 4;
  221. if (nVol > 100) nVol = 100;
  222. if (m_nGetVol == 1)
  223. {
  224. m_pctrlVolume->SetPos(nVol);
  225. m_nGetVol = 0;
  226. }
  227. else
  228. m_nGetVol ++;
  229. return 0L;
  230. }
  231. // ========================================================================= 
  232. BOOL CMainFrame::InitRecognition()
  233. {
  234. m_bDispose = FALSE;
  235. try
  236. {
  237. GenerateQuesion("Data.dll");
  238. for (int i = 0; i < 5; i ++)
  239. {
  240. m_szResult[i] = new char[MAX_PATH];
  241. m_szResult[i][0] = '';
  242. }
  243. memset(m_chCurSelCmd, '', sizeof(char));
  244. strcpy(m_chAM, "MALE");
  245. strcpy(m_chCMD, "CMD");
  246. char dataPathName[MAX_PATH];
  247. _getcwd(dataPathName, MAX_PATH);
  248. if (SrInitDragonVoice (dataPathName, m_chAM, GetSafeHwnd()) == 0)
  249. {
  250. SrLoadCommandMode("CMD");
  251. SrSetActiveCommand("CMD");
  252. SrSetParameter(SET_EP_CHECK, 3);
  253. }
  254. else
  255. {
  256. AfxMessageBox("Initialize Command Engine Failed, Exit");
  257. exit(1);
  258. }
  259. }
  260. catch(...)
  261. {
  262. AfxMessageBox("Initialize Command Engine Failed, Exit");
  263. exit(1);
  264. }
  265. theApp.m_LogTrace.WriteLine("初始化结束");
  266. SetTimer(ROBOT_STATUS_SYSTEM, 1000, NULL);
  267. return TRUE;
  268. }
  269. void CMainFrame::FreeResource()
  270. {
  271. SrExitDragonVoice();
  272. for (int i=0; i < 5; i++)
  273. {
  274. delete [] m_szResult[i];
  275. }
  276. for (i = 0; i < m_aryList.GetSize(); i ++)
  277. {
  278. LPQUESTIONINFO lpInfo = (LPQUESTIONINFO)m_aryList.GetAt(i);
  279. delete lpInfo;
  280. }
  281. m_aryList.RemoveAll();
  282. }
  283. void CMainFrame::OnTimer(UINT nIDEvent) 
  284. {
  285. switch(nIDEvent)
  286. {
  287. /*case WAITTIMER :
  288. {
  289. // 判断当前时间(小时)是否改变,记录日志文件名改变
  290. CTime tm = CTime::GetCurrentTime();
  291. if (tm.GetHour() != m_nLocalH)
  292. {
  293. m_nLocalH = tm.GetHour();
  294. CString sFileName;
  295. sFileName.Format("%04d年%02d月%02d日%02d点.txt", 
  296. tm.GetYear(), tm.GetMonth(), tm.GetDay(), tm.GetHour());
  297. theApp.m_LogTrace.SetFileName(sFileName);
  298. theApp.m_LogTrace.ResetFile();
  299. theApp.m_LogTrace.SetActive(TRUE);
  300. }
  301. m_nOvertime ++;
  302. // 端口监测
  303. CString sItem;
  304. int dwValue = (int)GetParallelStatus(sItem);
  305. switch (dwValue)
  306. {
  307. case 1 :
  308. {
  309. // 压力开关闭合
  310. if (m_bRun) SwitchStatus("./Data/Wav/welcome1.wav", "压力开关闭合");
  311. }
  312. break;
  313. case 2 :
  314. {
  315. // 有人靠近Mic
  316. if (m_bRun) 
  317. {
  318. SwitchStatus("", "有人靠近Mic");
  319. StartRecord();
  320. }
  321. }
  322. break;
  323. case -1 :
  324. {
  325. // 压力开关断开
  326. if (m_bLeave)
  327. {
  328. m_bLeave = FALSE;
  329. SwitchStatus("./Data/Wav/leave1.wav", "压力开关断开");
  330. }
  331. }
  332. break;
  333. case -2 :
  334. {
  335. // 有人离开Mic
  336. if (g_nQNum != 0) SwitchStatus("./Data/Wav/close1.wav", "有人离开Mic");
  337. if (m_bClose && g_nQNum == 0)
  338. {
  339. m_bClose = FALSE;
  340. SwitchStatus("./Data/Wav/close1.wav", "有人离开Mic");
  341. }
  342. }
  343. break;
  344. default : // 状态未变
  345. // 是否进行超时处理
  346. m_bRun = SwitchNext();
  347. if (m_bRun)
  348. {
  349. if (m_nOvertime == OVERTIME)
  350. {
  351. // 超时,则不处理识别结果
  352. theApp.m_LogTrace.WriteLine("超时,则不处理识别结果");
  353. KillTimer(WAITTIMER);
  354. StopRecord();
  355. m_nOvertime = 0;
  356. m_nDegree ++;
  357. //超时处理
  358. Sleep(2000);
  359. CView *pView = GetActiveView();
  360. pView->SendMessage(WM_DISPLAYRESULT, (WPARAM)("超时处理"), 0);
  361. WritePort(0x00);
  362. PlayFileAsync(g_nDeviceID, "./Data/Wav/remind1.wav", this->m_hWnd);
  363. WritePort(0xff);
  364. if (m_nDegree == OVERTIMES)
  365. {
  366. g_nQNum --;
  367. m_nDegree = 0;
  368. m_bRun = SwitchNext();
  369. }
  370. if (m_bRun) StartRecord();
  371. if (theApp.m_bSetTiemr) SetTimer(WAITTIMER, 1000, NULL);
  372. }
  373. }
  374. break;
  375. }
  376. }
  377. break;*/
  378. case ROBOT_STATUS_SYSTEM :
  379. {
  380. KillTimer(ROBOT_STATUS_SYSTEM);
  381. // 系统初始化结束,进入自我介绍状态
  382. g_nStatus = ROBOT_STATUS_INTRO;
  383. // 播放欢迎词
  384. PlayFileAsync(g_nDeviceID, "./Data/Wav/welcome1.wav", this->m_hWnd);
  385. // 进入等待状态,开启端口监测定时器
  386. //g_nStatus = ROBOT_STATUS_WAIT;
  387. //if (theApp.m_bSetTiemr) SetTimer(WAITTIMER, 1000, NULL);
  388. StartRecord();
  389. }
  390. break;
  391. }
  392. }
  393. void CMainFrame::StartRecord()
  394. {
  395. theApp.m_LogTrace.WriteLine("开始录音");
  396. m_bDispose = TRUE;
  397. SrMicOn();
  398. }
  399. void CMainFrame::StopRecord()
  400. {
  401. theApp.m_LogTrace.WriteLine("关闭录音");
  402. m_bDispose = FALSE;
  403. SrMicOff();
  404. }
  405. // 返回值:
  406. //  0:状态未改变
  407. //  1:用户靠近机器人有效距离
  408. // -1:用户离开机器人有效距离
  409. //  2:用户靠近Mic有效距离
  410. // -2:用户离开Mic有效距离
  411. DWORD CMainFrame::GetParallelStatus(CString &sItem)
  412. {
  413. return 0;
  414. }
  415. void CMainFrame::GenerateQuesion(CString szFileName)
  416. {
  417. CStdioFile file;
  418. CFileException ex;
  419. CString sAnswer, sPathName, sS, sAct, sTmp;
  420. LPQUESTIONINFO pInfo;
  421. if(file.Open(szFileName, CFile::typeText | CFile::modeRead, &ex))
  422. {
  423. file.SeekToBegin();
  424. int nPosBgn = -1;
  425. int nPosEnd = 0;
  426. char pBuf[65535];
  427. memset(pBuf, 0, 65535);
  428. int nLen = file.GetLength();
  429. file.ReadHuge(pBuf, nLen);
  430. CString s = pBuf;
  431. nPosBgn = s.Find("{", nPosEnd);
  432. nPosEnd = s.Find("}", nPosBgn);
  433. while ((nPosEnd != -1) && (nPosBgn != -1))
  434. {
  435. sTmp = s.Mid(nPosBgn + 1, nPosEnd - nPosBgn - 1);
  436. //用于存储输入参数的PROPERTY和VALUE
  437. CMapStringToString msPropertys;
  438. //循环分析输入参数,将参数内容另存到变量msPropertys中
  439. int nPos;
  440. while(sTmp.GetLength() > 0)
  441. {
  442. nPos = sTmp.Find("[");
  443. if(nPos >= 0) sTmp = sTmp.Mid(nPos + 1);
  444. CString sProperty;
  445. nPos = sTmp.Find("]");
  446. if(nPos >= 0)
  447. {
  448. sProperty = sTmp.Left(nPos);
  449. sTmp = sTmp.Mid(nPos + 1);
  450. }
  451. CString sValue;
  452. nPos = sTmp.Find("[");
  453. if(nPos >= 0)
  454. {
  455. //还有下一个属性结点
  456. sValue = sTmp.Left(nPos);
  457. sValue = sValue.Mid(1); //去"="
  458. sTmp = sTmp.Mid(nPos);
  459. }
  460. else
  461. {
  462. //此为最后一个属性结点
  463. sValue = sTmp.Mid(1); //去"="
  464. sTmp.Empty();
  465. }
  466. //存储属性
  467. msPropertys.SetAt(sProperty, sValue);
  468. }
  469. msPropertys.Lookup("CMD", sAnswer);
  470. msPropertys.Lookup("FILENAME", sPathName);
  471. msPropertys.Lookup("S", sS);
  472. msPropertys.Lookup("ACT", sAct);
  473. m_sScroll +=sAnswer;
  474. m_sScroll += "|";
  475. pInfo = new QUESTIONINFO;
  476. strcpy(pInfo->cmdbuf, sAnswer);
  477. strcpy(pInfo->filename, sPathName);
  478. pInfo->nS = atoi(sS);
  479. pInfo->nAct = atoi(sAct);
  480. m_aryList.Add(pInfo);
  481. // 取下一个选项
  482. nPosBgn = s.Find("{", nPosEnd);
  483. nPosEnd = s.Find("}", nPosBgn);
  484. }
  485. file.Close();
  486. }
  487. }
  488. void CMainFrame::OnMyPlayEnd(WPARAM wParam, LPARAM lParam)
  489. {
  490. switch(wParam)
  491. {
  492. case MCI_NOTIFY_SUCCESSFUL:
  493. StopPlayFileAsync(g_nDeviceID, this->m_hWnd);
  494. g_bPlayEnd = TRUE;
  495. theApp.m_LogTrace.WriteLine("播放声音文件结束");
  496. break;
  497. default:
  498. break;
  499. }
  500. }
  501. BOOL CMainFrame::SwitchNext()
  502. {
  503. // 如果问题数为零,则不识别(返回FALSE,否则返回TRUE)。
  504. if (g_nQNum == 0)
  505. return FALSE;
  506. else
  507. return TRUE;
  508. }
  509. void CMainFrame::SwitchStatus(char *szFileName, char *szInfo)
  510. {
  511. theApp.m_LogTrace.WriteLine(szInfo);
  512. KillTimer(WAITTIMER);
  513. StopRecord();
  514. m_nOvertime = 0;
  515. CView *pView = GetActiveView();
  516. pView->SendMessage(WM_DISPLAYRESULT, (WPARAM)szInfo, 0);
  517. if (strlen(szFileName) > 0)
  518. {
  519. WritePort(0x00);
  520. PlayFileAsync(g_nDeviceID, szFileName, this->m_hWnd);
  521. WritePort(0xff);
  522. }
  523. if (theApp.m_bSetTiemr) SetTimer(WAITTIMER, 1000, NULL);
  524. }
  525. void CMainFrame::OnPlayTime(WPARAM wParam, LPARAM lParam)
  526. {
  527. DWORD dwLen = (DWORD)lParam;
  528. CString sLen;
  529. sLen.Format("%d", dwLen);
  530. int nLen = (int)dwLen / 1000;
  531. CString sMinute, sSecond;
  532. sMinute.Format("%d", nLen / 60);
  533. sSecond.Format("%d", nLen % 60);
  534. CString sMilli = sLen.Right(3);
  535. sMilli = sMilli.Left(2);
  536. sLen = sMinute + ":" + sSecond + ":" + sMilli;
  537. m_pEditAM->SetWindowText(sLen);
  538. }
  539. void CMainFrame::WritePort(DWORD dwValue)
  540. {
  541. //DP_OutpW(WRITEPORT, dwValue);
  542. }