Figure 5    DXSound.cpp
/******************************************************************************
FILE: DXSound.cpp
This module contains all of the DirectSound specific code.  This includes
initialization and uninitialization functions as well as functions to create
and play sound buffers.

GLOBALS:
g_lpDSound -- A pointer to the IDirectSound interface
g_lpDSBufferPrimary -- A pointer to the IDirectSoundBuffer interface
                       used for the primary sound buffer
g_lpDS3dListener -- A pointer to the IDirectSound3DListener interface
g_lpDSBufferOuch[NUMOUCHES] -- Array of pointers to IDirectSoundBuffer 
                               interface for the "ouch" sound
g_lpDS3DBufferOuch[NUMOUCHES] -- Array of pointers to the IDirectSound3DBuffer
                                 interface for the "ouch" sound
g_lpDSBufferDoppler -- A pointer to the IDirectSoundBuffer for the doppler 
                       sound
g_lpDS3DBufferDoppler -- A pointer to the IDirectSound3DBuffer for the doppler
                         sound
g_lpDSBufferDance -- A pointer to the IDirectSoundBuffer for the "Dance" sound
g_lpDS3DBufferDance -- A pointer to the IDirectSound3DBuffer for the "Dance"
                       sound
g_lpDSBufferCone -- A pointer to the IDirectSoundBuffer for the "Cone" sound
g_lpDS3DBufferCone -- A pointer to the IDirectSound3DBuffer for the "Cone"
                      sound

g_bDSActive -- Is this application currently active
******************************************************************************/

#include <Windowsx.h>
#include <Dsound.h>
#include <mmsystem.h>
#include <mmreg.h>

#include "DXSound.h"
#include "main.h"
#include "resource.h"

#define NUMOUCHES 4

LPDIRECTSOUND           g_lpDSound = NULL ;
LPDIRECTSOUNDBUFFER     g_lpDSBufferPrimary = NULL ;
LPDIRECTSOUND3DLISTENER g_lpDS3dListener = NULL ;
LPDIRECTSOUNDBUFFER     g_lpDSBufferOuch[NUMOUCHES] = {NULL} ;
LPDIRECTSOUND3DBUFFER   g_lpDS3DBufferOuch[NUMOUCHES] = {NULL} ;
LPDIRECTSOUNDBUFFER     g_lpDSBufferDoppler = NULL ;
LPDIRECTSOUND3DBUFFER   g_lpDS3DBufferDoppler = NULL ;
LPDIRECTSOUNDBUFFER     g_lpDSBufferDance = NULL ;
LPDIRECTSOUND3DBUFFER   g_lpDS3DBufferDance = NULL ;
LPDIRECTSOUNDBUFFER     g_lpDSBufferCone = NULL ;
LPDIRECTSOUND3DBUFFER   g_lpDS3DBufferCone = NULL ;

BOOL g_bDSActive = TRUE ;

BOOL InitListener( void ) ;
BOOL InitOuchBuffer( void ) ;
LPDIRECTSOUNDBUFFER WavToStaticBuffer( LPBYTE lpBuffer, DWORD dwSize, 
                                       LPDIRECTSOUNDBUFFER lpdsBuffer ) ;
BOOL RestoreBufferData( LPDIRECTSOUNDBUFFER lpdsBuffer, UINT nResource ) ;
BOOL InitDopplerBuffer( void ) ;
BOOL InitDanceBuffer( void ) ;
BOOL InitConeBuffer( void ) ;


