Two common XACT gotchas

Originally posted to Shawn Hargreaves Blog on MSDN, Monday, February 5, 2007

Sounds are good. I particularly like the sound of Sibelius's later symphonies, although Stravinsky can be pretty incredible at times too.

If the sounds in your game are not good, make sure you are calling AudioEngine.Update at regular intervals. Your main game Update method is a good place to put this.

If you forget to call AudioEngine.Update, everything may appear ok for a surprising amount of time, but eventually the sky will come crashing down around you, foreshadowing the apocalyptic finale of Gotterdammerung.

Another common problem is leaking Cue instances:

    Cue cue = soundBank.GetCue("BrayOfTheCamel");

    cue.Play();

Using the above code you may notice the sound cutting out at unpredictable intervals. The resulting chopped up cacophony can be interesting if you are trying to twist the dance floor into an Aphex Twin beat, but most likely will not be what you wanted.

Your sounds are cutting out because when you create an XNA cue instance we attach that to an underlying XACT sound. When the cue is disposed the underlying sound will be destroyed as well. If you create a cue instance, start it playing, and then let go of all references to it, the instance becomes garbage so at some indeterminate future time the CLR garbage collector will reclaim it, at which point the sound will cut out.

The easy fix is to use an alternative method for playing your sounds:

    soundBank.PlayCue("SingingDromedary");

Because this never creates a cue instance there is nothing for the garbage collector to worry about, so the sound will always play to the end with no further hassle.

Of course that second method is no good if you need to manually control your sound, for instance to modify its pitch or volume, or to control exactly when it stops. In such cases you should hang on to your cue instance for as long as the sound is playing, thus making sure the garbage collector will leave it alone.

This quirk of how cues interact with garbage collection can actually be a useful way of measuring how often your game is triggering the collector. If you make a sound that loops forever, you can have your game loop trigger this every few seconds using the GetCue / Play combination, then deliberately discard all references to the cue you just created. Now listen until the sound cuts out, and you can literately hear the next time the garbage collector runs!

Blog index   -   Back to my homepage