namespace DarkWynterEngine.Audio { #region Using Statements using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using System.Xml; #endregion using Globals; using Physics; using GameObjects; public static class AudioMixer { /// /// Background Music /// static WaveBank music; /// /// Sound Effects /// static WaveBank effects; /// /// Provides access to WaveBank entries /// static SoundBank soundBank; public struct AudioBackground { /// /// Earth Attack sound. /// public static List background; } public struct Audio3D { /// /// Earth Attack sound. /// public static AudioCue earthAttack; /// /// Water Attack sound. /// public static AudioCue waterAttack; /// /// Air Attack sound. /// public static AudioCue airAttack; /// /// 3D Cue used with jump sound. /// public static AudioCue jump; /// /// 3D Cue used with hit sound. /// public static AudioCue smackDownHit; /// /// 3D Cue used with walk sound. /// public static AudioCue walking; /// /// 3D Cue used with terrainMod sound. /// public static AudioCue terrainMod; /// /// 3D Cue used with fire attack sound. /// /// Sound played when player finds a Key. /// public static AudioCue KeyFound; /// /// Sound played when Start button is pressed in menu system. /// public static AudioCue MenuStart; /// /// Sound played when Back button is pressed in menu system. /// public static AudioCue MenuBack; /// /// Sound played when Up button is pressed in menu system. /// public static AudioCue MenuUp; /// /// Sound played when Down button is pressed in menu system. /// public static AudioCue MenuDown; /// /// Sound played when Left button is pressed in menu system. /// public static AudioCue MenuLeft; /// /// Sound played when Right button is pressed in menu system. /// public static AudioCue MenuRight; /// /// Sound played when Player selection is changed in menu system. /// public static AudioCue MenuShuffleRight; /// /// Sound played when Player selection is changed in menu system. /// public static AudioCue MenuShuffleLeft; /// /// Sound played when Dpad button is pressed in Game. /// public static AudioCue MenuDPad(); } } /// /// Supports 2D and 3D audio in the form of an AudioCue. /// Functions are named after the effect they use in simple functions that /// wrap the audio file name, making it easy to change sounds that are /// scattered throughout the engine by changing a single reference. /// public static class AudioProcessor { /// /// XNA audio engine API /// static AudioEngine audioEngine; /// /// Keeps metranome synchronous time /// public static Stopwatch currentGameTime; /// /// Delay before playing another walk cue. /// Used to stop too many sounds from being played at once. /// public Stopwatch walkingSoundTimer; /// /// Delay before playing another terrainMod cue. /// Used to stop too many sounds from being played at once. /// public Stopwatch terrainModSoundTimer; /// /// Background music queue. /// Effects don't have cues b/c the sound isn't looped. /// static List cues; /// /// True if background music is playing. /// /// /// Used for 3D sound.. don't play if out of range.. wastes proccesses /// public static float SOUND_CUTOFF_DISTANCE = 1500; /// /// Loads audioEngine, soundBank, music waveBank, and effects waveBank. /// Hand out instruments to the musicians. /// public static void Initialize(XmlNode node) { // Clear music cue list cues = new List(); // Used to measure track elapsed time. currentGameTime = new Stopwatch(); currentGameTime.Start(); // Load Audio xml file and associate with engine sounds if (node.Name == "AudioConfig") { try { // Load Audio Engine Files audioEngine = new AudioEngine("Content/_audio/Elemental.xgs"); soundBank = new SoundBank(audioEngine, "Content/_audio/Sound Bank.xsb"); music = new WaveBank(audioEngine, "Content/_audio/Music.xwb"); effects = new WaveBank(audioEngine, "Content/_audio/Effects.xwb"); // Load Background Sounds if (node.ChildNodes[i].Name() == "Background") { for (int i = 0; i < node.ChildNodes; i++) { // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "EarthAttack") { AudioBackground.background = new AudioCue(node.ChildNodes[i].Value); } } } // Load Menu Sounds if (node.ChildNodes[i].Name() == "Menu") { for (int i = 0; i < node.ChildNodes; i++) { // ABSTRACT = CREATE ABSTRACT ENGINE SOUND CLASS // ALLOW GAME OVERRIDE OF SINGLE IF STATEMENT LIKE ONE BELOW // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuStart") { Audio2D.MenuStart = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuBack") { Audio2D.MenuBack = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuShuffleRight") { Audio2D.MenuShuffleRight = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuShuffleLeft") { Audio2D.MenuShuffleLeft = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuUp") { Audio2D.MenuUp = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuDown") { Audio2D.MenuDown = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuLeft") { Audio2D.MenuLeft = new AudioCue(node.ChildNodes[i].Value); } // Get Child Nodes and replace strings GetCue methods if (node.ChildNodes[i].Name() == "MenuRight") { Audio2D.MenuRight = new AudioCue(node.ChildNodes[i].Value); } } } // Load Engine Sounds if (node.ChildNodes[i].Name() == "Engine") { for (int i = 0; i < node.ChildNodes; i++) { if (node.ChildNodes[i].Name() == "EarthAttack") { Audio3D.earthAttack.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "Jump") { Audio3D.jump.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "Hit") { Audio3D.smackDownHit.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "Walking") { Audio3D.walking.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "TerrainMod") { Audio3D.terrainMod.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "FireBurst") { Audio3D.fireAttack.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "WaterBurst") { Audio3D.waterAttack.cue = new AudioCue(node.ChildNodes[i].Value); } if (node.ChildNodes[i].Name() == "AirBurst") { Audio3D.airAttack.cue = new AudioCue(node.ChildNodes[i].Value); } walkingSoundTimer.Start(); terrainModSoundTimer.Start(); /// Play's level song. PlayLevelSong(orchestration.Attributes["background"].Value); } } } catch { System.Diagnostics.Debug.WriteLine("Error reading music filename"); return; } } } /// /// Update XNA audio engine. /// See if user has requested to mute or unmute music. /// public static void Update() { // if (Statics.SystemSettings.music && !musicPlaying) { for (int i = 0; i < cues.Count; i++) { cues[i].Resume(); musicPlaying = true; } } else if (!Statics.SystemSettings.music && musicPlaying) { for (int i = 0; i < cues.Count; i++) { cues[i].Pause(); musicPlaying = false; } } audioEngine.Update(); } #region 3D Sounds /// /// Sound used in Fire attacks. /// Not based on particles, unlike Attack. /// /// Class containing cues for Player-based sounds. /// Location of the Attacker. /// Location of the Listener. public static void PlayAudio(AudioCue audioCue) { //check the distance first! if (Vector3.Distance(audioCue.emitterPosition, audioCue.listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } pSound.fireAttack.cue.Apply3D(audioCue.emitterPosition, audioCue.listenerPosition); if (!pSound.fireAttack.cue.IsPlaying) { pSound.fireAttack.cue = AudioProcessor.soundBank.GetCue("FireBurst"); pSound.fireAttack.cue.Apply3D(pSound.fireAttack.listener, pSound.fireAttack.emitter); pSound.fireAttack.cue.Play(); } if (pSound.terrainModSoundTimer.ElapsedMilliseconds > 900) { pSound.terrainMod.cue = soundBank.GetCue("TerrainMod"); pSound.terrainMod.cue.Apply3D(pSound.terrainMod.listener, pSound.terrainMod.emitter); pSound.terrainMod.cue.Play(); pSound.terrainModSoundTimer = Stopwatch.StartNew(); } } #endregion /// /// Kills all Attack sounds. /// /// Wrapper contatining attack cues. public static void StopAttack(EngineSounds pSound) { // Stop Sound if (pSound.earthAttack.cue != null) { pSound.earthAttack.cue.Stop(AudioStopOptions.Immediate); } if (pSound.waterAttack.cue != null) { pSound.waterAttack.cue.Stop(AudioStopOptions.Immediate); } if (pSound.airAttack.cue != null) { pSound.airAttack.cue.Stop(AudioStopOptions.Immediate); } } /// /// Play's a song in the background. /// /// Song Name contained in the loaded SoundBank. public static void PlayLevelSong(string songName) { // Kill everthing for (int i = 0; i < cues.Count; i++) { cues[i].Stop(AudioStopOptions.Immediate); } // Unload all the cues cues.Clear(); // Start new theme Cue playCue = soundBank.GetCue(songName); musicPlaying = true; cues.Add(playCue); if (Statics.SystemSettings.music) { playCue.Play(); } } #region 2D Sounds /// /// Base function called by all 2D sounds. /// /// Name of cue to play public static void PlayCue2D(string cueName) { if (Statics.SystemSettings.soundFX) { soundBank.PlayCue(cueName); } } #endregion } #region Audio Cue /// /// Contains the neccessary information for 2D and 3D sound processing. /// public class AudioCue { int length; int starttime; Enums.AudioType audioType; // 3D components /// /// Cue contatining sound used in 3D audio. /// public Cue cue; /// /// A sound generator. /// public AudioEmitter emitter; /// /// A sound receiver. /// public AudioListener listener; // Create a 2D sound public AudioCue(int TrackLength, string TrackName, Enums.AudioType type) { cue = AudioProcessor.soundBank.GetCue(TrackName); length = TrackLength; audioType = type; } // Create a 3D sound public AudioCue(int TrackLength, string TrackName, Enums.AudioType type, AudioEmitter EmitterObject, AudioListener ListenerObject) { cue = AudioProcessor.soundBank.GetCue(TrackName); length = TrackLength; emitter = EmitterObject; listener = ListenerObject; } } #endregion }