/******************************************************************************
FUNCTION: InitDirectSound
This is where the actual COM initialization occurs.  The DirectSound object
is created and initialized with the proper cooperative level.  Also the primary
sound buffer is created, and functions are called to create the secondary 
buffers.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitDirectSound( void )
{   
   DSBUFFERDESC   dsBufferDesc ;   

   // Create the DirectSoundObject and retrieve a pointer to its IDirectSound
   // interface
   if ( FAILED( DirectSoundCreate( NULL, &g_lpDSound, NULL ) ) )
      return FALSE ;

   // Set the cooperative level to normal.  This limits us to a primary
   // buffer format of 22kHz, stereo, 8-bit
   if ( FAILED( g_lpDSound->SetCooperativeLevel( g_hMainWnd, DSSCL_NORMAL ) ) )
   {
      UnInitDirectSound() ;
      return FALSE ;
   }

   // Set up the DSBUFFERDESC structure for creation of the primary buffer.
   // Make sure that the unused items in the structure are set to zero.
   // Notice the DSBCAPS_CTRL3D, we need this for 3d sound support.
   dsBufferDesc.dwSize = sizeof( dsBufferDesc ) ;
   dsBufferDesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER | 
                            DSBCAPS_LOCHARDWARE ;
   dsBufferDesc.dwBufferBytes = 0 ;
   dsBufferDesc.dwReserved = 0 ;
   dsBufferDesc.lpwfxFormat = NULL ;
      
   // Create the primary buffer.  If it fails, uninit DirectSound and exit
   if ( FAILED( g_lpDSound->CreateSoundBuffer( &dsBufferDesc, 
                                               &g_lpDSBufferPrimary, NULL ) ) )
   {        
      UnInitDirectSound() ;
      return FALSE ;
   }   

   // Set the buffer playing and looping.  This keeps the mixer running.
   g_lpDSBufferPrimary->Play( 0, 0, DSBPLAY_LOOPING ) ;

   // Call function to set up the listener interface
   if ( !InitListener() )
   {
      UnInitDirectSound() ;
      return FALSE ;
   }
      
   // Call a function to set up secondary sound buffers for the "ouch" sound
   if ( !InitOuchBuffer() )
   {      
      UnInitDirectSound() ;
      return FALSE ;
   }

   // Call a function to set up secondary sound buffers for the "Doppler" sound
   if ( !InitDopplerBuffer() )
   {      
      UnInitDirectSound() ;
      return FALSE ;
   }

   // Call a function to set up secondary sound buffers for the "Dance" sound
   if ( !InitDanceBuffer() )
   {      
      UnInitDirectSound() ;
      return FALSE ;
   }

   // Call a function to set up secondary sound buffers for the "Cone" sound
   if ( !InitConeBuffer() )
   {      
      UnInitDirectSound() ;
      return FALSE ;
   }
   
   return TRUE ;
}


/******************************************************************************
FUNCTION: DSActive
This function is called when the application becomes active.  It replays the
sounds that are constantly playing.

PARAMETERS:
None

RETURNS:
None
******************************************************************************/
void DSActive( void )
{   
   g_bDSActive = TRUE ;

   if ( g_lpDSBufferDoppler )      
      PlayDoppler() ;
   if ( g_lpDSBufferCone )
      PlayCone() ;         
}


/******************************************************************************
FUNCTION: DSInactive
This function is called when the application becomes inactive.  

PARAMETERS:
None

RETURNS:
None
******************************************************************************/
void DSInactive( void )
{
   // This variable is set false so that we know not to bother restoring 
   // buffers for the moment.
   g_bDSActive = FALSE ;
}


