This topic discusses the Microsoft Cross-Platform Audio Creation Tool (XACT) from the programmer's perspective.
The XACT APIs drive the low-level audio software engine functions to render sound. This is intended to be transparent to both the designer and the programmer.
In most cases, game title developers will find that the XACT and its functions provide a simple and elegant solution for their audio needs. However, developers who prefer to manage their audio data at a lower level will find no obstacle to accessing the functions of their audio engine directly.
Figure 1. Relationship of XACT to the audio engine
The game programmer will receive from the audio designer the files that result from the XACT build process. It is then the responsibility of the programmer to initialize the XACT, load the data when it is needed within the game and trigger cues at the appropriate junctures as gameplay progresses. The programmer is also responsible for allocation and management of the memory resources needed by the XACT.
The following sections outline the most common procedures for integrating game audio resources with XACT.
To start the XACT audio engine, you must first call IXACTEngine::Initialize. As the following example demonstrates, you may invoke this function with an empty set of initialization parameters, which indicates that default settings are desired. This function needs to be called only once at the beginning of your application.
XACT_RUNTIME_PARAMETERS Params; memset(&Params, 0, sizeof(Params)); pXACTEngine->Initialize(&Params);
The application must continuously call IXACTEngine::DoWork. This function is typically called during the main title loop that executes once per frame and drives the graphics rendering for the game. For more information, see IXACTEngine::DoWork.
bool fDone = false; do { // update all the game action Update(); // render graphic elements to the screen Render(); // drive audio every frame pXACTEngine->DoWork(); Sleep(1); } while (!fDone)
The game title must allocate the memory for the wave and sound bank data, then read the files into that memory. The program must then instantiate the wave and sound bank objects that will control that data. Once these banks are no longer needed, the program is responsible for destroying the objects and freeing the memory.
These procedures will typically occur at the beginning and end of a scene in the game.
The following example illustrates creation of an in-memory wave bank. For streaming wave banks, see XACT Streaming Wave Banks.
IXACTWaveBank * pWaveBank; IXACTSoundBank * pSoundBank; // Load Wave Bank file from media into memory, pointed to by pbWaveBank, dwWaveBankSize // Load Sound Bank file from media into memory, pointed to by pbSoundBank, dwSoundBankSize // Ready to create engines for wave banks and sound banks if ( SUCCEEDED( pXACTEngine->CreateInMemoryWaveBank( pbWaveBank, dwWaveBankSize, 0, 0, &pWaveBank ) ) ) { if ( SUCCEEDED( pXACTEngine->CreateSoundBank( pbSoundBank, dwSoundBankSize, 0, 0, &pSoundBank ) ) ) { // Ready to do work } }
Cues in the sound bank are referenced by index. However, the method IXACTSoundBank::GetCueIndex is provided so that the program can look up the cue index from the "friendly name," or text string given the cue by the audio designer (if friendly names were included when built).
In the following example, note the use of GetState and Release to wait until the cue has completed playing before freeing its resources. For further information, see Managing XACT Resources and Notifications
XACTINDEX XCueIndex_gs1; DWORD dwCueState; // Look up the cue index from the friendly name XCueIndex_gs1 = pSoundBank->GetCueIndex("Gunshot1"); // Trigger the cue hr = pSoundBank->Play(XCueIndex_gs1, 0, &pXCue_gs1); // Now wait for the cue to finish playing bool fDone = false; while (!fDone) { if ( SUCCEEDED (pXCue_gs1->GetState(&dwCueState) ) { if (dwCueState & XACT_CUESTATE_STOPPED) { fDone = true; continue; } pXACTEngine->DoWork(); Sleep(1); } } // Since we asked for the cue object pointer, we need to RELEASE it when done pXCue_gs1->Release();