Programming with DirectX : Sound in DirectX - XACT3 (part 2) - XACT3 Demo

7/6/2011 6:00:11 PM

XACT3 Demo

XACT3 is a great tool that allows developers to focus on game-play rather than on audio technology and hardware. XACT3 is so easy to use that all it takes to get simple sounds up and playing is to invoke the audio by cue name. At the minimum this could translate to a line of code to play a sound once it has been loaded. We recommend that you take the time to open up XACT3 and explore the GUI tool to see what you can do with it. Once you are comfortable using it, you can do a lot with audio in your gaming projects. As you become more advanced in game development audio, you might need to use XAudio2 since it offers a lower level of control than XACT3 does.

The header file for the XACT3 API is <xact3.h> and is part of the DirectX SDK, so no additional setup is necessary to begin coding with XACT. In code you’ll need three objects: a wave bank, a sound bank, and an audio engine.

The wave bank is represented by the DirectX type IXACT3WaveBank, and the sound bank is represented by IXACT3SoundBank. When you load wave and sound bank files, you load their contents into objects of these two types. The audio engine is an object that is created to process and control everything dealing with XACT3. This object is of the type IXACT3Engine. For readers familiar with earlier versions of XACT, the only difference in these names is the addition of the number 3 after XACT (for example, IXACT3Engine instead of the previous IXACTEngine).

In the XACT demo’s main source file these three objects are created and defined in the global section. A structure was created to hold the wave bank and sound bank in one object along with void pointers. The void pointers will be memory mapped data pointing to the file’s data, which we’ll discuss later in this section. The global section from the XACT demo is shown in Listing 1.

Listing 1. The Global Section of the XACT Demo’s Main Source File
struct stXACTAudio
IXACT3WaveBank *m_waveBank;
IXACT3SoundBank *m_soundBank;
void *m_waveBankData;
void *m_soundBankData;

stXACTAudio g_xactSound;
IXACT3Engine *g_soundEngine = NULL;

A few functions are created in the demo to make the setup and loading of XACT3 and the XACT files straightforward. In the first function, called SetupXACT(), the first step is to initialize COM with a call to CoInitializeEx().COM must be initialized to use COM libraries, which include many DirectX SDK libraries like XACT.

The next step is to create the XACT3 audio engine. This is done with a call to XACT3CreateEngine(), and it takes as parameters the creation flags and a pointer to the IXACT3Engine object that will be created by the function. The creation flags can be 0 to specify no additional flags, or they can be XACT_FLAG_API_AUDITION_MODE to create the audio engine in audition mode or XACT_FLAG_API_DEBUG_MODE to specify debug. You can use the logical OR operator to combine the two flags.

The remainder of the SetupXACT() function initializes the audio engine and loads the wave and sound banks. The loading of the wave and sound banks is done in separate functions that will be discussed later. The initialization of the XACT audio engine is done by calling the IXACT3Engine object’s Initialize() function. This function takes runtime parameters that are specified by the XACT_RUNTIME_PARAMETERS structure. This structure can be seen as follows.

DWORD lookAheadTime;
void *pGlobalSettingsBuffer;
DWORD globalSettingsBufferSize;
DWORD globalSettingsFlags;
DWORD globalSettingsAllocAttributes;
PWSTR pRendererID;
IXAudio2 *pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice;

Some of the runtime parameters deal with XAudio2. The SetupXACT() function is shown in Listing 2.

Listing 2. The SetupXACT() Function from the XACT Demo
bool SetupXACT(char *waveBank, char *soundBank)
ZeroMemory(&g_xactSound, sizeof(stXACTAudio));

return false;

return false;

if(g_soundEngine == NULL)
return false;

xparams.lookAheadTime = 250;

return false;

return false;

return false;

return true;

The loading of the wave and sound banks is performed in the LoadWaveBank() and LoadSoundBank() functions defined in the demo’s main source file. To load the file’s data, the demo uses memory-mapped file handling. This is a fast way to load memory data into XACT, and the functions are Win32 functions that are fairly straightforward to understand.

