diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 85d1492..689c75e 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -10,6 +10,7 @@ using MLEM.Input; using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Style; +using SoundEffectInfo = MLEM.Sound.SoundEffectInfo; namespace MLEM.Ui.Elements { /// diff --git a/MLEM.Ui/Style/UiStyle.cs b/MLEM.Ui/Style/UiStyle.cs index d6eac48..fc4ffc0 100644 --- a/MLEM.Ui/Style/UiStyle.cs +++ b/MLEM.Ui/Style/UiStyle.cs @@ -5,6 +5,7 @@ using MLEM.Formatting; using MLEM.Misc; using MLEM.Textures; using MLEM.Ui.Elements; +using SoundEffectInfo = MLEM.Sound.SoundEffectInfo; namespace MLEM.Ui.Style { /// diff --git a/MLEM/Misc/SoundEffectInfo.cs b/MLEM/Misc/SoundEffectInfo.cs index bffca93..683f2e1 100644 --- a/MLEM/Misc/SoundEffectInfo.cs +++ b/MLEM/Misc/SoundEffectInfo.cs @@ -1,59 +1,13 @@ +using System; using Microsoft.Xna.Framework.Audio; -using MLEM.Extensions; namespace MLEM.Misc { - /// - /// A sound effect info is a wrapper around that additionally stores , and information. - /// Additionally, a can be created using . - /// - public class SoundEffectInfo { + /// + [Obsolete("This class has been moved to MLEM.Sound.SoundEffectInfo in 5.1.0")] + public class SoundEffectInfo : Sound.SoundEffectInfo { - /// - /// The that is played by this info. - /// - public readonly SoundEffect Sound; - /// - /// Volume, ranging from 0.0 (silence) to 1.0 (full volume). Volume during playback is scaled by SoundEffect.MasterVolume. - /// - public float Volume; - /// - /// Pitch adjustment, ranging from -1.0 (down an octave) to 0.0 (no change) to 1.0 (up an octave). - /// - public float Pitch; - /// - /// Pan value ranging from -1.0 (left speaker) to 0.0 (centered), 1.0 (right speaker). - /// - public float Pan; - - /// - /// Creates a new sound effect info with the given values. - /// - /// The sound to play - /// The volume to play the sound with - /// The pitch to play the sound with - /// The pan to play the sound with - public SoundEffectInfo(SoundEffect sound, float volume = 1, float pitch = 0, float pan = 0) { - this.Sound = sound; - this.Volume = volume; - this.Pitch = pitch; - this.Pan = pan; - } - - /// - /// Plays this info's once. - /// - /// False if more sounds are currently playing than the platform allows - public bool Play() { - return this.Sound.Play(this.Volume, this.Pitch, this.Pan); - } - - /// - /// Creates a new with this sound effect info's data. - /// - /// The value to set the returned instance's to. Defaults to false. - /// A new sound effect instance, with this info's data applied - public SoundEffectInstance CreateInstance(bool isLooped = false) { - return this.Sound.CreateInstance(this.Volume, this.Pitch, this.Pan, isLooped); + /// + public SoundEffectInfo(SoundEffect sound, float volume = 1, float pitch = 0, float pan = 0) : base(sound, volume, pitch, pan) { } } diff --git a/MLEM/Misc/SoundEffectInstanceHandler.cs b/MLEM/Misc/SoundEffectInstanceHandler.cs index 61caaee..2c48a4c 100644 --- a/MLEM/Misc/SoundEffectInstanceHandler.cs +++ b/MLEM/Misc/SoundEffectInstanceHandler.cs @@ -1,141 +1,13 @@ using System; -using System.Collections; -using System.Collections.Generic; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Audio; namespace MLEM.Misc { - /// - /// A simple class that handles automatically removing and disposing objects once they are done playing to free up the audio source for new sounds. - /// Additionally, a callback can be registered that is invoked when the finishes playing. - /// Note that an object of this class can be added to a using its . - /// - public class SoundEffectInstanceHandler : GameComponent, IEnumerable { - - private readonly List playingSounds = new List(); - private AudioListener[] listeners; - - /// - /// Creates a new sound effect instance handler with the given settings - /// - /// The game instance - public SoundEffectInstanceHandler(Game game) : base(game) { - } - - /// - public override void Update(GameTime gameTime) { - this.Update(); - } - - /// - /// Updates this sound effect handler and manages all of the objects in it. - /// If has been called, all sounds will additionally be updated in 3D space. - /// This should be called each update frame. - /// - public void Update() { - for (var i = this.playingSounds.Count - 1; i >= 0; i--) { - var entry = this.playingSounds[i]; - if (entry.Instance.IsDisposed || entry.Instance.State == SoundState.Stopped) { - entry.Instance.Stop(true); - entry.OnStopped?.Invoke(entry.Instance); - this.playingSounds.RemoveAt(i); - } else { - entry.TryApply3D(this.listeners); - } - } - } - - /// - /// Sets the collection objects that should be listening to the sounds in this handler in 3D space. - /// If there are one or more listeners, this handler applies 3d effects to all sound effect instances that have been added to this handler along with an in automatically. - /// - public void SetListeners(params AudioListener[] listeners) { - this.listeners = listeners; - } - - /// - /// Pauses all of the sound effect instances that are currently playing - /// - public void Pause() { - foreach (var entry in this.playingSounds) - entry.Instance.Pause(); - } - - /// - /// Resumes all of the sound effect instances in this handler - /// - public void Resume() { - foreach (var entry in this.playingSounds) - entry.Instance.Resume(); - } - - /// - /// Adds a new to this handler. - /// This also starts playing the instance. - /// - /// The instance to add - /// The function that should be invoked when this instance stops playing, defaults to null - /// An optional audio emitter with which 3d sound can be applied - /// The passed instance, for chaining - public SoundEffectInstance Add(SoundEffectInstance instance, Action onStopped = null, AudioEmitter emitter = null) { - var entry = new Entry(instance, onStopped, emitter); - this.playingSounds.Add(entry); - instance.Play(); - entry.TryApply3D(this.listeners); - return instance; - } - - /// - /// Adds a new to this handler. - /// This also starts playing the created instance. - /// - /// The info for which to add a - /// The function that should be invoked when this instance stops playing, defaults to null - /// An optional audio emitter with which 3d sound can be applied - /// The newly created - public SoundEffectInstance Add(SoundEffectInfo info, Action onStopped = null, AudioEmitter emitter = null) { - return this.Add(info.CreateInstance(), onStopped, emitter); - } - - /// - /// Adds a new to this handler. - /// This also starts playing the created instance. - /// - /// The sound for which to add a - /// The function that should be invoked when this instance stops playing, defaults to null - /// An optional audio emitter with which 3d sound can be applied - /// The newly created - public SoundEffectInstance Add(SoundEffect effect, Action onStopped = null, AudioEmitter emitter = null) { - return this.Add(effect.CreateInstance(), onStopped, emitter); - } + /// + [Obsolete("This class has been moved to MLEM.Sound.SoundEffectInstanceHandler in 5.1.0")] + public class SoundEffectInstanceHandler : Sound.SoundEffectInstanceHandler { /// - public IEnumerator GetEnumerator() { - foreach (var sound in this.playingSounds) - yield return sound.Instance; - } - - IEnumerator IEnumerable.GetEnumerator() { - return this.GetEnumerator(); - } - - private readonly struct Entry { - - public readonly SoundEffectInstance Instance; - public readonly Action OnStopped; - public readonly AudioEmitter Emitter; - - public Entry(SoundEffectInstance instance, Action onStopped, AudioEmitter emitter) { - this.Instance = instance; - this.OnStopped = onStopped; - this.Emitter = emitter; - } - - public void TryApply3D(AudioListener[] listeners) { - if (listeners != null && listeners.Length > 0 && this.Emitter != null) - this.Instance.Apply3D(listeners, this.Emitter); - } - + public SoundEffectInstanceHandler(Game game) : base(game) { } } diff --git a/MLEM/Sound/SoundEffectInfo.cs b/MLEM/Sound/SoundEffectInfo.cs new file mode 100644 index 0000000..65e8445 --- /dev/null +++ b/MLEM/Sound/SoundEffectInfo.cs @@ -0,0 +1,60 @@ +using Microsoft.Xna.Framework.Audio; +using MLEM.Extensions; + +namespace MLEM.Sound { + /// + /// A sound effect info is a wrapper around that additionally stores , and information. + /// Additionally, a can be created using . + /// + public class SoundEffectInfo { + + /// + /// The that is played by this info. + /// + public readonly SoundEffect Sound; + /// + /// Volume, ranging from 0.0 (silence) to 1.0 (full volume). Volume during playback is scaled by SoundEffect.MasterVolume. + /// + public float Volume; + /// + /// Pitch adjustment, ranging from -1.0 (down an octave) to 0.0 (no change) to 1.0 (up an octave). + /// + public float Pitch; + /// + /// Pan value ranging from -1.0 (left speaker) to 0.0 (centered), 1.0 (right speaker). + /// + public float Pan; + + /// + /// Creates a new sound effect info with the given values. + /// + /// The sound to play + /// The volume to play the sound with + /// The pitch to play the sound with + /// The pan to play the sound with + public SoundEffectInfo(SoundEffect sound, float volume = 1, float pitch = 0, float pan = 0) { + this.Sound = sound; + this.Volume = volume; + this.Pitch = pitch; + this.Pan = pan; + } + + /// + /// Plays this info's once. + /// + /// False if more sounds are currently playing than the platform allows + public bool Play() { + return this.Sound.Play(this.Volume, this.Pitch, this.Pan); + } + + /// + /// Creates a new with this sound effect info's data. + /// + /// The value to set the returned instance's to. Defaults to false. + /// A new sound effect instance, with this info's data applied + public SoundEffectInstance CreateInstance(bool isLooped = false) { + return this.Sound.CreateInstance(this.Volume, this.Pitch, this.Pan, isLooped); + } + + } +} \ No newline at end of file diff --git a/MLEM/Sound/SoundEffectInstanceHandler.cs b/MLEM/Sound/SoundEffectInstanceHandler.cs new file mode 100644 index 0000000..9273c88 --- /dev/null +++ b/MLEM/Sound/SoundEffectInstanceHandler.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; + +namespace MLEM.Sound { + /// + /// A simple class that handles automatically removing and disposing objects once they are done playing to free up the audio source for new sounds. + /// Additionally, a callback can be registered that is invoked when the finishes playing. + /// Note that an object of this class can be added to a using its . + /// + public class SoundEffectInstanceHandler : GameComponent, IEnumerable { + + private readonly List playingSounds = new List(); + private AudioListener[] listeners; + + /// + /// Creates a new sound effect instance handler with the given settings + /// + /// The game instance + public SoundEffectInstanceHandler(Game game) : base(game) { + } + + /// + public override void Update(GameTime gameTime) { + this.Update(); + } + + /// + /// Updates this sound effect handler and manages all of the objects in it. + /// If has been called, all sounds will additionally be updated in 3D space. + /// This should be called each update frame. + /// + public void Update() { + for (var i = this.playingSounds.Count - 1; i >= 0; i--) { + var entry = this.playingSounds[i]; + if (entry.Instance.IsDisposed || entry.Instance.State == SoundState.Stopped) { + entry.Instance.Stop(true); + entry.OnStopped?.Invoke(entry.Instance); + this.playingSounds.RemoveAt(i); + } else { + entry.TryApply3D(this.listeners); + } + } + } + + /// + /// Sets the collection objects that should be listening to the sounds in this handler in 3D space. + /// If there are one or more listeners, this handler applies 3d effects to all sound effect instances that have been added to this handler along with an in automatically. + /// + public void SetListeners(params AudioListener[] listeners) { + this.listeners = listeners; + } + + /// + /// Pauses all of the sound effect instances that are currently playing + /// + public void Pause() { + foreach (var entry in this.playingSounds) + entry.Instance.Pause(); + } + + /// + /// Resumes all of the sound effect instances in this handler + /// + public void Resume() { + foreach (var entry in this.playingSounds) + entry.Instance.Resume(); + } + + /// + /// Adds a new to this handler. + /// This also starts playing the instance. + /// + /// The instance to add + /// The function that should be invoked when this instance stops playing, defaults to null + /// An optional audio emitter with which 3d sound can be applied + /// The passed instance, for chaining + public SoundEffectInstance Add(SoundEffectInstance instance, Action onStopped = null, AudioEmitter emitter = null) { + var entry = new Entry(instance, onStopped, emitter); + this.playingSounds.Add(entry); + instance.Play(); + entry.TryApply3D(this.listeners); + return instance; + } + + /// + /// Adds a new to this handler. + /// This also starts playing the created instance. + /// + /// The info for which to add a + /// The function that should be invoked when this instance stops playing, defaults to null + /// An optional audio emitter with which 3d sound can be applied + /// The newly created + public SoundEffectInstance Add(SoundEffectInfo info, Action onStopped = null, AudioEmitter emitter = null) { + return this.Add(info.CreateInstance(), onStopped, emitter); + } + + /// + /// Adds a new to this handler. + /// This also starts playing the created instance. + /// + /// The sound for which to add a + /// The function that should be invoked when this instance stops playing, defaults to null + /// An optional audio emitter with which 3d sound can be applied + /// The newly created + public SoundEffectInstance Add(SoundEffect effect, Action onStopped = null, AudioEmitter emitter = null) { + return this.Add(effect.CreateInstance(), onStopped, emitter); + } + + /// + public IEnumerator GetEnumerator() { + foreach (var sound in this.playingSounds) + yield return sound.Instance; + } + + IEnumerator IEnumerable.GetEnumerator() { + return this.GetEnumerator(); + } + + private readonly struct Entry { + + public readonly SoundEffectInstance Instance; + public readonly Action OnStopped; + public readonly AudioEmitter Emitter; + + public Entry(SoundEffectInstance instance, Action onStopped, AudioEmitter emitter) { + this.Instance = instance; + this.OnStopped = onStopped; + this.Emitter = emitter; + } + + public void TryApply3D(AudioListener[] listeners) { + if (listeners != null && listeners.Length > 0 && this.Emitter != null) + this.Instance.Apply3D(listeners, this.Emitter); + } + + } + + } +} \ No newline at end of file