Skip to content

Commit

Permalink
Added support for audio auto unloading based on game mode ownership.
Browse files Browse the repository at this point in the history
Now you can tell the game mode owning audio data.
The engine will then be able to remove the data from memory when
no owners are left.

You can still load data without owners, thus letting the old behaviour
happen (unload only when the cache is full).

This permitted most noticeabily to remove the need to pre-load
every map musics at map loading time, and permitted also
to keep the music play between two map mode sharing the same
music file.
  • Loading branch information
Yohann Ferreira committed Jul 11, 2012
1 parent e9933b4 commit f71ba55
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 162 deletions.
9 changes: 3 additions & 6 deletions dat/maps/vt_bronanns_home.lua
Expand Up @@ -31,12 +31,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_bronanns_home_first_floor.lua
Expand Up @@ -36,12 +36,9 @@ contexts[2] = {}
contexts[2].name = "Parent's room"
contexts[2].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/koertes-ccby-birdsongloop16s.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/koertes-ccby-birdsongloop16s.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_kalya_house_exterior.lua
Expand Up @@ -30,12 +30,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_kalya_house_path.lua
Expand Up @@ -30,12 +30,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_layna_center.lua
Expand Up @@ -31,12 +31,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_layna_center_shop.lua
Expand Up @@ -31,12 +31,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_layna_riverbank.lua
Expand Up @@ -31,12 +31,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
9 changes: 3 additions & 6 deletions dat/maps/vt_layna_south_entrance.lua
Expand Up @@ -31,12 +31,9 @@ contexts[0] = {}
contexts[0].name = "Base"
contexts[0].inherit_from = -1

-- The sound files used on this map.
sound_filenames = {}

-- The music files used as background music on this map.
music_filenames = {}
music_filenames[1] = "mus/Caketown_1-OGA-mat-pablo.ogg"
-- The music file used as default background music on this map.
-- Other musics will have to handled through scripting.
music_filename = "mus/Caketown_1-OGA-mat-pablo.ogg"

-- The names of the tilesets used, with the path and file extension omitted
tileset_filenames = {}
Expand Down
95 changes: 55 additions & 40 deletions src/engine/audio/audio.cpp
Expand Up @@ -345,46 +345,62 @@ void AudioEngine::SetListenerVelocity(const float velocity[3]) {
memcpy(_listener_velocity, velocity, sizeof(float) * 3);
}



void AudioEngine::SetListenerOrientation(const float orientation[3]) {
alListenerfv(AL_ORIENTATION, orientation);
memcpy(_listener_orientation, orientation, sizeof(float) * 3);
}



