#region File Description //----------------------------------------------------------------------------- // SoundManager.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using RobotGameData.Camera; #endregion namespace RobotGameData.Sound { #region SoundElement /// /// a sound structure with sound cue and emitter for 3D playback. /// public class SoundElement { public Cue cue = null; public AudioEmitter emitter = null; public string Name { get { return cue.Name; } } } #endregion /// /// It reads sound data and plays sound and supports 3D positional sound. /// When playing sound, it creates SoundElement class internally and /// manages a sound pool. /// In order to load sound data, the files, which have been created by /// Microsoft Cross-Platform Audio Creation Tool (XACT), such as .xgs, /// .xwb, and .xsb, are needed. /// public class SoundManager { #region Fields /// /// If set to false, all of the related functions get turned off. /// bool soundOn = true; static AudioEngine audioEngine = null; static WaveBank waveBank = null; static SoundBank soundBank = null; static Dictionary audioCategories = new Dictionary(); // Keep track of all the 3D sounds that are currently playing. static List activeSounds = new List(); // Keep track of spare SoundObject instances, so we can reuse them. // Otherwise we would have to allocate new instances each time // a sound was played, which would create unnecessary garbage. static Stack soundPool = new Stack(); // The listener describes the ear which is hearing 3D sounds. // This is usually set to match the camera. AudioListener listener = new AudioListener(); // The emitter describes an entity which is making a 3D sound. AudioEmitter emitter = new AudioEmitter(); static bool pauseAll = false; #endregion #region Properties public static AudioEngine AudioEngine { get { return audioEngine; } } public static WaveBank WaveBank { get { return waveBank; } } public static SoundBank SoundBank { get { return soundBank; } } public static bool PauseAll { get { return pauseAll; } } #endregion /// /// Constructor. /// public SoundManager() { audioCategories.Clear(); pauseAll = false; } /// /// applies 3D sound to the listener. /// /// listener position /// listener direction /// listener up vector /// listener velocity public void ApplyEmitter(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) { // Update listener by the current camera this.listener.Position = position; this.listener.Forward = direction; this.listener.Up = up; this.listener.Velocity = velocity; } /// /// processes the sound pool and the 3D sound playback. /// XNA's AudioEngine is updated here. /// public void Update() { if (soundOn == false) return; // Loop over all the currently playing 3D sounds. int index = 0; while (index < activeSounds.Count) { SoundElement sound = activeSounds[index]; if (sound.cue.IsStopped) { // If the cue has stopped playing, dispose it. //sound.cue.Dispose(); sound.cue = null; sound.emitter = null; // Store the SoundElement instance for future reuse. soundPool.Push(sound); // Remove it from the active list. activeSounds.RemoveAt(index); } else { if (sound.emitter != null) { // If the cue is still playing, update its 3D settings. Apply3D(sound); } index++; } } // Update the XACT engine. AudioEngine.Update(); } /// /// stops every sound and removes every sound member. /// public void Dispose() { if (soundOn == false) return; StopSound(); audioCategories.Clear(); SoundBank.Dispose(); WaveBank.Dispose(); AudioEngine.Dispose(); } /// /// initialize all sound members. /// creates and initializes the XNA's AudioEndgine. /// /// /// /// public void Initialize( string globalSettingsFileName, string waveBankFileName, string soundBankFileName) { if (soundOn == false) return; // Create audio engine audioEngine = new AudioEngine(globalSettingsFileName); if (audioEngine == null) { throw new ArgumentException( "The audio engine could not be created."); } // Create wave bank waveBank = new WaveBank(audioEngine, waveBankFileName); if (waveBank == null) { throw new ArgumentException( "The wave bank could not be created."); } // Create sound bank soundBank = new SoundBank(audioEngine, soundBankFileName); if (soundBank == null) { throw new ArgumentException( "The sound bank could not be created."); } } /// /// adds a sound category. /// /// name public void AddSoundCategory(string categoryName) { if (soundOn == false) return; AudioCategory audioCategory = AudioEngine.GetCategory(categoryName); audioCategories.Add(categoryName, audioCategory); } /// /// plays the sound for 3D. /// /// entried sound name /// 3D emitter /// playing sound cue public Cue PlaySound3D(string soundName, AudioEmitter emitter) { SoundElement sound; if (soundPool.Count > 0) { // If possible, reuse an existing Cue3D instance. sound = soundPool.Pop(); } else { // Otherwise we have to allocate a new one. sound = new SoundElement(); } // Fill in the cue and emitter fields. sound.cue = soundBank.GetCue(soundName); sound.emitter = emitter; // Set the 3D position of this cue, and then play it. Apply3D(sound); sound.cue.Play(); // Remember that this cue is now active. activeSounds.Add(sound); return sound.cue; } /// /// plays the sound. /// /// entried sound name /// playing sound cue public static Cue PlaySound(string soundName) { SoundElement sound = null; if (soundPool.Count > 0) { // If possible, reuse an existing Cue3D instance. sound = soundPool.Pop(); } else { // Otherwise we have to allocate a new one. sound = new SoundElement(); } // Fill in the cue and emitter fields. sound.cue = soundBank.GetCue(soundName); sound.cue.Play(); // Remember that this cue is now active. activeSounds.Add(sound); return sound.cue; } /// /// pauses the sound. /// public void PauseSound() { if (soundOn == false || pauseAll ) return; for (int i = 0; i < activeSounds.Count; i++) PauseSound(activeSounds[i]); pauseAll = true; } /// /// resumes the sound /// public void ResumeSound() { if (soundOn == false || pauseAll == false) return; for (int i = 0; i < activeSounds.Count; i++) ResumeSound(activeSounds[i]); pauseAll = false; } /// /// stops the sound /// /// playing sound public bool StopSound(Cue cue) { if (soundOn == false || cue == null) return false; if (cue.IsPaused || cue.IsPlaying) { cue.Stop(AudioStopOptions.Immediate); return true; } return false; } /// /// stop all sounds. /// public void StopSound() { if (soundOn == false) return; for (int i = 0; i < activeSounds.Count; i++) StopSound(activeSounds[i]); } /// /// sets volume. /// /// /// public void SetVolume(string categoryName, float volume) { if (soundOn == false) return; if (!audioCategories.ContainsKey(categoryName)) { throw new InvalidOperationException("Cannot find the category : " + categoryName); } audioCategories[categoryName].SetVolume( MathHelper.Clamp(volume, 0.0f, 1.0f)); } /// /// determines whether a sound is being played. /// /// playing sound cue /// true or false public bool IsPlaying(Cue cue) { if (soundOn == false) return false; if (cue != null) return cue.IsPlaying; return false; } /// /// determines whether a sound is being played. /// /// playing sound cue /// true or false public bool IsPause(Cue cue) { if (soundOn == false) return false; if (cue != null) return cue.IsPaused; return false; } /// /// applies 3D position to sound element. /// /// private void Apply3D(SoundElement element) { emitter.Position = element.emitter.Position; emitter.Forward = element.emitter.Forward; emitter.Up = element.emitter.Up; emitter.Velocity = element.emitter.Velocity; element.cue.Apply3D(listener, emitter); } /// /// pauses the sound. /// /// playing sound element private bool PauseSound(SoundElement sound) { if (soundOn == false || sound == null || sound.cue == null) return false; if (sound.cue.IsPlaying) { sound.cue.Pause(); return true; } return false; } /// /// resumes the sound. /// /// paused sound element private bool ResumeSound(SoundElement sound) { if (soundOn == false || sound == null || sound.cue == null) return false; if (sound.cue.IsPaused) { sound.cue.Resume(); return true; } return false; } /// /// stops the sound. /// /// playing sound element private bool StopSound(SoundElement sound) { if (soundOn == false || sound == null || sound.cue == null) return false; if (sound.cue.IsPaused || sound.cue.IsPlaying) { sound.cue.Stop(AudioStopOptions.Immediate); return true; } return false; } } }