private void DisposeWave()
        {
            lock (mutex)
            {
                if (dataStream != null)
                {
                    dataStream.Dispose();
                    dataStream = null;
                }

                if (audioBuffer != null)
                {
                    audioBuffer.Dispose();
                    audioBuffer = null;
                }

                if (sourceVoice != null)
                {
                    if (currentStream != null)
                    {
                        sourceVoice.BufferEnd -= bufferEndCallback;
                    }
                    sourceVoice.Stop();
                    sourceVoice.FlushSourceBuffers();
                    sourceVoice.Dispose();
                    sourceVoice = null;
                }

                current       = null;
                currentStream = null;
            }
        }
        private bool FillBuffer(int bufferIdx, IPlayableStream stream)
        {
            AudioBuffer buffer = this.streamBuffers[bufferIdx];

            byte[] byteBuffer = this.byteBuffers[bufferIdx];

            bool isDone;
            var  dataRead = stream.GetWaveData(byteBuffer, StreamingBufferSize);

            if (dataRead > 0)
            {
                streamBuffered   += dataRead;
                isDone            = (streamBuffered >= streamLength);
                buffer.Flags      = isDone ? BufferFlags.EndOfStream : BufferFlags.None;
                buffer.AudioBytes = dataRead;
                buffer.Context    = (IntPtr)bufferIdx;
                sourceVoice.SubmitSourceBuffer(buffer);
                bufferStatus.Set(bufferIdx, true);
            }
            else
            {
                isDone = true;
            }

            return(isDone);
        }
        private void DecoderThread(object wave)
        {
            IPlayableStream stream = wave as IPlayableStream;

            lock (mutex)
            {
                while (true)
                {
                    if (current != wave)
                    {
                        return;
                    }

                    // Fill any unfilled buffers
                    for (var i = 0; i < bufferStatus.Count; i++)
                    {
                        if (bufferStatus.Get(i) == false)
                        {
                            bool isDone = FillBuffer(i, stream);
                            if (isDone)
                            {
                                return;
                            }
                        }
                    }

                    // Wait to be signalled that a buffer is empty
                    System.Threading.Monitor.Wait(mutex);
                }
            }
        }
        public void Play(IPlayable wave)
        {
            lock (mutex)
            {
                if (wave == current)
                {
                    if (isPaused)
                    {
                        sourceVoice.Start();
                        isPaused = false;
                        return;
                    }
                }

                DisposeWave();
                xaudio.CommitChanges();
                isPaused      = false;
                current       = wave;
                currentStream = wave as IPlayableStream;

                if (decodeThread != null)
                {
                    System.Threading.Monitor.Pulse(mutex);
                    decodeThread = null;
                }

                if (currentStream == null)
                {
                    sourceVoice = new SourceVoice(xaudio, wave.WaveFormat);
                    dataStream  = new SlimDX.DataStream(wave.WaveData, true, false);

                    audioBuffer            = new SlimDX.XAudio2.AudioBuffer();
                    audioBuffer.AudioData  = dataStream;
                    audioBuffer.AudioBytes = wave.WaveData.Length;
                    audioBuffer.Flags      = BufferFlags.EndOfStream;

                    sourceVoice.SubmitSourceBuffer(audioBuffer);
                    sourceVoice.Start();
                }
                else
                {
                    streamLength   = currentStream.StreamLength;
                    streamBuffered = 0;

                    sourceVoice            = new SourceVoice(xaudio, wave.WaveFormat);
                    sourceVoice.BufferEnd += bufferEndCallback;

                    // Fill buffers initially
                    bool isDone = false;
                    for (var i = 0; i < NumStreamingBuffers; i++)
                    {
                        isDone = FillBuffer(i, currentStream);
                        if (isDone)
                        {
                            break;
                        }
                    }

                    sourceVoice.Start();
                    if (!isDone)
                    {
                        System.Threading.ParameterizedThreadStart threadProc = DecoderThread;
                        decodeThread      = new System.Threading.Thread(threadProc);
                        decodeThread.Name = "Vorbis Decoder Thread";
                        decodeThread.Start(currentStream);
                    }
                }
            }
        }
        private bool FillBuffer(int bufferIdx, IPlayableStream stream)
        {
            AudioBuffer buffer = this.streamBuffers[bufferIdx];
            byte[] byteBuffer = this.byteBuffers[bufferIdx];

            bool isDone;
            var dataRead = stream.GetWaveData(byteBuffer, StreamingBufferSize);
            if (dataRead > 0)
            {
                streamBuffered += dataRead;
                isDone = (streamBuffered >= streamLength);
                buffer.Flags = isDone ? BufferFlags.EndOfStream : BufferFlags.None;
                buffer.AudioBytes = dataRead;
                buffer.Context = (IntPtr)bufferIdx;
                sourceVoice.SubmitSourceBuffer(buffer);
                bufferStatus.Set(bufferIdx, true);
            } else {
                isDone = true;
            }

            return isDone;
        }
        private void DisposeWave()
        {
            lock (mutex)
            {
                if (dataStream != null)
                {
                    dataStream.Dispose();
                    dataStream = null;
                }

                if (audioBuffer != null)
                {
                    audioBuffer.Dispose();
                    audioBuffer = null;
                }

                if (sourceVoice != null)
                {
                    if (currentStream != null)
                    {
                        sourceVoice.BufferEnd -= bufferEndCallback;
                    }
                    sourceVoice.Stop();
                    sourceVoice.FlushSourceBuffers();
                    sourceVoice.Dispose();
                    sourceVoice = null;
                }

                current = null;
                currentStream = null;
            }
        }
        public void Play(IPlayable wave)
        {
            lock (mutex)
            {
                if (wave == current)
                {
                    if (isPaused)
                    {
                        sourceVoice.Start();
                        isPaused = false;
                        return;
                    }
                }

                DisposeWave();
                xaudio.CommitChanges();
                isPaused = false;
                current = wave;
                currentStream = wave as IPlayableStream;

                if (decodeThread != null)
                {
                    System.Threading.Monitor.Pulse(mutex);
                    decodeThread = null;
                }

                if (currentStream == null)
                {
                    sourceVoice = new SourceVoice(xaudio, wave.WaveFormat);
                    dataStream = new SlimDX.DataStream(wave.WaveData, true, false);

                    audioBuffer = new SlimDX.XAudio2.AudioBuffer();
                    audioBuffer.AudioData = dataStream;
                    audioBuffer.AudioBytes = wave.WaveData.Length;
                    audioBuffer.Flags = BufferFlags.EndOfStream;

                    sourceVoice.SubmitSourceBuffer(audioBuffer);
                    sourceVoice.Start();
                }
                else
                {
                    streamLength = currentStream.StreamLength;
                    streamBuffered = 0;

                    sourceVoice = new SourceVoice(xaudio, wave.WaveFormat);
                    sourceVoice.BufferEnd += bufferEndCallback;

                    // Fill buffers initially
                    bool isDone = false;
                    for (var i = 0; i < NumStreamingBuffers; i++)
                    {
                        isDone = FillBuffer(i, currentStream);
                        if (isDone)
                        {
                            break;
                        }
                    }

                    sourceVoice.Start();
                    if (!isDone)
                    {
                        System.Threading.ParameterizedThreadStart threadProc = DecoderThread;
                        decodeThread = new System.Threading.Thread(threadProc);
                        decodeThread.Name = "Vorbis Decoder Thread";
                        decodeThread.Start(currentStream);
                    }
                }
            }
        }