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; /// /// Contains the neccessary information to us a 3D sound cue. /// public class Cue3D { /// /// Cue contatining sound used in 3D audio. /// public Cue cue; /// /// A sound generator. /// public AudioEmitter emitter = new AudioEmitter(); /// /// A sound receiver. /// public AudioListener listener = new AudioListener(); } /// /// Sounds specific to particles /// public class ParticleSounds { /// /// Earth Attack sound. /// public Cue3D earthAttack = new Cue3D(); /// /// Water Attack sound. /// public Cue3D waterAttack = new Cue3D(); /// /// Air Attack sound. /// public Cue3D airAttack = new Cue3D(); /// /// Constructor for particle sounds. /// public ParticleSounds() { earthAttack.cue = Audio.soundBank.GetCue("EarthBurst"); waterAttack.cue = Audio.soundBank.GetCue("WaterBurst"); airAttack.cue = Audio.soundBank.GetCue("AirBurst"); } } /// /// Sounds specific to players /// public class PlayerSounds { /// /// 3D Cue used with jump sound. /// public Cue3D jump = new Cue3D(); /// /// 3D Cue used with hit sound. /// public Cue3D smackDownHit = new Cue3D(); /// /// 3D Cue used with walk sound. /// public Cue3D walking = new Cue3D(); /// /// 3D Cue used with terrainMod sound. /// public Cue3D terrainMod = new Cue3D(); /// /// 3D Cue used with fire attack sound. /// public Cue3D fireAttack = new Cue3D(); /// /// Delay before playing another walk cue. /// Used to stop too many sounds from being played at once. /// public Stopwatch walkingSoundTimer = new Stopwatch(); /// /// Delay before playing another terrainMod cue. /// Used to stop too many sounds from being played at once. /// public Stopwatch terrainModSoundTimer = new Stopwatch(); /// /// Player sounds constructor. /// public PlayerSounds() { jump.cue = Audio.soundBank.GetCue("Jump"); smackDownHit.cue = Audio.soundBank.GetCue("Hit"); walking.cue = Audio.soundBank.GetCue("Walking"); terrainMod.cue = Audio.soundBank.GetCue("TerrainMod"); fireAttack.cue = Audio.soundBank.GetCue("FireBurst"); walkingSoundTimer.Start(); terrainModSoundTimer.Start(); } } /// /// Supports 2D and 3D audio. /// 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 Audio { /// /// XNA audio engine API /// static AudioEngine audioEngine; /// /// Background Music /// static WaveBank music; /// /// Sound Effects /// static WaveBank effects; /// /// Provides access to WaveBank entries /// public static SoundBank soundBank; /// /// Holds the xml branch contatining music data. /// static XmlNode orchestration; /// /// Background music queue. Effects don't need queues b/c they aren't looped. /// static List cues; /// /// True if background music is playing. /// static bool musicPlaying = true; /// /// 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. /// public static void Initialize() { // 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"); if (orchestration != null) { orchestration.RemoveAll(); } // Clear music cue list cues = new List(); } /// /// Loads xml data for audio tag and play's level song. /// /// Audio xml node. public static void LoadXML(XmlNode musicNode) { // Save for later orchestration = musicNode; if (orchestration.Name == "music") { try { PlayLevelSong(orchestration.Attributes["background"].Value); } catch { System.Diagnostics.Debug.WriteLine("Error reading music filename"); return; } } } /// /// 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(); } } /// /// 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 coming from a particle on the board, used in attacks. /// Sound is attached to the particle itself. /// /// Sound wrapper containing particle-based sounds. /// Particle emmitting sound. /// Player listening to sounds. /// Used to cut off sound after a given time. public static void Attack(ParticleSounds pSound, Particle particle, Mass listener, float timestep) { //check the distance first! if (Vector3.Distance(particle.mass.currentPosition, listener.currentPosition) > SOUND_CUTOFF_DISTANCE) {return;} if (timestep < 1000){timestep = 1.0f;} else{timestep /= 1000.0f;} pSound.earthAttack.emitter.Position = particle.mass.currentPosition * timestep; pSound.earthAttack.emitter.Velocity = particle.mass.velocity; pSound.earthAttack.listener.Position = listener.currentPosition * timestep; pSound.earthAttack.listener.Velocity = listener.velocity; pSound.earthAttack.cue.Apply3D(pSound.earthAttack.listener, pSound.earthAttack.emitter); if (!pSound.earthAttack.cue.IsPlaying) { pSound.earthAttack.cue = Audio.soundBank.GetCue("EarthBurst"); pSound.earthAttack.cue.Apply3D(pSound.earthAttack.listener, pSound.earthAttack.emitter); pSound.earthAttack.cue.Play(); } } /// /// Kills all Attack sounds. /// /// Wrapper contatining attack cues. public static void StopAttack(ParticleSounds 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); } } /// /// 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 FireAttack(PlayerSounds pSound, Vector3 emitterPosition, Vector3 listenerPosition) { //check the distance first! if (Vector3.Distance(emitterPosition, listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } pSound.fireAttack.emitter.Position = emitterPosition; pSound.fireAttack.listener.Position = listenerPosition; pSound.fireAttack.cue.Apply3D(pSound.fireAttack.listener, pSound.fireAttack.emitter); if (!pSound.fireAttack.cue.IsPlaying) { pSound.fireAttack.cue = Audio.soundBank.GetCue("FireBurst"); pSound.fireAttack.cue.Apply3D(pSound.fireAttack.listener, pSound.fireAttack.emitter); pSound.fireAttack.cue.Play(); } } /// /// Sound used when Player jumps. /// /// Class containing cues for Player-based sounds. /// Location of the Attacker. /// Location of the Listener. public static void Jump(PlayerSounds pSound, Vector3 emitterPosition, Vector3 listenerPosition) { //check the distance first! if (Vector3.Distance(emitterPosition, listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } pSound.jump.cue = soundBank.GetCue("Jump"); pSound.jump.emitter.Position = emitterPosition; pSound.jump.listener.Position = listenerPosition; pSound.jump.cue.Apply3D(pSound.jump.listener, pSound.jump.emitter); pSound.jump.cue.Play(); } /// /// Sound used when Player gets hit. /// /// Class containing cues for Player-based sounds. /// Location of the Attacker. /// Location of the Listener. public static void Hit(PlayerSounds pSound, Vector3 emitterPosition, Vector3 listenerPosition) { //check the distance first! if (Vector3.Distance(emitterPosition, listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } pSound.smackDownHit.cue = soundBank.GetCue("Hit"); pSound.smackDownHit.emitter.Position = emitterPosition; pSound.smackDownHit.listener.Position = listenerPosition; pSound.smackDownHit.cue.Apply3D(pSound.smackDownHit.listener, pSound.smackDownHit.emitter); pSound.smackDownHit.cue.Play(); } /// /// Sound used when Player is walking. /// /// Class containing cues for Player-based sounds. /// Location of the Attacker. /// Location of the Listener. public static void Walking(PlayerSounds pSound, Vector3 emitterPosition, Vector3 listenerPosition) { //check the distance first! if (Vector3.Distance(emitterPosition, listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } //pSound.walking.emitter.Position = emitterPosition; //pSound.walking.listener.Position = listenerPosition; //pSound.walking.cue.Apply3D(pSound.walking.listener, pSound.walking.emitter); //if (pSound.walkingSoundTimer.ElapsedMilliseconds > 100) //{ // pSound.walking.cue = soundBank.GetCue("Walking"); // pSound.walking.cue.Apply3D(pSound.walking.listener, pSound.walking.emitter); // pSound.walking.cue.Play(); // pSound.walkingSoundTimer = Stopwatch.StartNew(); //} } /// /// Sound used when Player terrainMods. /// /// Class containing cues for Player-based sounds. /// Location of the Attacker. /// Location of the Listener. public static void TerrainMod(PlayerSounds pSound, Vector3 emitterPosition, Vector3 listenerPosition) { //check the distance first! if (Vector3.Distance(emitterPosition, listenerPosition) > SOUND_CUTOFF_DISTANCE) { return; } pSound.terrainMod.emitter.Position = emitterPosition; pSound.terrainMod.listener.Position = listenerPosition; pSound.terrainMod.cue.Apply3D(pSound.terrainMod.listener, pSound.terrainMod.emitter); 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 #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); } } /// /// Sound played when player finds a Key. /// public static void KeyFound() { PlayCue2D("KeyFound"); } /// /// Sound played when Start button is pressed in menu system. /// public static void MenuStart() { PlayCue2D("Tin"); } /// /// Sound played when Back button is pressed in menu system. /// public static void MenuBack() { PlayCue2D("Tin"); } /// /// Sound played when Up button is pressed in menu system. /// public static void MenuUp() { PlayCue2D("Tin"); } /// /// Sound played when Down button is pressed in menu system. /// public static void MenuDown() { PlayCue2D("Tin"); } /// /// Sound played when Left button is pressed in menu system. /// public static void MenuLeft() { PlayCue2D("Tin"); } /// /// Sound played when Right button is pressed in menu system. /// public static void MenuRight() { PlayCue2D("Tin"); } /// /// Sound played when Player selection is changed in menu system. /// public static void MenuPlayerShuffleRight() { PlayCue2D("Tin"); } /// /// Sound played when Player selection is changed in menu system. /// public static void MenuPlayerShuffleLeft() { PlayCue2D("Tin"); } /// /// Sound played when Dpad button is pressed in Game. /// public static void MenuDPad() { PlayCue2D("Tin"); } #endregion } }