Sign in to follow this  

Sound in Directx

This topic is 2844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im doing a project and im looking to add sound. Ive found a few tutorials and a book dedicated to Sound in Directx, but they all make use of files i dont have in my Directx SDK. stuff like dmusici.h and others. I read a thread here from 08 from some guy with a similar problem. So im wondering what people do now to add sound to there Directx games?

Share this post


Link to post
Share on other sites
Quote:
Original post by Waaayoff
I scanned the forums on a topic similar to yours a week ago, much of the answerers seemed to prefer using FMOD. Whatever that is.
Link [smile]

It's free so long as your software is free. If you're making shareware or commercial software then you need to purchase a license.

Share this post


Link to post
Share on other sites
Yeah ill take a look at it anyway. Cheers, man. I have no preference right now. It doesnt have to do much. Just play a background song and a few effects when explosions occur or that. Thanks

Share this post


Link to post
Share on other sites
Good. Below is how you would use the class in your game. The class is written as a singlton so that it's easy to use in any of your game classes. Be sure to add "X3DAudio.lib" to your project. I'm currently using MSVC++ 2008 Express Edition.

This is how you would load your "global settings" file and any number of wave and sound banks generated from using the "XACT audio creation tool". The global setting file has to be loaded first. Be sure to use the "XACT audio creation tool" found in your DirectX SDK. The file path is your string ID to that wave or sound bank. Unloading sound and wave banks is very similar but that is only needed if you want to manage memory in your game. The XAct class will clean-up everything that is currently loaded.

// Load the global settings
if( !CXAct::Instance().Init( string("sound\\gameTemplate.xgs") ) )
{
return false;
}

// load the Wave Bank
if( !CXAct::Instance().LoadWaveBank( string("sound\\sound_effects.xwb") ) )
{
return false;
}

// load the Wave Bank
if( !CXAct::Instance().LoadWaveBank( string("sound\\music.xwb") ) )
{
return false;
}

// Load the sound Bank
if( !CXAct::Instance().LoadSoundBank( string("sound\\sound_effects.xsb") ) )
{
return false;
}

// Load the sound bank
if( !CXAct::Instance().LoadSoundBank( string("sound\\music.xsb") ) )
{
return false;
}






The most flexible way to play sound is to get a sound cue. These are the names of the sound cues displayed in the XACT audio creation tool.

// Define it like this in the header of the class that will be playing the sound
CSoundCue music;
CSoundCue soundEffect1;
CSoundCue soundEffect2;

// Get the sound Cues
music = CXAct::Instance().GetSoundCue( string("music") );
soundEffect1 = CXAct::Instance().GetSoundCue( string("ammo_fire") );
soundEffect2 = CXAct::Instance().GetSoundCue( string("droid_destroyed") );

// This is how you would use the sound cues
music.Play();
soundEffect1.Play();
music.Stop();

// You can use these "Fire & Forget" methods but getting the sound Cue is best.
// Don't use the below call if you want to play a sound via button press.
// There's nothing keeping you from executing the call a zillion times. Not good.
CXAct::Instance().Play( string("music") );
CXAct::Instance().Stop( string("music") );

// This is how to play a sound cue safely from a button press
if( CGameController::Instance().WasAction(string("music")) )
{
if( !music.IsBusy() )
{
music.Play();
}
}

/***************************************************************************
* decs: Update animations, Move sprites, Check for collision
****************************************************************************/

void CGame::Update()
{
// This is how you can play sound at a point in 3D space.
// This is not something you need to do. Just showing you it's available
if( music.IsBusy() )
{
camera.Finialize();
CPoint point = camera.GetFinialMatrix().GetMatrixPoint();
point.Invert();
CXAct::Instance().PositionCue( point, music.pCue );
}

// This needs to be called every game loop to keep sound streaming happy
CXAct::Instance().Update();

} // Update






Here's the class header file

/************************************************************************
* FILE NAME: xact.h
*
* DESCRIPTION: DirectX sound class
************************************************************************/


#ifndef __xact_h__
#define __xact_h__

// DirectX lib dependencies
#include <xact3.h>
#include <xact3d3.h>

// Standard lib dependencies
#include <string>
#include <map>

// Game lib dependencies
#include "soundcue.h"
#include "xactdefs.h"
#include "3d\\point.h"

class CXAct
{
public:

// Get the CXAct instance
static CXAct & Instance();

// Init the xact audio system with the global settings file
bool Init( std::string & filePath );

// Load a wav bank
bool LoadWaveBank( std::string & filePath );

// Destroy a wav bank
void DestroyWaveBank( std::string & filePath );

// Load a sound bank
bool LoadSoundBank( std::string & filePath );

// Destroy a sound bank
void DestroySoundBank( std::string & filePath );

// Allows XACT to do required periodic work. call often
virtual void Update();

// Get a sound cue
CSoundCue GetSoundCue( std::string & sndCueStr );

// Play a sound
void Play( std::string & sndCueStr );

// Stop a sound
void Stop( std::string & sndCueStr );

// Prepare a sound
void Prepare( std::string & sndCueStr );

// Position the sound cue based on the point
void PositionCue( CPoint & point, IXACT3Cue * pCue );

protected:

// notification call back function - needs to be static to be passed as function pointer
static void WINAPI XACTNotificationCallback( const XACT_NOTIFICATION * pNotification );

// Function for handling XACT notifications
virtual void HandleNotification( const XACT_NOTIFICATION * pNotification );

// Display error information
void DisplayError( HRESULT hr );

// Init the class member variables for 3D sound
void Init3DSound();

// a ULONG used to signal when
// entering and exiting a critical state
CRITICAL_SECTION criticalSection;

// XACT audio engine
IXACT3Engine* pEngine;

// 3D audio instance
X3DAUDIO_HANDLE x3DInstance;

// map for wave bank
std::map<std::string, CWaveBank *> waveBankMap;

// map for sound bank
std::map<std::string, CSoundBank *> soundBankMap;

// 3D sound data members
X3DAUDIO_DSP_SETTINGS dspSettings;
X3DAUDIO_LISTENER listener;
X3DAUDIO_EMITTER emitter;
FLOAT32 delayTimes[2];
FLOAT32 matrixCoefficients[2 * 8];

private:

// Constructor
CXAct();

// Destructor
~CXAct();

};