/******************************************************************************
FUNCTION: InitListener
This function queries the primary sound buffer object for the 
IDirectSound3Dlistener interface.  It then sets up some settings for the 
listner.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitListener( void )
{
   // Query for the IDirectSound3DListener interface.
   if ( FAILED( g_lpDSBufferPrimary->QueryInterface( 
            IID_IDirectSound3DListener, (void**) &g_lpDS3dListener ) ) )
       return FALSE ;

   // This sets the distance factor to 1 which is actually the default, however
   // you could adjust this value to magnify or lessen the muting effect
   // of distance.  In general DirectSound is set up to behave like the real 
   // world where one unit is one meter.  This demo then has a one to one
   // ratio of meters to pixels.
   g_lpDS3dListener->SetDistanceFactor( (D3DVALUE) 1, DS3D_DEFERRED ) ;

   // The roll-off factor by default is 1.  However with a distance factor
   // of one, and a pixel==one meter situation, the roll-off of one would
   // make things too quiet.  By setting roll-off to 1/100 of the default
   // sounds are again loud enough.  This shows how these settings are
   // relative, and can be adjusted at will.
   g_lpDS3dListener->SetRolloffFactor( (D3DVALUE) .01, DS3D_DEFERRED ) ;

   // Set up the initial listener orientation.  Throughout we will be
   // adjusting the listener orientation as per user mouse input.  However, 
   // we will always keep the top of the head pointed in the same direction.
   g_lpDS3dListener->SetOrientation( 0, 1, 0, 0, 0, 1, DS3D_DEFERRED ) ;
   
   // Notice that our previous calls were using the DS3D_DEFERRED setting.
   // This call commits those settings in one action, which is more efficient
   // then changing them one at a time.
   g_lpDS3dListener->CommitDeferredSettings() ;
   
   return TRUE ;
}


/******************************************************************************
FUNCTION: InitOuchBuffer
This function creates four secondary sound buffers for the "ouch" sound.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitOuchBuffer( void )
{
    
   HRSRC    hrsrc ;
   HGLOBAL  hgRes ; 
   DWORD    dwSize ;
   int      nLoop ;
   
   // Find and load the user defined resource for the "ouch" wave file
   hrsrc = FindResource( NULL, MAKEINTRESOURCE( IDR_OUCH ), "WAVE" ) ;   
   hgRes = LoadResource( NULL, hrsrc ) ;
   dwSize = SizeofResource( NULL, hrsrc ) ;

   // Call our function WavToStaticBuffer, so that it can create a buffer for
   // us.
   g_lpDSBufferOuch[0] = WavToStaticBuffer( (LPBYTE) hgRes, dwSize, NULL ) ;
   if ( !g_lpDSBufferOuch[0] )
      return NULL ;

   // Make several duplicate buffers using the same actual sound data.  This
   // is an efficient way of having multiple sound buffers that can be played
   // autonomously without taking up more memory for the sounds.
   for ( nLoop = 0 ; nLoop < ( NUMOUCHES-1 ) ; nLoop++ )
   {
      if ( FAILED( g_lpDSound->DuplicateSoundBuffer( g_lpDSBufferOuch[0], 
                                               &g_lpDSBufferOuch[1+nLoop] ) ) )
      {
         g_lpDSBufferOuch[0]->Release() ;
      }
   }

   // Query interface for the IDirectSound3DBuffer interfaces for our four
   // sound buffers.  These interfaces will be used for the 3D capabilities 
   // of the sounds.
   for ( nLoop = 0 ; nLoop < NUMOUCHES ; nLoop++ )
   {
      if ( FAILED( g_lpDSBufferOuch[nLoop]->QueryInterface( 
           IID_IDirectSound3DBuffer, (void **) &g_lpDS3DBufferOuch[nLoop] ) ) )
      {      
         return NULL ;
      }
   }

   return TRUE ;
}


/******************************************************************************
FUNCTION: InitDopplerBuffer
This function creates a secondary sound buffer for the "Doppler" sound.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitDopplerBuffer( void )
{
    
   HRSRC    hrsrc ;
   HGLOBAL  hgRes ; 
   DWORD    dwSize ;
   
   // Find and load the user defined resource for the Doppler sound
   hrsrc = FindResource( NULL, MAKEINTRESOURCE( IDR_DOPPLER ), "WAVE" ) ;   
   hgRes = LoadResource( NULL, hrsrc ) ;
   dwSize = SizeofResource( NULL, hrsrc ) ;

   // Pass a pointer to the wav data to our function to create a secondary
   // sound buffer for the sound.
   g_lpDSBufferDoppler = WavToStaticBuffer( (LPBYTE) hgRes, dwSize, NULL ) ;
   if ( !g_lpDSBufferOuch )
      return NULL ;

   // Query interface for the IDirectSound3DBuffer.  This interface is used
   // to implement the 3D features for this sound.
   if ( FAILED( g_lpDSBufferDoppler->QueryInterface( IID_IDirectSound3DBuffer, 
                                         (void **) &g_lpDS3DBufferDoppler ) ) )
   {      
      return NULL ;
   }

   // Set this sounds velocity.  This is a constant.  The position of the
   // sound source is changed periodically by the demo, causing the Doppler
   // effect.  Try changing the velocity values to see how it affects the sound
   g_lpDS3DBufferDoppler->SetVelocity( 20, 20, 0, DS3D_IMMEDIATE ) ;

   return TRUE ;
}


/******************************************************************************
FUNCTION: InitDanceBuffer
This function creates a secondary sound buffer for the "Dance" sound.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitDanceBuffer( void )
{
    
   HRSRC    hrsrc ;
   HGLOBAL  hgRes ; 
   DWORD    dwSize ;
   
   // Find and load the user defined resource for the Dance sound
   hrsrc = FindResource( NULL, MAKEINTRESOURCE( IDR_DANCE ), "WAVE" ) ;   
   hgRes = LoadResource( NULL, hrsrc ) ;
   dwSize = SizeofResource( NULL, hrsrc ) ;

   // Pass a pointer to the wav data to our function to create a secondary
   // sound buffer for the sound.
   g_lpDSBufferDance = WavToStaticBuffer( (LPBYTE) hgRes, dwSize, NULL ) ;
   if ( !g_lpDSBufferDance )
      return NULL ;

   // Query interface for the IDirectSound3DBuffer.  This interface is used
   // to implement the 3D features for this sound.
   if ( FAILED( g_lpDSBufferDance->QueryInterface( IID_IDirectSound3DBuffer,
                                           (void **) &g_lpDS3DBufferDance ) ) )
   {      
      return NULL ;
   }

   return TRUE ;
}


/******************************************************************************
FUNCTION: InitConeBuffer
This function creates a secondary sound buffer for the "Cone" sound.

PARAMETERS:
None

RETURNS:
Success or Failure
******************************************************************************/
BOOL InitConeBuffer( void )
{
    
   HRSRC    hrsrc ;
   HGLOBAL  hgRes ; 
   DWORD    dwSize ;
   
   // Find and load the user defined resource for the "Cone" sound
   hrsrc = FindResource( NULL, MAKEINTRESOURCE( IDR_CONE ), "WAVE" ) ;   
   hgRes = LoadResource( NULL, hrsrc ) ;
   dwSize = SizeofResource( NULL, hrsrc ) ;

   // Pass the data to our function which will create a static buffer for it
   g_lpDSBufferCone = WavToStaticBuffer( (LPBYTE) hgRes, dwSize, NULL ) ;
   if ( !g_lpDSBufferCone )
      return NULL ;

   // QueryInterface for the IDirectSound3DBuffer.  This buffer is used for the
   // 3d features we will apply to the cone effect.
   if ( FAILED( g_lpDSBufferCone->QueryInterface( IID_IDirectSound3DBuffer, 
                                            (void **) &g_lpDS3DBufferCone ) ) )
   {      
      return NULL ;
   }

   // Set up the angles for the sound.  The demo will constantly rotate the 
   // orientation
   g_lpDS3DBufferCone->SetConeAngles( 90, 360, DS3D_DEFERRED ) ;
   g_lpDS3DBufferCone->SetConeOutsideVolume( DSBVOLUME_MIN/4, DS3D_DEFERRED ) ;

   // Once again, the settings are deferred, so now we commit them
   g_lpDS3dListener->CommitDeferredSettings() ;
   
   return TRUE ;
}


