AudioCtrl.cpp
上传用户:shenwh911
上传日期:2013-07-04
资源大小:54k
文件大小:26k
源码类别:

Audio

开发平台:

Visual C++

  1. // AudioCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "RecordAudio.h"
  5. #include "AudioCtrl.h"
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CAudioCtrl
  13. CAudioCtrl::CAudioCtrl()
  14. : m_uiDeviceID(0)
  15. , m_eStatus(ENUM_STATUS_INVALID)
  16. , m_hRecord(NULL)
  17. , m_hPlay(NULL)
  18. , m_dwQueuBufferSize(1024)
  19. , m_nDataQueueNum(0)
  20. , m_bRecording(FALSE)
  21. , m_eRecChannel(ENUM_REC_CHANNEL_MONO)
  22. , m_szAryInData(NULL)
  23. , m_szLeftInData(NULL)
  24. , m_szRightInData(NULL)
  25. , m_pAryHdr (NULL)
  26. , m_uiMixerID(0)
  27. {
  28. memset(&m_Format, 0, sizeof(WAVEFORMATEX));
  29. m_nDataQueueNum = 0;
  30. ZeroMemory(&m_MMCKInfoParent,sizeof(m_MMCKInfoParent));
  31. ZeroMemory(&m_MMCKInfoChild,sizeof(m_MMCKInfoChild));
  32. memset ( m_hWaveFile, 0, sizeof(m_hWaveFile) );
  33. SetBkColor(RGB(0, 0, 0));
  34. m_bAlwaysDrawTowChannel = false;
  35. }
  36. CAudioCtrl::~CAudioCtrl()
  37. {
  38. StopAndFreeAll();
  39. }
  40. BEGIN_MESSAGE_MAP(CAudioCtrl, CWnd)
  41. //{{AFX_MSG_MAP(CAudioCtrl)
  42. ON_WM_TIMER()
  43. ON_WM_ERASEBKGND()
  44. //}}AFX_MSG_MAP
  45. END_MESSAGE_MAP()
  46. /////////////////////////////////////////////////////////////////////////////
  47. // CAudioCtrl message handlers
  48. //
  49. // 获得声卡的数量
  50. //
  51. UINT CAudioCtrl::GetWaveInDevs()
  52. {
  53. return waveInGetNumDevs();
  54. }
  55. char* CAudioCtrl::GetWaveInName(UINT uiDevID)
  56. {
  57. WAVEINCAPS tagCaps;
  58. if (waveInGetDevCaps(uiDevID, &tagCaps, sizeof(tagCaps)) == MMSYSERR_NOERROR)
  59. {
  60. return tagCaps.szPname;
  61. }
  62. return NULL;
  63. }
  64. UINT CAudioCtrl::GetWaveInAvailableDev()
  65. {
  66. for ( DWORD i=0; i<GetWaveInDevs(); i++ )
  67. {
  68. CVolumeCtrl VolumeIn( 0, i );
  69. if (VolumeIn.IsAvailable())
  70. {
  71. return i;
  72. }
  73. }
  74. return -1;
  75. }
  76. void CAudioCtrl::SetDeviceID(UINT uiIndex)
  77. {
  78. m_uiDeviceID = uiIndex;
  79. }
  80. UINT CAudioCtrl::InitCtrl(UINT uiDevIndex,
  81.   DWORD dwBufSize, 
  82.   HWND hwndParent, 
  83.   LPRECT lpRect, 
  84.   MsgNotifyProc msgNodityProc, 
  85.   WPARAM wParam)
  86. {
  87. StopAndFreeAll();
  88. SetDeviceID(uiDevIndex);
  89. m_dwQueuBufferSize = dwBufSize;
  90. m_pMsgNotifyProc = msgNodityProc;
  91. m_wParam = wParam;
  92. Create(hwndParent, lpRect);
  93. /********** 绘图**********/
  94. if ( hwndParent && lpRect )
  95. {
  96. m_PenG.CreatePen ( PS_SOLID, 0, RGB(0, 255, 0) );
  97. m_PenPartLine.CreatePen ( PS_SOLID, PARTLINE_HEIGHT, COLOR_FRAME );
  98. }
  99. /********** 绘图**********/
  100. m_eStatus = ENUM_STATUS_READY;
  101. return TRUE;
  102. }
  103. //
  104. // 获得播放声音的声卡数量
  105. //
  106. UINT CAudioCtrl::GetWaveOutCount()
  107. {
  108. return waveOutGetNumDevs();
  109. }
  110. BOOL CAudioCtrl::Create(HWND hwndParent, LPRECT lpRect)
  111. {
  112. LPCTSTR lpszClassName = AfxRegisterWndClass(
  113. 0,
  114. LoadCursor(AfxGetInstanceHandle(), IDC_ARROW),
  115. NULL, NULL );
  116. CRect rc ( 0,0,0,0 );
  117. if ( lpRect ) rc = *lpRect;
  118. if ( !CreateEx ( 0, lpszClassName, "",
  119. WS_CHILD | WS_TABSTOP,
  120. rc.left, rc.top, rc.Width(), rc.Height(),
  121. hwndParent, NULL, NULL) )
  122. {
  123. AfxMessageBox ( "Create window failed" );
  124. return FALSE;
  125. }
  126. if ( lpRect )
  127. ShowWindow ( SW_SHOW );
  128. else
  129. ShowWindow ( SW_HIDE );
  130. GetClientRect (&m_rcClient );
  131. /********** 绘图**********/
  132. CClientDC dc(this);
  133. m_fntChannelText.CreatePointFont ( 100, "Impact", &dc );
  134. // m_fntDeviceNameText.CreateFont ( 14, 0, 0, 0, 0, TRUE, TRUE, FALSE, 0, 0,
  135. // 0, 0, 0, "MS Sans Serif" );
  136. /********** 绘图**********/
  137. return TRUE;
  138. }
  139. BOOL CAudioCtrl::PreTranslateMessage(MSG* pMsg) 
  140. {
  141. if ((pMsg->message >= MM_WOM_OPEN) && (pMsg->message <= MM_MOM_DONE))
  142. {
  143. switch ( pMsg->message )
  144. {
  145. case MM_WIM_DATA:
  146. OnMM_WIM_DATA ( pMsg->wParam, pMsg->lParam );
  147. break;
  148. case MM_WIM_CLOSE:
  149. m_eStatus = ENUM_STATUS_READY;
  150. m_nDataQueueNum = 0;
  151. m_bRecording = FALSE;
  152. break;
  153. case MM_WOM_DONE:
  154. OnMM_WOM_DONE ( pMsg->wParam, pMsg->lParam );
  155. break;
  156. case MM_WOM_CLOSE:
  157. m_eStatus = ENUM_STATUS_READY;
  158. m_bRecording = FALSE;
  159. break;
  160. case MM_WIM_OPEN:
  161. break;
  162. case MM_WOM_OPEN:
  163. break;
  164. }
  165. if (m_pMsgNotifyProc)
  166. {
  167. m_pMsgNotifyProc(pMsg->message, m_wParam);
  168. }
  169. }
  170. return CWnd::PreTranslateMessage(pMsg);
  171. }
  172. //
  173. // 录音对应当数据缓冲写满后触发的消息
  174. //
  175. LRESULT CAudioCtrl::OnMM_WIM_DATA (WPARAM wParam, LPARAM lParam)
  176. {
  177. MMRESULT mmReturn = 0;
  178. LPWAVEHDR pHdr = (LPWAVEHDR) lParam;
  179. ASSERT ( pHdr );
  180. // 清除波形输入缓冲区
  181. mmReturn = ::waveInUnprepareHeader (m_hRecord, pHdr, sizeof(WAVEHDR));
  182. if (mmReturn)
  183. {
  184. return -1L;
  185. }
  186. if(m_eStatus == ENUM_STATUS_RECORDING)
  187. {
  188. // 提取单声道PCM数据
  189. int nBytesPickup = PickupMonoData(m_Format.wBitsPerSample, pHdr->lpData, pHdr->dwBytesRecorded);
  190. // 根据需要保存的通道文件类型选择PCM数据和数据长度
  191. char *pRecData[ENUM_FILE_CHANNEL_NUM] = { pHdr->lpData, pHdr->lpData };
  192. int nRecBytes[ENUM_FILE_CHANNEL_NUM] = { pHdr->dwBytesRecorded, pHdr->dwBytesRecorded };
  193. if ( m_eRecChannel == ENUM_REC_CHANNEL_ALONE )
  194. {
  195. pRecData[ENUM_FILE_CHANNEL_LEFT] = m_szLeftInData;
  196. nRecBytes[ENUM_FILE_CHANNEL_LEFT] = nBytesPickup;
  197. pRecData[ENUM_FILE_CHANNEL_RIGHT] = m_szRightInData;
  198. nRecBytes[ENUM_FILE_CHANNEL_RIGHT] = nBytesPickup;
  199. }
  200. // 保存到wave文件中
  201. for ( int eFileChannel=ENUM_FILE_CHANNEL_COMMON; eFileChannel<ENUM_FILE_CHANNEL_NUM; eFileChannel++ )
  202. {
  203. if ( m_hWaveFile[eFileChannel] )
  204. {
  205. int length = ::mmioWrite(m_hWaveFile[eFileChannel], pRecData[eFileChannel], nRecBytes[eFileChannel] );
  206. if ( length != nRecBytes[eFileChannel] )
  207. {
  208. Stop ();
  209. m_nDataQueueNum --;
  210. TRACE("write file failedrn");
  211. return -1L;
  212. }
  213. }
  214. }
  215. // 为波形输入准备一个输入缓冲区
  216. mmReturn = ::waveInPrepareHeader (m_hRecord, pHdr, sizeof(WAVEHDR));
  217. if (mmReturn)
  218. {
  219. TRACE("waveInPrepareHeader failedrn");
  220. }
  221. else
  222. {
  223. // 给输入设备增加一个缓存
  224. mmReturn = ::waveInAddBuffer(m_hRecord, pHdr, sizeof(WAVEHDR));
  225. if (mmReturn)
  226. {
  227. TRACE("waveInAddBuffer() failedrn");
  228. }
  229. else
  230. {
  231. DrawWave( (DWORD)nBytesPickup );
  232. return S_OK;
  233. }
  234. }
  235. }
  236. else
  237. {
  238. if (m_nDataQueueNum == 1)
  239. {
  240. StopRec();
  241. }
  242. else
  243. {
  244. m_nDataQueueNum --;
  245. }
  246. }
  247. return S_OK;
  248. }
  249. //
  250. // 播放对应当数据缓冲读完后触发的消息
  251. //
  252. LRESULT CAudioCtrl::OnMM_WOM_DONE (WPARAM wParam, LPARAM lParam)
  253. {
  254. //TRACE("OnMM_WOM_DONE!rn");
  255. MMRESULT mmReturn = 0;
  256. LPWAVEHDR pHdr = (LPWAVEHDR)lParam;
  257. mmReturn = ::waveOutUnprepareHeader(m_hPlay, pHdr, sizeof(WAVEHDR));
  258. if ( mmReturn )
  259. {
  260. TRACE("waveOutUnprepareHeader() failed!rn" );
  261. return -1L;
  262. }
  263. m_nDataQueueNum--;
  264. if ( m_eStatus == ENUM_STATUS_PLAYING )
  265. {
  266. int nSize = m_dwQueuBufferSize;
  267. if ( ReadSoundDataFromFile ( pHdr->lpData, nSize ) )
  268. {
  269. AddOutputBufferToQueue ( (int)pHdr->dwUser, nSize );
  270. return 0L;
  271. }
  272. else
  273. {
  274. Stop();
  275. }
  276. }
  277. if ( m_nDataQueueNum == 0 && m_eStatus != ENUM_STATUS_PLAYING )
  278. {
  279. StopPlay ();
  280. }
  281. return S_OK;
  282. }
  283. //
  284. // 从立体声PCM数据中提取单声道数据,结果保存到 m_szLeftInData 、 m_szRightInData 中
  285. // return : ------------------------------------------------------------------------------
  286. // 单声道数据长度(字节)
  287. //
  288. int CAudioCtrl::PickupMonoData(WORD wBitsPerSample, char *szOrgData, int nOrgSize)
  289. {
  290. if ( m_Format.nChannels == 1 )
  291. {
  292. ASSERT ( m_dwQueuBufferSize >= (DWORD)nOrgSize );
  293. memcpy ( m_szLeftInData, szOrgData, nOrgSize );
  294. memcpy ( m_szRightInData, szOrgData, nOrgSize );
  295. return nOrgSize;
  296. }
  297. DWORD dwBytesPerSample = wBitsPerSample/8;
  298. int nDestBytes_Left = 0, nDestBytes_Right = 0;
  299. for ( int i=0; i<nOrgSize; i+=2*dwBytesPerSample )
  300. {
  301. memcpy ( m_szLeftInData+nDestBytes_Left, szOrgData+i, dwBytesPerSample );
  302. nDestBytes_Left += dwBytesPerSample;
  303. memcpy ( m_szRightInData+nDestBytes_Right, szOrgData+i+dwBytesPerSample, dwBytesPerSample );
  304. nDestBytes_Right += dwBytesPerSample;
  305. }
  306. ASSERT ( nDestBytes_Left == nDestBytes_Right );
  307. return nDestBytes_Left;
  308. }
  309. void CAudioCtrl::Stop()
  310. {
  311. if ( m_eStatus != ENUM_STATUS_PLAYING && m_eStatus != ENUM_STATUS_RECORDING )
  312. return;
  313. MMRESULT mmReturn = 0;
  314. if ( m_eStatus == ENUM_STATUS_PLAYING )
  315. {
  316. if ( ::waveOutReset(m_hPlay) ) 
  317. {
  318. TRACE("waveOutReset failedrn");
  319. }
  320. SetTimer ( TIMER_EVENT_STOPPLAY, 1000, NULL );
  321. }
  322. else if ( m_eStatus == ENUM_STATUS_RECORDING )
  323. {
  324. SetTimer ( TIMER_EVENT_STOPREC, 1000, NULL );
  325. }
  326. Invalidate ( TRUE );
  327. m_eStatus = ENUM_STATUS_STOPING;
  328. }
  329. void CAudioCtrl::StopRec()
  330. {
  331. if ( !m_hRecord ) return;
  332. if ( m_eStatus != ENUM_STATUS_RECORDING && m_eStatus != ENUM_STATUS_STOPING )
  333. return;
  334. MMRESULT mmReturn = 0;
  335. mmReturn = ::waveInReset ( m_hRecord );
  336. if ( mmReturn ) 
  337. {
  338. TRACE("waveInReset failedrn");
  339. }
  340. ::Sleep ( 10 );
  341. for ( int eFileChannel=ENUM_FILE_CHANNEL_COMMON; eFileChannel<ENUM_FILE_CHANNEL_NUM; eFileChannel++ )
  342. {
  343. //StopRecordAudioFile ( (ENUM_FILE_CHANNEL)eFileChannel, "mp3" );
  344. StopRecordAudioFile ( (ENUM_FILE_CHANNEL)eFileChannel, "wav" );
  345. }
  346. mmReturn = ::waveInClose ( m_hRecord );
  347. m_hRecord = NULL;
  348. if ( mmReturn ) 
  349. {
  350. TRACE("waveInClose failedrn" );
  351. }
  352. //FreeMp3Encode ();
  353. }
  354. // 
  355. // 录制
  356. //
  357. BOOL CAudioCtrl::Record(UINT uiRecChannel,   /*录制信道*/
  358. DWORD dwSamplingRate,/*采样率*/ 
  359. WORD  wSamplingBit  /*采样位*/
  360. {
  361. // 录音设备正在录音
  362. if ( m_eStatus == ENUM_STATUS_RECORDING )
  363. {
  364. TRACE("recording...rn");
  365. return FALSE;
  366. }
  367. if (m_eStatus != ENUM_STATUS_READY)
  368. {
  369. TRACE("AudioCtrl state failed...rn");
  370. return FALSE;
  371. }
  372. m_bRecording = TRUE;
  373. MMRESULT mmReturn = 0;
  374. ASSERT((wSamplingBit%8) == 0);
  375. if (wSamplingBit > 16)
  376. {
  377. wSamplingBit = 16;
  378. }
  379. SetWaveFormat(uiRecChannel, dwSamplingRate, wSamplingBit);
  380. if (!SetRelateParaAfterGetWaveFormat())
  381. {
  382. return TRUE;
  383. }
  384. mmReturn = ::waveInOpen(&m_hRecord, m_uiDeviceID, &m_Format, (DWORD)GetSafeHwnd(), NULL, CALLBACK_WINDOW);
  385. if (mmReturn)
  386. {
  387. TRACE("waveInOpen is failed!rn");
  388. goto failed;
  389. }
  390. else
  391. {
  392. // make several input buffers and add them to the input queue
  393. for(int i=0; i<m_wInQueu; i++)
  394. {
  395. AddInputBufferToQueue ( i );
  396. }
  397. // start recording
  398. mmReturn = ::waveInStart ( m_hRecord );
  399. if ( mmReturn )
  400. {
  401. TRACE("waveInStart is failed!rn");
  402. goto failed;
  403. }
  404. }
  405. m_eStatus = ENUM_STATUS_RECORDING;
  406. return TRUE;
  407. failed:
  408. FreeBuffer();
  409. return FALSE;
  410. }
  411. void CAudioCtrl::SetWaveFormat(UINT uiRecChannel, 
  412.    DWORD dwSamplingRate, 
  413.    WORD  wSamplingBit)
  414. {
  415. m_eRecChannel = (ENUM_REC_CHANNEL)uiRecChannel;
  416. memset(&m_Format, 0, sizeof(WAVEFORMATEX));
  417. m_Format.cbSize = 0;
  418. m_Format.wFormatTag = WAVE_FORMAT_PCM;
  419. m_Format.wBitsPerSample = wSamplingBit;
  420. m_Format.nChannels = ((uiRecChannel==ENUM_REC_CHANNEL_MONO) ? 1 : 2);
  421. m_Format.nSamplesPerSec = dwSamplingRate;
  422. m_Format.nAvgBytesPerSec = m_Format.nSamplesPerSec * (m_Format.wBitsPerSample/8);
  423. m_Format.nBlockAlign = m_Format.nChannels * (m_Format.wBitsPerSample/8);
  424. }
  425. void CAudioCtrl::FreeBuffer()
  426. {
  427. // 录音或者播放尚未停止,不能释放内存
  428. for ( int eFileChannel=ENUM_FILE_CHANNEL_COMMON; eFileChannel<ENUM_FILE_CHANNEL_NUM; eFileChannel++ )
  429. {
  430. //if ( m_hWaveFile[eFileChannel] || m_pFileMp3[eFileChannel] )
  431. if (m_hWaveFile[eFileChannel])
  432. return;
  433. }
  434. if (m_szAryInData)
  435. {
  436. for ( int i=0; i<m_wInQueu; i++ )
  437. {
  438. if ( m_szAryInData[i] )
  439. delete[] m_szAryInData[i];
  440. }
  441. memset ( m_szAryInData, 0, sizeof(char*)*m_wInQueu );
  442. delete[] m_szAryInData;
  443. m_szAryInData = NULL;
  444. }
  445. if ( m_szLeftInData )
  446. {
  447. delete[] m_szLeftInData;
  448. m_szLeftInData = NULL;
  449. }
  450. if ( m_szRightInData )
  451. {
  452. delete[] m_szRightInData;
  453. m_szRightInData = NULL;
  454. }
  455. if (m_pAryHdr)
  456. {
  457. for (int i=0; i<m_wInQueu; i++)
  458. {
  459. if (m_pAryHdr[i])
  460. {
  461. delete[] m_pAryHdr[i];
  462. }
  463. }
  464. memset(m_pAryHdr, 0, sizeof(WAVEHDR*)*m_wInQueu);
  465. delete[] m_pAryHdr;
  466. m_pAryHdr = NULL;
  467. }
  468. }
  469. BOOL CAudioCtrl::SetRelateParaAfterGetWaveFormat()
  470. {
  471. FreeBuffer ();
  472. m_wInQueu = (WORD) ( m_Format.nChannels + m_Format.wBitsPerSample/8 + m_Format.nSamplesPerSec/11025 );
  473. if ( !AllocateBuffer ( m_dwQueuBufferSize ) )
  474. return FALSE;
  475. return TRUE;
  476. }
  477. BOOL CAudioCtrl::AllocateBuffer(DWORD dwBufferSize)
  478. {
  479. m_dwQueuBufferSize = dwBufferSize;
  480. ASSERT ( m_wInQueu > 0 );
  481. m_szAryInData = new char*[m_wInQueu];
  482. m_szLeftInData = new char[m_dwQueuBufferSize];
  483. m_szRightInData = new char[m_dwQueuBufferSize];
  484. m_pAryHdr = new WAVEHDR*[m_wInQueu];
  485. if ( !m_szAryInData || !m_szLeftInData || !m_szRightInData || !m_pAryHdr )
  486. {
  487. ::AfxThrowMemoryException ();
  488. return FALSE;
  489. }
  490. memset ( m_szAryInData, 0, sizeof(char*)*m_wInQueu );
  491. memset ( m_szLeftInData, 0, sizeof(char)*m_dwQueuBufferSize );
  492. memset ( m_szRightInData, 0, sizeof(char)*m_dwQueuBufferSize );
  493. memset ( m_pAryHdr, 0, sizeof(WAVEHDR*)*m_wInQueu );
  494. for ( int i=0; i<m_wInQueu; i++ )
  495. {
  496. m_szAryInData[i] = new char[m_dwQueuBufferSize];
  497. m_pAryHdr[i] = new WAVEHDR;
  498. if ( !m_szAryInData[i] || !m_pAryHdr[i] )
  499. {
  500. ::AfxThrowMemoryException ();
  501. return FALSE;
  502. }
  503. memset ( m_szAryInData[i], 0, m_dwQueuBufferSize );
  504. memset ( m_pAryHdr[i], 0, sizeof(WAVEHDR) );
  505. }
  506. return TRUE;
  507. }
  508. BOOL CAudioCtrl::AddInputBufferToQueue(int nIndex)
  509. {
  510. ASSERT ( nIndex >= 0 && nIndex < m_wInQueu );
  511. ASSERT ( m_szAryInData[nIndex] );
  512. MMRESULT mmReturn = 0;
  513. LPWAVEHDR pHdr = m_pAryHdr[nIndex];
  514. ZeroMemory ( pHdr, sizeof(WAVEHDR) );
  515. pHdr->lpData = (char*)m_szAryInData[nIndex];
  516. pHdr->dwBufferLength = m_dwQueuBufferSize;
  517. // prepare it
  518. mmReturn = ::waveInPrepareHeader ( m_hRecord, pHdr, sizeof(WAVEHDR) );
  519. if ( mmReturn )
  520. {
  521. TRACE("waveInPrepareHeader Failedrn");
  522. return FALSE;
  523. }
  524. // add the input buffer to the queue
  525. mmReturn = ::waveInAddBuffer ( m_hRecord, pHdr, sizeof(WAVEHDR) );
  526. if ( mmReturn )
  527. {
  528. TRACE("waveInAddBuffer() failedrn");
  529. return FALSE;
  530. }
  531. m_nDataQueueNum ++;
  532. return TRUE;
  533. }
  534. BOOL CAudioCtrl::SetRecordAudioFile(UINT uiChancel, char *pszFileName)
  535. {
  536. if (uiChancel > ENUM_FILE_CHANNEL_NUM)
  537. {
  538. return FALSE;
  539. }
  540. if (m_hWaveFile[uiChancel])
  541. return TRUE;
  542. WAVEFORMATEX wfx = m_Format;
  543. if (uiChancel==ENUM_REC_CHANNEL_ALONE )
  544. wfx.nChannels = 1;
  545. m_hWaveFile[uiChancel] = ::mmioOpen((LPTSTR)pszFileName, NULL, MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE|MMIO_ALLOCBUF);
  546. if ( m_hWaveFile[uiChancel] == NULL ) 
  547. {
  548. AfxMessageBox ( "Open wave file failed" );
  549. return FALSE;
  550. }
  551. ZeroMemory ( &m_MMCKInfoParent[uiChancel], sizeof(MMCKINFO) );
  552. m_MMCKInfoParent[uiChancel].fccType = mmioFOURCC('W','A','V','E');
  553.     MMRESULT mmResult = ::mmioCreateChunk( m_hWaveFile[uiChancel], &m_MMCKInfoParent[uiChancel], MMIO_CREATERIFF);
  554. ZeroMemory ( &m_MMCKInfoChild[uiChancel], sizeof(MMCKINFO) );
  555. m_MMCKInfoChild[uiChancel].ckid = mmioFOURCC('f','m','t',' ');
  556. m_MMCKInfoChild[uiChancel].cksize = sizeof(WAVEFORMATEX) + wfx.cbSize;
  557. mmResult = ::mmioCreateChunk(m_hWaveFile[uiChancel], &m_MMCKInfoChild[uiChancel], 0);
  558. mmResult = ::mmioWrite(m_hWaveFile[uiChancel], (char*)&wfx, sizeof(WAVEFORMATEX) + wfx.cbSize); 
  559. mmResult = ::mmioAscend(m_hWaveFile[uiChancel], &m_MMCKInfoChild[uiChancel], 0);
  560. m_MMCKInfoChild[uiChancel].ckid = mmioFOURCC('d', 'a', 't', 'a');
  561. mmResult = ::mmioCreateChunk ( m_hWaveFile[uiChancel], &m_MMCKInfoChild[uiChancel], 0 );
  562. return TRUE;
  563. }
  564. void CAudioCtrl::StopRecordAudioFile(ENUM_FILE_CHANNEL eFileChannel, CString csStopFileType)
  565. {
  566. if ( csStopFileType=="wav" && m_hWaveFile[eFileChannel] )
  567. {
  568. ::mmioAscend ( m_hWaveFile[eFileChannel], &m_MMCKInfoChild[eFileChannel], 0 );
  569. ::mmioAscend ( m_hWaveFile[eFileChannel], &m_MMCKInfoParent[eFileChannel], 0 );
  570. ::mmioClose ( m_hWaveFile[eFileChannel], 0 );
  571. m_hWaveFile[eFileChannel] = NULL;
  572. }
  573. }
  574. void CAudioCtrl::OnTimer(UINT nIDEvent) 
  575. {
  576. switch ( nIDEvent )
  577. {
  578. case TIMER_EVENT_STOPREC:
  579. KillTimer ( nIDEvent );
  580. StopRec ();
  581. break;
  582. case TIMER_EVENT_STOPPLAY:
  583. KillTimer ( nIDEvent );
  584. StopPlay ();
  585. break;
  586. }
  587. CWnd::OnTimer(nIDEvent);
  588. }
  589. DWORD CAudioCtrl::SetMixerDevs(UINT uiLine, DWORD* pdwMinVolume, DWORD* pdwMaxVolume)
  590. {
  591. m_uiMixerID = uiLine;
  592. CVolumeCtrl volumeCtrl(uiLine, m_uiDeviceID);
  593. if (pdwMinVolume)
  594. {
  595. *pdwMinVolume = volumeCtrl.GetMinimalVolume();
  596. }
  597. if (pdwMaxVolume)
  598. {
  599. *pdwMaxVolume = volumeCtrl.GetMaximalVolume();
  600. }
  601. volumeCtrl.Enable();
  602. return volumeCtrl.GetCurrentVolume();
  603. }
  604. void CAudioCtrl::SetCurVolume(DWORD dwValue)
  605. {
  606. CVolumeCtrl volumeCtrl(m_uiMixerID, m_uiDeviceID);
  607. volumeCtrl.SetCurrentVolume(dwValue);
  608. }
  609. BOOL CAudioCtrl::Play(char *pszPath)
  610. {
  611. if (pszPath == NULL || m_eStatus == ENUM_STATUS_PLAYING)
  612. {
  613. return FALSE;
  614. }
  615. m_bRecording = FALSE;
  616. if (m_eStatus != ENUM_STATUS_READY)
  617. {
  618. return FALSE;
  619. }
  620. if (!OpenWaveFile(pszPath))
  621. return FALSE;
  622. MMRESULT mmReturn = 0;
  623. // open wavein device
  624. mmReturn = ::waveOutOpen ( &m_hPlay, m_uiDeviceID, &m_Format, (DWORD)GetSafeHwnd(), NULL, CALLBACK_WINDOW );
  625. if ( mmReturn )
  626. {
  627. TRACE("waveOutOpen() failedrn");
  628. return FALSE;
  629. }
  630. else
  631. {
  632. // make several input buffers and add them to the input queue
  633. for(int i=0; i<m_wInQueu; i++)
  634. {
  635. int nSize = m_dwQueuBufferSize;
  636. if ( !ReadSoundDataFromFile ( m_szAryInData[i], nSize ) )
  637. {
  638. if ( i == 0 )
  639. {
  640. AfxMessageBox ( "Read sound data from file failed" );
  641. return FALSE;
  642. }
  643. }
  644. if ( !AddOutputBufferToQueue ( i, nSize ) )
  645. return FALSE;
  646. }
  647. }
  648. m_eStatus = ENUM_STATUS_PLAYING;
  649. return TRUE;
  650. }
  651. BOOL CAudioCtrl::OpenWaveFile(char *lpszWaveFileName)
  652. {
  653. if ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] ) return FALSE; 
  654. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = ::mmioOpen ( (LPTSTR)lpszWaveFileName,NULL,MMIO_READ );
  655. if ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] == NULL ) 
  656. {
  657. AfxMessageBox ( "Open wave file failed" );
  658. return FALSE;
  659. }
  660. m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON].fccType = mmioFOURCC('W','A','V','E');
  661. MMRESULT mmResult = ::mmioDescend(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON],NULL,MMIO_FINDRIFF);
  662. if(mmResult)
  663. {
  664. AfxMessageBox("Error descending into file");
  665. ::mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0);
  666. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL;
  667. return FALSE;
  668. }
  669. m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].ckid = mmioFOURCC('f','m','t',' ');
  670. mmResult = mmioDescend(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],&m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON],&m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON],MMIO_FINDCHUNK);
  671. if(mmResult)
  672. {
  673. AfxMessageBox("Error descending in wave file");
  674. mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0);
  675. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL;
  676. return FALSE;
  677. }
  678. DWORD bytesRead = mmioRead ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],(LPSTR)&m_Format, m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].cksize );
  679. if ( bytesRead < 0 )
  680. {
  681. AfxMessageBox ( "Error reading PCM wave format record" );
  682. mmioClose ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], 0 );
  683. return FALSE;
  684. }
  685. if ( !SetRelateParaAfterGetWaveFormat () )
  686. return FALSE;
  687. // open output sound file
  688. mmResult = mmioAscend ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON], 0 );
  689. if ( mmResult )
  690. {
  691. AfxMessageBox ( "Error ascending in File" );
  692. mmioClose ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], 0 );
  693. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL;
  694. return FALSE;
  695. }
  696. m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].ckid = mmioFOURCC('d','a','t','a');
  697. mmResult = mmioDescend ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON], MMIO_FINDCHUNK );
  698. if ( mmResult )
  699. {
  700. AfxMessageBox("error reading data chunk");
  701. mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0);
  702. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL;
  703. return FALSE;
  704. }
  705. return TRUE;
  706. }
  707. BOOL CAudioCtrl::ReadSoundDataFromFile(LPVOID data, int &size)
  708. {
  709. ASSERT ( data && size > 0 );
  710. ASSERT ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] );
  711. return ( ( size = ::mmioRead ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], (char*)data, size) ) > 0 );
  712. }
  713. BOOL CAudioCtrl::AddOutputBufferToQueue(int nIndex, int nSize)
  714. {
  715. ASSERT ( nIndex >= 0 && nIndex < m_wInQueu );
  716. ASSERT ( m_szAryInData[nIndex] );
  717. MMRESULT mmReturn = 0;
  718. // create the header
  719. LPWAVEHDR pHdr = m_pAryHdr[nIndex];
  720. memset ( pHdr, 0, sizeof(WAVEHDR) );
  721. // new a buffer
  722. pHdr->lpData = (char*)m_szAryInData[nIndex];
  723. pHdr->dwBufferLength = m_dwQueuBufferSize;
  724. pHdr->dwBytesRecorded = nSize;
  725. pHdr->dwFlags = 0;
  726. pHdr->dwUser = nIndex;
  727. // prepare it
  728. mmReturn = ::waveOutPrepareHeader ( m_hPlay, pHdr, sizeof(WAVEHDR) );
  729. if ( mmReturn )
  730. {
  731. TRACE("waveOutPrepareHeader() failed!rn");
  732. return FALSE;
  733. }
  734. // write the buffer to output queue
  735. mmReturn = ::waveOutWrite ( m_hPlay, pHdr, sizeof(WAVEHDR) );
  736. if (mmReturn) 
  737. {
  738. TRACE("waveOutWrite() failed!rn");
  739. }
  740. // increment the number of waiting buffers
  741. m_nDataQueueNum++;
  742. int nBytesPickup = PickupMonoData ( m_Format.wBitsPerSample, pHdr->lpData, pHdr->dwBytesRecorded );
  743. //绘制波形
  744. DrawWave((DWORD)nBytesPickup);
  745. return TRUE;
  746. }
  747. void CAudioCtrl::StopPlay()
  748. {
  749. MMRESULT mmReturn = 0;
  750. if ( !m_hPlay ) return;
  751. if ( m_eStatus != ENUM_STATUS_PLAYING && m_eStatus != ENUM_STATUS_STOPING )
  752. return;
  753. waveOutPause(m_hPlay);
  754. mmReturn = ::waveOutClose(m_hPlay);
  755. if (mmReturn)
  756. {
  757. TRACE("waveOutClose() failed!rn");
  758. }
  759. m_hPlay = NULL;
  760. if (m_hWaveFile[ENUM_FILE_CHANNEL_COMMON])
  761. {
  762. ::mmioClose ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], 0 );
  763. m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL;
  764. }
  765. m_eStatus = ENUM_STATUS_READY;
  766. StopAndFreeAll();
  767. }
  768. void CAudioCtrl::StopAndFreeAll()
  769. {
  770. if (m_hRecord)
  771. {
  772. StopRec();
  773. }
  774. if (m_hPlay)
  775. {
  776. StopPlay();
  777. }
  778. FreeBuffer();
  779. }
  780. //
  781. // 绘图
  782. //
  783. BOOL CAudioCtrl::OnEraseBkgnd(CDC* pDC) 
  784. {
  785. DrawBackground ( pDC );
  786. return CWnd::OnEraseBkgnd(pDC);
  787. }
  788. void CAudioCtrl::DrawBackground(CDC *pDC, BOOL bLeftChannel)
  789. {
  790. ASSERT ( pDC );
  791. if ( !m_brsBkGnd.GetSafeHandle() ) return;
  792. // 画背景
  793. CString csCaption;
  794. CRect rcBK = GetRectByChannel ( bLeftChannel );
  795. if ( bLeftChannel )
  796. {
  797. csCaption = "Left";
  798. }
  799. else
  800. {
  801. csCaption = "Right";
  802. }
  803. pDC->FillRect ( &rcBK, &m_brsBkGnd );
  804. // 画文字
  805. CFont *pOldFnt = NULL;
  806. if ( m_fntChannelText.GetSafeHandle() )
  807. {
  808. pOldFnt = pDC->SelectObject ( &m_fntChannelText );
  809. }
  810. CRect rcText = rcBK;
  811. rcText.DeflateRect ( 2, 2 );
  812. pDC->SetTextColor ( RGB(255,255,0) );
  813. pDC->DrawText ( csCaption, &rcText, DT_LEFT | DT_TOP | DT_SINGLELINE );
  814. if ( pOldFnt ) pDC->SelectObject ( pOldFnt );
  815. }
  816. void CAudioCtrl::DrawBackground(CDC *pDC)
  817. {
  818. pDC->SetBkMode ( TRANSPARENT );
  819. DrawBackground ( pDC, TRUE );
  820. DrawBackground ( pDC, FALSE );
  821. // 画分隔线
  822. CPen *pOldPen = NULL;
  823. if ( m_PenPartLine.GetSafeHandle() )
  824. pOldPen = pDC->SelectObject ( &m_PenPartLine );
  825. pDC->MoveTo ( 0, m_rcClient.Height()/2 );
  826. pDC->LineTo ( m_rcClient.right, m_rcClient.Height()/2 );
  827. if ( pOldPen ) pDC->SelectObject ( pOldPen );
  828. // 画声卡名文字
  829. /*
  830. CFont *pOldFnt = NULL;
  831. CRect rcText = m_rcClient;
  832. rcText.DeflateRect ( 4, 4 );
  833. if ( m_fntDeviceNameText.GetSafeHandle() )
  834. {
  835. pOldFnt = pDC->SelectObject ( &m_fntDeviceNameText );
  836. }
  837. pDC->SetTextColor ( RGB(128,255,255) );
  838. pDC->DrawText ( "haha!", &rcText, DT_RIGHT | DT_BOTTOM | DT_SINGLELINE );
  839. if ( pOldFnt ) pDC->SelectObject ( pOldFnt );
  840. */
  841. // 画外框
  842. pDC->Draw3dRect ( &m_rcClient, COLOR_FRAME, COLOR_FRAME );
  843. }
  844. CRect CAudioCtrl::GetRectByChannel(BOOL bLeftChannel)
  845. {
  846. CRect rcBK = m_rcClient;
  847. if ( bLeftChannel )
  848. {
  849. rcBK.bottom = (m_rcClient.Height() - PARTLINE_HEIGHT) / 2;
  850. }
  851. else
  852. {
  853. rcBK.top = (m_rcClient.Height() + PARTLINE_HEIGHT) / 2;
  854. }
  855. return rcBK;
  856. }
  857. void CAudioCtrl::SetBkColor(COLORREF clr)
  858. {
  859. m_clrBK = clr;
  860. if ( m_brsBkGnd.GetSafeHandle() )
  861. {
  862. m_brsBkGnd.DeleteTempMap();
  863. m_brsBkGnd.DeleteObject();
  864. }
  865. m_brsBkGnd.CreateSolidBrush ( clr );
  866. if ( ::IsWindow ( m_hWnd ) )
  867. Invalidate ();
  868. if ( m_PenB.GetSafeHandle() )
  869. m_PenB.DeleteObject ();
  870. m_PenB.CreatePen ( PS_SOLID, 0, m_clrBK );
  871. }
  872. void CAudioCtrl::DrawWave(DWORD dwChannelBytes)
  873. {
  874. CClientDC dc(this);
  875. BOOL bRecLeft = TRUE, bRecRight = TRUE;
  876. if ( !m_bAlwaysDrawTowChannel && m_eStatus == ENUM_STATUS_RECORDING && m_eRecChannel == ENUM_REC_CHANNEL_ALONE )
  877. {
  878. if ( !m_hWaveFile[ENUM_FILE_CHANNEL_LEFT])
  879. bRecLeft = FALSE;
  880. if ( !m_hWaveFile[ENUM_FILE_CHANNEL_RIGHT])
  881. bRecRight = FALSE;
  882. }
  883. // 先将上次画的擦掉
  884. DrawBackground ( &dc );
  885. // 画波形图
  886. CPen *pOndPen = dc.SelectObject ( &m_PenG );
  887. if (m_Format.wBitsPerSample == 8)
  888. {
  889. if (bRecLeft) 
  890. {
  891. DrwaWaveChar(dc, dwChannelBytes/2, (BYTE*)m_szLeftInData, TRUE);
  892. }
  893. if (bRecRight) 
  894. {
  895. DrwaWaveChar(dc, dwChannelBytes/2, (BYTE*)m_szRightInData, FALSE);
  896. }
  897. }
  898. else
  899. {
  900. if (bRecLeft)
  901. {
  902. DrwaWaveShort(dc, dwChannelBytes/2, (SHORT*)m_szLeftInData, TRUE);
  903. }
  904. if (bRecRight) 
  905. {
  906. DrwaWaveShort(dc, dwChannelBytes/2, (SHORT*)m_szRightInData, FALSE);
  907. }
  908. }
  909. if (pOndPen)
  910. dc.SelectObject ( pOndPen );
  911. }
  912. void CAudioCtrl::DrwaWaveChar(CClientDC &dc, 
  913.   DWORD dwDrawBytes, 
  914.   BYTE *pCharData, 
  915.   BOOL bLeftChannel)
  916. {
  917. CRect rcBK = GetRectByChannel ( bLeftChannel );
  918. int y = (int) ( pCharData[0] * rcBK.Height() / 0xff );
  919. dc.MoveTo ( 0, y );
  920. float fStep = (float)rcBK.Width() / (float)(dwDrawBytes);
  921. float fLineX = 0;
  922. for ( DWORD i=1; i<dwDrawBytes; i++ )
  923. {
  924. fLineX += fStep;
  925. y = (int) ( pCharData[i] * rcBK.Height() / 0xff );
  926. dc.LineTo ( (int)fLineX, y );
  927. //TRACE2("DrawWave X=%f Y=%drn", fLineX, y);
  928. }
  929. }
  930. void CAudioCtrl::DrwaWaveShort(CClientDC &dc, DWORD dwDrawBytes, SHORT *pShortData, BOOL bLeftChannel)
  931. {
  932. CRect rcBK = GetRectByChannel ( bLeftChannel );
  933. int nCenterY = rcBK.CenterPoint().y;
  934. int y = nCenterY + (int) ( pShortData[0] * rcBK.Height() / 0xffff );
  935. dc.MoveTo ( 0, y );
  936. float fStep = (float)rcBK.Width() / (float)(dwDrawBytes);
  937. float fLineX = 0;
  938. for ( DWORD i=1; i<dwDrawBytes; i++ )
  939. {
  940. fLineX += fStep;
  941. y = nCenterY + (int) ( pShortData[i] * rcBK.Height() / 0xffff );
  942. dc.LineTo ( (int)fLineX, y );
  943. //TRACE2("DrwaWaveShort X=%f Y=%drn", fLineX, y);
  944. }
  945. }
  946. BOOL CAudioCtrl::IsPlay()
  947. {
  948. if (m_eStatus == ENUM_STATUS_PLAYING)
  949. {
  950. return TRUE;
  951. }
  952. return FALSE;
  953. }
  954. BOOL CAudioCtrl::IsRecord()
  955. {
  956. if (m_eStatus == ENUM_STATUS_RECORDING)
  957. {
  958. return TRUE;
  959. }
  960. return FALSE;
  961. }