fna-workbench

fna-workbench Git Source Tree


Root/src/Audio/SoundEffectInstance.cs

#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
 * Copyright 2009-2016 Ethan Lee and the MonoGame Team
 *
 * Released under the Microsoft Public License.
 * See LICENSE for details.
 */
#endregion
 
#region Using Statements
using System;
#endregion
 
namespace Microsoft.Xna.Framework.Audio
{
    public class SoundEffectInstance : IDisposable
    {
        #region Public Properties
 
        public bool IsDisposed
        {
            get;
            protected set;
        }
 
        private bool INTERNAL_looped = false;
        public virtual bool IsLooped
        {
            get
            {
                return INTERNAL_looped;
            }
            set
            {
                INTERNAL_looped = value;
                if (INTERNAL_alSource != null)
                {
                    AudioDevice.ALDevice.SetSourceLooped(
                        INTERNAL_alSource,
                        value
                    );
                }
            }
        }
 
        private float INTERNAL_pan = 0.0f;
        public float Pan
        {
            get
            {
                return INTERNAL_pan;
            }
            set
            {
                INTERNAL_pan = value;
                if (INTERNAL_alSource != null)
                {
                    AudioDevice.ALDevice.SetSourcePan(
                        INTERNAL_alSource,
                        value
                    );
                }
            }
        }
 
        private float INTERNAL_pitch = 0f;
        public float Pitch
        {
            get
            {
                return INTERNAL_pitch;
            }
            set
            {
                INTERNAL_pitch = value;
                if (INTERNAL_alSource != null)
                {
                    AudioDevice.ALDevice.SetSourcePitch(
                        INTERNAL_alSource,
                        value,
                        !INTERNAL_isXACTSource
                    );
                }
            }
        }
 
        public SoundState State
        {
            get
            {
                if (INTERNAL_alSource == null)
                {
                    return SoundState.Stopped;
                }
                SoundState result = AudioDevice.ALDevice.GetSourceState(
                    INTERNAL_alSource
                );
                if (result == SoundState.Stopped && isDynamic)
                {
                    // Force playing at all times for DSFI!
                    return SoundState.Playing;
                }
                return result;
            }
        }
 
        private float INTERNAL_volume = 1.0f;
        public float Volume
        {
            get
            {
                return INTERNAL_volume;
            }
            set
            {
                INTERNAL_volume = value;
                if (INTERNAL_alSource != null)
                {
                    AudioDevice.ALDevice.SetSourceVolume(
                        INTERNAL_alSource,
                        value
                    );
                }
            }
        }
 
        #endregion
 
        #region Internal Variables: XACT Filters
 
        internal byte FilterType;
 
        #endregion
 
        #region Private Variables: XNA Implementation
 
        private SoundEffect INTERNAL_parentEffect;
        private WeakReference selfReference;
 
        internal bool isDynamic;
 
        /* FNA' XACT runtime wraps around SoundEffect for audio output.
         * Only problem: XACT pitch has no boundaries, SoundEffect does.
         * So, we're going to use this to tell the pitch clamp to STFU.
         * -flibit
         */
        internal bool INTERNAL_isXACTSource = false;
 
        #endregion
 
        #region Private Variables: AL Source, EffectSlot
 
        internal IALSource INTERNAL_alSource;
        private IALReverb INTERNAL_alReverb;
 
        #endregion
 
        #region Private Variables: 3D Audio
 
        protected Vector3 position = new Vector3(0.0f, 0.0f, 0.1f);
 
        // Used to prevent outdated positional audio data from being used
        protected bool INTERNAL_positionalAudio = false;
 
        #endregion
 
        #region Internal Constructor
 
        internal SoundEffectInstance(SoundEffect parent)
        {
            INTERNAL_parentEffect = parent;
            if (INTERNAL_parentEffect != null)
            {
                selfReference = new WeakReference(this);
                INTERNAL_parentEffect.Instances.Add(selfReference);
            }
            isDynamic = false;
        }
 
        #endregion
 
        #region Destructor
 
        ~SoundEffectInstance()
        {
            Dispose();
        }
 
        #endregion
 
        #region Public Dispose Method
 
        public virtual void Dispose()
        {
            if (!IsDisposed)
            {
                Stop(true);
                if (INTERNAL_parentEffect != null)
                {
                    INTERNAL_parentEffect.Instances.Remove(selfReference);
                    selfReference = null;
                }
                IsDisposed = true;
            }
        }
 
        #endregion
 
        #region Public 3D Audio Methods
 
