home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / duel / ds3dutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  14.5 KB  |  418 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       ds3dutil.c
  6.  *  Content:    Routines for dealing with sounds from resources
  7.  *              The last 3 functions (the wave file parsing code)
  8.  *              are copied from dsutil.cpp
  9.  *
  10.  *
  11.  ***************************************************************************/
  12. #include <tchar.h>
  13. #include <dsound.h>
  14. #include "ds3dutil.h"
  15. //*************************** FUNCTION PROTOTYPES **************************/
  16. BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader,
  17.                          BYTE **ppbWaveData,DWORD *pcbWaveSize);
  18. BOOL DSGetWaveResource ( HMODULE hModule, LPCTSTR lpName,
  19.                          WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData,
  20.                          DWORD *pcbWaveSize);
  21. BOOL DSFillSoundBuffer(  IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize);
  22. BOOL DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName);
  23.  
  24. //*************************** GLOBAL VARIABLES **************************/
  25.  
  26. _TCHAR gszWaveString[5] = _T("WAVE");
  27.  
  28. /*****************************************************************************
  29. FUNCTION:  WaveInit
  30.  
  31. PURPOSE:   Loads a WAVEDATA struct with the named WAVE resource.
  32.  
  33. PARAMETERS:
  34. lplpWD  A pointer to a WAVEDATA struct.
  35.  
  36. lpDS:   A pointer to an IDirectSound object.  This object must be,
  37.         initialized BEFORE being passed to this function, and MUST have been
  38.         initialized with the DSBCAPS_CTRL3D flag.
  39.  
  40. lpName: A string that contains the name of the .WAV resource.
  41. *****************************************************************************/
  42. BOOL WaveInit(LPWAVEDATA *lplpWD, LPDIRECTSOUND lpDS, LPCTSTR lpName)                   
  43. {
  44. DSBUFFERDESC dsBD = {0};
  45. BYTE *pbWaveData=NULL;
  46. LPWAVEDATA lpWD;
  47.  
  48.     lpWD = (*lplpWD) = (LPWAVEDATA)malloc(sizeof(WAVEDATA));
  49.     lpWD->lpDirectSoundBuffer = NULL;
  50.     lpWD->lpName = NULL;
  51.     lpWD->lpDS = NULL;
  52.  
  53.     #ifndef UNICODE
  54.         lpWD->lpName = (LPTSTR)malloc(strlen(lpName) + 1);
  55.     #else
  56.         lpWD->lpName = (LPTSTR)malloc(2*(wcslen(lpName) + 1));
  57.     #endif
  58.     if (lpWD->lpName != NULL)
  59.     {
  60.         _tcscpy(lpWD->lpName, lpName);
  61.         
  62.         if (DSGetWaveResource(NULL, lpName, &dsBD.lpwfxFormat, &pbWaveData, &dsBD.dwBufferBytes))
  63.         {
  64.             dsBD.dwSize = sizeof(DSBUFFERDESC);
  65.             dsBD.dwFlags = DSBCAPS_STATIC     | DSBCAPS_GETCURRENTPOSITION2  | DSBCAPS_CTRL3D;
  66.             if (DS_OK == IDirectSound_CreateSoundBuffer(lpDS, &dsBD, &lpWD->lpDirectSoundBuffer, NULL))
  67.             {
  68.                 if (DSFillSoundBuffer(lpWD->lpDirectSoundBuffer, pbWaveData, dsBD.dwBufferBytes))
  69.                 {
  70.                     lpWD->lpDS = lpDS; //also copy the DirectSoundObject
  71.                     return(TRUE);
  72.                 }
  73.                 IDirectSoundBuffer_Release(lpWD->lpDirectSoundBuffer);
  74.                 lpWD->lpDirectSoundBuffer = NULL;
  75.             }
  76.         }
  77.         free(lpWD->lpName);        
  78.         lpWD->lpName = NULL;
  79.     }
  80.     free(*lplpWD);
  81.     *lplpWD = NULL;
  82.     return(FALSE);
  83. };        
  84.  
  85.  
  86. /*****************************************************************************
  87. FUNCTION:   WaveGetBuffers
  88.  
  89. PARAMS:     lplpWD:
  90.                 A pointer to a WAVEDATA struct.
  91.             lplpDirectSoundBuffer:
  92.                 The address of a pointer to a DirectSoundBuffer Interface.                
  93.             lplpDirectSound3DBuffer:
  94.                 The address of a pointer to a DirectSound3DBuffer Interface.
  95.             bOurShip:
  96.                 A Boolean telling whether the ship requesting the sound
  97.                 buffers is OUR ship.  If it is our ship, then instead of
  98.                 duplicating sound buffers for it we just copy the global
  99.                 pointers in.  That way we make sure that the global
  100.                 pointers are actually being put to good use before we
  101.                 go allocating more resources.
  102.                 
  103.             
  104.             Both of these must be Release()'d after their use.
  105.                 
  106. PURPOSE:    Gives the caller back two interface pointers:  one to a regular
  107.             DirectSoundBuffer interface and one to a 3D buffer interface.  These
  108.             MUST be Released() by the caller.
  109.  
  110. RETURNS:    Should return TRUE, unless something really catastrophic has happened.
  111.  
  112. NOTES:      BOTH of these Interfaces MUST be ->Release()'d when the object
  113.             or whatever is done using them.  Otherwise the buffer they point
  114.             to will just hang around and waste memory.  This wastes processing time,
  115.             since each buffer is checked by the mixer quite frequently to see if it
  116.             is playing.
  117.  
  118.             Defaults:  Both Position and Velocity vectors are set to (0,0,0).
  119.             
  120. **************************************************************************************/ 
  121. BOOL WaveGetBuffers (LPWAVEDATA lpWD,
  122.                     LPDIRECTSOUNDBUFFER   *lplpDirectSoundBuffer,
  123.                     LPDIRECTSOUND3DBUFFER *lplpDirectSound3DBuffer,
  124.                     BOOL bOurShip)
  125. {
  126. DSBCAPS dsbc; //in case there's a problem duplicating hardware buffer
  127. DSBUFFERDESC dsBD   ={0};
  128. BYTE *pbWaveData    =NULL;
  129.  
  130.     *lplpDirectSoundBuffer = NULL;
  131.     *lplpDirectSound3DBuffer = NULL;
  132.     //so if we get to "failed:", we know what worked and what didn't.
  133.     if (bOurShip)
  134.     {//This is OUR ship, so we'll copy the buffer pointer.
  135.         *lplpDirectSoundBuffer   = lpWD->lpDirectSoundBuffer;
  136.     }
  137.     else
  138.     {
  139.         //This is not our ship, so we'll have to dup a buffer or create a new one.
  140.         if (DS_OK!=IDirectSound_DuplicateSoundBuffer(lpWD->lpDS, lpWD->lpDirectSoundBuffer, lplpDirectSoundBuffer))
  141.         {
  142.             //degrading to software
  143.             dsbc.dwSize = sizeof(dsbc);
  144.             if (DS_OK!=IDirectSoundBuffer_GetCaps(lpWD->lpDirectSoundBuffer, &dsbc))
  145.             {
  146.                 goto failed;
  147.             }
  148.             //was the original one in hardware?
  149.             if (DSBCAPS_LOCHARDWARE & dsbc.dwFlags)
  150.             {
  151.                 //It's a HARDWARE buffer? Then we need to create a software sound
  152.                 //buffer, not duplicate this hardware one.
  153.                 if (DSGetWaveResource(NULL, lpWD->lpName, &dsBD.lpwfxFormat, &pbWaveData, &dsBD.dwBufferBytes))
  154.                 {
  155.                     dsBD.dwSize = sizeof(DSBUFFERDESC);
  156.                     dsBD.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2  | DSBCAPS_CTRL3D;
  157.                     if (DS_OK == IDirectSound_CreateSoundBuffer(lpWD->lpDS, &dsBD, lplpDirectSoundBuffer, NULL))
  158.                     {
  159.                         if (!DSFillSoundBuffer(*lplpDirectSoundBuffer, pbWaveData, dsBD.dwBufferBytes))
  160.                         {//DSFillSoundBuffer failed when creating software buffer for ship.                                   
  161.                             goto failed;
  162.                         }
  163.                     }
  164.                     else
  165.                     {//CreateSoundBuffer failed when creating software buffer for ship.                        
  166.                         goto failed;
  167.                     }
  168.                 }
  169.                 else 
  170.                 {//GetWaveResource failed trying to duplicating a SOFTWARE buffer for ship.                    
  171.                     goto failed;
  172.                 }
  173.             }
  174.             else
  175.             {//it wasn't even trying to duplicate a hardware buffer, and
  176.              //could not duplicate a software buffer.
  177.                 goto failed;
  178.             }
  179.         } //end the duplicate-regular-soundbuffer part.
  180.     }
  181.  
  182.  
  183.     //now we'll try to get a 3D buffer.
  184.     if (DS_OK==IDirectSoundBuffer_QueryInterface(*lplpDirectSoundBuffer, &IID_IDirectSound3DBuffer, (void **)lplpDirectSound3DBuffer)) 
  185.     {            
  186.         return TRUE; //buffer was allocated!!!!
  187.     }
  188.     else
  189.     {
  190.     //Query for a 3D SoundBuffer Failed!!
  191.         goto failed;
  192.     }
  193.  
  194.  
  195. failed:
  196.     if (*lplpDirectSoundBuffer!=NULL)
  197.     {
  198.         if (!bOurShip)
  199.             IDirectSoundBuffer_Release(*lplpDirectSoundBuffer);
  200.         *lplpDirectSoundBuffer=NULL;
  201.     }
  202.  
  203.     if (*lplpDirectSound3DBuffer!=NULL)
  204.     {
  205.         IDirectSoundBuffer_Release(*lplpDirectSound3DBuffer);
  206.         *lplpDirectSound3DBuffer=NULL;
  207.     }
  208.     return FALSE;
  209. };
  210.  
  211.  
  212.  
  213. /*****************************************************************************
  214. FUNCTION:  WaveFree
  215.  
  216. PURPOSE:   When this is called, we HOPE that all the buffers
  217.            (both the normal and the 3D ones) duplicated from "lpDirectSoundBuffer"
  218.            in the function WaveGetBuffers() have been ->Release()'d.  This frees
  219.            up the original buffer (lpDirectSoundBuffer) that all the other buffers
  220.            have been duplicated from.
  221. *****************************************************************************/ 
  222. void WaveFree(LPWAVEDATA lpWD)
  223. {
  224.     if (lpWD!=NULL)
  225.     {
  226.         if (lpWD->lpDirectSoundBuffer != NULL)
  227.           IDirectSoundBuffer_Release(lpWD->lpDirectSoundBuffer);
  228.         if (lpWD->lpName != NULL)
  229.             free(lpWD->lpName);
  230.         free(lpWD);
  231.     }
  232. };
  233.  
  234. /*****************************************************************************
  235. FUNCTION:   WaveReload
  236.  
  237. PURPOSE:    This reloads the wave's sound effect.
  238. *****************************************************************************/
  239. BOOL WaveReload(LPWAVEDATA lpWD)
  240. {
  241.     return DSReloadSoundBuffer(lpWD->lpDirectSoundBuffer, lpWD->lpName);
  242. };
  243.  
  244.  
  245.  
  246. /*****************************************************************************
  247. FUNCTION:  DSGetWaveResource
  248.  
  249. PURPOSE:   Sets the following:
  250.             a. A pointer to a WAV file header structure
  251.             b. A pointer to the WAV file data.
  252.             c. A DWORD which is the length of the data (in bytes, not samples)
  253. *****************************************************************************/
  254. BOOL DSGetWaveResource(HMODULE hModule, LPCTSTR lpName,
  255.                        WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData,
  256.                        DWORD *pcbWaveSize)
  257. {
  258.     HRSRC hResInfo;
  259.     HGLOBAL hResData;
  260.     void *pvRes;
  261.     
  262.  
  263.     if (((hResInfo = FindResource(hModule, lpName, gszWaveString)) != NULL) &&
  264.         ((hResData = LoadResource(hModule, hResInfo)) != NULL) &&
  265.         ((pvRes = LockResource(hResData)) != NULL) &&        
  266.         DSParseWaveResource(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize))
  267.     {
  268.         return TRUE;
  269.     }
  270.     return FALSE;
  271. }
  272.  
  273.  
  274.  
  275.  
  276. /*****************************************************************************
  277. FUNCTION:   DSParseWaveResource
  278.  
  279. PURPOSE:    This does the real meat of the file parsing, and is called by
  280.             DSGetWaveResource
  281. *****************************************************************************/
  282. BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader,
  283.                          BYTE **ppbWaveData,DWORD *pcbWaveSize)
  284. {
  285.     DWORD *pdw;
  286.     DWORD *pdwEnd;
  287.     DWORD dwRiff;
  288.     DWORD dwType;
  289.     DWORD dwLength;
  290.  
  291.     if (ppWaveHeader)
  292.         *ppWaveHeader = NULL;
  293.  
  294.     if (ppbWaveData)
  295.         *ppbWaveData = NULL;
  296.  
  297.     if (pcbWaveSize)
  298.         *pcbWaveSize = 0;
  299.  
  300.     pdw = (DWORD *)pvRes;
  301.     dwRiff = *pdw++;
  302.     dwLength = *pdw++;
  303.     dwType = *pdw++;
  304.  
  305.     if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
  306.         goto exit;      // not even RIFF
  307.  
  308.     if (dwType != mmioFOURCC('W', 'A', 'V', 'E'))
  309.         goto exit;      // not a WAV
  310.  
  311.     pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
  312.  
  313.     while (pdw < pdwEnd)
  314.     {
  315.         dwType = *pdw++;
  316.         dwLength = *pdw++;
  317.  
  318.         switch (dwType)
  319.         {
  320.         case mmioFOURCC('f', 'm', 't', ' '):
  321.             if (ppWaveHeader && !*ppWaveHeader)
  322.             {
  323.                 if (dwLength < sizeof(WAVEFORMAT))
  324.                     goto exit;      // not a WAV
  325.  
  326.                 *ppWaveHeader = (WAVEFORMATEX *)pdw;
  327.  
  328.                 if ((!ppbWaveData || *ppbWaveData) &&
  329.                     (!pcbWaveSize || *pcbWaveSize))
  330.                 {
  331.                     return TRUE;
  332.                 }
  333.             }
  334.             break;
  335.  
  336.         case mmioFOURCC('d', 'a', 't', 'a'):
  337.             if ((ppbWaveData && !*ppbWaveData) ||
  338.                 (pcbWaveSize && !*pcbWaveSize))
  339.             {
  340.                 if (ppbWaveData)
  341.                     *ppbWaveData = (LPBYTE)pdw;
  342.  
  343.                 if (pcbWaveSize)
  344.                     *pcbWaveSize = dwLength;
  345.  
  346.                 if (!ppWaveHeader || *ppWaveHeader)
  347.                     return TRUE;
  348.             }
  349.             break;
  350.         }
  351.  
  352.         pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
  353.     }
  354.  
  355. exit:
  356.     return FALSE;
  357. }
  358.  
  359.  
  360.  
  361. /*****************************************************************************
  362. FUNCTION:   DSFillSoundBuffer
  363.  
  364. PURPOSE:    Given an already-initialized DirectSoundBuffer, and pointer to
  365.             some sound data, and the sound data's size, this writes the data
  366.             to the DirectSoundBuffer.
  367. *****************************************************************************/
  368. BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize)
  369. {
  370.     if (pDSB && pbWaveData && cbWaveSize)
  371.     {
  372.         LPVOID pMem1, pMem2;
  373.         DWORD dwSize1, dwSize2;
  374.  
  375.         if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize,
  376.             &pMem1, &dwSize1, &pMem2, &dwSize2, 0)))
  377.         {
  378.             ZeroMemory(pMem1, dwSize1);
  379.             CopyMemory(pMem1, pbWaveData, dwSize1);
  380.  
  381.             if ( 0 != dwSize2 )
  382.                 CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2);
  383.  
  384.             IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2);
  385.             return TRUE;
  386.         }
  387.     }
  388.     return FALSE;
  389. }
  390.  
  391.  
  392. /*****************************************************************************
  393. FUNCTION:   DSReloadSoundBuffer
  394.  
  395. PURPOSE:    If an application with WRITE_PRIMARY takes the focus from our
  396.             humble window, then our secondary sound buffers become "lost" and
  397.             we must call restore and re-fill them.
  398. *****************************************************************************/
  399. BOOL DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName)
  400. {
  401.     BOOL result=FALSE;
  402.     BYTE *pbWaveData;
  403.     DWORD cbWaveSize;
  404.  
  405.     if (DSGetWaveResource(NULL, lpName, NULL, &pbWaveData, &cbWaveSize))
  406.     {
  407.         if (SUCCEEDED(IDirectSoundBuffer_Restore(pDSB)))
  408.         {
  409.         if (DSFillSoundBuffer(pDSB, pbWaveData, cbWaveSize))
  410.             {
  411.             result = TRUE;
  412.             }
  413.         }
  414.  
  415.     }
  416.     return result;
  417. }
  418.