1 //
2 // SuperTuxKart - a fun racing game with go-kart
3 // Copyright (C) 2008-2015 Joerg Henrichs
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 3
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include "audio/dummy_sfx.hpp"
20 #include "audio/music_manager.hpp"
21 #include "audio/sfx_openal.hpp"
22 #include "audio/sfx_buffer.hpp"
23 #include "config/user_config.hpp"
24 #include "io/file_manager.hpp"
25 #include "modes/world.hpp"
26 #include "race/race_manager.hpp"
27 #include "utils/stk_process.hpp"
28 #include "utils/profiler.hpp"
29 #include "utils/string_utils.hpp"
30 #include "utils/vs.hpp"
31
32 #include <stdexcept>
33 #include <algorithm>
34 #include <map>
35
36 #include <functional>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <limits>
41 #include <math.h>
42
43 // Define this if the profiler should also collect data of the sfx manager
44 #undef ENABLE_PROFILING_FOR_SFX_MANAGER
45 #ifndef ENABLE_PROFILING_FOR_SFX_MANAGER
46 // Otherwise ignore the profiler push/pop events
47 // Use undef to remove preprocessor warning
48 # undef PROFILER_PUSH_CPU_MARKER
49 # undef PROFILER_POP_CPU_MARKER
50 # define PROFILER_PUSH_CPU_MARKER(name, r, g, b)
51 # define PROFILER_POP_CPU_MARKER()
52 #endif
53
54 SFXManager *SFXManager::m_sfx_manager;
55
56 // ----------------------------------------------------------------------------
57 /** Static function to create the singleton sfx manager.
58 */
create()59 void SFXManager::create()
60 {
61 assert(!m_sfx_manager);
62 m_sfx_manager = new SFXManager();
63 } // create
64
65 // ------------------------------------------------------------------------
66 /** Static function to delete the singleton sfx manager.
67 */
destroy()68 void SFXManager::destroy()
69 {
70 delete m_sfx_manager;
71 m_sfx_manager = NULL;
72 } // destroy
73
74 // ----------------------------------------------------------------------------
75 /** Initialises the SFX manager and loads the sfx from a config file.
76 */
SFXManager()77 SFXManager::SFXManager()
78 {
79
80 // The sound manager initialises OpenAL
81 m_initialized = music_manager->initialized();
82 m_master_gain = UserConfigParams::m_sfx_volume;
83 m_last_update_time = std::numeric_limits<uint64_t>::max();
84 // Init position, since it can be used before positionListener is called.
85 // No need to use lock here, since the thread will be created later.
86 m_listener_position.getData() = Vec3(0, 0, 0);
87 m_listener_front = Vec3(0, 0, 1);
88 m_listener_up = Vec3(0, 1, 0);
89
90 loadSfx();
91
92 #ifdef ENABLE_SOUND
93 if (UserConfigParams::m_enable_sound)
94 {
95 // The thread is created even if there atm sfx are disabled
96 // (since the user might enable it later).
97 m_thread = std::thread(std::bind(mainLoop, this));
98 setMasterSFXVolume( UserConfigParams::m_sfx_volume );
99 m_sfx_commands.lock();
100 m_sfx_commands.getData().clear();
101 m_sfx_commands.unlock();
102 }
103 #endif
104 } // SoundManager
105
106 //-----------------------------------------------------------------------------
107 /** Destructor, frees all sound effects.
108 */
~SFXManager()109 SFXManager::~SFXManager()
110 {
111 #ifdef ENABLE_SOUND
112 if (UserConfigParams::m_enable_sound)
113 {
114 m_thread.join();
115 }
116 #endif
117
118 // ---- clear m_all_sfx
119 // not strictly necessary, but might avoid copy&paste problems
120 m_all_sfx.lock();
121 const int sfx_amount = (int) m_all_sfx.getData().size();
122 for (int n=0; n<sfx_amount; n++)
123 {
124 delete m_all_sfx.getData()[n];
125 }
126 m_all_sfx.getData().clear();
127 m_all_sfx.unlock();
128
129 m_quick_sounds.lock();
130 // ---- clear m_quick_sounds
131 {
132 std::map<std::string, SFXBase*>::iterator i = m_quick_sounds.getData().begin();
133 for (; i != m_quick_sounds.getData().end(); i++)
134 {
135 SFXBase* snd = (*i).second;
136 delete snd;
137 }
138 }
139 m_quick_sounds.getData().clear();
140 m_quick_sounds.unlock();
141
142 // ---- clear m_all_sfx_types
143 {
144 std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.begin();
145 for (; i != m_all_sfx_types.end(); i++)
146 {
147 SFXBuffer* buffer = (*i).second;
148 buffer->unload();
149 delete buffer;
150 }
151 m_all_sfx_types.clear();
152 }
153 m_all_sfx_types.clear();
154
155 } // ~SFXManager
156
157 //----------------------------------------------------------------------------
158 /** Adds a sound effect command to the queue of the sfx manager. Openal
159 * commands can sometimes cause a 5ms delay, so it is done in a separate
160 * thread.
161 * \param command The command to execute.
162 * \param sfx The sound effect to be started.
163 */
queue(SFXCommands command,SFXBase * sfx)164 void SFXManager::queue(SFXCommands command, SFXBase *sfx)
165 {
166 #ifdef ENABLE_SOUND
167 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
168 return;
169
170 SFXCommand *sfx_command = new SFXCommand(command, sfx);
171 queueCommand(sfx_command);
172 #endif
173 } // queue
174
175 //----------------------------------------------------------------------------
176 /** Adds a sound effect command with a single floating point parameter to the
177 * queue of the sfx manager. Openal commands can sometimes cause a 5ms delay,
178 * so it is done in a separate thread.
179 * \param command The command to execute.
180 * \param sfx The sound effect to be started.
181 * \param f Floating point parameter for the command.
182 */
queue(SFXCommands command,SFXBase * sfx,float f)183 void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f)
184 {
185 #ifdef ENABLE_SOUND
186 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
187 return;
188
189 SFXCommand *sfx_command = new SFXCommand(command, sfx, f);
190 queueCommand(sfx_command);
191 #endif
192 } // queue(float)
193
194 //----------------------------------------------------------------------------
195 /** Adds a sound effect command with a Vec3 parameter to the queue of the sfx
196 * manager. Openal commands can sometimes cause a 5ms delay, so it is done in
197 * a separate thread.
198 * \param command The command to execute.
199 * \param sfx The sound effect to be started.
200 * \param p A Vec3 parameter for the command.
201 */
queue(SFXCommands command,SFXBase * sfx,const Vec3 & p)202 void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p)
203 {
204 #ifdef ENABLE_SOUND
205 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
206 return;
207
208 SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
209 queueCommand(sfx_command);
210 #endif
211 } // queue (Vec3)
212
213 //----------------------------------------------------------------------------
214
queue(SFXCommands command,SFXBase * sfx,const Vec3 & p,SFXBuffer * buffer)215 void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p, SFXBuffer* buffer)
216 {
217 #ifdef ENABLE_SOUND
218 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
219 return;
220
221 SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
222 sfx_command->m_buffer = buffer;
223 queueCommand(sfx_command);
224 #endif
225 } // queue (Vec3)
226
227 //----------------------------------------------------------------------------
228 /** Adds a sound effect command with a float and a Vec3 parameter to the queue
229 * of the sfx manager. Openal commands can sometimes cause a 5ms delay, so it
230 * is done in a separate thread.
231 * \param command The command to execute.
232 * \param sfx The sound effect to be started.
233 * \param f A float parameter for the command.
234 * \param p A Vec3 parameter for the command.
235 */
queue(SFXCommands command,SFXBase * sfx,float f,const Vec3 & p)236 void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f,
237 const Vec3 &p)
238 {
239 #ifdef ENABLE_SOUND
240 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
241 return;
242
243 SFXCommand *sfx_command = new SFXCommand(command, sfx, f, p);
244 queueCommand(sfx_command);
245 #endif
246 } // queue(float, Vec3)
247
248 //----------------------------------------------------------------------------
249 /** Queues a command for the music manager.
250 * \param mi The music for which the command is.
251 */
queue(SFXCommands command,MusicInformation * mi)252 void SFXManager::queue(SFXCommands command, MusicInformation *mi)
253 {
254 #ifdef ENABLE_SOUND
255 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
256 return;
257
258 SFXCommand *sfx_command = new SFXCommand(command, mi);
259 queueCommand(sfx_command);
260 #endif
261 } // queue(MusicInformation)
262 //----------------------------------------------------------------------------
263 /** Queues a command for the music manager that takes a floating point value
264 * (e.g. setTemporaryVolume).
265 * \param mi The music for which the command is.
266 * \param f The floating point parameter.
267 */
queue(SFXCommands command,MusicInformation * mi,float f)268 void SFXManager::queue(SFXCommands command, MusicInformation *mi, float f)
269 {
270 #ifdef ENABLE_SOUND
271 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
272 return;
273
274 SFXCommand *sfx_command = new SFXCommand(command, mi, f);
275 queueCommand(sfx_command);
276 #endif
277 } // queue(MusicInformation)
278
279 //----------------------------------------------------------------------------
280 /** Enqueues a command to the sfx queue threadsafe. Then signal the
281 * sfx manager to wake up.
282 * \param command Pointer to the command to queue up.
283 */
queueCommand(SFXCommand * command)284 void SFXManager::queueCommand(SFXCommand *command)
285 {
286 #ifdef ENABLE_SOUND
287 if (!UserConfigParams::m_enable_sound || STKProcess::getType() != PT_MAIN)
288 return;
289
290 m_sfx_commands.lock();
291 if(World::getWorld() &&
292 m_sfx_commands.getData().size() > 20*RaceManager::get()->getNumberOfKarts()+20 &&
293 RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_CUTSCENE)
294 {
295 if(command->m_command==SFX_POSITION || command->m_command==SFX_LOOP ||
296 command->m_command==SFX_SPEED ||
297 command->m_command==SFX_SPEED_POSITION )
298 {
299 delete command;
300 static int count_messages = 0;
301 if(count_messages < 5)
302 {
303 Log::warn("SFXManager", "Throttling sfx - queue size %d",
304 m_sfx_commands.getData().size());
305 count_messages++;
306 }
307 m_sfx_commands.unlock();
308 return;
309 } // if throttling
310 }
311 m_sfx_commands.getData().push_back(command);
312 m_sfx_commands.unlock();
313 #endif
314 } // queueCommand
315
316 //----------------------------------------------------------------------------
317 /** Puts a NULL request into the queue, which will trigger the thread to
318 * exit.
319 */
stopThread()320 void SFXManager::stopThread()
321 {
322 #ifdef ENABLE_SOUND
323 if (UserConfigParams::m_enable_sound)
324 {
325 queue(SFX_EXIT);
326 // Make sure the thread wakes up.
327 m_condition_variable.notify_one();
328 }
329 else
330 #endif
331 {
332 setCanBeDeleted();
333 }
334 } // stopThread
335
336 //----------------------------------------------------------------------------
337 /** This loops runs in a different threads, and starts sfx to be played.
338 * This can sometimes take up to 5 ms, so it needs to be handled in a thread
339 * in order to avoid rendering delays.
340 * \param obj A pointer to the SFX singleton.
341 */
mainLoop(void * obj)342 void SFXManager::mainLoop(void *obj)
343 {
344 #ifdef ENABLE_SOUND
345 if (!UserConfigParams::m_enable_sound)
346 return;
347
348 VS::setThreadName("SFXManager");
349 SFXManager *me = (SFXManager*)obj;
350
351 std::unique_lock<std::mutex> ul = me->m_sfx_commands.acquireMutex();
352
353 // Wait till we have an empty sfx in the queue
354 while (me->m_sfx_commands.getData().empty() ||
355 me->m_sfx_commands.getData().front()->m_command!=SFX_EXIT)
356 {
357 PROFILER_PUSH_CPU_MARKER("Wait", 255, 0, 0);
358 bool empty = me->m_sfx_commands.getData().empty();
359
360 // Wait in cond_wait for a request to arrive. The 'while' is necessary
361 // since "spurious wakeups from the pthread_cond_wait ... may occur"
362 // (pthread_cond_wait man page)!
363 while (empty)
364 {
365 me->m_condition_variable.wait(ul);
366 empty = me->m_sfx_commands.getData().empty();
367 }
368 SFXCommand *current = me->m_sfx_commands.getData().front();
369 me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
370
371 if (current->m_command == SFX_EXIT)
372 {
373 delete current;
374 break;
375 }
376 ul.unlock();
377 PROFILER_POP_CPU_MARKER();
378 PROFILER_PUSH_CPU_MARKER("Execute", 0, 255, 0);
379 switch (current->m_command)
380 {
381 case SFX_PLAY: current->m_sfx->reallyPlayNow(); break;
382 case SFX_PLAY_POSITION:
383 current->m_sfx->reallyPlayNow(current->m_parameter, current->m_buffer); break;
384 case SFX_STOP: current->m_sfx->reallyStopNow(); break;
385 case SFX_PAUSE: current->m_sfx->reallyPauseNow(); break;
386 case SFX_RESUME: current->m_sfx->reallyResumeNow(); break;
387 case SFX_SPEED: current->m_sfx->reallySetSpeed(
388 current->m_parameter.getX()); break;
389 case SFX_POSITION: current->m_sfx->reallySetPosition(
390 current->m_parameter); break;
391 case SFX_SPEED_POSITION: current->m_sfx->reallySetSpeedPosition(
392 // Extract float from W component
393 current->m_parameter.getW(),
394 current->m_parameter); break;
395 case SFX_VOLUME: current->m_sfx->reallySetVolume(
396 current->m_parameter.getX()); break;
397 case SFX_MASTER_VOLUME:
398 current->m_sfx->reallySetMasterVolumeNow(
399 current->m_parameter.getX()); break;
400 case SFX_LOOP: current->m_sfx->reallySetLoop(
401 current->m_parameter.getX() != 0); break;
402 case SFX_DELETE: me->deleteSFX(current->m_sfx); break;
403 case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break;
404 case SFX_RESUME_ALL: me->reallyResumeAllNow(); break;
405 case SFX_LISTENER: me->reallyPositionListenerNow(); break;
406 case SFX_UPDATE: me->reallyUpdateNow(current); break;
407 case SFX_MUSIC_START:
408 {
409 current->m_music_information->setDefaultVolume();
410 current->m_music_information->startMusic(); break;
411 }
412 case SFX_MUSIC_STOP:
413 current->m_music_information->stopMusic(); break;
414 case SFX_MUSIC_PAUSE:
415 current->m_music_information->pauseMusic(); break;
416 case SFX_MUSIC_RESUME:
417 current->m_music_information->resumeMusic();
418 // This might be necessasary if the volume was changed
419 // in the in-game menu
420 current->m_music_information->setDefaultVolume(); break;
421 case SFX_MUSIC_SWITCH_FAST:
422 current->m_music_information->switchToFastMusic(); break;
423 case SFX_MUSIC_SET_TMP_VOLUME:
424 {
425 MusicInformation *mi = current->m_music_information;
426 mi->setTemporaryVolume(current->m_parameter.getX()); break;
427 }
428 case SFX_MUSIC_WAITING:
429 current->m_music_information->setMusicWaiting(); break;
430 case SFX_MUSIC_DEFAULT_VOLUME:
431 {
432 current->m_music_information->setDefaultVolume();
433 break;
434 }
435 case SFX_CREATE_SOURCE:
436 current->m_sfx->init(); break;
437 default: assert("Not yet supported.");
438 }
439 delete current;
440 current = NULL;
441 PROFILER_POP_CPU_MARKER();
442 PROFILER_PUSH_CPU_MARKER("yield", 0, 0, 255);
443 // We access the size without lock, doesn't matter if we
444 // should get an incorrect value because of concurrent read/writes
445 if (me->m_sfx_commands.getData().size() == 0 && me->sfxAllowed())
446 {
447 // Wait some time to let other threads run, then queue an
448 // update event to keep music playing.
449 uint64_t t = StkTime::getMonoTimeMs();
450 StkTime::sleep(1);
451 t = StkTime::getMonoTimeMs() - t;
452 me->queue(SFX_UPDATE, (SFXBase*)NULL, float(t / 1000.0));
453 }
454 ul = me->m_sfx_commands.acquireMutex();
455 PROFILER_POP_CPU_MARKER();
456 } // while
457
458 // Signal that the sfx manager can now be deleted.
459 // We signal this even before cleaning up memory, since there is no
460 // need to keep the user waiting for STK to exit.
461 me->setCanBeDeleted();
462
463 // Clean up memory to avoid leak detection
464 while(!me->m_sfx_commands.getData().empty())
465 {
466 delete me->m_sfx_commands.getData().front();
467 me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
468 }
469 #endif
470 return;
471 } // mainLoop
472
473 //----------------------------------------------------------------------------
474 /** Called when sound is globally switched on or off. It either pauses or
475 * resumes all sound effects.
476 * \param on If sound is switched on or off.
477 */
toggleSound(const bool on)478 void SFXManager::toggleSound(const bool on)
479 {
480 // When activating SFX, load all buffers
481 if (on)
482 {
483 std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.begin();
484 for (; i != m_all_sfx_types.end(); i++)
485 {
486 SFXBuffer* buffer = (*i).second;
487 buffer->load();
488 }
489
490 reallyResumeAllNow();
491 m_all_sfx.lock();
492 const int sfx_amount = (int)m_all_sfx.getData().size();
493 for (int n=0; n<sfx_amount; n++)
494 {
495 m_all_sfx.getData()[n]->onSoundEnabledBack();
496 }
497 m_all_sfx.unlock();
498 }
499 else
500 {
501 // First stop all sfx that are not looped
502 const int sfx_amount = (int)m_all_sfx.getData().size();
503 m_all_sfx.lock();
504 for (int i=0; i<sfx_amount; i++)
505 {
506 if(!m_all_sfx.getData()[i]->isLooped())
507 {
508 m_all_sfx.getData()[i]->reallyStopNow();
509 }
510 }
511 m_all_sfx.unlock();
512 pauseAll();
513 }
514 } // toggleSound
515
516 //----------------------------------------------------------------------------
517 /** Returns if sfx can be played. This means sfx are enabled and
518 * the manager is correctly initialised.
519 */
sfxAllowed()520 bool SFXManager::sfxAllowed()
521 {
522 if (STKProcess::getType() != PT_MAIN)
523 return false;
524 if(!UserConfigParams::m_sfx || !m_initialized)
525 return false;
526 else
527 return true;
528 } // sfxAllowed
529
530 //----------------------------------------------------------------------------
531 /** Loads all sounds specified in the sound config file.
532 */
loadSfx()533 void SFXManager::loadSfx()
534 {
535 std::string sfx_config_name = file_manager->getAsset(FileManager::SFX, "sfx.xml");
536 XMLNode* root = file_manager->createXMLTree(sfx_config_name);
537 if (!root || root->getName()!="sfx-config")
538 {
539 Log::fatal("SFXManager", "Could not read sound effects XML file '%s'.",
540 sfx_config_name.c_str());
541 }
542
543 int i;
544
545 const int amount = root->getNumNodes();
546 for (i=0; i<amount; i++)
547 {
548 const XMLNode* node = root->getNode(i);
549
550 if (node->getName() == "sfx")
551 {
552 loadSingleSfx(node, "", false);
553 }
554 else
555 {
556 Log::warn("SFXManager", "Unknown node '%s' in sfx XML file '%s'.",
557 node->getName().c_str(), sfx_config_name.c_str());
558 throw std::runtime_error("Unknown node in sfx XML file");
559 }
560 }// nend for
561
562 delete root;
563
564 // Now load them in parallel
565 const int max = (int)m_all_sfx_types.size();
566 SFXBuffer **array = new SFXBuffer *[max];
567 i = 0;
568
569 for (std::map<std::string, SFXBuffer*>::iterator it = m_all_sfx_types.begin();
570 it != m_all_sfx_types.end(); it++)
571 {
572 SFXBuffer* const buffer = (*it).second;
573 array[i++] = buffer;
574 }
575
576 for (i = 0; i < max; i++)
577 {
578 array[i]->load();
579 }
580
581 delete [] array;
582 } // loadSfx
583
584 // -----------------------------------------------------------------------------
585 /** Introduces a mechanism by which one can load sound effects beyond the basic
586 * enumerated types. This will be used when loading custom sound effects for
587 * individual karts (character voices) so that we can avoid creating an
588 * enumeration for each effect, for each kart.
589 * \param sfx_name
590 * \param sfxFile must be an absolute pathname
591 * \return whether loading this sound effect was successful
592
593 */
addSingleSfx(const std::string & sfx_name,const std::string & sfx_file,bool positional,float rolloff,float max_dist,float gain,const bool load)594 SFXBuffer* SFXManager::addSingleSfx(const std::string &sfx_name,
595 const std::string &sfx_file,
596 bool positional,
597 float rolloff,
598 float max_dist,
599 float gain,
600 const bool load)
601 {
602
603 SFXBuffer* buffer = new SFXBuffer(sfx_file, positional, rolloff,
604 max_dist, gain);
605
606 m_all_sfx_types[sfx_name] = buffer;
607
608 if (!m_initialized)
609 {
610 // Keep the buffer even if SFX is disabled, in case
611 // SFX is enabled back later
612 return NULL;
613 }
614
615 if (UserConfigParams::logMisc())
616 Log::debug("SFXManager", "Loading SFX %s", sfx_file.c_str());
617
618 if (load && buffer->load()) return buffer;
619
620 return NULL;
621 } // addSingleSFX
622
623 //----------------------------------------------------------------------------
624 /** Loads a single sfx from the XML specification.
625 * \param node The XML node with the data for this sfx.
626 */
loadSingleSfx(const XMLNode * node,const std::string & path,const bool load)627 SFXBuffer* SFXManager::loadSingleSfx(const XMLNode* node,
628 const std::string &path,
629 const bool load)
630 {
631 std::string filename;
632
633 if (node->get("filename", &filename) == 0)
634 {
635 Log::error("SFXManager",
636 "The 'filename' attribute is mandatory in the SFX XML file!");
637 return NULL;
638 }
639
640 std::string sfx_name = StringUtils::removeExtension(filename);
641
642 if(m_all_sfx_types.find(sfx_name)!=m_all_sfx_types.end())
643 {
644 Log::error("SFXManager",
645 "There is already a sfx named '%s' installed - new one is ignored.",
646 sfx_name.c_str());
647 return NULL;
648 }
649
650 // Only use the filename if no full path is specified. This is used
651 // to load terrain specific sfx.
652 const std::string full_path = (path == "")
653 ? file_manager->getAsset(FileManager::SFX,filename)
654 : path+"/"+filename;
655
656 SFXBuffer tmpbuffer(full_path, node);
657
658 return addSingleSfx(sfx_name, full_path,
659 tmpbuffer.isPositional(),
660 tmpbuffer.getRolloff(),
661 tmpbuffer.getMaxDist(),
662 tmpbuffer.getGain(),
663 load);
664
665 } // loadSingleSfx
666
667 //----------------------------------------------------------------------------
668 /** Creates a new SFX object. The memory for this object is managed completely
669 * by the SFXManager. This makes it easy to use different implementations of
670 * SFX - since createSoundSource can return whatever type is used. To free the memory,
671 * call deleteSFX().
672 * \param id Identifier of the sound effect to create.
673 */
createSoundSource(SFXBuffer * buffer,const bool add_to_SFX_list,const bool owns_buffer)674 SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer,
675 const bool add_to_SFX_list,
676 const bool owns_buffer)
677 {
678 bool positional = false;
679
680 if (RaceManager::get()->getNumLocalPlayers() < 2)
681 {
682 positional = buffer->isPositional();
683 }
684
685 SFXBase* sfx = NULL;
686
687 #ifdef ENABLE_SOUND
688 if (UserConfigParams::m_enable_sound && STKProcess::getType() == PT_MAIN)
689 {
690 //assert( alIsBuffer(buffer->getBufferID()) ); crashes on server
691 sfx = new SFXOpenAL(buffer, positional, buffer->getGain(), owns_buffer);
692 }
693 else
694 #endif
695 {
696 sfx = new DummySFX(buffer, positional, buffer->getGain());
697
698 if (owns_buffer)
699 {
700 delete buffer;
701 }
702 }
703
704 sfx->setMasterVolume(m_master_gain);
705
706 if (add_to_SFX_list)
707 {
708 m_all_sfx.lock();
709 m_all_sfx.getData().push_back(sfx);
710 m_all_sfx.unlock();
711 }
712
713 return sfx;
714 } // createSoundSource
715
716 //----------------------------------------------------------------------------
createSoundSource(const std::string & name,const bool add_to_SFXList)717 SFXBase* SFXManager::createSoundSource(const std::string &name,
718 const bool add_to_SFXList)
719 {
720 std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.find(name);
721 if ( i == m_all_sfx_types.end() )
722 {
723 Log::error("SFXManager",
724 "SFXManager::createSoundSource could not find the "
725 "requested sound effect : '%s'.", name.c_str());
726 return NULL;
727 }
728
729 return createSoundSource( i->second, add_to_SFXList );
730 } // createSoundSource
731
732 //----------------------------------------------------------------------------
733
getBuffer(const std::string & name)734 SFXBuffer* SFXManager::getBuffer(const std::string &name)
735 {
736 std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.find(name);
737 if (i == m_all_sfx_types.end())
738 {
739 Log::error("SFXManager",
740 "SFXManager::getBuffer could not find the "
741 "requested sound effect : '%s'.", name.c_str());
742 return NULL;
743 }
744
745 return i->second;
746 }
747
748 //----------------------------------------------------------------------------
749 /** Returns true if a sfx with the given name exists.
750 * \param name The internal name of the sfx (not the name of the ogg file)
751 */
soundExist(const std::string & name)752 bool SFXManager::soundExist(const std::string &name)
753 {
754 return m_all_sfx_types.find(name) != m_all_sfx_types.end();
755 } // soundExist
756
757 //----------------------------------------------------------------------------
758 /** This function removes a sfx buffer info entry from the mapping, and
759 * frees the openal buffer.
760 * \param name The name of the mapping entry to remove.
761 */
deleteSFXMapping(const std::string & name)762 void SFXManager::deleteSFXMapping(const std::string &name)
763 {
764 std::map<std::string, SFXBuffer*>::iterator i;
765 i = m_all_sfx_types.find(name);
766
767 if (i == m_all_sfx_types.end())
768 {
769 Log::warn("SFXManager",
770 "SFXManager::deleteSFXMapping : Warning: sfx not found in list.");
771 return;
772 }
773 (*i).second->unload();
774
775 m_all_sfx_types.erase(i);
776
777 } // deleteSFXMapping
778
779 //----------------------------------------------------------------------------
780 /** Make sure that the sfx thread is started at least once per frame. It also
781 * adds an update command for the music manager.
782 * \param dt Time step size.
783 */
update()784 void SFXManager::update()
785 {
786 #ifdef ENABLE_SOUND
787 if (!UserConfigParams::m_enable_sound)
788 return;
789
790 queue(SFX_UPDATE, (SFXBase*)NULL);
791 // Wake up the sfx thread to handle all queued up audio commands.
792 m_condition_variable.notify_one();
793 #endif
794 } // update
795
796 //----------------------------------------------------------------------------
797 /** Updates the status of all playing sfx (to test if they are finished).
798 * This function is executed once per frame (triggered by the audio thread).
799 * \param current The sfx command - used to get timestep information.
800 */
reallyUpdateNow(SFXCommand * current)801 void SFXManager::reallyUpdateNow(SFXCommand *current)
802 {
803 #ifdef ENABLE_SOUND
804 if (!UserConfigParams::m_enable_sound)
805 return;
806
807 if (m_last_update_time == std::numeric_limits<uint64_t>::max())
808 {
809 // first time
810 m_last_update_time = StkTime::getMonoTimeMs();
811 }
812
813 uint64_t previous_update_time = m_last_update_time;
814 m_last_update_time = StkTime::getMonoTimeMs();
815 float dt = float(m_last_update_time - previous_update_time) / 1000.0f;
816
817 assert(current->m_command==SFX_UPDATE);
818 if (music_manager->getCurrentMusic())
819 music_manager->getCurrentMusic()->update(dt);
820 m_all_sfx.lock();
821 for (std::vector<SFXBase*>::iterator i = m_all_sfx.getData().begin();
822 i != m_all_sfx.getData().end(); i++)
823 {
824 if((*i)->getStatus()==SFXBase::SFX_PLAYING)
825 (*i)->updatePlayingSFX(dt);
826 } // for i in m_all_sfx
827 m_all_sfx.unlock();
828
829 // We need to lock the quick sounds during update, since adding more
830 // quick sounds by another thread could invalidate the iterator.
831 m_quick_sounds.lock();
832 std::map<std::string, SFXBase*>::iterator i = m_quick_sounds.getData().begin();
833 for (; i != m_quick_sounds.getData().end(); i++)
834 {
835 if (i->second->getStatus() == SFXBase::SFX_PLAYING)
836 i->second->updatePlayingSFX(dt);
837 } // for i in m_all_sfx
838 m_quick_sounds.unlock();
839 #endif
840 } // reallyUpdateNow
841
842 //----------------------------------------------------------------------------
843 /** Delete a sound effect object, and removes it from the internal list of
844 * all SFXs. This call deletes the object, and removes it from the list of
845 * all SFXs.
846 * \param sfx SFX object to delete.
847 */
deleteSFX(SFXBase * sfx)848 void SFXManager::deleteSFX(SFXBase *sfx)
849 {
850 if(sfx) sfx->reallyStopNow();
851 std::vector<SFXBase*>::iterator i;
852
853 // The whole block needs to be locked, otherwise the iterator
854 // could become invalid.
855 m_all_sfx.lock();
856 i=std::find(m_all_sfx.getData().begin(), m_all_sfx.getData().end(), sfx);
857
858 if(i==m_all_sfx.getData().end())
859 {
860 Log::warn("SFXManager",
861 "SFXManager::deleteSFX : Warning: sfx '%s' %lx not found in list.",
862 sfx->getBuffer()->getFileName().c_str(), sfx);
863 m_all_sfx.unlock();
864 return;
865 }
866
867 m_all_sfx.getData().erase(i);
868 m_all_sfx.unlock();
869
870 delete sfx;
871 } // deleteSFX
872
873 //----------------------------------------------------------------------------
874 /** Pauses all looping SFXs. Non-looping SFX will be finished, since it's
875 * otherwise not possible to determine which SFX must be resumed (i.e. were
876 * actually playing at the time pause was called).
877 */
pauseAll()878 void SFXManager::pauseAll()
879 {
880 if (!sfxAllowed()) return;
881 queue(SFX_PAUSE_ALL);
882 } // pauseAll
883
884 //----------------------------------------------------------------------------
885 /** Pauses all looping SFXs. Non-looping SFX will be finished, since it's
886 * otherwise not possible to determine which SFX must be resumed (i.e. were
887 * actually playing at the time pause was called.
888 */
reallyPauseAllNow()889 void SFXManager::reallyPauseAllNow()
890 {
891 m_all_sfx.lock();
892 for (std::vector<SFXBase*>::iterator i= m_all_sfx.getData().begin();
893 i!=m_all_sfx.getData().end(); i++)
894 {
895 (*i)->reallyPauseNow();
896 } // for i in m_all_sfx
897 m_all_sfx.unlock();
898 } // pauseAll
899
900 //----------------------------------------------------------------------------
901 /** Resumes all paused SFXs. If sound is disabled, does nothing.
902 */
resumeAll()903 void SFXManager::resumeAll()
904 {
905 // ignore unpausing if sound is disabled
906 if (!sfxAllowed()) return;
907 queue(SFX_RESUME_ALL);
908 } // resumeAll
909
910 //----------------------------------------------------------------------------
911 /** Resumes all paused SFXs. If sound is disabled, does nothing.
912 */
reallyResumeAllNow()913 void SFXManager::reallyResumeAllNow()
914 {
915 m_all_sfx.lock();
916 for (std::vector<SFXBase*>::iterator i =m_all_sfx.getData().begin();
917 i!=m_all_sfx.getData().end(); i++)
918 {
919 (*i)->reallyResumeNow();
920 } // for i in m_all_sfx
921 m_all_sfx.unlock();
922 } // resumeAll
923
924 //-----------------------------------------------------------------------------
925 /** Returns whether or not an openal error has occurred. If so, an error
926 * message is printed containing the given context.
927 * \param context Context to specify in the error message.
928 * \return True if no error happened.
929 */
checkError(const std::string & context)930 bool SFXManager::checkError(const std::string &context)
931 {
932 #ifdef ENABLE_SOUND
933 if (!UserConfigParams::m_enable_sound)
934 return true;
935
936 // Check (and clear) the error flag
937 int error = alGetError();
938
939 if (error != AL_NO_ERROR)
940 {
941 Log::error("SFXManager", "SFXOpenAL OpenAL error while %s: %s",
942 context.c_str(), SFXManager::getErrorString(error).c_str());
943 return false;
944 }
945 #endif
946 return true;
947 } // checkError
948
949 //-----------------------------------------------------------------------------
950 /** Sets the master volume for all sound effects.
951 * \param gain The volume to set.
952 */
setMasterSFXVolume(float gain)953 void SFXManager::setMasterSFXVolume(float gain)
954 {
955 if (gain > 1.0) gain = 1.0f;
956 if (gain < 0.0f) gain = 0.0f;
957
958 m_master_gain = gain;
959
960 // regular SFX
961 {
962 m_all_sfx.lock();
963 for (std::vector<SFXBase*>::iterator i =m_all_sfx.getData().begin();
964 i!=m_all_sfx.getData().end(); i++)
965 {
966 (*i)->setMasterVolume(m_master_gain);
967 } // for i in m_all_sfx
968 m_all_sfx.unlock();
969 }
970
971 // quick SFX
972 {
973 m_quick_sounds.lock();
974 std::map<std::string, SFXBase*>::iterator i = m_quick_sounds.getData().begin();
975 for (; i != m_quick_sounds.getData().end(); i++)
976 {
977 (*i).second->setMasterVolume(m_master_gain);
978 }
979 m_quick_sounds.unlock();
980 }
981
982 } // setMasterSFXVolume
983
984 //-----------------------------------------------------------------------------
getErrorString(int err)985 const std::string SFXManager::getErrorString(int err)
986 {
987 #ifdef ENABLE_SOUND
988 if (!UserConfigParams::m_enable_sound)
989 return std::string("sound disabled");
990
991 switch(err)
992 {
993 case AL_NO_ERROR: return std::string("AL_NO_ERROR" );
994 case AL_INVALID_NAME: return std::string("AL_INVALID_NAME" );
995 case AL_INVALID_ENUM: return std::string("AL_INVALID_ENUM" );
996 case AL_INVALID_VALUE: return std::string("AL_INVALID_VALUE" );
997 case AL_INVALID_OPERATION: return std::string("AL_INVALID_OPERATION");
998 case AL_OUT_OF_MEMORY: return std::string("AL_OUT_OF_MEMORY" );
999 default: return std::string("UNKNOWN");
1000 };
1001 #endif
1002
1003 return std::string("sound disabled");
1004 } // getErrorString
1005
1006 //-----------------------------------------------------------------------------
1007 /** Sets the position and orientation of the listener.
1008 * \param position Position of the listener.
1009 * \param front Which way the listener is facing.
1010 * \param up The up direction of the listener.
1011 */
positionListener(const Vec3 & position,const Vec3 & front,const Vec3 & up)1012 void SFXManager::positionListener(const Vec3 &position, const Vec3 &front,
1013 const Vec3 &up)
1014 {
1015 m_listener_position.lock();
1016 m_listener_position.getData() = position;
1017 m_listener_front = front;
1018 m_listener_up = up;
1019 m_listener_position.unlock();
1020 queue(SFX_LISTENER);
1021 } // positionListener
1022
1023 //-----------------------------------------------------------------------------
1024 /** Sets the position and orientation of the listener.
1025 * \param position Position of the listener.
1026 * \param front Which way the listener is facing.
1027 */
reallyPositionListenerNow()1028 void SFXManager::reallyPositionListenerNow()
1029 {
1030 #ifdef ENABLE_SOUND
1031 if (!sfxAllowed()) return;
1032
1033 m_listener_position.lock();
1034 {
1035
1036 //forward vector
1037 float orientation[6];
1038 orientation[0] = m_listener_front.getX();
1039 orientation[1] = m_listener_front.getY();
1040 orientation[2] = -m_listener_front.getZ();
1041
1042 //up vector
1043 orientation[3] = m_listener_up.getX();
1044 orientation[4] = m_listener_up.getY();
1045 orientation[5] = -m_listener_up.getZ();
1046
1047 const Vec3 &pos = m_listener_position.getData();
1048 alListener3f(AL_POSITION, pos.getX(), pos.getY(), -pos.getZ());
1049 alListenerfv(AL_ORIENTATION, orientation);
1050 }
1051 m_listener_position.unlock();
1052
1053 #endif
1054 } // reallyPositionListenerNow
1055
1056 //-----------------------------------------------------------------------------
1057 /** Positional sound is cool, but creating a new object just to play a simple
1058 * menu sound is not. This function allows for 'quick sounds' in a single call.
1059 * \param sound_type Internal name of the sfx to play.
1060 * \return a pointer to the sound, for instance to check when the sound finished.
1061 * don't delete the returned pointer.
1062 */
quickSound(const std::string & sound_type)1063 SFXBase* SFXManager::quickSound(const std::string &sound_type)
1064 {
1065 #ifdef ENABLE_SOUND
1066 if (!sfxAllowed()) return NULL;
1067
1068 std::unique_lock<std::mutex> ul = m_quick_sounds.acquireMutex();
1069 std::map<std::string, SFXBase*>::iterator sound =
1070 m_quick_sounds.getData().find(sound_type);
1071
1072 if (sound == m_quick_sounds.getData().end())
1073 {
1074 // sound not yet in our local list of quick sounds
1075 SFXBase* new_sound = createSoundSource(sound_type, false);
1076 if (new_sound == NULL) return NULL;
1077 new_sound->play();
1078 m_quick_sounds.getData()[sound_type] = new_sound;
1079 return new_sound;
1080 }
1081 else
1082 {
1083 SFXBase *base_sound = sound->second;
1084 if (base_sound->getStatus() != SFXBase::SFX_PLAYING)
1085 base_sound->play();
1086 return base_sound;
1087 }
1088 #else
1089 return NULL;
1090 #endif
1091 } // quickSound
1092
1093