diff --git a/src/audio/music_information.hpp b/src/audio/music_information.hpp index d25ca3afe..b35fd5385 100644 --- a/src/audio/music_information.hpp +++ b/src/audio/music_information.hpp @@ -76,6 +76,30 @@ private: // The constructor is private so that the // static create function must be used. MusicInformation (const XMLNode *root, const std::string &filename); + + // Declare the following functions private, but allow the SFXManager + // and music manager to access them. This makes sure that only the sfx thread calls + // openal/vorbis etc, and so makes it all thread safe. +private: + friend class SFXManager; + friend class MusicManager; + void update(float dt); + void startMusic(); + void stopMusic(); + void pauseMusic(); + void resumeMusic(); + void volumeMusic(float gain); + void switchToFastMusic(); + void setTemporaryVolume(float gain); + // ------------------------------------------------------------------------ + /** Resets a temporary volume change. */ + void resetTemporaryVolume() { volumeMusic(m_adjusted_gain); } + // ------------------------------------------------------------------------ + /** Sets the music to be waiting, i.e. startMusic still needs to be + * called. Used to pre-load track music during track loading time. */ + void setMusicWaiting() { m_music_waiting = true; } + // ------------------------------------------------------------------------ + public: LEAK_CHECK() @@ -85,14 +109,6 @@ public: ~MusicInformation (); static MusicInformation *create(const std::string &filename); void addMusicToTracks(); - void update(float dt); - void startMusic(); - void stopMusic(); - void pauseMusic(); - void resumeMusic(); - void volumeMusic(float gain); - void setTemporaryVolume(float gain); - void switchToFastMusic(); bool isPlaying() const; // ------------------------------------------------------------------------ @@ -109,13 +125,6 @@ public: const std::string& getFastFilename() const { return m_fast_filename; } // ------------------------------------------------------------------------ float getMaxPitch() const { return m_max_pitch; } - // ------------------------------------------------------------------------ - /** Sets the music to be waiting, i.e. startMusic still needs to be - * called. Used to pre-load track music during track loading time. */ - void setMusicWaiting () {m_music_waiting = true;} - // ------------------------------------------------------------------------ - /** Resets a temporary volume change. */ - void resetTemporaryVolume() { volumeMusic(m_adjusted_gain); } }; // MusicInformation #endif diff --git a/src/audio/music_manager.cpp b/src/audio/music_manager.cpp index c3d41ef19..5ee8ca732 100644 --- a/src/audio/music_manager.cpp +++ b/src/audio/music_manager.cpp @@ -159,6 +159,16 @@ void MusicManager::addMusicToTracks() } } // addMusicToTracks +//----------------------------------------------------------------------------- +/** Special shortcut vor overworld (which skips other phases where the music + * would normally be started. + */ +void MusicManager::startMusic() +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_START, m_current_music); +} // startMusic + //----------------------------------------------------------------------------- /** Schedules the indicated music to be played next. * \param mi Music information of the music to be played. @@ -182,7 +192,7 @@ void MusicManager::startMusic(MusicInformation* mi, bool start_right_now) if(!mi || !UserConfigParams::m_music || !m_initialized) return; - mi->volumeMusic(m_masterGain); + mi->volumeMusic(m_master_gain); SFXManager::get()->queue(start_right_now ? SFXManager::SFX_MUSIC_START : SFXManager::SFX_MUSIC_WAITING, mi); @@ -198,6 +208,59 @@ void MusicManager::stopMusic() } // stopMusic //----------------------------------------------------------------------------- +/** Insert a command into the sfx queue to pause the current music. + */ +void MusicManager::pauseMusic() +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_PAUSE, m_current_music); +} // pauseMusic + +//----------------------------------------------------------------------------- +/** Inserts a resume current music event into the queue. + */ +void MusicManager::resumeMusic() +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_RESUME, m_current_music); +} // resumeMusic + +//----------------------------------------------------------------------------- +/** Switches to fast (last lap ) music (if defined for the current music). + */ +void MusicManager::switchToFastMusic() +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_SWITCH_FAST, + m_current_music); +} // switchToFastMusic + +//----------------------------------------------------------------------------- +/** Queues a command to temporarily change the volume. This is used to make + * the music a bit quieter while the 'last lap fanfare' is being played. + * \param gain The temporary volume value. + */ +void MusicManager::setTemporaryVolume(float gain) +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_SET_TMP_VOLUME, + m_current_music, gain); +} // setTemporaryVolume + +//----------------------------------------------------------------------------- +/** Queues a command for the sfx manager to reset a temporary volume change. + */ +void MusicManager::resetTemporaryVolume() +{ + if (m_current_music) + SFXManager::get()->queue(SFXManager::SFX_MUSIC_RESET_TMP_VOLUME, + m_current_music); +} // resetTemporaryVolume + +//----------------------------------------------------------------------------- +/** Sets the master music volume. + * \param gain The volume. + */ void MusicManager::setMasterMusicVolume(float gain) { if(gain > 1.0) @@ -205,15 +268,15 @@ void MusicManager::setMasterMusicVolume(float gain) if(gain < 0.0f) gain = 0.0f; - m_masterGain = gain; - if(m_current_music) m_current_music->volumeMusic(m_masterGain); + m_master_gain = gain; + if(m_current_music) m_current_music->volumeMusic(m_master_gain); - UserConfigParams::m_music_volume = m_masterGain; + UserConfigParams::m_music_volume = m_master_gain; } // setMasterMusicVolume //----------------------------------------------------------------------------- -/** - */ +/** @throw runtime_error if the music file could not be found/opened +*/ MusicInformation* MusicManager::getMusicInformation(const std::string& filename) { if(filename=="") @@ -229,7 +292,7 @@ MusicInformation* MusicManager::getMusicInformation(const std::string& filename) MusicInformation *mi = MusicInformation::create(filename); if(mi) { - mi->volumeMusic(m_masterGain); + mi->volumeMusic(m_master_gain); m_all_music[basename] = mi; } return mi; diff --git a/src/audio/music_manager.hpp b/src/audio/music_manager.hpp index 98b33537a..f77ce1a0d 100644 --- a/src/audio/music_manager.hpp +++ b/src/audio/music_manager.hpp @@ -42,42 +42,44 @@ private: /** If the sound could not be initialized, e.g. if the player doesn't has * a sound card, we want to avoid anything sound related so we crash the * game. */ - bool m_initialized; - std::map - m_all_music; + bool m_initialized; - void loadMusicInformation(); - float m_masterGain; + /** Stores all music information files (read from the .music files). */ + std::map + m_all_music; + float m_master_gain; + + void loadMusicInformation(); + void loadMusicFromOneDir(const std::string& dir); public: - MusicManager(); - virtual ~MusicManager(); + MusicManager(); + virtual ~MusicManager(); + MusicInformation* getMusicInformation(const std::string& filename); + void addMusicToTracks(); - void startMusic(MusicInformation* mi, - bool start_right_now=true); - void stopMusic(); - bool initialized() const { return m_initialized; } - void pauseMusic() {if(m_current_music) - m_current_music->pauseMusic(); } - void resumeMusic() {if(m_current_music) - m_current_music->resumeMusic(); } - void switchToFastMusic() {if(m_current_music) - m_current_music->switchToFastMusic();} - - void setMasterMusicVolume(float gain); - float getMasterMusicVolume() const { return m_masterGain; } - - MusicInformation *getCurrentMusic() {return m_current_music; } - - /** - * @throw runtime_error if the music file could not be found/opened - */ - MusicInformation *getMusicInformation(const std::string& filename); - - void loadMusicFromOneDir(const std::string& dir); - void addMusicToTracks(); - - void clearCurrentMusic() { m_current_music = NULL; } + void startMusic(); + void startMusic(MusicInformation* mi, + bool start_right_now=true); + void stopMusic(); + void pauseMusic(); + void resumeMusic(); + void switchToFastMusic(); + void setMasterMusicVolume(float gain); + void resetTemporaryVolume(); + void setTemporaryVolume(float gain); + // ------------------------------------------------------------------------ + /** Returns the master volume. */ + float getMasterMusicVolume() const { return m_master_gain; } + // ------------------------------------------------------------------------ + /** Returns if the music system is initialised. */ + bool initialized() const { return m_initialized; } + // ------------------------------------------------------------------------ + /** Returns the information object of the current music. */ + MusicInformation* getCurrentMusic() { return m_current_music; } + // ------------------------------------------------------------------------ + /** Stops and removes the current music. */ + void clearCurrentMusic() { m_current_music = NULL; } }; extern MusicManager* music_manager; diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index ded724e45..1baf827be 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -202,11 +202,25 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p) } // queue (Vec3) //---------------------------------------------------------------------------- +/** Queues a command for the music manager. + * \param mi The music for which the command is. + */ void SFXManager::queue(SFXCommands command, MusicInformation *mi) { SFXCommand *sfx_command = new SFXCommand(command, mi); queueCommand(sfx_command); } // queue(MusicInformation) +//---------------------------------------------------------------------------- +/** Queues a command for the music manager that takes a floating point value + * (e.g. setTemporaryVolume). + * \param mi The music for which the command is. + * \param f The floating point parameter. + */ +void SFXManager::queue(SFXCommands command, MusicInformation *mi, float f) +{ + SFXCommand *sfx_command = new SFXCommand(command, mi, f); + queueCommand(sfx_command); +} // queue(MusicInformation) //---------------------------------------------------------------------------- /** Enqueues a command to the sfx queue threadsafe. Then signal the @@ -286,40 +300,57 @@ void* SFXManager::mainLoop(void *obj) break; } me->m_sfx_commands.unlock(); - switch(current->m_command) + switch (current->m_command) { - case SFX_PLAY: current->m_sfx->reallyPlayNow(); break; - case SFX_STOP: current->m_sfx->reallyStopNow(); break; - case SFX_PAUSE: current->m_sfx->reallyPauseNow(); break; - case SFX_RESUME: current->m_sfx->reallyResumeNow(); break; + case SFX_PLAY: current->m_sfx->reallyPlayNow(); break; + case SFX_STOP: current->m_sfx->reallyStopNow(); break; + case SFX_PAUSE: current->m_sfx->reallyPauseNow(); break; + case SFX_RESUME: current->m_sfx->reallyResumeNow(); break; case SFX_SPEED: current->m_sfx->reallySetSpeed( - current->m_parameter.getX()); break; + current->m_parameter.getX()); break; case SFX_POSITION: current->m_sfx->reallySetPosition( - current->m_parameter); break; + current->m_parameter); break; case SFX_VOLUME: current->m_sfx->reallySetVolume( - current->m_parameter.getX()); break; - case SFX_MASTER_VOLUME: - current->m_sfx->reallySetMasterVolumeNow( - current->m_parameter.getX()); break; + current->m_parameter.getX()); break; + case SFX_MASTER_VOLUME: + current->m_sfx->reallySetMasterVolumeNow( + current->m_parameter.getX()); break; case SFX_LOOP: current->m_sfx->reallySetLoop( - current->m_parameter.getX()!=0); break; - case SFX_DELETE: { - me->deleteSFX(current->m_sfx); break; - } - case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break; - case SFX_RESUME_ALL: me->reallyResumeAllNow(); break; - case SFX_LISTENER: me->reallyPositionListenerNow(); break; - case SFX_UPDATE: me->reallyUpdateNow(current); break; + current->m_parameter.getX() != 0); break; + case SFX_DELETE: me->deleteSFX(current->m_sfx); break; + case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break; + case SFX_RESUME_ALL: me->reallyResumeAllNow(); break; + case SFX_LISTENER: me->reallyPositionListenerNow(); break; + case SFX_UPDATE: me->reallyUpdateNow(current); break; case SFX_MUSIC_START: - current->m_music_information->startMusic(); break; + current->m_music_information->startMusic(); break; case SFX_MUSIC_STOP: - current->m_music_information->stopMusic(); break; - case SFX_MUSIC_WAITING: - current->m_music_information->setMusicWaiting(); break; + current->m_music_information->stopMusic(); break; + case SFX_MUSIC_PAUSE: + current->m_music_information->pauseMusic(); break; + case SFX_MUSIC_RESUME: + current->m_music_information->resumeMusic(); break; + case SFX_MUSIC_SWITCH_FAST: + current->m_music_information->switchToFastMusic(); break; + case SFX_MUSIC_SET_TMP_VOLUME: + { + MusicInformation *mi = current->m_music_information; + mi->setTemporaryVolume(current->m_parameter.getX()); break; + } + case SFX_MUSIC_RESET_TMP_VOLUME: + { + MusicInformation *mi = current->m_music_information; + mi->resetTemporaryVolume(); break; + } + case SFX_MUSIC_WAITING: + current->m_music_information->setMusicWaiting(); break; default: assert("Not yet supported."); } - delete current; - current = NULL; + static SFXCommand *prev = NULL; + delete prev; + prev = current; + //delete current; + //current = NULL; me->m_sfx_commands.lock(); } // while @@ -622,7 +653,7 @@ void SFXManager::deleteSFXMapping(const std::string &name) */ void SFXManager::update(float dt) { - queue(SFX_UPDATE, NULL, dt); + queue(SFX_UPDATE, (SFXBase*)NULL, dt); // Wake up the sfx thread to handle all queued up audio commands. pthread_cond_signal(&m_cond_request); } // update diff --git a/src/audio/sfx_manager.hpp b/src/audio/sfx_manager.hpp index 5c3a43ca3..7cfa2e743 100644 --- a/src/audio/sfx_manager.hpp +++ b/src/audio/sfx_manager.hpp @@ -79,7 +79,11 @@ public: SFX_UPDATE, SFX_MUSIC_START, SFX_MUSIC_STOP, - SFX_MUSIC_UPDATE, + SFX_MUSIC_PAUSE, + SFX_MUSIC_RESUME, + SFX_MUSIC_SWITCH_FAST, + SFX_MUSIC_SET_TMP_VOLUME, + SFX_MUSIC_RESET_TMP_VOLUME, SFX_MUSIC_WAITING, SFX_EXIT, }; // SFXCommands @@ -135,7 +139,16 @@ private: { m_command = command; m_music_information = mi; - } // SFXCommnd + } // SFXCommnd(MusicInformation*) + // -------------------------------------------------------------------- + /** Constructor for music information commands that take a floating + * point parameter (which is stored in the X value of m_parameter). */ + SFXCommand(SFXCommands command, MusicInformation *mi, float f) + { + m_command = command; + m_parameter.setX(f); + m_music_information = mi; + } // SFXCommnd(MusicInformation *, float) // -------------------------------------------------------------------- SFXCommand(SFXCommands command, SFXBase *base, float parameter) { @@ -205,6 +218,7 @@ public: void queue(SFXCommands command, SFXBase *sfx, float f); void queue(SFXCommands command, SFXBase *sfx, const Vec3 &p); void queue(SFXCommands command, MusicInformation *mi); + void queue(SFXCommands command, MusicInformation *mi, float f); // ------------------------------------------------------------------------ /** Static function to get the singleton sfx manager. */ static SFXManager *get() diff --git a/src/main.cpp b/src/main.cpp index 18bea6fea..5acfb4f71 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1516,7 +1516,8 @@ static void cleanSuperTuxKart() SFXManager::destroy(); // Music manager can not be deleted before the sfx thread is stopped - // (since sfx commands can contain music information). + // (since sfx commands can contain music information, which are + // deleted by the music manager). delete music_manager; // The addons manager might still be called from a currenty running request diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 4d884189e..4b83ee3b2 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -157,8 +157,7 @@ void LinearWorld::update(float dt) if (m_last_lap_sfx_playing && m_last_lap_sfx->getStatus() != SFXBase::SFX_PLAYING) { - if(music_manager->getCurrentMusic()) - music_manager->getCurrentMusic()->resetTemporaryVolume(); + music_manager->resetTemporaryVolume(); m_last_lap_sfx_playing = false; } @@ -288,7 +287,7 @@ void LinearWorld::newLap(unsigned int kart_index) if(music_manager->getCurrentMusic() && music_manager->getMasterMusicVolume() > 0.2f) { - music_manager->getCurrentMusic()->setTemporaryVolume(0.2f); + music_manager->setTemporaryVolume(0.2f); } } else diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp index 187856fe9..9097c4add 100644 --- a/src/modes/overworld.cpp +++ b/src/modes/overworld.cpp @@ -114,9 +114,8 @@ void OverWorld::update(float dt) // so we have to start music 'manually', since we skip all phases. World::getWorld()->getTrack()->startMusic(); - if (music_manager->getCurrentMusic() != NULL && - UserConfigParams::m_music) - music_manager->getCurrentMusic()->startMusic(); + if (UserConfigParams::m_music) + music_manager->startMusic(); m_karts[0]->startEngineSFX(); } WorldWithRank::update(dt);