Why do I get an exception when playing multiple sound instances?

Posted by Boreal on Game Development See other posts from Game Development or by Boreal
Published on 2012-06-05T20:30:13Z Indexed on 2012/06/06 22:48 UTC
Read the original article Hit count: 234

Filed under:
|
|

Right now, I'm adding a rudimentary sound engine to my game. So far, I am able to load in a WAV file and play it once, then free up the memory when I close the game. However, the game crashes with a nice ArgumentOutOfBoundsException when I try to play another sound instance.

Specified argument was out of the range of valid values. Parameter name: readLength

I'm following this tutorial pretty much exactly, but I still keep getting the aforementioned error. Here's my sound-related code.

/// <summary>
/// Manages all sound instances.
/// </summary>
public static class Audio
{
    static XAudio2 device;
    static MasteringVoice master;

    static List<SoundInstance> instances;

    /// <summary>
    /// The XAudio2 device.
    /// </summary>
    internal static XAudio2 Device
    {
        get { return device; }
    }

    /// <summary>
    /// Initializes the audio device and master track.
    /// </summary>
    internal static void Initialize()
    {
        device = new XAudio2();
        master = new MasteringVoice(device);

        instances = new List<SoundInstance>();
    }

    /// <summary>
    /// Releases all XA2 resources.
    /// </summary>
    internal static void Shutdown()
    {
        foreach(SoundInstance i in instances)
            i.Dispose();
        master.Dispose();
        device.Dispose();
    }

    /// <summary>
    /// Registers a sound instance with the system.
    /// </summary>
    /// <param name="instance">Sound instance</param>
    internal static void AddInstance(SoundInstance instance)
    {
        instances.Add(instance);
    }

    /// <summary>
    /// Disposes any sound instance that has stopped playing.
    /// </summary>
    internal static void Update()
    {
        List<SoundInstance> temp = new List<SoundInstance>(instances);
        foreach(SoundInstance i in temp)
            if(!i.Playing)
            {
                i.Dispose();
                instances.Remove(i);
            }
    }
}

/// <summary>
/// Loads sounds from various files.
/// </summary>
internal class SoundLoader
{
    /// <summary>
    /// Loads a .wav sound file.
    /// </summary>
    /// <param name="format">The decoded format will be sent here</param>
    /// <param name="buffer">The data will be sent here</param>
    /// <param name="soundName">The path to the WAV file</param>
    internal static void LoadWAV(out WaveFormat format, out AudioBuffer buffer, string soundName)
    {
        WaveStream wave = new WaveStream(soundName);

        format = wave.Format;

        buffer = new AudioBuffer();
        buffer.AudioData = wave;
        buffer.AudioBytes = (int)wave.Length;
        buffer.Flags = BufferFlags.EndOfStream;
    }
}

/// <summary>
/// Manages the data for a single sound.
/// </summary>
public class Sound : IAsset
{
    WaveFormat format;
    AudioBuffer buffer;

    /// <summary>
    /// Loads a sound from a file.
    /// </summary>
    /// <param name="soundName">The path to the sound file</param>
    /// <returns>Whether the sound loaded successfully</returns>
    public bool Load(string soundName)
    {
        if(soundName.EndsWith(".wav"))
            SoundLoader.LoadWAV(out format, out buffer, soundName);
        else
            return false;

        return true;
    }

    /// <summary>
    /// Plays the sound.
    /// </summary>
    public void Play()
    {
        Audio.AddInstance(new SoundInstance(format, buffer));
    }

    /// <summary>
    /// Unloads the sound from memory.
    /// </summary>
    public void Unload()
    {
        buffer.Dispose();
    }
}

/// <summary>
/// Manages a single sound instance.
/// </summary>
public class SoundInstance
{
    SourceVoice source;
    bool playing;

    /// <summary>
    /// Whether the sound is currently playing.
    /// </summary>
    public bool Playing
    {
        get { return playing; }
    }

    /// <summary>
    /// Starts a new instance of a sound.
    /// </summary>
    /// <param name="format">Format of the sound</param>
    /// <param name="buffer">Buffer holding sound data</param>
    internal SoundInstance(WaveFormat format, AudioBuffer buffer)
    {
        source = new SourceVoice(Audio.Device, format);
        source.BufferEnd += (s, e) => playing = false;

        source.Start();
        source.SubmitSourceBuffer(buffer); // THIS IS WHERE THE EXCEPTION IS THROWN
        playing = true;
    }

    /// <summary>
    /// Releases memory used by the instance.
    /// </summary>
    internal void Dispose()
    {
        source.Dispose();
    }
}

The exception occurs on line 156 when I am playing the sound:

source.SubmitSourceBuffer(buffer);

© Game Development or respective owner

Related posts about c#

Related posts about slimdx