Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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);
share|improve this question

1 Answer 1

up vote 1 down vote accepted

The call to SubmitSourceBuffer will attempt to convert the managed AudioBuffer to its native representation and then invoke the native function. Assuming the exception is not thrown from a callback into your own code, the likely place for this error to come from is the call to Utilities::ReadStream that occurs with AudioBuffer's ToUnmanaged function.

The conversion process is attempting to read buffer.AudioBytes worth of data from buffer.AudioData, which is of type System.IO.Stream.

You probably need to set buffer.AudioData.Position = 0 prior to calling SubmitSourceBuffer.

share|improve this answer
    
Thank you so much! I don't know how I didn't think of that... –  Boreal Jun 7 '12 at 1:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.