Setup entry point + integrated moonworks stuff
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nerfed.Runtime.Audio;
|
||||
|
||||
/// <summary>
|
||||
/// Use in conjunction with an AudioDataStreamable object to play back streaming audio data.
|
||||
/// </summary>
|
||||
public class StreamingVoice : UpdatingSourceVoice, IPoolable<StreamingVoice>
|
||||
{
|
||||
private const int BUFFER_COUNT = 3;
|
||||
private readonly IntPtr[] buffers;
|
||||
private int nextBufferIndex = 0;
|
||||
private uint BufferSize;
|
||||
|
||||
public bool Loop { get; set; }
|
||||
|
||||
public AudioDataStreamable AudioData { get; protected set; }
|
||||
|
||||
public unsafe StreamingVoice(AudioDevice device, Format format) : base(device, format)
|
||||
{
|
||||
buffers = new IntPtr[BUFFER_COUNT];
|
||||
}
|
||||
|
||||
public static StreamingVoice Create(AudioDevice device, Format format)
|
||||
{
|
||||
return new StreamingVoice(device, format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads and prepares an AudioDataStreamable for streaming playback.
|
||||
/// This automatically calls Load on the given AudioDataStreamable.
|
||||
/// </summary>
|
||||
public void Load(AudioDataStreamable data)
|
||||
{
|
||||
lock (StateLock)
|
||||
{
|
||||
if (AudioData != null)
|
||||
{
|
||||
AudioData.Unload();
|
||||
}
|
||||
|
||||
data.Load();
|
||||
AudioData = data;
|
||||
|
||||
InitializeBuffers();
|
||||
QueueBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads AudioDataStreamable from this voice.
|
||||
/// This automatically calls Unload on the given AudioDataStreamable.
|
||||
/// </summary>
|
||||
public void Unload()
|
||||
{
|
||||
lock (StateLock)
|
||||
{
|
||||
if (AudioData != null)
|
||||
{
|
||||
Stop();
|
||||
AudioData.Unload();
|
||||
AudioData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Unload();
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
lock (StateLock)
|
||||
{
|
||||
if (AudioData == null || State != SoundState.Playing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QueueBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
private void QueueBuffers()
|
||||
{
|
||||
int buffersNeeded = BUFFER_COUNT - (int) BuffersQueued; // don't get got by uint underflow!
|
||||
for (int i = 0; i < buffersNeeded; i += 1)
|
||||
{
|
||||
AddBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void AddBuffer()
|
||||
{
|
||||
IntPtr buffer = buffers[nextBufferIndex];
|
||||
nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;
|
||||
|
||||
AudioData.Decode(
|
||||
(void*) buffer,
|
||||
(int) BufferSize,
|
||||
out int filledLengthInBytes,
|
||||
out bool reachedEnd
|
||||
);
|
||||
|
||||
if (filledLengthInBytes > 0)
|
||||
{
|
||||
FAudio.FAudioBuffer 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)
|
||||
{
|
||||
AudioData.Seek(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void InitializeBuffers()
|
||||
{
|
||||
BufferSize = AudioData.DecodeBufferSize;
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i += 1)
|
||||
{
|
||||
if (buffers[i] != IntPtr.Zero)
|
||||
{
|
||||
NativeMemory.Free((void*) buffers[i]);
|
||||
}
|
||||
|
||||
buffers[i] = (IntPtr) NativeMemory.Alloc(BufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected override unsafe void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
lock (StateLock)
|
||||
{
|
||||
Stop();
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i += 1)
|
||||
{
|
||||
if (buffers[i] != IntPtr.Zero)
|
||||
{
|
||||
NativeMemory.Free((void*) buffers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user