1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2006-2015 Patrick Ammann <pammann@aro.ch>
4 //  Copyright (C) 2008-2015 Patrick Ammann <pammann@aro.ch>, Joerg Henrichs
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 3
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 #include "audio/music_manager.hpp"
21 
22 #include <assert.h>
23 #include <fstream>
24 
25 #ifdef ENABLE_SOUND
26 #  ifdef __APPLE__
27 #    define OPENAL_DEPRECATED
28 #    include <OpenAL/al.h>
29 #    include <OpenAL/alc.h>
30 #  else
31 #    include <AL/al.h>
32 #    include <AL/alc.h>
33 #  endif
34 #endif
35 
36 #include "audio/music_ogg.hpp"
37 #include "audio/sfx_manager.hpp"
38 #include "audio/sfx_openal.hpp"
39 #include "config/user_config.hpp"
40 #include "io/file_manager.hpp"
41 #include "utils/stk_process.hpp"
42 #include "utils/string_utils.hpp"
43 
44 MusicManager* music_manager= NULL;
45 
46 
MusicManager()47 MusicManager::MusicManager()
48 {
49     m_current_music= NULL;
50     m_initialized = false;
51     setMasterMusicVolume(UserConfigParams::m_music_volume);
52 
53     //FIXME: I'm not sure that this code goes here
54 #ifdef ENABLE_SOUND
55     if (UserConfigParams::m_enable_sound)
56     {
57 #if defined(__APPLE__) && !defined(NDEBUG)
58         // HACK: On OSX, when OpenAL is initialized, breaking in a debugger
59         // causes my iTunes music to stop too, which is highly annoying ;) so in
60         // debug mode, require a restart to enable sound
61         if (UserConfigParams::m_sfx || UserConfigParams::m_music)
62         {
63 #endif
64             ALCdevice* device = alcOpenDevice(NULL); //The default sound device
65 
66             if (device == NULL)
67             {
68                 Log::warn("MusicManager", "Could not open the default sound "
69                                           "device.");
70                 m_initialized = false;
71             }
72             else
73             {
74                 ALCcontext* context = alcCreateContext(device, NULL);
75 
76                 if (context == NULL)
77                 {
78                     Log::warn("MusicManager", "Could not create a sound "
79                                               "context.");
80                     m_initialized = false;
81                 }
82                 else
83                 {
84                     alcMakeContextCurrent(context);
85                     m_initialized = true;
86                 }
87             }
88 #if defined(__APPLE__) && !defined(NDEBUG)
89         }
90 #endif
91         alGetError(); //Called here to clear any non-important errors found
92     }
93 #endif
94 
95     loadMusicInformation();
96 }  // MusicManager
97 
98 //-----------------------------------------------------------------------------
~MusicManager()99 MusicManager::~MusicManager()
100 {
101     for(std::map<std::string,MusicInformation*>::iterator
102         i=m_all_music.begin(); i!=m_all_music.end(); i++)
103     {
104         delete i->second;
105         i->second = NULL;
106     }
107 
108 #ifdef ENABLE_SOUND
109     if(m_initialized)
110     {
111         ALCcontext* context = alcGetCurrentContext();
112         ALCdevice* device = alcGetContextsDevice( context );
113 
114         alcMakeContextCurrent( NULL );
115         alcDestroyContext( context );
116 
117         alcCloseDevice( device );
118     }
119 #endif
120 }   // ~MusicManager
121 
122 //-----------------------------------------------------------------------------
loadMusicInformation()123 void MusicManager::loadMusicInformation()
124 {
125     // Load music files from data/music, and dirs defined in
126     // SUPERTUXKART_MUSIC_PATH
127     std::vector<std::string> allMusicDirs=file_manager->getMusicDirs();
128     for(std::vector<std::string>::iterator dir=allMusicDirs.begin();
129                                            dir!=allMusicDirs.end(); dir++)
130     {
131         loadMusicFromOneDir(*dir);
132     }   // for dir
133 }   // loadMusicInformation
134 
135  //----------------------------------------------------------------------------
loadMusicFromOneDir(const std::string & dir)136 void MusicManager::loadMusicFromOneDir(const std::string& dir)
137 {
138     std::set<std::string> files;
139     file_manager->listFiles(files, dir, /*is_full_path*/ true);
140     for(std::set<std::string>::iterator i  = files.begin();
141                                         i != files.end(); ++i)
142     {
143         if(StringUtils::getExtension(*i)!="music") continue;
144         MusicInformation *mi =  MusicInformation::create(*i);
145         if(mi)
146             m_all_music[StringUtils::getBasename(*i)] = mi;
147     }   // for i
148 
149 } // loadMusicFromOneDir
150 
151 //-----------------------------------------------------------------------------
addMusicToTracks()152 void MusicManager::addMusicToTracks()
153 {
154     for(std::map<std::string,MusicInformation*>::iterator
155         i=m_all_music.begin(); i!=m_all_music.end(); i++)
156     {
157         if(!i->second)
158         {
159             Log::warn("MusicManager", "Can't find music file '%s' - ignored.",
160                       i->first.c_str());
161             continue;
162         }
163         i->second->addMusicToTracks();
164     }
165 }   // addMusicToTracks
166 
167 //-----------------------------------------------------------------------------
168 /** Special shortcut vor overworld (which skips other phases where the music
169  *  would normally be started.
170  */
startMusic()171 void MusicManager::startMusic()
172 {
173     if (m_current_music && UserConfigParams::m_music)
174         SFXManager::get()->queue(SFXManager::SFX_MUSIC_START, m_current_music);
175 }   // startMusic
176 
177 //-----------------------------------------------------------------------------
178 /** Schedules the indicated music to be played next.
179  *  \param mi Music information of the music to be played.
180  *  \param start_right_now
181  */
startMusic(MusicInformation * mi,bool start_right_now)182 void MusicManager::startMusic(MusicInformation* mi, bool start_right_now)
183 {
184     if (STKProcess::getType() != PT_MAIN)
185         return;
186 
187     // If this music is already playing, ignore this call.
188     if (m_current_music != NULL &&
189         m_current_music == mi &&
190         m_current_music->isPlaying())
191         return;
192 
193     // It is possible here that startMusic() will be called without first
194     // calling stopMusic(). This would cause a memory leak by overwriting
195     // m_current_music without first releasing its resources. Guard against
196     // this here by making sure that stopMusic() is called before starting
197     // new music.
198     stopMusic();
199     m_current_music = mi;
200 
201     if(!mi || !UserConfigParams::m_music || !m_initialized) return;
202 
203     SFXManager::get()->queue(start_right_now ? SFXManager::SFX_MUSIC_START
204                                              : SFXManager::SFX_MUSIC_WAITING,
205                              mi);
206 }   // startMusic
207 
208 //-----------------------------------------------------------------------------
209 /** Queues a stop current music event for the audio thread.
210  */
stopMusic()211 void MusicManager::stopMusic()
212 {
213     if (m_current_music)
214         SFXManager::get()->queue(SFXManager::SFX_MUSIC_STOP, m_current_music);
215 }   // stopMusic
216 
217 //-----------------------------------------------------------------------------
218 /** Insert a command into the sfx queue to pause the current music.
219  */
pauseMusic()220 void MusicManager::pauseMusic()
221 {
222     if (m_current_music)
223         SFXManager::get()->queue(SFXManager::SFX_MUSIC_PAUSE, m_current_music);
224 }   // pauseMusic
225 
226 //-----------------------------------------------------------------------------
227 /** Inserts a resume current music event into the queue.
228  */
resumeMusic()229 void MusicManager::resumeMusic()
230 {
231     if (m_current_music)
232         SFXManager::get()->queue(SFXManager::SFX_MUSIC_RESUME, m_current_music);
233 }   // resumeMusic
234 
235 //-----------------------------------------------------------------------------
236 /** Switches to fast (last lap ) music (if defined for the current music).
237  */
switchToFastMusic()238 void MusicManager::switchToFastMusic()
239 {
240     if (m_current_music)
241         SFXManager::get()->queue(SFXManager::SFX_MUSIC_SWITCH_FAST,
242                                 m_current_music);
243 }   // switchToFastMusic
244 
245 //-----------------------------------------------------------------------------
246 /** Queues a command to temporarily change the volume. This is used to make
247  *  the music a bit quieter while the 'last lap fanfare' is being played.
248  *  \param gain The temporary volume value.
249  */
setTemporaryVolume(float gain)250 void MusicManager::setTemporaryVolume(float gain)
251 {
252     if (m_current_music)
253         SFXManager::get()->queue(SFXManager::SFX_MUSIC_SET_TMP_VOLUME,
254                                  m_current_music, gain);
255 }   // setTemporaryVolume
256 
257 //-----------------------------------------------------------------------------
258 /** Queues a command for the sfx manager to reset a temporary volume change.
259  */
resetTemporaryVolume()260 void MusicManager::resetTemporaryVolume()
261 {
262     if (m_current_music)
263         SFXManager::get()->queue(SFXManager::SFX_MUSIC_DEFAULT_VOLUME,
264                                  m_current_music);
265 }   // resetTemporaryVolume
266 
267 //-----------------------------------------------------------------------------
268 /** Sets the master music volume.
269  *  \param gain The volume.
270  */
setMasterMusicVolume(float gain)271 void MusicManager::setMasterMusicVolume(float gain)
272 {
273     if(gain > 1.0)
274         gain = 1.0f;
275     if(gain < 0.0f)
276         gain = 0.0f;
277 
278     m_master_gain = gain;
279     if (m_current_music)
280     {
281         // Sets the music volume to m_master_gain
282         SFXManager::get()->queue(SFXManager::SFX_MUSIC_DEFAULT_VOLUME,
283                                  m_current_music);
284     }
285 
286     UserConfigParams::m_music_volume = m_master_gain;
287 }   // setMasterMusicVolume
288 
289 //-----------------------------------------------------------------------------
290 /** @throw runtime_error if the music file could not be found/opened
291 */
getMusicInformation(const std::string & filename)292 MusicInformation* MusicManager::getMusicInformation(const std::string& filename)
293 {
294     if(filename=="")
295     {
296         return NULL;
297     }
298     const std::string basename = StringUtils::getBasename(filename);
299     std::map<std::string, MusicInformation*>::iterator p;
300     p = m_all_music.find(basename);
301     if(p==m_all_music.end())
302     {
303         // Note that this might raise an exception
304         MusicInformation *mi = MusicInformation::create(filename);
305         if(mi)
306         {
307             SFXManager::get()->queue(SFXManager::SFX_MUSIC_DEFAULT_VOLUME, mi);
308             m_all_music[basename] = mi;
309         }
310         return mi;
311     }
312     return p->second;
313 }   // getMusicInformation
314 
315 //----------------------------------------------------------------------------
316