diff --git a/src/Audio/StreamingSound.cs b/src/Audio/StreamingSound.cs index 1bb06d3..eac63fd 100644 --- a/src/Audio/StreamingSound.cs +++ b/src/Audio/StreamingSound.cs @@ -1,23 +1,22 @@ using System; -using System.Collections.Generic; using System.Runtime.InteropServices; namespace MoonWorks.Audio { /// /// For streaming long playback. - /// Can be extended to support custom decoders. + /// Must be extended with a decoder routine called by FillBuffer. + /// See StreamingSoundOgg for an example. /// public abstract class StreamingSound : SoundInstance { - private readonly List queuedBuffers = new List(); - private const int MINIMUM_BUFFER_CHECK = 3; - - private int PendingBufferCount => queuedBuffers.Count; - + private const int BUFFER_COUNT = 3; + private readonly IntPtr[] buffers; + private int nextBufferIndex = 0; + private uint queuedBufferCount = 0; public abstract int BUFFER_SIZE { get; } - public StreamingSound( + public unsafe StreamingSound( AudioDevice device, ushort formatTag, ushort bitsPerSample, @@ -27,6 +26,12 @@ namespace MoonWorks.Audio ) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond) { device.AddDynamicSoundInstance(this); + + buffers = new IntPtr[BUFFER_COUNT]; + for (int i = 0; i < BUFFER_COUNT; i += 1) + { + buffers[i] = (IntPtr) NativeMemory.Alloc((nuint) BUFFER_SIZE); + } } public override void Play() @@ -78,25 +83,14 @@ namespace MoonWorks.Audio FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED ); - while (PendingBufferCount > state.BuffersQueued) - { - lock (queuedBuffers) - { - NativeMemory.Free((void*) queuedBuffers[0]); - queuedBuffers.RemoveAt(0); - } - } + queuedBufferCount = state.BuffersQueued; QueueBuffers(); } protected void QueueBuffers() { - for ( - int i = MINIMUM_BUFFER_CHECK - PendingBufferCount; - i > 0; - i -= 1 - ) + for (int i = 0; i < BUFFER_COUNT - queuedBufferCount; i += 1) { AddBuffer(); } @@ -104,51 +98,40 @@ namespace MoonWorks.Audio protected unsafe void ClearBuffers() { - lock (queuedBuffers) - { - foreach (IntPtr buf in queuedBuffers) - { - NativeMemory.Free((void*) buf); - } - queuedBuffers.Clear(); - } + nextBufferIndex = 0; + queuedBufferCount = 0; } protected unsafe void AddBuffer() { - void* buffer = NativeMemory.Alloc((nuint) BUFFER_SIZE); + var buffer = buffers[nextBufferIndex]; + nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT; FillBuffer( - buffer, + (void*) buffer, BUFFER_SIZE, out int filledLengthInBytes, out bool reachedEnd ); - lock (queuedBuffers) + FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer { - queuedBuffers.Add((IntPtr) buffer); - if (State != SoundState.Stopped) - { - FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer - { - AudioBytes = (uint) filledLengthInBytes, - pAudioData = (IntPtr) buffer, - PlayLength = ( - (uint) (filledLengthInBytes / - Format.nChannels / - (uint) (Format.wBitsPerSample / 8)) - ) - }; + AudioBytes = (uint) filledLengthInBytes, + pAudioData = (IntPtr) buffer, + PlayLength = ( + (uint) (filledLengthInBytes / + Format.nChannels / + (uint) (Format.wBitsPerSample / 8)) + ) + }; - FAudio.FAudioSourceVoice_SubmitSourceBuffer( - Handle, - ref buf, - IntPtr.Zero - ); - } - } + FAudio.FAudioSourceVoice_SubmitSourceBuffer( + Handle, + ref buf, + IntPtr.Zero + ); + queuedBufferCount += 1; /* We have reached the end of the file, what do we do? */ if (reachedEnd) @@ -169,9 +152,14 @@ namespace MoonWorks.Audio out bool reachedEnd ); - protected override void Destroy() + protected unsafe override void Destroy() { StopImmediate(); + + for (int i = 0; i < BUFFER_COUNT; i += 1) + { + NativeMemory.Free((void*) buffers[i]); + } } } }