#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.Runtime.InteropServices; #endregion namespace Microsoft.Xna.Framework.Audio { // http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.audio.soundbank.aspx public class SoundBank : IDisposable { #region Public Properties public bool IsDisposed { get; private set; } public bool IsInUse { get { uint state; FAudio.FACTSoundBank_GetState(handle, out state); return (state & FAudio.FACT_STATE_INUSE) != 0; } } #endregion #region Internal Variables internal AudioEngine engine; internal FAudio.F3DAUDIO_DSP_SETTINGS dspSettings; #endregion #region Private Variables private IntPtr handle; private WeakReference selfReference; #endregion #region Disposing Event public event EventHandler Disposing; #endregion #region Public Constructor public SoundBank(AudioEngine audioEngine, string filename) { if (audioEngine == null) { throw new ArgumentNullException("audioEngine"); } if (String.IsNullOrEmpty(filename)) { throw new ArgumentNullException("filename"); } byte[] buffer = TitleContainer.ReadAllBytes(filename); GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); FAudio.FACTAudioEngine_CreateSoundBank( audioEngine.handle, pin.AddrOfPinnedObject(), (uint) buffer.Length, 0, 0, out handle ); pin.Free(); buffer = null; engine = audioEngine; selfReference = new WeakReference(this, true); dspSettings = new FAudio.F3DAUDIO_DSP_SETTINGS(); dspSettings.SrcChannelCount = 1; dspSettings.DstChannelCount = engine.channels; dspSettings.pMatrixCoefficients = Marshal.AllocHGlobal( 4 * (int) dspSettings.SrcChannelCount * (int) dspSettings.DstChannelCount ); engine.RegisterSoundBank(handle, selfReference); IsDisposed = false; } #endregion #region Destructor ~SoundBank() { 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 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.UnregisterSoundBank(handle); FAudio.FACTSoundBank_Destroy(handle); Marshal.FreeHGlobal(dspSettings.pMatrixCoefficients); } OnSoundBankDestroyed(); } } } #endregion #region Public Methods public Cue GetCue(string name) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } ushort cue = FAudio.FACTSoundBank_GetCueIndex( handle, name ); if (cue == FAudio.FACTINDEX_INVALID) { throw new InvalidOperationException( "Invalid cue name!" ); } IntPtr result; FAudio.FACTSoundBank_Prepare( handle, cue, 0, 0, out result ); return new Cue(result, name, this); } public void PlayCue(string name) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } ushort cue = FAudio.FACTSoundBank_GetCueIndex( handle, name ); if (cue == FAudio.FACTINDEX_INVALID) { throw new InvalidOperationException( "Invalid cue name!" ); } FAudio.FACTSoundBank_Play( handle, cue, 0, 0, IntPtr.Zero ); } public void PlayCue( string name, AudioListener listener, AudioEmitter emitter ) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (listener == null) { throw new ArgumentNullException("listener"); } if (emitter == null) { throw new ArgumentNullException("emitter"); } ushort cue = FAudio.FACTSoundBank_GetCueIndex( handle, name ); if (cue == FAudio.FACTINDEX_INVALID) { throw new InvalidOperationException( "Invalid cue name!" ); } emitter.emitterData.ChannelCount = dspSettings.SrcChannelCount; emitter.emitterData.CurveDistanceScaler = float.MaxValue; FAudio.FACT3DCalculate( engine.handle3D, ref listener.listenerData, ref emitter.emitterData, ref dspSettings ); FAudio.FACTSoundBank_Play3D( handle, cue, 0, 0, ref dspSettings, IntPtr.Zero ); } #endregion #region Internal Methods internal void OnSoundBankDestroyed() { IsDisposed = true; handle = IntPtr.Zero; selfReference = null; } #endregion } }