To start, a call to CreateFile() is used to create a file handle. This function takes the file’s name, the access flag that specifies the type of object, the shared flag that specifies how subsequent calls are allowed to access the file while the file handle is still active, security attributes (which are ignored, so they’re not used and can be set to NULL), creation flags, attributes flags, and the template file, which is also not used and therefore can be set to NULL.

The next part of the function retrieves the file size with a call to GetFileSize(), which takes the file handle and a pointer to a variable where the high-order double-word of the file size is returned. The last parameter can be set to NULL, and the return value of the function will return the size of the file.

The next step is to create the file mapping by first calling CreateFileMapping(), which takes as parameters the file’s handle, the optional security attributes, the file protection with the view, the high order of the maximum file size, which can be 0, the low order of the maximum file size, which can be the file size we read before, and the name of the object, which is optional. The next step in the file mapping is to call MapViewOfFile(), which takes the file mapping handle, the access flags, the high and low offsets, and the number of bytes to map. If the number of bytes to map is 0, then the mapping extends to the end of the file.

With a pointer to the mapped file data, the XACT3 audio engine is ready to load its contents. This is done with a call to CreateInMemoryWaveBank() and CreateInMemorySoundBank() to create in-memory banks. Both functions take as parameters void pointers to the mapped file data, the size of the file, a flag that can be 0 or XACT_FLAG_API_CREATE_MANAGEDATA to specify that the data is freed when the wave bank is released (which we must do since we are using mapped data and must unmap it first), memory buffer allocation attributes, and the out pointer address to the bank that will be created. The LoadWaveBank() and LoadSoundBank() functions are shown in Listing 3.

Listing 3. The XACT Demo’s LoadWaveBank() and LoadSoundBank()
bool LoadWaveBank(char *fileName)
HANDLE file = CreateFile(fileName, GENERIC_READ,

return false;
DWORD fileSize = GetFileSize(file, NULL);

if(fileSize == -1)
return false;
HANDLE mapFile = CreateFileMapping(file, NULL, PAGE_READONLY,
0, fileSize, NULL);

return false;

void *ptr = MapViewOfFile(mapFile, FILE_MAP_READ, 0, 0, 0);

return false;

g_xactSound.m_waveBankData = ptr;

fileSize, 0, 0, &g_xactSound.m_waveBank)))
return false;


return true;

bool LoadSoundBank(char *fileName)

g_xactSound.m_soundBankData = ptr;

fileSize, 0, 0, &g_xactSound.m_soundBank)))
return false;


return true;

The last function in the demo is the main() function. In this function XACT is set up, and the wave and sound banks are loaded before the audio is played. To play the sound a sound cue is obtained by calling GetCueIndex() on the sound bank object. This function takes as a parameter the name of the sound cue, which was specified when you created the cue in the XACT GUI tool, and it returns the index of the sound as an XACTINDEX object.

The sound itself is played by calling the sound bank’s Play() function. The Play() function takes as parameters the cue index as an XACTINDEX variable, playback flags, offset start time in milliseconds, and, optionally, a pointer to the address of an IXACTCue object that will be returned by this function.

Alternatively, you can create an IXACTCue object and obtain a cue using that. Therefore, to play a sound you just call Play() on theIXACTCue object. To stop it you call Stop(), and so on.

XACT3 requires frequent updates to the audio engine to work properly. This means that in the demo we need to specify a loop that keeps calling DoWork() often enough for the audio to play. To accomplish this the XACT demo calls the audio engine’s DoWork() function inside a loop. Once the sound has finished playing, the loop breaks, and the application proceeds to exit. To determine if the sound is playing, we get the audio state of the sound bank by calling GetState(), which returns an unsigned long variable representing the state. We can then test this state for the flag XACT_CUESTATE_PLAYING to see if the sound bank is playing audio. When it stops playing audio, the loop terminates, so be sure that inside the XACT3 GUI tool you don’t specify any sounds to loop infinitely for this demo.

