optimize StreamingSound allocation and update

pull/20/head
cosmonaut 2022-08-02 11:06:45 -07:00
parent b4a0c7de88
commit dc7e68fecc
1 changed files with 41 additions and 53 deletions

View File

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