330 likes | 457 Views
Adding Audio to Your Game Chapter 27. Cameron Haider. Two Choices for Sound. Default Sound API ( SoundEffects Class) XACT (Cross-platform Audio Creation Tool). Default Sound API. SoundEffect and SoundEffectInstance classes. Capable of streaming audio, must use wav format.
E N D
Adding Audio to Your GameChapter 27 Cameron Haider
Two Choices for Sound • Default Sound API (SoundEffects Class) • XACT (Cross-platform Audio Creation Tool)
Default Sound API • SoundEffect and SoundEffectInstance classes. • Capable of streaming audio, must use wav format. • Slower runtime than using the content pipeline. • May build audio in the content pipeline, source does not matter. • Mp3, wma, wav and others may be loaded through the ContentManager, thus converting them into the XNB (XNA Framework Content Pipeline Binary file) format.
XACT (Cross-platform Audio Creation Tool) • May only import uncompressed audio (pcmwav and aiff) • Allows separation of Audio engineer’s and programmer’s responsibilities.
Default API Example Adding sound to Lab1
Declare SoundEffects publicclassGame1 : Microsoft.Xna.Framework.Game { *** *** SoundEffecthitRock; SoundEffect fire; public Game1() { *** *** }
Define SoundEffects in Content Loader protectedoverridevoidLoadContent() { *** *** hitRock = Content.Load<SoundEffect>("Sounds\\hitrock"); fire = Content.Load<SoundEffect>("Sounds\\fire"); }
Playing Sound Asteroid Hit By Bullet privatevoidCheckCollisions(GameTimegameTime) { *** *** foreach (Sprite a in asteroids) { *** *** foreach (Sprite b in bullets) { *** *** if (bRectangle.Intersects(aRectangle)) // rough collision check if (PixelCollision( // exact collision check aTransform, a.Width, a.Height, a, bTransform, b.Width, b.Height, b)) { hitRock.Play(); dead.Add(a); dead.Add(b); } } } } • As Simple as calling the Play method from a SoundEffectObject defined in the Content loader. • hitRock= Content.Load<SoundEffect>("Sounds\\hitrock");
Playing SoundWeapon Fire privatevoidFireBullet(GameTimegameTime) { *** //Create Projectile *** fire.Play(); } • Again, simiply add a function call to any SoundEffectObject defined in the Content loader. • fire = Content.Load<SoundEffect>("Sounds\\fire");
Summery of SoundEffect Class • Creation is a simple as: • SoundEffect fire = Content.Load<SoundEffect>("Sounds\\fire"); • Use of the sound effect is a simple as: • fire.Play();
Increased Control ThroughSoundEffectInstance Class • SoundEffectInstance’s are defined from an instance of the SoundEffect class • If creating multiple SoundEffectInstances from a single defined SoundEffect object, all SoundEffectInstances will use the memory resources reserved by the original SoundEffect object. Destroying the SoundEffect will break all SoundEffectInstances created from it. • Various additional methods and properties become available when using the SoundEffectInstance.
SoundEffectInstanceMethods and Properties • methods: Play, Pause, Resume, Stop, Dispose (releases resources – may create a runtime null pointer exception,) Apply3D (Applies 3D position to the sound effect) • The properties Pan (ratio of left to right speaker output,) IsLooped, Pitch, Volume may be either retrieved or set. • Further properties include: IsDisposed (check if resources are still held,) State (returns the SoundState: playing, paused or stopped)
Declare SoundEffectInstance publicclassGame1 : Microsoft.Xna.Framework.Game { *** *** SoundEffectInstancebackgroundSound; public Game1() { *** *** }
Define SoundEffectsInstance in Content Loader protectedoverridevoidLoadContent() { *** *** backgroundSound = Content.Load<SoundEffect>("Sounds\\background").CreateInstance(); } Creates an Instance of the SoundEffectInstance Class Creates an Instance of the SoundEffect Class
Set SoundEffectInstance to Loop protectedoverridevoidLoadContent() { *** *** backgroundSound = Content.Load<SoundEffect>("Sounds\\background").CreateInstance(); // Set the SoundEffectInstance’sIsLooped property to true // Must be set before the SoundEffectInstance’s // Play() method is called backgroundSound.IsLooped= true; }
Playing Sound with SoundEffectInstance if (asteroids.Count == 0) { if (backgroundSound.State == SoundState.Playing) backgroundSound.Stop(); elsebackgroundSound.Play(); *** } • I added these if statements to my update method. The above statement runs every time the level is cleared, the statement below runs if the M key is held down. Both of them will then check if the background music is playing, it will stop, else it will play. if (keyboard.IsKeyDown(Keys.M)&&!(last.IsKeyDown(Keys.M))) { if (backgroundSound.State == SoundState.Playing) backgroundSound.Stop(); elsebackgroundSound.Resume(); }
Disposing of SoundEffectInstance if (keyboard.IsKeyDown(Keys.Delete) ) { backgroundSound.Dispose();} • The SoundEffectInstance’sDispose() method, releases the SoundEffect’s memory resource usage. If you expect the SoundEffect may be disposed, you must add an IsDisposedproperity check before every possible Play() or Resume() call, for the disposed SoundByte. if (asteroids.Count == 0) { if(!backgroundSound.IsDisposed) { if (backgroundSound.State == SoundState.Playing) backgroundSound.Stop(); elsebackgroundSound.Play(); } *** } if (keyboard.IsKeyDown(Keys.M)&&!(last.IsKeyDown(Keys.M))) { if(!backgroundSound.IsDisposed) { if (backgroundSound.State == SoundState.Playing) backgroundSound.Stop(); elsebackgroundSound.Resume(); } }
XACT - Example • Launch XACT and create a new xact project inside of the sound content directory of your visual studio project.
Create a new Wave Bank and Sound Bank • Right Click both Wave Bank and Sound Bank, create a new file for each. • Both of the new banks should open in separate windows, click in the middle of the Wave Bank window and insert your wav files. • Drag the new files from the wave bank into the bottom half of the Sound Bank. This will populate the top half of the Sound bank at the same time.
Waves, Sounds and Cues • Waves are uncompressed audio data. • Sounds are collections of instructions to regulate how the wave files are played. • Cues are the objects called to play specified Sounds. With XACT you should only be referring to Cue objects, to play and control your audio. You can either save the Cue objects in memory or retrieve them from your xact project for every event. An example modifying a Cue to simulate 3D positioning: Cue.Apply3D(AudioListner listener, AudioEmitter emitter); //AudioListener and AdioEmitter simply contain: Speed, //Magnitude and Direction of both the noise’s origin and our listener
Sounds – Control Additional Effects • Categories: Group Sounds together • RPC: Run-Time parameter controls, aka Sliders • DSP: digital signal processing effects, such as reverb • Compression
Sounds - RPC An example of this is when Audio waves and pitches for an engine are adjusted as the gear and RPMs change. Run-Time parameter controls are known as sliders because some attribute/s of the sound is altered based on a graph and some variable.
Sounds - DSP Digital Signal Processing effects, such as reverb
Sounds - Compression Allows sound quality to be set.
Global and Cue, Variables Variables are either Global or Cue based. They can be applied to RPCs.
Adding the XACT to the Game Project Add the XACT project you saved as an existing object the same way you would add a sprite. There is no need to add sounds which will be added to your XACT Project.
Declare AudioEngine, WaveBank and SoundBank Objects publicclassGame1 : Microsoft.Xna.Framework.Game { *** *** AudioEngineaudioEngine; WaveBankwaveBank; SoundBanksoundBank; public Game1() { *** *** }
Define XACT Objects in Content Loader protectedoverridevoidLoadContent() { *** *** audioEngine = newAudioEngine("Content/Sounds/xact.xgs"); waveBank = newWaveBank(audioEngine, "Content/Sounds/Wave Bank.xwb"); soundBank = newSoundBank(audioEngine, "Content/Sounds/Sound Bank.xsb"); } You will also need to add an Update() method call for your AudioEngine, into the games update method. protectedoverridevoid Update(GameTimegameTime) { audioEngine.Update(); *** *** }
Looping Sound in XACT This is done from inside the XACT application. Select the file from the Sound bank and the file details will display on the lower left hand side. In the Looping section of the detail window, either input a number for the loop count or mark the infinite option.
Playing Sound Asteroid Hit By Bullet privatevoidCheckCollisions(GameTimegameTime) { *** *** foreach (Sprite a in asteroids) { *** *** foreach (Sprite b in bullets) { *** *** if (bRectangle.Intersects(aRectangle)) // rough collision check if (PixelCollision( // exact collision check aTransform, a.Width, a.Height, a, bTransform, b.Width, b.Height, b)) { soundBank.PlayCue("hitrock"); dead.Add(a); dead.Add(b); } } } } As Simple as calling the PlayCue method from our Sound Bank Object. The filename used in the paramater is the name given in the cue list.
Playing SoundWeapon Fire privatevoidFireBullet(GameTimegameTime) { *** //Create Projectile *** soundBank.PlayCue("fire"); } • Send the soundBank’sPlayCue() method, the Cue name of the desired sound.
Playing Sound Background Soundwith XACT • The following is the changes I made while converting the background music from the default API to XACT. • CuebackgroundSound; • protectedoverridevoidLoadContent() • { • *** • *** • backgroundSound= soundBank.GetCue("background"); • backgroundSound.Play(); • } • if(asteroids.Count == 0) • { • if (backgroundSound.IsPaused) backgroundSound.Resume(); • elsebackgroundSound.Pause(); • *** • } • if(keyboard.IsKeyDown(Keys.M)&&!(last.IsKeyDown(Keys.M))) • { • if (backgroundSound.IsPaused) backgroundSound.Resume(); • elsebackgroundSound.Pause(); • }