#endif // __xact_h__






Here's the sound cue header file

/************************************************************************
* FILE NAME: soundcue.h
*
* DESCRIPTION: Sound cue management class
************************************************************************/


#ifndef __sound_cue_h__
#define __sound_cue_h__

// DirectX lib dependencies
#include <xact3.h>

class CSoundCue
{
public:

/************************************************************************
* desc: constructor
************************************************************************/

CSoundCue() : pSoundBank(NULL), cueIndex(XACTINDEX_INVALID), pCue(NULL)
{
}

/************************************************************************
* desc: Copy constructor
************************************************************************/

CSoundCue( const CSoundCue & obj )
{
*this = obj;
}

/************************************************************************
* desc: Play a sound
************************************************************************/

void Play()
{
if( (pSoundBank != NULL) && (cueIndex != XACTINDEX_INVALID) )
{
pSoundBank->Play( cueIndex, 0, 0, &pCue );
}
}

/************************************************************************
* desc: stop a sound
************************************************************************/

void Stop()
{
if( (pSoundBank != NULL) && (cueIndex != XACTINDEX_INVALID) )
{
pSoundBank->Stop( cueIndex, 0 );
}
}

/************************************************************************
* desc: Prepare a sound
************************************************************************/

void Prepare()
{
if( (pSoundBank != NULL) && (cueIndex != XACTINDEX_INVALID) )
{
pSoundBank->Prepare( cueIndex, 0, 0, &pCue );
}
}

/************************************************************************
* desc: Check if a cue is busy
*
* ret: bool - true if busy
************************************************************************/

bool IsBusy()
{
DWORD cueState = GetState();

return ((cueState > XACT_STATE_CREATED) &&
(cueState < XACT_STATE_STOPPED));
}

/************************************************************************
* desc: Get the state of the sound
*
* ret: DWORD - state value of cue
************************************************************************/

DWORD GetState()
{
DWORD cueState(0);

if( pCue != NULL )
{
pCue->GetState( &cueState );
}

return cueState;
}

// Pointer to sound bank
IXACT3SoundBank * pSoundBank;

// Index of sound cue
XACTINDEX cueIndex;

// Cue instance pointer
IXACT3Cue * pCue;
};


#endif // __sound_cue_h__






Here are some misc needed class defines

/************************************************************************
* FILE NAME: xactdefs.h
*
* DESCRIPTION: xact defines
************************************************************************/


#ifndef __xact_defs_h__
#define __xact_defs_h__

// DirectX lib dependencies
#include <xact3.h>

class CWaveBankFileHeader
{
public:
char header[4];
int version;
int headerSize1;
int headerSize2;
int offsetDetailsDir;
int lengthDetailsDir;
int offsetFileNameDir;
int lengthFileNameDir;
int firstFileOffset;
int unknown1;
short int unknown2[6];
short int streaming;
short int unknown3;
int noOfFiles;
char fileName[16];
int lengthDetailEntry;
int lengthFilenameEntry;
int paddingBetweenFiles;
int nullValue;
};


class CWaveBank
{
public:

CWaveBank() : pWaveBank(NULL),
pMemMapBuffer(NULL),
streamFileHandle(NULL)
{
}

// pointer to wav bank
IXACT3WaveBank * pWaveBank;

// pointer to memory mapped buffer
VOID * pMemMapBuffer;

// handle to stream file
HANDLE streamFileHandle;
};


class CSoundBank
{
public:

CSoundBank() : pSoundBank(NULL),
pSoundBankBuffer(NULL)
{
}

// Pointer to sound bank
IXACT3SoundBank * pSoundBank;

// Allocated sound bank buffer
unsigned char * pSoundBankBuffer;
};


#endif // __xact_defs_h__






Here's the C++ file

/************************************************************************
* FILE NAME: xact.cpp
*
* DESCRIPTION: DirectX sound class wapper
************************************************************************/


// Physical component dependency
#include "xact.h"

// DirectX lib dependencies
#include "d3dx9.h"

// Game lib dependencies
#include "genfunc.h"
#include "deletefuncs.h"

// Required namespace(s)
using namespace std;

/************************************************************************
* desc: Constructor
************************************************************************/

CXAct::CXAct()
: pEngine(NULL)
{
} // Constructor


/************************************************************************
* desc: Destructor
************************************************************************/

CXAct::~CXAct()
{
// Shutdown XACT
if( pEngine != NULL )
{
pEngine->ShutDown();
pEngine->Release();
pEngine = NULL;
}

// Delete the sound bank buffers
for( map<string, CSoundBank *>::iterator iter = soundBankMap.begin();
iter != soundBankMap.end();
iter++ )
{
DeleteArray( iter->second->pSoundBankBuffer );
}

DeleteMapPointers( soundBankMap );

// Close memory map and streaming file handles
for( map<string, CWaveBank *>::iterator iter = waveBankMap.begin();
iter != waveBankMap.end();
iter++ )
{
if( iter->second->pMemMapBuffer != NULL )
{
UnmapViewOfFile( iter->second->pMemMapBuffer );
}
else if( iter->second->streamFileHandle != NULL )
{
CloseHandle( iter->second->streamFileHandle );
}
}

DeleteMapPointers( waveBankMap );

CoUninitialize();
DeleteCriticalSection( &criticalSection );

} // Destructor


/************************************************************************
* desc: Init the xact audio system with the global settings file
*
* param: std::string & filePath - path to the global settings file
*
* ret: bool - false on fail
************************************************************************/

bool CXAct::Init( std::string & filePath )
{
HRESULT hr;

// Set our critical section variable
InitializeCriticalSection( &criticalSection );

// COINIT_APARTMENTTHREADED will work too
if( SUCCEEDED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) )
{
hr = XACT3CreateEngine( 0, &pEngine );
}
if( FAILED( hr ) || pEngine == NULL )
{
DisplayError( hr );
return false;
}

