From 216575a7328808bc5661633953a377798880b5a1 Mon Sep 17 00:00:00 2001 From: hiker Date: Sat, 11 Oct 2014 11:55:02 +1100 Subject: [PATCH 1/5] Started to let all sfx related command be executed from the sfx manager to avoid race condition and crashes. --- src/audio/sfx_manager.cpp | 54 ++++++++++++++++++++++++--------------- src/audio/sfx_manager.hpp | 33 ++++++++++++++++++++++-- src/audio/sfx_openal.cpp | 2 +- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index 1bfd2c54e..7ebc2c061 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -106,9 +106,9 @@ SFXManager::SFXManager() if (!sfxAllowed()) return; setMasterSFXVolume( UserConfigParams::m_sfx_volume ); - m_sfx_to_play.lock(); - m_sfx_to_play.getData().clear(); - m_sfx_to_play.unlock(); + m_sfx_commands.lock(); + m_sfx_commands.getData().clear(); + m_sfx_commands.unlock(); } // SoundManager @@ -163,15 +163,17 @@ SFXManager::~SFXManager() * separate thread. * \param sfx The sound effect to be started. */ -void SFXManager::queue(SFXBase *sfx) +void SFXManager::queue(SFXCommands command, SFXBase *sfx) { // Don't add sfx that are either not working correctly (e.g. because sfx // are disabled); if(sfx && sfx->getStatus()==SFX_UNKNOWN ) return; - m_sfx_to_play.lock(); - m_sfx_to_play.getData().push_back(sfx); - m_sfx_to_play.unlock(); + SFXCommand *sfx_command = new SFXCommand(command, sfx); + + m_sfx_commands.lock(); + m_sfx_commands.getData().push_back(sfx_command); + m_sfx_commands.unlock(); // Wake up the sfx thread pthread_cond_signal(&m_cond_request); @@ -183,7 +185,7 @@ void SFXManager::queue(SFXBase *sfx) */ void SFXManager::stopThread() { - queue(NULL); + queue(SFX_EXIT, NULL); } // stopThread //---------------------------------------------------------------------------- @@ -198,35 +200,47 @@ void* SFXManager::mainLoop(void *obj) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - me->m_sfx_to_play.lock(); + me->m_sfx_commands.lock(); // Wait till we have an empty sfx in the queue - while (me->m_sfx_to_play.getData().empty() || - me->m_sfx_to_play.getData().front()!=NULL ) + while (me->m_sfx_commands.getData().empty() || + me->m_sfx_commands.getData().front()->m_command!=SFX_EXIT) { - bool empty = me->m_sfx_to_play.getData().empty(); + bool empty = me->m_sfx_commands.getData().empty(); // Wait in cond_wait for a request to arrive. The 'while' is necessary // since "spurious wakeups from the pthread_cond_wait ... may occur" // (pthread_cond_wait man page)! while (empty) { - pthread_cond_wait(&me->m_cond_request, me->m_sfx_to_play.getMutex()); - empty = me->m_sfx_to_play.getData().empty(); + pthread_cond_wait(&me->m_cond_request, me->m_sfx_commands.getMutex()); + empty = me->m_sfx_commands.getData().empty(); } - SFXBase *current = me->m_sfx_to_play.getData().front(); - me->m_sfx_to_play.getData().erase(me->m_sfx_to_play.getData().begin()); + SFXCommand *current = me->m_sfx_commands.getData().front(); + me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin()); - if (!current) // empty sfx indicates to abort the sfx manager + if (current->m_command == SFX_EXIT) break; - me->m_sfx_to_play.unlock(); - current->reallyPlayNow(); - me->m_sfx_to_play.lock(); + me->m_sfx_commands.unlock(); + switch(current->m_command) + { + case SFX_PLAY: current->m_sfx->reallyPlayNow(); break; + default: assert("Not yet supported."); + } + delete current; + current = NULL; + me->m_sfx_commands.lock(); } // while + // Clean up memory to avoid leak detection + while(!me->m_sfx_commands.getData().empty()) + { + delete me->m_sfx_commands.getData().front(); + me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin()); + } return NULL; } // mainLoop diff --git a/src/audio/sfx_manager.hpp b/src/audio/sfx_manager.hpp index 4af8f6e22..90e0ce323 100644 --- a/src/audio/sfx_manager.hpp +++ b/src/audio/sfx_manager.hpp @@ -19,6 +19,7 @@ #ifndef HEADER_SFX_MANAGER_HPP #define HEADER_SFX_MANAGER_HPP +#include "utils/leak_check.hpp" #include "utils/no_copy.hpp" #include "utils/synchronised.hpp" #include "utils/vec3.hpp" @@ -57,6 +58,18 @@ private: public: + /** The various commands to be executed by the sfx manager thread + * for each sfx. */ + enum SFXCommands + { + SFX_PLAY = 1, + SFX_STOP = 2, + SFX_PAUSE = 3, + SFX_RESUME = 4, + SFX_DELETE = 5, + SFX_EXIT = 6, + }; // SFXCommands + /** * Entries for custom SFX sounds. These are unique for each kart. * eg. kart->playCustomSFX(SFX_MANAGER::CUSTOM_HORN) @@ -85,6 +98,22 @@ public: private: + /** Data structure for the queue, which stores a sfx and the command to + * execute for it. */ + class SFXCommand : public NoCopy + { + private: + LEAK_CHECK() + public: + SFXBase *m_sfx; + SFXCommands m_command; + SFXCommand(SFXCommands command, SFXBase *base) + { + m_command = command; + m_sfx = base; + } + }; // SFXCommand + /** Listener position */ Vec3 m_position; @@ -96,7 +125,7 @@ private: std::vector m_all_sfx; /** The list of sound effects to be played in the next update. */ - Synchronised< std::vector > m_sfx_to_play; + Synchronised< std::vector > m_sfx_commands; /** To play non-positional sounds without having to create a new object for each */ std::map m_quick_sounds; @@ -124,7 +153,7 @@ private: public: static void create(); static void destroy(); - void queue(SFXBase *sfx); + void queue(SFXCommands command, SFXBase *sfx); // ------------------------------------------------------------------------ /** Static function to get the singleton sfx manager. */ static SFXManager *get() diff --git a/src/audio/sfx_openal.cpp b/src/audio/sfx_openal.cpp index bb220d7c5..029f1d9f1 100644 --- a/src/audio/sfx_openal.cpp +++ b/src/audio/sfx_openal.cpp @@ -234,7 +234,7 @@ void SFXOpenAL::play() // but for STK this is correct since we don't want to start the same // sfx twice. m_is_playing = true; - SFXManager::get()->queue(this); + SFXManager::get()->queue(SFXManager::SFX_PLAY, this); } // play //----------------------------------------------------------------------------- From bfe84612fa408b070801ba3cd23054592307ec68 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 13 Oct 2014 08:26:45 +1100 Subject: [PATCH 2/5] Let all SFX commands be handled by the sfx manager thread (otherwise events could be handled in the wrong order, e.g. a delete from the main thread before the play in the manager thread, resulting in a crash). Should fix #1511 and #1604. --- src/audio/dummy_sfx.hpp | 5 ++ src/audio/sfx_base.hpp | 4 ++ src/audio/sfx_manager.cpp | 71 +++++++++++++++------- src/audio/sfx_manager.hpp | 4 +- src/audio/sfx_openal.cpp | 45 ++++++++++++-- src/audio/sfx_openal.hpp | 4 ++ src/graphics/hit_sfx.cpp | 5 +- src/graphics/weather.cpp | 6 +- src/items/attachment.cpp | 14 ++--- src/items/bowling.cpp | 6 +- src/items/powerup.cpp | 4 +- src/items/rubber_ball.cpp | 2 +- src/items/swatter.cpp | 2 +- src/karts/controller/player_controller.cpp | 10 +-- src/karts/kart.cpp | 31 +++++----- src/modes/linear_world.cpp | 2 +- src/modes/soccer_world.cpp | 2 +- src/modes/world_status.cpp | 6 +- src/tracks/track_object_presentation.cpp | 44 +++++++++----- 19 files changed, 175 insertions(+), 92 deletions(-) diff --git a/src/audio/dummy_sfx.hpp b/src/audio/dummy_sfx.hpp index 012a75d00..adf73d184 100644 --- a/src/audio/dummy_sfx.hpp +++ b/src/audio/dummy_sfx.hpp @@ -40,9 +40,14 @@ public: virtual void position(const Vec3 &position) {} virtual void setLoop(bool status) {} virtual void play() {} + virtual void reallyPlayNow() {} virtual void stop() {} + virtual void reallyStopNow() {} virtual void pause() {} + virtual void reallyPauseNow() {} virtual void resume() {} + virtual void reallyResumeNow() {} + virtual void deleteSFX() { delete this; } virtual void speed(float factor) {} virtual void volume(float gain) {} virtual SFXManager::SFXStatus getStatus() { return SFXManager::SFX_STOPPED; } diff --git a/src/audio/sfx_base.hpp b/src/audio/sfx_base.hpp index 65809307b..3ade04eb8 100644 --- a/src/audio/sfx_base.hpp +++ b/src/audio/sfx_base.hpp @@ -52,8 +52,12 @@ public: virtual void play() = 0; virtual void reallyPlayNow() = 0; virtual void stop() = 0; + virtual void reallyStopNow() = 0; virtual void pause() = 0; + virtual void reallyPauseNow() = 0; virtual void resume() = 0; + virtual void reallyResumeNow() = 0; + virtual void deleteSFX() = 0; virtual void speed(float factor) = 0; virtual void volume(float gain) = 0; virtual void setMasterVolume(float gain) = 0; diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index 7ebc2c061..968adc5d9 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -124,13 +124,15 @@ SFXManager::~SFXManager() pthread_cond_destroy(&m_cond_request); // ---- clear m_all_sfx - const int sfx_amount = (int) m_all_sfx.size(); + // not strictly necessary, but might avoid copy&paste problems + m_all_sfx.lock(); + const int sfx_amount = (int) m_all_sfx.getData().size(); for (int n=0; n::iterator i = m_quick_sounds.begin(); @@ -226,7 +228,15 @@ void* SFXManager::mainLoop(void *obj) me->m_sfx_commands.unlock(); switch(current->m_command) { - case SFX_PLAY: current->m_sfx->reallyPlayNow(); 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_DELETE: { + current->m_sfx->reallyStopNow(); + me->deleteSFX(current->m_sfx); + break; + } default: assert("Not yet supported."); } delete current; @@ -262,12 +272,13 @@ void SFXManager::soundToggled(const bool on) } resumeAll(); - - const int sfx_amount = (int)m_all_sfx.size(); + m_all_sfx.lock(); + const int sfx_amount = (int)m_all_sfx.getData().size(); for (int n=0; nonSoundEnabledBack(); + m_all_sfx.getData()[n]->onSoundEnabledBack(); } + m_all_sfx.unlock(); } else { @@ -451,7 +462,14 @@ SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer, sfx->setMasterVolume(m_master_gain); - if (add_to_SFX_list) m_all_sfx.push_back(sfx); + if (add_to_SFX_list) + { + m_all_sfx.lock(); + m_all_sfx.getData().push_back(sfx); + m_all_sfx.unlock(); + } + else + printf(""); return sfx; } // createSoundSource @@ -511,21 +529,26 @@ void SFXManager::deleteSFXMapping(const std::string &name) */ void SFXManager::deleteSFX(SFXBase *sfx) { - if(sfx) sfx->stop(); + if(sfx) sfx->reallyStopNow(); std::vector::iterator i; - i=std::find(m_all_sfx.begin(), m_all_sfx.end(), sfx); + + // The whole block needs to be locked, otherwise the iterator + // could become invalid. + m_all_sfx.lock(); + i=std::find(m_all_sfx.getData().begin(), m_all_sfx.getData().end(), sfx); - if(i==m_all_sfx.end()) + if(i==m_all_sfx.getData().end()) { Log::warn("SFXManager", - "SFXManager::deleteSFX : Warning: sfx not found in list."); + "SFXManager::deleteSFX : Warning: sfx '%s' %lx not found in list.", + sfx->getBuffer()->getFileName().c_str(), sfx); return; } + m_all_sfx.getData().erase(i); delete sfx; - m_all_sfx.erase(i); - + m_all_sfx.unlock(); } // deleteSFX //---------------------------------------------------------------------------- @@ -535,11 +558,13 @@ void SFXManager::deleteSFX(SFXBase *sfx) */ void SFXManager::pauseAll() { - for (std::vector::iterator i=m_all_sfx.begin(); - i!=m_all_sfx.end(); i++) + m_all_sfx.lock(); + for (std::vector::iterator i= m_all_sfx.getData().begin(); + i!=m_all_sfx.getData().end(); i++) { (*i)->pause(); } // for i in m_all_sfx + m_all_sfx.unlock(); } // pauseAll //---------------------------------------------------------------------------- @@ -551,13 +576,15 @@ void SFXManager::resumeAll() // ignore unpausing if sound is disabled if (!sfxAllowed()) return; - for (std::vector::iterator i=m_all_sfx.begin(); - i!=m_all_sfx.end(); i++) + m_all_sfx.lock(); + for (std::vector::iterator i =m_all_sfx.getData().begin(); + i!=m_all_sfx.getData().end(); i++) { SFXStatus status = (*i)->getStatus(); // Initial happens when if (status==SFX_PAUSED) (*i)->resume(); } // for i in m_all_sfx + m_all_sfx.unlock(); } // resumeAll //----------------------------------------------------------------------------- @@ -594,11 +621,13 @@ void SFXManager::setMasterSFXVolume(float gain) // regular SFX { - for (std::vector::iterator i=m_all_sfx.begin(); - i!=m_all_sfx.end(); i++) + m_all_sfx.lock(); + for (std::vector::iterator i =m_all_sfx.getData().begin(); + i!=m_all_sfx.getData().end(); i++) { (*i)->setMasterVolume(m_master_gain); } // for i in m_all_sfx + m_all_sfx.unlock(); } // quick SFX diff --git a/src/audio/sfx_manager.hpp b/src/audio/sfx_manager.hpp index 90e0ce323..00ca9375e 100644 --- a/src/audio/sfx_manager.hpp +++ b/src/audio/sfx_manager.hpp @@ -122,7 +122,7 @@ private: std::map m_all_sfx_types; /** The actual instances (sound sources) */ - std::vector m_all_sfx; + Synchronised > m_all_sfx; /** The list of sound effects to be played in the next update. */ Synchronised< std::vector > m_sfx_commands; @@ -150,6 +150,7 @@ private: virtual ~SFXManager(); static void* mainLoop(void *obj); + void deleteSFX(SFXBase *sfx); public: static void create(); static void destroy(); @@ -182,7 +183,6 @@ public: SFXBase* createSoundSource(const std::string &name, const bool addToSFXList=true); - void deleteSFX(SFXBase *sfx); void deleteSFXMapping(const std::string &name); void pauseAll(); void resumeAll(); diff --git a/src/audio/sfx_openal.cpp b/src/audio/sfx_openal.cpp index 029f1d9f1..c596ac55b 100644 --- a/src/audio/sfx_openal.cpp +++ b/src/audio/sfx_openal.cpp @@ -182,9 +182,16 @@ void SFXOpenAL::setLoop(bool status) } // loop //----------------------------------------------------------------------------- -/** Stops playing this sound effect. +/** Queues a stop for this effect to the sound manager. */ void SFXOpenAL::stop() +{ + SFXManager::get()->queue(SFXManager::SFX_STOP, this); +} // stop +//----------------------------------------------------------------------------- +/** The sfx manager thread executes a stop for this sfx. + */ +void SFXOpenAL::reallyStopNow() { if(!m_ok) return; @@ -193,23 +200,39 @@ void SFXOpenAL::stop() alSourcei(m_soundSource, AL_LOOPING, AL_FALSE); alSourceStop(m_soundSource); SFXManager::checkError("stoping"); -} // stop +} // reallyStopNow + +//----------------------------------------------------------------------------- +/** Queues up a pause command for this sfx. + */ +void SFXOpenAL::pause() +{ + SFXManager::get()->queue(SFXManager::SFX_PAUSE, this); +} // pause //----------------------------------------------------------------------------- /** Pauses a SFX that's currently played. Nothing happens it the effect is * currently not being played. */ -void SFXOpenAL::pause() +void SFXOpenAL::reallyPauseNow() { if(!m_ok) return; alSourcePause(m_soundSource); SFXManager::checkError("pausing"); -} // pause +} // reallyPauseNow + +//----------------------------------------------------------------------------- +/** Queues up a resume command for this sound effect. + */ +void SFXOpenAL::resume() +{ + SFXManager::get()->queue(SFXManager::SFX_RESUME, this); +} // resume //----------------------------------------------------------------------------- /** Resumes a sound effect. */ -void SFXOpenAL::resume() +void SFXOpenAL::reallyResumeNow() { if (!m_ok) { @@ -222,7 +245,17 @@ void SFXOpenAL::resume() alSourcePlay(m_soundSource); SFXManager::checkError("resuming"); -} // resume +} // 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 diff --git a/src/audio/sfx_openal.hpp b/src/audio/sfx_openal.hpp index 807111a33..0de11c78a 100644 --- a/src/audio/sfx_openal.hpp +++ b/src/audio/sfx_openal.hpp @@ -77,8 +77,12 @@ public: virtual void setLoop(bool status); virtual bool isPlaying(); virtual void stop(); + virtual void reallyStopNow(); virtual void pause(); + virtual void reallyPauseNow(); virtual void resume(); + virtual void reallyResumeNow(); + virtual void deleteSFX(); virtual void speed(float factor); virtual void position(const Vec3 &position); virtual void volume(float gain); diff --git a/src/graphics/hit_sfx.cpp b/src/graphics/hit_sfx.cpp index 53800b28c..507ce3cee 100644 --- a/src/graphics/hit_sfx.cpp +++ b/src/graphics/hit_sfx.cpp @@ -42,10 +42,7 @@ HitSFX::HitSFX(const Vec3& coord, const char* explosion_sound) */ HitSFX::~HitSFX() { - if (m_sfx->getStatus() == SFXManager::SFX_PLAYING) - m_sfx->stop(); - - SFXManager::get()->deleteSFX(m_sfx); + m_sfx->deleteSFX(); } // ~HitEffect //----------------------------------------------------------------------------- diff --git a/src/graphics/weather.cpp b/src/graphics/weather.cpp index 79f51b983..8162f8f11 100644 --- a/src/graphics/weather.cpp +++ b/src/graphics/weather.cpp @@ -51,11 +51,11 @@ Weather::Weather(bool lightning, std::string sound) Weather::~Weather() { if (m_thunder_sound != NULL) - SFXManager::get()->deleteSFX(m_thunder_sound); + m_thunder_sound->deleteSFX(); if (m_weather_sound != NULL) - SFXManager::get()->deleteSFX(m_weather_sound); -} + m_weather_sound->deleteSFX(); +} // ~Weather // ---------------------------------------------------------------------------- diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index ec6816354..02513b4a4 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -80,13 +80,13 @@ Attachment::~Attachment() if (m_bomb_sound) { - SFXManager::get()->deleteSFX(m_bomb_sound); + m_bomb_sound->deleteSFX(); m_bomb_sound = NULL; } if (m_bubble_explode_sound) { - SFXManager::get()->deleteSFX(m_bubble_explode_sound); + m_bubble_explode_sound->deleteSFX(); m_bubble_explode_sound = NULL; } } // ~Attachment @@ -139,7 +139,7 @@ void Attachment::set(AttachmentType type, float time, break; case ATTACH_BOMB: m_node->setMesh(attachment_manager->getMesh(type)); - if (m_bomb_sound) SFXManager::get()->deleteSFX(m_bomb_sound); + if (m_bomb_sound) m_bomb_sound->deleteSFX(); m_bomb_sound = SFXManager::get()->createSoundSource("clock"); m_bomb_sound->setLoop(true); m_bomb_sound->position(m_kart->getXYZ()); @@ -198,8 +198,7 @@ void Attachment::clear() if (m_bomb_sound) { - m_bomb_sound->stop(); - SFXManager::get()->deleteSFX(m_bomb_sound); + m_bomb_sound->deleteSFX(); m_bomb_sound = NULL; } @@ -460,8 +459,7 @@ void Attachment::update(float dt) if (m_bomb_sound) { - m_bomb_sound->stop(); - SFXManager::get()->deleteSFX(m_bomb_sound); + m_bomb_sound->deleteSFX(); m_bomb_sound = NULL; } } @@ -474,7 +472,7 @@ void Attachment::update(float dt) if (m_time_left < 0) { m_time_left = 0.0f; - if (m_bubble_explode_sound) SFXManager::get()->deleteSFX(m_bubble_explode_sound); + if (m_bubble_explode_sound) m_bubble_explode_sound->deleteSFX(); m_bubble_explode_sound = SFXManager::get()->createSoundSource("bubblegum_explode"); m_bubble_explode_sound->position(m_kart->getXYZ()); m_bubble_explode_sound->play(); diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index ae0d821d7..28b239e47 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -87,9 +87,9 @@ Bowling::Bowling(AbstractKart *kart) */ Bowling::~Bowling() { - if(m_roll_sfx->getStatus()==SFXManager::SFX_PLAYING) - m_roll_sfx->stop(); - SFXManager::get()->deleteSFX(m_roll_sfx); + // This will stop the sfx and delete the object. + m_roll_sfx->deleteSFX(); + } // ~RubberBall // ----------------------------------------------------------------------------- diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 6752edc56..9cdbcd8b0 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -53,7 +53,7 @@ Powerup::Powerup(AbstractKart* kart) */ Powerup::~Powerup() { - if(m_sound_use) SFXManager::get()->deleteSFX(m_sound_use); + if(m_sound_use) m_sound_use->deleteSFX(); } // ~Powerup //----------------------------------------------------------------------------- @@ -88,7 +88,7 @@ void Powerup::set(PowerupManager::PowerupType type, int n) if(m_sound_use != NULL) { - SFXManager::get()->deleteSFX(m_sound_use); + m_sound_use->deleteSFX(); m_sound_use = NULL; } diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index 566e69e53..8f9309517 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -109,7 +109,7 @@ RubberBall::~RubberBall() { if(m_ping_sfx->getStatus()==SFXManager::SFX_PLAYING) m_ping_sfx->stop(); - SFXManager::get()->deleteSFX(m_ping_sfx); + m_ping_sfx->deleteSFX(); } // ~RubberBall // ---------------------------------------------------------------------------- diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index 78a44cc7a..60513aba3 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -100,7 +100,7 @@ Swatter::~Swatter() } if (m_swat_sound) { - SFXManager::get()->deleteSFX(m_swat_sound); + m_swat_sound->deleteSFX(); } } // ~Swatter diff --git a/src/karts/controller/player_controller.cpp b/src/karts/controller/player_controller.cpp index 61298f308..a7a1a3403 100644 --- a/src/karts/controller/player_controller.cpp +++ b/src/karts/controller/player_controller.cpp @@ -74,11 +74,11 @@ PlayerController::PlayerController(AbstractKart *kart, */ PlayerController::~PlayerController() { - SFXManager::get()->deleteSFX(m_bzzt_sound); - SFXManager::get()->deleteSFX(m_wee_sound ); - SFXManager::get()->deleteSFX(m_ugh_sound ); - SFXManager::get()->deleteSFX(m_grab_sound); - SFXManager::get()->deleteSFX(m_full_sound); + m_bzzt_sound->deleteSFX(); + m_wee_sound ->deleteSFX(); + m_ugh_sound ->deleteSFX(); + m_grab_sound->deleteSFX(); + m_full_sound->deleteSFX(); } // ~PlayerController //----------------------------------------------------------------------------- diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 3e8112ced..4c0430c74 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -246,15 +246,15 @@ Kart::~Kart() SFXManager::get()->deleteSFX(m_custom_sounds[n]); }*/ - SFXManager::get()->deleteSFX(m_engine_sound ); - SFXManager::get()->deleteSFX(m_crash_sound ); - SFXManager::get()->deleteSFX(m_skid_sound ); - SFXManager::get()->deleteSFX(m_goo_sound ); - SFXManager::get()->deleteSFX(m_beep_sound ); - SFXManager::get()->deleteSFX(m_boing_sound ); + m_engine_sound->deleteSFX(); + m_crash_sound ->deleteSFX(); + m_skid_sound ->deleteSFX(); + m_goo_sound ->deleteSFX(); + m_beep_sound ->deleteSFX(); + m_boing_sound ->deleteSFX(); delete m_kart_gfx; - if(m_terrain_sound) SFXManager::get()->deleteSFX(m_terrain_sound); - if(m_previous_terrain_sound) SFXManager::get()->deleteSFX(m_previous_terrain_sound); + if(m_terrain_sound) m_terrain_sound->deleteSFX(); + if(m_previous_terrain_sound) m_previous_terrain_sound->deleteSFX(); if(m_collision_particles) delete m_collision_particles; if(m_slipstream) delete m_slipstream; if(m_sky_particles_emitter) delete m_sky_particles_emitter; @@ -363,16 +363,15 @@ void Kart::reset() if(m_terrain_sound) { - SFXManager::get()->deleteSFX(m_terrain_sound); + m_terrain_sound->deleteSFX(); + m_terrain_sound = NULL; } if(m_previous_terrain_sound) { - SFXManager::get()->deleteSFX(m_previous_terrain_sound); + m_previous_terrain_sound->deleteSFX(); + m_previous_terrain_sound = NULL; } - m_terrain_sound = NULL; - m_previous_terrain_sound = NULL; - if(m_engine_sound) m_engine_sound->stop(); @@ -1430,7 +1429,7 @@ void Kart::handleMaterialSFX(const Material *material) // can be used again. if(m_previous_terrain_sound) { - SFXManager::get()->deleteSFX(m_previous_terrain_sound); + m_previous_terrain_sound->deleteSFX(); } m_previous_terrain_sound = m_terrain_sound; if(m_previous_terrain_sound) @@ -1467,7 +1466,7 @@ void Kart::handleMaterialSFX(const Material *material) // We don't modify the position of m_previous_terrain_sound // anymore, so that it keeps on playing at the place where the // kart left the material. - SFXManager::get()->deleteSFX(m_previous_terrain_sound); + m_previous_terrain_sound->deleteSFX(); m_previous_terrain_sound = NULL; } @@ -1592,7 +1591,7 @@ void Kart::handleMaterialGFX() (m_terrain_sound == NULL || m_terrain_sound->getStatus() == SFXManager::SFX_STOPPED)) { - if (m_previous_terrain_sound) SFXManager::get()->deleteSFX(m_previous_terrain_sound); + if (m_previous_terrain_sound) m_previous_terrain_sound->deleteSFX(); m_previous_terrain_sound = m_terrain_sound; if(m_previous_terrain_sound) m_previous_terrain_sound->setLoop(false); diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 9cbd969d2..8883d0aec 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -73,7 +73,7 @@ void LinearWorld::init() */ LinearWorld::~LinearWorld() { - SFXManager::get()->deleteSFX(m_last_lap_sfx); + m_last_lap_sfx->deleteSFX(); } // ~LinearWorld //----------------------------------------------------------------------------- diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index c853570fe..672411ac3 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -60,7 +60,7 @@ SoccerWorld::SoccerWorld() : WorldWithRank() */ SoccerWorld::~SoccerWorld() { - SFXManager::get()->deleteSFX(m_goal_sound); + m_goal_sound->deleteSFX(); } // ~SoccerWorld //----------------------------------------------------------------------------- diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 1deeb3903..62419091e 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -74,9 +74,9 @@ void WorldStatus::reset() */ WorldStatus::~WorldStatus() { - SFXManager::get()->deleteSFX(m_prestart_sound); - SFXManager::get()->deleteSFX(m_start_sound); - SFXManager::get()->deleteSFX(m_track_intro_sound); + m_prestart_sound->deleteSFX(); + m_start_sound->deleteSFX(); + m_track_intro_sound->deleteSFX(); IrrlichtDevice *device = irr_driver->getDevice(); if (device->getTimer()->isStopped()) diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index c6ba494f2..7b7f7af29 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -382,8 +382,9 @@ void TrackObjectPresentationMesh::reset() // ---------------------------------------------------------------------------- -TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_node, scene::ISceneNode* parent) : - TrackObjectPresentation(xml_node) +TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_node, + scene::ISceneNode* parent) + : TrackObjectPresentation(xml_node) { // TODO: respect 'parent' if any @@ -440,8 +441,9 @@ TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_no { ItemManager::get()->newItem(m_init_xyz, trigger_distance, this); } -} +} // TrackObjectPresentationSound +// ---------------------------------------------------------------------------- void TrackObjectPresentationSound::update(float dt) { if (m_sound != NULL) @@ -451,16 +453,18 @@ void TrackObjectPresentationSound::update(float dt) // moved m_sound->position(m_xyz); } -} +} // update +// ---------------------------------------------------------------------------- void TrackObjectPresentationSound::onTriggerItemApproached(Item* who) { if (m_sound != NULL && m_sound->getStatus() != SFXManager::SFX_PLAYING) { m_sound->play(); } -} +} // onTriggerItemApproached +// ---------------------------------------------------------------------------- void TrackObjectPresentationSound::triggerSound(bool loop) { if (m_sound != NULL) @@ -468,34 +472,37 @@ void TrackObjectPresentationSound::triggerSound(bool loop) m_sound->setLoop(loop); m_sound->play(); } -} +} // triggerSound +// ---------------------------------------------------------------------------- void TrackObjectPresentationSound::stopSound() { if (m_sound != NULL) m_sound->stop(); -} +} // stopSound +// ---------------------------------------------------------------------------- TrackObjectPresentationSound::~TrackObjectPresentationSound() { if (m_sound) { - //delete m_sound->getBuffer(); - SFXManager::get()->deleteSFX(m_sound); + m_sound->deleteSFX(); } -} +} // ~TrackObjectPresentationSound -void TrackObjectPresentationSound::move(const core::vector3df& xyz, const core::vector3df& hpr, +// ---------------------------------------------------------------------------- +void TrackObjectPresentationSound::move(const core::vector3df& xyz, + const core::vector3df& hpr, const core::vector3df& scale) { m_xyz = xyz; if (m_sound != NULL) m_sound->position(xyz); -} +} // move // ---------------------------------------------------------------------------- - -TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(const XMLNode& xml_node, scene::ISceneNode* parent) : - TrackObjectPresentationSceneNode(xml_node) +TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(const XMLNode& xml_node, + scene::ISceneNode* parent) + : TrackObjectPresentationSceneNode(xml_node) { std::string texture_name; float width, height; @@ -529,6 +536,7 @@ TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(const XMLNode m_node->setPosition(m_init_xyz); } +// ---------------------------------------------------------------------------- void TrackObjectPresentationBillboard::update(float dt) { if (m_fade_out_when_close) @@ -554,6 +562,7 @@ void TrackObjectPresentationBillboard::update(float dt) } } +// ---------------------------------------------------------------------------- TrackObjectPresentationBillboard::~TrackObjectPresentationBillboard() { if (m_node) @@ -613,6 +622,7 @@ TrackObjectPresentationParticles::TrackObjectPresentationParticles(const XMLNode } } +// ---------------------------------------------------------------------------- TrackObjectPresentationParticles::~TrackObjectPresentationParticles() { if (m_emitter) @@ -626,6 +636,7 @@ TrackObjectPresentationParticles::~TrackObjectPresentationParticles() } } +// ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::update(float dt) { if (m_emitter != NULL) @@ -634,6 +645,7 @@ void TrackObjectPresentationParticles::update(float dt) } } +// ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::triggerParticles() { if (m_emitter != NULL) @@ -671,6 +683,7 @@ TrackObjectPresentationLight::TrackObjectPresentationLight(const XMLNode& xml_no } } +// ---------------------------------------------------------------------------- TrackObjectPresentationLight::~TrackObjectPresentationLight() { } @@ -693,6 +706,7 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(const ItemManager::get()->newItem(m_init_xyz, trigger_distance, this); } +// ---------------------------------------------------------------------------- void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who) { if (!m_action_active) return; From 2b90cb2a69d5bc4464c46b4a1347583b606f73d0 Mon Sep 17 00:00:00 2001 From: Marianne Gagnon Date: Sun, 12 Oct 2014 20:12:40 -0400 Subject: [PATCH 3/5] Use case-insensitive comparison for animated textures, for some reason --- src/tracks/track.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 076458a5b..1319d4084 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -1419,6 +1419,9 @@ void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml) continue; } + // to lower case, for case-insensitive comparison + name = StringUtils::toLowerCase(name); + for(unsigned int i=0; igetMaterialCount(); i++) { video::SMaterial &irrMaterial=node->getMaterial(i); @@ -1426,9 +1429,13 @@ void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml) { video::ITexture* t=irrMaterial.getTexture(j); if(!t) continue; - const std::string texture_name = + std::string texture_name = StringUtils::getBasename(core::stringc(t->getName()).c_str()); - if(texture_name!=name) continue; + + // to lower case, for case-insensitive comparison + texture_name = StringUtils::toLowerCase(texture_name); + + if (texture_name != name) continue; core::matrix4 *m = &irrMaterial.getTextureMatrix(j); m_animated_textures.push_back(new MovingTexture(m, *texture_node)); } // for j Date: Mon, 13 Oct 2014 22:04:46 +1100 Subject: [PATCH 4/5] Removed status check when queueing sfx, to get more consistent runtime behaviour. --- src/audio/sfx_manager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index 968adc5d9..9842e687f 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -167,10 +167,6 @@ SFXManager::~SFXManager() */ void SFXManager::queue(SFXCommands command, SFXBase *sfx) { - // Don't add sfx that are either not working correctly (e.g. because sfx - // are disabled); - if(sfx && sfx->getStatus()==SFX_UNKNOWN ) return; - SFXCommand *sfx_command = new SFXCommand(command, sfx); m_sfx_commands.lock(); @@ -255,7 +251,7 @@ void* SFXManager::mainLoop(void *obj) } // mainLoop //---------------------------------------------------------------------------- -/** Called then sound is globally switched on or off. It either pauses or +/** Called when sound is globally switched on or off. It either pauses or * resumes all sound effects. * \param on If sound is switched on or off. */ From 5cf7b0dca9575f0247efb7ac6ce07b85e05820cd Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 13 Oct 2014 22:06:05 +1100 Subject: [PATCH 5/5] Added computation of the duration of a sound buffer (unused atm). --- src/audio/sfx_buffer.cpp | 54 ++++++++++++++++++++++++------- src/audio/sfx_buffer.hpp | 70 ++++++++++++++++++++++++---------------- 2 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/audio/sfx_buffer.cpp b/src/audio/sfx_buffer.cpp index 910b29f88..0ac37f2d2 100644 --- a/src/audio/sfx_buffer.cpp +++ b/src/audio/sfx_buffer.cpp @@ -36,27 +36,37 @@ #endif //---------------------------------------------------------------------------- - +/** Creates a sfx. The parameter are taken from the parameters: + * \param file File name of the buffer. + * \param positional If the sfx is positional. + * \param rolloff Rolloff value of this sfx. + * \param max_dist Maximum distance the sfx can be heard. + * \param gain Gain value of this sfx. + */ SFXBuffer::SFXBuffer(const std::string& file, bool positional, float rolloff, - float max_width, + float max_dist, float gain) { m_buffer = 0; m_gain = 1.0f; m_rolloff = 0.1f; m_loaded = false; - m_max_dist = max_width; + m_max_dist = max_dist; + m_duration = -1.0f; m_file = file; m_rolloff = rolloff; m_positional = positional; m_gain = gain; -} +} // SFXBuffer //---------------------------------------------------------------------------- - +/** Constructor getting the sfx parameters from an XML node. + * \param file File name of the data. + * \param node XML Node with the data for this sfx. + */ SFXBuffer::SFXBuffer(const std::string& file, const XMLNode* node) { @@ -64,6 +74,7 @@ SFXBuffer::SFXBuffer(const std::string& file, m_gain = 1.0f; m_rolloff = 0.1f; m_max_dist = 300.0f; + m_duration = -1.0f; m_positional = false; m_loaded = false; m_file = file; @@ -72,10 +83,15 @@ SFXBuffer::SFXBuffer(const std::string& file, node->get("positional", &m_positional ); node->get("volume", &m_gain ); node->get("max_dist", &m_max_dist ); -} + node->get("duration", &m_duration ); +} // SFXBuffer(XMLNode) //---------------------------------------------------------------------------- - +/** \brief load the buffer from file into OpenAL. + * \note If this buffer is already loaded, this call does nothing and + * returns false. + * \return Whether loading was successful. + */ bool SFXBuffer::load() { if (UserConfigParams::m_sfx == false) return false; @@ -103,9 +119,13 @@ bool SFXBuffer::load() m_loaded = true; return true; -} +} // load //---------------------------------------------------------------------------- +/** \brief Frees the loaded buffer. + * Cannot appear in destructor because copy-constructors may be used, + * and the OpenAL source must not be deleted on a copy + */ void SFXBuffer::unload() { @@ -117,7 +137,7 @@ void SFXBuffer::unload() } #endif m_loaded = false; -} +} // unload //---------------------------------------------------------------------------- /** Load a vorbis file into an OpenAL buffer @@ -164,7 +184,7 @@ bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer) if(!data) { ov_clear(&oggFile); - Log::error("SFXBuffer", "[SFXBuffer] loadVorbisBuffer() - Error : LoadVorbisBuffer() - couldn't allocate decode buffer\n"); + Log::error("SFXBuffer", "[SFXBuffer] Could not allocate decode buffer."); return false; } @@ -188,9 +208,21 @@ bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer) ov_clear(&oggFile); fclose(file); + + // Allow the xml data to overwrite the duration, but if there is no + // duration (which is the norm), compute it: + if(m_duration < 0) + { + ALint buffer_size, frequency, bits_per_sample, channels; + alGetBufferi(buffer, AL_SIZE, &buffer_size ); + alGetBufferi(buffer, AL_FREQUENCY, &frequency ); + alGetBufferi(buffer, AL_CHANNELS, &channels ); + alGetBufferi(buffer, AL_BITS, &bits_per_sample); + m_duration = float(buffer_size) / (frequency*channels*(bits_per_sample / 8)); + } return success; #else return false; #endif -} +} // loadVorbisBuffer diff --git a/src/audio/sfx_buffer.hpp b/src/audio/sfx_buffer.hpp index 98ffbc8e4..e0583b67c 100644 --- a/src/audio/sfx_buffer.hpp +++ b/src/audio/sfx_buffer.hpp @@ -46,18 +46,32 @@ class SFXBuffer { private: + LEAK_CHECK() + /** Whether the contents of the file was loaded */ bool m_loaded; /** The file that contains the OGG audio data */ std::string m_file; + /** The openal buffer id. */ ALuint m_buffer; + + /** If the sound is positional. */ bool m_positional; + + /** The roll-off value. */ float m_rolloff; + + /** The volume gain value. */ float m_gain; + + /** Maximum distance the sfx can be heard. */ float m_max_dist; + /** Duration of the sfx. */ + float m_duration; + bool loadVorbisBuffer(const std::string &name, ALuint buffer); public: @@ -70,41 +84,43 @@ public: SFXBuffer(const std::string& file, const XMLNode* node); - ~SFXBuffer() { - } + } // ~SFXBuffer - /** - * \brief load the buffer from file into OpenAL. - * \note If this buffer is already loaded, this call does nothing and returns false - * \return whether loading was successful - */ - bool load(); - /** - * \brief Frees the loaded buffer - * Cannot appear in destructor because copy-constructors may be used, - * and the OpenAL source must not be deleted on a copy - */ - void unload(); + bool load(); + void unload(); + // ------------------------------------------------------------------------ /** \return whether this buffer was loaded from disk */ - bool isLoaded() const { return m_loaded; } - + bool isLoaded() const { return m_loaded; } + // ------------------------------------------------------------------------ /** Only returns a valid buffer if isLoaded() returned true */ - ALuint getBufferID() const { return m_buffer; } + ALuint getBufferID() const { return m_buffer; } + // ------------------------------------------------------------------------ + /** Returns if the buffer is positional. */ + bool isPositional() const { return m_positional; } + // ------------------------------------------------------------------------ + /** Returns the rolloff value of this buffer. */ + float getRolloff() const { return m_rolloff; } + // ------------------------------------------------------------------------ + /** Returns the gain for this sfx. */ + float getGain() const { return m_gain; } + // ------------------------------------------------------------------------ + /** Returns the maximum distance this sfx can be heard. */ + float getMaxDist() const { return m_max_dist; } + // ------------------------------------------------------------------------ + /** Returns the file name of this buffer. */ + const std::string& getFileName() const { return m_file; } + // ------------------------------------------------------------------------ + /** Sets if this buffer is positional or not. */ + void setPositional(bool positional) { m_positional = positional; } + // ------------------------------------------------------------------------ + /** Returns how long this buffer will play. */ + float getDuration() const { return m_duration; } - bool isPositional() const { return m_positional; } - float getRolloff() const { return m_rolloff; } - float getGain() const { return m_gain; } - float getMaxDist() const { return m_max_dist; } - std::string getFileName() const { return m_file; } - - void setPositional(bool positional) { m_positional = positional; } - - LEAK_CHECK() -}; +}; // class SFXBuffer #endif // HEADER_SFX_BUFFER_HPP