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();
+ }
+}