start reimplementing streaming audio on voice API

pull/50/head
cosmonaut 2023-08-01 19:36:07 -07:00
parent c2cb83f93f
commit a0408a863c
4 changed files with 97 additions and 6 deletions

View File

@ -159,6 +159,8 @@ namespace MoonWorks.Audio
previousTickTime = TickStopwatch.Elapsed.Ticks; previousTickTime = TickStopwatch.Elapsed.Ticks;
float elapsedSeconds = (float) tickDelta / System.TimeSpan.TicksPerSecond; 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) for (var i = autoUpdateStreamingSoundReferences.Count - 1; i >= 0; i -= 1)
{ {
var streamingSound = autoUpdateStreamingSoundReferences[i]; var streamingSound = autoUpdateStreamingSoundReferences[i];
@ -206,6 +208,8 @@ namespace MoonWorks.Audio
FAudio.FAudio_CommitChanges(Handle, syncGroup); FAudio.FAudio_CommitChanges(Handle, syncGroup);
} }
// TODO: is pooling SourceVoices generically a good idea? there are a lot of different kinds
/// <summary> /// <summary>
/// Obtains an appropriate source voice from the voice pool. /// Obtains an appropriate source voice from the voice pool.
/// </summary> /// </summary>

View File

@ -160,11 +160,6 @@ namespace MoonWorks.Audio
); );
} }
public void Submit(StreamingSound streamingSound)
{
}
/// <summary> /// <summary>
/// Designates that this source voice will return to the voice pool once all its buffers are exhausted. /// Designates that this source voice will return to the voice pool once all its buffers are exhausted.
/// </summary> /// </summary>

View File

@ -165,7 +165,7 @@ namespace MoonWorks.Audio
queuedBufferCount = 0; queuedBufferCount = 0;
} }
protected unsafe void AddBuffer() public unsafe void AddBuffer()
{ {
var buffer = buffers[nextBufferIndex]; var buffer = buffers[nextBufferIndex];
nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT; nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;

View File

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