diff --git a/src/audio/dummy_sfx.hpp b/src/audio/dummy_sfx.hpp index 72f2ac17e..b7448d49d 100644 --- a/src/audio/dummy_sfx.hpp +++ b/src/audio/dummy_sfx.hpp @@ -35,7 +35,7 @@ public: /** Late creation, if SFX was initially disabled */ virtual bool init() { return true; } - + virtual void updatePlayingSFX(float dt) {} virtual void setLoop(bool status) {} virtual void reallySetLoop(bool status) {} virtual void setPosition(const Vec3 &p) {} diff --git a/src/audio/sfx_base.hpp b/src/audio/sfx_base.hpp index 50fc0aee9..d8e7785ec 100644 --- a/src/audio/sfx_base.hpp +++ b/src/audio/sfx_base.hpp @@ -52,6 +52,7 @@ public: /** Late creation, if SFX was initially disabled */ virtual bool init() = 0; + virtual void updatePlayingSFX(float dt) = 0; virtual void setPosition(const Vec3 &p) = 0; virtual void reallySetPosition(const Vec3 &p) = 0; virtual void setLoop(bool status) = 0; diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index fb4251931..19a0ea795 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -232,18 +232,6 @@ void SFXManager::queueCommand(SFXCommand *command) m_sfx_commands.unlock(); } // queueCommand -//---------------------------------------------------------------------------- -/** Make sures that the sfx thread is started at least one per frame. It also - * adds an update command for the music manager. - * \param dt Time step size. - */ -void SFXManager::update(float dt) -{ - queue(SFX_UPDATE_MUSIC, NULL, dt); - // Wake up the sfx thread to handle all queued up audio commands. - pthread_cond_signal(&m_cond_request); -} // update - //---------------------------------------------------------------------------- /** Puts a NULL request into the queue, which will trigger the thread to * exit. @@ -309,8 +297,7 @@ void* SFXManager::mainLoop(void *obj) case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break; case SFX_RESUME_ALL: me->reallyResumeAllNow(); break; case SFX_LISTENER: me->reallyPositionListenerNow(); break; - case SFX_UPDATE_MUSIC: music_manager->update( - current->m_parameter.getX()); break; + case SFX_UPDATE: me->reallyUpdateNow(current); break; default: assert("Not yet supported."); } delete current; @@ -593,6 +580,38 @@ void SFXManager::deleteSFXMapping(const std::string &name) } // deleteSFXMapping +//---------------------------------------------------------------------------- +/** Make sures that the sfx thread is started at least one per frame. It also + * adds an update command for the music manager. + * \param dt Time step size. + */ +void SFXManager::update(float dt) +{ + queue(SFX_UPDATE, NULL, dt); + // Wake up the sfx thread to handle all queued up audio commands. + pthread_cond_signal(&m_cond_request); +} // update + +//---------------------------------------------------------------------------- +/** Updates the status of all playing sfx (to test if they are finished). + * This function is executed once per thread (triggered by the +*/ +void SFXManager::reallyUpdateNow(SFXCommand *current) +{ + assert(current->m_command==SFX_UPDATE); + float dt = current->m_parameter.getX(); + music_manager->update(dt); + m_all_sfx.lock(); + for (std::vector::iterator i = m_all_sfx.getData().begin(); + i != m_all_sfx.getData().end(); i++) + { + if((*i)->getStatus()==SFXBase::SFX_PLAYING) + (*i)->updatePlayingSFX(dt); + } // for i in m_all_sfx + m_all_sfx.unlock(); + +} // reallyUpdateNow + //---------------------------------------------------------------------------- /** Delete a sound effect object, and removes it from the internal list of * all SFXs. This call deletes the object, and removes it from the list of diff --git a/src/audio/sfx_manager.hpp b/src/audio/sfx_manager.hpp index 09ba8ba42..47e4cbb74 100644 --- a/src/audio/sfx_manager.hpp +++ b/src/audio/sfx_manager.hpp @@ -74,7 +74,7 @@ public: SFX_VOLUME, SFX_LOOP, SFX_LISTENER, - SFX_UPDATE_MUSIC, + SFX_UPDATE, SFX_EXIT, }; // SFXCommands @@ -220,6 +220,7 @@ public: void resumeAll(); void reallyResumeAllNow(); void update(float dt); + void reallyUpdateNow(SFXCommand *current); bool soundExist(const std::string &name); void setMasterSFXVolume(float gain); float getMasterSFXVolume() const { return m_master_gain; } diff --git a/src/audio/sfx_openal.cpp b/src/audio/sfx_openal.cpp index 20d6a0d59..989dcab56 100644 --- a/src/audio/sfx_openal.cpp +++ b/src/audio/sfx_openal.cpp @@ -51,7 +51,7 @@ SFXOpenAL::SFXOpenAL(SFXBuffer* buffer, bool positional, float gain, m_gain = -1.0f; m_master_gain = 1.0f; m_owns_buffer = owns_buffer; - m_end_time = -1.0f; + m_play_time = 0.0f; // Don't initialise anything else if the sfx manager was not correctly // initialised. First of all the initialisation will not work, and it @@ -123,19 +123,24 @@ bool SFXOpenAL::init() return true; } // init +// ------------------------------------------------------------------------ +/** Updates the status of a playing sfx. If the sound has been played long + * enough, mark it to be finished. This avoid (a potentially costly) + * call to openal. + * \param dt Time step size. + */ +void SFXOpenAL::updatePlayingSFX(float dt) +{ + assert(m_status==SFX_PLAYING); + m_play_time += dt; + if(!m_loop && m_play_time > m_sound_buffer->getDuration()) + m_status = SFX_STOPPED; +} // updatePlayingSFX + // ------------------------------------------------------------------------ /** Returns the status of this sfx. */ SFXBase::SFXStatus SFXOpenAL::getStatus() { - if(m_status==SFX_PLAYING) - { - if(m_loop) return SFX_PLAYING; - if(World::getWorld() && World::getWorld()->getTime() > m_end_time) - { - m_status = SFX_STOPPED; - return m_status; - } - } return m_status; } // getStatus; @@ -295,24 +300,17 @@ void SFXOpenAL::reallyResumeNow() } } // reallyResumeNow -//----------------------------------------------------------------------------- -/** Queues up a delete request for this object. This is necessary to avoid - * a crash if the sfx manager thread might be delayed and access this object - * after it was deleted. - */ -void SFXOpenAL::deleteSFX() -{ - SFXManager::get()->queue(SFXManager::SFX_DELETE, this); -} // deleteSFX - //----------------------------------------------------------------------------- /** This actually queues up the sfx in the sfx manager. It will be started * from a separate thread later (in this frame). */ void SFXOpenAL::play() { + if(m_status==SFX_STOPPED) + m_play_time = 0.0f; + // Technically the sfx is only playing after the sfx thread starts it, - // but this is important to set this here since stk might decide the + // but it is important to set this here since stk might decide to // delete a sfx if it has finished playing (i.e. is in stopped state) // - which can happen if the sfx thread had no time to actually start // it yet. @@ -337,23 +335,6 @@ void SFXOpenAL::reallyPlayNow() alSourcePlay(m_sound_source); SFXManager::checkError("playing"); - - // At non-race time the end time is not important - if(World::getWorld()) - { - float t= World::getWorld()->getTime(); - // A special case: the track intro music starts at world clock = 0, - // and has a duration of 3.7 seconds. So if the game is paused in the - // first 3.7 seconds, the sfx wil be considered to be not finished - // (since the world clock stays at 0 before the race start), and - // therefore resumed if the game is resumed, which means it is - // played again. To avoid this, any sound starting at t=0 is set - // to have an end time of 0 - which means the track intro music is - // not resumed in this case. - m_end_time = t>0 ? t+m_sound_buffer->getDuration() : 0; - } - else - m_end_time = 1.0f; } // reallyPlayNow //----------------------------------------------------------------------------- @@ -410,6 +391,16 @@ void SFXOpenAL::reallySetPosition(const Vec3 &position) SFXManager::checkError("positioning"); } // reallySetPosition +//----------------------------------------------------------------------------- +/** Queues up a delete request for this object. This is necessary to avoid + * a crash if the sfx manager thread might be delayed and access this object + * after it was deleted. + */ +void SFXOpenAL::deleteSFX() +{ + SFXManager::get()->queue(SFXManager::SFX_DELETE, this); +} // deleteSFX + //----------------------------------------------------------------------------- void SFXOpenAL::onSoundEnabledBack() diff --git a/src/audio/sfx_openal.hpp b/src/audio/sfx_openal.hpp index 7ba7ca456..23321f3e9 100644 --- a/src/audio/sfx_openal.hpp +++ b/src/audio/sfx_openal.hpp @@ -72,15 +72,15 @@ private: /** If this sfx should also free the sound buffer. */ bool m_owns_buffer; - /** Time at which a sfx ends playing. Used to avoid frequently getting - * the openl status (which can slow down stk). */ - float m_end_time; + /** How long the sfx has been playing. */ + float m_play_time; public: SFXOpenAL(SFXBuffer* buffer, bool positional, float gain, bool owns_buffer = false); virtual ~SFXOpenAL(); + virtual void updatePlayingSFX(float dt); virtual bool init(); virtual void play(); virtual void reallyPlayNow();