From d472f400811fb89ea72a742765ffb294dcdcfb70 Mon Sep 17 00:00:00 2001 From: TwinFan Date: Sat, 11 Nov 2023 20:52:46 +0100 Subject: [PATCH 1/3] fix: Freeze in XP12 related to XPD-13332 --- src/AIMultiplayer.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/AIMultiplayer.cpp b/src/AIMultiplayer.cpp index f02f7a7..797a158 100755 --- a/src/AIMultiplayer.cpp +++ b/src/AIMultiplayer.cpp @@ -749,26 +749,24 @@ int AIMultiControlPlaneCount( // /// @brief Resets all actual values of the AI/multiplayer dataRefs of one plane to something initial -/// @note There as pending bug, filed as XPD-13332, which affects this function with XP12 on Mac. +/// @note There as pending bug, filed as XPD-13332, which affects this function with XP12. /// X-Plane 12 can freeze since b5 when clearing Multiplayer positions to zero. /// @see https://forums.x-plane.org/index.php?/forums/topic/276319-xp12-on-mac-since-b5-freeze-upon-tcas-activation/ +/// @see also https://forums.x-plane.org/index.php?/forums/topic/296584-livetraffic-freezes-xp-1208beta1-on-taking-over-tcas/ +/// reporting the same issue for Linux, so we switch initializing off completely. void AIMultiClearAIDataRefs (multiDataRefsTy& drM, bool bDeactivateToZero) { // not ok dataRefs? if (!drM) return; -#if APL - // Apple Workaround for XP12: Don't init position, otherwise may freeze + // XPD-13332 Workaround for XP12: Don't init position, otherwise may freeze if (glob.verXPlane < 12000) { -#endif - // either a "far away" location or standard 0, which is, however, a valid location somewhere! - XPLMSetDataf(drM.X, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); - XPLMSetDataf(drM.Y, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); - XPLMSetDataf(drM.Z, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); -#if APL + // either a "far away" location or standard 0, which is, however, a valid location somewhere! + XPLMSetDataf(drM.X, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); + XPLMSetDataf(drM.Y, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); + XPLMSetDataf(drM.Z, bDeactivateToZero ? 0.0f : FAR_AWAY_VAL_GL); } -#endif XPLMSetDataf(drM.v_x, 0.0f); // zero speed XPLMSetDataf(drM.v_y, 0.0f); From 1390c6a189af80078d8f46f4e9defb2baa71cd2b Mon Sep 17 00:00:00 2001 From: TwinFan Date: Sat, 11 Nov 2023 22:52:57 +0100 Subject: [PATCH 2/3] fix/sound: Start paused to avoid crackling --- src/Sound.cpp | 37 +++++++++++++++++++++++++++++++++---- src/Sound.h | 10 ++++++++++ src/SoundFMOD.cpp | 15 ++++++++++++++- src/SoundFMOD.h | 2 ++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/Sound.cpp b/src/Sound.cpp index 67fa6cd..ac777fc 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -397,9 +397,15 @@ std::pair SoundSystem::AddChn (SoundFile* pSnd, float vo // Return the SoundChannel object for a given id, or `nullptr` if not found SoundChannel* SoundSystem::GetChn (uint64_t sndId) { + // check cached value first + if (cacheSndId == sndId && pCacheChn) + return pCacheChn; + // search in map of channels auto i = mapChn.find(sndId); - if (i != mapChn.end()) - return &i->second; + if (i != mapChn.end()) { + cacheSndId = sndId; // fill cache + return pCacheChn = &i->second; + } else return nullptr; } @@ -407,6 +413,8 @@ SoundChannel* SoundSystem::GetChn (uint64_t sndId) // Remove a channel from out tracking void SoundSystem::RemoveChn (uint64_t sndId) { + if (cacheSndId == sndId) // clear cache + pCacheChn = nullptr; mapChn.erase(sndId); } @@ -480,7 +488,13 @@ uint64_t SoundSystemXP::Play (const std::string& sndName, float vol, const Aircr xplm_AudioExteriorEnvironment, PlayCallback, (void*)sndId); if (!pChn->pChn) throw std::runtime_error("XPLMPlayPCMOnBus return NULL"); - +#if INCLUDE_FMOD_SOUND + 0 >= 1 + // if we have FMOD available then start in a paused state to avoid crackling + FMOD_LOG(FMOD_Channel_SetPaused(pChn->pChn, true)); +#else + pChn->nPauseCountdown = 0; +#endif + // Set a few more parameters to the sound FMOD_LOG(gpXPLMSetAudioFadeDistance(pChn->pChn, (float)ac.sndMinDist, FMOD_3D_MAX_DIST)); SetPosOrientation(sndId, ac, true); @@ -525,6 +539,20 @@ void SoundSystemXP::PlayCallback (void* inRefcon, me->RemoveChn(sndId); } +// Unpause a sound, which got started in a paused state to avoid crackling +/// @note Only available if built with FMOD library +void SoundSystemXP::Unpause (uint64_t sndId) +{ +#if INCLUDE_FMOD_SOUND + 0 >= 1 + SoundChannel* pChn = GetChn(sndId); + if (!pChn || !pChn->pChn) return; + + if (pChn->ShallUnpause()) { + FMOD_LOG(FMOD_Channel_SetPaused(pChn->pChn, false)); + } +#endif +} + // Stop the sound void SoundSystemXP::Stop (uint64_t sndId) @@ -895,7 +923,7 @@ void Aircraft::SoundUpdate () } } - // --- Update all channels' 3D position + // --- Unpause and Update all channels' 3D position // Decide here already if this time we do expensive computations (like sound cone orientation) bool bDoExpensiveComp = false; @@ -909,6 +937,7 @@ void Aircraft::SoundUpdate () // Still valid? const uint64_t sndId = *iter; if (gpSndSys->IsValid(sndId)) { + gpSndSys->Unpause(sndId); gpSndSys->SetPosOrientation(sndId, *this, bDoExpensiveComp); iter++; } else { diff --git a/src/Sound.h b/src/Sound.h index 92bb8d8..04014d4 100644 --- a/src/Sound.h +++ b/src/Sound.h @@ -182,6 +182,7 @@ class SoundChannel { SoundFile* pSnd = nullptr; ///< the sound file the sound was created from float vol = 1.0f; ///< volume (if not muted) bool bMuted = false; ///< currently muted? + int nPauseCountdown = 2; ///< frame till unpause this sound (starts paused to avoid crackling) public: /// Default Constructor creates an invalid object SoundChannel () {} @@ -189,6 +190,8 @@ class SoundChannel { SoundChannel (FMOD_CHANNEL* c, SoundFile* s, float v) : pChn(c), pSnd(s), vol(v) {} /// Has valid pointers? (Doesn't say if actual objects are valid any longer) operator bool () const { return pChn && pSnd; } + /// Need to unpause now? (returns `true` only once when countdown reaches zero) + bool ShallUnpause () { return nPauseCountdown > 0 ? (--nPauseCountdown == 0) : false; } }; /// Base class for sound systems, practically empty @@ -201,6 +204,9 @@ class SoundSystem { private: /// Next sound channel id uint64_t uNxtId = 0; + /// Cache to avoid re-lookup of repeatedly same sound id + uint64_t cacheSndId = 0; + SoundChannel* pCacheChn = nullptr; public: /// Construtor @@ -218,6 +224,8 @@ class SoundSystem { /// Play a new sound, returns an id for that sound virtual uint64_t Play (const std::string& sndName, float vol, const Aircraft& ac) = 0; + /// Unpause a sound, which got started in a paused state to avoid crackling + virtual void Unpause (uint64_t sndId) = 0; /// Stop the sound virtual void Stop (uint64_t sndId) = 0; /// Update sound's position and orientation @@ -274,6 +282,8 @@ class SoundSystemXP : public SoundSystem { /// Play a new sound, returns an id for that sound uint64_t Play (const std::string& sndName, float vol, const Aircraft& ac) override; + /// Unpause a sound, which got started in a paused state to avoid crackling + void Unpause (uint64_t sndId) override; /// Stop the sound void Stop (uint64_t sndId) override; /// Update sound's position and orientation diff --git a/src/SoundFMOD.cpp b/src/SoundFMOD.cpp index e11b549..dc3f287 100644 --- a/src/SoundFMOD.cpp +++ b/src/SoundFMOD.cpp @@ -290,7 +290,8 @@ uint64_t SoundSystemFMOD::Play (const std::string& sndName, float vol, const Air SoundFMOD* pSndFmod = dynamic_cast(pSnd.get()); if (!pSndFmod) throw std::runtime_error("Sound has not been loaded for FMOD system"); - FMOD_TEST(FMOD_System_PlaySound(pFmodSystem, pSndFmod->GetSnd(), pChnGrp, ac.SoundIsMuted(), &pFmodChn)); + // Start playing the sound, but in a paused state to avoid crackling + FMOD_TEST(FMOD_System_PlaySound(pFmodSystem, pSndFmod->GetSnd(), pChnGrp, true, &pFmodChn)); if (!pFmodChn) throw std::runtime_error("FMOD_System_PlaySound returned NULL channel"); // We must keep track of the sounds we produce so we can clean up after us @@ -310,6 +311,7 @@ uint64_t SoundSystemFMOD::Play (const std::string& sndName, float vol, const Air } SetPosOrientation(sndId, ac, true); FMOD_LOG(FMOD_Channel_SetVolume(pFmodChn, vol)); + FMOD_LOG(FMOD_Channel_SetMute(pFmodChn, ac.SoundIsMuted())); if (bLowPass) { FMOD_LOG(FMOD_Channel_SetLowPassGain(pFmodChn, FMOD_LOW_PASS_GAIN)); } @@ -329,6 +331,17 @@ uint64_t SoundSystemFMOD::Play (const std::string& sndName, float vol, const Air return 0; } + +// Unpause a sound, which got started in a paused state to avoid crackling +void SoundSystemFMOD::Unpause (uint64_t sndId) +{ + SoundChannel* pChn = GetChn(sndId); + if (!pChn || !pChn->pChn) return; + + if (pChn->ShallUnpause()) { + FMOD_LOG(FMOD_Channel_SetPaused(pChn->pChn, false)); + } +} // Stop the sound void SoundSystemFMOD::Stop (uint64_t sndId) diff --git a/src/SoundFMOD.h b/src/SoundFMOD.h index 4045cf1..e1f22d1 100644 --- a/src/SoundFMOD.h +++ b/src/SoundFMOD.h @@ -92,6 +92,8 @@ class SoundSystemFMOD : public SoundSystem { /// Play a new sound, returns an id for that sound uint64_t Play (const std::string& sndName, float vol, const Aircraft& ac) override; + /// Unpause a sound, which got started in a paused state to avoid crackling + void Unpause (uint64_t sndId) override; /// Stop the sound void Stop (uint64_t sndId) override; /// Update sound's position and orientation From 88ecfe1597387b8d095efab4687275e957241066 Mon Sep 17 00:00:00 2001 From: TwinFan Date: Sat, 11 Nov 2023 23:14:31 +0100 Subject: [PATCH 3/3] v3.3.1 --- CMakeLists.txt | 2 +- XPMP2.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c055a80..36ed308 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ else() endif() project(XPMP2 - VERSION 3.3.0 + VERSION 3.3.1 DESCRIPTION "Multiplayer library for X-Plane 11 and 12") # Provide compile macros from the above project version definition diff --git a/XPMP2.xcodeproj/project.pbxproj b/XPMP2.xcodeproj/project.pbxproj index a3f9307..304a711 100644 --- a/XPMP2.xcodeproj/project.pbxproj +++ b/XPMP2.xcodeproj/project.pbxproj @@ -481,7 +481,7 @@ ); XPMP2_VER_MAJOR = 3; XPMP2_VER_MINOR = 3; - XPMP2_VER_PATCH = 0; + XPMP2_VER_PATCH = 1; XPSDK_ROOT = lib/SDK; }; name = Debug; @@ -583,7 +583,7 @@ ); XPMP2_VER_MAJOR = 3; XPMP2_VER_MINOR = 3; - XPMP2_VER_PATCH = 0; + XPMP2_VER_PATCH = 1; XPSDK_ROOT = lib/SDK; }; name = Release;