The remainder of the main() function frees all resources and quits. This means the audio engine must be released by first calling the Shutdown() function of the object and the object’s Release() function to free it. It also means we must call CoUninitialize() to uninitialize COM, and we must call UnmapViewOfFile() to unmap the file data that we obtained when we loaded the wave and sound banks. The main() function from the XACT demo is shown in Listing 4.

Listing 4. The XACT Demo’s main() Function
int main(int args, char* argc[])
cout << "XACT Demo: Playing clip.wav" << endl << endl;
cout << "Demo will end when the sound is done." << endl << endl;

if(!SetupXACT("Win/Wave Bank.xwb", "Win/Sound Bank.xsb"))
return 0;
XACTINDEX g_clipCue = g_xactSound.m_soundBank->GetCueIndex(

unsigned long state = 0;


g_xactSound.m_soundBank->Play(g_clipCue, 0, 0, NULL);

} while(state && XACT_CUESTATE_PLAYING);
  •  iPhone 3D Programming : Image-Processing Example: Bloom
  •  iPhone 3D Programming : Anisotropic Filtering: Textures on Steroids
  •  iPhone 3D Programming : Reflections with Cube Maps
  •  Silverlight Recipes : Networking and Web Service Integration - Accessing Resources over HTTP
  •  Silverlight Recipes : Networking and Web Service Integration - Using JSON Serialization over HTTP
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Using Resources in a Game (part 4) - Filling the Screen
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Using Resources in a Game (part 3) - Sprite Drawing with SpriteBatch
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Using Resources in a Game (part 2) - Positioning Your Game Sprite on the Screen
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Using Resources in a Game (part 1) - Loading XNA Textures
  •  iPhone 3D Programming : Holodeck Sample (part 5) - Overlaying with a Live Camera Image
    PS4 game trailer XBox One game trailer
    WiiU game trailer 3ds game trailer
    Top 10 Video Game
    -   Minecraft Mods - MAD PACK #10 'NETHER DOOM!' with Vikkstar & Pete (Minecraft Mod - Mad Pack 2)
    -   Minecraft Mods - MAD PACK #9 'KING SLIME!' with Vikkstar & Pete (Minecraft Mod - Mad Pack 2)
    -   Minecraft Mods - MAD PACK #2 'LAVA LOBBERS!' with Vikkstar & Pete (Minecraft Mod - Mad Pack 2)
    -   Minecraft Mods - MAD PACK #3 'OBSIDIAN LONGSWORD!' with Vikkstar & Pete (Minecraft Mod - Mad Pack 2)
    -   Total War: Warhammer [PC] Demigryph Trailer
    -   Minecraft | MINIONS MOVIE MOD! (Despicable Me, Minions Movie)
    -   Minecraft | Crazy Craft 3.0 - Ep 3! "TITANS ATTACK"
    -   Minecraft | Crazy Craft 3.0 - Ep 2! "THIEVING FROM THE CRAZIES"
    -   Minecraft | MORPH HIDE AND SEEK - Minions Despicable Me Mod
    -   Minecraft | Dream Craft - Star Wars Modded Survival Ep 92 "IS JOE DEAD?!"
    -   Minecraft | Dream Craft - Star Wars Modded Survival Ep 93 "JEDI STRIKE BACK"
    -   Minecraft | Dream Craft - Star Wars Modded Survival Ep 94 "TATOOINE PLANET DESTRUCTION"
    -   Minecraft | Dream Craft - Star Wars Modded Survival Ep 95 "TATOOINE CAPTIVES"
    -   Hitman [PS4/XOne/PC] Alpha Gameplay Trailer
    -   Satellite Reign [PC] Release Date Trailer
    Game of War | Kate Upton Commercial