bool bSuccess = false;

// Initialize & create the XACT runtime
XACT_RUNTIME_PARAMETERS xrParams = {0};
xrParams.globalSettingsFlags = XACT_FLAG_GLOBAL_SETTINGS_MANAGEDATA;
xrParams.fnNotificationCallback = XACTNotificationCallback;
xrParams.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT;

HANDLE hFile = CreateFile( filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if( hFile != NULL )
{
xrParams.globalSettingsBufferSize = GetFileSize( hFile, NULL );
if( xrParams.globalSettingsBufferSize != INVALID_FILE_SIZE )
{
// Using CoTaskMemAlloc so that XACT can clean up this data when its done
xrParams.pGlobalSettingsBuffer = CoTaskMemAlloc( xrParams.globalSettingsBufferSize );
if( xrParams.pGlobalSettingsBuffer != NULL )
{
DWORD dwBytesRead;
if( 0 != ReadFile( hFile, xrParams.pGlobalSettingsBuffer, xrParams.globalSettingsBufferSize, &dwBytesRead, NULL ) )
{
bSuccess = true;
}
}
}
CloseHandle( hFile );
}

if( !bSuccess )
{
if( xrParams.pGlobalSettingsBuffer != NULL )
{
CoTaskMemFree( xrParams.pGlobalSettingsBuffer );
}

PostMsg( "XACT Error", "Error reading in global settings file." );
return false;
}

// Initialize & create the XACT runtime
if( FAILED( hr = pEngine->Initialize( &xrParams ) ) )
{
DisplayError( hr );
return false;
}

// Initialize 3D settings
if( FAILED( hr = XACT3DInitialize( pEngine, x3DInstance ) ) )
{
DisplayError( hr );
return false;
}

// Init for 3D sound
Init3DSound();

return true;

} // Init


/************************************************************************
* desc: Init the class member variables for 3D sound
************************************************************************/

void CXAct::Init3DSound()
{
HRESULT hr;

// Setup 3D audio structs
ZeroMemory( &listener, sizeof( listener ) );
listener.OrientFront = D3DXVECTOR3( 0, 0, 1 );
listener.OrientTop = D3DXVECTOR3( 0, 1, 0 );
listener.Position = D3DXVECTOR3( 0, 0, 0 );
listener.Velocity = D3DXVECTOR3( 0, 0, 0 );

ZeroMemory( &emitter, sizeof( emitter ) );
emitter.pCone = NULL;
emitter.OrientFront = D3DXVECTOR3( 0, 0, 1 );
emitter.OrientTop = D3DXVECTOR3( 0, 1, 0 );
emitter.Position = D3DXVECTOR3( 0, 0, 0 );
emitter.Velocity = D3DXVECTOR3( 0, 0, 0 );
emitter.ChannelCount = 2;
emitter.ChannelRadius = 1.0f;
emitter.pChannelAzimuths = NULL;
emitter.pVolumeCurve = NULL;
emitter.pLFECurve = NULL;
emitter.pLPFDirectCurve = NULL;
emitter.pLPFReverbCurve = NULL;
emitter.pReverbCurve = NULL;
emitter.CurveDistanceScaler = 1.0f;
emitter.DopplerScaler = NULL;

// query number of channels on the final mix
WAVEFORMATEXTENSIBLE wfxFinalMixFormat;
if( FAILED( hr = pEngine->GetFinalMixFormat( &wfxFinalMixFormat ) ) )
{
// Just show an error message. Don't kill the game over this
DisplayError( hr );
}

// Init MatrixCoefficients. XACT will fill in the values
ZeroMemory( &matrixCoefficients, sizeof( matrixCoefficients ) );

ZeroMemory( &dspSettings, sizeof( dspSettings ) );
ZeroMemory( &delayTimes, sizeof( delayTimes ) );
dspSettings.pMatrixCoefficients = matrixCoefficients;
dspSettings.pDelayTimes = delayTimes;
dspSettings.SrcChannelCount = 2;
dspSettings.DstChannelCount = wfxFinalMixFormat.Format.nChannels;

} // Init3DSound


/************************************************************************
* desc: Load a wav bank
*
* param: std::string & filePath - path to the wav bank file
*
* ret: bool - false of fail
************************************************************************/

