Manually keep track of the duration each sfx has been played (instead
of relying on the world clock, which can run backwards, e.g. in FTL mode). Fixes #1624.
This commit is contained in:
parent
2f45266c6f
commit
19f9afb67f
@ -35,7 +35,7 @@ public:
|
|||||||
|
|
||||||
/** Late creation, if SFX was initially disabled */
|
/** Late creation, if SFX was initially disabled */
|
||||||
virtual bool init() { return true; }
|
virtual bool init() { return true; }
|
||||||
|
virtual void updatePlayingSFX(float dt) {}
|
||||||
virtual void setLoop(bool status) {}
|
virtual void setLoop(bool status) {}
|
||||||
virtual void reallySetLoop(bool status) {}
|
virtual void reallySetLoop(bool status) {}
|
||||||
virtual void setPosition(const Vec3 &p) {}
|
virtual void setPosition(const Vec3 &p) {}
|
||||||
|
@ -52,6 +52,7 @@ public:
|
|||||||
|
|
||||||
/** Late creation, if SFX was initially disabled */
|
/** Late creation, if SFX was initially disabled */
|
||||||
virtual bool init() = 0;
|
virtual bool init() = 0;
|
||||||
|
virtual void updatePlayingSFX(float dt) = 0;
|
||||||
virtual void setPosition(const Vec3 &p) = 0;
|
virtual void setPosition(const Vec3 &p) = 0;
|
||||||
virtual void reallySetPosition(const Vec3 &p) = 0;
|
virtual void reallySetPosition(const Vec3 &p) = 0;
|
||||||
virtual void setLoop(bool status) = 0;
|
virtual void setLoop(bool status) = 0;
|
||||||
|
@ -232,18 +232,6 @@ void SFXManager::queueCommand(SFXCommand *command)
|
|||||||
m_sfx_commands.unlock();
|
m_sfx_commands.unlock();
|
||||||
} // queueCommand
|
} // 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
|
/** Puts a NULL request into the queue, which will trigger the thread to
|
||||||
* exit.
|
* exit.
|
||||||
@ -309,8 +297,7 @@ void* SFXManager::mainLoop(void *obj)
|
|||||||
case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break;
|
case SFX_PAUSE_ALL: me->reallyPauseAllNow(); break;
|
||||||
case SFX_RESUME_ALL: me->reallyResumeAllNow(); break;
|
case SFX_RESUME_ALL: me->reallyResumeAllNow(); break;
|
||||||
case SFX_LISTENER: me->reallyPositionListenerNow(); break;
|
case SFX_LISTENER: me->reallyPositionListenerNow(); break;
|
||||||
case SFX_UPDATE_MUSIC: music_manager->update(
|
case SFX_UPDATE: me->reallyUpdateNow(current); break;
|
||||||
current->m_parameter.getX()); break;
|
|
||||||
default: assert("Not yet supported.");
|
default: assert("Not yet supported.");
|
||||||
}
|
}
|
||||||
delete current;
|
delete current;
|
||||||
@ -593,6 +580,38 @@ void SFXManager::deleteSFXMapping(const std::string &name)
|
|||||||
|
|
||||||
} // deleteSFXMapping
|
} // 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<SFXBase*>::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
|
/** 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
|
* all SFXs. This call deletes the object, and removes it from the list of
|
||||||
|
@ -74,7 +74,7 @@ public:
|
|||||||
SFX_VOLUME,
|
SFX_VOLUME,
|
||||||
SFX_LOOP,
|
SFX_LOOP,
|
||||||
SFX_LISTENER,
|
SFX_LISTENER,
|
||||||
SFX_UPDATE_MUSIC,
|
SFX_UPDATE,
|
||||||
SFX_EXIT,
|
SFX_EXIT,
|
||||||
}; // SFXCommands
|
}; // SFXCommands
|
||||||
|
|
||||||
@ -220,6 +220,7 @@ public:
|
|||||||
void resumeAll();
|
void resumeAll();
|
||||||
void reallyResumeAllNow();
|
void reallyResumeAllNow();
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
|
void reallyUpdateNow(SFXCommand *current);
|
||||||
bool soundExist(const std::string &name);
|
bool soundExist(const std::string &name);
|
||||||
void setMasterSFXVolume(float gain);
|
void setMasterSFXVolume(float gain);
|
||||||
float getMasterSFXVolume() const { return m_master_gain; }
|
float getMasterSFXVolume() const { return m_master_gain; }
|
||||||
|
@ -51,7 +51,7 @@ SFXOpenAL::SFXOpenAL(SFXBuffer* buffer, bool positional, float gain,
|
|||||||
m_gain = -1.0f;
|
m_gain = -1.0f;
|
||||||
m_master_gain = 1.0f;
|
m_master_gain = 1.0f;
|
||||||
m_owns_buffer = owns_buffer;
|
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
|
// Don't initialise anything else if the sfx manager was not correctly
|
||||||
// initialised. First of all the initialisation will not work, and it
|
// initialised. First of all the initialisation will not work, and it
|
||||||
@ -123,19 +123,24 @@ bool SFXOpenAL::init()
|
|||||||
return true;
|
return true;
|
||||||
} // init
|
} // 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. */
|
/** Returns the status of this sfx. */
|
||||||
SFXBase::SFXStatus SFXOpenAL::getStatus()
|
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;
|
return m_status;
|
||||||
} // getStatus;
|
} // getStatus;
|
||||||
|
|
||||||
@ -295,24 +300,17 @@ void SFXOpenAL::reallyResumeNow()
|
|||||||
}
|
}
|
||||||
} // 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
|
/** This actually queues up the sfx in the sfx manager. It will be started
|
||||||
* from a separate thread later (in this frame).
|
* from a separate thread later (in this frame).
|
||||||
*/
|
*/
|
||||||
void SFXOpenAL::play()
|
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,
|
// 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)
|
// 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
|
// - which can happen if the sfx thread had no time to actually start
|
||||||
// it yet.
|
// it yet.
|
||||||
@ -337,23 +335,6 @@ void SFXOpenAL::reallyPlayNow()
|
|||||||
|
|
||||||
alSourcePlay(m_sound_source);
|
alSourcePlay(m_sound_source);
|
||||||
SFXManager::checkError("playing");
|
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
|
} // reallyPlayNow
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -410,6 +391,16 @@ void SFXOpenAL::reallySetPosition(const Vec3 &position)
|
|||||||
SFXManager::checkError("positioning");
|
SFXManager::checkError("positioning");
|
||||||
} // reallySetPosition
|
} // 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()
|
void SFXOpenAL::onSoundEnabledBack()
|
||||||
|
@ -72,15 +72,15 @@ private:
|
|||||||
/** If this sfx should also free the sound buffer. */
|
/** If this sfx should also free the sound buffer. */
|
||||||
bool m_owns_buffer;
|
bool m_owns_buffer;
|
||||||
|
|
||||||
/** Time at which a sfx ends playing. Used to avoid frequently getting
|
/** How long the sfx has been playing. */
|
||||||
* the openl status (which can slow down stk). */
|
float m_play_time;
|
||||||
float m_end_time;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SFXOpenAL(SFXBuffer* buffer, bool positional, float gain,
|
SFXOpenAL(SFXBuffer* buffer, bool positional, float gain,
|
||||||
bool owns_buffer = false);
|
bool owns_buffer = false);
|
||||||
virtual ~SFXOpenAL();
|
virtual ~SFXOpenAL();
|
||||||
|
|
||||||
|
virtual void updatePlayingSFX(float dt);
|
||||||
virtual bool init();
|
virtual bool init();
|
||||||
virtual void play();
|
virtual void play();
|
||||||
virtual void reallyPlayNow();
|
virtual void reallyPlayNow();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user