1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 /** ****************************************************************************
12 *** \file    audio.cpp
13 *** \author  Tyler Olsen - roots@allacrost.org
14 *** \author  Mois�s Ferrer Serra - byaku@allacrost.org
15 *** \author  Aaron Smith - etherstar@allacrost.org
16 *** \author  Yohann Ferreira, yohann ferreira orange fr
17 *** \brief   Implementation of the audio engine singleton.
18 ***
19 *** The code included here implements the interface of the audio singleton.
20 ***
21 *** \note This code uses the OpenAL audio library. See http://www.openal.com/
22 *** ***************************************************************************/
23 
24 #include "engine/audio/audio.h"
25 
26 #include "engine/system.h"
27 #include "engine/mode_manager.h"
28 
29 #include "utils/utils_strings.h"
30 #include "utils/utils_files.h"
31 
32 using namespace vt_utils;
33 using namespace vt_system;
34 using namespace vt_audio::private_audio;
35 
36 namespace vt_audio
37 {
38 
39 AudioEngine *AudioManager = nullptr;
40 bool AUDIO_DEBUG = false;
41 bool AUDIO_ENABLE = true;
42 
AudioEngine()43 AudioEngine::AudioEngine() :
44     _sound_volume(1.0f),
45     _music_volume(1.0f),
46     _device(0),
47     _context(0),
48     _max_sources(MAX_DEFAULT_AUDIO_SOURCES),
49     _active_music(nullptr)
50 {}
51 
SingletonInitialize()52 bool AudioEngine::SingletonInitialize()
53 {
54     if(!AUDIO_ENABLE)
55         return true;
56 
57     const ALCchar *best_device = 0; // Will store the name of the 'best' device for audio playback
58     ALCint highest_version = 0; // The highest version number found
59     CheckALError(); // Clears errors
60     CheckALCError(); // Clears errors
61 
62     // Find the highest-version device available, if the extension for device enumeration is present
63     if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_TRUE) {
64         const ALCchar *device_list = 0;
65         device_list = alcGetString(0, ALC_DEVICE_SPECIFIER); // Get list of all devices (terminated with two '0')
66         if(CheckALCError()) {
67             IF_PRINT_WARNING(AUDIO_DEBUG) << "failed to retrieve the list of available audio devices: " << CreateALCErrorString() << std::endl;
68         }
69 
70 
71         while(*device_list != 0) {  // Check all the detected devices
72             ALCint major_v = 0, minor_v = 0;
73 
74             // Open a temporary device for reading in its version number
75             ALCdevice *temp_device = alcOpenDevice(device_list);
76             if(CheckALCError() || temp_device == nullptr) {  // If we couldn't open the device, just move on to the next
77                 IF_PRINT_WARNING(AUDIO_DEBUG) << "couldn't open device for version checking: " << device_list << std::endl;
78                 device_list += strlen(device_list) + 1;
79                 continue;
80             }
81 
82             // Create a temporary context for the device
83             ALCcontext *temp_context = alcCreateContext(temp_device, 0);
84             if(CheckALCError() || temp_context == nullptr) {  // If we couldn't create the context, move on to the next device
85                 IF_PRINT_WARNING(AUDIO_DEBUG) << "couldn't create a temporary context for device: " << device_list << std::endl;
86                 alcCloseDevice(temp_device);
87                 device_list += strlen(device_list) + 1;
88                 continue;
89             }
90 
91             // Retrieve the version number for the device
92             alcMakeContextCurrent(temp_context);
93 
94             alcGetIntegerv(temp_device, ALC_MAJOR_VERSION, sizeof(ALCint), &major_v);
95             alcGetIntegerv(temp_device, ALC_MINOR_VERSION, sizeof(ALCint), &minor_v);
96             alcMakeContextCurrent(0); // Disable the temporary context
97             alcDestroyContext(temp_context); // Destroy the temporary context
98             alcCloseDevice(temp_device); // Close the temporary device
99 
100             // Check if a higher version device was found
101             if(highest_version < (major_v * 10 + minor_v)) {
102                 highest_version = (major_v * 10 + minor_v);
103                 best_device = device_list;
104             }
105             device_list += strlen(device_list) + 1; // Go to the next device name in the list
106         } // while (*device_name != 0)
107     } // if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_TRUE)
108 
109     // Open the 'best' device we found above. If no devices were previously found,
110     // it will try opening the default device (= 0)
111     _device = alcOpenDevice(best_device);
112     if(CheckALCError() || _device == nullptr) {
113         PRINT_ERROR << "failed to open an OpenAL audio device: " << CreateALCErrorString() << std::endl;
114         return false;
115     }
116 
117     // Create an OpenAL context
118     _context = alcCreateContext(_device, nullptr);
119     if(CheckALCError() || _context == nullptr) {
120         PRINT_ERROR << "failed to create an OpenAL context: " << CreateALCErrorString() << std::endl;
121         alcCloseDevice(_device);
122         return false;
123     }
124 
125     alcMakeContextCurrent(_context);
126     CheckALError(); // Clear errors
127     CheckALCError(); // Clear errors
128 
129     // Create as many sources as possible (we fix an upper bound of MAX_DEFAULT_AUDIO_SOURCES)
130     ALuint source;
131     for(uint16_t i = 0; i < _max_sources; ++i) {
132         alGenSources(1, &source);
133         if(CheckALError()) {
134             _max_sources = i;
135             break;
136         }
137         _audio_sources.push_back(new private_audio::AudioSource(source));
138     }
139 
140     if(_max_sources == 0) {
141         PRINT_ERROR << "failed to create at least one OpenAL audio source" << std::endl;
142         return false;
143     }
144 
145     return true;
146 } // bool AudioEngine::SingletonInitialize()
147 
~AudioEngine()148 AudioEngine::~AudioEngine()
149 {
150     if(!AUDIO_ENABLE)
151         return;
152 
153     // Delete all entries in the sound cache
154     for(std::map<std::string, private_audio::AudioCacheElement>::iterator i = _audio_cache.begin(); i != _audio_cache.end(); ++i) {
155         delete i->second.audio;
156     }
157     _audio_cache.clear();
158 
159     // Delete all audio sources
160     for(std::vector<AudioSource *>::iterator i = _audio_sources.begin(); i != _audio_sources.end(); ++i) {
161         delete(*i);
162     }
163     _audio_sources.clear();
164 
165     // We shouldn't have any descriptors registered left,
166     // except when some scripts have created its own descriptors and didn't free them.
167     // So, let's do that now.
168     if(!_registered_sounds.empty()) {
169         PRINT_WARNING << _registered_sounds.size() << " SoundDescriptor objects were still "
170                       "registered when the destructor was invoked, "
171                       "the objects will be freed now." << std::endl;
172 
173         for(std::vector<SoundDescriptor *>::iterator it = _registered_sounds.begin();
174                 it != _registered_sounds.end();) {
175             std::string filename = (*it)->GetFilename();
176             if(!filename.empty()) {
177                 PRINT_WARNING << "This sound file was never unloaded: "
178                               << filename << std::endl;
179             }
180 
181             delete *it;
182             it = _registered_sounds.erase(it);
183         }
184     }
185     if(!_registered_music.empty()) {
186         PRINT_WARNING << _registered_music.size() << " MusicDescriptor objects were still "
187                       "registered when the destructor was invoked, "
188                       "the objects will be freed now." << std::endl;
189         for(std::vector<MusicDescriptor *>::iterator it = _registered_music.begin();
190                 it != _registered_music.end();) {
191             std::string filename = (*it)->GetFilename();
192             if(!filename.empty()) {
193                 PRINT_WARNING << "This music file was never unloaded: "
194                               << filename << std::endl;
195             }
196 
197             delete *it;
198             it = _registered_music.erase(it);
199         }
200     }
201 
202     alcMakeContextCurrent(0);
203     alcDestroyContext(_context);
204     alcCloseDevice(_device);
205 }
206 
Update()207 void AudioEngine::Update()
208 {
209     if(!AUDIO_ENABLE)
210         return;
211 
212     for(std::vector<AudioSource *>::iterator i = _audio_sources.begin(); i != _audio_sources.end(); ++i) {
213         if((*i)->owner) {
214             (*i)->owner->_Update();
215         }
216     }
217 }
218 
SetSoundVolume(float volume)219 void AudioEngine::SetSoundVolume(float volume)
220 {
221     if(volume < 0.0f) {
222         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set sound volume less than 0.0f" << std::endl;
223         _sound_volume = 0.0f;
224     } else if(volume > 1.0f) {
225         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set sound volume greater than 1.0f" << std::endl;
226         _sound_volume = 1.0f;
227     } else {
228         _sound_volume = volume;
229     }
230 
231     for(std::vector<SoundDescriptor *>::iterator i = _registered_sounds.begin(); i != _registered_sounds.end(); ++i) {
232         if((*i)->_source != nullptr) {
233             alSourcef((*i)->_source->source, AL_GAIN, _sound_volume * (*i)->GetVolume());
234         }
235     }
236 }
237 
SetMusicVolume(float volume)238 void AudioEngine::SetMusicVolume(float volume)
239 {
240     if(volume < 0.0f) {
241         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set music volume less than 0.0f: " << volume << std::endl;
242         _music_volume = 0.0f;
243     } else if(volume > 1.0f) {
244         IF_PRINT_WARNING(AUDIO_DEBUG) << "tried to set music volume greater than 1.0f: " << volume << std::endl;
245         _music_volume = 1.0f;
246     } else {
247         _music_volume = volume;
248     }
249 
250     for(std::vector<MusicDescriptor *>::iterator i = _registered_music.begin(); i != _registered_music.end(); ++i) {
251         if((*i)->_source != nullptr) {
252             alSourcef((*i)->_source->source, AL_GAIN, _music_volume * (*i)->GetVolume());
253         }
254     }
255 }
256 
PauseAllSounds()257 void AudioEngine::PauseAllSounds()
258 {
259     for(std::vector<SoundDescriptor *>::iterator i = _registered_sounds.begin();
260             i != _registered_sounds.end(); ++i) {
261         (*i)->Pause();
262     }
263 }
264 
ResumeAllSounds()265 void AudioEngine::ResumeAllSounds()
266 {
267     for(std::vector<SoundDescriptor *>::iterator i = _registered_sounds.begin();
268             i != _registered_sounds.end(); ++i) {
269         (*i)->Resume();
270     }
271 }
272 
StopAllSounds()273 void AudioEngine::StopAllSounds()
274 {
275     for(std::vector<SoundDescriptor *>::iterator i = _registered_sounds.begin();
276             i != _registered_sounds.end(); ++i) {
277         (*i)->Stop();
278     }
279 }
280 
RewindAllSounds()281 void AudioEngine::RewindAllSounds()
282 {
283     for(std::vector<SoundDescriptor *>::iterator i = _registered_sounds.begin();
284             i != _registered_sounds.end(); ++i) {
285         (*i)->Rewind();
286     }
287 }
288 
PauseActiveMusic()289 void AudioEngine::PauseActiveMusic()
290 {
291     MusicDescriptor* music = GetActiveMusic();
292     if (music)
293         music->Pause();
294 }
295 
ResumeActiveMusic()296 void AudioEngine::ResumeActiveMusic()
297 {
298     MusicDescriptor* music = GetActiveMusic();
299     if (music)
300         music->Resume();
301 }
302 
StopActiveMusic()303 void AudioEngine::StopActiveMusic()
304 {
305     MusicDescriptor* music = GetActiveMusic();
306     if (music)
307         music->Stop();
308 }
309 
RewindActiveMusic()310 void AudioEngine::RewindActiveMusic()
311 {
312     MusicDescriptor* music = GetActiveMusic();
313     if (music)
314         music->Rewind();
315 }
316 
FadeOutActiveMusic(float time)317 void AudioEngine::FadeOutActiveMusic(float time)
318 {
319     MusicDescriptor* music = GetActiveMusic();
320     if (music)
321         music->FadeOut(time);
322 }
323 
FadeInActiveMusic(float time)324 void AudioEngine::FadeInActiveMusic(float time)
325 {
326     MusicDescriptor* music = GetActiveMusic();
327     if (music)
328         music->FadeIn(time);
329 }
330 
FadeOutAllSounds(float time)331 void AudioEngine::FadeOutAllSounds(float time)
332 {
333     for(std::vector<SoundDescriptor *>::iterator it = _registered_sounds.begin();
334             it != _registered_sounds.end(); ++it) {
335         if(*it)
336             (*it)->FadeOut(time);
337     }
338 }
339 
SetListenerPosition(const float position[3])340 void AudioEngine::SetListenerPosition(const float position[3])
341 {
342     alListenerfv(AL_POSITION, position);
343     memcpy(_listener_position, position, sizeof(float) * 3);
344 }
345 
SetListenerVelocity(const float velocity[3])346 void AudioEngine::SetListenerVelocity(const float velocity[3])
347 {
348     alListenerfv(AL_VELOCITY, velocity);
349     memcpy(_listener_velocity, velocity, sizeof(float) * 3);
350 }
351 
SetListenerOrientation(const float orientation[3])352 void AudioEngine::SetListenerOrientation(const float orientation[3])
353 {
354     alListenerfv(AL_ORIENTATION, orientation);
355     memcpy(_listener_orientation, orientation, sizeof(float) * 3);
356 }
357 
GetListenerPosition(float position[3]) const358 void AudioEngine::GetListenerPosition(float position[3]) const
359 {
360     memcpy(position, _listener_position, sizeof(float) * 3);
361 }
362 
GetListenerVelocity(float velocity[3]) const363 void AudioEngine::GetListenerVelocity(float velocity[3]) const
364 {
365     memcpy(velocity, _listener_velocity, sizeof(float) * 3);
366 }
367 
GetListenerOrientation(float orientation[3]) const368 void AudioEngine::GetListenerOrientation(float orientation[3]) const
369 {
370     memcpy(orientation, _listener_orientation, sizeof(float) * 3);
371 }
372 
LoadSound(const std::string & filename,vt_mode_manager::GameMode * gm)373 bool AudioEngine::LoadSound(const std::string &filename, vt_mode_manager::GameMode *gm)
374 {
375     return _LoadAudio(filename, false, gm);
376 }
377 
LoadMusic(const std::string & filename,vt_mode_manager::GameMode * gm)378 bool AudioEngine::LoadMusic(const std::string &filename, vt_mode_manager::GameMode *gm)
379 {
380     return _LoadAudio(filename, true, gm);
381 }
382 
PlaySound(const std::string & filename)383 void AudioEngine::PlaySound(const std::string &filename)
384 {
385     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
386 
387     if(element == _audio_cache.end()) {
388         // Don't check the current game mode to prevent the sound unloading in certain cases.
389         // We'll let the audio cache handle it all atm.
390         if(!LoadSound(filename)) {
391             IF_PRINT_WARNING(AUDIO_DEBUG)
392                     << "could not play sound from cache because "
393                     "the sound could not be loaded" << std::endl;
394             return;
395         } else {
396             element = _audio_cache.find(filename);
397         }
398     }
399 
400     element->second.audio->Play();
401     element->second.last_update_time = SDL_GetTicks();
402 }
403 
PlayMusic(const std::string & filename)404 void AudioEngine::PlayMusic(const std::string &filename)
405 {
406     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
407 
408     if(element == _audio_cache.end()) {
409         // Get the current game mode, so that the loading/freeing micro management
410         // is handled the most possible.
411         vt_mode_manager::GameMode *gm = vt_mode_manager::ModeManager->GetTop();
412         if(!LoadMusic(filename, gm)) {
413             IF_PRINT_WARNING(AUDIO_DEBUG)
414                     << "could not play music from cache because "
415                     "the music could not be loaded" << std::endl;
416             return;
417         } else {
418             element = _audio_cache.find(filename);
419         }
420     }
421 
422     // Special case: the music descriptor object must be taken back:
423     MusicDescriptor *music_audio = reinterpret_cast<MusicDescriptor *>(element->second.audio);
424     if(music_audio) {
425         music_audio->Play();
426         element->second.last_update_time = SDL_GetTicks();
427     }
428 }
429 
StopSound(const std::string & filename)430 void AudioEngine::StopSound(const std::string &filename)
431 {
432     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
433 
434     if(element == _audio_cache.end()) {
435         IF_PRINT_WARNING(AUDIO_DEBUG) << "could not stop audio because it was not contained in the cache: " << filename << std::endl;
436         return;
437     }
438 
439     element->second.audio->Stop();
440     element->second.last_update_time = SDL_GetTicks();
441 }
442 
PauseSound(const std::string & filename)443 void AudioEngine::PauseSound(const std::string &filename)
444 {
445     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
446 
447     if(element == _audio_cache.end()) {
448         IF_PRINT_WARNING(AUDIO_DEBUG) << "could not pause audio because it was not contained in the cache: " << filename << std::endl;
449         return;
450     }
451 
452     element->second.audio->Pause();
453     element->second.last_update_time = SDL_GetTicks();
454 }
455 
ResumeSound(const std::string & filename)456 void AudioEngine::ResumeSound(const std::string &filename)
457 {
458     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
459 
460     if(element == _audio_cache.end()) {
461         IF_PRINT_WARNING(AUDIO_DEBUG) << "could not resume audio because it was not contained in the cache: " << filename << std::endl;
462         return;
463     }
464 
465     element->second.audio->Resume();
466     element->second.last_update_time = SDL_GetTicks();
467 }
468 
RetrieveSound(const std::string & filename)469 SoundDescriptor *AudioEngine::RetrieveSound(const std::string &filename)
470 {
471     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
472 
473     if(element == _audio_cache.end()) {
474         return nullptr;
475     } else if(element->second.audio->IsSound() == false) {
476         IF_PRINT_WARNING(AUDIO_DEBUG) << "incorrectly requested to retrieve a sound for a music filename: " << filename << std::endl;
477         return nullptr;
478     } else {
479         return dynamic_cast<SoundDescriptor *>(element->second.audio);
480     }
481 }
482 
RetrieveMusic(const std::string & filename)483 MusicDescriptor *AudioEngine::RetrieveMusic(const std::string &filename)
484 {
485     std::map<std::string, AudioCacheElement>::iterator element = _audio_cache.find(filename);
486 
487     if(element == _audio_cache.end()) {
488         return nullptr;
489     } else if(element->second.audio->IsSound()) {
490         IF_PRINT_WARNING(AUDIO_DEBUG) << "incorrectly requested to retrieve music for a sound filename: " << filename << std::endl;
491         return nullptr;
492     } else {
493         return dynamic_cast<MusicDescriptor *>(element->second.audio);
494     }
495 }
496 
RemoveGameModeOwner(vt_mode_manager::GameMode * gm)497 void AudioEngine::RemoveGameModeOwner(vt_mode_manager::GameMode* gm)
498 {
499     if(!gm)
500         return;
501 
502     // Tells all audio descriptor the owner can be removed.
503     std::map<std::string, AudioCacheElement>::iterator it = _audio_cache.begin();
504     for(; it != _audio_cache.end();) {
505         // If the audio buffers are erased, we can remove the descriptor from the cache.
506         if(it->second.audio->RemoveGameModeOwner(gm)) {
507             delete it->second.audio;
508             // Make sure the iterator doesn't get flawed after erase.
509             _audio_cache.erase(it++);
510         } else {
511             ++it;
512         }
513     }
514 }
515 
CreateALErrorString()516 const std::string AudioEngine::CreateALErrorString()
517 {
518     switch(_al_error_code) {
519     case AL_NO_ERROR:
520         return "AL_NO_ERROR";
521     case AL_INVALID_NAME:
522         return "AL_INVALID_NAME";
523     case AL_INVALID_ENUM:
524         return "AL_INVALID_ENUM";
525     case AL_INVALID_VALUE:
526         return "AL_INVALID_VALUE";
527     case AL_INVALID_OPERATION:
528         return "AL_INVALID_OPERATION";
529     case AL_OUT_OF_MEMORY:
530         return "AL_OUT_OF_MEMORY";
531     default:
532         return ("Unknown AL error code: " + NumberToString(_al_error_code));
533     }
534 }
535 
CreateALCErrorString()536 const std::string AudioEngine::CreateALCErrorString()
537 {
538     switch(_alc_error_code) {
539     case ALC_NO_ERROR:
540         return "ALC_NO_ERROR";
541     case ALC_INVALID_DEVICE:
542         return "ALC_INVALID_DEVICE";
543     case ALC_INVALID_CONTEXT:
544         return "ALC_INVALID_CONTEXT";
545     case ALC_INVALID_ENUM:
546         return "ALC_INVALID_ENUM";
547     case ALC_INVALID_VALUE:
548         return "ALC_INVALID_VALUE";
549     case ALC_OUT_OF_MEMORY:
550         return "ALC_OUT_OF_MEMORY";
551     default:
552         return ("Unknown ALC error code: " + NumberToString(_alc_error_code));
553     }
554 }
555 
DEBUG_PrintInfo()556 void AudioEngine::DEBUG_PrintInfo()
557 {
558     const ALCchar *c;
559 
560     PRINT_WARNING << "*** Audio Information ***" << std::endl;
561 
562     PRINT_WARNING << "Maximum number of sources:   " << _max_sources << std::endl;
563     PRINT_WARNING << "Default audio device:        " << alcGetString(_device, ALC_DEFAULT_DEVICE_SPECIFIER) << std::endl;
564     PRINT_WARNING << "OpenAL Version:              " << alGetString(AL_VERSION) << std::endl;
565     PRINT_WARNING << "OpenAL Renderer:             " << alGetString(AL_RENDERER) << std::endl;
566     PRINT_WARNING << "OpenAL Vendor:               " << alGetString(AL_VENDOR) << std::endl;
567 
568     CheckALError();
569 
570     PRINT_WARNING << "Available OpenAL Extensions:" << std::endl;
571     c = alGetString(AL_EXTENSIONS);
572     bool new_extension = true;
573     while(c[0]) {
574         if(new_extension) {
575             PRINT_WARNING << " - ";
576             new_extension = false;
577             continue;
578         } else if(c[0] == ' ') {
579             PRINT_WARNING << std::endl;
580             new_extension = true;
581             c++;
582             continue;
583         }
584 
585         PRINT_WARNING << c[0];
586         c++;
587     }
588 }
589 
_AcquireAudioSource()590 private_audio::AudioSource* AudioEngine::_AcquireAudioSource()
591 {
592     // Find and return the first source that does not have an owner
593     for(std::vector<AudioSource *>::iterator i = _audio_sources.begin(); i != _audio_sources.end(); ++i) {
594         AudioDescriptor* descriptor = (*i)->owner;
595         if(descriptor == nullptr) {
596             return *i;
597         }
598         else if (descriptor->GetState() == AUDIO_STATE_UNLOADED) {
599             // Test whether the sound is unloaded, meaning the source is available
600             return *i;
601         }
602     }
603 
604     // Return nullptr in the (extremely rare) case that all sources are owned and actively playing or paused
605     return nullptr;
606 }
607 
608 
609 
_LoadAudio(const std::string & filename,bool is_music,vt_mode_manager::GameMode * gm)610 bool AudioEngine::_LoadAudio(const std::string &filename, bool is_music, vt_mode_manager::GameMode *gm)
611 {
612     if(!DoesFileExist(filename))
613         return false;
614 
615     std::map<std::string, private_audio::AudioCacheElement>::iterator it = _audio_cache.find(filename);
616     if(it != _audio_cache.end()) {
617 
618         if (gm)
619             it->second.audio->AddGameModeOwner(gm);
620 
621         // Return a success since basically everything will keep on working as expected.
622         return true;
623     }
624 
625     // Creates the new audio object and adds its potential game mode owner.
626     AudioDescriptor* audio = nullptr;
627     if (is_music)
628         audio = new MusicDescriptor();
629     else
630         audio = new SoundDescriptor();
631 
632     if (gm)
633         audio->AddGameModeOwner(gm);
634 
635     // Try loading the audio and adding it in.
636     if (!audio->LoadAudio(filename)) {
637         IF_PRINT_WARNING(AUDIO_DEBUG) << "Could not add new audio file into cache because load operation failed: " << filename << std::endl;
638         delete audio;
639         return false;
640     }
641 
642     _audio_cache.insert(std::make_pair(filename, AudioCacheElement(SDL_GetTicks(), audio)));
643     return true;
644 }
645 
646 } // namespace vt_audio
647