Table of Contents
AudioManager - One interface, many implementations
If you look in BaseApp.h you'll see this near the bottom:
AudioManager * GetAudioManager(); //supply this yourself
It means it expects you to implement this function somewhere in your App code. Shared-level components and code will be able to use audio through the AudioManager interface, without knowing how you implemented it. (Just standard C++ subclassing with virtuals)
The minimum you have to do is this:
AudioManager g_audioManager; //to disable sound AudioManager * GetAudioManager() { return &g_audioManager; }
The above will let everything “think” they are using sound functions, but do nothing. To actually hear sound on windows (or iOS using FMOD), do:
#include "Audio/AudioManagerFMOD.h" AudioManagerFMOD g_audioManager; //play with the FMOD implementation AudioManager * GetAudioManager() { return &g_audioManager; }
RTSimpleApp uses #ifdefs to use the correct implementation for the correct platform.
BaseApp will run Init() on it, you don't.
Playing a sound
GetAudioManager()->Play("click.wav");
Internally, the audio manager will play it and keep the sound object around for future calls.
Caching/preloading manually
Auto caching is good enough, but if you notice jerks in your game the first time audio is loading you should probably preload them.
GetAudioManager()->Preload("click.wav");
All of audio implementations handle playing compressed music (ogg or mp3, or both) and at a minimum, .wav sounds for effects with mixing. FMOD supports more formats like .mid and .xm as well.
Music has its own special way of being called by using the bIsMusic flag:
//defined as: virtual AudioHandle Play(string fName, bool bLooping = false, bool bIsMusic = false, bool bAddBasePath = true, bool bForceStreaming = false); GetAudioManager()->Play("song.ogg", false, true);
When you say, “this is music” here is what happens:
- If the same song is already playing, the call is ignored
- If another song is playing, it kills it first
- The file is streamed from disk, not loaded or cached
- On systems that can only decode one compressed audio in hardware at a time, it is reserved for music
- If AudioManager::SetMusicEnabled was set with false, it is ignored
- The volume it plays at is set by AudioManager::SetMusicVol
Advanced controls with AudioHandles
If you want to be able to kill a sound or perform other effects on it during playback, you need to keep track of the AudioHandle returned from the Play() command. (it's just a uint32)
//init somewhere AudioHandle npcTalk = 0; //entities AI sees the player npcTalk = GetAudioManager()->Play(taunt.wav); GetAudioManager()->SetPan(npcTalk, -1.0f); //left speaker only GetAudioManager()->SetVol(npcTalk, 1.0f); //max volume //but soon after he starts to taunt, he is killed and should do his deathscream GetAudioManager()->Stop(npcTalk); npcTalk = GetAudioManager()->Play("scream.wav");
Using old/dead handles doesn't cause problems.
Note: Some of the more advanced audio functions such as AudioManager::SetPan and AudioManager::SetFrequency are not available on all sound implementations.
Controlling memory
You know that FPS debug text that always shows up in the examples? The A:<number> is how much memory is allocated in audio. (if it says 0, it means this implementation doesn't know and is returning 0 from AudioManager::GetMemoryUsed)
If you are running low on memory you can use AudioManager::KillCachedSounds between levels, or even during levels. Its parameters allow you to further refine what is killed; including by last usage time and priority level.
Good vibrations
For some reason its the AudioManager's job to phone vibration. Called vibration on a platform that can't do it (like PC) will be ignored or write “VIBRATE!” to the debug text.
GetAudioManager()->Vibrate(); //hmm, I may need a VibrateEx() at some point with more options.
If GetAudioManager()→SetVibrateDisabled was set to true, it will be ignored.