AudioPlayer.cpp
Upload User: shxiangxiu
Upload Date: 2007-01-03
Package Size: 1101k
Code Size: 18k
Category:

OpenGL program

Development Platform:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // AudioPlayer.cpp : implementation file
  3. //
  4. // glOOP (OpenGL Object Oriented Programming library)
  5. // Copyright (c) Craig Fahrnbach 1997, 1998
  6. //
  7. // OpenGL is a registered trademark of Silicon Graphics
  8. //
  9. //
  10. // This program is provided for educational and personal use only and
  11. // is provided without guarantee or warrantee expressed or implied.
  12. //
  13. // Commercial use is strickly prohibited without written permission
  14. // from ImageWare Development.
  15. //
  16. // This program is -not- in the public domain.
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "glOOP.h"
  21. #include "DIBUtil.h"
  22. #include <mmsystem.h>
  23. #include <time.h>
  24. #ifdef _DEBUG
  25. #define new DEBUG_NEW
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CAudioPlayer Global definitions
  31. // Since we can only have one audio device playing at any time, we declare a few 
  32. // global variable
  33. BOOL g_bDeviceIsBusy = FALSE; // Audio device flag
  34. long g_lSample; // Position, in samples, of the avi audio read stream
  35. long g_lNumSamples; // Number of audio samples in the avi audio stream
  36. HWAVEOUT g_hWaveOut; // Handle identifying the open waveform-audio output device.
  37. // Our multi-media timer callback procedure
  38. static void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser,
  39.   DWORD dw1, DWORD dw2)
  40. {
  41. // The multi-media timer has timed out.  Write the wave header to the audio
  42. // device.  The waveOutWrite function returns immediately and waveform data
  43. // is sent to the output device in the background.  If the audio device queue
  44. // is empty, playback begins immediatly, otherwise the wave header is placed
  45. // in the queue.
  46. waveOutWrite(g_hWaveOut, (LPWAVEHDR)dwUser, sizeof(WAVEHDR)); 
  47. }
  48.  
  49. // Our audio device callback procedure
  50. static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
  51.  DWORD dwParam1, DWORD dwParam2)
  52. {
  53. CAudioPlayer* pAudioPlayer;
  54. pAudioPlayer = (CAudioPlayer*) dwInstance;
  55. ASSERT(pAudioPlayer);
  56. if(uMsg == WOM_DONE && pAudioPlayer->m_bPlayAudioClip)
  57. {
  58. // The audio device has finished playing the wave header data, so get the next
  59. // audio 'chunk'.
  60. pAudioPlayer->GetWaveformData(pAudioPlayer, (LPWAVEHDR)dwParam1);
  61. // Start a multi-media timer, which when expired, will call our waveOutWrite
  62. // function.  We cannot call the waveOutWrite function here, since, per the
  63. // waveOutProc documentation:  Calling other wave functions will cause deadlock.
  64. timeSetEvent(10, // Event delay, in milliseconds.
  65.  10, // Resolution of the timer event, in milliseconds. 
  66.  &TimeProc, // Address of the callback function
  67.  dwParam1, // User supplied callback data (pointer to our wavehdr)
  68.  TIME_ONESHOT); // Trigger event once, after uDelay milliseconds.
  69. }
  70. }
  71. /////////////////////////////////////////////////////////////////////////////
  72. // CAudioPlayer
  73. IMPLEMENT_DYNAMIC(CAudioPlayer, CObject)
  74. /////////////////////////////////////////////////////////////////////////////
  75. // CAudioPlayer construction
  76. CAudioPlayer* CAudioPlayer::Create(LPSTR pszFileName)
  77. {
  78. UINT wResult; // Return error code
  79. if(!pszFileName)
  80. return NULL;
  81. // TODO:  Add file extension check for formats other than .avi
  82. CAudioPlayer* pAudioPlayer = new CAudioPlayer;
  83. ASSERT(pAudioPlayer);
  84. wResult = pAudioPlayer->InitAVI(pszFileName);
  85. if(wResult)
  86. {
  87. delete pAudioPlayer;
  88. return (NULL);
  89. }
  90. return (pAudioPlayer);
  91. }
  92. CAudioPlayer::CAudioPlayer()
  93. {
  94. int i;
  95. m_bPlayAudioClip = FALSE; // Flag for this Audio clip
  96. m_bDeviceOpen  = FALSE; // Audio device not opened
  97. m_bSynchAudio    = FALSE; // Resynchronize audio stream
  98. m_pAudioStream   = NULL; // Pointer to the AVI Audio stream interface.
  99. m_dwDataSize    = 0L; // Size of our audio data buffer
  100. m_iWBufferScale = 4; // Audio write buffer scale size
  101. for(i=0; i<WRITE_BUFFERS; i++)
  102. {
  103. // Clear our audio data buffer handles and pointers
  104. m_hAudioData[i]  = NULL; // Handle of waveform data memory 
  105. m_lpAudioData[i] = NULL; // Pointer to waveform data memory 
  106. // Clear our wave header handles and pointers
  107. m_hWaveHdr[i]    = NULL; // Handle to waveform data block header 
  108. m_lpWaveHdr[i]   = NULL; // Pointer to waveform data block header
  109. }
  110. }
  111. /////////////////////////////////////////////////////////////////////////////
  112. // CAudioPlayer Destructor
  113. CAudioPlayer::~CAudioPlayer()
  114. {
  115. int i;
  116. if(m_bDeviceOpen)
  117. {
  118. Close(); // Close the audio device;
  119. // End streaming
  120. AVIStreamEndStreaming(m_pAudioStream);
  121. for(i=0; i<WRITE_BUFFERS; i++)
  122. {
  123. // Clean up the preparation performed by the waveOutPrepareHeader
  124. // function before we free the header..
  125. waveOutUnprepareHeader(g_hWaveOut, m_lpWaveHdr[i], sizeof(WAVEHDR));
  126. // Free the waveform data block header
  127. if(m_hWaveHdr[i])
  128. {
  129. GlobalUnlock(m_hWaveHdr[i]);
  130. GlobalFree(m_hWaveHdr[i]);
  131. m_hWaveHdr[i]  = NULL;
  132. m_lpWaveHdr[i] = NULL;
  133. }
  134. // Free the waveform data memory block
  135. if(m_hAudioData[i])
  136. {
  137. GlobalUnlock(m_hAudioData[i]);
  138. GlobalFree(m_hAudioData[i]);
  139. m_hAudioData[i]  = NULL;
  140. m_lpAudioData[i] = NULL;
  141. }
  142. }
  143. // Clear the handle of the wave out audio device
  144. g_hWaveOut = NULL;
  145. // Clear the audio stream pointer
  146. m_pAudioStream = NULL;
  147. }
  148. }
  149. /////////////////////////////////////////////////////////////////////////////
  150. // CAudioPlayer AVI type specific function implementation
  151. void CAudioPlayer::GetAviWaveformData(LPVOID pInstance, LPWAVEHDR lpWaveHdr)
  152. {
  153. UINT wResult; // Return error code
  154. long lBytes;
  155. long lSamples;
  156. CAudioPlayer* pAudioPlayer;
  157. pAudioPlayer = (CAudioPlayer*) pInstance;
  158. ASSERT(pAudioPlayer);
  159. if(pAudioPlayer->m_bSynchAudio)
  160. {
  161. clock_t current;
  162. double dDuration;
  163. long lTimeOffset;
  164. // Reset the flag
  165. pAudioPlayer->m_bSynchAudio = FALSE;
  166. // Get the current time
  167. current = clock();
  168. // Calculate the time offset and ADD to our stream sample index
  169. dDuration = (double)(current - pAudioPlayer->m_SynchTime) / CLOCKS_PER_SEC;
  170. lTimeOffset = (long)(dDuration/1000.f);
  171. g_lSample +=lTimeOffset;
  172. }
  173. // Read the waveform data 'chunk' from the stream
  174. wResult = AVIStreamRead(pAudioPlayer->m_pAudioStream,
  175. g_lSample,
  176. pAudioPlayer->m_dwDataSize,
  177. lpWaveHdr->lpData,
  178. pAudioPlayer->m_dwDataSize,
  179. &lBytes,
  180. &lSamples);
  181. if(wResult)
  182. return;
  183. // Increment the stream sample index and ensure that it does not extend beyond
  184. // the number of samples in the stream (Note that this will wrap the sample
  185. // index back to the beginning of the stream if necessary..)
  186. g_lSample = (g_lSample += lSamples) % g_lNumSamples;
  187. }
  188. DWORD CAudioPlayer::InitAVI(LPSTR pszFileName)
  189. {
  190. AVISTREAMINFO FAR psi; // AVI Stream Info header pointer
  191. UINT wResult; // Return error code
  192. if(m_pAudioStream)
  193. return (1); // Should initilize the device only once!
  194. // Try to open the AVI audio stream
  195. wResult = AVIStreamOpenFromFile(&m_pAudioStream,
  196. pszFileName,
  197. streamtypeAUDIO,
  198. 0,
  199. OF_READ,
  200. NULL);
  201. if(wResult)
  202. return (wResult); // return error
  203. // Get the length and number of samples in the audio stream
  204. m_lAudioLength = AVIStreamLengthTime(m_pAudioStream);
  205. g_lNumSamples = AVIStreamLength(m_pAudioStream);
  206. // Fill the AVISTREAMINFO structure information for this stream
  207. AVIStreamInfo(m_pAudioStream, &psi, sizeof(AVISTREAMINFO FAR));
  208. // Save the size of the audio data block.  We use the SuggestedBuffer
  209. // size and multiply by our buffer scaling factor.  
  210. // Note:  for optimum performance, our buffer should be aprox. 500 ms in size..
  211. m_dwDataSize = psi.dwSuggestedBufferSize * m_iWBufferScale;
  212. // Fill the waveform-audio data structure
  213. // m_WFX.wFormatTag = WAVE_FORMAT_PCM;
  214. // m_WFX.nChannels = 2;
  215. // m_WFX.nSamplesPerSec = psi.dwRate/psi.dwScale;
  216. // m_WFX.nAvgBytesPerSec = m_WFX.nSamplesPerSec*m_WFX.nChannels;
  217. // m_WFX.nBlockAlign = (unsigned short)psi.dwSampleSize;
  218. // m_WFX.wBitsPerSample = 8;
  219. // m_WFX.cbSize = 0;
  220. // Read the WAVEFORMATEX settings from the audio stream
  221. long sizeofWFX = sizeof(WAVEFORMATEX);
  222. wResult = AVIStreamReadFormat(m_pAudioStream,
  223.   AVIStreamTimeToSample(m_pAudioStream, 0L),
  224.   &m_WFX,
  225.   &sizeofWFX);
  226. if(wResult)
  227. return (wResult); // return error
  228. // Set the GetWaveformData function pointer to point to the
  229. // appropriate static procedure..
  230. GetWaveformData = CAudioPlayer::GetAviWaveformData;
  231. // Now that we have the AVI specific audio 'stuff' initialized,
  232. // allocate memory for our audio data and wave header
  233. return( Initialize() );
  234. }
  235. /////////////////////////////////////////////////////////////////////////////
  236. // CAudioPlayer generic function implementation
  237. DWORD CAudioPlayer::Initialize()
  238. {
  239. int i;
  240. for(i=0; i<WRITE_BUFFERS; i++)
  241. {
  242. // Allocate and lock memory for the audio data block
  243. m_hAudioData[i] = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, m_dwDataSize ); 
  244. if (!m_hAudioData[i])
  245. {
  246. AfxMessageBox("CAudioPlayer::Initialize - Out of memory.",
  247. MB_OK | MB_ICONEXCLAMATION); 
  248. return (1); // return error
  249. if ((m_lpAudioData[i] = (HPSTR)GlobalLock(m_hAudioData[i])) == NULL)
  250. {
  251. AfxMessageBox("CAudioPlayer::Initialize - Failed to lock memory for data chunk.",
  252. MB_OK | MB_ICONEXCLAMATION);
  253. GlobalFree(m_hAudioData[i]); 
  254. m_hAudioData[i] = NULL;
  255. return (1); // return error
  256. // Allocate and lock memory for the header. 
  257. m_hWaveHdr[i] = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 
  258.    (DWORD) sizeof(WAVEHDR)); 
  259. if (m_hWaveHdr[i] == NULL)
  260. {
  261. GlobalUnlock(m_hAudioData[i]);
  262. GlobalFree(m_hAudioData[i]); 
  263. AfxMessageBox("CAudioPlayer::Initialize - Not enough memory for header.",
  264. MB_OK | MB_ICONEXCLAMATION); 
  265. return (1); // return error
  266. m_lpWaveHdr[i] = (LPWAVEHDR) GlobalLock(m_hWaveHdr[i]);
  267. if (m_lpWaveHdr[i] == NULL)
  268. {
  269. GlobalUnlock(m_hAudioData[i]);
  270. GlobalFree(m_hAudioData[i]);
  271. AfxMessageBox("CAudioPlayer::Initialize - Failed to lock memory for header.",
  272. MB_OK | MB_ICONEXCLAMATION);
  273. GlobalFree(m_hWaveHdr[i]);
  274. m_hWaveHdr[i] = NULL;
  275. return (1); // return error
  276. }
  277. return (0); // No errors
  278. }
  279. DWORD CAudioPlayer::Open(LPSTR pszFileName)
  280. {
  281. UINT wResult; // Return error code
  282. // If the audio device is busy (playing another file)
  283. // return error
  284. if(g_bDeviceIsBusy)
  285. return (1);
  286. // Try to open the AVI audio stream
  287. wResult = AVIStreamOpenFromFile(&m_pAudioStream,
  288. pszFileName,
  289. streamtypeAUDIO,
  290. 0,
  291. OF_READ,
  292. NULL);
  293. if(wResult)
  294. return (wResult); // return error
  295. // Open the audio device
  296. wResult = waveOutOpen(&g_hWaveOut,
  297.   WAVE_MAPPER, // select a waveform-audio output device
  298.    // capable of playing the given format.
  299.   &m_WFX,
  300.   (DWORD)&waveOutProc, // Callback procedure
  301.   (DWORD)this, // CallbackInstance,
  302.   CALLBACK_FUNCTION |
  303.   WAVE_ALLOWSYNC);
  304. if(wResult)
  305. {
  306. // If an error occurred, display the error message
  307. DisplayError(wResult);
  308. return (wResult); // return error
  309. }
  310. // This CAudioPlayer class instance has the audio device open
  311. m_bDeviceOpen = TRUE;
  312. // Set the global flag (Audio device busy)
  313. g_bDeviceIsBusy = TRUE;
  314. return (0); // No errors
  315. }
  316. DWORD CAudioPlayer::Close()
  317. {
  318. UINT wResult; // Return error code
  319. int  iWait = 0;
  320. if(m_bPlayAudioClip && m_bDeviceOpen)
  321. {
  322. m_bPlayAudioClip = FALSE; // Disable the audio track
  323. // Wait for the audio 'chunck' to finish
  324. while(!m_lpWaveHdr[0]->dwFlags & WHDR_DONE)
  325. {
  326. // Let's wait for the device to finish.  Just so
  327. // we don't get caught in this loop forever, increment
  328. // a wait counter and abort if exceeded.
  329. Sleep(100);
  330. ++iWait;
  331. if(iWait > 20) // Max 2 second delay
  332. break;
  333. }
  334. }
  335. // Close the waveform-audio output device
  336. if(g_hWaveOut)
  337. {
  338. wResult = waveOutReset(g_hWaveOut); // Reset the audio device
  339. if(!wResult)
  340. {
  341. wResult = waveOutClose(g_hWaveOut); // Close the audio device
  342. if(!wResult)
  343. {
  344. m_bDeviceOpen = FALSE;
  345. g_bDeviceIsBusy = FALSE;
  346. }
  347. }
  348. }
  349. return (wResult);
  350. }
  351. DWORD CAudioPlayer::Play(double dTime)
  352. {
  353. // The Play() procedure converts the requested start time to correspond to 
  354. // the stream sample requested, formats the Wave Write Header, prepares the
  355. // header for writing, gets the audio data from the stream and writes the
  356. // data to the audio device.  We use two write buffers to ensure that the 
  357. // audio is played without 'gaps' by initially writing both buffers to the 
  358. // audio device.  Once the audio chunk has been played, our WaveOutProc() 
  359. // takes care of getting the next audio chunk and sending to the device.
  360. //
  361. // Note that this procedure just gets things going...
  362. //
  363. UINT wResult; // Return error code
  364. long lTime; // Converted time value to long (milliseconds)
  365. if(!m_bPlayAudioClip && m_bDeviceOpen)
  366. {
  367. m_bPlayAudioClip = TRUE;
  368. int i;
  369. // Convert the requested start time to samples, in milliseconds.
  370. lTime = (long)((int)(dTime*1000) % m_lAudioLength);
  371. // Get the starting sample
  372. g_lSample = AVIStreamTimeToSample(m_pAudioStream, lTime);
  373.  
  374. for(i=0; i<WRITE_BUFFERS; i++)
  375. {
  376. // To ensure that our audio stream is played without 'gaps', we need at
  377. // least two (2) audio write buffers.  Format the wave headers
  378. m_lpWaveHdr[i]->dwBufferLength = m_dwDataSize;
  379. m_lpWaveHdr[i]->lpData = m_lpAudioData[i];
  380. m_lpWaveHdr[i]->dwFlags = 0L;
  381. m_lpWaveHdr[i]->dwLoops = 0L;
  382. // Prepare the waveform-audio data block for playback.
  383. wResult = waveOutPrepareHeader(g_hWaveOut, m_lpWaveHdr[i], sizeof(WAVEHDR)); 
  384. if(wResult)
  385. {
  386. // If an error occurred, display the error message
  387. DisplayError(wResult);
  388. return (wResult); // return error
  389. }
  390. // Get the waveform audio data
  391. GetWaveformData(this, m_lpWaveHdr[i]);
  392. // Now the data block can be sent to the output device. The 
  393. // waveOutWrite function returns immediately and waveform 
  394. // data is sent to the output device in the background.
  395. // If the audio device queue is empty, playback begins immediatly, 
  396. // otherwise the wave header is placed in the queue.
  397. wResult = waveOutWrite(g_hWaveOut, m_lpWaveHdr[i], sizeof(WAVEHDR));
  398. if(wResult)
  399. {
  400. // If an error occurred, display the error message
  401. DisplayError(wResult);
  402. return (wResult); // return error
  403. }
  404. }
  405. return (wResult);
  406. }
  407. return (1); // Audio already playing or opened by another device..
  408. }
  409. DWORD CAudioPlayer::Stop()
  410. {
  411. return (Close());
  412. }
  413. DWORD CAudioPlayer::GetVolumn(LPDWORD lpdwVolumn)
  414. {
  415. UINT wResult; // Return error code
  416. // UINT uDeviceID; // Audio device ID
  417. // AUXCAPS Caps; // Structure which describes the audio device capabilities
  418. /*
  419. wResult = waveOutGetID(g_hWaveOut, (LPUINT)&uDeviceID);
  420. if(wResult)
  421. return (wResult); // Return error code
  422. wResult = auxGetDevCaps(uDeviceID, &Caps, sizeof(AUXCAPS));
  423. if(wResult)
  424. return (wResult); // Return error code
  425. if(Caps.dwSupport & AUXCAPS_VOLUME)
  426. {
  427. // Device supports Volumn control
  428. wResult = auxGetVolume(uDeviceID, lpdwVolumn);
  429. if(wResult)
  430. return (wResult); // Return error code
  431. }
  432. */
  433. // Device supports Volumn control
  434. wResult = waveOutGetVolume(g_hWaveOut, lpdwVolumn);
  435. if(wResult)
  436. return (wResult); // Return error code
  437. return (0);
  438. }
  439. DWORD CAudioPlayer::SetVolumn(DWORD dwVolumn)
  440. {
  441. UINT wResult; // Return error code
  442. // UINT uDeviceID; // Audio device ID
  443. // AUXCAPS Caps; // Structure which describes the audio device capabilities
  444. /*
  445. wResult = waveOutGetID(g_hWaveOut, &uDeviceID);
  446. if(wResult)
  447. return (wResult); // Return error code
  448. wResult = auxGetDevCaps(uDeviceID, &Caps, sizeof(AUXCAPS));
  449. if(wResult)
  450. return (wResult); // Return error code
  451. if(Caps.dwSupport & AUXCAPS_VOLUME)
  452. {
  453. // Device supports Volumn control
  454. wResult = auxSetVolume(uDeviceID, dwVolumn);
  455. if(wResult)
  456. return (wResult); // Return error code
  457. }
  458. */
  459. // Device supports Volumn control
  460. wResult = waveOutSetVolume(g_hWaveOut, dwVolumn);
  461. if(wResult)
  462. return (wResult); // Return error code
  463. return (0);
  464. }
  465. DWORD CAudioPlayer::GetPitch(LPDWORD lpdwPitch)
  466. {
  467. UINT wResult; // Return error code
  468. // Get the audio device's pitch or playback rate
  469. wResult = waveOutGetPitch(g_hWaveOut, lpdwPitch);
  470. if(wResult)
  471. return (wResult); // Return error code
  472. return (0);
  473. }
  474. DWORD CAudioPlayer::SetPitch(DWORD dwPitch)
  475. {
  476. UINT wResult; // Return error code
  477. // Set the audio device's pitch or playback rate
  478. wResult = waveOutSetPitch(g_hWaveOut, dwPitch);
  479. if(wResult)
  480. return (wResult); // Return error code
  481. return (0);
  482. }
  483. void CAudioPlayer::SynchAudio(double dTime)
  484. {
  485. // Set the Resynch flag and get the time of the request
  486. m_bSynchAudio = TRUE;
  487. m_SynchTime = clock();
  488. }
  489. void CAudioPlayer::DisplayError(UINT wError)
  490. {
  491. char buffer[128];
  492. switch (wError) 
  493. {
  494. case MMSYSERR_ALLOCATED:
  495. sprintf(buffer, "CAudioPlayer - Specified resource is already allocated.");
  496. case MMSYSERR_BADDEVICEID:
  497. sprintf(buffer, "CAudioPlayer - Specified device identifier is out of range.");
  498. case WAVERR_BADFORMAT:
  499. sprintf(buffer, "CAudioPlayer - Attempted to open with an unsupported waveform-audio format.");
  500. case WAVERR_SYNC:
  501. sprintf(buffer, "CAudioPlayer - The device is synchronous but waveOutOpen was called without using the WAVE_ALLOWSYNC flag.");
  502. case MMSYSERR_INVALHANDLE:
  503. sprintf(buffer, "CAudioPlayer - Specified device handle is invalid.");
  504. case MMSYSERR_NODRIVER:
  505. sprintf(buffer, "CAudioPlayer - No device driver is present.");
  506. case MMSYSERR_NOMEM:
  507. sprintf(buffer, "CAudioPlayer - Unable to allocate or lock memory.");
  508. case WAVERR_UNPREPARED:
  509. sprintf(buffer, "CAudioPlayer - The data block pointed to by the pwh parameter hasn't been prepared.");
  510. default:
  511. sprintf(buffer, "CAudioPlayer - UnDefined error.");
  512. }
  513. AfxMessageBox(buffer, MB_OK | MB_ICONEXCLAMATION);
  514. }