/******************************************************************************
FUNCTION: WavToStaticBuffer
This function takes a buffer which holds a wav file, and creates a secondary
static sound buffer for the wav.  It then loads the data from the buffer into
the static buffer.  This function uses the multimedia functions (mm) to parse
the wave data.  It would be a very simple task to extend this function to read
a WAV file.

PARAMETERS:
lpBuffer -- Pointer to a buffer containing wave data
dwSize -- size of buffer
lpdsBuffer -- pointer to an existing IDirectSoundBuffer interface.  Pass NULL
              if a new interface should be created.  Otherwise, the data will
              be stored with this interface.

RETURNS:
A pointer to the IDirectSoundBuffer interface, or NULL if it failed
******************************************************************************/
LPDIRECTSOUNDBUFFER WavToStaticBuffer( LPBYTE lpBuffer, DWORD dwSize, 
                                       LPDIRECTSOUNDBUFFER lpdsBuffer )
{
   MMIOINFO       mmIOInfo ;
   HMMIO          mmioWave ;
   MMCKINFO       mmckinfoParent, mmckinfoSubchunk ;
   WAVEFORMATEX   wfPCM ;
   char           *lpFile = (char *) lpBuffer ;
   HRESULT        hr ;
   BOOL           bNewBuffer = FALSE ;
   
   DSBUFFERDESC   dsBufferDesc ;   
   LPBYTE         lpvAudio1 ;
   LPBYTE         lpvAudio2 ;
   DWORD          dwWriteBytes1 ;
   DWORD          dwWriteBytes2 ;

   // Set the MMIOINFO structure up for reading a multimedia WAV file from 
   // memory.
   memset( &mmIOInfo, sizeof( MMIOINFO ), 0 ) ;
   mmIOInfo.pIOProc = NULL ;
   mmIOInfo.fccIOProc = FOURCC_MEM ;
   mmIOInfo.pchBuffer = lpFile ;
   mmIOInfo.cchBuffer = dwSize ;    

   // Open the wave data using the mm functions
   mmioWave = mmioOpen( NULL, &mmIOInfo, MMIO_READWRITE ) ;
   if ( !mmioWave )
      return NULL ;

   // Descend to find a "WAVE" block, if this fails then the data is not
   // WAV data.
   mmckinfoParent.fccType = mmioFOURCC( 'W', 'A', 'V', 'E' ) ;
   if ( mmioDescend( mmioWave, &mmckinfoParent, NULL, MMIO_FINDRIFF ) ) 
   {
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }

   // Descend again to the "fmt " block and retrieve the format information
   mmckinfoSubchunk.ckid = mmioFOURCC( 'f', 'm', 't', ' ' ) ;
   if ( mmioDescend( mmioWave, &mmckinfoSubchunk, &mmckinfoParent, 
                     MMIO_FINDCHUNK ) )
   {
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }

   // This line actually reads the data from the "fmt " chunk, this data
   // should be in the form of a WAVEFORMATEX structure
   if ( mmioRead( mmioWave, (char *) &wfPCM, mmckinfoSubchunk.cksize ) == -1 )
   {
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }
    
   // Step out a layer... think of the mm functions as step in and out of
   // hierarchies of "chunks" of information
   mmioAscend( mmioWave, &mmckinfoSubchunk, 0 ) ;

   // Find the "data" subchunk
    mmckinfoSubchunk.ckid = mmioFOURCC( 'd', 'a', 't', 'a' ) ;
    if ( mmioDescend( mmioWave, &mmckinfoSubchunk, &mmckinfoParent, 
                      MMIO_FINDCHUNK ) ) 
   {
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }   

   // At this point we have succeeded in finding the data for the WAV file so
   // we need to create a DirectSoundBuffer if one wasn't passed.
   if ( !lpdsBuffer )
   {
      // Set up DSBUFFERDESC structure for a static secondary buffer.       
      dsBufferDesc.dwSize = sizeof( DSBUFFERDESC ) ;       
      dsBufferDesc.dwFlags =  DSBCAPS_CTRL3D | DSBCAPS_STATIC ;    
      // Buffer size retrieved from the mmckinfo structure for the data 
      // portion of the wav
      dsBufferDesc.dwBufferBytes = mmckinfoSubchunk.cksize ; 
      dsBufferDesc.dwReserved = 0 ;
      dsBufferDesc.lpwfxFormat = &wfPCM ; 

      // Create buffer.    
      if ( FAILED( g_lpDSound->CreateSoundBuffer( &dsBufferDesc, &lpdsBuffer, 
                                                  NULL ) ) )
      {
         mmioClose( mmioWave, 0 ) ;
         return NULL ;
      }
      // Did we create a new buffer
      bNewBuffer = TRUE ;
   }
   
   // Lock the buffer for the DirectSoundBuffer object
   hr = lpdsBuffer->Lock( 0, 0, (void **) &lpvAudio1, &dwWriteBytes1, 
                 (void **) &lpvAudio2, &dwWriteBytes2, DSBLOCK_ENTIREBUFFER ) ;
   if ( hr == DSERR_BUFFERLOST )
   {
      // If the buffer was lost try restoring it and lock again
      lpdsBuffer->Restore() ;
      hr = lpdsBuffer->Lock( 0, 0, (void **) &lpvAudio1, &dwWriteBytes1, 
                 (void **) &lpvAudio2, &dwWriteBytes2, DSBLOCK_ENTIREBUFFER ) ;
   }

   if ( FAILED( hr ) )
   {
      if ( bNewBuffer )
         lpdsBuffer->Release() ;   
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }

   if ( dwWriteBytes1 != mmckinfoSubchunk.cksize )
   {
      if ( bNewBuffer )
         lpdsBuffer->Release() ;   
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }
 
   // Read the data directly into the locked buffer
   if ( mmioRead( mmioWave, ( char* ) lpvAudio1, mmckinfoSubchunk.cksize ) 
        == -1 )
   {
      if ( bNewBuffer )
         lpdsBuffer->Release() ;   
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }   

   // Unlock the buffer
   if ( FAILED( lpdsBuffer->Unlock( (void *) lpvAudio1, dwWriteBytes1, 
                                    (void *) lpvAudio2, dwWriteBytes2 ) ) )
   {
      if ( bNewBuffer )
         lpdsBuffer->Release() ;
      mmioClose( mmioWave, 0 ) ;
      return NULL ;
   }
   
   // Close the multimedia object
   mmioClose( mmioWave, 0 ) ;

   return lpdsBuffer ;
}


