forked from MoonsideGames/MoonWorks
UpdatingSourceVoice + warn on audio leak
parent
772a0378bb
commit
e961a18a83
|
@ -64,7 +64,7 @@ namespace MoonWorks.Audio
|
|||
};
|
||||
}
|
||||
|
||||
protected override unsafe void Destroy()
|
||||
protected override unsafe void DisposeUnmanagedState()
|
||||
{
|
||||
if (OwnsBufferData)
|
||||
{
|
||||
|
|
|
@ -90,22 +90,15 @@ namespace MoonWorks.Audio
|
|||
/// <summary>
|
||||
/// Unloads the Ogg data, freeing resources.
|
||||
/// </summary>
|
||||
public override unsafe void Unload()
|
||||
public override void Unload()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
FAudio.stb_vorbis_close(VorbisHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
|
||||
VorbisHandle = IntPtr.Zero;
|
||||
FileDataPtr = IntPtr.Zero;
|
||||
}
|
||||
DisposeUnmanagedState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads an entire ogg file into an AudioBuffer. Useful for static audio.
|
||||
/// </summary>
|
||||
public unsafe static AudioBuffer CreateBuffer(AudioDevice device, string filePath)
|
||||
public static unsafe AudioBuffer CreateBuffer(AudioDevice device, string filePath)
|
||||
{
|
||||
var filePointer = FAudio.stb_vorbis_open_filename(filePath, out var error, IntPtr.Zero);
|
||||
|
||||
|
@ -143,5 +136,17 @@ namespace MoonWorks.Audio
|
|||
(uint) lengthInBytes,
|
||||
true);
|
||||
}
|
||||
|
||||
protected override unsafe void DisposeUnmanagedState()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
FAudio.stb_vorbis_close(VorbisHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
|
||||
VorbisHandle = IntPtr.Zero;
|
||||
FileDataPtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,16 +99,9 @@ namespace MoonWorks.Audio
|
|||
/// <summary>
|
||||
/// Unloads the qoa data, freeing resources.
|
||||
/// </summary>
|
||||
public override unsafe void Unload()
|
||||
public override void Unload()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
FAudio.qoa_close(QoaHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
|
||||
QoaHandle = IntPtr.Zero;
|
||||
FileDataPtr = IntPtr.Zero;
|
||||
}
|
||||
DisposeUnmanagedState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -160,5 +153,17 @@ namespace MoonWorks.Audio
|
|||
((UInt64)(bytes[4]) << 24) | ((UInt64)(bytes[5]) << 16) |
|
||||
((UInt64)(bytes[6]) << 8) | ((UInt64)(bytes[7]) << 0);
|
||||
}
|
||||
|
||||
protected override unsafe void DisposeUnmanagedState()
|
||||
{
|
||||
if (Loaded)
|
||||
{
|
||||
FAudio.qoa_close(QoaHandle);
|
||||
NativeMemory.Free((void*) FileDataPtr);
|
||||
|
||||
QoaHandle = IntPtr.Zero;
|
||||
FileDataPtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,10 +36,5 @@ namespace MoonWorks.Audio
|
|||
/// <param name="filledLengthInBytes">How much data was actually filled in by the decode.</param>
|
||||
/// <param name="reachedEnd">Whether the end of the data was reached on this decode.</param>
|
||||
public abstract unsafe void Decode(void* buffer, int bufferLengthInBytes, out int filledLengthInBytes, out bool reachedEnd);
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace MoonWorks.Audio
|
|||
public float SpeedOfSound = 343.5f;
|
||||
|
||||
private readonly HashSet<GCHandle> resources = new HashSet<GCHandle>();
|
||||
private readonly HashSet<SourceVoice> activeSourceVoices = new HashSet<SourceVoice>();
|
||||
private readonly HashSet<UpdatingSourceVoice> updatingSourceVoices = new HashSet<UpdatingSourceVoice>();
|
||||
|
||||
private AudioTweenManager AudioTweenManager;
|
||||
|
||||
|
@ -42,7 +42,7 @@ namespace MoonWorks.Audio
|
|||
internal readonly object StateLock = new object();
|
||||
|
||||
private bool Running;
|
||||
private bool IsDisposed;
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
internal unsafe AudioDevice()
|
||||
{
|
||||
|
@ -164,15 +164,19 @@ namespace MoonWorks.Audio
|
|||
|
||||
AudioTweenManager.Update(elapsedSeconds);
|
||||
|
||||
foreach (var voice in activeSourceVoices)
|
||||
foreach (var voice in updatingSourceVoices)
|
||||
{
|
||||
voice.Update();
|
||||
}
|
||||
|
||||
foreach (var voice in VoicesToReturn)
|
||||
{
|
||||
if (voice is UpdatingSourceVoice updatingSourceVoice)
|
||||
{
|
||||
updatingSourceVoices.Remove(updatingSourceVoice);
|
||||
}
|
||||
|
||||
voice.Reset();
|
||||
activeSourceVoices.Remove(voice);
|
||||
VoicePool.Return(voice);
|
||||
}
|
||||
|
||||
|
@ -197,7 +201,12 @@ namespace MoonWorks.Audio
|
|||
lock (StateLock)
|
||||
{
|
||||
var voice = VoicePool.Obtain<T>(format);
|
||||
activeSourceVoices.Add(voice);
|
||||
|
||||
if (voice is UpdatingSourceVoice updatingSourceVoice)
|
||||
{
|
||||
updatingSourceVoices.Add(updatingSourceVoice);
|
||||
}
|
||||
|
||||
return voice;
|
||||
}
|
||||
}
|
||||
|
@ -258,9 +267,9 @@ namespace MoonWorks.Audio
|
|||
{
|
||||
resources.Add(resourceReference);
|
||||
|
||||
if (resourceReference.Target is SourceVoice voice)
|
||||
if (resourceReference.Target is UpdatingSourceVoice updatableVoice)
|
||||
{
|
||||
activeSourceVoices.Add(voice);
|
||||
updatingSourceVoices.Add(updatableVoice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,5 @@ namespace MoonWorks.Audio
|
|||
emitterData.pReverbCurve = IntPtr.Zero;
|
||||
emitterData.CurveDistanceScaler = 1.0f;
|
||||
}
|
||||
|
||||
protected override void Destroy() { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,5 @@ namespace MoonWorks.Audio
|
|||
/* Unexposed variables, defaults based on XNA behavior */
|
||||
listenerData.pCone = IntPtr.Zero;
|
||||
}
|
||||
|
||||
protected override void Destroy() { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,16 +19,22 @@ namespace MoonWorks.Audio
|
|||
Device.AddResourceReference(SelfReference);
|
||||
}
|
||||
|
||||
protected abstract void Destroy();
|
||||
protected virtual void DisposeManagedState() { }
|
||||
protected virtual void DisposeUnmanagedState() { }
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
Destroy();
|
||||
if (disposing)
|
||||
{
|
||||
DisposeManagedState();
|
||||
|
||||
Device.RemoveResourceReference(SelfReference);
|
||||
SelfReference.Free();
|
||||
Device.RemoveResourceReference(SelfReference);
|
||||
SelfReference.Free();
|
||||
}
|
||||
|
||||
DisposeUnmanagedState();
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
@ -36,6 +42,17 @@ namespace MoonWorks.Audio
|
|||
|
||||
~AudioResource()
|
||||
{
|
||||
#if DEBUG
|
||||
// If the graphics device associated with this resource was already disposed, we assume
|
||||
// that your game is in the middle of shutting down.
|
||||
if (!IsDisposed && Device != null && !Device.IsDisposed)
|
||||
{
|
||||
// If you see this log message, you leaked a graphics resource without disposing it!
|
||||
// This means your game may eventually run out of native memory for mysterious reasons.
|
||||
Logger.LogWarn($"A resource of type {GetType().Name} was not Disposed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: false);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace MoonWorks.Audio
|
|||
/// <summary>
|
||||
/// Plays back a series of AudioBuffers in sequence. Set the OnSoundNeeded callback to add AudioBuffers dynamically.
|
||||
/// </summary>
|
||||
public class SoundSequence : SourceVoice, IPoolable<SoundSequence>
|
||||
public class SoundSequence : UpdatingSourceVoice, IPoolable<SoundSequence>
|
||||
{
|
||||
public int NeedSoundThreshold = 0;
|
||||
public delegate void OnSoundNeededFunc();
|
||||
|
|
|
@ -191,12 +191,6 @@ namespace MoonWorks.Audio
|
|||
Device.Return(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called automatically by AudioDevice in the audio thread.
|
||||
/// Don't call this yourself! You might regret it!
|
||||
/// </summary>
|
||||
public virtual void Update() { }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an FAudio buffer to the voice queue.
|
||||
/// The voice processes and plays back the buffers in its queue in the order that they were submitted.
|
||||
|
@ -221,10 +215,9 @@ namespace MoonWorks.Audio
|
|||
base.Reset();
|
||||
}
|
||||
|
||||
protected override unsafe void Destroy()
|
||||
protected override void DisposeManagedState()
|
||||
{
|
||||
Stop();
|
||||
base.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace MoonWorks.Audio
|
|||
/// <summary>
|
||||
/// Use in conjunction with an AudioDataStreamable object to play back streaming audio data.
|
||||
/// </summary>
|
||||
public class StreamingVoice : SourceVoice, IPoolable<StreamingVoice>
|
||||
public class StreamingVoice : UpdatingSourceVoice, IPoolable<StreamingVoice>
|
||||
{
|
||||
private const int BUFFER_COUNT = 3;
|
||||
private readonly IntPtr[] buffers;
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace MoonWorks.Audio
|
|||
/// TransientVoice is intended for playing one-off sound effects that don't have a long term reference. <br/>
|
||||
/// It will be automatically returned to the AudioDevice SourceVoice pool once it is done playing back.
|
||||
/// </summary>
|
||||
public class TransientVoice : SourceVoice, IPoolable<TransientVoice>
|
||||
public class TransientVoice : UpdatingSourceVoice, IPoolable<TransientVoice>
|
||||
{
|
||||
static TransientVoice IPoolable<TransientVoice>.Create(AudioDevice device, Format format)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
namespace MoonWorks.Audio
|
||||
{
|
||||
public abstract class UpdatingSourceVoice : SourceVoice
|
||||
{
|
||||
protected UpdatingSourceVoice(AudioDevice device, Format format) : base(device, format)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void Update();
|
||||
}
|
||||
}
|
|
@ -565,7 +565,7 @@ namespace MoonWorks.Audio
|
|||
);
|
||||
}
|
||||
|
||||
protected unsafe override void Destroy()
|
||||
protected override void DisposeUnmanagedState()
|
||||
{
|
||||
NativeMemory.Free(pMatrixCoefficients);
|
||||
FAudio.FAudioVoice_DestroyVoice(Handle);
|
||||
|
|
Loading…
Reference in New Issue