AUDIO.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:10k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /****************************************************************************
  2.  *
  3.  *  AUDIO.C
  4.  *
  5.  *  Simple routines to play audio using an AVIStream to get data.
  6.  *
  7.  *  Uses global variables, so only one instance at a time.
  8.  *  (Usually, there's only one sound card, so this isn't so bad.
  9.  *
  10.  **************************************************************************/
  11. /**************************************************************************
  12.  *
  13.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  14.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  15.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  16.  *  PURPOSE.
  17.  *
  18.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  19.  *
  20.  **************************************************************************/
  21. #define STRICT
  22. #define INC_OLE2
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include <mmsystem.h>
  26. #include "muldiv32.h"
  27. #include <vfw.h>
  28. #include "audio.h"
  29. /*--------------------------------------------------------------+
  30. | ****************** AUDIO PLAYING SUPPORT ******************** |
  31. +--------------------------------------------------------------*/
  32. static  HWAVEOUT        shWaveOut = 0;  /* Current MCI device ID */
  33. static  LONG            slBegin;
  34. static  LONG            slCurrent;
  35. static  LONG            slEnd;
  36. static  BOOL            sfLooping;
  37. static  BOOL            sfPlaying = FALSE;
  38. #define MAX_AUDIO_BUFFERS       16
  39. #define MIN_AUDIO_BUFFERS       2
  40. #define AUDIO_BUFFER_SIZE       16384
  41. static  WORD            swBuffers;          // total # buffers
  42. static  WORD            swBuffersOut;       // buffers device has
  43. static  WORD            swNextBuffer;       // next buffer to fill
  44. static  LPWAVEHDR       salpAudioBuf[MAX_AUDIO_BUFFERS];
  45. static  PAVISTREAM      spavi;              // stream we're playing
  46. static  LONG            slSampleSize;       // size of an audio sample
  47. static  LONG            sdwBytesPerSec;
  48. static  LONG            sdwSamplesPerSec;
  49. /*---------------------------------------------------------------+
  50. | aviaudioCloseDevice -- close the open audio device, if any.    |
  51. +---------------------------------------------------------------*/
  52. void aviaudioCloseDevice(void)
  53. {
  54.     if (shWaveOut)
  55.     {
  56. while (swBuffers > 0)
  57. {
  58. --swBuffers;
  59. waveOutUnprepareHeader(shWaveOut, salpAudioBuf[swBuffers],
  60. sizeof(WAVEHDR));
  61. GlobalFreePtr((LPSTR) salpAudioBuf[swBuffers]);
  62. }
  63. waveOutClose(shWaveOut);
  64. shWaveOut = NULL;
  65.     }
  66. }
  67. /*--------------------------------------------------------------+
  68. | aviaudioOpenDevice -- get ready to play waveform data.        |
  69. +--------------------------------------------------------------*/
  70. BOOL CALLBACK aviaudioOpenDevice(HWND hwnd, PAVISTREAM pavi)
  71. {
  72.     MMRESULT            mmResult;
  73.     LPVOID              lpFormat;
  74.     LONG                cbFormat;
  75.     AVISTREAMINFO       strhdr;
  76.     if (!pavi)          // no wave data to play
  77. return FALSE;
  78.     if (shWaveOut)      // already something playing
  79. return TRUE;
  80.     spavi = pavi;
  81.     AVIStreamInfo(pavi, &strhdr, sizeof(strhdr));
  82.     slSampleSize = (LONG) strhdr.dwSampleSize;
  83.     if (slSampleSize <= 0 || slSampleSize > AUDIO_BUFFER_SIZE)
  84. return FALSE;
  85.     AVIStreamFormatSize(pavi, 0, &cbFormat);
  86.     lpFormat = GlobalAllocPtr(GHND, cbFormat);
  87.     if (!lpFormat)
  88. return FALSE;
  89.     AVIStreamReadFormat(pavi, 0, lpFormat, &cbFormat);
  90.     sdwSamplesPerSec = ((LPWAVEFORMAT) lpFormat)->nSamplesPerSec;
  91.     sdwBytesPerSec = ((LPWAVEFORMAT) lpFormat)->nAvgBytesPerSec;
  92.     mmResult = waveOutOpen(&shWaveOut, (UINT)WAVE_MAPPER, lpFormat,
  93. (DWORD) (UINT) hwnd, 0L, CALLBACK_WINDOW);
  94.     //
  95.     // Maybe we failed because someone is playing sound already.
  96.     // Shut any sound off, and try once more before giving up.
  97.     //
  98.     if (mmResult) {
  99. sndPlaySound(NULL, 0);
  100. mmResult = waveOutOpen(&shWaveOut, (UINT)WAVE_MAPPER, lpFormat,
  101. (DWORD) (UINT)hwnd, 0L, CALLBACK_WINDOW);
  102.     }
  103.     if (mmResult != 0)
  104.     {
  105. /* Show error message here? */
  106. return FALSE;
  107.     }
  108.     for (swBuffers = 0; swBuffers < MAX_AUDIO_BUFFERS; swBuffers++)
  109.     {
  110. if (!(salpAudioBuf[swBuffers] =
  111. (LPWAVEHDR)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  112. (DWORD)(sizeof(WAVEHDR) + AUDIO_BUFFER_SIZE))))
  113. break;
  114. salpAudioBuf[swBuffers]->dwFlags = WHDR_DONE;
  115. salpAudioBuf[swBuffers]->lpData = (LPSTR) salpAudioBuf[swBuffers]
  116.     + sizeof(WAVEHDR);
  117. salpAudioBuf[swBuffers]->dwBufferLength = AUDIO_BUFFER_SIZE;
  118. if (!waveOutPrepareHeader(shWaveOut, salpAudioBuf[swBuffers],
  119. sizeof(WAVEHDR)))
  120. continue;
  121. GlobalFreePtr((LPSTR) salpAudioBuf[swBuffers]);
  122. break;
  123.     }
  124.     if (swBuffers < MIN_AUDIO_BUFFERS)
  125.     {
  126. aviaudioCloseDevice();
  127. return FALSE;
  128.     }
  129.     swBuffersOut = 0;
  130.     swNextBuffer = 0;
  131.     sfPlaying = FALSE;
  132.     return TRUE;
  133. }
  134. /*--------------------------------------------------------------+
  135. | aviaudioTime -                                                |
  136. | Return the time in milliseconds corresponding to the          |
  137. | currently playing audio sample, or -1 if no audio is playing. |
  138. |                                                               |
  139. | WARNING: Some sound cards are pretty inaccurate!              |
  140. +--------------------------------------------------------------*/
  141. LONG CALLBACK aviaudioTime(void)
  142. {
  143.     MMTIME      mmtime;
  144.     if (!sfPlaying)
  145. return -1;
  146.     mmtime.wType = TIME_SAMPLES;
  147.     waveOutGetPosition(shWaveOut, &mmtime, sizeof(mmtime));
  148.     if (mmtime.wType == TIME_SAMPLES)
  149. return AVIStreamSampleToTime(spavi, slBegin)
  150. + muldiv32(mmtime.u.sample, 1000, sdwSamplesPerSec);
  151.     else if (mmtime.wType == TIME_BYTES)
  152. return AVIStreamSampleToTime(spavi, slBegin)
  153. + muldiv32(mmtime.u.cb, 1000, sdwBytesPerSec);
  154.     else
  155. return -1;
  156. }
  157. /*--------------------------------------------------------------+
  158. | aviaudioiFillBuffers -                                        |
  159. | Fill up any empty audio buffers and ship them out to the      |
  160. | device.                                                       |
  161. +--------------------------------------------------------------*/
  162. BOOL aviaudioiFillBuffers(void)
  163. {
  164.     LONG                lRead;
  165. MMRESULT        mmResult;
  166.     LONG                lSamplesToPlay;
  167.     /* We're not playing, so do nothing. */
  168.     if (!sfPlaying)
  169. return TRUE;
  170.     while (swBuffersOut < swBuffers)
  171.     {
  172. if (slCurrent >= slEnd)
  173. {
  174. if (sfLooping)
  175. {
  176. /* Looping, so go to the beginning. */
  177. slCurrent = slBegin;
  178. }
  179.     else
  180. break;
  181. }
  182. /* Figure out how much data should go in this buffer */
  183. lSamplesToPlay = slEnd - slCurrent;
  184. if (lSamplesToPlay > AUDIO_BUFFER_SIZE / slSampleSize)
  185.     lSamplesToPlay = AUDIO_BUFFER_SIZE / slSampleSize;
  186. AVIStreamRead(spavi, slCurrent, lSamplesToPlay,
  187.       salpAudioBuf[swNextBuffer]->lpData,
  188.       AUDIO_BUFFER_SIZE,
  189.       (LPVOID)&salpAudioBuf[swNextBuffer]->dwBufferLength,
  190.       &lRead);
  191. if (lRead != lSamplesToPlay)
  192.     return FALSE;
  193. slCurrent += lRead;
  194. mmResult = waveOutWrite(shWaveOut, salpAudioBuf[swNextBuffer],sizeof(WAVEHDR));
  195. if (mmResult != 0)
  196.     return FALSE;
  197. ++swBuffersOut;
  198. ++swNextBuffer;
  199. if (swNextBuffer >= swBuffers)
  200.     swNextBuffer = 0;
  201.     }//while
  202.     if (swBuffersOut == 0 && slCurrent >= slEnd)
  203. aviaudioStop();
  204.     /* We've filled all of the buffers we can or want to. */
  205.     return TRUE;
  206. }
  207. /*--------------------------------------------------------------+
  208. | aviaudioPlay -- Play audio, starting at a given frame         |
  209. |                                                               |
  210. +--------------------------------------------------------------*/
  211. BOOL CALLBACK aviaudioPlay(HWND hwnd, PAVISTREAM pavi, LONG lStart, LONG lEnd, BOOL fWait)
  212. {
  213.     if (lStart < 0)
  214. lStart = AVIStreamStart(pavi);
  215.     if (lEnd < 0)
  216. lEnd = AVIStreamEnd(pavi);
  217.     if (lStart >= lEnd)
  218. return FALSE;
  219.     if (!aviaudioOpenDevice(hwnd, pavi))
  220. return FALSE;
  221.     if (!sfPlaying)
  222.     {
  223. // We're beginning play, so pause until we've filled the buffers
  224. // for a seamless start
  225. //
  226. waveOutPause(shWaveOut);
  227. slBegin = lStart;
  228. slCurrent = lStart;
  229. slEnd = lEnd;
  230. sfPlaying = TRUE;
  231.     }
  232.     else
  233.     {
  234. slEnd = lEnd;
  235.     }
  236.     aviaudioiFillBuffers();
  237.     //
  238.     // Now unpause the audio and away it goes!
  239.     //
  240.     waveOutRestart(shWaveOut);
  241.     //
  242.     // Caller wants us not to return until play is finished
  243.     //
  244.     if(fWait)
  245.     {
  246. while (swBuffersOut > 0)
  247. Yield();
  248.     }
  249.     return TRUE;
  250. }
  251. /*--------------------------------------------------------------------------------+
  252. | aviaudioMessage                                                                 |
  253. |                                                                                 |
  254. | The WaveProc callback function - Handles wave messages recieved by the          |
  255. | window controlling playback.                                                    |
  256. +--------------------------------------------------------------------------------*/
  257. void CALLBACK aviaudioMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  258. {
  259.     if (msg == MM_WOM_DONE) {
  260.         --swBuffersOut;
  261.         aviaudioiFillBuffers();
  262.     }
  263. }
  264. /*--------------------------------------------------------------+
  265. | aviaudioStop -- stop playing, close the device.               |
  266. +--------------------------------------------------------------*/
  267. void CALLBACK aviaudioStop(void)
  268. {
  269. MMRESULT        mmResult;
  270.     if (shWaveOut != 0)
  271.     {
  272. mmResult = waveOutReset(shWaveOut);
  273. sfPlaying = FALSE;
  274. aviaudioCloseDevice();
  275.     }
  276. }