bool AudioEngine::LoadSound(const std::string& filename) {
bool AudioEngine::LoadSound(const std::string& filename, hoa_mode_manager::GameMode* gm) {
if (!DoesFileExist(filename))
return false;

SoundDescriptor* new_sound = new SoundDescriptor();

if (_LoadAudio(new_sound, filename) == false) {
// Add potential ownership of the sound descriptor
if (gm)
new_sound->AddOwner(gm);

if (!_LoadAudio(new_sound, filename)) {
delete new_sound;

// When the sound is used by multiple modes, simply add the ownership there.
std::map<std::string, private_audio::AudioCacheElement>::iterator it = _audio_cache.find(filename);
if (it != _audio_cache.end()) {
it->second.audio->AddOwner(gm);
return true;
}

return false;
}

return true;
}



bool AudioEngine::LoadMusic(const std::string& filename) {
bool AudioEngine::LoadMusic(const std::string& filename, hoa_mode_manager::GameMode* gm) {
MusicDescriptor* new_music = new MusicDescriptor();

if (_LoadAudio(new_music, filename) == false) {
// Add potential ownership of the sound descriptor
if (gm)
new_music->AddOwner(gm);

if (!_LoadAudio(new_music, filename)) {
delete new_music;

// When the music is used by multiple modes, simply add the ownership there.
std::map<std::string, private_audio::AudioCacheElement>::iterator it = _audio_cache.find(filename);
if (it != _audio_cache.end()) {
it->second.audio->AddOwner(gm);
return true;
}

return false;
}

return true;
}



void AudioEngine::PlaySound(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
if (LoadSound(filename) == false) {
Expand All @@ -400,10 +416,8 @@ void AudioEngine::PlaySound(const std::string& filename) {
element->second.last_update_time = SDL_GetTicks();
}



void AudioEngine::PlayMusic(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
if (LoadMusic(filename) == false) {
Expand All @@ -419,10 +433,8 @@ void AudioEngine::PlayMusic(const std::string& filename) {
element->second.last_update_time = SDL_GetTicks();
}



void AudioEngine::StopSound(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
IF_PRINT_WARNING(AUDIO_DEBUG) << "could not stop audio because it was not contained in the cache: " << filename << endl;
Expand All @@ -433,10 +445,8 @@ void AudioEngine::StopSound(const std::string& filename) {
element->second.last_update_time = SDL_GetTicks();
}



void AudioEngine::PauseSound(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
IF_PRINT_WARNING(AUDIO_DEBUG) << "could not pause audio because it was not contained in the cache: " << filename << endl;
Expand All @@ -447,10 +457,8 @@ void AudioEngine::PauseSound(const std::string& filename) {
element->second.last_update_time = SDL_GetTicks();
}



void AudioEngine::ResumeSound(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
IF_PRINT_WARNING(AUDIO_DEBUG) << "could not resume audio because it was not contained in the cache: " << filename << endl;
Expand All @@ -461,10 +469,8 @@ void AudioEngine::ResumeSound(const std::string& filename) {
element->second.last_update_time = SDL_GetTicks();
}



SoundDescriptor* AudioEngine::RetrieveSound(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
return NULL;
Expand All @@ -478,10 +484,8 @@ SoundDescriptor* AudioEngine::RetrieveSound(const std::string& filename) {
}
}



MusicDescriptor* AudioEngine::RetrieveMusic(const std::string& filename) {
map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);

if (element == _audio_cache.end()) {
return NULL;
Expand All @@ -495,7 +499,20 @@ MusicDescriptor* AudioEngine::RetrieveMusic(const std::string& filename) {
}
}

void AudioEngine::RemoveOwner(hoa_mode_manager::GameMode* gm) {
if (!gm)
return;

// Tells all audio descriptor the owner can be removed.
std::map<std::string, AudioCacheElement>::iterator it = _audio_cache.begin();
for (; it != _audio_cache.end(); ++it) {
// If the audio buffers are erased, we can remove the descriptor from the cache.
if (it->second.audio->RemoveOwner(gm)) {
delete it->second.audio;
_audio_cache.erase(it);
}
}
}

const std::string AudioEngine::CreateALErrorString() {
switch (_al_error_code) {
Expand All @@ -516,8 +533,6 @@ const std::string AudioEngine::CreateALErrorString() {
}
}



const std::string AudioEngine::CreateALCErrorString() {
switch (_alc_error_code) {
case ALC_NO_ERROR:
Expand All @@ -537,8 +552,6 @@ const std::string AudioEngine::CreateALCErrorString() {
}
}



void AudioEngine::DEBUG_PrintInfo() {
const ALCchar* c;

Expand Down Expand Up @@ -574,8 +587,6 @@ void AudioEngine::DEBUG_PrintInfo() {
}
}



private_audio::AudioSource* AudioEngine::_AcquireAudioSource() {
// (1) Find and return the first source that does not have an owner
for (vector<AudioSource*>::iterator i = _audio_sources.begin(); i != _audio_sources.end(); i++) {
Expand All @@ -602,9 +613,13 @@ private_audio::AudioSource* AudioEngine::_AcquireAudioSource() {


bool AudioEngine::_LoadAudio(AudioDescriptor* audio, const std::string& filename) {
if (_audio_cache.find(filename) != _audio_cache.end()) {
IF_PRINT_WARNING(AUDIO_DEBUG) << "audio was already contained within the cache: " << filename << endl;
return false;
std::map<std::string, private_audio::AudioCacheElement>::iterator it = _audio_cache.find(filename);
if (it != _audio_cache.end()) {
it->second.audio->AddOwners(*audio->GetOwners());
// Once the owners have been copied, we don't need the given descriptor anymore.
delete audio;
// Return a success since basically everything will keep on working as expected.
return true;
}

// (1) If the cache is not full, try loading the audio and adding it in
Expand Down
13 changes: 11 additions & 2 deletions src/engine/audio/audio.h
Expand Up @@ -230,14 +230,16 @@ class AudioEngine : public hoa_utils::Singleton<AudioEngine> {
**/
//@{
/** \brief Creates a new SoundDescriptor using the given filename and loads it into the audio cache
*** \param gm The game mode owning the audio descriptor to load.
*** \return True if the sound was loaded into the cache successfully
**/
bool LoadSound(const std::string& filename);
bool LoadSound(const std::string& filename, hoa_mode_manager::GameMode* gm = NULL);

/** \brief Creates a new MusicDescriptor using the given filename and loads it into the audio cache
*** \param gm The game mode owning the audio descriptor to load.
*** \return True if the music was loaded into the cache successfully
**/
bool LoadMusic(const std::string& filename);
bool LoadMusic(const std::string& filename, hoa_mode_manager::GameMode* gm = NULL);

//! \brief Plays a sound that is contained within the audio cache
void PlaySound(const std::string& filename);
Expand Down Expand Up @@ -273,6 +275,13 @@ class AudioEngine : public hoa_utils::Singleton<AudioEngine> {
MusicDescriptor* RetrieveMusic(const std::string& filename);
//@}

/**
*** Tells the audio engine that a game mode ended.
*** Thus, permitting to check whether the audio descriptors owned by the mode can be freed
*** from memory.
**/
void RemoveOwner(hoa_mode_manager::GameMode* gm);

/** \name Error Detection and Processing methods
*** Code external to the audio engine should not need to make use of the following methods,
*** as error detection is routinely done by the engine itself.
Expand Down

0 comments on commit f71ba55

Please sign in to comment.