        public void Apply3D(AudioListener listener, AudioEmitter emitter)
        {
            if (INTERNAL_alSource == null)
            {
                return;
            }
 
            // Set up orientation matrix
            Matrix orientation = Matrix.CreateWorld(Vector3.Zero, listener.Forward, listener.Up);
 
            // Set up our final position according to orientation of listener
            position = Vector3.Transform(emitter.Position - listener.Position, orientation);
            if (position != Vector3.Zero)
            {
                position.Normalize();
            }
 
            // Set the position based on relative positon
            AudioDevice.ALDevice.SetSourcePosition(
                INTERNAL_alSource,
                position
            );
 
            // We positional now
            INTERNAL_positionalAudio = true;
        }
 
        public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
        {
            throw new NotSupportedException("OpenAL can only make use of one listener.");
        }
 
        #endregion
 
        #region Public Playback Methods
 
        public virtual void Play()
        {
            if (State != SoundState.Stopped)
            {
                return;
            }
 
            if (INTERNAL_alSource != null)
            {
                // The sound has stopped, but hasn't cleaned up yet...
                AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource);
                INTERNAL_alSource = null;
            }
 
            INTERNAL_alSource = AudioDevice.ALDevice.GenSource(
                INTERNAL_parentEffect.INTERNAL_buffer
            );
            if (INTERNAL_alSource == null)
            {
                FNAPlatform.Log("WARNING: AL SOURCE WAS NOT AVAILABLE. SKIPPING.");
                return;
            }
 
            // Apply Pan/Position
            if (INTERNAL_positionalAudio)
            {
                INTERNAL_positionalAudio = false;
                AudioDevice.ALDevice.SetSourcePosition(
                    INTERNAL_alSource,
                    position
                );
            }
            else
            {
                Pan = Pan;
            }
 
            // Reassign Properties, in case the AL properties need to be applied.
            Volume = Volume;
            IsLooped = IsLooped;
            Pitch = Pitch;
 
            // Apply EFX
            if (INTERNAL_alReverb != null)
            {
                AudioDevice.ALDevice.SetSourceReverb(
                    INTERNAL_alSource,
                    INTERNAL_alReverb
                );
            }
 
            AudioDevice.ALDevice.PlaySource(INTERNAL_alSource);
        }
 
        public void Pause()
        {
            if (INTERNAL_alSource != null && State == SoundState.Playing)
            {
                AudioDevice.ALDevice.PauseSource(INTERNAL_alSource);
            }
        }
 
        public void Resume()
        {
            if (INTERNAL_alSource == null)
            {
                // XNA4 just plays if we've not started yet.
                Play();
            }
            else if (State == SoundState.Paused)
            {
                AudioDevice.ALDevice.ResumeSource(INTERNAL_alSource);
            }
        }
 
        public void Stop()
        {
            if (INTERNAL_alSource != null)
            {
                // TODO: GraphicsResource-like reference management -flibit
                if (AudioDevice.ALDevice != null)
                {
                    AudioDevice.ALDevice.StopAndDisposeSource(INTERNAL_alSource);
                    DynamicSoundEffectInstance dsfi = this as DynamicSoundEffectInstance;
                    if (dsfi != null && AudioDevice.DynamicInstancePool.Contains(dsfi))
                    {
                        AudioDevice.DynamicInstancePool.Remove(dsfi);
                    }
                }
                INTERNAL_alSource = null;
            }
        }
 
        public void Stop(bool immediate)
        {
            Stop();
        }
 
        #endregion
 
        #region Internal Effects Methods
 
        internal void INTERNAL_applyReverb(IALReverb reverb)
        {
            INTERNAL_alReverb = reverb;
            if (INTERNAL_alSource != null)
            {
                AudioDevice.ALDevice.SetSourceReverb(
                    INTERNAL_alSource,
                    INTERNAL_alReverb
                );
            }
        }
 
        internal void INTERNAL_applyLowPassFilter(float hfGain)
        {
            if (INTERNAL_alSource != null)
            {
                AudioDevice.ALDevice.SetSourceLowPassFilter(INTERNAL_alSource, hfGain);
            }
        }
 
        internal void INTERNAL_applyHighPassFilter(float lfGain)
        {
            if (INTERNAL_alSource != null)
            {
                AudioDevice.ALDevice.SetSourceHighPassFilter(INTERNAL_alSource, lfGain);
            }
        }
 
        internal void INTERNAL_applyBandPassFilter(float hfGain, float lfGain)
        {
            if (INTERNAL_alSource != null)
            {
                AudioDevice.ALDevice.SetSourceBandPassFilter(INTERNAL_alSource, hfGain, lfGain);
            }
        }
 
        #endregion
    }
}

Archive Download this file

Branches

Number of commits:
Page rendered in 0.09976s using 11 queries.