/******************************************************************************
FUNCTION: RestoreBufferData
This function will reload a resource and attempt to restore the buffer for a
direct sound buffer.

PARAMETERS:
lpdsBuffer -- Existing direct sound interface
nResource -- Resource ID of the user defined resource holding the WAV data

RETURNS:
Returns success or failure
******************************************************************************/
BOOL RestoreBufferData( LPDIRECTSOUNDBUFFER lpdsBuffer, UINT nResource )
{
   HRSRC    hrsrc ;
   HGLOBAL  hgRes ; 
   DWORD    dwSize ;
  
   // Don't bother trying if the application window is not in the foreground
   if ( !g_bDSActive )
      return FALSE ;

   // Find and load the resources
   hrsrc = FindResource( NULL, MAKEINTRESOURCE( nResource ), "WAVE" ) ;   
   hgRes = LoadResource( NULL, hrsrc ) ;
   dwSize = SizeofResource( NULL, hrsrc ) ;

   // Copy the data from the resource into our buffer using our nifty function
   lpdsBuffer = WavToStaticBuffer( (LPBYTE) hgRes, dwSize, lpdsBuffer ) ;
   if ( !lpdsBuffer )
      return FALSE ;

   return TRUE ;
}


/******************************************************************************
FUNCTION: SetListenerPos
This function sets the position of the listener object in 3D space.  It also
sets the orientation.  The data is taken from an application defined structure
called DemoListener.

PARAMETERS:
pDL -- Pointer to the DemoListener structure containing the position info
bDeferred -- Defer changes?

RETURNS:
Returns success or failure
******************************************************************************/
BOOL SetListenerPos( DemoListener *pDL, BOOL bDeferred )
{   
   // Set the position of the listener
   if ( FAILED( g_lpDS3dListener->SetPosition( (D3DVALUE) pDL->m_nXPos, 
       (D3DVALUE) pDL->m_nYPos, 0, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ) )
      return FALSE ; 

   // Set orientation of the listener
   return !FAILED( g_lpDS3dListener->SetOrientation( pDL->m_fnFaceX, 
      pDL->m_fnFaceY, 0, 0, 0, -1, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ) ;
}


/******************************************************************************
FUNCTION: SetDopplerPos
This function sets the position of the Doppler object.  The data is taken from 
an application defined structure called DemoDoppler.

PARAMETERS:
pDD -- Pointer to the DemoDoppler structure containing the position info
bDeferred -- Defer changes?

RETURNS:
Returns success or failure
******************************************************************************/
BOOL SetDopplerPos( DemoDoppler *pDD, BOOL bDeferred )
{   
   // Set the position of the Doppler object
   if ( FAILED( g_lpDS3DBufferDoppler->SetPosition( (D3DVALUE) pDD->m_nXPos, 
       (D3DVALUE) pDD->m_nYPos, 0, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ) )
      return FALSE ; 

   return TRUE ;
}


/******************************************************************************
FUNCTION: PlayDoppler
Play the doppler object, and restore it if the buffer has been lost.

PARAMETERS:
void

RETURNS:
void
******************************************************************************/
void PlayDoppler( void )
{
   HRESULT hr ;

   // Play
   hr = g_lpDSBufferDoppler->Play( 0, 0, DSBPLAY_LOOPING ) ;
   if ( hr == DSERR_BUFFERLOST )
   {
      // Failed?  Restore.
      if ( RestoreBufferData( g_lpDSBufferDoppler, IDR_DOPPLER ) )
      {
         // Play again...
         g_lpDSBufferDoppler->Play( 0, 0, DSBPLAY_LOOPING ) ;
      }
   }   
}


/******************************************************************************
FUNCTION: SetConePos
Set the position of the Cone object in DirectSound 3D space.

PARAMETERS:
void

RETURNS:
void
******************************************************************************/
BOOL SetConePos( DemoCone *pDLS, BOOL bDeferred )
{   
   // Set the position.  The demo currently locks the position.
   if ( FAILED( g_lpDS3DBufferCone->SetPosition( (D3DVALUE) pDLS->m_nXPos, 
      (D3DVALUE) pDLS->m_nYPos, 0, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ) )
      return FALSE ; 

   // Set the orientation.
   return !FAILED( g_lpDS3DBufferCone->SetConeOrientation( pDLS->m_fnFaceX, 
       pDLS->m_fnFaceY, 0, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ) ;
}


/******************************************************************************
FUNCTION: PlayCone
Play the cone object

PARAMETERS:
void

RETURNS:
void
******************************************************************************/
void PlayCone( void )
{     
   HRESULT hr ;

   // Play
   hr = g_lpDSBufferCone->Play( 0, 0, DSBPLAY_LOOPING ) ;   
   if ( hr == DSERR_BUFFERLOST )
   {
      // buffer lost?  Restore.
      if ( RestoreBufferData( g_lpDSBufferCone, IDR_CONE ) )
      {
         // Play again
         g_lpDSBufferCone->Play( 0, 0, DSBPLAY_LOOPING ) ;
      }
   }   
}


/******************************************************************************
FUNCTION: PlayOuch
Play the ouch object.  A little more complicated then the other "Play" 
functions because it plays the first available buffer of 4.
    
PARAMETERS:
nX -- X position of the source
nY -- Y position of the source
bDeferred -- Defer the changes?

RETURNS:
none
******************************************************************************/
void PlayOuch( int nX, int nY, BOOL bDeferred )
{   
   DWORD    dwStatus ;
   int      nLoop ;
   HRESULT  hr ;
   
   
   // Loop through each buffer and check status playing.  
   for ( nLoop = 0 ; nLoop < NUMOUCHES ; nLoop++ )
   {
      if ( FAILED( g_lpDSBufferOuch[nLoop]->GetStatus( &dwStatus ) ) )
         continue ;

      // If not playing... then this is the one that we will play.
      if ( !( dwStatus & DSBSTATUS_PLAYING ) )
      {    
         // Set the position
         g_lpDS3DBufferOuch[nLoop]->SetPosition( (D3DVALUE) nX, (D3DVALUE) nY, 
                                  0, bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ;
         // Play it
         hr = g_lpDSBufferOuch[nLoop]->Play( 0, 0, 0 ) ;
         if ( hr == DSERR_BUFFERLOST )
         {
            // Buffer lost?  Restore.
            if ( RestoreBufferData( g_lpDSBufferOuch[nLoop], IDR_OUCH ) )
            {
               // Play
               g_lpDSBufferOuch[nLoop]->Play( 0, 0, 0 ) ;
            }
         }   
         break ;
      }
   }   
}


/******************************************************************************
FUNCTION: PlayDance
Play the "Dance" object.  

PARAMETERS:
nX -- X position of the source
nY -- Y position of the source
bDeferred -- Defer the changes?

RETURNS:
none
******************************************************************************/
void PlayDance( int nX, int nY, BOOL bDeferred )
{     
   HRESULT hr ;

   // Set the object's position
   g_lpDS3DBufferDance->SetPosition( (D3DVALUE) nX, (D3DVALUE) nY, 0, 
       bDeferred?DS3D_DEFERRED:DS3D_IMMEDIATE ) ;

   // Play the sound
   hr = g_lpDSBufferDance->Play( 0, 0, 0 ) ;   
   if ( hr == DSERR_BUFFERLOST )
   {
      if ( RestoreBufferData( g_lpDSBufferDance, IDR_DANCE ) )
      {
         g_lpDSBufferDance->Play( 0, 0, 0 ) ;
      }
   }
}


/******************************************************************************
FUNCTION: StopDance
Stop the "Dance" object.  It is important that we can stop the "Dance" sound
when the user lets go of the button.

PARAMETERS:
none

RETURNS:
none
******************************************************************************/
void StopDance( void )
{
   // Stop
   g_lpDSBufferDance->Stop() ;   
}


/******************************************************************************
FUNCTION: CommitChanges
This function will commit deferred changes for DirectSound.  This is an 
important feature because it allows you to make multiple changes at once which 
is more effecient.

PARAMETERS:
none

RETURNS:
none
******************************************************************************/
void CommitChanges( void )
{
   g_lpDS3dListener->CommitDeferredSettings() ;
}


/******************************************************************************
FUNCTION: UnInitDirectSound
Un init all of the DirectSound stuff.

PARAMETERS:
none

RETURNS:
none
******************************************************************************/
void UnInitDirectSound( void )
{
   int nLoop ;

   // Release
   if ( g_lpDS3DBufferCone )
      g_lpDS3DBufferCone->Release() ;

   // Release
   if ( g_lpDS3DBufferDance )
      g_lpDS3DBufferDance->Release() ;

   // Release
   if ( g_lpDS3DBufferDoppler )
      g_lpDS3DBufferDoppler->Release() ;

   // Release
   if ( g_lpDSBufferCone )
      g_lpDSBufferCone->Release() ;

   // Release
   if ( g_lpDSBufferDance )
      g_lpDSBufferDance->Release() ;

   // Release
   if ( g_lpDSBufferDoppler )
      g_lpDSBufferDoppler->Release() ;

   // Loop and release
   for ( nLoop = 0 ; nLoop < NUMOUCHES ; nLoop++ )
   {
      if ( g_lpDS3DBufferOuch[nLoop] )
         g_lpDS3DBufferOuch[nLoop]->Release() ;

      if ( g_lpDSBufferOuch[nLoop] )
         g_lpDSBufferOuch[nLoop]->Release() ;

   }

   // Release
   if ( g_lpDS3dListener )
      g_lpDS3dListener->Release() ;

   // Release -- talk about your cut and paste comments
   if ( g_lpDSBufferPrimary )
      g_lpDSBufferPrimary->Release() ;

   // Release
   if ( g_lpDSound )
      g_lpDSound->Release() ;
   
}