//-------------------------------------------------------------------------------------- // Initialize XACT engine //-------------------------------------------------------------------------------------- HRESULT InitXACT( IXACT3Engine** ppXACTEngine ) { // Init COM and create XACT engine HRESULT hr; hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if( SUCCEEDED( hr ) ) { // Switch to auditioning mode based on command line. Change if desired bool bAuditionMode = DoesCommandLineContainAuditionSwitch(); bool bDebugMode = false; DWORD dwCreationFlags = 0; if( bAuditionMode ) dwCreationFlags |= XACT_FLAG_API_AUDITION_MODE; if( bDebugMode ) dwCreationFlags |= XACT_FLAG_API_DEBUG_MODE; hr = XACT3CreateEngine( dwCreationFlags, ppXACTEngine ); } if( FAILED( hr ) || *ppXACTEngine == NULL ) return E_FAIL; XACT_RENDERER_DETAILS rendererDetails = {0}; if( FAILED( hr = ( *ppXACTEngine )->GetRendererDetails( 0, &rendererDetails ) ) ) return hr; XACT_RUNTIME_PARAMETERS xrParams = {0}; xrParams.fnNotificationCallback = NULL; xrParams.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT; xrParams.pRendererID = rendererDetails.rendererID; if( FAILED( hr = ( *ppXACTEngine )->Initialize( &xrParams ) ) ) return hr; return S_OK; }
HRESULT Sound::init() { ZeroMemory( &audioState, sizeof( AUDIO_STATE ) ); InitializeCriticalSection( &audioState.cs ); audioState.nCurSongPlaying = -1; audioState.nCurWorld = -1; audioState.bInBattle = false; audioState.bGlobalPaused = false; audioState.bMusicPaused = false; audioState.bBGMPaused = false; audioState.bBGMStopped = false; audioState.bBGMFade = false; audioState.fGlobalVolume = 1.0f; audioState.fMusicVolume = 1.0f; audioState.fBGMVolume = 1.0f; hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); // COINIT_APARTMENTTHREADED will work too if( SUCCEEDED( hr ) ) { // Switch to auditioning mode based on command line. Change if desired bool bAuditionMode = DoesCommandLineContainAuditionSwitch(); bool bDebugMode = false; DWORD dwCreationFlags = 0; if( bAuditionMode ) dwCreationFlags |= XACT_FLAG_API_AUDITION_MODE; if( bDebugMode ) dwCreationFlags |= XACT_FLAG_API_DEBUG_MODE; #ifdef USE_XACT3 hr = XACT3CreateEngine( dwCreationFlags, &audioState.pEngine ); #else hr = XACTCreateEngine( dwCreationFlags, &audioState.pEngine ); #endif } if( FAILED( hr ) || audioState.pEngine == NULL ) return E_FAIL; // Load the global settings file and pass it into XACTInitialize VOID* pGlobalSettingsData = NULL; DWORD dwGlobalSettingsFileSize = 0; bool bSuccess = false; hFile = CreateFile( L"Sounds.xgs", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if( hFile ) { dwGlobalSettingsFileSize = GetFileSize( hFile, NULL ); if( dwGlobalSettingsFileSize != INVALID_FILE_SIZE ) { pGlobalSettingsData = CoTaskMemAlloc( dwGlobalSettingsFileSize ); if( pGlobalSettingsData ) { if( 0 != ReadFile( hFile, pGlobalSettingsData, dwGlobalSettingsFileSize, reinterpret_cast<LPDWORD>(&dwBytesRead), NULL ) ) { bSuccess = true; } } } CloseHandle( hFile ); } if( !bSuccess ) { if( pGlobalSettingsData ) CoTaskMemFree( pGlobalSettingsData ); pGlobalSettingsData = NULL; dwGlobalSettingsFileSize = 0; } // Initialize & create the XACT runtime XACT_RUNTIME_PARAMETERS xrParams = {0}; xrParams.pGlobalSettingsBuffer = pGlobalSettingsData; xrParams.globalSettingsBufferSize = dwGlobalSettingsFileSize; xrParams.globalSettingsFlags = XACT_FLAG_GLOBAL_SETTINGS_MANAGEDATA; // this will tell XACT to delete[] the buffer when its unneeded xrParams.lookAheadTime = 250; xrParams.fnNotificationCallback = XACTNotificationCallback; hr = audioState.pEngine->Initialize( &xrParams ); if( FAILED( hr ) ) return hr; //----------------------------------------------------------------------------------------- // Register for XACT notifications //----------------------------------------------------------------------------------------- // The "wave bank prepared" notification will let the app know when it is save to use // play cues that reference streaming wave data. XACT_NOTIFICATION_DESCRIPTION desc = {0}; desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED; audioState.pEngine->RegisterNotification( &desc ); // The "sound bank destroyed" notification will let the app know when it is save to use // play cues that reference streaming wave data. desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED; audioState.pEngine->RegisterNotification( &desc ); // The "cue stop" notification will let the app know when it a song stops so a new one // can be played desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_CUESTOP; desc.cueIndex = XACTINDEX_INVALID; audioState.pEngine->RegisterNotification( &desc ); // The "cue prepared" notification will let the app know when it a a cue that uses // streaming data has been prepared so it is ready to be used for zero latency streaming desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_CUEPREPARED; desc.cueIndex = XACTINDEX_INVALID; audioState.pEngine->RegisterNotification( &desc ); // Create an "in memory" XACT wave bank file 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 hr = E_FAIL; // assume failure hFile = CreateFile( L"InMemory.xwb", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if( hFile != INVALID_HANDLE_VALUE ) { dwFileSize = GetFileSize( hFile, NULL ); if( dwFileSize != -1 ) { hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL ); if( hMapFile ) { audioState.pbInMemoryWaveBank = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 ); if( audioState.pbInMemoryWaveBank ) { hr = audioState.pEngine->CreateInMemoryWaveBank( audioState.pbInMemoryWaveBank, dwFileSize, 0, 0, &audioState.pInMemoryWaveBank ); } CloseHandle( hMapFile ); // pbInMemoryWaveBank maintains a handle on the file so close this unneeded handle } } CloseHandle( hFile ); // pbInMemoryWaveBank maintains a handle on the file so close this unneeded handle } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting //----------------------------------------------------------------------------------------- // Create a streaming XACT wave bank file. // Take note of the following: // 1) This wave bank in the XACT project file must marked as a streaming wave bank // This is set inside the XACT authoring tool) // 2) Use FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING flags when opening the file // 3) To use cues that reference this streaming wave bank, you must wait for the // wave bank to prepared first or the playing the cue will fail //----------------------------------------------------------------------------------------- hr = E_FAIL; // assume failure audioState.hStreamingWaveBankFile = CreateFile( L"Stream.xwb", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); if( audioState.hStreamingWaveBankFile != INVALID_HANDLE_VALUE ) { XACT_WAVEBANK_STREAMING_PARAMETERS wsParams; ZeroMemory( &wsParams, sizeof( XACT_WAVEBANK_STREAMING_PARAMETERS ) ); wsParams.file = audioState.hStreamingWaveBankFile; 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; hr = audioState.pEngine->CreateStreamingWaveBank( &wsParams, &audioState.pStreamingWaveBank ); } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting // Read and register the sound bank file with XACT. Do not use memory mapped file IO because the // memory needs to be read/write and the working set of sound banks are small. hr = E_FAIL; // assume failure hFile = CreateFile( L"Sounds.xsb", 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 audioState.pbSoundBank = new BYTE[dwFileSize]; if( audioState.pbSoundBank ) { if( 0 != ReadFile( hFile, audioState.pbSoundBank, dwFileSize, reinterpret_cast<LPDWORD>(&dwBytesRead), NULL ) ) { hr = audioState.pEngine->CreateSoundBank( audioState.pbSoundBank, dwFileSize, 0, 0, &audioState.pSoundBank ); } } } CloseHandle( hFile ); } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting // Get the sound cue index from the sound bank // // Note that if the cue does not exist in the sound bank, the index will be XACTINDEX_INVALID // however this is ok especially during development. The Play or Prepare call will just fail. audioState.iSE = audioState.pSoundBank->GetCueIndex( "se" ); for( int i = 0; i < 2; i++ ) { for( int j = 0; j < 2; j++) { CHAR sz[256]; StringCchPrintfA( sz, 256, "stage%d-%d", i + 1, j + 1 ); audioState.iStage[i][j] = audioState.pSoundBank->GetCueIndex( sz ); } } for( int i = 0; i < 2; i++ ) { CHAR sz[256]; StringCchPrintfA( sz, 256, "battle%d", i + 1 ); audioState.iBattle[i] = audioState.pSoundBank->GetCueIndex( sz ); } audioState.iOpening = audioState.pSoundBank->GetCueIndex( "opening" ); audioState.iBoss = audioState.pSoundBank->GetCueIndex( "boss" ); audioState.iCeiling = audioState.pSoundBank->GetCueIndex( "ceiling" ); audioState.iAttack = audioState.pSoundBank->GetCueIndex( "attack" ); audioState.iBomb = audioState.pSoundBank->GetCueIndex( "bomb" ); audioState.iHit = audioState.pSoundBank->GetCueIndex( "hit" ); audioState.iPuzzleClear = audioState.pSoundBank->GetCueIndex( "puzzleclear" ); audioState.iWalk = audioState.pSoundBank->GetCueIndex( "walk" ); audioState.iGlobalCategory = audioState.pEngine->GetCategory( "Global" ); audioState.iMusicCategory = audioState.pEngine->GetCategory( "Music" ); audioState.iBGMCategory = audioState.pEngine->GetCategory( "BGM" ); return S_OK; }
//----------------------------------------------------------------------------------------- // This function does the following steps: // // 1. Initialize XACT by calling pEngine->Initialize // 2. Register for the XACT notification desired // 3. Create the in memory XACT wave bank(s) you want to use // 4. Create the streaming XACT wave bank(s) you want to use // 5. Create the XACT sound bank(s) you want to use // 6. Store indices to the XACT cue(s) your game uses //----------------------------------------------------------------------------------------- HRESULT PrepareXACT() { HRESULT hr; WCHAR str[MAX_PATH]; HANDLE hFile; DWORD dwFileSize; DWORD dwBytesRead; HANDLE hMapFile; // Clear struct ZeroMemory( &g_audioState, sizeof( AUDIO_STATE ) ); InitializeCriticalSection( &g_audioState.cs ); hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); // COINIT_APARTMENTTHREADED will work too if( SUCCEEDED( hr ) ) { // Switch to auditioning mode based on command line. Change if desired bool bAuditionMode = DoesCommandLineContainAuditionSwitch(); bool bDebugMode = false; DWORD dwCreationFlags = 0; if( bAuditionMode ) dwCreationFlags |= XACT_FLAG_API_AUDITION_MODE; if( bDebugMode ) dwCreationFlags |= XACT_FLAG_API_DEBUG_MODE; hr = XACT3CreateEngine( dwCreationFlags, &g_audioState.pEngine ); } if( FAILED( hr ) || g_audioState.pEngine == NULL ) return E_FAIL; // Initialize & create the XACT runtime XACT_RUNTIME_PARAMETERS xrParams = {0}; xrParams.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT; xrParams.fnNotificationCallback = XACTNotificationCallback; hr = g_audioState.pEngine->Initialize( &xrParams ); if( FAILED( hr ) ) return hr; //----------------------------------------------------------------------------------------- // Register for XACT notifications //----------------------------------------------------------------------------------------- // The "wave bank prepared" notification will let the app know when it is save to use // play cues that reference streaming wave data. XACT_NOTIFICATION_DESCRIPTION desc = {0}; desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED; g_audioState.pEngine->RegisterNotification( &desc ); // The "sound bank destroyed" notification will let the app know when it is save to use // play cues that reference streaming wave data. desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED; g_audioState.pEngine->RegisterNotification( &desc ); // The "cue stop" notification will let the app know when it a song stops so a new one // can be played desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_CUESTOP; desc.cueIndex = XACTINDEX_INVALID; g_audioState.pEngine->RegisterNotification( &desc ); // The "cue prepared" notification will let the app know when it a a cue that uses // streaming data has been prepared so it is ready to be used for zero latency streaming desc.flags = XACT_FLAG_NOTIFICATION_PERSIST; desc.type = XACTNOTIFICATIONTYPE_CUEPREPARED; desc.cueIndex = XACTINDEX_INVALID; g_audioState.pEngine->RegisterNotification( &desc ); if( FAILED( hr = FindMediaFileCch( str, MAX_PATH, L"InMemoryWaveBank.xwb" ) ) ) return hr; // Create an "in memory" XACT wave bank file using memory mapped file IO hr = E_FAIL; // assume failure hFile = CreateFile( str, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if( hFile != INVALID_HANDLE_VALUE ) { dwFileSize = GetFileSize( hFile, NULL ); if( dwFileSize != -1 ) { hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL ); if( hMapFile ) { g_audioState.pbInMemoryWaveBank = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 ); if( g_audioState.pbInMemoryWaveBank ) { hr = g_audioState.pEngine->CreateInMemoryWaveBank( g_audioState.pbInMemoryWaveBank, dwFileSize, 0, 0, &g_audioState.pInMemoryWaveBank ); } CloseHandle( hMapFile ); // pbInMemoryWaveBank maintains a handle on the file so close this unneeded handle } } CloseHandle( hFile ); // pbInMemoryWaveBank maintains a handle on the file so close this unneeded handle } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting //----------------------------------------------------------------------------------------- // Create a streaming XACT wave bank file. // Take note of the following: // 1) This wave bank in the XACT project file must marked as a streaming wave bank // This is set inside the XACT authoring tool) // 2) Use FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING flags when opening the file // 3) To use cues that reference this streaming wave bank, you must wait for the // wave bank to prepared first or the playing the cue will fail //----------------------------------------------------------------------------------------- if( FAILED( hr = FindMediaFileCch( str, MAX_PATH, L"StreamingWaveBank.xwb" ) ) ) return hr; hr = E_FAIL; // assume failure g_audioState.hStreamingWaveBankFile = CreateFile( str, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); if( g_audioState.hStreamingWaveBankFile != INVALID_HANDLE_VALUE ) { XACT_WAVEBANK_STREAMING_PARAMETERS wsParams; ZeroMemory( &wsParams, sizeof( XACT_WAVEBANK_STREAMING_PARAMETERS ) ); wsParams.file = g_audioState.hStreamingWaveBankFile; 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; hr = g_audioState.pEngine->CreateStreamingWaveBank( &wsParams, &g_audioState.pStreamingWaveBank ); } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting // Create the XACT sound bank file with using memory mapped file IO if( FAILED( hr = FindMediaFileCch( str, MAX_PATH, L"sounds.xsb" ) ) ) return hr; hr = E_FAIL; // assume failure hFile = CreateFile( 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 g_audioState.pbSoundBank = new BYTE[dwFileSize]; if( g_audioState.pbSoundBank ) { if( 0 != ReadFile( hFile, g_audioState.pbSoundBank, dwFileSize, &dwBytesRead, NULL ) ) { hr = g_audioState.pEngine->CreateSoundBank( g_audioState.pbSoundBank, dwFileSize, 0, 0, &g_audioState.pSoundBank ); } } } CloseHandle( hFile ); // pbInMemoryWaveBank maintains a handle on the file so close this unneeded handle } if( FAILED( hr ) ) return E_FAIL; // CleanupXACT() will cleanup state before exiting // Get the cue indices from the sound bank g_audioState.iZap = g_audioState.pSoundBank->GetCueIndex( "zap" ); g_audioState.iRev = g_audioState.pSoundBank->GetCueIndex( "rev" ); for( int i = 0; i < 3; i++ ) { CHAR sz[256]; StringCchPrintfA( sz, 256, "song%d", i + 1 ); g_audioState.iSong[i] = g_audioState.pSoundBank->GetCueIndex( sz ); } return S_OK; }