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