#region License /* FNA - XNA4 Reimplementation for Desktop Platforms * Copyright 2009-2020 Ethan Lee and the MonoGame Team * * Released under the Microsoft Public License. * See LICENSE for details. */ #endregion #region Using Statements using System; using System.IO; using System.Runtime.InteropServices; #endregion namespace Microsoft.Xna.Framework.Audio { // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.wavebank.aspx public class WaveBank : IDisposable { #region Public Properties public bool IsDisposed { get; private set; } public bool IsPrepared { get { uint state; FAudio.FACTWaveBank_GetState(handle, out state); return (state & FAudio.FACT_STATE_PREPARED) != 0; } } public bool IsInUse { get { uint state; FAudio.FACTWaveBank_GetState(handle, out state); return (state & FAudio.FACT_STATE_INUSE) != 0; } } #endregion #region Private Variables private IntPtr handle; private AudioEngine engine; private WeakReference selfReference; // Non-streaming WaveBanks private byte[] buffer; private GCHandle pin; // Streaming WaveBanks private IntPtr ioStream; #endregion #region Disposing Event public event EventHandler Disposing; #endregion #region Public Constructors public WaveBank( AudioEngine audioEngine, string nonStreamingWaveBankFilename ) { if (audioEngine == null) { throw new ArgumentNullException("audioEngine"); } if (String.IsNullOrEmpty(nonStreamingWaveBankFilename)) { throw new ArgumentNullException("nonStreamingWaveBankFilename"); } buffer = TitleContainer.ReadAllBytes( nonStreamingWaveBankFilename ); pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); FAudio.FACTAudioEngine_CreateInMemoryWaveBank( audioEngine.handle, pin.AddrOfPinnedObject(), (uint) buffer.Length, 0, 0, out handle ); engine = audioEngine; selfReference = new WeakReference(this, true); engine.RegisterWaveBank(handle, selfReference); IsDisposed = false; } public WaveBank( AudioEngine audioEngine, string streamingWaveBankFilename, int offset, short packetsize ) { if (audioEngine == null) { throw new ArgumentNullException("audioEngine"); } if (String.IsNullOrEmpty(streamingWaveBankFilename)) { throw new ArgumentNullException("streamingWaveBankFilename"); } string safeName = MonoGame.Utilities.FileHelpers.NormalizeFilePathSeparators( streamingWaveBankFilename ); if (!Path.IsPathRooted(safeName)) { safeName = Path.Combine( TitleLocation.Path, safeName ); } ioStream = FAudio.FAudio_fopen(safeName); FAudio.FACTStreamingParameters settings = new FAudio.FACTStreamingParameters(); settings.file = ioStream; FAudio.FACTAudioEngine_CreateStreamingWaveBank( audioEngine.handle, ref settings, out handle ); engine = audioEngine; selfReference = new WeakReference(this, true); engine.RegisterWaveBank(handle, selfReference); IsDisposed = false; } #endregion #region Destructor ~WaveBank() { if (AudioEngine.ProgramExiting) { return; } if (!IsDisposed && IsInUse) { // STOP LEAKING YOUR BANKS, ARGH GC.ReRegisterForFinalize(this); return; } Dispose(false); } #endregion #region Public Dispose Method public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion #region Protected Dispose Method protected virtual void Dispose(bool disposing) { lock (engine.gcSync) { if (!IsDisposed) { if (Disposing != null) { Disposing.Invoke(this, null); } // If this is disposed, stop leaking memory! if (!engine.IsDisposed) { engine.UnregisterWaveBank(handle); FAudio.FACTWaveBank_Destroy(handle); } OnWaveBankDestroyed(); } } } #endregion #region Internal Methods internal void OnWaveBankDestroyed() { IsDisposed = true; if (buffer != null) { pin.Free(); buffer = null; } else if (ioStream != IntPtr.Zero) { // FACT frees this pointer! ioStream = IntPtr.Zero; } handle = IntPtr.Zero; selfReference = null; } #endregion } }