bool CXAct::LoadWaveBank( std::string & filePath )
{
CWaveBankFileHeader header;
unsigned long bytesRead;
DWORD dwFileSize;
HRESULT hr;
CWaveBank * pWaveBank;

// See if this wave bank has already been loaded
map<std::string, CWaveBank *>::iterator iter = waveBankMap.find( filePath );

// If it's not found, allocate the wave bank class and add it to the list
if( iter == waveBankMap.end() )
{
pWaveBank = new CWaveBank;
waveBankMap.insert( make_pair(filePath, pWaveBank) );
}
else
{
PostMsg( "Error", "Wave bank already loaded (%s).", filePath.c_str() );
return false;
}

// NOTE: This is a bit of a hack because parts of the xwb file header is unknown.
// As far as I can tell, the part that I isolated is the flag that indicates if
// the wav bank is loaded into memory or that it is ment to be streamed.

// Open the file on the hard drive and read in the header
HANDLE hFile = CreateFile( filePath.c_str(), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL );

// Check to see that we have a valid file handle
if( hFile == INVALID_HANDLE_VALUE )
{
PostMsg( "Error", "Can't open wave bank (%s) to read header information.", filePath.c_str() );
CloseHandle( hFile );

return false;
}

// Read contents of file into memory
BOOL readResult = ReadFile( hFile, &header, sizeof(header), &bytesRead, NULL );

if( !readResult || bytesRead != sizeof(header) )
{
PostMsg( "Error", "Can't read wave bank file (%s) for header information.", filePath.c_str() );
CloseHandle( hFile );

return false;
}

// We got what we came for so close it
CloseHandle( hFile );

if( header.streaming )
{
hFile = CreateFile( filePath.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
NULL );

if( hFile != INVALID_HANDLE_VALUE )
{
XACT_WAVEBANK_STREAMING_PARAMETERS wsParams;
ZeroMemory( &wsParams, sizeof( XACT_WAVEBANK_STREAMING_PARAMETERS ) );
wsParams.file = hFile;
wsParams.offset = 0;

// 64 means to allocate a 64 * 2k buffer for streaming.
// This is a good size for DVD streaming and takes good advantage of the read ahead cache
wsParams.packetSize = 64;

if( FAILED( hr = pEngine->CreateStreamingWaveBank( &wsParams, &pWaveBank->pWaveBank ) ) )
{
DisplayError( hr );
PostMsg( "Error", "Can't create streaming wav bank (%s).", filePath.c_str() );
return false;
}
}
else
{
PostMsg( "Error", "Can't open wave bank (%s) to create streaming wav bank.", filePath.c_str() );
CloseHandle( hFile );
return false;
}

// Record the file handle
pWaveBank->streamFileHandle = hFile;
}
else
{
// assume failure
hr = E_FAIL;

// Read and register the wave bank file with XACT using memory mapped file IO
// Memory mapped files tend to be the fastest for most situations assuming you
// have enough virtual address space for a full map of the file
hFile = CreateFile( filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if( hFile != INVALID_HANDLE_VALUE )
{
dwFileSize = GetFileSize( hFile, NULL );
if( dwFileSize != -1 )
{
HANDLE hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL );
if( hMapFile )
{
pWaveBank->pMemMapBuffer = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );
if( pWaveBank->pMemMapBuffer != NULL )
{
hr = pEngine->CreateInMemoryWaveBank( pWaveBank->pMemMapBuffer, dwFileSize, 0, 0, &pWaveBank->pWaveBank );
}
CloseHandle( hMapFile ); // pbWaveBank is maintains a handle on the file so close this unneeded handle
}
}
CloseHandle( hFile ); // pbWaveBank is maintains a handle on the file so close this unneeded handle
}

if( FAILED( hr ) )
{
DisplayError( hr );
PostMsg( "Error", "Can't create in memory wav bank (%s).", filePath.c_str() );
return false;
}
}

// Register for XACT notification if this wave bank is to be destroyed
XACT_NOTIFICATION_DESCRIPTION desc = {0};
desc.flags = XACT_FLAG_NOTIFICATION_PERSIST;
desc.type = XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED;
desc.pWaveBank = pWaveBank->pWaveBank;
desc.pvContext = this; // never forget the this pointer!

if( FAILED( hr = pEngine->RegisterNotification( &desc ) ) )
{
DisplayError( hr );
return false;
}

return true;

} // LoadWavBank


/************************************************************************
* desc: Load a sound bank
*
* param: std::string & filePath - path to the sound bank file
*
* ret: bool - false of fail
************************************************************************/

