add SoundQueue

pull/50/head
cosmonaut 2023-07-28 13:02:50 -07:00
parent dbbd6540ab
commit 1d86d0c210
2 changed files with 150 additions and 0 deletions

View File

@ -30,6 +30,7 @@ namespace MoonWorks.Audio
private readonly HashSet<WeakReference> resources = new HashSet<WeakReference>(); private readonly HashSet<WeakReference> resources = new HashSet<WeakReference>();
private readonly List<StreamingSound> autoUpdateStreamingSoundReferences = new List<StreamingSound>(); private readonly List<StreamingSound> autoUpdateStreamingSoundReferences = new List<StreamingSound>();
private readonly List<StaticSoundInstance> autoFreeStaticSoundInstanceReferences = new List<StaticSoundInstance>(); private readonly List<StaticSoundInstance> autoFreeStaticSoundInstanceReferences = new List<StaticSoundInstance>();
private readonly List<WeakReference<SoundQueue>> soundQueueReferences = new List<WeakReference<SoundQueue>>();
private AudioTweenManager AudioTweenManager; private AudioTweenManager AudioTweenManager;
@ -184,6 +185,18 @@ namespace MoonWorks.Audio
} }
} }
for (var i = soundQueueReferences.Count - 1; i >= 0; i -= 1)
{
if (soundQueueReferences[i].TryGetTarget(out var soundQueue))
{
soundQueue.Update();
}
else
{
soundQueueReferences.RemoveAt(i);
}
}
AudioTweenManager.Update(elapsedSeconds); AudioTweenManager.Update(elapsedSeconds);
} }
@ -256,6 +269,11 @@ namespace MoonWorks.Audio
autoFreeStaticSoundInstanceReferences.Add(instance); autoFreeStaticSoundInstanceReferences.Add(instance);
} }
internal void AddSoundQueueReference(SoundQueue queue)
{
soundQueueReferences.Add(new WeakReference<SoundQueue>(queue));
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)

132
src/Audio/SoundQueue.cs Normal file
View File

@ -0,0 +1,132 @@
using System;
namespace MoonWorks.Audio
{
// NOTE: all sounds played with a playlist must have the same audio format!
public class SoundQueue : SoundInstance
{
public int NeedBufferThreshold = 0;
private uint queuedBufferCount = 0;
public delegate void OnBufferNeededFunc();
public OnBufferNeededFunc OnBufferNeeded;
private object StateLock = new object();
public SoundQueue(AudioDevice device, ushort formatTag, ushort bitsPerSample, ushort blockAlign, ushort channels, uint samplesPerSecond) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond)
{
device.AddSoundQueueReference(this);
}
public SoundQueue(AudioDevice device, StaticSound templateSound) : base(device, templateSound.FormatTag, templateSound.BitsPerSample, templateSound.BlockAlign, templateSound.Channels, templateSound.SamplesPerSecond)
{
device.AddSoundQueueReference(this);
}
public void Update()
{
lock (StateLock)
{
if (IsDisposed) { return; }
if (State != SoundState.Playing) { return; }
if (NeedBufferThreshold > 0)
{
FAudio.FAudioSourceVoice_GetState(
Voice,
out var state,
FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED
);
var queuedBufferCount = state.BuffersQueued;
for (int i = 0; i < NeedBufferThreshold - queuedBufferCount; i += 1)
{
if (OnBufferNeeded != null)
{
OnBufferNeeded();
}
}
}
}
}
public void EnqueueSound(StaticSound sound)
{
#if DEBUG
if (
sound.FormatTag != Format.wFormatTag ||
sound.BitsPerSample != Format.wBitsPerSample ||
sound.Channels != Format.nChannels ||
sound.SamplesPerSecond != Format.nSamplesPerSec
)
{
Logger.LogWarn("Playlist audio format mismatch!");
}
#endif
lock (StateLock)
{
FAudio.FAudioSourceVoice_SubmitSourceBuffer(
Voice,
ref sound.Handle,
IntPtr.Zero
);
}
}
public override void Pause()
{
lock (StateLock)
{
if (State == SoundState.Playing)
{
FAudio.FAudioSourceVoice_Stop(Voice, 0, 0);
State = SoundState.Paused;
}
}
}
public override void Play()
{
PlayUsingOperationSet(0);
}
public override void QueueSyncPlay()
{
PlayUsingOperationSet(1);
}
private void PlayUsingOperationSet(uint operationSet)
{
lock (StateLock)
{
if (State == SoundState.Playing)
{
return;
}
FAudio.FAudioSourceVoice_Start(Voice, 0, operationSet);
State = SoundState.Playing;
}
}
public override void Stop()
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_ExitLoop(Voice, 0);
State = SoundState.Stopped;
}
}
public override void StopImmediate()
{
lock (StateLock)
{
FAudio.FAudioSourceVoice_Stop(Voice, 0, 0);
FAudio.FAudioSourceVoice_FlushSourceBuffers(Voice);
State = SoundState.Stopped;
}
}
}
}