using System; namespace MoonWorks.Audio { public abstract class StreamingVoice : SourceVoice { private const int BUFFER_COUNT = 3; private readonly IntPtr[] buffers; private int nextBufferIndex = 0; private uint BufferSize; public bool Loop { get; set; } public StreamingVoice(AudioDevice device, Format format, uint bufferSize) : base(device, format) { BufferSize = bufferSize; } internal unsafe void Update() { lock (StateLock) { if (!IsDisposed) { if (State != SoundState.Playing) { return; } QueueBuffers(); } } } protected void QueueBuffers() { var buffersQueued = BuffersQueued; for (int i = 0; i < BUFFER_COUNT - buffersQueued; i += 1) { AddBuffer(); } } protected unsafe void AddBuffer() { var buffer = buffers[nextBufferIndex]; nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT; FillBuffer( (void*) buffer, (int) BufferSize, out int filledLengthInBytes, out bool reachedEnd ); if (filledLengthInBytes > 0) { var buf = new FAudio.FAudioBuffer { AudioBytes = (uint) filledLengthInBytes, pAudioData = buffer, PlayLength = ( (uint) (filledLengthInBytes / Format.Channels / (uint) (Format.BitsPerSample / 8)) ) }; Submit(buf); } if (reachedEnd) { /* We have reached the end of the data, what do we do? */ if (Loop) { SeekStart(); AddBuffer(); } } } protected unsafe abstract void FillBuffer( void* buffer, int bufferLengthInBytes, /* in bytes */ out int filledLengthInBytes, /* in bytes */ out bool reachedEnd ); protected abstract void SeekStart(); } }