#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.cue.aspx public sealed class Cue : IDisposable { #region Public Properties public bool IsCreated { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_CREATED) != 0; } } public bool IsDisposed { get; private set; } public bool IsPaused { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_PAUSED) != 0; } } public bool IsPlaying { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_PLAYING) != 0; } } public bool IsPrepared { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_PREPARED) != 0; } } public bool IsPreparing { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_PREPARING) != 0; } } public bool IsStopped { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_STOPPED) != 0; } } public bool IsStopping { get { uint state; FAudio.FACTCue_GetState(handle, out state); return (state & FAudio.FACT_STATE_STOPPING) != 0; } } public string Name { get; private set; } #endregion #region Private Variables private IntPtr handle; private SoundBank bank; private WeakReference selfReference; #endregion #region Disposing Event public event EventHandler Disposing; #endregion #region Internal Constructor internal Cue(IntPtr cue, string name, SoundBank soundBank) { handle = cue; Name = name; bank = soundBank; selfReference = new WeakReference(this, true); bank.engine.RegisterCue(handle, selfReference); } #endregion #region Destructor ~Cue() { if (AudioEngine.ProgramExiting) { return; } if (!IsDisposed && IsPlaying) { // STOP LEAKING YOUR CUES, ARGH GC.ReRegisterForFinalize(this); return; } Dispose(false); } #endregion #region Public Dispose Method public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion #region Public Methods public void Apply3D(AudioListener listener, AudioEmitter emitter) { if (listener == null) { throw new ArgumentNullException("listener"); } if (emitter == null) { throw new ArgumentNullException("emitter"); } emitter.emitterData.ChannelCount = bank.dspSettings.SrcChannelCount; emitter.emitterData.CurveDistanceScaler = float.MaxValue; FAudio.FACT3DCalculate( bank.engine.handle3D, ref listener.listenerData, ref emitter.emitterData, ref bank.dspSettings ); FAudio.FACT3DApply(ref bank.dspSettings, handle); } public float GetVariable(string name) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } ushort variable = FAudio.FACTCue_GetVariableIndex( handle, name ); if (variable == FAudio.FACTVARIABLEINDEX_INVALID) { throw new InvalidOperationException( "Invalid variable name!" ); } float result; FAudio.FACTCue_GetVariable( handle, variable, out result ); return result; } public void Pause() { FAudio.FACTCue_Pause(handle, 1); } public void Play() { FAudio.FACTCue_Play(handle); } public void Resume() { FAudio.FACTCue_Pause(handle, 0); } public void SetVariable(string name, float value) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } ushort variable = FAudio.FACTCue_GetVariableIndex( handle, name ); if (variable == FAudio.FACTVARIABLEINDEX_INVALID) { throw new InvalidOperationException( "Invalid variable name!" ); } FAudio.FACTCue_SetVariable( handle, variable, value ); } public void Stop(AudioStopOptions options) { FAudio.FACTCue_Stop( handle, (options == AudioStopOptions.Immediate) ? FAudio.FACT_FLAG_STOP_IMMEDIATE : FAudio.FACT_FLAG_STOP_RELEASE ); } #endregion #region Internal Methods internal void OnCueDestroyed() { IsDisposed = true; handle = IntPtr.Zero; selfReference = null; } #endregion #region Private Methods private void Dispose(bool disposing) { lock (bank.engine.gcSync) { if (!IsDisposed) { if (Disposing != null) { Disposing.Invoke(this, null); } // If this is Disposed, stop leaking memory! if (!bank.engine.IsDisposed) { bank.engine.UnregisterCue(handle); FAudio.FACTCue_Destroy(handle); } OnCueDestroyed(); } } } #endregion } }