bool CXAct::LoadSoundBank( std::string & filePath )
{
unsigned long bytesRead;
DWORD dwFileSize;
HRESULT hr;
CSoundBank * pSoundBank;

// See if this wave bank has already been loaded
map<std::string, CSoundBank *>::iterator iter = soundBankMap.find( filePath );

// If it's not found, allocate the wave bank class and add it to the list
if( iter == soundBankMap.end() )
{
pSoundBank = new CSoundBank;
soundBankMap.insert( make_pair(filePath, pSoundBank) );
}
else
{
PostMsg( "Error", "Sound bank already loaded (%s).", filePath.c_str() );
return false;
}

hr = E_FAIL; // assume failure
HANDLE hFile = CreateFile( filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if( hFile != INVALID_HANDLE_VALUE )
{
dwFileSize = GetFileSize( hFile, NULL );
if( dwFileSize != -1 )
{
// Allocate the data here and free the data when recieving the sound bank destroyed notification
pSoundBank->pSoundBankBuffer = new unsigned char[dwFileSize];
if( pSoundBank->pSoundBankBuffer != NULL )
{
BOOL readResult = ReadFile( hFile, pSoundBank->pSoundBankBuffer, dwFileSize, &bytesRead, NULL );
if( readResult || bytesRead == dwFileSize )
{
hr = pEngine->CreateSoundBank( pSoundBank->pSoundBankBuffer, dwFileSize, 0, 0, &pSoundBank->pSoundBank );
}
}
}
CloseHandle( hFile );
}

if( FAILED( hr ) )
{
DisplayError( hr );
PostMsg( "Error", "Can't create sound bank (%s).", filePath.c_str() );
return false;
}

// Register for XACT notification if this wave bank is to be destroyed
XACT_NOTIFICATION_DESCRIPTION desc = {0};
desc.flags = XACT_FLAG_NOTIFICATION_PERSIST;
desc.type = XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED;
desc.pSoundBank = pSoundBank->pSoundBank;
desc.pvContext = this; // never forget the this pointer!

if( FAILED( hr = pEngine->RegisterNotification( &desc ) ) )
{
DisplayError( hr );
return false;
}

return true;

} // LoadSoundBank


/************************************************************************
* desc: Destroy a wave bank
*
* param: std::string & filePath - path to the wave bank file
************************************************************************/

void CXAct::DestroyWaveBank( std::string & filePath )
{
// See if this wave bank has been loaded
map<std::string, CWaveBank *>::iterator iter = waveBankMap.find( filePath );

// Only destroy it if it has been found
if( iter != waveBankMap.end() )
{
// an XACTNotificationCallback will be sent and there
// is where the clean-up will be handled
iter->second->pWaveBank->Destroy();
}

} // DestroyWaveBank


/************************************************************************
* desc: Destroy a sound bank
*
* param: std::string & filePath - path to the wave bank file
************************************************************************/

void CXAct::DestroySoundBank( std::string & filePath )
{
// See if this wave bank has been loaded
map<std::string, CSoundBank *>::iterator iter = soundBankMap.find( filePath );

// Only destroy it if it has been found
if( iter != soundBankMap.end() )
{
// an XACTNotificationCallback will be sent and there
// is where the clean-up will be handled
iter->second->pSoundBank->Destroy();
}

} // DestroyWaveBank


/************************************************************************
* desc: Position the sound cue based on the point
*
* param: std::string & sndCueStr - sound cue string
*
* ret: CSoundCue - filled in sound cue class
************************************************************************/

void CXAct::PositionCue( CPoint & point, IXACT3Cue * pCue )
{
listener.Position = D3DXVECTOR3( point.x, point.y, point.z );

XACT3DCalculate( x3DInstance, &listener, &emitter, &dspSettings );
XACT3DApply( &dspSettings, pCue );

} // PositionCue


/************************************************************************
* desc: This is the callback for handling XACT notifications
*
* param: const XACT_NOTIFICATION* pNotification - notification pointer
*
* ret: WINAPI
************************************************************************/

void WINAPI CXAct::XACTNotificationCallback( const XACT_NOTIFICATION * pNotification )
{
if( (pNotification != NULL) && (pNotification->pvContext != NULL) )
{
// Cast our pointer
// Be sure to set pNotification->pvContext to the "this" pointer
CXAct * pXAct = reinterpret_cast<CXAct *>(pNotification->pvContext);

pXAct->HandleNotification( pNotification );
}

} // XACTNotificationCallback


/************************************************************************
* desc: Function for handling XACT notifications
*
* param: const XACT_NOTIFICATION* pNotification - notification pointer
************************************************************************/

void CXAct::HandleNotification( const XACT_NOTIFICATION * pNotification )
{
if( pNotification->type == XACTNOTIFICATIONTYPE_WAVEBANKDESTROYED )
{
// Close memory map and streaming file handles
for( map<string, CWaveBank *>::iterator iter = waveBankMap.begin();
iter != waveBankMap.end();
iter++ )
{
// Find the wave bank we want to delete
if( iter->second->pWaveBank == pNotification->waveBank.pWaveBank )
{
if( iter->second->pMemMapBuffer != NULL )
{
UnmapViewOfFile( iter->second->pMemMapBuffer );
}
else if( iter->second->streamFileHandle != NULL )
{
CloseHandle( iter->second->streamFileHandle );
}
Delete( iter->second );
PostDebugMsg( "Wave Bank Deleted: %s", iter->first.c_str() );
waveBankMap.erase( iter );
break;
}
}
}
else if( pNotification->type == XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED )
{
for( map<string, CSoundBank *>::iterator iter = soundBankMap.begin();
iter != soundBankMap.end();
iter++ )
{
// Find the sound bank we want to delete
if( iter->second->pSoundBank == pNotification->soundBank.pSoundBank )
{
DeleteArray( iter->second->pSoundBankBuffer );
Delete( iter->second );
PostDebugMsg( "Sound Bank Deleted: %s", iter->first.c_str() );
soundBankMap.erase( iter );
break;
}
}
}
} // HandleNotification


/************************************************************************
* desc: Allows XACT to do required periodic work. call within game loop
************************************************************************/

void CXAct::Update()
{
if( pEngine != NULL )
{
pEngine->DoWork();
}
} // Update


/************************************************************************
* desc: Get a sound cue
*
* param: std::string & sndCueStr - sound cue string
*
* ret: CSoundCue - filled in sound cue class
************************************************************************/

CSoundCue CXAct::GetSoundCue( std::string & sndCueStr )
{
CSoundCue soundCue;

for( map<string, CSoundBank *>::iterator iter = soundBankMap.begin();
iter != soundBankMap.end();
iter++ )
{
if( XACTINDEX_INVALID != (soundCue.cueIndex = iter->second->pSoundBank->GetCueIndex( sndCueStr.c_str() )) )
{
// copy the pointer to the sound bank
soundCue.pSoundBank = iter->second->pSoundBank;
break;
}
}

return soundCue;

} // GetSoundCue


/************************************************************************
* desc: Play a sound - Good for "Fire & Forget" but use GetSoundCue
* for more options.
*
* param: std::string & - string ID of sound cue. Name entered in XACT
* tool.
************************************************************************/

void CXAct::Play( std::string & sndCueStr )
{
GetSoundCue( sndCueStr ).Play();

} // Play


/************************************************************************
* desc: Stop a sound - Good for "Fire & Forget" but use GetSoundCue
* for more options.
*
* param: std::string & - string ID of sound cue. Name entered in XACT
* tool.
************************************************************************/

void CXAct::Stop( std::string & sndCueStr )
{
GetSoundCue( sndCueStr ).Stop();

} // Stop


/************************************************************************
* desc: Prepare a sound - Good for "Fire & Forget" but use GetSoundCue
* for more options.
*
* param: std::string & - string ID of sound cue. Name entered in XACT
* tool.
************************************************************************/

void CXAct::Prepare( std::string & sndCueStr )
{
GetSoundCue( sndCueStr ).Prepare();

} // Stop


/************************************************************************
* desc: Get the instance of the CXAct singleton class
************************************************************************/

CXAct & CXAct::Instance()
{
static CXAct xact;

return xact;
}


/************************************************************************
* desc: Display error information
*
* param: HRESULT hr - return result from function call
************************************************************************/

void CXAct::DisplayError( HRESULT hr )
{
switch( hr )
{
case XACTENGINE_E_OUTOFMEMORY:
{
PostMsg( "XACT Error", "%s", "XACT engine out of memory." );
break;
}

case XACTENGINE_E_INVALIDARG:
{
PostMsg( "XACT Error", "%s", "Invalid arguments." );
break;
}

case XACTENGINE_E_NOTIMPL:
{
PostMsg( "XACT Error", "%s", "Feature not implemented" );
break;
}

case XACTENGINE_E_ALREADYINITIALIZED:
{
PostMsg( "XACT Error", "XACT engine is already initialized." );
break;
}

case XACTENGINE_E_NOTINITIALIZED:
{
PostMsg( "XACT Error", "XACT engine has not been initialized." );
break;
}

case XACTENGINE_E_EXPIRED:
{
PostMsg( "XACT Error", "XACT engine has expired (demo or pre-release version)." );
break;
}

case XACTENGINE_E_NONOTIFICATIONCALLBACK:
{
PostMsg( "XACT Error", "No notification callback" );
break;
}

case XACTENGINE_E_NOTIFICATIONREGISTERED:
{
PostMsg( "XACT Error", "Notification already registered." );
break;
}

case XACTENGINE_E_INVALIDUSAGE:
{
PostMsg( "XACT Error", "Invalid usage." );
break;
}

case XACTENGINE_E_INVALIDDATA:
{
PostMsg( "XACT Error", "Invalid data." );
break;
}

case XACTENGINE_E_INSTANCELIMITFAILTOPLAY:
{
PostMsg( "XACT Error", "Fail to play due to instance limit." );
break;
}

case XACTENGINE_E_NOGLOBALSETTINGS:
{
PostMsg( "XACT Error", "Global Settings not loaded." );
break;
}

case XACTENGINE_E_INVALIDVARIABLEINDEX:
{
PostMsg( "XACT Error", "Invalid variable index." );
break;
}

case XACTENGINE_E_INVALIDCATEGORY:
{
PostMsg( "XACT Error", "Invalid category." );
break;
}

case XACTENGINE_E_INVALIDCUEINDEX:
{
PostMsg( "XACT Error", "Invalid cue index." );
break;
}

case XACTENGINE_E_INVALIDWAVEINDEX:
{
PostMsg( "XACT Error", "Invalid wave index." );
break;
}

case XACTENGINE_E_INVALIDTRACKINDEX:
{
PostMsg( "XACT Error", "Invalid track index." );
break;
}

case XACTENGINE_E_INVALIDSOUNDOFFSETORINDEX:
{
PostMsg( "XACT Error", "Invalid sound offset or index." );
break;
}

case XACTENGINE_E_READFILE:
{
PostMsg( "XACT Error", "Error reading a file." );
break;
}

case XACTENGINE_E_UNKNOWNEVENT:
{
PostMsg( "XACT Error", "Unknown event type." );
break;
}

case XACTENGINE_E_INCALLBACK:
{
PostMsg( "XACT Error", "Invalid call of method of function from callback." );
break;
}

case XACTENGINE_E_NOWAVEBANK:
{
PostMsg( "XACT Error", "No wavebank exists for desired operation." );
break;
}

case XACTENGINE_E_SELECTVARIATION:
{
PostMsg( "XACT Error", "Unable to select a variation." );
break;
}

case XACTENGINE_E_MULTIPLEAUDITIONENGINES:
{
PostMsg( "XACT Error", "There can be only one audition engine." );
break;
}

case XACTENGINE_E_WAVEBANKNOTPREPARED:
{
PostMsg( "XACT Error", "The wavebank is not prepared." );
break;
}

case XACTENGINE_E_NORENDERER:
{
PostMsg( "XACT Error", "No audio device found on." );
break;
}

case XACTENGINE_E_INVALIDENTRYCOUNT:
{
PostMsg( "XACT Error", "Invalid entry count for channel maps." );
break;
}

case XACTENGINE_E_SEEKTIMEBEYONDCUEEND:
{
PostMsg( "XACT Error", "Time offset for seeking is beyond the cue end." );
break;
}

case XACTENGINE_E_SEEKTIMEBEYONDWAVEEND:
{
PostMsg( "XACT Error", "Time offset for seeking is beyond the wave end." );
break;
}

case XACTENGINE_E_NOFRIENDLYNAMES:
{
PostMsg( "XACT Error", "Friendly names are not included in the bank." );
break;
}

default:
{
PostMsg( "XACT Error", "Unknown error" );
break;
}
}
} // DisplayError






Last but not least, here are the helper header files being used by the class. That should be all that you need.

/************************************************************************
* FILE NAME: point.h
*
* DESCRIPTION: 3D Point class
************************************************************************/


#ifndef __point_h__
#define __point_h__

#include <math.h>

#define PIOVER180 0.017453292519943295
#define PI 3.14159265358979323846

class CPoint
{
public:

// point values.
float x, y, z;

// Fast init if class varaibles.
CPoint():x(0.0),y(0.0),z(0.0)
{
}

// Copy constructor
CPoint( const CPoint & obj )
{
*this = obj;
}

// Constructor
CPoint( float _x, float _y, float _z ):x(_x),y(_y),z(_z)
{
}

/************************************************************************
* desc: Clear the x
************************************************************************/

void ClearX()
{
x = 0.0f;
}

/************************************************************************
* desc: Clear the y
************************************************************************/

void ClearY()
{
y = 0.0f;
}

/************************************************************************
* desc: Clear the z
************************************************************************/

void ClearZ()
{
z = 0.0f;
}

/************************************************************************
* desc: Clear the values
************************************************************************/

void Clear()
{
x = 0.0f;
y = 0.0f;
z = 0.0f;
}

/************************************************************************
* desc: The equality operator
*
* param: CPoint & point - point to check
*
* return: bool - true or false
************************************************************************/

bool operator == ( CPoint & point )
{
if( (point.x == x) && (point.y == y) && (point.z == z) )
{
return true;
}
return false;

} // operator ==

/************************************************************************
* desc: The inequality operator
*
* param: CPoint & point - point to check
*
* return: bool - true or false
************************************************************************/

bool operator != ( CPoint & point )
{
if( ( point.x != x ) || ( point.y != y ) || ( point.z != z ) )
{
return true;
}
return false;

} // operator !=

/************************************************************************
* desc: The subtraction operator
*
* param: CPoint & point - point to subtract
*
* return: CPoint - subtracted point
************************************************************************/

CPoint operator - ( CPoint & point )
{
CPoint tmp;
tmp.x = x - point.x;
tmp.y = y - point.y;
tmp.z = z - point.z;

return tmp;

} // operator -

/************************************************************************
* desc: The subtraction operator
*
* param: float * value - value to subtract
*
* return: CPoint - subtracted point
************************************************************************/

CPoint operator - ( float value )
{
CPoint tmp;
tmp.x = x - value;
tmp.y = y - value;
tmp.z = z - value;

return tmp;

} // operator -

/************************************************************************
* desc: The addition operator
*
* param: CPoint & point - point to add
*
* return: CPoint - added point
************************************************************************/

CPoint operator + ( CPoint & point )
{
CPoint tmp;
tmp.x = x + point.x;
tmp.y = y + point.y;
tmp.z = z + point.z;

return tmp;

} // operator +

/************************************************************************
* desc: The addition operator
*
* param: float value - value to add
*
* return: CPoint - added point
************************************************************************/

CPoint operator + ( float value )
{
CPoint tmp;
tmp.x = x + value;
tmp.y = y + value;
tmp.z = z + value;

return tmp;

} // operator +

/************************************************************************
* desc: The addition operator
*
* param: CPoint & point - point to add
*
* return: CPoint - added point
************************************************************************/

CPoint operator += ( CPoint & point )
{
x += point.x;
y += point.y;
z += point.z;

return *this;

} // operator +=

/************************************************************************
* desc: The addition operator
*
* param: float value - value to add
*
* return: CPoint - added point
************************************************************************/

CPoint operator += ( float value )
{
x += value;
y += value;
z += value;

return *this;

} // operator +=

/************************************************************************
* desc: The multiplication operator
*
* param: CPoint & point * point to multiply
*
* return: CPoint - multiplied point
************************************************************************/

CPoint operator * ( CPoint & point )
{
CPoint tmp;
tmp.x = x * point.x;
tmp.y = y * point.y;
tmp.z = z * point.z;

return tmp;

} // operator *

/************************************************************************
* desc: The multiplication operator
*
* param: float value - value to multiply
*
* return: CPoint - multiplied point
************************************************************************/

CPoint operator * ( float value )
{
CPoint tmp;
tmp.x = x * value;
tmp.y = y * value;
tmp.z = z * value;

return tmp;

} // operator *

/************************************************************************
* desc: The multiplication operator
*
* param: CPoint & point - point to multiply
*
* return: CPoint - multiplied point
************************************************************************/

CPoint operator *= ( CPoint & point )
{
x *= point.x;
y *= point.y;
z *= point.z;

return *this;

} // operator *=

/************************************************************************
* desc: The multiplication operator
*
* param: float value * value to multiply
*
* return: CPoint - multiplied point
************************************************************************/

CPoint operator *= ( float value )
{
x *= value;
y *= value;
z *= value;

return *this;

} // operator *=

/************************************************************************
* desc: The division operator
*
* param: CPoint & point / point to divide
*
* return: CPoint - divided point
************************************************************************/

CPoint operator /= ( CPoint & point )
{
x /= point.x;
y /= point.y;
z /= point.z;

return *this;

} // operator *=

/************************************************************************
* desc: The division operator
*
* param: float value / value to divide
*
* return: CPoint - divided point
************************************************************************/

CPoint operator /= ( float value )
{
x /= value;
y /= value;
z /= value;

return *this;

} // operator *=

/************************************************************************
* desc: Set the point data
************************************************************************/

void Set( float _x, float _y, float _z )
{
x = _x;
y = _y;
z = _z;

} // Set

/************************************************************************
* desc: Cap the value
************************************************************************/

void Cap( float value )
{
if( value > 0.0f )
{
if( x > value )
{
x -= value;
}
else if ( x < 0.0f )
{
x += value;
}

if( y > value )
{
y -= value;
}
else if ( y < 0.0f )
{
y += value;
}

if( z > value )
{
z -= value;
}
else if ( z < 0.0f )
{
z += value;
}
}
else
{
if( x > value )
{
x += value;
}
else if ( x < 0.0f )
{
x -= value;
}

if( y > value )
{
y += value;
}
else if ( y < 0.0f )
{
y -= value;
}

if( z > value )
{
z += value;
}
else if ( z < 0.0f )
{
z -= value;
}
}

} // Cap

/************************************************************************
* desc: Does this point not have any data?
*
* return: bool
************************************************************************/

bool IsEmpty()
{
return ( x == 0.0f ) && ( y == 0.0f ) && ( z == 0.0f );

} // IsEmpty

/************************************************************************
* desc: Invert the values of this point
************************************************************************/

void Invert()
{
x = -x;
y = -y;
z = -z;

} // Invert

/************************************************************************
* desc: Invert the values of this point
************************************************************************/

void InvertX()
{
x = -x;

} // Invert

/************************************************************************
* desc: Invert the values of this point
************************************************************************/

void InvertY()
{
y = -y;

} // Invert

/************************************************************************
* desc: Invert the values of this point
************************************************************************/

void InvertZ()
{
z = -z;

} // Invert

/************************************************************************
* desc: Get the length between two untransformed points
*
* param: CPoint & point - point
*
* return: float - distance between two points
************************************************************************/

float _fastcall GetLength( CPoint & point )
{
// Calculate the distance between the center points of both objects
return( ((x - point.x) * (x - point.x)) +
((y - point.y) * (y - point.y)) +
((z - point.z) * (z - point.z)) );

} // GetLengthSt

/************************************************************************
* desc: Get the length of the points
*
* return: float - length of point
************************************************************************/

float GetLength()
{
return( x * x ) + ( y * y ) + ( z * z );

} // GetLength

/************************************************************************
* desc: Get the dot product
*
* param: CPoint & point
*
* return: float - distance between two points
************************************************************************/

float _fastcall GetDotProduct( CPoint & point )
{
// Calculate the dot product between two
return( ( x * point.x ) +
( y * point.y ) +
( z * point.z ) );

} // GetDotProduct

/************************************************************************
* desc: normalize this point
************************************************************************/

void Normalize()
{
float length = sqrt( GetLength() );

if( length != 0.0f )
{
x /= length;
y /= length;
z /= length;
}

} // Normalize

/************************************************************************
* desc: Create a displacement vector
*
* param: CPoint & point
* float amount - amount of displacement
*
* return: CPoint - the dislacement vector
************************************************************************/

CPoint GetDisplacement( CPoint & point, float amount )
{
CPoint displacement( *this - point );
displacement.Normalize();
CPoint tmp = *this + (displacement * amount);

return tmp;

} // GetDisplacement

/************************************************************************
* desc: Create a displacement vector
*
* param: CPoint & point
* float amount - amount of displacement
*
* return: CPoint - the dislacement vector
************************************************************************/

CPoint _fastcall GetDisplacementN( CPoint & point, float amount )
{
CPoint displacement( *this - point );
displacement.Normalize();
CPoint tmp = *this + (point * amount);

return tmp;
}
};

#endif // __point_h__






/************************************************************************
* FILE NAME: genfunc.h
*
* DESCRIPTION: General mutipurpose functions
************************************************************************/


#ifndef __genfunc_h__
#define __genfunc_h__

#include <windows.h> // Windows header file for creating windows programs. This is a must have.
#include <stdlib.h>
#include <stdio.h>

/************************************************************************
* desc: Translates into a windows messagebox with
* sprintf capabilities.
*
* param: char *title - Title of the windows message box
* char *fmt - Used with vprintf to get the argument list
* for wvsprintf.
************************************************************************/

inline void PostMsg( char *title, char *fmt, ... )
{
va_list argptr;
char strBuffer[512];

va_start( argptr, fmt );
vprintf( fmt, argptr );
vsprintf_s( strBuffer, fmt, argptr );
MessageBox( GetActiveWindow(), strBuffer, title, MB_ICONINFORMATION );
va_end( argptr );

} // PostMsg


/************************************************************************
* desc: Translates into a debug string to your VC++ Output window with
* sprintf capabilities.
*
* param: char *fmt - Used with vprintf to get the argument list
* for vsprintf_s.
************************************************************************/

inline void PostDebugMsg( char *fmt, ... )
{
va_list argptr;
char strBuffer[256];

va_start( argptr, fmt );
vprintf( fmt, argptr );
vsprintf_s( strBuffer, fmt, argptr );
strcat_s( strBuffer, "\n" );
OutputDebugString( strBuffer );
va_end( argptr );

} // PostMsg


#endif /* __genfunc_h__ */






//*****************************************************************************
/*!
* \file deletefuncs.h
*
* \brief Delete functions for pointers, vectors m.m.
*
*****************************************************************************/


#ifndef _deletefuncs_h
#define _deletefuncs_h

// Standard lib dependencies.
#include <map>
#include <list>
#include <vector>
#include <deque>
#include <algorithm>
#include <functional>


//*****************************************************************************
/*!
* \brief Templetized safe-delete function.
*
* \param T *& ptr - A reference to a pointer of type T
*
*****************************************************************************/

template <class T>
inline void Delete(T & ptr)
{
// Check for NULL-pointer
if (ptr != NULL)
{
// Delete object pointed to.
delete ptr;
ptr = NULL;
}
}


//*****************************************************************************
/*!
* \brief Templetized safe-release comm function.
*
* \param T *& ptr - A reference to a pointer of type T
*
*****************************************************************************/

template <class T>
inline void Release(T & ptr)
{
// Check for NULL-pointer
if (ptr != NULL)
{
// Release comm object.
ptr->Release();
ptr = NULL;
}
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete array function.
*
* \param T *& ptr - A reference to an array pointer of type T
*
*****************************************************************************/

template <class T>
inline void DeleteArray(T & ptr)
{
// Check for NULL-pointer
if (ptr != NULL)
{
// Delete object pointed to.
delete [] ptr;
ptr = NULL;
}
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for vectors of pointers.
*
* \param vector<T> & obj - A reference to a vector of objects of type T.
*
*****************************************************************************/

template <class T>
inline void DeleteVectorPointers(std::vector<T> & obj)
{
// Loop through the vector and delete all objects pointed to.
for_each(obj.begin(), obj.end(), Delete<T>);

// Clear out the vector.
obj.clear();
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for vectors of pointers.
*
* \param vector<T> & obj - A reference to a vector of objects of type T.
*
*****************************************************************************/

template <class T>
inline void DeleteVectorPointerArrays(std::vector<T> & obj)
{
// Loop through the vector and delete all objects pointed to.
for_each(obj.begin(), obj.end(), DeleteArray<T>);

// Clear out the vector.
obj.clear();
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for a deque of pointers.
*
* \param deque<T> & obj - A reference to a deque of objects of type T.
*
*****************************************************************************/

template <class T>
inline void DeleteDequePointers(std::deque<T> & obj)
{
// Loop through the vector and delete all objects pointed to.
for_each(obj.begin(), obj.end(), Delete<T>);

// Clear out the deque.
obj.clear();
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for lists of pointers.
*
* \param list<T> & obj - A reference to a list of objects of type T.
*
*****************************************************************************/

template <class T>
inline void DeleteListPointers(std::list<T> & obj)
{
// Loop through the vector and delete all objects pointed to.
for_each(obj.begin(), obj.end(), Delete<T>);

// Clear out the list.
obj.clear();
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for maps where the 'second' is
* a pointer to an allocated object.
*
* \param map<T> & obj - A reference to a map where the 'second' is an object
* of type T.
*
*****************************************************************************/

template <class key, class ptr>
inline void DeleteMapPointers(std::map<key, ptr> & obj)
{
// Loop through the map and delete all objects pointed to.
for (typename std::map<key, ptr>::iterator iter = obj.begin();
iter != obj.end();
++iter)
{
// Delete object pointed to by the dereferenced iterator..
Delete(iter->second);
}

// Clear out the map.
obj.clear();
}


//*****************************************************************************
/*!
* \brief Templetized safe-delete function for maps where the 'second' is
* a pointer to an allocated object.
*
* \param map<T> & obj - A reference to a map where the 'second' is an object
* of type T.
*
*****************************************************************************/

template <class key, class ptr>
inline void DeleteMapDirectXPointers(std::map<key, ptr> & obj)
{
// Loop through the map and delete all objects pointed to.
for (typename std::map<key, ptr>::iterator iter = obj.begin();
iter != obj.end();
++iter)
{
// Have directX release the data
Release( iter->second );
}

// Clear out the map.
obj.clear();
}

#endif // _deletefunc_h







[Edited by - howie_007 on March 3, 2010 6:33:30 AM]

Share this post


Link to post
Share on other sites

This topic is 2844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this