home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / aviview / audplay.c next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  9.1 KB  |  346 lines

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