diff --git a/src/Audio/AudioDevice.cs b/src/Audio/AudioDevice.cs index 2c39408..f198920 100644 --- a/src/Audio/AudioDevice.cs +++ b/src/Audio/AudioDevice.cs @@ -159,6 +159,8 @@ namespace MoonWorks.Audio previousTickTime = TickStopwatch.Elapsed.Ticks; float elapsedSeconds = (float) tickDelta / System.TimeSpan.TicksPerSecond; + // TODO: call an Update on all active voices + for (var i = autoUpdateStreamingSoundReferences.Count - 1; i >= 0; i -= 1) { var streamingSound = autoUpdateStreamingSoundReferences[i]; @@ -206,6 +208,8 @@ namespace MoonWorks.Audio FAudio.FAudio_CommitChanges(Handle, syncGroup); } + // TODO: is pooling SourceVoices generically a good idea? there are a lot of different kinds + /// /// Obtains an appropriate source voice from the voice pool. /// diff --git a/src/Audio/SourceVoice.cs b/src/Audio/SourceVoice.cs index 696b884..753abb4 100644 --- a/src/Audio/SourceVoice.cs +++ b/src/Audio/SourceVoice.cs @@ -160,11 +160,6 @@ namespace MoonWorks.Audio ); } - public void Submit(StreamingSound streamingSound) - { - - } - /// /// Designates that this source voice will return to the voice pool once all its buffers are exhausted. /// diff --git a/src/Audio/StreamingSound.cs b/src/Audio/StreamingSound.cs index 280f37a..f38e64e 100644 --- a/src/Audio/StreamingSound.cs +++ b/src/Audio/StreamingSound.cs @@ -165,7 +165,7 @@ namespace MoonWorks.Audio queuedBufferCount = 0; } - protected unsafe void AddBuffer() + public unsafe void AddBuffer() { var buffer = buffers[nextBufferIndex]; nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT; diff --git a/src/Audio/StreamingVoice.cs b/src/Audio/StreamingVoice.cs new file mode 100644 index 0000000..2b1ae05 --- /dev/null +++ b/src/Audio/StreamingVoice.cs @@ -0,0 +1,92 @@ +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(); + } +}