From 86b60631a1410f6e447e42177fa92f8fa59cce44 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 22 Sep 2024 13:42:08 +0200 Subject: [PATCH 001/104] :wrench: Add missing namespace --- source/main/physics/ActorSpawner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/main/physics/ActorSpawner.cpp b/source/main/physics/ActorSpawner.cpp index 7c57434a75..d941307728 100644 --- a/source/main/physics/ActorSpawner.cpp +++ b/source/main/physics/ActorSpawner.cpp @@ -5903,9 +5903,9 @@ void ActorSpawner::ProcessNode(RigDef::Node & def) /* Positioning */ Ogre::Vector3 node_position = m_spawn_position + TuneupUtil::getTweakedNodePosition(m_actor->getWorkingTuneupDef(), node.pos, def.position); - ROR_ASSERT(!isnan(node_position.x)); - ROR_ASSERT(!isnan(node_position.y)); - ROR_ASSERT(!isnan(node_position.z)); + ROR_ASSERT(!std::isnan(node_position.x)); + ROR_ASSERT(!std::isnan(node_position.y)); + ROR_ASSERT(!std::isnan(node_position.z)); node.AbsPosition = node_position; node.RelPosition = node_position - m_actor->ar_origin; From 911bb582ec7a3cb84fb6dd0339df528853d3ff38 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 22 Sep 2024 13:45:14 +0200 Subject: [PATCH 002/104] :wrench: Add missing constructor gcc requires this due to how the struct is initialized in AddonPartFileFormat.cpp --- .../resources/addonpart_fileformat/AddonPartFileFormat.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/main/resources/addonpart_fileformat/AddonPartFileFormat.h b/source/main/resources/addonpart_fileformat/AddonPartFileFormat.h index e479ec62ad..fb4c5b05a2 100644 --- a/source/main/resources/addonpart_fileformat/AddonPartFileFormat.h +++ b/source/main/resources/addonpart_fileformat/AddonPartFileFormat.h @@ -41,6 +41,13 @@ struct AddonPartConflict //!< Conflict between two addonparts tweaking the same CacheEntryPtr atc_addonpart2; std::string atc_keyword; int atc_element_id = -1; + + AddonPartConflict(CacheEntryPtr addonpart1, CacheEntryPtr addonpart2, std::string keyword, int element_id): + atc_addonpart1(addonpart1), + atc_addonpart2(addonpart2), + atc_keyword(keyword), + atc_element_id(element_id) + {} }; typedef std::vector AddonPartConflictVec; From 0f4373751ad9732da9cc3852bbf13997fde24d89 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Mon, 23 Sep 2024 19:18:28 +0200 Subject: [PATCH 003/104] :bug: Update/fix Doppler effect for OpenAL 1.1 implementations OpenAL 1.1 changed the way how the doppler effect is handled from OpenAL 1.0. Using the old way did not break the build as demanded by the spec but disabled the effect for at least the OpenAL Soft implementation. --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5eb254fe26..671aa09b0d 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -109,7 +109,7 @@ SoundManager::SoundManager() } alDopplerFactor(1.0f); - alDopplerVelocity(343.0f); + alSpeedOfSound(343.3f); for (int i = 0; i < MAX_HARDWARE_SOURCES; i++) { From 3aac9eb3624a3be996ac723363bdd72a8427efc2 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 08:42:17 +0200 Subject: [PATCH 004/104] :wrench: rename setCamera methods of audio related classes to setListener --- source/main/audio/SoundManager.cpp | 2 +- source/main/audio/SoundManager.h | 2 +- source/main/audio/SoundScriptManager.cpp | 6 +++--- source/main/audio/SoundScriptManager.h | 2 +- source/main/main.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 671aa09b0d..61a6be5f23 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -135,7 +135,7 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } -void SoundManager::setCamera(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) +void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) { if (!audio_device) return; diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 510a997797..122e510423 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -55,7 +55,7 @@ class SoundManager */ SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name = ""); - void setCamera(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void pauseAllSounds(); void resumeAllSounds(); void setMasterVolume(float v); diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 6894caa870..93a6db7b7b 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -317,15 +317,15 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 upVector = App::GetCameraManager()->GetCameraNode()->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 cameraDir = App::GetCameraManager()->GetCameraNode()->getOrientation() * -Ogre::Vector3::UNIT_Z; - this->setCamera(App::GetCameraManager()->GetCameraNode()->getPosition(), cameraDir, upVector, cameraSpeed); + this->setListener(App::GetCameraManager()->GetCameraNode()->getPosition(), cameraDir, upVector, cameraSpeed); } } -void SoundScriptManager::setCamera(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) +void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) { if (disabled) return; - sound_manager->setCamera(position, direction, up, velocity); + sound_manager->setListener(position, direction, up, velocity); } const StringVector& SoundScriptManager::getScriptPatterns(void) const diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index fe557fe5ab..060d0c8f97 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -326,7 +326,7 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); - void setCamera(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setLoadingBaseSounds(bool value) { loading_base = value; }; bool isDisabled() { return disabled; } diff --git a/source/main/main.cpp b/source/main/main.cpp index adc108ec4a..616ec50a5e 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -933,7 +933,7 @@ int main(int argc, char *argv[]) App::sim_terrain_name->setStr(""); App::sim_terrain_gui_name->setStr(""); App::GetOutGauge()->Close(); - App::GetSoundScriptManager()->setCamera(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); + App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); } catch (...) { From aa54fbd967d34eaba1e593deb4350085a371dabe Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 10:10:03 +0200 Subject: [PATCH 005/104] :wrench: Refactor SoundScriptManager::update method update variable names to follow coding style and prefer local variables over method calls --- source/main/audio/SoundScriptManager.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 93a6db7b7b..e0fb0f35c7 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -310,14 +310,15 @@ void SoundScriptManager::update(float dt_sec) if (App::sim_state->getEnum() == SimState::RUNNING || App::sim_state->getEnum() == SimState::EDITOR_MODE) { - Ogre::SceneNode* cam_node = App::GetCameraManager()->GetCameraNode(); - static Vector3 lastCameraPosition; - Vector3 cameraSpeed = (cam_node->getPosition() - lastCameraPosition) / dt_sec; - lastCameraPosition = cam_node->getPosition(); - Ogre::Vector3 upVector = App::GetCameraManager()->GetCameraNode()->getOrientation() * Ogre::Vector3::UNIT_Y; + Ogre::SceneNode* camera_node = App::GetCameraManager()->GetCameraNode(); + static Vector3 last_camera_position; + Ogre::Vector3 camera_position = camera_node->getPosition(); + Vector3 camera_velocity = (camera_position - last_camera_position) / dt_sec; + last_camera_position = camera_position; + Ogre::Vector3 camera_up = camera_node->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) - Ogre::Vector3 cameraDir = App::GetCameraManager()->GetCameraNode()->getOrientation() * -Ogre::Vector3::UNIT_Z; - this->setListener(App::GetCameraManager()->GetCameraNode()->getPosition(), cameraDir, upVector, cameraSpeed); + Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; + this->setListener(camera_position, camera_direction, camera_up, camera_velocity); } } From a4e2fc2ed0d9c24388a1e9883e960a6f01f62db6 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 10:40:26 +0200 Subject: [PATCH 006/104] :sparkles: Add ConsoleCmd to get current speed of sound --- source/main/audio/SoundManager.h | 2 ++ source/main/system/ConsoleCmd.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 122e510423..a56e7d3288 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -62,6 +62,8 @@ class SoundManager bool isDisabled() { return audio_device == 0; } + float getSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + int getNumHardwareSources() { return hardware_sources_num; } static const float MAX_DISTANCE; diff --git a/source/main/system/ConsoleCmd.cpp b/source/main/system/ConsoleCmd.cpp index 9b578d4353..3a636159db 100644 --- a/source/main/system/ConsoleCmd.cpp +++ b/source/main/system/ConsoleCmd.cpp @@ -355,6 +355,34 @@ class AsCmd: public ConsoleCmd } }; +class SpeedOfSoundCmd: public ConsoleCmd +{ +public: + SpeedOfSoundCmd(): ConsoleCmd("speedofsound", "[]", _L("speedofsound - outputs the current speed of sound")) {} + + void Run(Ogre::StringVector const& args) override + { + if (!this->CheckAppState(AppState::SIMULATION)) + return; + + Str<200> reply; + reply << m_name << ": "; + Console::MessageType reply_type = Console::CONSOLE_SYSTEM_REPLY; + + SoundManager* sound_manager = App::GetSoundScriptManager()->getSoundManager(); + if (sound_manager == nullptr) + { + reply << _L("unable to get sound manager"); + } + else + { + reply << _L("Current speed of sound: ") << sound_manager->getSpeedOfSound(); + } + + App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, reply_type, reply.ToCStr()); + } +}; + class QuitCmd: public ConsoleCmd { public: @@ -666,6 +694,7 @@ void Console::regBuiltinCommands() // Additions cmd = new ClearCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new LoadScriptCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); + cmd = new SpeedOfSoundCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); // CVars cmd = new SetCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new SetstringCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); From 1ac28ad1a5f9787c35aacf974c9f31a8d2005612 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 10:44:14 +0200 Subject: [PATCH 007/104] :sparkles: Set speed of sound dependent of the medium the listener is in --- source/main/audio/SoundManager.cpp | 11 ++++++++++- source/main/audio/SoundManager.h | 2 +- source/main/audio/SoundScriptManager.cpp | 10 +++++++--- source/main/audio/SoundScriptManager.h | 2 +- source/main/main.cpp | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 61a6be5f23..bf48d374e7 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -135,7 +135,7 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } -void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) +void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater) { if (!audio_device) return; @@ -155,6 +155,15 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); alListenerfv(AL_ORIENTATION, orientation); + + if(!listener_is_underwater) + { + alSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + } + else + { + alSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + } } bool compareByAudibility(std::pair a, std::pair b) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index a56e7d3288..9ef898abe7 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -55,7 +55,7 @@ class SoundManager */ SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name = ""); - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater); void pauseAllSounds(); void resumeAllSounds(); void setMasterVolume(float v); diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index e0fb0f35c7..56fd684c86 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -24,6 +24,8 @@ #include "Actor.h" #include "CameraManager.h" +#include "GameContext.h" +#include "IWater.h" #include "Sound.h" #include "SoundManager.h" #include "Utils.h" @@ -318,15 +320,17 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 camera_up = camera_node->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; - this->setListener(camera_position, camera_direction, camera_up, camera_velocity); + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool camera_is_underwater = (water != nullptr ? water->IsUnderWater(camera_position) : false); + this->setListener(camera_position, camera_direction, camera_up, camera_velocity, camera_is_underwater); } } -void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) +void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity, bool listener_is_underwater) { if (disabled) return; - sound_manager->setListener(position, direction, up, velocity); + sound_manager->setListener(position, direction, up, velocity, listener_is_underwater); } const StringVector& SoundScriptManager::getScriptPatterns(void) const diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 060d0c8f97..cdfa6453f2 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -326,7 +326,7 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater); void setLoadingBaseSounds(bool value) { loading_base = value; }; bool isDisabled() { return disabled; } diff --git a/source/main/main.cpp b/source/main/main.cpp index 616ec50a5e..08ebb36bf1 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -933,7 +933,7 @@ int main(int argc, char *argv[]) App::sim_terrain_name->setStr(""); App::sim_terrain_gui_name->setStr(""); App::GetOutGauge()->Close(); - App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); + App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO, /*is underwater:*/ false); } catch (...) { From 2de6ca18fa576b4292b82603a94d148d6558d7da Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 14:26:52 +0200 Subject: [PATCH 008/104] :wrench: Adjust formatting for upcoming new function call --- source/main/gui/panels/GUI_GameSettings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index d7eb895aa4..b06f17bf6b 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -329,9 +329,9 @@ void GameSettings::DrawAudioSettings() App::audio_device_name->setStr(audio_devices[device_id]); } - DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); - DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); - DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); + DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); + DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); + DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); #endif // USE_OPENAL } From 2a1a2fa8bdc4819f0d7066444b488e6c791ac06d Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 24 Sep 2024 14:36:44 +0200 Subject: [PATCH 009/104] :sparkles: Make doppler factor configurable and scriptable this also allows to disable the effect by setting the doppler factor to 0 --- doc/angelscript/Script2Game/globals.h | 2 + source/main/Application.cpp | 3 + source/main/Application.h | 3 + source/main/audio/SoundManager.cpp | 2 +- source/main/audio/SoundManager.h | 2 + source/main/audio/SoundScriptManager.cpp | 7 +++ source/main/audio/SoundScriptManager.h | 1 + source/main/gui/panels/GUI_GameSettings.cpp | 1 + source/main/main.cpp | 10 ++++ source/main/scripting/GameScript.cpp | 16 ++++++ .../bindings/MsgQueueAngelscript.cpp | 2 + source/main/system/CVar.cpp | 1 + source/main/system/ConsoleCmd.cpp | 55 +++++++++++++++++++ 13 files changed, 104 insertions(+), 1 deletion(-) diff --git a/doc/angelscript/Script2Game/globals.h b/doc/angelscript/Script2Game/globals.h index aa7f918348..ceb908adea 100644 --- a/doc/angelscript/Script2Game/globals.h +++ b/doc/angelscript/Script2Game/globals.h @@ -664,6 +664,8 @@ enum MsgType MSG_EDI_RELOAD_BUNDLE_REQUESTED, //!< This deletes all actors using that bundle (= ZIP or directory)! Params: 'cache_entry' (CacheEntryClass@) MSG_EDI_UNLOAD_BUNDLE_REQUESTED, //!< This deletes all actors using that bundle (= ZIP or directory)! Params: 'cache_entry' (CacheEntryClass@) MSG_EDI_CREATE_PROJECT_REQUESTED, //!< Creates a subdir under 'projects/', pre-populates it and adds to modcache. Params: 'name' (string), 'ext' (string, optional), 'source_entry' (CacheEntryClass@) + // Audio + MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED //!< Request change of doppler factor. Params: 'doppler_factor' (float). doppler_factor must not be negative.NAL }; } // namespace Script2Game diff --git a/source/main/Application.cpp b/source/main/Application.cpp index b25c55e36c..f31cd56fef 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -209,6 +209,7 @@ CVar* io_invert_orbitcam; CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_device_name; +CVar* audio_doppler_factor; CVar* audio_menu_music; // Graphics @@ -627,6 +628,8 @@ const char* MsgTypeToString(MsgType type) case MSG_EDI_MODIFY_PROJECT_REQUESTED : return "MSG_EDI_MODIFY_PROJECT_REQUESTED"; case MSG_EDI_DELETE_PROJECT_REQUESTED : return "MSG_EDI_DELETE_PROJECT_REQUESTED"; + case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED : return "MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED"; + default: return ""; } } diff --git a/source/main/Application.h b/source/main/Application.h index ef0a52d4d3..7a9fae9833 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -150,6 +150,8 @@ enum MsgType MSG_EDI_CREATE_PROJECT_REQUESTED, //!< Payload = RoR::CreateProjectRequest* (owner) MSG_EDI_MODIFY_PROJECT_REQUESTED, //!< Payload = RoR::UpdateProjectRequest* (owner) MSG_EDI_DELETE_PROJECT_REQUESTED, //!< Payload = RoR::CacheEntryPtr* (owner) + // Audio + MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED, //!< Payload = float* }; const char* MsgTypeToString(MsgType type); @@ -446,6 +448,7 @@ extern CVar* io_invert_orbitcam; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_device_name; +extern CVar* audio_doppler_factor; extern CVar* audio_menu_music; // Graphics diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index bf48d374e7..dd6c90ecbc 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -108,7 +108,7 @@ SoundManager::SoundManager() alSourcef(hardware_sources[hardware_sources_num], AL_MAX_DISTANCE, MAX_DISTANCE); } - alDopplerFactor(1.0f); + alDopplerFactor(App::audio_doppler_factor->getFloat()); alSpeedOfSound(343.3f); for (int i = 0; i < MAX_HARDWARE_SOURCES; i++) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 9ef898abe7..d86c21862e 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -63,6 +63,8 @@ class SoundManager bool isDisabled() { return audio_device == 0; } float getSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } + void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } int getNumHardwareSources() { return hardware_sources_num; } diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 56fd684c86..2cfd7a50ac 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -333,6 +333,13 @@ void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector sound_manager->setListener(position, direction, up, velocity, listener_is_underwater); } +void SoundScriptManager::setDopplerFactor(float doppler_factor) +{ + if (disabled) + return; + sound_manager->setDopplerFactor(doppler_factor); +} + const StringVector& SoundScriptManager::getScriptPatterns(void) const { return script_patterns; diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index cdfa6453f2..8e7e6f7fd7 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -326,6 +326,7 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); + void setDopplerFactor(float doppler_factor); void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater); void setLoadingBaseSounds(bool value) { loading_base = value; }; diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index b06f17bf6b..88348fb9f6 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -332,6 +332,7 @@ void GameSettings::DrawAudioSettings() DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); + DrawGFloatSlider(App::audio_doppler_factor, _LC("GameSettings", "Doppler factor (requires restart)"), 0, 10); #endif // USE_OPENAL } diff --git a/source/main/main.cpp b/source/main/main.cpp index 08ebb36bf1..a61758f506 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -1581,6 +1581,16 @@ int main(int argc, char *argv[]) break; } + // -- Audio events -- + case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED: + { + float* doppler_factor_ptr = static_cast(m.payload); + LOG(fmt::format("Changing doppler factor to '{}' (from message bus)", *doppler_factor_ptr)); + App::GetSoundScriptManager()->getSoundManager()->setDopplerFactor(*doppler_factor_ptr); + delete doppler_factor_ptr; + break; + } + default:; } diff --git a/source/main/scripting/GameScript.cpp b/source/main/scripting/GameScript.cpp index 4a6a0ecd0a..6ae28de72f 100644 --- a/source/main/scripting/GameScript.cpp +++ b/source/main/scripting/GameScript.cpp @@ -1704,6 +1704,22 @@ bool GameScript::pushMessage(MsgType type, AngelScript::CScriptDictionary* dict) } break; } + // Audio + case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED: + { + float* doppler_factor_ptr = new float(); + if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "doppler_factor", "float", doppler_factor_ptr) && + !(*doppler_factor_ptr < 0.0f)) + { + m.payload = static_cast(doppler_factor_ptr); + } + else + { + delete doppler_factor_ptr; + return false; + } + break; + } default:; } diff --git a/source/main/scripting/bindings/MsgQueueAngelscript.cpp b/source/main/scripting/bindings/MsgQueueAngelscript.cpp index bfc91846c6..04ae7922cc 100644 --- a/source/main/scripting/bindings/MsgQueueAngelscript.cpp +++ b/source/main/scripting/bindings/MsgQueueAngelscript.cpp @@ -98,6 +98,8 @@ void RoR::RegisterMessageQueue(asIScriptEngine* engine) result = engine->RegisterEnumValue("MsgType", "MSG_EDI_RELOAD_BUNDLE_REQUESTED", MSG_EDI_RELOAD_BUNDLE_REQUESTED); ROR_ASSERT(result >= 0); result = engine->RegisterEnumValue("MsgType", "MSG_EDI_UNLOAD_BUNDLE_REQUESTED", MSG_EDI_UNLOAD_BUNDLE_REQUESTED); ROR_ASSERT(result >= 0); result = engine->RegisterEnumValue("MsgType", "MSG_EDI_CREATE_PROJECT_REQUESTED", MSG_EDI_CREATE_PROJECT_REQUESTED); ROR_ASSERT(result >= 0); + // Audio + result = engine->RegisterEnumValue("MsgType", "MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED", MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED); ROR_ASSERT(result >= 0); // enum FreeForceType result = engine->RegisterEnum("FreeForceType"); ROR_ASSERT(result>=0); diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 99697ca057..eb33924153 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -152,6 +152,7 @@ void Console::cVarSetupBuiltins() App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); + App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); diff --git a/source/main/system/ConsoleCmd.cpp b/source/main/system/ConsoleCmd.cpp index 3a636159db..11886dff55 100644 --- a/source/main/system/ConsoleCmd.cpp +++ b/source/main/system/ConsoleCmd.cpp @@ -383,6 +383,60 @@ class SpeedOfSoundCmd: public ConsoleCmd } }; +class DopplerFactorCmd: public ConsoleCmd +{ +public: + DopplerFactorCmd(): ConsoleCmd("dopplerfactor", "[]", _L("Get or set doppler factor (1.0 for realistic effect, 0 for disabling).")) {} + + void Run(Ogre::StringVector const& args) override + { + if (!this->CheckAppState(AppState::SIMULATION)) + return; + + Str<200> reply; + Console::MessageType reply_type; + reply << m_name << ": "; + + if (!(args.size() >= 1 && args.size() <= 2)) + { + reply_type = Console::CONSOLE_HELP; + reply <<_L("usage: dopplerfactor [doppler factor (float)]"); + } + else + { + SoundManager* sound_manager = App::GetSoundScriptManager()->getSoundManager(); + if (sound_manager == nullptr) + { + reply << _L("unable to get sound manager"); + } + else + { + if(args.size() == 2) + { + float doppler_factor = std::stof(args[1]); + if (doppler_factor < 0.0f) + { + reply << _L("doppler factor must not be negative"); + } + else + { + Message m(MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED); + float* doppler_factor_ptr = new float(doppler_factor); + m.payload = static_cast(doppler_factor_ptr); + App::GetGameContext()->PushMessage(m); + reply << _L("Queued update of doppler factor to: ") << doppler_factor; + } + } + else + { + reply << _L("Doppler Factor is configured as: ") << "CVar (change requires restart): " << App::audio_doppler_factor->getFloat() << ", currently used by OpenAL: " << sound_manager->getDopplerFactor(); + } + } + } + App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, reply_type, reply.ToCStr()); + } +}; + class QuitCmd: public ConsoleCmd { public: @@ -695,6 +749,7 @@ void Console::regBuiltinCommands() cmd = new ClearCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new LoadScriptCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new SpeedOfSoundCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); + cmd = new DopplerFactorCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); // CVars cmd = new SetCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new SetstringCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); From 5a219c57361938b6999e3434f1479cbe6d6a7db7 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 25 Sep 2024 10:07:56 +0200 Subject: [PATCH 010/104] :wrench: Rename camera_position to listener_position where appropriate --- source/main/audio/SoundManager.cpp | 6 +++--- source/main/audio/SoundManager.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index dd6c90ecbc..0ad77ff53e 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -139,7 +139,7 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, { if (!audio_device) return; - camera_position = position; + listener_position = position; recomputeAllSources(); float orientation[6]; @@ -180,7 +180,7 @@ void SoundManager::recomputeAllSources() for (int i=0; i < audio_buffers_in_use_count; i++) { - audio_sources[i]->computeAudibility(camera_position); + audio_sources[i]->computeAudibility(listener_position); audio_sources_most_audible[i].first = i; audio_sources_most_audible[i].second = audio_sources[i]->audibility; } @@ -218,7 +218,7 @@ void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vect { if (!audio_device) return; - audio_sources[source_index]->computeAudibility(camera_position); + audio_sources[source_index]->computeAudibility(listener_position); if (audio_sources[source_index]->audibility == 0.0f) { diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index d86c21862e..5d8fe3f0dc 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -100,7 +100,7 @@ class SoundManager ALuint audio_buffers[MAX_AUDIO_BUFFERS]; Ogre::String audio_buffer_file_name[MAX_AUDIO_BUFFERS]; - Ogre::Vector3 camera_position = Ogre::Vector3::ZERO; + Ogre::Vector3 listener_position = Ogre::Vector3::ZERO; ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; }; From e51e8483a534589ef3f7f8f143183c1744794083 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 25 Sep 2024 15:21:15 +0200 Subject: [PATCH 011/104] :wrench: Refactor how the speed of sound is set This design has less coupling and allows for setting more environmental properties of the listener in the future --- source/main/audio/SoundManager.cpp | 11 +--------- source/main/audio/SoundManager.h | 3 ++- source/main/audio/SoundScriptManager.cpp | 27 +++++++++++++++++++----- source/main/audio/SoundScriptManager.h | 4 +++- source/main/main.cpp | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 0ad77ff53e..e08baee2fd 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -135,7 +135,7 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } -void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater) +void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) { if (!audio_device) return; @@ -155,15 +155,6 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); alListenerfv(AL_ORIENTATION, orientation); - - if(!listener_is_underwater) - { - alSpeedOfSound(343.3f); // assume listener is in air at 20° celsius - } - else - { - alSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) - } } bool compareByAudibility(std::pair a, std::pair b) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 5d8fe3f0dc..7268935f6f 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -55,7 +55,7 @@ class SoundManager */ SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name = ""); - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void pauseAllSounds(); void resumeAllSounds(); void setMasterVolume(float v); @@ -63,6 +63,7 @@ class SoundManager bool isDisabled() { return audio_device == 0; } float getSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + void setSpeedOfSound(float speed_of_sound) { alSpeedOfSound(speed_of_sound); } float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 2cfd7a50ac..6e73fbd07c 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -320,17 +320,34 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 camera_up = camera_node->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - bool camera_is_underwater = (water != nullptr ? water->IsUnderWater(camera_position) : false); - this->setListener(camera_position, camera_direction, camera_up, camera_velocity, camera_is_underwater); + this->setListener(camera_position, camera_direction, camera_up, camera_velocity); + this->setListenerEnvironment(camera_position); } } -void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity, bool listener_is_underwater) +void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) { if (disabled) return; - sound_manager->setListener(position, direction, up, velocity, listener_is_underwater); + sound_manager->setListener(position, direction, up, velocity); +} + +void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) +{ + if (disabled) + return; + + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + + if(listener_is_underwater) + { + sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + } + else + { + sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + } } void SoundScriptManager::setDopplerFactor(float doppler_factor) diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 8e7e6f7fd7..559a28ed1d 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -327,7 +327,7 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); void setDopplerFactor(float doppler_factor); - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity, bool listener_is_underwater); + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setLoadingBaseSounds(bool value) { loading_base = value; }; bool isDisabled() { return disabled; } @@ -367,6 +367,8 @@ class SoundScriptManager : public Ogre::ScriptLoader // soundLinks, soundItems, actor_ids, triggers std::map > > > state_map; + void setListenerEnvironment(Ogre::Vector3 position); + SoundManager* sound_manager; }; diff --git a/source/main/main.cpp b/source/main/main.cpp index a61758f506..4c5c96f68c 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -933,7 +933,7 @@ int main(int argc, char *argv[]) App::sim_terrain_name->setStr(""); App::sim_terrain_gui_name->setStr(""); App::GetOutGauge()->Close(); - App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO, /*is underwater:*/ false); + App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); } catch (...) { From e061fe0cb01bfa4fe43a228a662f1a2995225d6d Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 25 Sep 2024 17:41:06 +0200 Subject: [PATCH 012/104] :sparkles: Add preliminary support for reverb using OpenAL EFX --- source/main/Application.cpp | 2 + source/main/Application.h | 2 + source/main/audio/SoundManager.cpp | 192 ++++++++++++++++++++ source/main/audio/SoundManager.h | 34 ++++ source/main/audio/SoundScriptManager.cpp | 30 +++ source/main/audio/SoundScriptManager.h | 1 + source/main/gui/panels/GUI_GameSettings.cpp | 1 + source/main/system/CVar.cpp | 2 + 8 files changed, 264 insertions(+) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index f31cd56fef..4d68f71990 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -208,6 +208,8 @@ CVar* io_invert_orbitcam; // Audio CVar* audio_master_volume; CVar* audio_enable_creak; +CVar* audio_enable_efx; +CVar* audio_force_efx_preset; CVar* audio_device_name; CVar* audio_doppler_factor; CVar* audio_menu_music; diff --git a/source/main/Application.h b/source/main/Application.h index 7a9fae9833..f118dc91df 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -447,6 +447,8 @@ extern CVar* io_invert_orbitcam; // Audio extern CVar* audio_master_volume; extern CVar* audio_enable_creak; +extern CVar* audio_enable_efx; +extern CVar* audio_force_efx_preset; extern CVar* audio_device_name; extern CVar* audio_doppler_factor; extern CVar* audio_menu_music; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index e08baee2fd..c8ee0afb17 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -96,6 +96,57 @@ SoundManager::SoundManager() if (alcGetString(audio_device, ALC_DEVICE_SPECIFIER)) LOG("SoundManager: OpenAL device is: " + String(alcGetString(audio_device, ALC_DEVICE_SPECIFIER))); if (alcGetString(audio_device, ALC_EXTENSIONS)) LOG("SoundManager: OpenAL ALC extensions are: " + String(alcGetString(audio_device, ALC_EXTENSIONS))); + // initialize use of OpenAL EFX extensions + this->efx_is_available = alcIsExtensionPresent(audio_device, "ALC_EXT_EFX"); + if (efx_is_available) + { + LOG("SoundManager: Found OpenAL EFX extension"); + + // Get OpenAL function pointers + alGenEffects = (LPALGENEFFECTS)alGetProcAddress("alGenEffects"); + alDeleteEffects = (LPALDELETEEFFECTS)alGetProcAddress("alDeleteEffects"); + alIsEffect = (LPALISEFFECT)alGetProcAddress("alIsEffect"); + alEffecti = (LPALEFFECTI)alGetProcAddress("alEffecti"); + alEffectf = (LPALEFFECTF)alGetProcAddress("alEffectf"); + alEffectfv = (LPALEFFECTFV)alGetProcAddress("alEffectfv"); + alGenFilters = (LPALGENFILTERS)alGetProcAddress("alGenFilters"); + alDeleteFilters = (LPALDELETEFILTERS)alGetProcAddress("alDeleteFilters"); + alIsFilter = (LPALISFILTER)alGetProcAddress("alIsFilter"); + alFilteri = (LPALFILTERI)alGetProcAddress("alFilteri"); + alFilterf = (LPALFILTERF)alGetProcAddress("alFilterf"); + alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)alGetProcAddress("alGenAuxiliaryEffectSlots"); + alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)alGetProcAddress("alDeleteAuxiliaryEffectSlots"); + alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)alGetProcAddress("alIsAuxiliaryEffectSlot"); + alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)alGetProcAddress("alAuxiliaryEffectSloti"); + alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)alGetProcAddress("alAuxiliaryEffectSlotf"); + alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)alGetProcAddress("alAuxiliaryEffectSlotfv"); + + if (App::audio_enable_efx->getBool()) + { + // create effect slot for the listener + if(!this->alIsAuxiliaryEffectSlot(listener_slot)) + { + alGetError(); + + this->alGenAuxiliaryEffectSlots(1, &listener_slot); + ALuint e = alGetError(); + + if (e != AL_NO_ERROR) + { + LOG("SoundManager: alGenAuxiliaryEffectSlots for listener_slot failed: " + e); + listener_slot = AL_EFFECTSLOT_NULL; + } + } + + this->build_efx_property_map(); + } + } + else + { + LOG("SoundManager: OpenAL EFX extension not found, disabling EFX"); + App::audio_enable_efx->setVal(false); + } + // generate the AL sources for (hardware_sources_num = 0; hardware_sources_num < MAX_HARDWARE_SOURCES; hardware_sources_num++) { @@ -106,6 +157,12 @@ SoundManager::SoundManager() alSourcef(hardware_sources[hardware_sources_num], AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE); alSourcef(hardware_sources[hardware_sources_num], AL_ROLLOFF_FACTOR, ROLLOFF_FACTOR); alSourcef(hardware_sources[hardware_sources_num], AL_MAX_DISTANCE, MAX_DISTANCE); + + // connect source to listener slot effect + if(App::audio_enable_efx->getBool()) + { + alSource3i(hardware_sources[hardware_sources_num], AL_AUXILIARY_SEND_FILTER, listener_slot, 0, AL_FILTER_NULL); + } } alDopplerFactor(App::audio_doppler_factor->getFloat()); @@ -115,6 +172,8 @@ SoundManager::SoundManager() { hardware_sources_map[i] = -1; } + + } SoundManager::~SoundManager() @@ -123,6 +182,18 @@ SoundManager::~SoundManager() alDeleteSources(MAX_HARDWARE_SOURCES, hardware_sources); alDeleteBuffers(MAX_AUDIO_BUFFERS, audio_buffers); + if(efx_is_available) + { + // TODO: alDeleteEffects + + if (alIsAuxiliaryEffectSlot(listener_slot)) + { + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + alDeleteAuxiliaryEffectSlots(1, &listener_slot); + listener_slot = AL_EFFECTSLOT_NULL; + } + } + // destroy the sound context and device sound_context = alcGetCurrentContext(); audio_device = alcGetContextsDevice(sound_context); @@ -135,6 +206,49 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } +void SoundManager::build_efx_property_map() +{ + this->efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; + this->efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; + this->efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; + this->efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; + this->efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; + this->efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; + this->efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; + this->efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; + this->efx_properties_map["EFX_REVERB_PRESET_QUARRY"] = EFX_REVERB_PRESET_QUARRY; + this->efx_properties_map["EFX_REVERB_PRESET_PLAIN"] = EFX_REVERB_PRESET_PLAIN; + this->efx_properties_map["EFX_REVERB_PRESET_PARKINGLOT"] = EFX_REVERB_PRESET_PARKINGLOT; + this->efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; + this->efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; + this->efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; + this->efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; + this->efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; + this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; + this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; + this->efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; + this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_BACKYARD"] = EFX_REVERB_PRESET_OUTDOORS_BACKYARD; + this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS"] = EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS; + this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON"] = EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON; + this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_CREEK"] = EFX_REVERB_PRESET_OUTDOORS_CREEK; + this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_VALLEY"] = EFX_REVERB_PRESET_OUTDOORS_VALLEY; + this->efx_properties_map["EFX_REVERB_PRESET_MOOD_HEAVEN"] = EFX_REVERB_PRESET_MOOD_HEAVEN; + this->efx_properties_map["EFX_REVERB_PRESET_MOOD_HELL"] = EFX_REVERB_PRESET_MOOD_HELL; + this->efx_properties_map["EFX_REVERB_PRESET_MOOD_MEMORY"] = EFX_REVERB_PRESET_MOOD_MEMORY; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_COMMENTATOR"] = EFX_REVERB_PRESET_DRIVING_COMMENTATOR; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_PITGARAGE"] = EFX_REVERB_PRESET_DRIVING_PITGARAGE; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; + this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; + this->efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; + this->efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; + this->efx_properties_map["EFX_REVERB_PRESET_CITY_UNDERPASS"] = EFX_REVERB_PRESET_CITY_UNDERPASS; + this->efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; +} + void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) { if (!audio_device) @@ -155,6 +269,84 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); alListenerfv(AL_ORIENTATION, orientation); + + if(App::audio_enable_efx->getBool()) + { + this->updateListenerEnvironment(); + } +} + +void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) +{ + if(efx_properties_map.find(listener_efx_preset_name) == efx_properties_map.end()) + { + // LOG("SoundManager: EFX preset `" + listener_efx_preset_name + "` is not available"); + listener_efx_preset_name = ""; // force that no preset is active + } + + if(listener_efx_preset_name != this->listener_efx_preset_name) + { + this->listener_efx_preset_name = listener_efx_preset_name; + listener_efx_environment_has_changed = true; + } + else + { + listener_efx_environment_has_changed = false; + } +} + +void SoundManager::updateListenerEnvironment() +{ + if (listener_efx_environment_has_changed) + { + if (listener_efx_preset_name.empty()) + { + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + } + else + { + // TODO: Reuse already existing effects + ALuint effect = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, effect); + } + } +} + +ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) +{ + ALuint effect = 0; + ALenum error; + + alGenEffects(1, &effect); + { + alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); + alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); + alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); + alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + } + /* Check if an error occured, and clean up if so. */ + error = alGetError(); + if(error != AL_NO_ERROR) + { + LOG("ERROR in SoundManager::LoadEffect: Could not create EFX effect:" + error); + + if(alIsEffect(effect)) + alDeleteEffects(1, &effect); + return 0; + } + + return effect; } bool compareByAudibility(std::pair a, std::pair b) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 7268935f6f..0a778f645d 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -31,9 +31,13 @@ #ifdef __APPLE__ #include #include + #include + #include #else #include #include + #include + #include #endif // __APPLE__ namespace RoR { @@ -56,6 +60,8 @@ class SoundManager SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name = ""); void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void setListenerEnvironment(std::string listener_environment); + void updateListenerEnvironment(); void pauseAllSounds(); void resumeAllSounds(); void setMasterVolume(float v); @@ -66,6 +72,7 @@ class SoundManager void setSpeedOfSound(float speed_of_sound) { alSpeedOfSound(speed_of_sound); } float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } + std::string getReverbPresetAt(Ogre::Vector3 position); int getNumHardwareSources() { return hardware_sources_num; } @@ -104,6 +111,33 @@ class SoundManager Ogre::Vector3 listener_position = Ogre::Vector3::ZERO; ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; + + // OpenAL EFX stuff + bool efx_is_available = false; + bool listener_efx_environment_has_changed = true; + ALuint listener_slot = 0; + std::string listener_efx_preset_name; + std::map efx_properties_map; + LPALGENEFFECTS alGenEffects = nullptr; + LPALDELETEEFFECTS alDeleteEffects = nullptr; + LPALISEFFECT alIsEffect = nullptr; + LPALEFFECTI alEffecti = nullptr; + LPALEFFECTF alEffectf = nullptr; + LPALEFFECTFV alEffectfv = nullptr; + LPALGENFILTERS alGenFilters = nullptr; + LPALDELETEFILTERS alDeleteFilters = nullptr; + LPALISFILTER alIsFilter = nullptr; + LPALFILTERI alFilteri = nullptr; + LPALFILTERF alFilterf = nullptr; + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots = nullptr; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots = nullptr; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot = nullptr; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti = nullptr; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf = nullptr; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv = nullptr; + + ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); + void build_efx_property_map(); }; /// @} diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 6e73fbd07c..115380d108 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -348,6 +348,36 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) { sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius } + + if (App::audio_enable_efx->getBool()) + { + std::string listener_environment; + + if(!App::audio_force_efx_preset->getStr().empty()) + { + listener_environment = App::audio_force_efx_preset->getStr(); + } + else + { + if(listener_is_underwater) + { + listener_environment = "EFX_REVERB_PRESET_UNDERWATER"; + } + else + { + listener_environment = this->getReverbPresetAt(listener_position); + } + // TODO: Might want to set an in-cockpit effect when appropriate + } + + sound_manager->setListenerEnvironment(listener_environment); + } +} + +std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) +{ + // TODO: This is a stub + return ""; } void SoundScriptManager::setDopplerFactor(float doppler_factor) diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 559a28ed1d..f4f69de3d7 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -367,6 +367,7 @@ class SoundScriptManager : public Ogre::ScriptLoader // soundLinks, soundItems, actor_ids, triggers std::map > > > state_map; + std::string getReverbPresetAt(Ogre::Vector3 position); void setListenerEnvironment(Ogre::Vector3 position); SoundManager* sound_manager; diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 88348fb9f6..5df18b3d11 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -330,6 +330,7 @@ void GameSettings::DrawAudioSettings() } DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); + DrawGCheckbox(App::audio_enable_efx, _LC("GameSettings", "Enable advanced sound effects via OpenAL EFX")); DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); DrawGFloatSlider(App::audio_doppler_factor, _LC("GameSettings", "Doppler factor (requires restart)"), 0, 10); diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index eb33924153..5b1510f105 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -154,6 +154,8 @@ void Console::cVarSetupBuiltins() App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); + App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From f7617a328c007d72bbd70986fdb427a75c3047b2 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 25 Sep 2024 18:33:05 +0200 Subject: [PATCH 013/104] :bug: Replace redundant efx preset with the intended one --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index c8ee0afb17..2a7c92a922 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -225,7 +225,7 @@ void SoundManager::build_efx_property_map() this->efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; this->efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; - this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + this->efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; From fbd1d8744bf8c1f9e3e37312ca4631431aadfb4b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 05:59:05 +0200 Subject: [PATCH 014/104] :wrench: Rename updateListenerEnvironment to updateListenerEffectSlot and make it private --- source/main/audio/SoundManager.cpp | 4 ++-- source/main/audio/SoundManager.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 2a7c92a922..f471d949d2 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -272,7 +272,7 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, if(App::audio_enable_efx->getBool()) { - this->updateListenerEnvironment(); + this->updateListenerEffectSlot(); } } @@ -295,7 +295,7 @@ void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) } } -void SoundManager::updateListenerEnvironment() +void SoundManager::updateListenerEffectSlot() { if (listener_efx_environment_has_changed) { diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 0a778f645d..bcbac5f4bb 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -61,7 +61,6 @@ class SoundManager void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setListenerEnvironment(std::string listener_environment); - void updateListenerEnvironment(); void pauseAllSounds(); void resumeAllSounds(); void setMasterVolume(float v); @@ -138,6 +137,7 @@ class SoundManager ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); void build_efx_property_map(); + void updateListenerEffectSlot(); }; /// @} From 63e3e245772a13fd7db8a8c72cf4e090aeff8cec Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 07:35:58 +0200 Subject: [PATCH 015/104] :triangular_ruler: Add whitespaces for upcoming CVars --- source/main/system/CVar.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 5b1510f105..c58d0934fb 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -149,13 +149,13 @@ void Console::cVarSetupBuiltins() App::io_discord_rpc = this->cVarCreate("io_discord_rpc", "Discord Rich Presence", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::io_invert_orbitcam = this->cVarCreate("io_invert_orbitcam", "Invert orbit camera", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); - App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); - App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); - App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); - App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); + App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); + App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); + App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); + App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); + App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From ce210cc5994e7307ef8464ae4b21cc59096a20d1 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 07:52:56 +0200 Subject: [PATCH 016/104] :wrench: Only create OpenAL effects when not already existing --- source/main/audio/SoundManager.cpp | 16 ++++++++++++---- source/main/audio/SoundManager.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f471d949d2..8f829bd55b 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -184,7 +184,10 @@ SoundManager::~SoundManager() if(efx_is_available) { - // TODO: alDeleteEffects + for (auto const& efx_effect_id : efx_effect_id_map) + { + alDeleteEffects(1, &efx_effect_id.second); + } if (alIsAuxiliaryEffectSlot(listener_slot)) { @@ -305,9 +308,14 @@ void SoundManager::updateListenerEffectSlot() } else { - // TODO: Reuse already existing effects - ALuint effect = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, effect); + // create new effect if not existing + if(!listener_efx_preset_name.empty() && efx_effect_id_map.find(listener_efx_preset_name) == efx_effect_id_map.end()) + { + efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); + } + + // update the effect on the listener effect slot + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); } } } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index bcbac5f4bb..55ade3217e 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -117,6 +117,7 @@ class SoundManager ALuint listener_slot = 0; std::string listener_efx_preset_name; std::map efx_properties_map; + std::map efx_effect_id_map; LPALGENEFFECTS alGenEffects = nullptr; LPALDELETEEFFECTS alDeleteEffects = nullptr; LPALISEFFECT alIsEffect = nullptr; From 7569d9f8995ec5a81d22667274d9f41de0a7015b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 08:20:18 +0200 Subject: [PATCH 017/104] :construction: Simulate absorption of sound at high frequencies This is considered WIP since the parameters are configurable, but they get currently overwritten at each frame dependent on the environment of the listener --- source/main/Application.cpp | 2 ++ source/main/Application.h | 2 ++ source/main/audio/SoundManager.cpp | 12 ++++++++++++ source/main/audio/SoundScriptManager.cpp | 9 +++++++++ source/main/system/CVar.cpp | 2 ++ 5 files changed, 27 insertions(+) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 4d68f71990..e181c4e98f 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -206,6 +206,8 @@ CVar* io_discord_rpc; CVar* io_invert_orbitcam; // Audio +CVar* audio_air_absorption_factor; +CVar* audio_air_absorption_gain_hf; CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_efx; diff --git a/source/main/Application.h b/source/main/Application.h index f118dc91df..c65e73a241 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -445,6 +445,8 @@ extern CVar* io_discord_rpc; extern CVar* io_invert_orbitcam; // Audio +extern CVar* audio_air_absorption_factor; +extern CVar* audio_air_absorption_gain_hf; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_efx; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 8f829bd55b..f1e05d9a36 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -314,6 +314,9 @@ void SoundManager::updateListenerEffectSlot() efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); } + // update air absorption gain hf of effect + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + // update the effect on the listener effect slot alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); } @@ -403,6 +406,15 @@ void SoundManager::recomputeAllSources() } } #endif + + if(App::audio_enable_efx->getBool()) + { + for(hardware_sources_num = 0; hardware_sources_num < MAX_HARDWARE_SOURCES; hardware_sources_num++) + { + // update air absorption factor + alSourcef(hardware_sources[hardware_sources_num], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + } + } } void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vector3* vvec) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 115380d108..dfb1298dc5 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -343,10 +343,19 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if(listener_is_underwater) { sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + /* + According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in water + and assuming the Air Absorption Gain HF property of OpenAL is set to the minimum of 0.892, + the absorption factor should be ~11.25, which is just slightly above the maximum of 10.0. + */ + App::audio_air_absorption_factor->setVal(10.0f); + App::audio_air_absorption_gain_hf->setVal(0.892f); } else { sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + App::audio_air_absorption_factor->setVal(1.0f); + App::audio_air_absorption_gain_hf->setVal(0.994f); } if (App::audio_enable_efx->getBool()) diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index c58d0934fb..93c612b14d 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -149,6 +149,8 @@ void Console::cVarSetupBuiltins() App::io_discord_rpc = this->cVarCreate("io_discord_rpc", "Discord Rich Presence", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::io_invert_orbitcam = this->cVarCreate("io_invert_orbitcam", "Invert orbit camera", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_air_absorption_factor = this->cVarCreate("audio_air_absorption_factor", "Air absorption factor", CVAR_TYPE_FLOAT, "1.0"); + App::audio_air_absorption_gain_hf = this->cVarCreate("audio_air_absorption_gain_hf", "Air absorption Gain HF", CVAR_TYPE_FLOAT, "0.994"); App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); From b65c3ea3fb9943e4d44b171164b8c1a4b8e54991 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 14:39:24 +0200 Subject: [PATCH 018/104] :construction: Simulate obstruction of sound emitters This should be considered an incomplete implementation. The line of sight checks/collision detection need to be improved. It does not detect trucks and some meshes on the terrain while it sometimes detects invisible walls --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 75 ++++++++++++++++++++++++++++++ source/main/audio/SoundManager.h | 6 ++- source/main/system/CVar.cpp | 1 + 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index e181c4e98f..4be8365299 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -210,6 +210,7 @@ CVar* audio_air_absorption_factor; CVar* audio_air_absorption_gain_hf; CVar* audio_master_volume; CVar* audio_enable_creak; +CVar* audio_enable_obstruction; CVar* audio_enable_efx; CVar* audio_force_efx_preset; CVar* audio_device_name; diff --git a/source/main/Application.h b/source/main/Application.h index c65e73a241..26426e702d 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -449,6 +449,7 @@ extern CVar* audio_air_absorption_factor; extern CVar* audio_air_absorption_gain_hf; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; +extern CVar* audio_enable_obstruction; extern CVar* audio_enable_efx; extern CVar* audio_force_efx_preset; extern CVar* audio_device_name; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f1e05d9a36..d73948ca61 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -139,6 +139,28 @@ SoundManager::SoundManager() } this->build_efx_property_map(); + + /* + Create filter for obstruction + Currently we don't check for how much high-frequency content the obstacle + lets through. We assume it's a hard surface with significant absorption + of high frequencies (which should be true for trucks, buildings and terrain). + */ + alGetError(); + + alGenFilters(1, &efx_outdoor_obstruction_lowpass_filter_id); + ALuint e = alGetError(); + + if (e != AL_NO_ERROR) + { + efx_outdoor_obstruction_lowpass_filter_id = AL_FILTER_NULL; + } + else + { + alFilteri(efx_outdoor_obstruction_lowpass_filter_id, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilterf(efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAIN, 0.33f); + alFilterf(efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAINHF, 0.25f); + } } } else @@ -184,6 +206,11 @@ SoundManager::~SoundManager() if(efx_is_available) { + if(alIsFilter(efx_outdoor_obstruction_lowpass_filter_id)) + { + alDeleteFilters(1, &efx_outdoor_obstruction_lowpass_filter_id); + } + for (auto const& efx_effect_id : efx_effect_id_map) { alDeleteEffects(1, &efx_effect_id.second); @@ -413,6 +440,54 @@ void SoundManager::recomputeAllSources() { // update air absorption factor alSourcef(hardware_sources[hardware_sources_num], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + + if(App::audio_enable_obstruction->getBool()) + { + /* + Check whether the source is obstructed and filter and attenuate it accordingly. + Currently, only the change in timbre of the sound is simulated. + TODO: Simulate diffraction path. + */ + + // find Sound the hardware_source belongs to + SoundPtr corresponding_sound = nullptr; + for(SoundPtr sound : audio_sources) + { + if(sound != nullptr) + { + if (sound->hardware_index == hardware_sources_num) + { + corresponding_sound = sound; + break; + } + } + } + + if (corresponding_sound != nullptr) + { + Ray direct_path_to_sound = Ray(listener_position, corresponding_sound->getPosition()); + std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + + /* + TODO: Also check if trucks are obstructing the sound. + Trucks shouldn't obstruct their own sound sources since the obstruction is most likely + already contained in the recording. + If the obstacle is the sound source's own truck, we should still check for other obstacles. + */ + + if(intersection.first) // sound is obstructed + { + // Apply obstruction filter to the source + alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); + } + else + { + // reset direct filter for the source in case it has been set previously + alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, AL_FILTER_NULL); + } + corresponding_sound = nullptr; + } + } } } } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 55ade3217e..61e10f98e9 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -24,6 +24,9 @@ #pragma once #include "Application.h" +#include "Collisions.h" +#include "GameContext.h" +#include "Sound.h" #include #include @@ -98,7 +101,7 @@ class SoundManager ALuint hardware_sources[MAX_HARDWARE_SOURCES]; // this buffer contains valid AL handles up to m_hardware_sources_num // audio sources - SoundPtr audio_sources[MAX_AUDIO_BUFFERS]; + SoundPtr audio_sources[MAX_AUDIO_BUFFERS] = { nullptr }; // helper for calculating the most audible sources std::pair audio_sources_most_audible[MAX_AUDIO_BUFFERS]; @@ -115,6 +118,7 @@ class SoundManager bool efx_is_available = false; bool listener_efx_environment_has_changed = true; ALuint listener_slot = 0; + ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; std::string listener_efx_preset_name; std::map efx_properties_map; std::map efx_effect_id_map; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 93c612b14d..1578569787 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -153,6 +153,7 @@ void Console::cVarSetupBuiltins() App::audio_air_absorption_gain_hf = this->cVarCreate("audio_air_absorption_gain_hf", "Air absorption Gain HF", CVAR_TYPE_FLOAT, "0.994"); App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); From 429439365639d754843d918aeef4978c8eea2777 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 26 Sep 2024 18:32:25 +0200 Subject: [PATCH 019/104] :sparkles: Add support for the AL_EFFECT_EAXREVERB reverb engine The AL_EFFECT_EAXREVERB engine is a superset of the AL_EFFECT_REVERB engine. Not all OpenAL implementations might support it. At least the Creative AL driver and OpenAL Soft support this reverb engine and there is a noticable difference in some of the reverb presets. Some of the features it provides might be useful for a more realistic audio experience as well. --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 110 +++++++++++++++++++++++------ source/main/audio/SoundManager.h | 13 ++++ source/main/system/CVar.cpp | 1 + 5 files changed, 106 insertions(+), 20 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 4be8365299..0e92f4ee9f 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -212,6 +212,7 @@ CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; CVar* audio_enable_efx; +CVar* audio_efx_reverb_engine; CVar* audio_force_efx_preset; CVar* audio_device_name; CVar* audio_doppler_factor; diff --git a/source/main/Application.h b/source/main/Application.h index 26426e702d..42d3c0b731 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -451,6 +451,7 @@ extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; extern CVar* audio_enable_efx; +extern CVar* audio_efx_reverb_engine; extern CVar* audio_force_efx_preset; extern CVar* audio_device_name; extern CVar* audio_doppler_factor; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index d73948ca61..0f041231c6 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -123,6 +123,33 @@ SoundManager::SoundManager() if (App::audio_enable_efx->getBool()) { + // allow user to change reverb engines at will + switch(efx_reverb_engine_map[App::audio_efx_reverb_engine->getStr()]) + { + case EfxReverbEngine::EAXREVERB: efx_reverb_engine = EfxReverbEngine::EAXREVERB; break; + case EfxReverbEngine::REVERB: efx_reverb_engine = EfxReverbEngine::REVERB; break; + default: + efx_reverb_engine = EfxReverbEngine::NONE; + LOG("SoundManager: Reverb engine disabled"); + } + + if(efx_reverb_engine == EfxReverbEngine::EAXREVERB) + { + if (alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) + { + LOG("SoundManager: OpenAL driver supports AL_EFFECT_EAXREVERB, using it"); + } + else + { + LOG("SoundManager: AL_EFFECT_EAXREVERB requested but OpenAL driver does not support it, falling back to standard reverb"); + efx_reverb_engine = EfxReverbEngine::REVERB; + } + } + else if(efx_reverb_engine == EfxReverbEngine::REVERB) + { + LOG("SoundManager: Using OpenAL standard reverb"); + } + // create effect slot for the listener if(!this->alIsAuxiliaryEffectSlot(listener_slot)) { @@ -342,7 +369,14 @@ void SoundManager::updateListenerEffectSlot() } // update air absorption gain hf of effect - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + if (efx_reverb_engine == EfxReverbEngine::EAXREVERB) + { + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + } + else if (efx_reverb_engine == EfxReverbEngine::REVERB) + { + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + } // update the effect on the listener effect slot alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); @@ -356,28 +390,64 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties ALenum error; alGenEffects(1, &effect); - { - alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - - alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); - alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); - alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); - alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); - alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); - alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); - } - /* Check if an error occured, and clean up if so. */ + + switch (efx_reverb_engine) + { + case EfxReverbEngine::EAXREVERB: + alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + + alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); + alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); + alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); + alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); + alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); + alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); + alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); + alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); + alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); + alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); + alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); + alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); + alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + + break; + case EfxReverbEngine::REVERB: + alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); + alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); + alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); + alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + + break; + case EfxReverbEngine::NONE: + default: + LOG("SoundManager: No usable reverb engine set, not creating reverb effect"); + } + error = alGetError(); if(error != AL_NO_ERROR) { - LOG("ERROR in SoundManager::LoadEffect: Could not create EFX effect:" + error); + LOG("SoundManager: Could not create EFX effect:" + error); if(alIsEffect(effect)) alDeleteEffects(1, &effect); diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 61e10f98e9..4b563b2a15 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -119,9 +119,22 @@ class SoundManager bool listener_efx_environment_has_changed = true; ALuint listener_slot = 0; ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; + + enum EfxReverbEngine + { + NONE, + REVERB, + EAXREVERB + }; + EfxReverbEngine efx_reverb_engine = EfxReverbEngine::NONE; + std::string listener_efx_preset_name; std::map efx_properties_map; std::map efx_effect_id_map; + std::map efx_reverb_engine_map = + {{"EAXREVERB", EfxReverbEngine::EAXREVERB}, + {"REVERB", EfxReverbEngine::REVERB}, + {"NONE", EfxReverbEngine::NONE}}; LPALGENEFFECTS alGenEffects = nullptr; LPALDELETEEFFECTS alDeleteEffects = nullptr; LPALISEFFECT alIsEffect = nullptr; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 1578569787..cb2e94a7a0 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -158,6 +158,7 @@ void Console::cVarSetupBuiltins() App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); + App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE, "EAXREVERB"); App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); From c9cddb424ba9f3080c19df1652597ac9efa8161e Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 06:22:04 +0200 Subject: [PATCH 020/104] :video_game: Add EFX_REVERB_PRESET_PREFAB_CARAVAN preset --- source/main/audio/SoundManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 0f041231c6..aab33614c0 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -283,6 +283,7 @@ void SoundManager::build_efx_property_map() this->efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; this->efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; + this->efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; this->efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; From 271a54af9a64632ea9e854dd60889f3042845e8d Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 06:24:56 +0200 Subject: [PATCH 021/104] :triangular_ruler: Remove leftover function declaration that was moved to SoundScriptManager class --- source/main/audio/SoundManager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 4b563b2a15..ef66258e0a 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -74,7 +74,6 @@ class SoundManager void setSpeedOfSound(float speed_of_sound) { alSpeedOfSound(speed_of_sound); } float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } - std::string getReverbPresetAt(Ogre::Vector3 position); int getNumHardwareSources() { return hardware_sources_num; } From 3caa7960ea8a711734ba45d8ab1be5081d030e6a Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 07:09:03 +0200 Subject: [PATCH 022/104] :triangular_ruler: Rename build_efx_property_map() to prepopulate_efx_property_map() --- source/main/audio/SoundManager.cpp | 4 ++-- source/main/audio/SoundManager.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index aab33614c0..f9d9141829 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -165,7 +165,7 @@ SoundManager::SoundManager() } } - this->build_efx_property_map(); + this->prepopulate_efx_property_map(); /* Create filter for obstruction @@ -263,7 +263,7 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } -void SoundManager::build_efx_property_map() +void SoundManager::prepopulate_efx_property_map() { this->efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; this->efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index ef66258e0a..6fc37fff04 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -153,7 +153,7 @@ class SoundManager LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv = nullptr; ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); - void build_efx_property_map(); + void prepopulate_efx_property_map(); void updateListenerEffectSlot(); }; From 75b643ddf613f647c2980d981cccc6c3e95a181d Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 10:22:28 +0200 Subject: [PATCH 023/104] :triangular_ruler: Reformat audio CVars for upcoming CVar --- source/main/system/CVar.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index cb2e94a7a0..98a35f26f8 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -149,17 +149,17 @@ void Console::cVarSetupBuiltins() App::io_discord_rpc = this->cVarCreate("io_discord_rpc", "Discord Rich Presence", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::io_invert_orbitcam = this->cVarCreate("io_invert_orbitcam", "Invert orbit camera", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_air_absorption_factor = this->cVarCreate("audio_air_absorption_factor", "Air absorption factor", CVAR_TYPE_FLOAT, "1.0"); - App::audio_air_absorption_gain_hf = this->cVarCreate("audio_air_absorption_gain_hf", "Air absorption Gain HF", CVAR_TYPE_FLOAT, "0.994"); - App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); - App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); - App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); - App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); - App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE, "EAXREVERB"); - App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); + App::audio_air_absorption_factor = this->cVarCreate("audio_air_absorption_factor", "Air absorption factor", CVAR_TYPE_FLOAT, "1.0"); + App::audio_air_absorption_gain_hf = this->cVarCreate("audio_air_absorption_gain_hf", "Air absorption Gain HF", CVAR_TYPE_FLOAT, "0.994"); + App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); + App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); + App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); + App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); + App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE, "EAXREVERB"); + App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From 4614579b3bb1116d334bf75ca715e65a984a2f65 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 10:41:32 +0200 Subject: [PATCH 024/104] :sparkles: Allow to disable engine-controlled environmental audio This allows the user to set environmental audio parameters from console or scripts without fearing they get overwritten by the engine --- source/main/Application.cpp | 3 +- source/main/Application.h | 3 +- source/main/audio/SoundScriptManager.cpp | 52 +++++++++++++----------- source/main/system/CVar.cpp | 3 +- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 0e92f4ee9f..85358f2590 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -212,8 +212,9 @@ CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; CVar* audio_enable_efx; +CVar* audio_engine_controls_environmental_audio; CVar* audio_efx_reverb_engine; -CVar* audio_force_efx_preset; +CVar* audio_listener_efx_preset; CVar* audio_device_name; CVar* audio_doppler_factor; CVar* audio_menu_music; diff --git a/source/main/Application.h b/source/main/Application.h index 42d3c0b731..37cf9e7577 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -451,8 +451,9 @@ extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; extern CVar* audio_enable_efx; +extern CVar* audio_engine_controls_environmental_audio; extern CVar* audio_efx_reverb_engine; -extern CVar* audio_force_efx_preset; +extern CVar* audio_listener_efx_preset; extern CVar* audio_device_name; extern CVar* audio_doppler_factor; extern CVar* audio_menu_music; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index dfb1298dc5..e711afd20e 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -337,36 +337,32 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (disabled) return; - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + std::string listener_environment; - if(listener_is_underwater) + if (App::audio_engine_controls_environmental_audio->getBool()) { - sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) - /* - According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in water - and assuming the Air Absorption Gain HF property of OpenAL is set to the minimum of 0.892, - the absorption factor should be ~11.25, which is just slightly above the maximum of 10.0. - */ - App::audio_air_absorption_factor->setVal(10.0f); - App::audio_air_absorption_gain_hf->setVal(0.892f); - } - else - { - sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius - App::audio_air_absorption_factor->setVal(1.0f); - App::audio_air_absorption_gain_hf->setVal(0.994f); - } + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); - if (App::audio_enable_efx->getBool()) - { - std::string listener_environment; - - if(!App::audio_force_efx_preset->getStr().empty()) + if(listener_is_underwater) { - listener_environment = App::audio_force_efx_preset->getStr(); + sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + /* + According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in water + and assuming the Air Absorption Gain HF property of OpenAL is set to the minimum of 0.892, + the absorption factor should be ~11.25, which is just slightly above the maximum of 10.0. + */ + App::audio_air_absorption_factor->setVal(10.0f); + App::audio_air_absorption_gain_hf->setVal(0.892f); } else + { + sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + App::audio_air_absorption_factor->setVal(1.0f); + App::audio_air_absorption_gain_hf->setVal(0.994f); + } + + if (App::audio_enable_efx->getBool()) { if(listener_is_underwater) { @@ -378,7 +374,15 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) } // TODO: Might want to set an in-cockpit effect when appropriate } + } + if (App::audio_enable_efx->getBool()) + { + if (listener_environment.empty()) + { + listener_environment = App::audio_listener_efx_preset->getStr(); + } + // always update the environment in case it was changed via console or script sound_manager->setListenerEnvironment(listener_environment); } } diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 98a35f26f8..586930ef03 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -158,8 +158,9 @@ void Console::cVarSetupBuiltins() App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); + App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_TYPE_BOOL, "true"); App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE, "EAXREVERB"); - App::audio_force_efx_preset = this->cVarCreate("audio_force_efx_preset", "Enforce OpenAL EFX preset", 0, ""); + App::audio_listener_efx_preset = this->cVarCreate("audio_listener_efx_preset", "OpenAL listener EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From b30019756d11cebfa7fe335692de30ef9ee95806 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 11:06:49 +0200 Subject: [PATCH 025/104] :wrench: Always update the listener effect This is necessary to change the AIR_ABSORPTION_GAIN_HF property once a preset has been made active. It will also be necessary for panning of reflection and late reverb. --- source/main/audio/SoundManager.cpp | 51 ++++++++++++------------------ source/main/audio/SoundManager.h | 1 - 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f9d9141829..1622db3514 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -342,46 +342,35 @@ void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) listener_efx_preset_name = ""; // force that no preset is active } - if(listener_efx_preset_name != this->listener_efx_preset_name) - { - this->listener_efx_preset_name = listener_efx_preset_name; - listener_efx_environment_has_changed = true; - } - else - { - listener_efx_environment_has_changed = false; - } + this->listener_efx_preset_name = listener_efx_preset_name; } void SoundManager::updateListenerEffectSlot() { - if (listener_efx_environment_has_changed) + if (listener_efx_preset_name.empty()) { - if (listener_efx_preset_name.empty()) + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + } + else + { + // create new effect if not existing + if(!listener_efx_preset_name.empty() && efx_effect_id_map.find(listener_efx_preset_name) == efx_effect_id_map.end()) { - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); } - else - { - // create new effect if not existing - if(!listener_efx_preset_name.empty() && efx_effect_id_map.find(listener_efx_preset_name) == efx_effect_id_map.end()) - { - efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); - } - // update air absorption gain hf of effect - if (efx_reverb_engine == EfxReverbEngine::EAXREVERB) - { - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); - } - else if (efx_reverb_engine == EfxReverbEngine::REVERB) - { - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); - } - - // update the effect on the listener effect slot - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); + // update air absorption gain hf of effect + if (efx_reverb_engine == EfxReverbEngine::EAXREVERB) + { + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } + else if (efx_reverb_engine == EfxReverbEngine::REVERB) + { + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + } + + // update the effect on the listener effect slot + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); } } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 6fc37fff04..fa53dde15b 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -115,7 +115,6 @@ class SoundManager // OpenAL EFX stuff bool efx_is_available = false; - bool listener_efx_environment_has_changed = true; ALuint listener_slot = 0; ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; From 7adf4340e9d59beb041caea07a8ee3dce9b18284 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 27 Sep 2024 17:25:32 +0200 Subject: [PATCH 026/104] :construction: Implement basic reflection panning This should be considered experimental. If nearby surfaces are detected, the early reflections of the currently active EFX preset are panned toward the surface and the reflection delay is adjusted based on the distance to this surface. It is considered experimental since the collision detection could use an improvement. --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 88 ++++++++++++++++++++++++++++++ source/main/audio/SoundManager.h | 2 + source/main/system/CVar.cpp | 1 + 5 files changed, 93 insertions(+) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 85358f2590..f9229661c6 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -211,6 +211,7 @@ CVar* audio_air_absorption_gain_hf; CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; +CVar* audio_enable_reflection_panning; CVar* audio_enable_efx; CVar* audio_engine_controls_environmental_audio; CVar* audio_efx_reverb_engine; diff --git a/source/main/Application.h b/source/main/Application.h index 37cf9e7577..68a693955a 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -450,6 +450,7 @@ extern CVar* audio_air_absorption_gain_hf; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; +extern CVar* audio_enable_reflection_panning; extern CVar* audio_enable_efx; extern CVar* audio_engine_controls_environmental_audio; extern CVar* audio_efx_reverb_engine; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 1622db3514..dba0ddeb38 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -312,6 +312,8 @@ void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, if (!audio_device) return; listener_position = position; + listener_direction = direction; + listener_up = up; recomputeAllSources(); float orientation[6]; @@ -369,6 +371,92 @@ void SoundManager::updateListenerEffectSlot() alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } + // reflection panning + if( + App::audio_enable_reflection_panning->getBool() && + efx_reverb_engine == EfxReverbEngine::EAXREVERB && + App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu + ) + { + /* + * Detect surfaces close to the listener and pan and delay early reflections accordingly. + * Use ray casting to probe for a collision up to max_distance to each side of the listener. + */ + float max_distance = 2.0f; + float reflection_delay = -1.0f; + float magnitude; + + Ogre::Vector3 reflection_panning_direction = { 0.0f, 0.0f, 0.0f}; + Ogre::Vector3 left = listener_position - listener_direction.crossProduct(listener_up).normalisedCopy() * max_distance; + Ogre::Vector3 right = listener_position + listener_direction.crossProduct(listener_up).normalisedCopy() * max_distance; + + Ray left_side = Ray(listener_position, left); + Ray right_side = Ray(listener_position, right); + + std::pair intersection_left = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(left_side); + std::pair intersection_right = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(right_side); + + // there is a nearby surface on both sides + if (intersection_left.first && intersection_right.first) + { + // pan toward the closer object + if (intersection_left.second < intersection_right.second) + { + reflection_panning_direction = left; + magnitude = intersection_left.second; + reflection_delay = intersection_left.second / getSpeedOfSound(); + } + else + { + reflection_panning_direction = right; + magnitude = intersection_right.second; + reflection_delay = intersection_right.second / getSpeedOfSound(); + } + // take the difference in collision distance to determine the magnitude of the panning vector + magnitude = Math::Abs(intersection_left.second - intersection_right.second); + } + else if (intersection_left.first) // there is a nearby surface on the left side + { + reflection_panning_direction = left; + magnitude = intersection_left.second; + reflection_delay = intersection_left.second / getSpeedOfSound(); + } + else if (intersection_right.first) // there is a nearby surface on the right side + { + reflection_panning_direction = right; + magnitude = intersection_right.second; + reflection_delay = intersection_right.second / getSpeedOfSound(); + } + else // no nearby surface detected + { + // reset reflection delay to the original value of the preset since there are no nearby surfaces + reflection_delay = efx_properties_map[listener_efx_preset_name].flReflectionsDelay; + } + + // transform reflection_panning_direction vector to listener-relative EAXREVERB reflection-panning vector + // invert z since EAXREVERB panning vectors use a left-handed coordinate system + float angle = std::acos(-listener_direction.z); + + if (listener_direction.x < 0) + { + angle = -angle; + } + + Ogre::Vector3 reflection_panning_vector = + {(reflection_panning_direction.x * std::cos(-angle)) + (reflection_panning_direction.z * std::sin(-angle)), + 0, + -(reflection_panning_direction.x * -std::sin(-angle)) + (reflection_panning_direction.z * std::cos(-angle))}; + reflection_panning_vector *= magnitude; + + float eaxreverb_reflection_panning_vector[3] = + { reflection_panning_vector.x, + reflection_panning_vector.y, + -reflection_panning_vector.z }; + + alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_reflection_panning_vector); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, reflection_delay); + } + // update the effect on the listener effect slot alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index fa53dde15b..8446db9353 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -110,6 +110,8 @@ class SoundManager Ogre::String audio_buffer_file_name[MAX_AUDIO_BUFFERS]; Ogre::Vector3 listener_position = Ogre::Vector3::ZERO; + Ogre::Vector3 listener_direction = Ogre::Vector3::ZERO; + Ogre::Vector3 listener_up = Ogre::Vector3::ZERO; ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 586930ef03..bbc5caf2d7 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -154,6 +154,7 @@ void Console::cVarSetupBuiltins() App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_reflection_panning = this->cVarCreate("audio_enable_reflection_panning", "Pan reflections", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); From c079bc87035467af5d33ff4d405c0aea25b52e3c Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 07:48:56 +0200 Subject: [PATCH 027/104] :bug: Fix calculation of magnitude --- source/main/audio/SoundManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index dba0ddeb38..f599bd3761 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -403,13 +403,13 @@ void SoundManager::updateListenerEffectSlot() if (intersection_left.second < intersection_right.second) { reflection_panning_direction = left; - magnitude = intersection_left.second; + magnitude = 1.0f - intersection_left.second / max_distance; reflection_delay = intersection_left.second / getSpeedOfSound(); } else { reflection_panning_direction = right; - magnitude = intersection_right.second; + magnitude = 1.0f - intersection_right.second / max_distance; reflection_delay = intersection_right.second / getSpeedOfSound(); } // take the difference in collision distance to determine the magnitude of the panning vector @@ -418,13 +418,13 @@ void SoundManager::updateListenerEffectSlot() else if (intersection_left.first) // there is a nearby surface on the left side { reflection_panning_direction = left; - magnitude = intersection_left.second; + magnitude = 1.0f - intersection_left.second / max_distance; reflection_delay = intersection_left.second / getSpeedOfSound(); } else if (intersection_right.first) // there is a nearby surface on the right side { reflection_panning_direction = right; - magnitude = intersection_right.second; + magnitude = 1.0f - intersection_right.second / max_distance; reflection_delay = intersection_right.second / getSpeedOfSound(); } else // no nearby surface detected From 2d39efffc5b6208330114e37f711a55dddb822c4 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 07:50:35 +0200 Subject: [PATCH 028/104] :books: Describe how we tranform the reflections panning vector --- source/main/audio/SoundManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f599bd3761..8aac735201 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -435,6 +435,8 @@ void SoundManager::updateListenerEffectSlot() // transform reflection_panning_direction vector to listener-relative EAXREVERB reflection-panning vector // invert z since EAXREVERB panning vectors use a left-handed coordinate system + + // determine the angle between listener_direction and straight ahead vector (0, 0, 1) float angle = std::acos(-listener_direction.z); if (listener_direction.x < 0) @@ -442,10 +444,14 @@ void SoundManager::updateListenerEffectSlot() angle = -angle; } + // inversely rotate reflection_panning_vector by the angle Ogre::Vector3 reflection_panning_vector = {(reflection_panning_direction.x * std::cos(-angle)) + (reflection_panning_direction.z * std::sin(-angle)), 0, -(reflection_panning_direction.x * -std::sin(-angle)) + (reflection_panning_direction.z * std::cos(-angle))}; + + // scale panning vector based on the distance to the collision + // we assume that surfaces further away cause less focussed reflections reflection_panning_vector *= magnitude; float eaxreverb_reflection_panning_vector[3] = From 98b576549a52367d4abfb0340169e87aaacf9728 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 08:00:51 +0200 Subject: [PATCH 029/104] :sparkles: Boost early reflections if a nearby surface is detected --- source/main/audio/SoundManager.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 8aac735201..9e58a9ca85 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -383,6 +383,8 @@ void SoundManager::updateListenerEffectSlot() * Use ray casting to probe for a collision up to max_distance to each side of the listener. */ float max_distance = 2.0f; + const float reflections_gain_boost_max = 0.316f; // 1 db + float reflections_gain; float reflection_delay = -1.0f; float magnitude; @@ -414,23 +416,39 @@ void SoundManager::updateListenerEffectSlot() } // take the difference in collision distance to determine the magnitude of the panning vector magnitude = Math::Abs(intersection_left.second - intersection_right.second); + reflections_gain = std::min( + (efx_properties_map[listener_efx_preset_name].flReflectionsGain + + reflections_gain_boost_max + - (reflections_gain_boost_max * magnitude)), + 3.16f); } else if (intersection_left.first) // there is a nearby surface on the left side { reflection_panning_direction = left; magnitude = 1.0f - intersection_left.second / max_distance; reflection_delay = intersection_left.second / getSpeedOfSound(); + reflections_gain = std::min( + (efx_properties_map[listener_efx_preset_name].flReflectionsGain + + reflections_gain_boost_max + - (reflections_gain_boost_max * magnitude)), + 3.16f); } else if (intersection_right.first) // there is a nearby surface on the right side { reflection_panning_direction = right; magnitude = 1.0f - intersection_right.second / max_distance; reflection_delay = intersection_right.second / getSpeedOfSound(); + reflections_gain = std::min( + (efx_properties_map[listener_efx_preset_name].flReflectionsGain + + reflections_gain_boost_max + - (reflections_gain_boost_max * magnitude)), + 3.16f); } else // no nearby surface detected { - // reset reflection delay to the original value of the preset since there are no nearby surfaces + // reset values to the original of the preset since there are no nearby surfaces reflection_delay = efx_properties_map[listener_efx_preset_name].flReflectionsDelay; + reflections_gain = efx_properties_map[listener_efx_preset_name].flReflectionsGain; } // transform reflection_panning_direction vector to listener-relative EAXREVERB reflection-panning vector @@ -461,6 +479,7 @@ void SoundManager::updateListenerEffectSlot() alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_reflection_panning_vector); alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, reflection_delay); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, reflections_gain); } // update the effect on the listener effect slot From 4e23e3441c04fe7758878c33040efff2dd633d59 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 08:13:46 +0200 Subject: [PATCH 030/104] :triangular_ruler: Minor optimizations --- source/main/audio/SoundManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 9e58a9ca85..8a520734e2 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -382,10 +382,10 @@ void SoundManager::updateListenerEffectSlot() * Detect surfaces close to the listener and pan and delay early reflections accordingly. * Use ray casting to probe for a collision up to max_distance to each side of the listener. */ - float max_distance = 2.0f; + const float max_distance = 2.0f; const float reflections_gain_boost_max = 0.316f; // 1 db float reflections_gain; - float reflection_delay = -1.0f; + float reflection_delay; float magnitude; Ogre::Vector3 reflection_panning_direction = { 0.0f, 0.0f, 0.0f}; From 380a5fd7bc5deae33c6458253907b721058055c0 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 08:25:14 +0200 Subject: [PATCH 031/104] :sparkles: Add options for obstruction and reflection panning to settings menu --- source/main/audio/SoundManager.cpp | 2 +- source/main/gui/panels/GUI_GameSettings.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 8a520734e2..6bbc2b077c 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -141,7 +141,7 @@ SoundManager::SoundManager() } else { - LOG("SoundManager: AL_EFFECT_EAXREVERB requested but OpenAL driver does not support it, falling back to standard reverb"); + LOG("SoundManager: AL_EFFECT_EAXREVERB requested but OpenAL driver does not support it, falling back to standard reverb. Advanced features, such as reflection panning, will not be available"); efx_reverb_engine = EfxReverbEngine::REVERB; } } diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 5df18b3d11..ce70e53f9a 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -331,6 +331,13 @@ void GameSettings::DrawAudioSettings() DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); DrawGCheckbox(App::audio_enable_efx, _LC("GameSettings", "Enable advanced sound effects via OpenAL EFX")); + + if (App::audio_enable_efx->getBool()) + { + DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction (experimental)")); + DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); + } + DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); DrawGFloatSlider(App::audio_doppler_factor, _LC("GameSettings", "Doppler factor (requires restart)"), 0, 10); From 52dd97c21e99db0d8249731ce6036ddd4a69db32 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 10:00:55 +0200 Subject: [PATCH 032/104] :sparkles: Make OpenAL EFX reverb engine selectable in settings menu --- source/main/Application.cpp | 11 ++++++++ source/main/Application.h | 8 ++++++ source/main/audio/SoundManager.cpp | 4 +-- source/main/audio/SoundManager.h | 12 --------- source/main/gui/panels/GUI_GameSettings.cpp | 16 ++++++++++-- source/main/gui/panels/GUI_GameSettings.h | 1 + source/main/system/AppConfig.cpp | 28 +++++++++++++++++++++ source/main/system/CVar.cpp | 2 +- 8 files changed, 65 insertions(+), 17 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index f9229661c6..6fabefe3c1 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -553,6 +553,17 @@ std::string ToLocalizedString(IoInputGrabMode e) } } +std::string ToLocalizedString(EfxReverbEngine e) +{ + switch (e) + { + case EfxReverbEngine::NONE: return _LC("EfxReverbEngine", "None (no reverb, fastest)"); + case EfxReverbEngine::REVERB: return _LC("EfxReverbEngine", "REVERB"); + case EfxReverbEngine::EAXREVERB: return _LC("EfxReverbEngine", "EAXREVERB (more realistic effects, slower)"); + default: return ""; + } +} + std::string ToLocalizedString(SimResetMode e) { switch (e) diff --git a/source/main/Application.h b/source/main/Application.h index 68a693955a..47709fb505 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -266,6 +266,14 @@ enum class GfxSkyMode }; std::string ToLocalizedString(GfxSkyMode e); +enum class EfxReverbEngine +{ + NONE, + REVERB, + EAXREVERB, +}; +std::string ToLocalizedString(EfxReverbEngine e); + enum class IoInputGrabMode { NONE, diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 6bbc2b077c..63ee46137f 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -124,7 +124,7 @@ SoundManager::SoundManager() if (App::audio_enable_efx->getBool()) { // allow user to change reverb engines at will - switch(efx_reverb_engine_map[App::audio_efx_reverb_engine->getStr()]) + switch(App::audio_efx_reverb_engine->getEnum()) { case EfxReverbEngine::EAXREVERB: efx_reverb_engine = EfxReverbEngine::EAXREVERB; break; case EfxReverbEngine::REVERB: efx_reverb_engine = EfxReverbEngine::REVERB; break; @@ -371,7 +371,7 @@ void SoundManager::updateListenerEffectSlot() alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } - // reflection panning + // early reflections panning, delay and strength if( App::audio_enable_reflection_panning->getBool() && efx_reverb_engine == EfxReverbEngine::EAXREVERB && diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 8446db9353..e686edaeb2 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -119,22 +119,10 @@ class SoundManager bool efx_is_available = false; ALuint listener_slot = 0; ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; - - enum EfxReverbEngine - { - NONE, - REVERB, - EAXREVERB - }; EfxReverbEngine efx_reverb_engine = EfxReverbEngine::NONE; - std::string listener_efx_preset_name; std::map efx_properties_map; std::map efx_effect_id_map; - std::map efx_reverb_engine_map = - {{"EAXREVERB", EfxReverbEngine::EAXREVERB}, - {"REVERB", EfxReverbEngine::REVERB}, - {"NONE", EfxReverbEngine::NONE}}; LPALGENEFFECTS alGenEffects = nullptr; LPALDELETEEFFECTS alDeleteEffects = nullptr; LPALISEFFECT alIsEffect = nullptr; diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index ce70e53f9a..c0d82656cf 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -334,8 +334,12 @@ void GameSettings::DrawAudioSettings() if (App::audio_enable_efx->getBool()) { - DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction (experimental)")); - DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); + DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); + DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction (experimental)")); + if (App::audio_efx_reverb_engine->getEnum() == EfxReverbEngine::EAXREVERB) + { + DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); + } } DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); @@ -587,4 +591,12 @@ void GameSettings::SetVisible(bool v) ImAddItemToComboboxString(m_combo_items_input_grab, ToLocalizedString(IoInputGrabMode::DYNAMIC)); ImTerminateComboboxString(m_combo_items_input_grab); } + + if (m_combo_items_efx_reverb_engine == "") + { + ImAddItemToComboboxString(m_combo_items_efx_reverb_engine, ToLocalizedString(EfxReverbEngine::NONE)); + ImAddItemToComboboxString(m_combo_items_efx_reverb_engine, ToLocalizedString(EfxReverbEngine::REVERB)); + ImAddItemToComboboxString(m_combo_items_efx_reverb_engine, ToLocalizedString(EfxReverbEngine::EAXREVERB)); + ImTerminateComboboxString(m_combo_items_efx_reverb_engine); + } } diff --git a/source/main/gui/panels/GUI_GameSettings.h b/source/main/gui/panels/GUI_GameSettings.h index 775e939594..37b955ab53 100644 --- a/source/main/gui/panels/GUI_GameSettings.h +++ b/source/main/gui/panels/GUI_GameSettings.h @@ -63,6 +63,7 @@ class GameSettings std::string m_combo_items_water_mode; std::string m_combo_items_extcam_mode; std::string m_combo_items_input_grab; + std::string m_combo_items_efx_reverb_engine; // Render settings bool m_render_must_restart = false; diff --git a/source/main/system/AppConfig.cpp b/source/main/system/AppConfig.cpp index 655abff531..8546939c66 100644 --- a/source/main/system/AppConfig.cpp +++ b/source/main/system/AppConfig.cpp @@ -79,6 +79,10 @@ const char* CONF_SKY_CAELUM = "Caelum (best looking, slower)"; const char* CONF_SKY_SKYX = "SkyX (best looking, slower)"; const char* CONF_SKY_SANDSTORM = "Sandstorm (fastest)"; +const char* CONF_EFX_REVERB_ENGINE_EAXREVERB = "EAXREVERB (more realistic effects, slower)"; +const char* CONF_EFX_REVERB_ENGINE_REVERB = "REVERB"; +const char* CONF_EFX_REVERB_ENGINE_NONE = "None (no reverb, fastest)"; + const char* CONF_INPUT_GRAB_DYNAMIC = "Dynamically"; const char* CONF_INPUT_GRAB_NONE = "None"; const char* CONF_INPUT_GRAB_ALL = "All"; @@ -160,6 +164,14 @@ GfxSkyMode ParseGfxSkyMode(std::string const & s) else { return GfxSkyMode::SANDSTORM ; } } +EfxReverbEngine ParseEfxReverbEngine(std::string const & s) +{ + if (s == CONF_EFX_REVERB_ENGINE_EAXREVERB) { return EfxReverbEngine::EAXREVERB ; } + if (s == CONF_EFX_REVERB_ENGINE_REVERB) { return EfxReverbEngine::REVERB ; } + if (s == CONF_EFX_REVERB_ENGINE_NONE) { return EfxReverbEngine::NONE ; } + else { return EfxReverbEngine::NONE ; } +} + const char* IoInputGrabModeToStr(IoInputGrabMode v) { switch (v) @@ -267,6 +279,17 @@ const char* GfxSkyModeToStr(GfxSkyMode v) } } +const char* EfxReverbEngineToStr(EfxReverbEngine v) +{ + switch(v) + { + case EfxReverbEngine::EAXREVERB : return CONF_EFX_REVERB_ENGINE_EAXREVERB; + case EfxReverbEngine::REVERB : return CONF_EFX_REVERB_ENGINE_REVERB; + case EfxReverbEngine::NONE : return CONF_EFX_REVERB_ENGINE_NONE; + default : return ""; + } +} + // -------------------------------- // Config file parsing @@ -333,6 +356,10 @@ void ParseHelper(CVar* cvar, std::string const & val) AssignHelper(cvar, fov); } } + else if (cvar->getName() == App::audio_efx_reverb_engine->getName()) + { + AssignHelper(App::audio_efx_reverb_engine, (int)ParseEfxReverbEngine(val)); + } else { App::GetConsole()->cVarAssign(cvar, val); @@ -397,6 +424,7 @@ void WriteVarsHelper(std::stringstream& f, const char* label, const char* prefix else if (pair.second->getName() == App::gfx_water_mode->getName() ){ f << GfxWaterModeToStr (App::gfx_water_mode ->getEnum()); } else if (pair.second->getName() == App::gfx_sky_mode->getName() ){ f << GfxSkyModeToStr (App::gfx_sky_mode ->getEnum()); } else if (pair.second->getName() == App::sim_gearbox_mode->getName() ){ f << SimGearboxModeToStr(App::sim_gearbox_mode->getEnum()); } + else if (pair.second->getName() == App::audio_efx_reverb_engine->getName() ) {f << EfxReverbEngineToStr(App::audio_efx_reverb_engine->getEnum());} else { f << pair.second->getStr(); } f << std::endl; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index bbc5caf2d7..c0c5e5666d 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -160,7 +160,7 @@ void Console::cVarSetupBuiltins() App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_TYPE_BOOL, "true"); - App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE, "EAXREVERB"); + App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE | CVAR_TYPE_INT, "2"/*(int)EfxReverbEngine::EAXREVERB*/); App::audio_listener_efx_preset = this->cVarCreate("audio_listener_efx_preset", "OpenAL listener EFX preset", 0, ""); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); From 9d1ba298a6ffb2151c3979d8692781cd76791345 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 10:26:01 +0200 Subject: [PATCH 033/104] :bug: Fix calculation of magnitude for the case where there are surfaces on both sides --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 63ee46137f..b19a508f13 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -415,7 +415,7 @@ void SoundManager::updateListenerEffectSlot() reflection_delay = intersection_right.second / getSpeedOfSound(); } // take the difference in collision distance to determine the magnitude of the panning vector - magnitude = Math::Abs(intersection_left.second - intersection_right.second); + magnitude = 1.0f - Math::Abs(intersection_left.second - intersection_right.second) / max_distance; reflections_gain = std::min( (efx_properties_map[listener_efx_preset_name].flReflectionsGain + reflections_gain_boost_max From 6904fdadb0015b8dbed2b7096dd205e4352f792a Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 28 Sep 2024 21:06:28 +0200 Subject: [PATCH 034/104] :bug: Improve the collision detection for the obstruction filter The previous collision checks were incorrect due to a misunderstanding of how Rays are constructed. However, this still needs to be improved since the collision detection does not detect every object a listener would expect to obstruct a sound. --- source/main/audio/SoundManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index b19a508f13..2d1f5003c1 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -638,7 +638,9 @@ void SoundManager::recomputeAllSources() if (corresponding_sound != nullptr) { - Ray direct_path_to_sound = Ray(listener_position, corresponding_sound->getPosition()); + // no normalisation due to how the intersectsTris function determines its number of steps + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; + Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); /* From 60f196fafd001b573c03fd5e3fb7fcf2d878d75c Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 08:08:44 +0200 Subject: [PATCH 035/104] :sparkles: Add options to settings menu for overriding environmental audio controls --- source/main/gui/panels/GUI_GameSettings.cpp | 7 +++++++ source/main/gui/panels/GUI_GameSettings.h | 1 + source/main/system/CVar.cpp | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index c0d82656cf..d84b00bdff 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -340,6 +340,13 @@ void GameSettings::DrawAudioSettings() { DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); } + + DrawGCheckbox(App::audio_engine_controls_environmental_audio, _LC("GameSettings", "Engine exerts automatic control over environmental audio")); + if (!App::audio_engine_controls_environmental_audio->getBool()) + { + m_buf_audio_listener_efx_preset = App::audio_listener_efx_preset->getStr(); + DrawGTextEdit(App::audio_listener_efx_preset, _LC("GameSettings", "EFX Reverb preset to apply by default"), m_buf_audio_listener_efx_preset); + } } DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); diff --git a/source/main/gui/panels/GUI_GameSettings.h b/source/main/gui/panels/GUI_GameSettings.h index 37b955ab53..9e7d69d477 100644 --- a/source/main/gui/panels/GUI_GameSettings.h +++ b/source/main/gui/panels/GUI_GameSettings.h @@ -52,6 +52,7 @@ class GameSettings Str<1000> m_buf_diag_preset_veh_config; Str<1000> m_buf_app_extra_mod_dir; Str<1000> m_buf_io_outgauge_ip; + Str<1000> m_buf_audio_listener_efx_preset; // Pre-formatted combobox items std::string m_combo_items_gearbox_mode; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index c0c5e5666d..2ec9ccdff2 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -159,9 +159,9 @@ void Console::cVarSetupBuiltins() App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_menu_music = this->cVarCreate("audio_menu_music", "MainMenuMusic", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); - App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_TYPE_BOOL, "true"); + App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE | CVAR_TYPE_INT, "2"/*(int)EfxReverbEngine::EAXREVERB*/); - App::audio_listener_efx_preset = this->cVarCreate("audio_listener_efx_preset", "OpenAL listener EFX preset", 0, ""); + App::audio_listener_efx_preset = this->cVarCreate("audio_listener_efx_preset", "OpenAL listener EFX preset", CVAR_ARCHIVE); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From 5005f5acf220e3ef2ec66773fd56f9ae1deb0b7c Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 08:10:32 +0200 Subject: [PATCH 036/104] :wrench: Add get function for efx properties map --- source/main/audio/SoundManager.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index e686edaeb2..b89e81cc06 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -77,6 +77,12 @@ class SoundManager int getNumHardwareSources() { return hardware_sources_num; } + /** + * Returns currently registered EFX presets + * @return Map of EFX Preset names to their EFXEAXREVERBPROPERTIES object. + */ + std::map getEfxPropertiesMap() const { return efx_properties_map; } + static const float MAX_DISTANCE; static const float ROLLOFF_FACTOR; static const float REFERENCE_DISTANCE; From 8fc9ad165815c4f2cc74181bbd4af74f74a67c08 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 15:22:33 +0200 Subject: [PATCH 037/104] :wrench: Add function to check whether a ray intersects with the terrain --- source/main/physics/collision/Collisions.cpp | 18 ++++++++++++++++++ source/main/physics/collision/Collisions.h | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/source/main/physics/collision/Collisions.cpp b/source/main/physics/collision/Collisions.cpp index 991b474fe5..ba57620506 100644 --- a/source/main/physics/collision/Collisions.cpp +++ b/source/main/physics/collision/Collisions.cpp @@ -668,6 +668,24 @@ std::pair Collisions::intersectsTris(Ogre::Ray ray) return std::make_pair(false, 0.0f); } +std::pair Collisions::intersectsTerrain(Ogre::Ray ray, const Ogre::Real distance_limit, const Ogre::Real step_size) +{ + ray.setDirection(ray.getDirection().normalisedCopy()); + + for (Ogre::Real distance = Ogre::Real(0); distance < distance_limit; distance += step_size) + { + Ogre::Vector3 position = ray.getPoint(distance); + Ogre::Real terrain_height = App::GetGameContext()->GetTerrain()->GetHeightAt(position.x, position.z); + + if (terrain_height > position.y) + { + return std::make_pair(true, distance); + } + } + + return std::make_pair(false, 0.0f); +} + float Collisions::getSurfaceHeight(float x, float z) { return getSurfaceHeightBelow(x, z, std::numeric_limits::max()); diff --git a/source/main/physics/collision/Collisions.h b/source/main/physics/collision/Collisions.h index b8351e7064..ea31ba3157 100644 --- a/source/main/physics/collision/Collisions.h +++ b/source/main/physics/collision/Collisions.h @@ -179,6 +179,15 @@ class Collisions std::pair intersectsTris(Ogre::Ray ray); + /** + * Checks whether a Ray intersects the terrain. The accuracy of the results largely depends on the step_size parameter. + * @param ray The ray that is checked for an intersection with the terrain. + * @param distance_limit No intersection check is performed beyond this distance starting from the ray's origin toward its direction. + * @param step_size Defines the interval between points of the ray at which intersection checks will be performed. + * @return Pair of whether an intersection was found and the distance to the point of the intersection. + */ + std::pair intersectsTerrain(Ogre::Ray ray, Ogre::Real distance_limit, Ogre::Real step_size = Ogre::Real(0.1)); + float getSurfaceHeight(float x, float z); float getSurfaceHeightBelow(float x, float z, float height); bool collisionCorrect(Ogre::Vector3* refpos, bool envokeScriptCallbacks = true); From 7d8e1064042031b62be297d73461386e94a25099 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 15:25:54 +0200 Subject: [PATCH 038/104] :sparkles: Also apply the obstruction filter if a sound is obstructed by terrain --- source/main/audio/SoundManager.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 2d1f5003c1..77f0239531 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -638,19 +638,30 @@ void SoundManager::recomputeAllSources() if (corresponding_sound != nullptr) { + bool obstacle_detected = false; + std::pair intersection; // no normalisation due to how the intersectsTris function determines its number of steps Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); - std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); + obstacle_detected = intersection.first; + + if(!obstacle_detected) + { + // perform line of sight check against collision meshes + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + obstacle_detected = intersection.first; + } /* TODO: Also check if trucks are obstructing the sound. Trucks shouldn't obstruct their own sound sources since the obstruction is most likely already contained in the recording. - If the obstacle is the sound source's own truck, we should still check for other obstacles. */ - if(intersection.first) // sound is obstructed + if(obstacle_detected) { // Apply obstruction filter to the source alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); @@ -660,7 +671,6 @@ void SoundManager::recomputeAllSources() // reset direct filter for the source in case it has been set previously alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, AL_FILTER_NULL); } - corresponding_sound = nullptr; } } } From ca138507d8adc5da9b2fc91c6e9aa699a6db44d0 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 18:57:37 +0200 Subject: [PATCH 039/104] :wrench: Add get function for listener position --- source/main/audio/SoundManager.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index b89e81cc06..ca11154876 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -62,6 +62,11 @@ class SoundManager */ SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name = ""); + /** Returns the position vector of the listener + * @return listener position vector + */ + Ogre::Vector3 getListenerPosition() const { return listener_position; } + void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setListenerEnvironment(std::string listener_environment); void pauseAllSounds(); From c31e21b4b520f44466a3ab73098d349f61c7f4d0 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 18:58:29 +0200 Subject: [PATCH 040/104] :sparkles: Apply incar reverb preset if the listener is inside an actor --- source/main/audio/SoundScriptManager.cpp | 30 ++++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index e711afd20e..1121ca84c5 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -364,15 +364,7 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (App::audio_enable_efx->getBool()) { - if(listener_is_underwater) - { - listener_environment = "EFX_REVERB_PRESET_UNDERWATER"; - } - else - { - listener_environment = this->getReverbPresetAt(listener_position); - } - // TODO: Might want to set an in-cockpit effect when appropriate + listener_environment = this->getReverbPresetAt(listener_position); } } @@ -389,7 +381,25 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) { - // TODO: This is a stub + Ogre::Vector3 listener_position = sound_manager->getListenerPosition(); + ActorPtr actor_of_player = App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling(); + + if (actor_of_player != nullptr && + actor_of_player->ar_bounding_box.contains(listener_position)) + { + // the player is in a vehicle + // there is no reverb preset for trucks, but this seems ok + return "EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"; + } + + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + + if(listener_is_underwater) + { + return "EFX_REVERB_PRESET_UNDERWATER"; + } + return ""; } From b516f76e8b8621ec86823f3fbedff8b51050da0a Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 19:58:11 +0200 Subject: [PATCH 041/104] :wrench: Create helper function for determining if the listener is underwater --- source/main/audio/SoundScriptManager.cpp | 14 ++++++-------- source/main/audio/SoundScriptManager.h | 6 ++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 1121ca84c5..8bc2389643 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -321,6 +321,10 @@ void SoundScriptManager::update(float dt_sec) // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; this->setListener(camera_position, camera_direction, camera_up, camera_velocity); + + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + this->listener_is_underwater = (water != nullptr ? water->IsUnderWater(this->sound_manager->getListenerPosition()) : false); + this->setListenerEnvironment(camera_position); } } @@ -341,10 +345,7 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (App::audio_engine_controls_environmental_audio->getBool()) { - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); - - if(listener_is_underwater) + if(this->listenerIsUnderwater()) { sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) /* @@ -392,10 +393,7 @@ std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) return "EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"; } - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - bool listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); - - if(listener_is_underwater) + if(this->listenerIsUnderwater()) { return "EFX_REVERB_PRESET_UNDERWATER"; } diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index f4f69de3d7..fc1cdfc111 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -334,6 +334,11 @@ class SoundScriptManager : public Ogre::ScriptLoader void update(float dt_sec); + /** + * @return True if the listener position is below water level. False otherwise. + */ + bool listenerIsUnderwater() const { return listener_is_underwater; } + SoundManager* getSoundManager() { return sound_manager; } private: @@ -344,6 +349,7 @@ class SoundScriptManager : public Ogre::ScriptLoader bool disabled; bool loading_base; + bool listener_is_underwater; float max_distance; float reference_distance; float rolloff_factor; From 2ad39b5150d05bb048703fd5e45b6091b9197d5e Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 20:08:48 +0200 Subject: [PATCH 042/104] :wrench: Create helper function for checking if the listener is inside the actor coupled to the player --- source/main/audio/SoundScriptManager.cpp | 19 +++++++++++++------ source/main/audio/SoundScriptManager.h | 8 +++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 8bc2389643..fe0682ac69 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -321,9 +321,20 @@ void SoundScriptManager::update(float dt_sec) // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; this->setListener(camera_position, camera_direction, camera_up, camera_velocity); + Ogre::Vector3 listener_position = sound_manager->getListenerPosition(); const auto water = App::GetGameContext()->GetTerrain()->getWater(); - this->listener_is_underwater = (water != nullptr ? water->IsUnderWater(this->sound_manager->getListenerPosition()) : false); + this->listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + + ActorPtr actor_of_player = App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling(); + if (actor_of_player != nullptr) + { + this->listener_is_inside_the_player_coupled_actor = actor_of_player->ar_bounding_box.contains(listener_position); + } + else + { + this->listener_is_inside_the_player_coupled_actor = false; + } this->setListenerEnvironment(camera_position); } @@ -382,11 +393,7 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) { - Ogre::Vector3 listener_position = sound_manager->getListenerPosition(); - ActorPtr actor_of_player = App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling(); - - if (actor_of_player != nullptr && - actor_of_player->ar_bounding_box.contains(listener_position)) + if (this->listener_is_inside_the_player_coupled_actor) { // the player is in a vehicle // there is no reverb preset for trucks, but this seems ok diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index fc1cdfc111..f035a0461b 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -339,6 +339,11 @@ class SoundScriptManager : public Ogre::ScriptLoader */ bool listenerIsUnderwater() const { return listener_is_underwater; } + /** + * @return True if the listener position is inside the AABB of the actor the player character is coupled to. False otherwise. + */ + bool listenerIsInsideThePlayerCoupledActor() const { return listener_is_inside_the_player_coupled_actor; } + SoundManager* getSoundManager() { return sound_manager; } private: @@ -349,7 +354,8 @@ class SoundScriptManager : public Ogre::ScriptLoader bool disabled; bool loading_base; - bool listener_is_underwater; + bool listener_is_underwater = false; + bool listener_is_inside_the_player_coupled_actor = false; float max_distance; float reference_distance; float rolloff_factor; From 42afaee0f12e0411af52cc797de7a8222f8b14b9 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 29 Sep 2024 20:29:21 +0200 Subject: [PATCH 043/104] :construction: Also apply the obstruction filter if the listener is inside the player's coupled actor's BB WIP. The current implementation can cause the effect to be applied if the listener (camera) is close to but not inside the driven vehicle. --- source/main/audio/SoundManager.cpp | 50 ++++++++++++++++++------------ source/main/audio/SoundManager.h | 1 + 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 77f0239531..8cf8717908 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -638,30 +638,42 @@ void SoundManager::recomputeAllSources() if (corresponding_sound != nullptr) { - bool obstacle_detected = false; - std::pair intersection; - // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; - Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); + bool obstruction_filter_has_to_be_applied = false; - // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); - obstacle_detected = intersection.first; - - if(!obstacle_detected) + // always obstruct sounds if the player is in a vehicle + if(App::GetSoundScriptManager()->listenerIsInsideThePlayerCoupledActor()) { - // perform line of sight check against collision meshes - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstacle_detected = intersection.first; + obstruction_filter_has_to_be_applied = true; } + else + { + bool obstacle_was_detected = false; + std::pair intersection; + // no normalisation due to how the intersectsTris function determines its number of steps + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; + Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); - /* - TODO: Also check if trucks are obstructing the sound. - Trucks shouldn't obstruct their own sound sources since the obstruction is most likely - already contained in the recording. - */ + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); + obstacle_was_detected = intersection.first; + + if(!obstacle_was_detected) + { + // perform line of sight check against collision meshes + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + obstacle_was_detected = intersection.first; + } + + /* + TODO: Also check if trucks are obstructing the sound. + Trucks shouldn't obstruct their own sound sources since the obstruction is most likely + already contained in the recording. + */ + + obstruction_filter_has_to_be_applied = obstacle_was_detected; + } - if(obstacle_detected) + if(obstruction_filter_has_to_be_applied) { // Apply obstruction filter to the source alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index ca11154876..21088566cb 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -27,6 +27,7 @@ #include "Collisions.h" #include "GameContext.h" #include "Sound.h" +#include "SoundScriptManager.h" #include #include From 795f20ec634ca288ce6c31933aa3961325157da8 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Mon, 30 Sep 2024 18:43:27 +0200 Subject: [PATCH 044/104] :wrench: Move obstruction filter code to its own function --- source/main/audio/SoundManager.cpp | 131 +++++++++++++++-------------- source/main/audio/SoundManager.h | 8 ++ 2 files changed, 74 insertions(+), 65 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 8cf8717908..ced1ceda5d 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -616,75 +616,76 @@ void SoundManager::recomputeAllSources() if(App::audio_enable_obstruction->getBool()) { - /* - Check whether the source is obstructed and filter and attenuate it accordingly. - Currently, only the change in timbre of the sound is simulated. - TODO: Simulate diffraction path. - */ - - // find Sound the hardware_source belongs to - SoundPtr corresponding_sound = nullptr; - for(SoundPtr sound : audio_sources) - { - if(sound != nullptr) - { - if (sound->hardware_index == hardware_sources_num) - { - corresponding_sound = sound; - break; - } - } - } + updateObstructionFilter(hardware_sources[hardware_sources_num]); + } + } + } +} - if (corresponding_sound != nullptr) - { - bool obstruction_filter_has_to_be_applied = false; +void SoundManager::updateObstructionFilter(const ALuint hardware_source) +{ + // TODO: Simulate diffraction path. - // always obstruct sounds if the player is in a vehicle - if(App::GetSoundScriptManager()->listenerIsInsideThePlayerCoupledActor()) - { - obstruction_filter_has_to_be_applied = true; - } - else - { - bool obstacle_was_detected = false; - std::pair intersection; - // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; - Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); - - // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); - obstacle_was_detected = intersection.first; - - if(!obstacle_was_detected) - { - // perform line of sight check against collision meshes - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstacle_was_detected = intersection.first; - } - - /* - TODO: Also check if trucks are obstructing the sound. - Trucks shouldn't obstruct their own sound sources since the obstruction is most likely - already contained in the recording. - */ - - obstruction_filter_has_to_be_applied = obstacle_was_detected; - } + // find Sound the hardware_source belongs to + SoundPtr corresponding_sound = nullptr; + for(SoundPtr sound : audio_sources) + { + if(sound != nullptr) + { + if (sound->hardware_index == hardware_source) + { + corresponding_sound = sound; + break; + } + } + } - if(obstruction_filter_has_to_be_applied) - { - // Apply obstruction filter to the source - alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); - } - else - { - // reset direct filter for the source in case it has been set previously - alSourcei(hardware_sources[hardware_sources_num], AL_DIRECT_FILTER, AL_FILTER_NULL); - } - } + if (corresponding_sound != nullptr) + { + bool obstruction_filter_has_to_be_applied = false; + + // always obstruct sounds if the player is in a vehicle + if(App::GetSoundScriptManager()->listenerIsInsideThePlayerCoupledActor()) + { + obstruction_filter_has_to_be_applied = true; + } + else + { + bool obstacle_was_detected = false; + std::pair intersection; + // no normalisation due to how the intersectsTris function determines its number of steps + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; + Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); + + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); + obstacle_was_detected = intersection.first; + + if(!obstacle_was_detected) + { + // perform line of sight check against collision meshes + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + obstacle_was_detected = intersection.first; } + + /* + TODO: Also check if trucks are obstructing the sound. + Trucks shouldn't obstruct their own sound sources since the obstruction is most likely + already contained in the recording. + */ + + obstruction_filter_has_to_be_applied = obstacle_was_detected; + } + + if(obstruction_filter_has_to_be_applied) + { + // Apply obstruction filter to the source + alSourcei(hardware_source, AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); + } + else + { + // reset direct filter for the source in case it has been set previously + alSourcei(hardware_source, AL_DIRECT_FILTER, AL_FILTER_NULL); } } } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 21088566cb..35ba34ffa8 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -156,6 +156,14 @@ class SoundManager ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); void prepopulate_efx_property_map(); void updateListenerEffectSlot(); + + /** + * Applies an obstruction filter to the provided source if certain conditions apply. + * To decide whether the filter should be applied or not, the function performs + * various checks against the environment of the listener. + * @param hardware_souce The index of the hardware source. + */ + void updateObstructionFilter(const ALuint hardware_source); }; /// @} From 05dd2f5af5be9d62dca0487d23ab36013642be6c Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Mon, 30 Sep 2024 19:40:16 +0200 Subject: [PATCH 045/104] :books: Add a comment describing the obstruction checks --- source/main/audio/SoundManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index ced1ceda5d..5dd711b159 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -651,6 +651,11 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) } else { + /* + * Perform various line of sight checks until either a collision was detected + * and the filter has to be applied or no obstruction was detected. + */ + bool obstacle_was_detected = false; std::pair intersection; // no normalisation due to how the intersectsTris function determines its number of steps From 8025c5248e5faea381ae4abfe93ffe035da350ac Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 1 Oct 2024 19:15:32 +0200 Subject: [PATCH 046/104] :wrench: Only iterate over hardware source in use --- source/main/audio/SoundManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5dd711b159..4a000ac0c7 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -609,14 +609,14 @@ void SoundManager::recomputeAllSources() if(App::audio_enable_efx->getBool()) { - for(hardware_sources_num = 0; hardware_sources_num < MAX_HARDWARE_SOURCES; hardware_sources_num++) + for(int source_index = 0; source_index < hardware_sources_in_use_count; source_index++) { // update air absorption factor - alSourcef(hardware_sources[hardware_sources_num], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + alSourcef(hardware_sources[source_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); if(App::audio_enable_obstruction->getBool()) { - updateObstructionFilter(hardware_sources[hardware_sources_num]); + updateObstructionFilter(hardware_sources[source_index]); } } } From 82b19c73f859a19886ed2ebfdf4f6185ccfe6664 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 1 Oct 2024 19:27:42 +0200 Subject: [PATCH 047/104] :sparkles: Also apply the obstruction filter if a sound is obstructed by an actor I think the loop for determining whether a sound belongs to an actor or not should be put into its function. But where? Sound class? --- source/main/audio/SoundManager.cpp | 38 ++++++++++++++++++++++++++---- source/main/audio/SoundManager.h | 1 + 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 4a000ac0c7..b5d0c3b727 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -673,11 +673,39 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) obstacle_was_detected = intersection.first; } - /* - TODO: Also check if trucks are obstructing the sound. - Trucks shouldn't obstruct their own sound sources since the obstruction is most likely - already contained in the recording. - */ + // Check if an actor is obstructing the sound + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + bool soundsource_belongs_to_current_actor = false; + for(const ActorPtr actor : actors) + { + // Trucks shouldn't obstruct their own sound sources since the + // obstruction is most likely already contained in the recording. + for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) + { + const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; + const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); + for (int num_sound = 0; num_sound < num_sounds; ++num_sound) + { + if (soundsource.ssi->getSound(num_sound) == corresponding_sound) + { + soundsource_belongs_to_current_actor = true; + } + } + if (soundsource_belongs_to_current_actor) { break; } + } + + if (soundsource_belongs_to_current_actor) + { + continue; + } + + intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); + if (intersection.first) + { + obstacle_was_detected = true; + break; + } + } obstruction_filter_has_to_be_applied = obstacle_was_detected; } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 35ba34ffa8..3f19b7604a 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -23,6 +23,7 @@ #pragma once +#include "Actor.h" #include "Application.h" #include "Collisions.h" #include "GameContext.h" From 2df5cdc9008670086eaedb07857061e39376ed43 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Tue, 1 Oct 2024 21:13:41 +0200 Subject: [PATCH 048/104] :wrench: Add settings for setting a default reverb preset and a forced one The default preset applies if no other reverb preset was found for the current position of the listener. The forced preset overrides all presets regardless of the position of the listener. --- source/main/Application.cpp | 3 ++- source/main/Application.h | 3 ++- source/main/audio/SoundScriptManager.cpp | 11 ++++++----- source/main/gui/panels/GUI_GameSettings.cpp | 7 ++++--- source/main/gui/panels/GUI_GameSettings.h | 3 ++- source/main/system/CVar.cpp | 3 ++- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 6fabefe3c1..b88b192d93 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -215,7 +215,8 @@ CVar* audio_enable_reflection_panning; CVar* audio_enable_efx; CVar* audio_engine_controls_environmental_audio; CVar* audio_efx_reverb_engine; -CVar* audio_listener_efx_preset; +CVar* audio_default_listener_efx_preset; +CVar* audio_force_listener_efx_preset; CVar* audio_device_name; CVar* audio_doppler_factor; CVar* audio_menu_music; diff --git a/source/main/Application.h b/source/main/Application.h index 47709fb505..f834fec7cd 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -462,7 +462,8 @@ extern CVar* audio_enable_reflection_panning; extern CVar* audio_enable_efx; extern CVar* audio_engine_controls_environmental_audio; extern CVar* audio_efx_reverb_engine; -extern CVar* audio_listener_efx_preset; +extern CVar* audio_default_listener_efx_preset; +extern CVar* audio_force_listener_efx_preset; extern CVar* audio_device_name; extern CVar* audio_doppler_factor; extern CVar* audio_menu_music; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index fe0682ac69..602bc3cc95 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -382,10 +382,6 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (App::audio_enable_efx->getBool()) { - if (listener_environment.empty()) - { - listener_environment = App::audio_listener_efx_preset->getStr(); - } // always update the environment in case it was changed via console or script sound_manager->setListenerEnvironment(listener_environment); } @@ -393,6 +389,11 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) { + if (!App::audio_force_listener_efx_preset->getStr().empty()) + { + return App::audio_force_listener_efx_preset->getStr(); + } + if (this->listener_is_inside_the_player_coupled_actor) { // the player is in a vehicle @@ -405,7 +406,7 @@ std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) return "EFX_REVERB_PRESET_UNDERWATER"; } - return ""; + return App::audio_default_listener_efx_preset->getStr(); } void SoundScriptManager::setDopplerFactor(float doppler_factor) diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index d84b00bdff..9f0fa47f05 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -342,10 +342,11 @@ void GameSettings::DrawAudioSettings() } DrawGCheckbox(App::audio_engine_controls_environmental_audio, _LC("GameSettings", "Engine exerts automatic control over environmental audio")); - if (!App::audio_engine_controls_environmental_audio->getBool()) + + if(App::audio_engine_controls_environmental_audio) { - m_buf_audio_listener_efx_preset = App::audio_listener_efx_preset->getStr(); - DrawGTextEdit(App::audio_listener_efx_preset, _LC("GameSettings", "EFX Reverb preset to apply by default"), m_buf_audio_listener_efx_preset); + DrawGTextEdit(App::audio_default_listener_efx_preset, _LC("GameSettings", "Default EFX Reverb Preset"), m_buf_audio_default_listener_efx_preset); + DrawGTextEdit(App::audio_force_listener_efx_preset, _LC("GameSettings", "Force EFX Reverb Preset"), m_buf_audio_force_listener_efx_preset); } } diff --git a/source/main/gui/panels/GUI_GameSettings.h b/source/main/gui/panels/GUI_GameSettings.h index 9e7d69d477..c84e7671d9 100644 --- a/source/main/gui/panels/GUI_GameSettings.h +++ b/source/main/gui/panels/GUI_GameSettings.h @@ -52,7 +52,8 @@ class GameSettings Str<1000> m_buf_diag_preset_veh_config; Str<1000> m_buf_app_extra_mod_dir; Str<1000> m_buf_io_outgauge_ip; - Str<1000> m_buf_audio_listener_efx_preset; + Str<1000> m_buf_audio_default_listener_efx_preset; + Str<1000> m_buf_audio_force_listener_efx_preset; // Pre-formatted combobox items std::string m_combo_items_gearbox_mode; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 2ec9ccdff2..a1322f736e 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -161,7 +161,8 @@ void Console::cVarSetupBuiltins() App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE | CVAR_TYPE_INT, "2"/*(int)EfxReverbEngine::EAXREVERB*/); - App::audio_listener_efx_preset = this->cVarCreate("audio_listener_efx_preset", "OpenAL listener EFX preset", CVAR_ARCHIVE); + App::audio_default_listener_efx_preset = this->cVarCreate("audio_default_listener_efx_preset", "OpenAL default listener EFX preset",CVAR_ARCHIVE); + App::audio_force_listener_efx_preset = this->cVarCreate("audio_force_listener_efx_preset", "OpenAL forced listener EFX preset", CVAR_ARCHIVE); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/); From 68895d9f9d78c0cbf731c66016af12538498f3f8 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 2 Oct 2024 19:37:47 +0200 Subject: [PATCH 049/104] :wrench: Minor refactoring of the obstruction filter code --- source/main/audio/SoundManager.cpp | 66 +++++++++++++++--------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index b5d0c3b727..9fed612041 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -632,7 +632,7 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) { if(sound != nullptr) { - if (sound->hardware_index == hardware_source) + if (sound->getCurrentHardwareIndex() == hardware_source) { corresponding_sound = sound; break; @@ -642,12 +642,12 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) if (corresponding_sound != nullptr) { - bool obstruction_filter_has_to_be_applied = false; + bool obstruction_detected = false; // always obstruct sounds if the player is in a vehicle if(App::GetSoundScriptManager()->listenerIsInsideThePlayerCoupledActor()) { - obstruction_filter_has_to_be_applied = true; + obstruction_detected = true; } else { @@ -656,7 +656,6 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) * and the filter has to be applied or no obstruction was detected. */ - bool obstacle_was_detected = false; std::pair intersection; // no normalisation due to how the intersectsTris function determines its number of steps Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; @@ -664,53 +663,54 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) // perform line of sight check against terrain intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); - obstacle_was_detected = intersection.first; + obstruction_detected = intersection.first; - if(!obstacle_was_detected) + if(!obstruction_detected) { // perform line of sight check against collision meshes intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstacle_was_detected = intersection.first; + obstruction_detected = intersection.first; } - // Check if an actor is obstructing the sound - const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); - bool soundsource_belongs_to_current_actor = false; - for(const ActorPtr actor : actors) + if(!obstruction_detected) { - // Trucks shouldn't obstruct their own sound sources since the - // obstruction is most likely already contained in the recording. - for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) + // perform line of sight check against actors + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + bool soundsource_belongs_to_current_actor = false; + for(const ActorPtr actor : actors) { - const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; - const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); - for (int num_sound = 0; num_sound < num_sounds; ++num_sound) + // Trucks shouldn't obstruct their own sound sources since the + // obstruction is most likely already contained in the recording. + for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) { - if (soundsource.ssi->getSound(num_sound) == corresponding_sound) + const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; + const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); + for (int num_sound = 0; num_sound < num_sounds; ++num_sound) { - soundsource_belongs_to_current_actor = true; + if (soundsource.ssi->getSound(num_sound) == corresponding_sound) + { + soundsource_belongs_to_current_actor = true; + } } + if (soundsource_belongs_to_current_actor) { break; } } - if (soundsource_belongs_to_current_actor) { break; } - } - if (soundsource_belongs_to_current_actor) - { - continue; - } + if (soundsource_belongs_to_current_actor) + { + continue; + } - intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); - if (intersection.first) - { - obstacle_was_detected = true; - break; + intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); + obstruction_detected = intersection.first; + if (obstruction_detected) + { + break; + } } } - - obstruction_filter_has_to_be_applied = obstacle_was_detected; } - if(obstruction_filter_has_to_be_applied) + if(obstruction_detected) { // Apply obstruction filter to the source alSourcei(hardware_source, AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); From 90ec4e54961de4dc146fab8faa0a3a3960409ba8 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 3 Oct 2024 08:12:42 +0200 Subject: [PATCH 050/104] :books: Add documentation for several functions --- source/main/audio/SoundManager.h | 85 +++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 3f19b7604a..d09f0d32f1 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -70,18 +70,60 @@ class SoundManager Ogre::Vector3 getListenerPosition() const { return listener_position; } void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + + /** + * Updates the EFX/EAX reverb preset that is used as a base for updating the listener's effect slot. + * @param listener_environment The preset that will be used for the listener environment. + * @see updateListenerEffectSlot() + */ void setListenerEnvironment(std::string listener_environment); + + /** + * Unlike the name suggests, this sets the listener's gain to 0, essentially muting all sounds. + */ void pauseAllSounds(); + + /** + * Unlike the name suggests, this sets the listener's gain to the value of the CVar audio_master_volume. + */ void resumeAllSounds(); + + /** + * Updates both CVar audio_master_volume and the listener's gain to the provided value. + * @param v Volume within the range of AL_GAIN. + */ void setMasterVolume(float v); bool isDisabled() { return audio_device == 0; } + /** + * @return The value of AL_SPEED_OF_SOUND as currently set in OpenAL. + */ float getSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + + /** + * Updates the speed of sound in OpenAL with the provided value. + * This value should based on RoR units for correct results. + * @param speed_of_sound Speed of sound within the range of AL_SPEED_OF_SOUND. + */ void setSpeedOfSound(float speed_of_sound) { alSpeedOfSound(speed_of_sound); } + + /** + * @return The value of AL_DOPPLER_FACTOR as currently set in OpenAL. + */ float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } + + /** + * Updates the doppler factor in OpenAL with the provided value. + * @param doppler_factor Doppler factor within the range of AL_DOPPLER_FACTOR. + */ void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } + /** + * Returns the number of currently used hardware sources. In a typical scenario, + * this value changes dynamically. + * @return The number of hardware sources currently in use. + */ int getNumHardwareSources() { return hardware_sources_num; } /** @@ -98,10 +140,35 @@ class SoundManager private: void recomputeAllSources(); + + /** + * Computes audibility of an audio source and retires it if it is inaudible. Otherwise, it updates + * its state (e.g. play/stop) if it is already assigned to a hardware source. If it was not assigned + * to a hardware source yet, it will either be assigned to a free slot or replace a less audible + * source, if one exists. + * @see assign() + * @see retire() + */ void recomputeSource(int source_index, int reason, float vfl, Ogre::Vector3 *vvec); + + /** + * Returns the AL handle for the hardware source with the provided index. + * @param hardware_index Index of the hardware source. + * @return The AL handle for the requested hardware source. + */ ALuint getHardwareSource(int hardware_index) { return hardware_sources[hardware_index]; }; + /** + * Adds an audio source to hardware source. + * @param source_index Index of the audio source. + * @param hardware_index Index of the hardware source to which the audio source will be assigned. + */ void assign(int source_index, int hardware_index); + + /** + * Stops and the removes an audio source from hardware source. + * @param source_index The index of the audio source. + */ void retire(int source_index); bool loadWAVFile(Ogre::String filename, ALuint buffer, Ogre::String resource_group_name = ""); @@ -116,7 +183,7 @@ class SoundManager SoundPtr audio_sources[MAX_AUDIO_BUFFERS] = { nullptr }; // helper for calculating the most audible sources std::pair audio_sources_most_audible[MAX_AUDIO_BUFFERS]; - + // audio buffers: Array of AL buffers and filenames int audio_buffers_in_use_count = 0; ALuint audio_buffers[MAX_AUDIO_BUFFERS]; @@ -154,8 +221,24 @@ class SoundManager LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf = nullptr; LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv = nullptr; + /** + * Creates an OpenAL effect based on the parameters of an efx/eax reverb preset. + * @param efx_properties Pointer to a struct holding the parameters of the reverb preset. + */ ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); + + /** + * Helper function that fills the efx_properties_map with presets provided by + * OpenAL's efx-presets.h header. + */ void prepopulate_efx_property_map(); + + /** + * Dynamically adjusts some parameters of the currently active reverb preset based + * on the current environment of the listener. It works on the AL effect correspondig + * to a reverb preset, i.e. the original preset in efx_properties_map remains unchanged. + * Finally, it updates the AL listener's effect slot with the adjusted preset. + */ void updateListenerEffectSlot(); /** From 3b7c291a864e39118684639e3ca56b088d34591b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 3 Oct 2024 09:08:22 +0200 Subject: [PATCH 051/104] :wrench: Split the setListener function into several functions Previously, the setListener function was more similar to an update function since it did more than just setting the listener vectors --- source/main/audio/SoundManager.cpp | 40 +++++++++++++++--------- source/main/audio/SoundManager.h | 19 +++++++++++ source/main/audio/SoundScriptManager.cpp | 1 + 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 9fed612041..bcdfe48aa0 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -307,33 +307,43 @@ void SoundManager::prepopulate_efx_property_map() this->efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; } -void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) +void SoundManager::update() { if (!audio_device) return; + + recomputeAllSources(); + updateAlListener(); + + if(App::audio_enable_efx->getBool()) + { + this->updateListenerEffectSlot(); + } +} + +void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) +{ listener_position = position; listener_direction = direction; listener_up = up; - recomputeAllSources(); + listener_velocity = velocity; +} +void SoundManager::updateAlListener() +{ float orientation[6]; // direction - orientation[0] = direction.x; - orientation[1] = direction.y; - orientation[2] = direction.z; + orientation[0] = listener_direction.x; + orientation[1] = listener_direction.y; + orientation[2] = listener_direction.z; // up - orientation[3] = up.x; - orientation[4] = up.y; - orientation[5] = up.z; + orientation[3] = listener_up.x; + orientation[4] = listener_up.y; + orientation[5] = listener_up.z; - alListener3f(AL_POSITION, position.x, position.y, position.z); - alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); + alListener3f(AL_POSITION, listener_position.x, listener_position.y, listener_position.z); + alListener3f(AL_VELOCITY, listener_velocity.x, listener_velocity.y, listener_velocity.z); alListenerfv(AL_ORIENTATION, orientation); - - if(App::audio_enable_efx->getBool()) - { - this->updateListenerEffectSlot(); - } } void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index d09f0d32f1..95701e348b 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -69,6 +69,19 @@ class SoundManager */ Ogre::Vector3 getListenerPosition() const { return listener_position; } + /** + * Does the per-frame update of sounds and listener environment. With the help of other functions it + * determines and then submits the current state of the audio world to OpenAL. + */ + void update(); + + /** + * Sets position and speed of the listener + * @param position The position of the listener. + * @param direction This direction vector specifies where the front of the listener is pointing to. + * @param up This direction vector specifies where the top of the head of the listener is pointing to. + * @param velocity The movement speed of the listener in each dimension. + */ void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); /** @@ -139,6 +152,11 @@ class SoundManager static const unsigned int MAX_AUDIO_BUFFERS = 8192; private: + /** + * Updates the listener's position, orientation and velocity vectors in OpenAL. + * @see setListener() + */ + void updateAlListener(); void recomputeAllSources(); /** @@ -192,6 +210,7 @@ class SoundManager Ogre::Vector3 listener_position = Ogre::Vector3::ZERO; Ogre::Vector3 listener_direction = Ogre::Vector3::ZERO; Ogre::Vector3 listener_up = Ogre::Vector3::ZERO; + Ogre::Vector3 listener_velocity = Ogre::Vector3::ZERO; ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 602bc3cc95..6cb0376c21 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -337,6 +337,7 @@ void SoundScriptManager::update(float dt_sec) } this->setListenerEnvironment(camera_position); + sound_manager->update(); } } From d762a6cad6b723711ec21ae4fcc9914d396fd571 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 3 Oct 2024 09:14:16 +0200 Subject: [PATCH 052/104] :wrench: Move the source filtering code to the update() function --- source/main/audio/SoundManager.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index bcdfe48aa0..79f7d0f01c 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -317,7 +317,19 @@ void SoundManager::update() if(App::audio_enable_efx->getBool()) { - this->updateListenerEffectSlot(); + // apply filters to sources when appropriate + for(int source_index = 0; source_index < hardware_sources_in_use_count; source_index++) + { + // update air absorption factor + alSourcef(hardware_sources[source_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + + if(App::audio_enable_obstruction->getBool()) + { + updateObstructionFilter(hardware_sources[source_index]); + } + } + + updateListenerEffectSlot(); } } @@ -616,20 +628,6 @@ void SoundManager::recomputeAllSources() } } #endif - - if(App::audio_enable_efx->getBool()) - { - for(int source_index = 0; source_index < hardware_sources_in_use_count; source_index++) - { - // update air absorption factor - alSourcef(hardware_sources[source_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); - - if(App::audio_enable_obstruction->getBool()) - { - updateObstructionFilter(hardware_sources[source_index]); - } - } - } } void SoundManager::updateObstructionFilter(const ALuint hardware_source) From 1bff42dee49e3a74face47a1d2e7898125140b2e Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Thu, 3 Oct 2024 14:20:08 +0200 Subject: [PATCH 053/104] :sparkles: Also apply the obstruction filter if a sound is obstructed by a collision box --- source/main/audio/SoundManager.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 79f7d0f01c..b8bea30467 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -667,19 +667,42 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) std::pair intersection; // no normalisation due to how the intersectsTris function determines its number of steps Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; + Ogre::Real distance_to_sound = direction_to_sound.length(); Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, Ogre::Real(direction_to_sound.length())); + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); obstruction_detected = intersection.first; if(!obstruction_detected) { // perform line of sight check against collision meshes + // for this to work correctly, the direction vector of the ray must have + // the length of the distance from the listener to the sound intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); obstruction_detected = intersection.first; } + // do not normalise before intersectsTris() due to how that function works + direction_to_sound.normalise(); + direct_path_to_sound.setDirection(direction_to_sound); + + if(!obstruction_detected) + { + // perform line of sight check agains collision boxes + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + { + if (!collision_box.enabled || collision_box.virt) { continue; } + + intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); + if (intersection.first && intersection.second <= distance_to_sound) + { + obstruction_detected = true; + break; + } + } + } + if(!obstruction_detected) { // perform line of sight check against actors From 6d27bb249bb2cc0a26fad5f6d58ed5f7de700f00 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 5 Oct 2024 13:34:45 +0200 Subject: [PATCH 054/104] :wrench: Add Get function for CELL_SIZE --- source/main/physics/collision/Collisions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/main/physics/collision/Collisions.h b/source/main/physics/collision/Collisions.h index ea31ba3157..0676711a97 100644 --- a/source/main/physics/collision/Collisions.h +++ b/source/main/physics/collision/Collisions.h @@ -176,6 +176,7 @@ class Collisions Ogre::Vector3 getPosition(const Ogre::String& inst, const Ogre::String& box); Ogre::Quaternion getDirection(const Ogre::String& inst, const Ogre::String& box); collision_box_t* getBox(const Ogre::String& inst, const Ogre::String& box); + const int GetCellSize() const { return CELL_SIZE; } std::pair intersectsTris(Ogre::Ray ray); From dc325776613bbb52205a70ef469e02b986cb1f29 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 5 Oct 2024 13:43:26 +0200 Subject: [PATCH 055/104] :construction: Improve algorithm for early reflections panning Still missing: better collision detection, smooth panning, vertical raycasts --- source/main/audio/SoundManager.cpp | 195 ++++++++++++++--------------- source/main/audio/SoundManager.h | 8 ++ 2 files changed, 100 insertions(+), 103 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index b8bea30467..ce78132740 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -394,119 +394,108 @@ void SoundManager::updateListenerEffectSlot() } // early reflections panning, delay and strength - if( - App::audio_enable_reflection_panning->getBool() && - efx_reverb_engine == EfxReverbEngine::EAXREVERB && - App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu - ) + if ( + App::audio_enable_reflection_panning->getBool() && + efx_reverb_engine == EfxReverbEngine::EAXREVERB && + App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu + ) { - /* - * Detect surfaces close to the listener and pan and delay early reflections accordingly. - * Use ray casting to probe for a collision up to max_distance to each side of the listener. - */ - const float max_distance = 2.0f; - const float reflections_gain_boost_max = 0.316f; // 1 db - float reflections_gain; - float reflection_delay; - float magnitude; - - Ogre::Vector3 reflection_panning_direction = { 0.0f, 0.0f, 0.0f}; - Ogre::Vector3 left = listener_position - listener_direction.crossProduct(listener_up).normalisedCopy() * max_distance; - Ogre::Vector3 right = listener_position + listener_direction.crossProduct(listener_up).normalisedCopy() * max_distance; - - Ray left_side = Ray(listener_position, left); - Ray right_side = Ray(listener_position, right); - - std::pair intersection_left = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(left_side); - std::pair intersection_right = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(right_side); - - // there is a nearby surface on both sides - if (intersection_left.first && intersection_right.first) - { - // pan toward the closer object - if (intersection_left.second < intersection_right.second) - { - reflection_panning_direction = left; - magnitude = 1.0f - intersection_left.second / max_distance; - reflection_delay = intersection_left.second / getSpeedOfSound(); - } - else - { - reflection_panning_direction = right; - magnitude = 1.0f - intersection_right.second / max_distance; - reflection_delay = intersection_right.second / getSpeedOfSound(); - } - // take the difference in collision distance to determine the magnitude of the panning vector - magnitude = 1.0f - Math::Abs(intersection_left.second - intersection_right.second) / max_distance; - reflections_gain = std::min( - (efx_properties_map[listener_efx_preset_name].flReflectionsGain - + reflections_gain_boost_max - - (reflections_gain_boost_max * magnitude)), - 3.16f); - } - else if (intersection_left.first) // there is a nearby surface on the left side - { - reflection_panning_direction = left; - magnitude = 1.0f - intersection_left.second / max_distance; - reflection_delay = intersection_left.second / getSpeedOfSound(); - reflections_gain = std::min( - (efx_properties_map[listener_efx_preset_name].flReflectionsGain - + reflections_gain_boost_max - - (reflections_gain_boost_max * magnitude)), - 3.16f); - } - else if (intersection_right.first) // there is a nearby surface on the right side - { - reflection_panning_direction = right; - magnitude = 1.0f - intersection_right.second / max_distance; - reflection_delay = intersection_right.second / getSpeedOfSound(); - reflections_gain = std::min( - (efx_properties_map[listener_efx_preset_name].flReflectionsGain - + reflections_gain_boost_max - - (reflections_gain_boost_max * magnitude)), - 3.16f); - } - else // no nearby surface detected - { - // reset values to the original of the preset since there are no nearby surfaces - reflection_delay = efx_properties_map[listener_efx_preset_name].flReflectionsDelay; - reflections_gain = efx_properties_map[listener_efx_preset_name].flReflectionsGain; - } + const std::tuple early_reflections_properties = + calculateEarlyReflectionsProperties(); + + // convert panning vector to EAXREVERB's LHS + const float eaxreverb_early_reflections_pan[3] = + { std::get<0>(early_reflections_properties).x, + 0, // TODO + -std::get<0>(early_reflections_properties).z }; + + alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(early_reflections_properties)); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(early_reflections_properties)); + } - // transform reflection_panning_direction vector to listener-relative EAXREVERB reflection-panning vector - // invert z since EAXREVERB panning vectors use a left-handed coordinate system + // update the effect on the listener effect slot + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); + } +} - // determine the angle between listener_direction and straight ahead vector (0, 0, 1) - float angle = std::acos(-listener_direction.z); +std::tuple SoundManager::calculateEarlyReflectionsProperties() +{ + const float max_distance = 2.0f; + const float reflections_gain_boost_max = 2.0f; // 6.32 db + float early_reflections_gain; + float early_reflections_delay; + float magnitude = 0; + Ogre::Vector3 early_reflections_pan = { 0.0f, 0.0f, 0.0f}; + + /* + * To detect surfaces around the listener within the vicinity of + * max_distance, we cast rays counter-clockwise in a 360° circle + * around the listener on a horizontal plane realative to the listener. + */ + bool nearby_surface_detected = false; + const float angle_step_size = 90; + float closest_surface_distance = std::numeric_limits::max(); + + for (float angle = 0; angle < 360; angle += angle_step_size) + { + Ogre::Vector3 raycast_direction = Quaternion(Ogre::Degree(angle), listener_up) * listener_direction; + raycast_direction.normalise(); + // accompany direction vector for how the intersectsTris function works + Ray ray = Ray(listener_position, raycast_direction * max_distance * App::GetGameContext()->GetTerrain()->GetCollisions()->GetCellSize()); + std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(ray); - if (listener_direction.x < 0) - { - angle = -angle; - } + if (intersection.first) + { + nearby_surface_detected = true; + early_reflections_pan += raycast_direction * max_distance * intersection.second; + closest_surface_distance = std::min(intersection.second, closest_surface_distance); + } + } - // inversely rotate reflection_panning_vector by the angle - Ogre::Vector3 reflection_panning_vector = - {(reflection_panning_direction.x * std::cos(-angle)) + (reflection_panning_direction.z * std::sin(-angle)), - 0, - -(reflection_panning_direction.x * -std::sin(-angle)) + (reflection_panning_direction.z * std::cos(-angle))}; + // TODO vertical raycasts - // scale panning vector based on the distance to the collision - // we assume that surfaces further away cause less focussed reflections - reflection_panning_vector *= magnitude; + if (!nearby_surface_detected) + { + // reset values to the original values of the preset + early_reflections_delay = efx_properties_map[listener_efx_preset_name].flReflectionsDelay; + early_reflections_gain = efx_properties_map[listener_efx_preset_name].flReflectionsGain; + } + else // at least one nearby surface was detected + { + // we assume that surfaces further away cause less focussed reflections + magnitude = 1.0f - early_reflections_pan.length() / max_distance; - float eaxreverb_reflection_panning_vector[3] = - { reflection_panning_vector.x, - reflection_panning_vector.y, - -reflection_panning_vector.z }; + // set delay based on distance to the closest surface + early_reflections_delay = closest_surface_distance / getSpeedOfSound(); - alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_reflection_panning_vector); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, reflection_delay); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, reflections_gain); - } + early_reflections_gain = std::min( + (efx_properties_map[listener_efx_preset_name].flReflectionsGain + + reflections_gain_boost_max + - (reflections_gain_boost_max * (1.0f - magnitude))), + AL_EAXREVERB_MAX_REFLECTIONS_GAIN); + } - // update the effect on the listener effect slot - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); + // transform the pan vector from being listener-relative to being user-relative + + // determine the rotation of the listener direction from straight-ahead vector + // work around Quaternion quirks at around 180° rotation + Ogre::Quaternion horizontal_rotation; + if (listener_direction.z > 0.0f) + { + horizontal_rotation = Quaternion(Ogre::Degree(180), listener_up) * listener_direction.getRotationTo(Ogre::Vector3::UNIT_Z); + } + else + { + horizontal_rotation = listener_direction.getRotationTo(Ogre::Vector3::NEGATIVE_UNIT_Z); } + + early_reflections_pan = horizontal_rotation * early_reflections_pan; + early_reflections_pan.normalise(); + + early_reflections_pan = magnitude * early_reflections_pan; + + return std::make_tuple(early_reflections_pan, early_reflections_gain, early_reflections_delay); } ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 95701e348b..5c46172622 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -260,6 +260,14 @@ class SoundManager */ void updateListenerEffectSlot(); + /** + * Detects surfaces close to the listener and calculates a user-relative (as opposed to listener-relative) + * panning vector for early reflections as well as gain and delay values for early reflections based + * on surface distance. + * @return A tuple of user-relative panning vector, gain and delay for early reflections + */ + std::tuple calculateEarlyReflectionsProperties(); + /** * Applies an obstruction filter to the provided source if certain conditions apply. * To decide whether the filter should be applied or not, the function performs From 5bd3418ac3852b6f4289f1b435f7187d9d19cefa Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 5 Oct 2024 19:43:10 +0200 Subject: [PATCH 056/104] :bugfix: Fix calculation of magnitude Previously it was possible that magnitude was negative, which caused errors in OpenAL. --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index ce78132740..85ae37a487 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -464,7 +464,7 @@ std::tuple SoundManager::calculateEarlyReflectionsP else // at least one nearby surface was detected { // we assume that surfaces further away cause less focussed reflections - magnitude = 1.0f - early_reflections_pan.length() / max_distance; + magnitude = 1.0f - early_reflections_pan.length() / Ogre::Math::Sqrt(2.0f * Ogre::Math::Pow(max_distance, 2)); // set delay based on distance to the closest surface early_reflections_delay = closest_surface_distance / getSpeedOfSound(); From 44a04afebad2da4b9119c429a128502fe0778039 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 5 Oct 2024 20:08:34 +0200 Subject: [PATCH 057/104] :construction: Implement smooth updates of early reflections properties --- source/main/audio/SoundManager.cpp | 51 +++++++++++++++++++----- source/main/audio/SoundManager.h | 6 ++- source/main/audio/SoundScriptManager.cpp | 2 +- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 85ae37a487..db7237dca6 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -307,7 +307,7 @@ void SoundManager::prepopulate_efx_property_map() this->efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; } -void SoundManager::update() +void SoundManager::update(const float dt_sec) { if (!audio_device) return; @@ -329,7 +329,7 @@ void SoundManager::update() } } - updateListenerEffectSlot(); + updateListenerEffectSlot(dt_sec); } } @@ -369,7 +369,7 @@ void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) this->listener_efx_preset_name = listener_efx_preset_name; } -void SoundManager::updateListenerEffectSlot() +void SoundManager::updateListenerEffectSlot(const float dt_sec) { if (listener_efx_preset_name.empty()) { @@ -400,18 +400,49 @@ void SoundManager::updateListenerEffectSlot() App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu ) { - const std::tuple early_reflections_properties = - calculateEarlyReflectionsProperties(); + // smoothly pan from the current properties to the target properties over several timesteps (frames) + const float time_to_target = 0.100f; // seconds to reach the target properties from the current properties + const float step = dt_sec / time_to_target; + static std::tuple target_early_reflections_properties; + static std::tuple current_early_reflections_properties = + std::make_tuple(Ogre::Vector3(efx_properties_map[listener_efx_preset_name].flReflectionsPan[0], + efx_properties_map[listener_efx_preset_name].flReflectionsPan[1], + efx_properties_map[listener_efx_preset_name].flReflectionsPan[2]), + efx_properties_map[listener_efx_preset_name].flReflectionsGain, + efx_properties_map[listener_efx_preset_name].flReflectionsDelay); + + target_early_reflections_properties = calculateEarlyReflectionsProperties(); + + const Ogre::Vector3 current_early_reflections_pan = + std::get<0>(current_early_reflections_properties) + + step * ( std::get<0>(target_early_reflections_properties) + - std::get<0>(current_early_reflections_properties)); + + const float current_early_reflections_gain = + std::get<1>(current_early_reflections_properties) + + step * ( std::get<1>(target_early_reflections_properties) + - std::get<1>(current_early_reflections_properties)); + + const float current_early_reflections_delay = + std::get<2>(current_early_reflections_properties) + + step * ( std::get<2>(target_early_reflections_properties) + - std::get<2>(current_early_reflections_properties)); + + current_early_reflections_properties = + std::make_tuple(Ogre::Vector3(current_early_reflections_pan.x, + current_early_reflections_pan.y, + current_early_reflections_pan.z), + current_early_reflections_gain, + current_early_reflections_delay); // convert panning vector to EAXREVERB's LHS const float eaxreverb_early_reflections_pan[3] = - { std::get<0>(early_reflections_properties).x, + { current_early_reflections_pan.x, 0, // TODO - -std::get<0>(early_reflections_properties).z }; - + -current_early_reflections_pan.z }; alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(early_reflections_properties)); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(early_reflections_properties)); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); + alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); } // update the effect on the listener effect slot diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 5c46172622..668ea46501 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -72,8 +72,9 @@ class SoundManager /** * Does the per-frame update of sounds and listener environment. With the help of other functions it * determines and then submits the current state of the audio world to OpenAL. + * @param dt_sec Time since last frame in seconds */ - void update(); + void update(const float dt_sec); /** * Sets position and speed of the listener @@ -257,8 +258,9 @@ class SoundManager * on the current environment of the listener. It works on the AL effect correspondig * to a reverb preset, i.e. the original preset in efx_properties_map remains unchanged. * Finally, it updates the AL listener's effect slot with the adjusted preset. + * @param dt_sec Time since last frame in seconds */ - void updateListenerEffectSlot(); + void updateListenerEffectSlot(const float dt_sec); /** * Detects surfaces close to the listener and calculates a user-relative (as opposed to listener-relative) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 6cb0376c21..1a5c840e39 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -337,7 +337,7 @@ void SoundScriptManager::update(float dt_sec) } this->setListenerEnvironment(camera_position); - sound_manager->update(); + sound_manager->update(dt_sec); } } From 46f1160c93f204cf611a9cf96cc376a4e31663a7 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 6 Oct 2024 08:19:00 +0200 Subject: [PATCH 058/104] :triangular_ruler: Add const qualifier at several places --- source/main/audio/SoundManager.cpp | 4 ++-- source/main/audio/SoundManager.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index db7237dca6..01bd6d1195 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -529,7 +529,7 @@ std::tuple SoundManager::calculateEarlyReflectionsP return std::make_tuple(early_reflections_pan, early_reflections_gain, early_reflections_delay); } -ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) +ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const { ALuint effect = 0; ALenum error; @@ -650,7 +650,7 @@ void SoundManager::recomputeAllSources() #endif } -void SoundManager::updateObstructionFilter(const ALuint hardware_source) +void SoundManager::updateObstructionFilter(const ALuint hardware_source) const { // TODO: Simulate diffraction path. diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 668ea46501..5dca033640 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -113,25 +113,25 @@ class SoundManager /** * @return The value of AL_SPEED_OF_SOUND as currently set in OpenAL. */ - float getSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + float getSpeedOfSound() const { return alGetFloat(AL_SPEED_OF_SOUND); } /** * Updates the speed of sound in OpenAL with the provided value. * This value should based on RoR units for correct results. * @param speed_of_sound Speed of sound within the range of AL_SPEED_OF_SOUND. */ - void setSpeedOfSound(float speed_of_sound) { alSpeedOfSound(speed_of_sound); } + void setSpeedOfSound(const float speed_of_sound) const { alSpeedOfSound(speed_of_sound); } /** * @return The value of AL_DOPPLER_FACTOR as currently set in OpenAL. */ - float getDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } + float getDopplerFactor() const { return alGetFloat(AL_DOPPLER_FACTOR); } /** * Updates the doppler factor in OpenAL with the provided value. * @param doppler_factor Doppler factor within the range of AL_DOPPLER_FACTOR. */ - void setDopplerFactor(float doppler_factor) { alDopplerFactor(doppler_factor); } + void setDopplerFactor(const float doppler_factor) const { alDopplerFactor(doppler_factor); } /** * Returns the number of currently used hardware sources. In a typical scenario, @@ -245,7 +245,7 @@ class SoundManager * Creates an OpenAL effect based on the parameters of an efx/eax reverb preset. * @param efx_properties Pointer to a struct holding the parameters of the reverb preset. */ - ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties); + ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const; /** * Helper function that fills the efx_properties_map with presets provided by @@ -276,7 +276,7 @@ class SoundManager * various checks against the environment of the listener. * @param hardware_souce The index of the hardware source. */ - void updateObstructionFilter(const ALuint hardware_source); + void updateObstructionFilter(const ALuint hardware_source) const; }; /// @} From 7532b23c663da62a0e7547e93ecdf3fc8e409704 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 6 Oct 2024 11:35:48 +0200 Subject: [PATCH 059/104] :triangular_ruler: Use const reference instead of pointer --- source/main/audio/SoundManager.cpp | 79 +++++++++++++++--------------- source/main/audio/SoundManager.h | 5 +- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 01bd6d1195..ac9fca7562 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -380,7 +380,7 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) // create new effect if not existing if(!listener_efx_preset_name.empty() && efx_effect_id_map.find(listener_efx_preset_name) == efx_effect_id_map.end()) { - efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(&this->efx_properties_map[listener_efx_preset_name]); + efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(efx_properties_map[listener_efx_preset_name]); } // update air absorption gain hf of effect @@ -529,7 +529,7 @@ std::tuple SoundManager::calculateEarlyReflectionsP return std::make_tuple(early_reflections_pan, early_reflections_gain, early_reflections_delay); } -ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const +ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties) const { ALuint effect = 0; ALenum error; @@ -540,48 +540,49 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties { case EfxReverbEngine::EAXREVERB: alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - - alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); - alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); - alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); - alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); - alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); - alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); - alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); - alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); - alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); - alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); - alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); - alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); - alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); - alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties.flGain); + + alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties.flDensity); + alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties.flDiffusion); + alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties.flGain); + alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties.flGainHF); + alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties.flGainLF); + alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties.flDecayTime); + alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties.flDecayHFRatio); + alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties.flDecayLFRatio); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties.flReflectionsGain); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties.flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties.flReflectionsPan); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties.flLateReverbGain); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties.flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties.flLateReverbPan); + alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties.flEchoTime); + alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties.flEchoDepth); + alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties.flModulationTime); + alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties.flModulationDepth); + alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties.flAirAbsorptionGainHF); + alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties.flHFReference); + alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties.flLFReference); + alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties.flRoomRolloffFactor); + alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties.iDecayHFLimit); break; case EfxReverbEngine::REVERB: alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); - alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); - alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); - alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); - alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); - alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + alEffectf(effect, AL_REVERB_DENSITY, efx_properties.flDensity); + alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties.flDiffusion); + alEffectf(effect, AL_REVERB_GAIN, efx_properties.flGain); + alEffectf(effect, AL_REVERB_GAINHF, efx_properties.flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties.flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties.flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties.flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties.flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties.flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties.flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties.flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties.flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties.iDecayHFLimit); break; case EfxReverbEngine::NONE: diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 5dca033640..2176a8961a 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -243,9 +243,10 @@ class SoundManager /** * Creates an OpenAL effect based on the parameters of an efx/eax reverb preset. - * @param efx_properties Pointer to a struct holding the parameters of the reverb preset. + * @param efx_properties EFXEAXREVERBPROPERTIES object holding the parameters of the reverb preset. + * @see `AL/efx-presets.h` from OpenAL */ - ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const; + ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties) const; /** * Helper function that fills the efx_properties_map with presets provided by From 8bc2c5fa2f4ef48e40691e4efac913b75d412b4e Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 18 Oct 2024 17:38:15 +0200 Subject: [PATCH 060/104] :bug: Fix overshooting on smooth early reflections properties updates when framestep is too large This was easily triggered when returning from a terrain to the main menu, waiting a bit and then loading a terrain. It could cause some early reflections properties values to be out of range after the smooth update due to overshooting too much. --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index ac9fca7562..5075956d70 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -402,7 +402,7 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) { // smoothly pan from the current properties to the target properties over several timesteps (frames) const float time_to_target = 0.100f; // seconds to reach the target properties from the current properties - const float step = dt_sec / time_to_target; + const float step = std::min(dt_sec / time_to_target, 1.0f); static std::tuple target_early_reflections_properties; static std::tuple current_early_reflections_properties = std::make_tuple(Ogre::Vector3(efx_properties_map[listener_efx_preset_name].flReflectionsPan[0], From 3f45dc154a1103caa2236b5169f088e5dcda6a92 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 18 Oct 2024 19:30:59 +0200 Subject: [PATCH 061/104] :wrench: Optimize passing around EFX reverb properties --- source/main/audio/SoundManager.cpp | 186 ++++++++++++++--------- source/main/audio/SoundManager.h | 31 +++- source/main/audio/SoundScriptManager.cpp | 16 +- source/main/audio/SoundScriptManager.h | 13 +- source/main/main.cpp | 1 + 5 files changed, 161 insertions(+), 86 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5075956d70..4561d8eb38 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -238,19 +238,16 @@ SoundManager::~SoundManager() alDeleteFilters(1, &efx_outdoor_obstruction_lowpass_filter_id); } - for (auto const& efx_effect_id : efx_effect_id_map) - { - alDeleteEffects(1, &efx_effect_id.second); - } - if (alIsAuxiliaryEffectSlot(listener_slot)) { alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); alDeleteAuxiliaryEffectSlots(1, &listener_slot); - listener_slot = AL_EFFECTSLOT_NULL; + listener_slot = 0; } } + CleanUp(); + // destroy the sound context and device sound_context = alcGetCurrentContext(); audio_device = alcGetContextsDevice(sound_context); @@ -263,6 +260,38 @@ SoundManager::~SoundManager() LOG("SoundManager destroyed."); } +void SoundManager::CleanUp() +{ + if(efx_is_available) + { + listener_efx_reverb_properties = nullptr; + if (alIsAuxiliaryEffectSlot(listener_slot)) + { + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + } + + for (const auto& entry : efx_effect_id_map) + { + DeleteAlEffect(entry.second); + efx_effect_id_map.erase(entry.first); + } + } +} + +const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& efx_preset_name) const +{ + const auto it = efx_properties_map.find(efx_preset_name); + + if (it != efx_properties_map.end()) + { + return &it->second; + } + else + { + return nullptr; + } +} + void SoundManager::prepopulate_efx_property_map() { this->efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; @@ -358,39 +387,40 @@ void SoundManager::updateAlListener() alListenerfv(AL_ORIENTATION, orientation); } -void SoundManager::setListenerEnvironment(std::string listener_efx_preset_name) +void SoundManager::setListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_reverb_properties) { - if(efx_properties_map.find(listener_efx_preset_name) == efx_properties_map.end()) - { - // LOG("SoundManager: EFX preset `" + listener_efx_preset_name + "` is not available"); - listener_efx_preset_name = ""; // force that no preset is active - } - - this->listener_efx_preset_name = listener_efx_preset_name; + this->listener_efx_reverb_properties = listener_reverb_properties; } void SoundManager::updateListenerEffectSlot(const float dt_sec) { - if (listener_efx_preset_name.empty()) + if (listener_efx_reverb_properties == nullptr) { alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); } else { + ALuint efx_effect_id; + // create new effect if not existing - if(!listener_efx_preset_name.empty() && efx_effect_id_map.find(listener_efx_preset_name) == efx_effect_id_map.end()) + if(efx_effect_id_map.find(listener_efx_reverb_properties) == efx_effect_id_map.end()) + { + efx_effect_id = CreateAlEffect(listener_efx_reverb_properties); + efx_effect_id_map[listener_efx_reverb_properties] = efx_effect_id; + } + else { - efx_effect_id_map[listener_efx_preset_name] = this->CreateAlEffect(efx_properties_map[listener_efx_preset_name]); + efx_effect_id = efx_effect_id_map.find(listener_efx_reverb_properties)->second; } // update air absorption gain hf of effect if (efx_reverb_engine == EfxReverbEngine::EAXREVERB) { - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + alEffectf(efx_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } else if (efx_reverb_engine == EfxReverbEngine::REVERB) { - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + alEffectf(efx_effect_id, AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } // early reflections panning, delay and strength @@ -405,11 +435,11 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) const float step = std::min(dt_sec / time_to_target, 1.0f); static std::tuple target_early_reflections_properties; static std::tuple current_early_reflections_properties = - std::make_tuple(Ogre::Vector3(efx_properties_map[listener_efx_preset_name].flReflectionsPan[0], - efx_properties_map[listener_efx_preset_name].flReflectionsPan[1], - efx_properties_map[listener_efx_preset_name].flReflectionsPan[2]), - efx_properties_map[listener_efx_preset_name].flReflectionsGain, - efx_properties_map[listener_efx_preset_name].flReflectionsDelay); + std::make_tuple(Ogre::Vector3(listener_efx_reverb_properties->flReflectionsPan[0], + listener_efx_reverb_properties->flReflectionsPan[1], + listener_efx_reverb_properties->flReflectionsPan[2]), + listener_efx_reverb_properties->flReflectionsGain, + listener_efx_reverb_properties->flReflectionsDelay); target_early_reflections_properties = calculateEarlyReflectionsProperties(); @@ -440,17 +470,17 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) { current_early_reflections_pan.x, 0, // TODO -current_early_reflections_pan.z }; - alEffectfv(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); - alEffectf(efx_effect_id_map[listener_efx_preset_name], AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); + alEffectfv(efx_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); + alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); + alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); } // update the effect on the listener effect slot - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id_map[listener_efx_preset_name]); + alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id); } } -std::tuple SoundManager::calculateEarlyReflectionsProperties() +std::tuple SoundManager::calculateEarlyReflectionsProperties() const { const float max_distance = 2.0f; const float reflections_gain_boost_max = 2.0f; // 6.32 db @@ -489,8 +519,8 @@ std::tuple SoundManager::calculateEarlyReflectionsP if (!nearby_surface_detected) { // reset values to the original values of the preset - early_reflections_delay = efx_properties_map[listener_efx_preset_name].flReflectionsDelay; - early_reflections_gain = efx_properties_map[listener_efx_preset_name].flReflectionsGain; + early_reflections_delay = listener_efx_reverb_properties->flReflectionsDelay; + early_reflections_gain = listener_efx_reverb_properties->flReflectionsGain; } else // at least one nearby surface was detected { @@ -501,7 +531,7 @@ std::tuple SoundManager::calculateEarlyReflectionsP early_reflections_delay = closest_surface_distance / getSpeedOfSound(); early_reflections_gain = std::min( - (efx_properties_map[listener_efx_preset_name].flReflectionsGain + (listener_efx_reverb_properties->flReflectionsGain + reflections_gain_boost_max - (reflections_gain_boost_max * (1.0f - magnitude))), AL_EAXREVERB_MAX_REFLECTIONS_GAIN); @@ -529,7 +559,7 @@ std::tuple SoundManager::calculateEarlyReflectionsP return std::make_tuple(early_reflections_pan, early_reflections_gain, early_reflections_delay); } -ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties) const +ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const { ALuint effect = 0; ALenum error; @@ -540,49 +570,49 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties { case EfxReverbEngine::EAXREVERB: alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties.flGain); - - alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties.flDensity); - alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties.flDiffusion); - alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties.flGain); - alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties.flGainHF); - alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties.flGainLF); - alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties.flDecayTime); - alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties.flDecayHFRatio); - alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties.flDecayLFRatio); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties.flReflectionsGain); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties.flReflectionsDelay); - alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties.flReflectionsPan); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties.flLateReverbGain); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties.flLateReverbDelay); - alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties.flLateReverbPan); - alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties.flEchoTime); - alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties.flEchoDepth); - alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties.flModulationTime); - alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties.flModulationDepth); - alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties.flAirAbsorptionGainHF); - alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties.flHFReference); - alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties.flLFReference); - alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties.flRoomRolloffFactor); - alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties.iDecayHFLimit); + alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + + alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); + alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); + alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); + alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); + alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); + alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); + alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); + alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); + alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); + alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); + alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); + alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); + alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); break; case EfxReverbEngine::REVERB: alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - alEffectf(effect, AL_REVERB_DENSITY, efx_properties.flDensity); - alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties.flDiffusion); - alEffectf(effect, AL_REVERB_GAIN, efx_properties.flGain); - alEffectf(effect, AL_REVERB_GAINHF, efx_properties.flGainHF); - alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties.flDecayTime); - alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties.flDecayHFRatio); - alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties.flReflectionsGain); - alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties.flReflectionsDelay); - alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties.flLateReverbGain); - alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties.flLateReverbDelay); - alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties.flAirAbsorptionGainHF); - alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties.flRoomRolloffFactor); - alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties.iDecayHFLimit); + alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); + alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); + alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); + alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); break; case EfxReverbEngine::NONE: @@ -603,6 +633,20 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties return effect; } +void SoundManager::DeleteAlEffect(const ALuint efx_effect_id) const +{ + ALenum error; + alGetError(); + + alDeleteEffects(1, &efx_effect_id); + + error = alGetError(); + if(error != AL_NO_ERROR) + { + LOG("SoundManager: Could not delete EFX effect: " + error); + } +} + bool compareByAudibility(std::pair a, std::pair b) { return a.second > b.second; diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 2176a8961a..7ac0aaa18f 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -58,6 +58,11 @@ class SoundManager SoundManager(); ~SoundManager(); + /** + * Cleans up various objects that should be reset when returning from a terrain to the main menu. + */ + void CleanUp(); + /** * @param filename WAV file. * @param resource_group_name Leave empty to auto-search all groups (classic behavior). @@ -90,7 +95,7 @@ class SoundManager * @param listener_environment The preset that will be used for the listener environment. * @see updateListenerEffectSlot() */ - void setListenerEnvironment(std::string listener_environment); + void setListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties); /** * Unlike the name suggests, this sets the listener's gain to 0, essentially muting all sounds. @@ -144,7 +149,15 @@ class SoundManager * Returns currently registered EFX presets * @return Map of EFX Preset names to their EFXEAXREVERBPROPERTIES object. */ - std::map getEfxPropertiesMap() const { return efx_properties_map; } + const std::map& getEfxPropertiesMap() const { return efx_properties_map; } + + /** + * Returns a pointer to properties of an EFX preset stored in the EFX properties map. + * The presets should not be modified directly so they can serve as a reference. + * @param efx_preset_name The name of the preset for which the properties shall be returned. + * @return Pointer to properties of a reverb preset if the lookup for the name in the EFX Properties map was positive, nullptr otherwise. + */ + const EFXEAXREVERBPROPERTIES* GetEfxProperties(const std::string& efx_preset_name) const; static const float MAX_DISTANCE; static const float ROLLOFF_FACTOR; @@ -220,9 +233,9 @@ class SoundManager ALuint listener_slot = 0; ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; EfxReverbEngine efx_reverb_engine = EfxReverbEngine::NONE; - std::string listener_efx_preset_name; + const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties = nullptr; std::map efx_properties_map; - std::map efx_effect_id_map; + std::map efx_effect_id_map; LPALGENEFFECTS alGenEffects = nullptr; LPALDELETEEFFECTS alDeleteEffects = nullptr; LPALISEFFECT alIsEffect = nullptr; @@ -246,7 +259,13 @@ class SoundManager * @param efx_properties EFXEAXREVERBPROPERTIES object holding the parameters of the reverb preset. * @see `AL/efx-presets.h` from OpenAL */ - ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES& efx_properties) const; + ALuint CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties) const; + + /** + * Deletes an OpenAL effect. + * @param effect_id ID of the effect targeted for removal. + */ + void DeleteAlEffect(const ALuint efx_effect_id) const; /** * Helper function that fills the efx_properties_map with presets provided by @@ -269,7 +288,7 @@ class SoundManager * on surface distance. * @return A tuple of user-relative panning vector, gain and delay for early reflections */ - std::tuple calculateEarlyReflectionsProperties(); + std::tuple calculateEarlyReflectionsProperties() const; /** * Applies an obstruction filter to the provided source if certain conditions apply. diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 1a5c840e39..91d5f541c4 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -353,7 +353,7 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (disabled) return; - std::string listener_environment; + const EFXEAXREVERBPROPERTIES* listener_reverb_properties = nullptr; if (App::audio_engine_controls_environmental_audio->getBool()) { @@ -377,37 +377,37 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (App::audio_enable_efx->getBool()) { - listener_environment = this->getReverbPresetAt(listener_position); + listener_reverb_properties = this->getReverbPresetAt(listener_position); } } if (App::audio_enable_efx->getBool()) { // always update the environment in case it was changed via console or script - sound_manager->setListenerEnvironment(listener_environment); + sound_manager->setListenerEnvironment(listener_reverb_properties); } } -std::string SoundScriptManager::getReverbPresetAt(Ogre::Vector3 position) +const EFXEAXREVERBPROPERTIES* SoundScriptManager::getReverbPresetAt(const Ogre::Vector3 position) const { if (!App::audio_force_listener_efx_preset->getStr().empty()) { - return App::audio_force_listener_efx_preset->getStr(); + return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); } if (this->listener_is_inside_the_player_coupled_actor) { // the player is in a vehicle // there is no reverb preset for trucks, but this seems ok - return "EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"; + return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); } if(this->listenerIsUnderwater()) { - return "EFX_REVERB_PRESET_UNDERWATER"; + return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); } - return App::audio_default_listener_efx_preset->getStr(); + return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); } void SoundScriptManager::setDopplerFactor(float doppler_factor) diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index f035a0461b..a9e543f2f7 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -31,6 +31,12 @@ #include +#ifdef __APPLE__ + #include +#else + #include +#endif + #define SOUND_PLAY_ONCE(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigOnce ( (_ACTOR_), (_TRIG_) ) #define SOUND_START(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigStart ( (_ACTOR_), (_TRIG_) ) #define SOUND_STOP(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigStop ( (_ACTOR_), (_TRIG_) ) @@ -379,7 +385,12 @@ class SoundScriptManager : public Ogre::ScriptLoader // soundLinks, soundItems, actor_ids, triggers std::map > > > state_map; - std::string getReverbPresetAt(Ogre::Vector3 position); + /** + * Determines which environment in terms of reverb corresponds to the provided position and returns + * its properties. + * @return Reverb properties for the provided position. + */ + const EFXEAXREVERBPROPERTIES* getReverbPresetAt(Ogre::Vector3 position) const; void setListenerEnvironment(Ogre::Vector3 position); SoundManager* sound_manager; diff --git a/source/main/main.cpp b/source/main/main.cpp index 4c5c96f68c..efab4108fb 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -934,6 +934,7 @@ int main(int argc, char *argv[]) App::sim_terrain_gui_name->setStr(""); App::GetOutGauge()->Close(); App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); + App::GetSoundScriptManager()->getSoundManager()->CleanUp(); } catch (...) { From 06c22e479cfc57ab4930893c459e3b66ed832c49 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Fri, 18 Oct 2024 22:01:42 +0200 Subject: [PATCH 062/104] :triangular_ruler: Adapt to coding style guidelines --- source/main/audio/SoundManager.cpp | 360 +++++++++++------------ source/main/audio/SoundManager.h | 58 ++-- source/main/audio/SoundScriptManager.cpp | 40 +-- source/main/audio/SoundScriptManager.h | 16 +- source/main/main.cpp | 4 +- source/main/system/ConsoleCmd.cpp | 4 +- 6 files changed, 241 insertions(+), 241 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 4561d8eb38..e27c75bcd6 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -97,8 +97,8 @@ SoundManager::SoundManager() if (alcGetString(audio_device, ALC_EXTENSIONS)) LOG("SoundManager: OpenAL ALC extensions are: " + String(alcGetString(audio_device, ALC_EXTENSIONS))); // initialize use of OpenAL EFX extensions - this->efx_is_available = alcIsExtensionPresent(audio_device, "ALC_EXT_EFX"); - if (efx_is_available) + m_efx_is_available = alcIsExtensionPresent(audio_device, "ALC_EXT_EFX"); + if (m_efx_is_available) { LOG("SoundManager: Found OpenAL EFX extension"); @@ -126,14 +126,14 @@ SoundManager::SoundManager() // allow user to change reverb engines at will switch(App::audio_efx_reverb_engine->getEnum()) { - case EfxReverbEngine::EAXREVERB: efx_reverb_engine = EfxReverbEngine::EAXREVERB; break; - case EfxReverbEngine::REVERB: efx_reverb_engine = EfxReverbEngine::REVERB; break; + case EfxReverbEngine::EAXREVERB: m_efx_reverb_engine = EfxReverbEngine::EAXREVERB; break; + case EfxReverbEngine::REVERB: m_efx_reverb_engine = EfxReverbEngine::REVERB; break; default: - efx_reverb_engine = EfxReverbEngine::NONE; + m_efx_reverb_engine = EfxReverbEngine::NONE; LOG("SoundManager: Reverb engine disabled"); } - if(efx_reverb_engine == EfxReverbEngine::EAXREVERB) + if(m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) { if (alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) { @@ -142,30 +142,30 @@ SoundManager::SoundManager() else { LOG("SoundManager: AL_EFFECT_EAXREVERB requested but OpenAL driver does not support it, falling back to standard reverb. Advanced features, such as reflection panning, will not be available"); - efx_reverb_engine = EfxReverbEngine::REVERB; + m_efx_reverb_engine = EfxReverbEngine::REVERB; } } - else if(efx_reverb_engine == EfxReverbEngine::REVERB) + else if(m_efx_reverb_engine == EfxReverbEngine::REVERB) { LOG("SoundManager: Using OpenAL standard reverb"); } // create effect slot for the listener - if(!this->alIsAuxiliaryEffectSlot(listener_slot)) + if(!this->alIsAuxiliaryEffectSlot(m_listener_slot)) { alGetError(); - this->alGenAuxiliaryEffectSlots(1, &listener_slot); + this->alGenAuxiliaryEffectSlots(1, &m_listener_slot); ALuint e = alGetError(); if (e != AL_NO_ERROR) { LOG("SoundManager: alGenAuxiliaryEffectSlots for listener_slot failed: " + e); - listener_slot = AL_EFFECTSLOT_NULL; + m_listener_slot = AL_EFFECTSLOT_NULL; } } - this->prepopulate_efx_property_map(); + this->PrepopulateEfxPropertiesMap(); /* Create filter for obstruction @@ -175,18 +175,18 @@ SoundManager::SoundManager() */ alGetError(); - alGenFilters(1, &efx_outdoor_obstruction_lowpass_filter_id); + this->alGenFilters(1, &m_efx_outdoor_obstruction_lowpass_filter_id); ALuint e = alGetError(); if (e != AL_NO_ERROR) { - efx_outdoor_obstruction_lowpass_filter_id = AL_FILTER_NULL; + m_efx_outdoor_obstruction_lowpass_filter_id = AL_FILTER_NULL; } else { - alFilteri(efx_outdoor_obstruction_lowpass_filter_id, AL_FILTER_TYPE, AL_FILTER_LOWPASS); - alFilterf(efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAIN, 0.33f); - alFilterf(efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAINHF, 0.25f); + this->alFilteri(m_efx_outdoor_obstruction_lowpass_filter_id, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + this->alFilterf(m_efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAIN, 0.33f); + this->alFilterf(m_efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAINHF, 0.25f); } } } @@ -210,7 +210,7 @@ SoundManager::SoundManager() // connect source to listener slot effect if(App::audio_enable_efx->getBool()) { - alSource3i(hardware_sources[hardware_sources_num], AL_AUXILIARY_SEND_FILTER, listener_slot, 0, AL_FILTER_NULL); + alSource3i(hardware_sources[hardware_sources_num], AL_AUXILIARY_SEND_FILTER, m_listener_slot, 0, AL_FILTER_NULL); } } @@ -231,18 +231,18 @@ SoundManager::~SoundManager() alDeleteSources(MAX_HARDWARE_SOURCES, hardware_sources); alDeleteBuffers(MAX_AUDIO_BUFFERS, audio_buffers); - if(efx_is_available) + if(m_efx_is_available) { - if(alIsFilter(efx_outdoor_obstruction_lowpass_filter_id)) + if(this->alIsFilter(m_efx_outdoor_obstruction_lowpass_filter_id)) { - alDeleteFilters(1, &efx_outdoor_obstruction_lowpass_filter_id); + this->alDeleteFilters(1, &m_efx_outdoor_obstruction_lowpass_filter_id); } - if (alIsAuxiliaryEffectSlot(listener_slot)) + if (this->alIsAuxiliaryEffectSlot(m_listener_slot)) { - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); - alDeleteAuxiliaryEffectSlots(1, &listener_slot); - listener_slot = 0; + this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + this->alDeleteAuxiliaryEffectSlots(1, &m_listener_slot); + m_listener_slot = 0; } } @@ -262,27 +262,27 @@ SoundManager::~SoundManager() void SoundManager::CleanUp() { - if(efx_is_available) + if(m_efx_is_available) { - listener_efx_reverb_properties = nullptr; - if (alIsAuxiliaryEffectSlot(listener_slot)) + m_listener_efx_reverb_properties = nullptr; + if (this->alIsAuxiliaryEffectSlot(m_listener_slot)) { - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); } - for (const auto& entry : efx_effect_id_map) + for (const auto& entry : m_efx_effect_id_map) { - DeleteAlEffect(entry.second); - efx_effect_id_map.erase(entry.first); + this->DeleteAlEffect(entry.second); + m_efx_effect_id_map.erase(entry.first); } } } const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& efx_preset_name) const { - const auto it = efx_properties_map.find(efx_preset_name); + const auto it = m_efx_properties_map.find(efx_preset_name); - if (it != efx_properties_map.end()) + if (it != m_efx_properties_map.end()) { return &it->second; } @@ -292,57 +292,57 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& } } -void SoundManager::prepopulate_efx_property_map() +void SoundManager::PrepopulateEfxPropertiesMap() { - this->efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; - this->efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; - this->efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; - this->efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; - this->efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; - this->efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; - this->efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; - this->efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; - this->efx_properties_map["EFX_REVERB_PRESET_QUARRY"] = EFX_REVERB_PRESET_QUARRY; - this->efx_properties_map["EFX_REVERB_PRESET_PLAIN"] = EFX_REVERB_PRESET_PLAIN; - this->efx_properties_map["EFX_REVERB_PRESET_PARKINGLOT"] = EFX_REVERB_PRESET_PARKINGLOT; - this->efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; - this->efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; - this->efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; - this->efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; - this->efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; - this->efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; - this->efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; - this->efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; - this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; - this->efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; - this->efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; - this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_BACKYARD"] = EFX_REVERB_PRESET_OUTDOORS_BACKYARD; - this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS"] = EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS; - this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON"] = EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON; - this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_CREEK"] = EFX_REVERB_PRESET_OUTDOORS_CREEK; - this->efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_VALLEY"] = EFX_REVERB_PRESET_OUTDOORS_VALLEY; - this->efx_properties_map["EFX_REVERB_PRESET_MOOD_HEAVEN"] = EFX_REVERB_PRESET_MOOD_HEAVEN; - this->efx_properties_map["EFX_REVERB_PRESET_MOOD_HELL"] = EFX_REVERB_PRESET_MOOD_HELL; - this->efx_properties_map["EFX_REVERB_PRESET_MOOD_MEMORY"] = EFX_REVERB_PRESET_MOOD_MEMORY; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_COMMENTATOR"] = EFX_REVERB_PRESET_DRIVING_COMMENTATOR; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_PITGARAGE"] = EFX_REVERB_PRESET_DRIVING_PITGARAGE; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; - this->efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; - this->efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; - this->efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; - this->efx_properties_map["EFX_REVERB_PRESET_CITY_UNDERPASS"] = EFX_REVERB_PRESET_CITY_UNDERPASS; - this->efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; + m_efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; + m_efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; + m_efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; + m_efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; + m_efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; + m_efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; + m_efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; + m_efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; + m_efx_properties_map["EFX_REVERB_PRESET_QUARRY"] = EFX_REVERB_PRESET_QUARRY; + m_efx_properties_map["EFX_REVERB_PRESET_PLAIN"] = EFX_REVERB_PRESET_PLAIN; + m_efx_properties_map["EFX_REVERB_PRESET_PARKINGLOT"] = EFX_REVERB_PRESET_PARKINGLOT; + m_efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; + m_efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; + m_efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; + m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_BACKYARD"] = EFX_REVERB_PRESET_OUTDOORS_BACKYARD; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS"] = EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON"] = EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_CREEK"] = EFX_REVERB_PRESET_OUTDOORS_CREEK; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_VALLEY"] = EFX_REVERB_PRESET_OUTDOORS_VALLEY; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HEAVEN"] = EFX_REVERB_PRESET_MOOD_HEAVEN; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HELL"] = EFX_REVERB_PRESET_MOOD_HELL; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_MEMORY"] = EFX_REVERB_PRESET_MOOD_MEMORY; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_COMMENTATOR"] = EFX_REVERB_PRESET_DRIVING_COMMENTATOR; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_PITGARAGE"] = EFX_REVERB_PRESET_DRIVING_PITGARAGE; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_UNDERPASS"] = EFX_REVERB_PRESET_CITY_UNDERPASS; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; } -void SoundManager::update(const float dt_sec) +void SoundManager::Update(const float dt_sec) { if (!audio_device) return; recomputeAllSources(); - updateAlListener(); + UpdateAlListener(); if(App::audio_enable_efx->getBool()) { @@ -354,79 +354,79 @@ void SoundManager::update(const float dt_sec) if(App::audio_enable_obstruction->getBool()) { - updateObstructionFilter(hardware_sources[source_index]); + this->UpdateObstructionFilter(hardware_sources[source_index]); } } - updateListenerEffectSlot(dt_sec); + this->UpdateListenerEffectSlot(dt_sec); } } -void SoundManager::setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) +void SoundManager::SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) { - listener_position = position; - listener_direction = direction; - listener_up = up; - listener_velocity = velocity; + m_listener_position = position; + m_listener_direction = direction; + m_listener_up = up; + m_listener_velocity = velocity; } -void SoundManager::updateAlListener() +void SoundManager::UpdateAlListener() { float orientation[6]; // direction - orientation[0] = listener_direction.x; - orientation[1] = listener_direction.y; - orientation[2] = listener_direction.z; + orientation[0] = m_listener_direction.x; + orientation[1] = m_listener_direction.y; + orientation[2] = m_listener_direction.z; // up - orientation[3] = listener_up.x; - orientation[4] = listener_up.y; - orientation[5] = listener_up.z; + orientation[3] = m_listener_up.x; + orientation[4] = m_listener_up.y; + orientation[5] = m_listener_up.z; - alListener3f(AL_POSITION, listener_position.x, listener_position.y, listener_position.z); - alListener3f(AL_VELOCITY, listener_velocity.x, listener_velocity.y, listener_velocity.z); + alListener3f(AL_POSITION, m_listener_position.x, m_listener_position.y, m_listener_position.z); + alListener3f(AL_VELOCITY, m_listener_velocity.x, m_listener_velocity.y, m_listener_velocity.z); alListenerfv(AL_ORIENTATION, orientation); } -void SoundManager::setListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_reverb_properties) +void SoundManager::SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_reverb_properties) { - this->listener_efx_reverb_properties = listener_reverb_properties; + m_listener_efx_reverb_properties = listener_reverb_properties; } -void SoundManager::updateListenerEffectSlot(const float dt_sec) +void SoundManager::UpdateListenerEffectSlot(const float dt_sec) { - if (listener_efx_reverb_properties == nullptr) + if (m_listener_efx_reverb_properties == nullptr) { - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); } else { ALuint efx_effect_id; // create new effect if not existing - if(efx_effect_id_map.find(listener_efx_reverb_properties) == efx_effect_id_map.end()) + if(m_efx_effect_id_map.find(m_listener_efx_reverb_properties) == m_efx_effect_id_map.end()) { - efx_effect_id = CreateAlEffect(listener_efx_reverb_properties); - efx_effect_id_map[listener_efx_reverb_properties] = efx_effect_id; + efx_effect_id = this->CreateAlEffect(m_listener_efx_reverb_properties); + m_efx_effect_id_map[m_listener_efx_reverb_properties] = efx_effect_id; } else { - efx_effect_id = efx_effect_id_map.find(listener_efx_reverb_properties)->second; + efx_effect_id = m_efx_effect_id_map.find(m_listener_efx_reverb_properties)->second; } // update air absorption gain hf of effect - if (efx_reverb_engine == EfxReverbEngine::EAXREVERB) + if (m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) { - alEffectf(efx_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + this->alEffectf(efx_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } - else if (efx_reverb_engine == EfxReverbEngine::REVERB) + else if (m_efx_reverb_engine == EfxReverbEngine::REVERB) { - alEffectf(efx_effect_id, AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); + this->alEffectf(efx_effect_id, AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); } // early reflections panning, delay and strength if ( App::audio_enable_reflection_panning->getBool() && - efx_reverb_engine == EfxReverbEngine::EAXREVERB && + m_efx_reverb_engine == EfxReverbEngine::EAXREVERB && App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu ) { @@ -435,13 +435,13 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) const float step = std::min(dt_sec / time_to_target, 1.0f); static std::tuple target_early_reflections_properties; static std::tuple current_early_reflections_properties = - std::make_tuple(Ogre::Vector3(listener_efx_reverb_properties->flReflectionsPan[0], - listener_efx_reverb_properties->flReflectionsPan[1], - listener_efx_reverb_properties->flReflectionsPan[2]), - listener_efx_reverb_properties->flReflectionsGain, - listener_efx_reverb_properties->flReflectionsDelay); + std::make_tuple(Ogre::Vector3(m_listener_efx_reverb_properties->flReflectionsPan[0], + m_listener_efx_reverb_properties->flReflectionsPan[1], + m_listener_efx_reverb_properties->flReflectionsPan[2]), + m_listener_efx_reverb_properties->flReflectionsGain, + m_listener_efx_reverb_properties->flReflectionsDelay); - target_early_reflections_properties = calculateEarlyReflectionsProperties(); + target_early_reflections_properties = this->ComputeEarlyReflectionsProperties(); const Ogre::Vector3 current_early_reflections_pan = std::get<0>(current_early_reflections_properties) @@ -470,17 +470,17 @@ void SoundManager::updateListenerEffectSlot(const float dt_sec) { current_early_reflections_pan.x, 0, // TODO -current_early_reflections_pan.z }; - alEffectfv(efx_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); - alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); - alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); + this->alEffectfv(efx_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); + this->alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); + this->alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); } // update the effect on the listener effect slot - alAuxiliaryEffectSloti(listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id); + this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id); } } -std::tuple SoundManager::calculateEarlyReflectionsProperties() const +std::tuple SoundManager::ComputeEarlyReflectionsProperties() const { const float max_distance = 2.0f; const float reflections_gain_boost_max = 2.0f; // 6.32 db @@ -500,10 +500,10 @@ std::tuple SoundManager::calculateEarlyReflectionsP for (float angle = 0; angle < 360; angle += angle_step_size) { - Ogre::Vector3 raycast_direction = Quaternion(Ogre::Degree(angle), listener_up) * listener_direction; + Ogre::Vector3 raycast_direction = Quaternion(Ogre::Degree(angle), m_listener_up) * m_listener_direction; raycast_direction.normalise(); // accompany direction vector for how the intersectsTris function works - Ray ray = Ray(listener_position, raycast_direction * max_distance * App::GetGameContext()->GetTerrain()->GetCollisions()->GetCellSize()); + Ray ray = Ray(m_listener_position, raycast_direction * max_distance * App::GetGameContext()->GetTerrain()->GetCollisions()->GetCellSize()); std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(ray); if (intersection.first) @@ -519,8 +519,8 @@ std::tuple SoundManager::calculateEarlyReflectionsP if (!nearby_surface_detected) { // reset values to the original values of the preset - early_reflections_delay = listener_efx_reverb_properties->flReflectionsDelay; - early_reflections_gain = listener_efx_reverb_properties->flReflectionsGain; + early_reflections_delay = m_listener_efx_reverb_properties->flReflectionsDelay; + early_reflections_gain = m_listener_efx_reverb_properties->flReflectionsGain; } else // at least one nearby surface was detected { @@ -528,10 +528,10 @@ std::tuple SoundManager::calculateEarlyReflectionsP magnitude = 1.0f - early_reflections_pan.length() / Ogre::Math::Sqrt(2.0f * Ogre::Math::Pow(max_distance, 2)); // set delay based on distance to the closest surface - early_reflections_delay = closest_surface_distance / getSpeedOfSound(); + early_reflections_delay = closest_surface_distance / GetSpeedOfSound(); early_reflections_gain = std::min( - (listener_efx_reverb_properties->flReflectionsGain + (m_listener_efx_reverb_properties->flReflectionsGain + reflections_gain_boost_max - (reflections_gain_boost_max * (1.0f - magnitude))), AL_EAXREVERB_MAX_REFLECTIONS_GAIN); @@ -542,13 +542,13 @@ std::tuple SoundManager::calculateEarlyReflectionsP // determine the rotation of the listener direction from straight-ahead vector // work around Quaternion quirks at around 180° rotation Ogre::Quaternion horizontal_rotation; - if (listener_direction.z > 0.0f) + if (m_listener_direction.z > 0.0f) { - horizontal_rotation = Quaternion(Ogre::Degree(180), listener_up) * listener_direction.getRotationTo(Ogre::Vector3::UNIT_Z); + horizontal_rotation = Quaternion(Ogre::Degree(180), m_listener_up) * m_listener_direction.getRotationTo(Ogre::Vector3::UNIT_Z); } else { - horizontal_rotation = listener_direction.getRotationTo(Ogre::Vector3::NEGATIVE_UNIT_Z); + horizontal_rotation = m_listener_direction.getRotationTo(Ogre::Vector3::NEGATIVE_UNIT_Z); } early_reflections_pan = horizontal_rotation * early_reflections_pan; @@ -564,55 +564,55 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties ALuint effect = 0; ALenum error; - alGenEffects(1, &effect); + this->alGenEffects(1, &effect); - switch (efx_reverb_engine) + switch (m_efx_reverb_engine) { case EfxReverbEngine::EAXREVERB: - alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); - - alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); - alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); - alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); - alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); - alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); - alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); - alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); - alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); - alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); - alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); - alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); - alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); - alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); - alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + this->alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + this->alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + + this->alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); + this->alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); + this->alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + this->alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); + this->alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); + this->alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); + this->alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + this->alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); + this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + this->alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); + this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + this->alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); + this->alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); + this->alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); + this->alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); + this->alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); + this->alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + this->alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); + this->alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); + this->alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + this->alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); break; case EfxReverbEngine::REVERB: - alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - - alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); - alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); - alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); - alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); - alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); - alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + this->alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + this->alEffectf(effect, AL_REVERB_DENSITY, efx_properties->flDensity); + this->alEffectf(effect, AL_REVERB_DIFFUSION, efx_properties->flDiffusion); + this->alEffectf(effect, AL_REVERB_GAIN, efx_properties->flGain); + this->alEffectf(effect, AL_REVERB_GAINHF, efx_properties->flGainHF); + this->alEffectf(effect, AL_REVERB_DECAY_TIME, efx_properties->flDecayTime); + this->alEffectf(effect, AL_REVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + this->alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + this->alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + this->alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + this->alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + this->alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + this->alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + this->alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); break; case EfxReverbEngine::NONE: @@ -625,8 +625,8 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties { LOG("SoundManager: Could not create EFX effect:" + error); - if(alIsEffect(effect)) - alDeleteEffects(1, &effect); + if(this->alIsEffect(effect)) + this->alDeleteEffects(1, &effect); return 0; } @@ -638,7 +638,7 @@ void SoundManager::DeleteAlEffect(const ALuint efx_effect_id) const ALenum error; alGetError(); - alDeleteEffects(1, &efx_effect_id); + this->alDeleteEffects(1, &efx_effect_id); error = alGetError(); if(error != AL_NO_ERROR) @@ -661,7 +661,7 @@ void SoundManager::recomputeAllSources() for (int i=0; i < audio_buffers_in_use_count; i++) { - audio_sources[i]->computeAudibility(listener_position); + audio_sources[i]->computeAudibility(m_listener_position); audio_sources_most_audible[i].first = i; audio_sources_most_audible[i].second = audio_sources[i]->audibility; } @@ -695,7 +695,7 @@ void SoundManager::recomputeAllSources() #endif } -void SoundManager::updateObstructionFilter(const ALuint hardware_source) const +void SoundManager::UpdateObstructionFilter(const ALuint hardware_source) const { // TODO: Simulate diffraction path. @@ -718,7 +718,7 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) const bool obstruction_detected = false; // always obstruct sounds if the player is in a vehicle - if(App::GetSoundScriptManager()->listenerIsInsideThePlayerCoupledActor()) + if(App::GetSoundScriptManager()->ListenerIsInsideThePlayerCoupledActor()) { obstruction_detected = true; } @@ -731,9 +731,9 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) const std::pair intersection; // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - listener_position; + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; Ogre::Real distance_to_sound = direction_to_sound.length(); - Ray direct_path_to_sound = Ray(listener_position, direction_to_sound); + Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); // perform line of sight check against terrain intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); @@ -809,7 +809,7 @@ void SoundManager::updateObstructionFilter(const ALuint hardware_source) const if(obstruction_detected) { // Apply obstruction filter to the source - alSourcei(hardware_source, AL_DIRECT_FILTER, efx_outdoor_obstruction_lowpass_filter_id); + alSourcei(hardware_source, AL_DIRECT_FILTER, m_efx_outdoor_obstruction_lowpass_filter_id); } else { @@ -823,7 +823,7 @@ void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vect { if (!audio_device) return; - audio_sources[source_index]->computeAudibility(listener_position); + audio_sources[source_index]->computeAudibility(m_listener_position); if (audio_sources[source_index]->audibility == 0.0f) { diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 7ac0aaa18f..e6897b97ca 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -72,14 +72,14 @@ class SoundManager /** Returns the position vector of the listener * @return listener position vector */ - Ogre::Vector3 getListenerPosition() const { return listener_position; } + Ogre::Vector3 GetListenerPosition() const { return m_listener_position; } /** * Does the per-frame update of sounds and listener environment. With the help of other functions it * determines and then submits the current state of the audio world to OpenAL. * @param dt_sec Time since last frame in seconds */ - void update(const float dt_sec); + void Update(const float dt_sec); /** * Sets position and speed of the listener @@ -88,14 +88,14 @@ class SoundManager * @param up This direction vector specifies where the top of the head of the listener is pointing to. * @param velocity The movement speed of the listener in each dimension. */ - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); /** * Updates the EFX/EAX reverb preset that is used as a base for updating the listener's effect slot. * @param listener_environment The preset that will be used for the listener environment. - * @see updateListenerEffectSlot() + * @see UpdateListenerEffectSlot() */ - void setListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties); + void SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties); /** * Unlike the name suggests, this sets the listener's gain to 0, essentially muting all sounds. @@ -118,25 +118,25 @@ class SoundManager /** * @return The value of AL_SPEED_OF_SOUND as currently set in OpenAL. */ - float getSpeedOfSound() const { return alGetFloat(AL_SPEED_OF_SOUND); } + float GetSpeedOfSound() const { return alGetFloat(AL_SPEED_OF_SOUND); } /** * Updates the speed of sound in OpenAL with the provided value. * This value should based on RoR units for correct results. * @param speed_of_sound Speed of sound within the range of AL_SPEED_OF_SOUND. */ - void setSpeedOfSound(const float speed_of_sound) const { alSpeedOfSound(speed_of_sound); } + void SetSpeedOfSound(const float speed_of_sound) const { alSpeedOfSound(speed_of_sound); } /** * @return The value of AL_DOPPLER_FACTOR as currently set in OpenAL. */ - float getDopplerFactor() const { return alGetFloat(AL_DOPPLER_FACTOR); } + float GetDopplerFactor() const { return alGetFloat(AL_DOPPLER_FACTOR); } /** * Updates the doppler factor in OpenAL with the provided value. * @param doppler_factor Doppler factor within the range of AL_DOPPLER_FACTOR. */ - void setDopplerFactor(const float doppler_factor) const { alDopplerFactor(doppler_factor); } + void SetDopplerFactor(const float doppler_factor) const { alDopplerFactor(doppler_factor); } /** * Returns the number of currently used hardware sources. In a typical scenario, @@ -149,7 +149,7 @@ class SoundManager * Returns currently registered EFX presets * @return Map of EFX Preset names to their EFXEAXREVERBPROPERTIES object. */ - const std::map& getEfxPropertiesMap() const { return efx_properties_map; } + const std::map& getEfxPropertiesMap() const { return m_efx_properties_map; } /** * Returns a pointer to properties of an EFX preset stored in the EFX properties map. @@ -168,9 +168,9 @@ class SoundManager private: /** * Updates the listener's position, orientation and velocity vectors in OpenAL. - * @see setListener() + * @see SetListener() */ - void updateAlListener(); + void UpdateAlListener(); void recomputeAllSources(); /** @@ -221,21 +221,21 @@ class SoundManager ALuint audio_buffers[MAX_AUDIO_BUFFERS]; Ogre::String audio_buffer_file_name[MAX_AUDIO_BUFFERS]; - Ogre::Vector3 listener_position = Ogre::Vector3::ZERO; - Ogre::Vector3 listener_direction = Ogre::Vector3::ZERO; - Ogre::Vector3 listener_up = Ogre::Vector3::ZERO; - Ogre::Vector3 listener_velocity = Ogre::Vector3::ZERO; + Ogre::Vector3 m_listener_position = Ogre::Vector3::ZERO; + Ogre::Vector3 m_listener_direction = Ogre::Vector3::ZERO; + Ogre::Vector3 m_listener_up = Ogre::Vector3::ZERO; + Ogre::Vector3 m_listener_velocity = Ogre::Vector3::ZERO; ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; // OpenAL EFX stuff - bool efx_is_available = false; - ALuint listener_slot = 0; - ALuint efx_outdoor_obstruction_lowpass_filter_id = 0; - EfxReverbEngine efx_reverb_engine = EfxReverbEngine::NONE; - const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties = nullptr; - std::map efx_properties_map; - std::map efx_effect_id_map; + bool m_efx_is_available = false; + ALuint m_listener_slot = 0; + ALuint m_efx_outdoor_obstruction_lowpass_filter_id = 0; + EfxReverbEngine m_efx_reverb_engine = EfxReverbEngine::NONE; + const EFXEAXREVERBPROPERTIES* m_listener_efx_reverb_properties = nullptr; + std::map m_efx_properties_map; + std::map m_efx_effect_id_map; LPALGENEFFECTS alGenEffects = nullptr; LPALDELETEEFFECTS alDeleteEffects = nullptr; LPALISEFFECT alIsEffect = nullptr; @@ -268,19 +268,19 @@ class SoundManager void DeleteAlEffect(const ALuint efx_effect_id) const; /** - * Helper function that fills the efx_properties_map with presets provided by + * Helper function that fills the m_efx_properties_map with presets provided by * OpenAL's efx-presets.h header. */ - void prepopulate_efx_property_map(); + void PrepopulateEfxPropertiesMap(); /** * Dynamically adjusts some parameters of the currently active reverb preset based * on the current environment of the listener. It works on the AL effect correspondig - * to a reverb preset, i.e. the original preset in efx_properties_map remains unchanged. + * to a reverb preset, i.e. the original preset in m_efx_properties_map remains unchanged. * Finally, it updates the AL listener's effect slot with the adjusted preset. * @param dt_sec Time since last frame in seconds */ - void updateListenerEffectSlot(const float dt_sec); + void UpdateListenerEffectSlot(const float dt_sec); /** * Detects surfaces close to the listener and calculates a user-relative (as opposed to listener-relative) @@ -288,7 +288,7 @@ class SoundManager * on surface distance. * @return A tuple of user-relative panning vector, gain and delay for early reflections */ - std::tuple calculateEarlyReflectionsProperties() const; + std::tuple ComputeEarlyReflectionsProperties() const; /** * Applies an obstruction filter to the provided source if certain conditions apply. @@ -296,7 +296,7 @@ class SoundManager * various checks against the environment of the listener. * @param hardware_souce The index of the hardware source. */ - void updateObstructionFilter(const ALuint hardware_source) const; + void UpdateObstructionFilter(const ALuint hardware_source) const; }; /// @} diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 91d5f541c4..7c2cb2f44a 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -320,35 +320,35 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 camera_up = camera_node->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; - this->setListener(camera_position, camera_direction, camera_up, camera_velocity); - Ogre::Vector3 listener_position = sound_manager->getListenerPosition(); + SetListener(camera_position, camera_direction, camera_up, camera_velocity); + Ogre::Vector3 listener_position = sound_manager->GetListenerPosition(); const auto water = App::GetGameContext()->GetTerrain()->getWater(); - this->listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + m_listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); ActorPtr actor_of_player = App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling(); if (actor_of_player != nullptr) { - this->listener_is_inside_the_player_coupled_actor = actor_of_player->ar_bounding_box.contains(listener_position); + m_listener_is_inside_the_player_coupled_actor = actor_of_player->ar_bounding_box.contains(listener_position); } else { - this->listener_is_inside_the_player_coupled_actor = false; + m_listener_is_inside_the_player_coupled_actor = false; } - this->setListenerEnvironment(camera_position); - sound_manager->update(dt_sec); + SetListenerEnvironment(camera_position); + sound_manager->Update(dt_sec); } } -void SoundScriptManager::setListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) +void SoundScriptManager::SetListener(Vector3 position, Vector3 direction, Vector3 up, Vector3 velocity) { if (disabled) return; - sound_manager->setListener(position, direction, up, velocity); + sound_manager->SetListener(position, direction, up, velocity); } -void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) +void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) { if (disabled) return; @@ -357,9 +357,9 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) if (App::audio_engine_controls_environmental_audio->getBool()) { - if(this->listenerIsUnderwater()) + if(ListenerIsUnderwater()) { - sound_manager->setSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + sound_manager->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) /* According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in water and assuming the Air Absorption Gain HF property of OpenAL is set to the minimum of 0.892, @@ -370,39 +370,39 @@ void SoundScriptManager::setListenerEnvironment(Vector3 listener_position) } else { - sound_manager->setSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + sound_manager->SetSpeedOfSound(343.3f); // assume listener is in air at 20° celsius App::audio_air_absorption_factor->setVal(1.0f); App::audio_air_absorption_gain_hf->setVal(0.994f); } if (App::audio_enable_efx->getBool()) { - listener_reverb_properties = this->getReverbPresetAt(listener_position); + listener_reverb_properties = GetReverbPresetAt(listener_position); } } if (App::audio_enable_efx->getBool()) { // always update the environment in case it was changed via console or script - sound_manager->setListenerEnvironment(listener_reverb_properties); + sound_manager->SetListenerEnvironment(listener_reverb_properties); } } -const EFXEAXREVERBPROPERTIES* SoundScriptManager::getReverbPresetAt(const Ogre::Vector3 position) const +const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre::Vector3 position) const { if (!App::audio_force_listener_efx_preset->getStr().empty()) { return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); } - if (this->listener_is_inside_the_player_coupled_actor) + if (m_listener_is_inside_the_player_coupled_actor) { // the player is in a vehicle // there is no reverb preset for trucks, but this seems ok return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); } - if(this->listenerIsUnderwater()) + if(m_listener_is_underwater) { return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); } @@ -410,11 +410,11 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::getReverbPresetAt(const Ogre:: return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); } -void SoundScriptManager::setDopplerFactor(float doppler_factor) +void SoundScriptManager::SetDopplerFactor(float doppler_factor) { if (disabled) return; - sound_manager->setDopplerFactor(doppler_factor); + sound_manager->SetDopplerFactor(doppler_factor); } const StringVector& SoundScriptManager::getScriptPatterns(void) const diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index a9e543f2f7..c8065433e6 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -332,8 +332,8 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); - void setDopplerFactor(float doppler_factor); - void setListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); + void SetDopplerFactor(float doppler_factor); + void SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setLoadingBaseSounds(bool value) { loading_base = value; }; bool isDisabled() { return disabled; } @@ -343,12 +343,12 @@ class SoundScriptManager : public Ogre::ScriptLoader /** * @return True if the listener position is below water level. False otherwise. */ - bool listenerIsUnderwater() const { return listener_is_underwater; } + bool ListenerIsUnderwater() const { return m_listener_is_underwater; } /** * @return True if the listener position is inside the AABB of the actor the player character is coupled to. False otherwise. */ - bool listenerIsInsideThePlayerCoupledActor() const { return listener_is_inside_the_player_coupled_actor; } + bool ListenerIsInsideThePlayerCoupledActor() const { return m_listener_is_inside_the_player_coupled_actor; } SoundManager* getSoundManager() { return sound_manager; } @@ -360,8 +360,8 @@ class SoundScriptManager : public Ogre::ScriptLoader bool disabled; bool loading_base; - bool listener_is_underwater = false; - bool listener_is_inside_the_player_coupled_actor = false; + bool m_listener_is_underwater = false; + bool m_listener_is_inside_the_player_coupled_actor = false; float max_distance; float reference_distance; float rolloff_factor; @@ -390,8 +390,8 @@ class SoundScriptManager : public Ogre::ScriptLoader * its properties. * @return Reverb properties for the provided position. */ - const EFXEAXREVERBPROPERTIES* getReverbPresetAt(Ogre::Vector3 position) const; - void setListenerEnvironment(Ogre::Vector3 position); + const EFXEAXREVERBPROPERTIES* GetReverbPresetAt(Ogre::Vector3 position) const; + void SetListenerEnvironment(Ogre::Vector3 position); SoundManager* sound_manager; }; diff --git a/source/main/main.cpp b/source/main/main.cpp index efab4108fb..647d5522a6 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -933,7 +933,7 @@ int main(int argc, char *argv[]) App::sim_terrain_name->setStr(""); App::sim_terrain_gui_name->setStr(""); App::GetOutGauge()->Close(); - App::GetSoundScriptManager()->setListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); + App::GetSoundScriptManager()->SetListener(/*position:*/Ogre::Vector3::ZERO, /*direction:*/Ogre::Vector3::ZERO, /*up:*/Ogre::Vector3::UNIT_Y, /*velocity:*/Ogre::Vector3::ZERO); App::GetSoundScriptManager()->getSoundManager()->CleanUp(); } catch (...) @@ -1587,7 +1587,7 @@ int main(int argc, char *argv[]) { float* doppler_factor_ptr = static_cast(m.payload); LOG(fmt::format("Changing doppler factor to '{}' (from message bus)", *doppler_factor_ptr)); - App::GetSoundScriptManager()->getSoundManager()->setDopplerFactor(*doppler_factor_ptr); + App::GetSoundScriptManager()->getSoundManager()->SetDopplerFactor(*doppler_factor_ptr); delete doppler_factor_ptr; break; } diff --git a/source/main/system/ConsoleCmd.cpp b/source/main/system/ConsoleCmd.cpp index 11886dff55..99c4b4b679 100644 --- a/source/main/system/ConsoleCmd.cpp +++ b/source/main/system/ConsoleCmd.cpp @@ -376,7 +376,7 @@ class SpeedOfSoundCmd: public ConsoleCmd } else { - reply << _L("Current speed of sound: ") << sound_manager->getSpeedOfSound(); + reply << _L("Current speed of sound: ") << sound_manager->GetSpeedOfSound(); } App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, reply_type, reply.ToCStr()); @@ -429,7 +429,7 @@ class DopplerFactorCmd: public ConsoleCmd } else { - reply << _L("Doppler Factor is configured as: ") << "CVar (change requires restart): " << App::audio_doppler_factor->getFloat() << ", currently used by OpenAL: " << sound_manager->getDopplerFactor(); + reply << _L("Doppler Factor is configured as: ") << "CVar (change requires restart): " << App::audio_doppler_factor->getFloat() << ", currently used by OpenAL: " << sound_manager->GetDopplerFactor(); } } } From c441dc049a96f50127f32e13bea8f115921f90a3 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 07:51:03 +0200 Subject: [PATCH 063/104] :video_game: Disable obstruction filter for sources when the feature is disabled during playing --- source/main/audio/SoundManager.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index e27c75bcd6..bf099927eb 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -352,10 +352,7 @@ void SoundManager::Update(const float dt_sec) // update air absorption factor alSourcef(hardware_sources[source_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); - if(App::audio_enable_obstruction->getBool()) - { - this->UpdateObstructionFilter(hardware_sources[source_index]); - } + this->UpdateObstructionFilter(hardware_sources[source_index]); } this->UpdateListenerEffectSlot(dt_sec); @@ -699,6 +696,13 @@ void SoundManager::UpdateObstructionFilter(const ALuint hardware_source) const { // TODO: Simulate diffraction path. + if(!App::audio_enable_obstruction->getBool()) + { + // detach the obstruction filter in case it was attached when the feature was previously enabled + alSourcei(hardware_source, AL_DIRECT_FILTER, AL_FILTER_NULL); + return; + } + // find Sound the hardware_source belongs to SoundPtr corresponding_sound = nullptr; for(SoundPtr sound : audio_sources) From 926c21621070b1118f7ddaab2de9d14b36194cf9 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 07:54:36 +0200 Subject: [PATCH 064/104] :bug: Get error messages from OpenAL instead of integers/enum values --- source/main/audio/SoundManager.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index bf099927eb..3cccc88b68 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -156,11 +156,11 @@ SoundManager::SoundManager() alGetError(); this->alGenAuxiliaryEffectSlots(1, &m_listener_slot); - ALuint e = alGetError(); + ALuint error = alGetError(); - if (e != AL_NO_ERROR) + if (error != AL_NO_ERROR) { - LOG("SoundManager: alGenAuxiliaryEffectSlots for listener_slot failed: " + e); + LOG("SoundManager: alGenAuxiliaryEffectSlots for listener_slot failed: " + TOSTRING(alGetString(error))); m_listener_slot = AL_EFFECTSLOT_NULL; } } @@ -620,7 +620,7 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties error = alGetError(); if(error != AL_NO_ERROR) { - LOG("SoundManager: Could not create EFX effect:" + error); + LOG("SoundManager: Could not create EFX effect:" + TOSTRING(alGetString(error))); if(this->alIsEffect(effect)) this->alDeleteEffects(1, &effect); @@ -640,7 +640,7 @@ void SoundManager::DeleteAlEffect(const ALuint efx_effect_id) const error = alGetError(); if(error != AL_NO_ERROR) { - LOG("SoundManager: Could not delete EFX effect: " + error); + LOG("SoundManager: Could not delete EFX effect: " + TOSTRING(alGetString(error))); } } From ae6a3fa7e4155ed25d59bfc119120e54e3549dfa Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 08:52:39 +0200 Subject: [PATCH 065/104] :books: Update documentation of variables --- source/main/audio/SoundManager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index e6897b97ca..ee050c04eb 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -206,9 +206,9 @@ class SoundManager bool loadWAVFile(Ogre::String filename, ALuint buffer, Ogre::String resource_group_name = ""); // active audio sources (hardware sources) - int hardware_sources_num = 0; // total number of available hardware sources < MAX_HARDWARE_SOURCES + int hardware_sources_num = 0; //!< total number of allocated hardware sources (<= MAX_HARDWARE_SOURCES) int hardware_sources_in_use_count = 0; - int hardware_sources_map[MAX_HARDWARE_SOURCES]; // stores the hardware index for each source. -1 = unmapped + int hardware_sources_map[MAX_HARDWARE_SOURCES]; //!< maps from the index of a hardware source to the index of the audio source currently assigned to the corresponding hardware source. -1 = unmapped ALuint hardware_sources[MAX_HARDWARE_SOURCES]; // this buffer contains valid AL handles up to m_hardware_sources_num // audio sources From 6a9866b386caa2c8c3fb1d136a617cc46a59e39e Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 08:53:45 +0200 Subject: [PATCH 066/104] :bug: Track audio sources and buffers separately This is a revert of 491c3dd with some additions. Tracking them separately is necessary since multiple sounds at different locations might share the same sound file (buffer). --- source/main/audio/SoundManager.cpp | 25 ++++++++++++++----------- source/main/audio/SoundManager.h | 1 + 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 3cccc88b68..4f51959649 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -276,6 +276,8 @@ void SoundManager::CleanUp() m_efx_effect_id_map.erase(entry.first); } } + + // TODO: Delete Sounds and buffers } const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& efx_preset_name) const @@ -656,26 +658,26 @@ void SoundManager::recomputeAllSources() #if 0 if (!audio_device) return; - for (int i=0; i < audio_buffers_in_use_count; i++) + for (int i=0; i < m_audio_sources_in_use_count; i++) { audio_sources[i]->computeAudibility(m_listener_position); audio_sources_most_audible[i].first = i; audio_sources_most_audible[i].second = audio_sources[i]->audibility; } - // sort first 'num_hardware_sources' sources by audibility - // see: https://en.wikipedia.org/wiki/Selection_algorithm - if ((audio_buffers_in_use_count - 1) > hardware_sources_num) + // sort first 'num_hardware_sources' sources by audibility + // see: https://en.wikipedia.org/wiki/Selection_algorithm + if ((m_audio_sources_in_use_count - 1) > hardware_sources_num) { - std::nth_element(audio_sources_most_audible, audio_sources_most_audible+hardware_sources_num, audio_sources_most_audible + audio_buffers_in_use_count - 1, compareByAudibility); + std::nth_element(audio_sources_most_audible, audio_sources_most_audible+hardware_sources_num, audio_sources_most_audible + m_audio_sources_in_use_count - 1, compareByAudibility); } - // retire out of range sources first - for (int i=0; i < audio_buffers_in_use_count; i++) + // retire out of range sources first + for (int i=0; i < m_audio_sources_in_use_count; i++) { if (audio_sources[audio_sources_most_audible[i].first]->hardware_index != -1 && (i >= hardware_sources_num || audio_sources_most_audible[i].second == 0)) retire(audio_sources_most_audible[i].first); } - // assign new sources - for (int i=0; i < std::min(audio_buffers_in_use_count, hardware_sources_num); i++) + // assign new sources + for (int i=0; i < std::min(m_audio_sources_in_use_count, hardware_sources_num); i++) { if (audio_sources[audio_sources_most_audible[i].first]->hardware_index == -1 && audio_sources_most_audible[i].second > 0) { @@ -1005,11 +1007,12 @@ SoundPtr SoundManager::createSound(String filename, Ogre::String resource_group_ } buffer = audio_buffers[audio_buffers_in_use_count]; audio_buffer_file_name[audio_buffers_in_use_count] = filename; + audio_buffers_in_use_count++; } - audio_sources[audio_buffers_in_use_count] = new Sound(buffer, this, audio_buffers_in_use_count); + audio_sources[m_audio_sources_in_use_count] = new Sound(buffer, this, m_audio_sources_in_use_count); - return audio_sources[audio_buffers_in_use_count++]; + return audio_sources[m_audio_sources_in_use_count++]; } bool SoundManager::loadWAVFile(String filename, ALuint buffer, Ogre::String resource_group_name /*= ""*/) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index ee050c04eb..2cf528fb82 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -212,6 +212,7 @@ class SoundManager ALuint hardware_sources[MAX_HARDWARE_SOURCES]; // this buffer contains valid AL handles up to m_hardware_sources_num // audio sources + int m_audio_sources_in_use_count = 0; SoundPtr audio_sources[MAX_AUDIO_BUFFERS] = { nullptr }; // helper for calculating the most audible sources std::pair audio_sources_most_audible[MAX_AUDIO_BUFFERS]; From ba80d76c72a23c1a0148f826f178bd892821d070 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 10:51:23 +0200 Subject: [PATCH 067/104] :bug: Fix obstruction filter not getting updated in all cases --- source/main/audio/SoundManager.cpp | 182 +++++++++++++---------------- source/main/audio/SoundManager.h | 4 +- 2 files changed, 86 insertions(+), 100 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 4f51959649..14c4f5a28d 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -349,12 +349,12 @@ void SoundManager::Update(const float dt_sec) if(App::audio_enable_efx->getBool()) { // apply filters to sources when appropriate - for(int source_index = 0; source_index < hardware_sources_in_use_count; source_index++) + for(int hardware_index = 0; hardware_index < hardware_sources_num; hardware_index++) { // update air absorption factor - alSourcef(hardware_sources[source_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); - this->UpdateObstructionFilter(hardware_sources[source_index]); + this->UpdateObstructionFilter(hardware_index); } this->UpdateListenerEffectSlot(dt_sec); @@ -694,134 +694,120 @@ void SoundManager::recomputeAllSources() #endif } -void SoundManager::UpdateObstructionFilter(const ALuint hardware_source) const +void SoundManager::UpdateObstructionFilter(const int hardware_index) const { - // TODO: Simulate diffraction path. + if(hardware_sources_map[hardware_index] == -1) { return; } // no sound assigned to hardware source if(!App::audio_enable_obstruction->getBool()) { // detach the obstruction filter in case it was attached when the feature was previously enabled - alSourcei(hardware_source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); return; } - // find Sound the hardware_source belongs to - SoundPtr corresponding_sound = nullptr; - for(SoundPtr sound : audio_sources) + bool obstruction_detected = false; + const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; + + // TODO: Simulate diffraction path. + + // always obstruct sounds if the player is in a vehicle + if(App::GetSoundScriptManager()->ListenerIsInsideThePlayerCoupledActor()) { - if(sound != nullptr) - { - if (sound->getCurrentHardwareIndex() == hardware_source) - { - corresponding_sound = sound; - break; - } - } + obstruction_detected = true; } - - if (corresponding_sound != nullptr) + else { - bool obstruction_detected = false; - - // always obstruct sounds if the player is in a vehicle - if(App::GetSoundScriptManager()->ListenerIsInsideThePlayerCoupledActor()) + /* + * Perform various line of sight checks until either a collision was detected + * and the filter has to be applied or no obstruction was detected. + */ + + std::pair intersection; + // no normalisation due to how the intersectsTris function determines its number of steps + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; + Ogre::Real distance_to_sound = direction_to_sound.length(); + Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); + obstruction_detected = intersection.first; + + if(!obstruction_detected) { - obstruction_detected = true; + // perform line of sight check against collision meshes + // for this to work correctly, the direction vector of the ray must have + // the length of the distance from the listener to the sound + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + obstruction_detected = intersection.first; } - else - { - /* - * Perform various line of sight checks until either a collision was detected - * and the filter has to be applied or no obstruction was detected. - */ - - std::pair intersection; - // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; - Ogre::Real distance_to_sound = direction_to_sound.length(); - Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); - // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); - obstruction_detected = intersection.first; + // do not normalise before intersectsTris() due to how that function works + direction_to_sound.normalise(); + direct_path_to_sound.setDirection(direction_to_sound); - if(!obstruction_detected) + if(!obstruction_detected) + { + // perform line of sight check agains collision boxes + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) { - // perform line of sight check against collision meshes - // for this to work correctly, the direction vector of the ray must have - // the length of the distance from the listener to the sound - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstruction_detected = intersection.first; - } + if (!collision_box.enabled || collision_box.virt) { continue; } - // do not normalise before intersectsTris() due to how that function works - direction_to_sound.normalise(); - direct_path_to_sound.setDirection(direction_to_sound); - - if(!obstruction_detected) - { - // perform line of sight check agains collision boxes - for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); + if (intersection.first && intersection.second <= distance_to_sound) { - if (!collision_box.enabled || collision_box.virt) { continue; } - - intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); - if (intersection.first && intersection.second <= distance_to_sound) - { - obstruction_detected = true; - break; - } + obstruction_detected = true; + break; } } + } - if(!obstruction_detected) + if(!obstruction_detected) + { + // perform line of sight check against actors + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + bool soundsource_belongs_to_current_actor = false; + for(const ActorPtr actor : actors) { - // perform line of sight check against actors - const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); - bool soundsource_belongs_to_current_actor = false; - for(const ActorPtr actor : actors) + // Trucks shouldn't obstruct their own sound sources since the + // obstruction is most likely already contained in the recording. + for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) { - // Trucks shouldn't obstruct their own sound sources since the - // obstruction is most likely already contained in the recording. - for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) + const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; + const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); + for (int num_sound = 0; num_sound < num_sounds; ++num_sound) { - const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; - const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); - for (int num_sound = 0; num_sound < num_sounds; ++num_sound) + if (soundsource.ssi->getSound(num_sound) == corresponding_sound) { - if (soundsource.ssi->getSound(num_sound) == corresponding_sound) - { - soundsource_belongs_to_current_actor = true; - } + soundsource_belongs_to_current_actor = true; } - if (soundsource_belongs_to_current_actor) { break; } } + if (soundsource_belongs_to_current_actor) { break; } + } - if (soundsource_belongs_to_current_actor) - { - continue; - } + if (soundsource_belongs_to_current_actor) + { + continue; + } - intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); - obstruction_detected = intersection.first; - if (obstruction_detected) - { - break; - } + intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); + obstruction_detected = intersection.first; + if (obstruction_detected) + { + break; } } } + } - if(obstruction_detected) - { - // Apply obstruction filter to the source - alSourcei(hardware_source, AL_DIRECT_FILTER, m_efx_outdoor_obstruction_lowpass_filter_id); - } - else - { - // reset direct filter for the source in case it has been set previously - alSourcei(hardware_source, AL_DIRECT_FILTER, AL_FILTER_NULL); - } + if(obstruction_detected) + { + // Apply obstruction filter to the source + alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, m_efx_outdoor_obstruction_lowpass_filter_id); + } + else + { + // reset direct filter for the source in case it has been set previously + alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); } } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 2cf528fb82..4a6bd3a35f 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -295,9 +295,9 @@ class SoundManager * Applies an obstruction filter to the provided source if certain conditions apply. * To decide whether the filter should be applied or not, the function performs * various checks against the environment of the listener. - * @param hardware_souce The index of the hardware source. + * @param hardware_index The index of the hardware source. */ - void UpdateObstructionFilter(const ALuint hardware_source) const; + void UpdateObstructionFilter(const int hardware_index) const; }; /// @} From ae24b34ac3ff3d276811ad3096bd1d3973e31c69 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 11:15:01 +0200 Subject: [PATCH 068/104] :bug: Update obstruction filter before playing a source to avoid pop-ins --- source/main/audio/SoundManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 14c4f5a28d..f7dc9395f1 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -835,7 +835,9 @@ void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vect // update the AL settings switch (reason) { - case Sound::REASON_PLAY: alSourcePlay(hw_source); + case Sound::REASON_PLAY: + this->UpdateObstructionFilter(audio_sources[source_index]->hardware_index); + alSourcePlay(hw_source); break; case Sound::REASON_STOP: alSourceStop(hw_source); break; @@ -914,6 +916,7 @@ void SoundManager::assign(int source_index, int hardware_index) if (audio_source->should_play) { + this->UpdateObstructionFilter(hardware_index); alSourcePlay(hw_source); } From 9d022cb1521510de3ba2101bc1140a180dc8e846 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 11:44:26 +0200 Subject: [PATCH 069/104] :video_game: Add option to force efx preset to top menu --- source/main/gui/panels/GUI_TopMenubar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/main/gui/panels/GUI_TopMenubar.cpp b/source/main/gui/panels/GUI_TopMenubar.cpp index 2b1e4405bd..6750ab18f0 100644 --- a/source/main/gui/panels/GUI_TopMenubar.cpp +++ b/source/main/gui/panels/GUI_TopMenubar.cpp @@ -571,6 +571,11 @@ void TopMenubar::Draw(float dt) ImGui::PushItemWidth(125.f); // Width includes [+/-] buttons ImGui::TextColored(GRAY_HINT_TEXT, "%s", _LC("TopMenubar", "Audio:")); DrawGFloatSlider(App::audio_master_volume, _LC("TopMenubar", "Volume"), 0, 1); + + static Str<1000> buf_audio_force_listener_efx_preset; + buf_audio_force_listener_efx_preset.Assign(App::audio_force_listener_efx_preset->getStr().c_str()); + DrawGTextEdit(App::audio_force_listener_efx_preset, _LC("TopMenubar", "Force Listener EFX Preset"), buf_audio_force_listener_efx_preset); + ImGui::Separator(); ImGui::TextColored(GRAY_HINT_TEXT, "%s", _LC("TopMenubar", "Frames per second:")); if (App::gfx_envmap_enabled->getBool()) From 22af2aaa4a86dedd962cb72be05a4e7e3833d433 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 14:05:38 +0200 Subject: [PATCH 070/104] :video_game: Add a few more EFX presets --- source/main/audio/SoundManager.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f7dc9395f1..3868386335 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -297,6 +297,7 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& void SoundManager::PrepopulateEfxPropertiesMap() { m_efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; + m_efx_properties_map["EFX_REVERB_PRESET_ROOM"] = EFX_REVERB_PRESET_ROOM; m_efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; m_efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; m_efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; @@ -310,9 +311,29 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; m_efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; m_efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_LARGEROOM"] = EFX_REVERB_PRESET_CASTLE_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_HALL"] = EFX_REVERB_PRESET_CASTLE_HALL; m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SMALLROOM"] = EFX_REVERB_PRESET_FACTORY_SMALLROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE"] = EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_MEDIUMROOM"] = EFX_REVERB_PRESET_FACTORY_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LARGEROOM"] = EFX_REVERB_PRESET_FACTORY_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LONGPASSAGE"] = EFX_REVERB_PRESET_FACTORY_LONGPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_COURTYARD"] = EFX_REVERB_PRESET_FACTORY_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_ALCOVE"] = EFX_REVERB_PRESET_FACTORY_ALCOVE; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM"] = EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LARGEROOM"] = EFX_REVERB_PRESET_SPACESTATION_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE"] = EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_HALL"] = EFX_REVERB_PRESET_SPACESTATION_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_MEDIUMROOM"] = EFX_REVERB_PRESET_WOODEN_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LARGEROOM"] = EFX_REVERB_PRESET_WOODEN_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LONGPASSAGE"] = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_HALL"] = EFX_REVERB_PRESET_WOODEN_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_COURTYARD"] = EFX_REVERB_PRESET_WOODEN_COURTYARD; m_efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_FULLSTADIUM"] = EFX_REVERB_PRESET_SPORT_FULLSTADIUM; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_STADIUMTANNOY"] = EFX_REVERB_PRESET_SPORT_STADIUMTANNOY; m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; @@ -331,6 +352,8 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND; m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; m_efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; m_efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; From d9ac309742a1cd61c38cbcaffe8ef2b0275d40bb Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 14:09:33 +0200 Subject: [PATCH 071/104] :triangular_ruler: Prettify alignment of assignments --- source/main/audio/SoundManager.cpp | 126 ++++++++++++++--------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 3868386335..5f0d802a57 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -296,69 +296,69 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetEfxProperties(const std::string& void SoundManager::PrepopulateEfxPropertiesMap() { - m_efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; - m_efx_properties_map["EFX_REVERB_PRESET_ROOM"] = EFX_REVERB_PRESET_ROOM; - m_efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; - m_efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; - m_efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; - m_efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; - m_efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; - m_efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; - m_efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; - m_efx_properties_map["EFX_REVERB_PRESET_QUARRY"] = EFX_REVERB_PRESET_QUARRY; - m_efx_properties_map["EFX_REVERB_PRESET_PLAIN"] = EFX_REVERB_PRESET_PLAIN; - m_efx_properties_map["EFX_REVERB_PRESET_PARKINGLOT"] = EFX_REVERB_PRESET_PARKINGLOT; - m_efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; - m_efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; - m_efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; - m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_LARGEROOM"] = EFX_REVERB_PRESET_CASTLE_LARGEROOM; - m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_HALL"] = EFX_REVERB_PRESET_CASTLE_HALL; - m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SMALLROOM"] = EFX_REVERB_PRESET_FACTORY_SMALLROOM; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE"] = EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_MEDIUMROOM"] = EFX_REVERB_PRESET_FACTORY_MEDIUMROOM; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LARGEROOM"] = EFX_REVERB_PRESET_FACTORY_LARGEROOM; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LONGPASSAGE"] = EFX_REVERB_PRESET_FACTORY_LONGPASSAGE; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_COURTYARD"] = EFX_REVERB_PRESET_FACTORY_COURTYARD; - m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_ALCOVE"] = EFX_REVERB_PRESET_FACTORY_ALCOVE; - m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM"] = EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM; - m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LARGEROOM"] = EFX_REVERB_PRESET_SPACESTATION_LARGEROOM; - m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE"] = EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE; - m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_HALL"] = EFX_REVERB_PRESET_SPACESTATION_HALL; - m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_MEDIUMROOM"] = EFX_REVERB_PRESET_WOODEN_MEDIUMROOM; - m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LARGEROOM"] = EFX_REVERB_PRESET_WOODEN_LARGEROOM; - m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LONGPASSAGE"] = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE; - m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_HALL"] = EFX_REVERB_PRESET_WOODEN_HALL; - m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_COURTYARD"] = EFX_REVERB_PRESET_WOODEN_COURTYARD; - m_efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; - m_efx_properties_map["EFX_REVERB_PRESET_SPORT_FULLSTADIUM"] = EFX_REVERB_PRESET_SPORT_FULLSTADIUM; - m_efx_properties_map["EFX_REVERB_PRESET_SPORT_STADIUMTANNOY"] = EFX_REVERB_PRESET_SPORT_STADIUMTANNOY; - m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; - m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; - m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; - m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; - m_efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; - m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_BACKYARD"] = EFX_REVERB_PRESET_OUTDOORS_BACKYARD; - m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS"] = EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS; - m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON"] = EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON; - m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_CREEK"] = EFX_REVERB_PRESET_OUTDOORS_CREEK; - m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_VALLEY"] = EFX_REVERB_PRESET_OUTDOORS_VALLEY; - m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HEAVEN"] = EFX_REVERB_PRESET_MOOD_HEAVEN; - m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HELL"] = EFX_REVERB_PRESET_MOOD_HELL; - m_efx_properties_map["EFX_REVERB_PRESET_MOOD_MEMORY"] = EFX_REVERB_PRESET_MOOD_MEMORY; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_COMMENTATOR"] = EFX_REVERB_PRESET_DRIVING_COMMENTATOR; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_PITGARAGE"] = EFX_REVERB_PRESET_DRIVING_PITGARAGE; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND; - m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; - m_efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; - m_efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; - m_efx_properties_map["EFX_REVERB_PRESET_CITY_UNDERPASS"] = EFX_REVERB_PRESET_CITY_UNDERPASS; - m_efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; + m_efx_properties_map["EFX_REVERB_PRESET_GENERIC"] = EFX_REVERB_PRESET_GENERIC; + m_efx_properties_map["EFX_REVERB_PRESET_ROOM"] = EFX_REVERB_PRESET_ROOM; + m_efx_properties_map["EFX_REVERB_PRESET_CAVE"] = EFX_REVERB_PRESET_CAVE; + m_efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; + m_efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; + m_efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; + m_efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; + m_efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; + m_efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; + m_efx_properties_map["EFX_REVERB_PRESET_QUARRY"] = EFX_REVERB_PRESET_QUARRY; + m_efx_properties_map["EFX_REVERB_PRESET_PLAIN"] = EFX_REVERB_PRESET_PLAIN; + m_efx_properties_map["EFX_REVERB_PRESET_PARKINGLOT"] = EFX_REVERB_PRESET_PARKINGLOT; + m_efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; + m_efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; + m_efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_LARGEROOM"] = EFX_REVERB_PRESET_CASTLE_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_HALL"] = EFX_REVERB_PRESET_CASTLE_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SMALLROOM"] = EFX_REVERB_PRESET_FACTORY_SMALLROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE"] = EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_MEDIUMROOM"] = EFX_REVERB_PRESET_FACTORY_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LARGEROOM"] = EFX_REVERB_PRESET_FACTORY_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_LONGPASSAGE"] = EFX_REVERB_PRESET_FACTORY_LONGPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_COURTYARD"] = EFX_REVERB_PRESET_FACTORY_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_ALCOVE"] = EFX_REVERB_PRESET_FACTORY_ALCOVE; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM"] = EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LARGEROOM"] = EFX_REVERB_PRESET_SPACESTATION_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE"] = EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_HALL"] = EFX_REVERB_PRESET_SPACESTATION_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_MEDIUMROOM"] = EFX_REVERB_PRESET_WOODEN_MEDIUMROOM; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LARGEROOM"] = EFX_REVERB_PRESET_WOODEN_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LONGPASSAGE"] = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_HALL"] = EFX_REVERB_PRESET_WOODEN_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_COURTYARD"] = EFX_REVERB_PRESET_WOODEN_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_FULLSTADIUM"] = EFX_REVERB_PRESET_SPORT_FULLSTADIUM; + m_efx_properties_map["EFX_REVERB_PRESET_SPORT_STADIUMTANNOY"] = EFX_REVERB_PRESET_SPORT_STADIUMTANNOY; + m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; + m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; + m_efx_properties_map["EFX_REVERB_PRESET_PIPE_RESONANT"] = EFX_REVERB_PRESET_PIPE_RESONANT; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_BACKYARD"] = EFX_REVERB_PRESET_OUTDOORS_BACKYARD; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS"] = EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON"] = EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_CREEK"] = EFX_REVERB_PRESET_OUTDOORS_CREEK; + m_efx_properties_map["EFX_REVERB_PRESET_OUTDOORS_VALLEY"] = EFX_REVERB_PRESET_OUTDOORS_VALLEY; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HEAVEN"] = EFX_REVERB_PRESET_MOOD_HEAVEN; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_HELL"] = EFX_REVERB_PRESET_MOOD_HELL; + m_efx_properties_map["EFX_REVERB_PRESET_MOOD_MEMORY"] = EFX_REVERB_PRESET_MOOD_MEMORY; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_COMMENTATOR"] = EFX_REVERB_PRESET_DRIVING_COMMENTATOR; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_PITGARAGE"] = EFX_REVERB_PRESET_DRIVING_PITGARAGE; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_RACER"] = EFX_REVERB_PRESET_DRIVING_INCAR_RACER; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"] = EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY"] = EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND"] = EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND; + m_efx_properties_map["EFX_REVERB_PRESET_DRIVING_TUNNEL"] = EFX_REVERB_PRESET_DRIVING_TUNNEL; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_STREETS"] = EFX_REVERB_PRESET_CITY_STREETS; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_SUBWAY"] = EFX_REVERB_PRESET_CITY_SUBWAY; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_UNDERPASS"] = EFX_REVERB_PRESET_CITY_UNDERPASS; + m_efx_properties_map["EFX_REVERB_PRESET_CITY_ABANDONED"] = EFX_REVERB_PRESET_CITY_ABANDONED; } void SoundManager::Update(const float dt_sec) From 343e342f39238a7f69b64bf596f0e433fc8c4bd7 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 19 Oct 2024 15:41:33 +0200 Subject: [PATCH 072/104] :video_game: Add a few more efx reverb presets --- source/main/audio/SoundManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5f0d802a57..2b02eb1bbd 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -302,6 +302,7 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_ARENA"] = EFX_REVERB_PRESET_ARENA; m_efx_properties_map["EFX_REVERB_PRESET_HANGAR"] = EFX_REVERB_PRESET_HANGAR; m_efx_properties_map["EFX_REVERB_PRESET_ALLEY"] = EFX_REVERB_PRESET_ALLEY; + m_efx_properties_map["EFX_REVERB_PRESET_HALLWAY"] = EFX_REVERB_PRESET_HALLWAY; m_efx_properties_map["EFX_REVERB_PRESET_FOREST"] = EFX_REVERB_PRESET_FOREST; m_efx_properties_map["EFX_REVERB_PRESET_CITY"] = EFX_REVERB_PRESET_CITY; m_efx_properties_map["EFX_REVERB_PRESET_MOUNTAINS"] = EFX_REVERB_PRESET_MOUNTAINS; @@ -311,7 +312,9 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_UNDERWATER"] = EFX_REVERB_PRESET_UNDERWATER; m_efx_properties_map["EFX_REVERB_PRESET_DRUGGED"] = EFX_REVERB_PRESET_DRUGGED; m_efx_properties_map["EFX_REVERB_PRESET_DIZZY"] = EFX_REVERB_PRESET_DIZZY; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE"] = EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_LARGEROOM"] = EFX_REVERB_PRESET_CASTLE_LARGEROOM; + m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_LONGPASSAGE"] = EFX_REVERB_PRESET_CASTLE_LONGPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_HALL"] = EFX_REVERB_PRESET_CASTLE_HALL; m_efx_properties_map["EFX_REVERB_PRESET_CASTLE_COURTYARD"] = EFX_REVERB_PRESET_CASTLE_COURTYARD; m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_SMALLROOM"] = EFX_REVERB_PRESET_FACTORY_SMALLROOM; @@ -322,10 +325,14 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_HALL"] = EFX_REVERB_PRESET_FACTORY_HALL; m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_COURTYARD"] = EFX_REVERB_PRESET_FACTORY_COURTYARD; m_efx_properties_map["EFX_REVERB_PRESET_FACTORY_ALCOVE"] = EFX_REVERB_PRESET_FACTORY_ALCOVE; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_SMALLROOM"] = EFX_REVERB_PRESET_SPACESTATION_SMALLROOM; + m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE"] = EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM"] = EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM; m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LARGEROOM"] = EFX_REVERB_PRESET_SPACESTATION_LARGEROOM; m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE"] = EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_SPACESTATION_HALL"] = EFX_REVERB_PRESET_SPACESTATION_HALL; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_SMALLROOM"] = EFX_REVERB_PRESET_WOODEN_SMALLROOM; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE"] = EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_MEDIUMROOM"] = EFX_REVERB_PRESET_WOODEN_MEDIUMROOM; m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LARGEROOM"] = EFX_REVERB_PRESET_WOODEN_LARGEROOM; m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LONGPASSAGE"] = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE; @@ -335,6 +342,7 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_SPORT_FULLSTADIUM"] = EFX_REVERB_PRESET_SPORT_FULLSTADIUM; m_efx_properties_map["EFX_REVERB_PRESET_SPORT_STADIUMTANNOY"] = EFX_REVERB_PRESET_SPORT_STADIUMTANNOY; m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_WORKSHOP"] = EFX_REVERB_PRESET_PREFAB_WORKSHOP; + m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_OUTHOUSE"] = EFX_REVERB_PRESET_PREFAB_OUTHOUSE; m_efx_properties_map["EFX_REVERB_PRESET_PREFAB_CARAVAN"] = EFX_REVERB_PRESET_PREFAB_CARAVAN; m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LARGE"] = EFX_REVERB_PRESET_PIPE_LARGE; m_efx_properties_map["EFX_REVERB_PRESET_PIPE_LONGTHIN"] = EFX_REVERB_PRESET_PIPE_LONGTHIN; From 9291a234b8c5c6449887aa8fc740b75956733764 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 08:21:51 +0200 Subject: [PATCH 073/104] :sparkles: Add option to boxes for defining reverb presets --- source/main/audio/SoundScriptManager.cpp | 14 ++++++++++++++ source/main/physics/SimData.h | 1 + source/main/physics/collision/Collisions.cpp | 8 +++++++- source/main/physics/collision/Collisions.h | 2 +- .../resources/odef_fileformat/ODefFileFormat.cpp | 8 ++++++++ .../resources/odef_fileformat/ODefFileFormat.h | 7 +++++-- source/main/terrain/TerrainObjectManager.cpp | 5 +++-- 7 files changed, 39 insertions(+), 6 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 7c2cb2f44a..8bd8bc5424 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -407,6 +407,20 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); } + // check if position is inside a collision box with a reverb_preset assigned to it + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + { + if (!collision_box.reverb_preset_name.empty()) + { + const Ogre::AxisAlignedBox collision_box_aab = Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi); + + if(collision_box_aab.contains(position)) + { + return sound_manager->GetEfxProperties(collision_box.reverb_preset_name); + } + } + } + return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); } diff --git a/source/main/physics/SimData.h b/source/main/physics/SimData.h index 212a7245ad..a8b3f3cacf 100644 --- a/source/main/physics/SimData.h +++ b/source/main/physics/SimData.h @@ -731,6 +731,7 @@ struct collision_box_t Ogre::Vector3 rehi; //!< relative collision box Ogre::Vector3 campos; //!< camera position Ogre::Vector3 debug_verts[8];//!< box corners in absolute world position + std::string reverb_preset_name; //!< name of the reverb preset that applies to the inside of the collision box }; typedef std::vector CollisionBoxPtrVec; diff --git a/source/main/physics/collision/Collisions.cpp b/source/main/physics/collision/Collisions.cpp index ba57620506..e4c8523a82 100644 --- a/source/main/physics/collision/Collisions.cpp +++ b/source/main/physics/collision/Collisions.cpp @@ -398,7 +398,7 @@ int Collisions::hash_find(int cell_x, int cell_z) return static_cast(pos); } -int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String &eventname, const Ogre::String &instancename, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc /* = Vector3::UNIT_SCALE */, Ogre::Vector3 dr /* = Vector3::ZERO */, CollisionEventFilter event_filter /* = EVENT_ALL */, int scripthandler /* = -1 */) +int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String &eventname, const Ogre::String &instancename, const Ogre::String& reverb_preset_name, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc /* = Vector3::UNIT_SCALE */, Ogre::Vector3 dr /* = Vector3::ZERO */, CollisionEventFilter event_filter /* = EVENT_ALL */, int scripthandler /* = -1 */) { Quaternion rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z); Quaternion direction = Quaternion(Degree(dr.x), Vector3::UNIT_X) * Quaternion(Degree(dr.y), Vector3::UNIT_Y) * Quaternion(Degree(dr.z), Vector3::UNIT_Z); @@ -428,6 +428,12 @@ int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vec coll_box.campos = coll_box.center + rotation * campos; } + // audio stuff + if (!reverb_preset_name.empty()) + { + coll_box.reverb_preset_name = reverb_preset_name; + } + // first, self-rotate if (rotating) { diff --git a/source/main/physics/collision/Collisions.h b/source/main/physics/collision/Collisions.h index 0676711a97..97059da654 100644 --- a/source/main/physics/collision/Collisions.h +++ b/source/main/physics/collision/Collisions.h @@ -201,7 +201,7 @@ class Collisions void finishLoadingTerrain(); - int addCollisionBox(bool rotating, bool virt, Ogre::Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String& eventname, const Ogre::String& instancename, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc = Ogre::Vector3::UNIT_SCALE, Ogre::Vector3 dr = Ogre::Vector3::ZERO, CollisionEventFilter event_filter = EVENT_ALL, int scripthandler = -1); + int addCollisionBox(bool rotating, bool virt, Ogre::Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String& eventname, const Ogre::String& instancename, const Ogre::String& reverb_preset_name, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc = Ogre::Vector3::UNIT_SCALE, Ogre::Vector3 dr = Ogre::Vector3::ZERO, CollisionEventFilter event_filter = EVENT_ALL, int scripthandler = -1); void addCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, Ogre::Quaternion const& q, Ogre::Vector3 const& scale, ground_model_t* gm = 0, std::vector* collTris = 0); //!< generate collision tris from existing mesh resource void registerCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, Ogre::AxisAlignedBox bounding_box, ground_model_t* gm, int ctri_start, int ctri_count); //!< Mark already generated collision tris as belonging to (virtual) mesh. int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t* gm); diff --git a/source/main/resources/odef_fileformat/ODefFileFormat.cpp b/source/main/resources/odef_fileformat/ODefFileFormat.cpp index e1bf987251..0d43524ffd 100644 --- a/source/main/resources/odef_fileformat/ODefFileFormat.cpp +++ b/source/main/resources/odef_fileformat/ODefFileFormat.cpp @@ -278,12 +278,19 @@ bool ODefParser::ProcessCurrentLine() // hack to avoid fps drops near spawnzones if (!strncmp(ev_name, "spawnzone", 9)) { m_ctx.cbox_event_filter = EVENT_AVATAR; } } + else if (StartsWith(line_str, "reverb_preset")) + { + char tmp[200] = ""; + sscanf(line_str.c_str(), "reverb_preset %199s", tmp); + m_ctx.cbox_reverb_preset_name = tmp; + } else if (line_str == "endbox") { m_def->collision_boxes.emplace_back( m_ctx.cbox_aabb_min, m_ctx.cbox_aabb_max, m_ctx.cbox_rotation, m_ctx.cbox_cam_pos, m_ctx.cbox_direction, m_ctx.header_scale, + m_ctx.cbox_reverb_preset_name, m_ctx.cbox_event_name, m_ctx.cbox_event_filter, m_ctx.cbox_is_rotating, m_ctx.cbox_is_virtual, m_ctx.cbox_force_cam); } @@ -309,6 +316,7 @@ void ODefParser::ResetCBoxContext() m_ctx.cbox_event_filter = EVENT_NONE; m_ctx.cbox_event_name.clear(); m_ctx.cbox_mesh_name.clear(); + m_ctx.cbox_reverb_preset_name.clear(); m_ctx.cbox_groundmodel_name = "concrete"; } diff --git a/source/main/resources/odef_fileformat/ODefFileFormat.h b/source/main/resources/odef_fileformat/ODefFileFormat.h index 5b06950179..65c1d42573 100644 --- a/source/main/resources/odef_fileformat/ODefFileFormat.h +++ b/source/main/resources/odef_fileformat/ODefFileFormat.h @@ -38,10 +38,11 @@ struct ODefCollisionBox { ODefCollisionBox(Ogre::Vector3 min, Ogre::Vector3 max, Ogre::Vector3 rot, Ogre::Vector3 campos, Ogre::Vector3 dir, Ogre::Vector3 scal, - std::string ev_name, CollisionEventFilter ev_filter, bool is_rot, bool is_virt, bool forcecam): + std::string reverb_preset_name, std::string ev_name, CollisionEventFilter ev_filter, + bool is_rot, bool is_virt, bool forcecam): aabb_min(min), aabb_max(max), box_rot(rot), cam_pos(campos), direction(dir), scale(scal), - event_name(ev_name), event_filter(ev_filter), + reverb_preset_name(reverb_preset_name), event_name(ev_name), event_filter(ev_filter), is_rotating(is_rot), is_virtual(is_virt), force_cam_pos(forcecam) {} @@ -51,6 +52,7 @@ struct ODefCollisionBox Ogre::Vector3 cam_pos; Ogre::Vector3 direction; Ogre::Vector3 scale; + std::string reverb_preset_name; std::string event_name; CollisionEventFilter event_filter; @@ -167,6 +169,7 @@ class ODefParser CollisionEventFilter cbox_event_filter; std::string cbox_event_name; std::string cbox_mesh_name; + std::string cbox_reverb_preset_name; std::string cbox_groundmodel_name; Ogre::Vector3 cbox_aabb_min; Ogre::Vector3 cbox_aabb_max; diff --git a/source/main/terrain/TerrainObjectManager.cpp b/source/main/terrain/TerrainObjectManager.cpp index 4ad8314d1a..9ae584f104 100644 --- a/source/main/terrain/TerrainObjectManager.cpp +++ b/source/main/terrain/TerrainObjectManager.cpp @@ -1044,8 +1044,9 @@ void TerrainObjectManager::ProcessODefCollisionBoxes(StaticObject* obj, ODefFile int boxnum = terrainManager->GetCollisions()->addCollisionBox( cbox.is_rotating, cbox.is_virtual, params.position, params.rotation, cbox.aabb_min, cbox.aabb_max, cbox.box_rot, cbox.event_name, - params.instance_name, cbox.force_cam_pos, cbox.cam_pos, - cbox.scale, cbox.direction, cbox.event_filter, params.script_handler); + params.instance_name, cbox.reverb_preset_name, cbox.force_cam_pos, + cbox.cam_pos, cbox.scale, cbox.direction, cbox.event_filter, + params.script_handler); obj->collBoxes.push_back(boxnum); } From 1ad8791096e31872288946443b89f6781428a5a1 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 08:23:41 +0200 Subject: [PATCH 074/104] :video_game: Define reverb presets for some of the prefab models --- resources/meshes/ferryslip.odef | 7 +++++++ resources/meshes/hangar.odef | 1 + resources/meshes/myhangar2.odef | 2 ++ resources/meshes/truckshop.odef | 1 + 4 files changed, 11 insertions(+) diff --git a/resources/meshes/ferryslip.odef b/resources/meshes/ferryslip.odef index 9d7ca5824e..e8a88f41c2 100644 --- a/resources/meshes/ferryslip.odef +++ b/resources/meshes/ferryslip.odef @@ -3,4 +3,11 @@ ferryslip.mesh beginmesh mesh ferryslipcol.mesh endmesh + +beginbox +boxcoords -8.1, 8.2, 6.9, 9.5, -4.7, -2.3 +virtual +reverb_preset EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE +endbox + end \ No newline at end of file diff --git a/resources/meshes/hangar.odef b/resources/meshes/hangar.odef index 64d6f0b1c3..2f81334d9d 100644 --- a/resources/meshes/hangar.odef +++ b/resources/meshes/hangar.odef @@ -16,6 +16,7 @@ beginbox boxcoords -17, 17, 0, 4.5, -29, 4 virtual event spawnzone +reverb_preset EFX_REVERB_PRESET_FACTORY_HALL direction 0, 90, 0 endbox diff --git a/resources/meshes/myhangar2.odef b/resources/meshes/myhangar2.odef index b838858b71..388a848a8a 100644 --- a/resources/meshes/myhangar2.odef +++ b/resources/meshes/myhangar2.odef @@ -74,12 +74,14 @@ endbox beginbox boxcoords -11.5, -2.1, -0.5, 3.0, -9.70, -7.5 virtual +reverb_preset EFX_REVERB_PRESET_ROOM event repair avatar endbox beginbox boxcoords -12.0, 12.0, -0.5, 5.5, -7.0, 7.0 virtual +reverb_preset EFX_REVERB_PRESET_FACTORY_SMALLROOM forcecamera 11.35, 5.06, 6.41 endbox diff --git a/resources/meshes/truckshop.odef b/resources/meshes/truckshop.odef index 2463c38aa5..961949088a 100644 --- a/resources/meshes/truckshop.odef +++ b/resources/meshes/truckshop.odef @@ -20,6 +20,7 @@ endbox beginbox boxcoords -12.0, 12.0, -0.5, 5.5, -7.0, 7.0 virtual +reverb_preset EFX_REVERB_PRESET_FACTORY_LARGEROOM forcecamera 11.35, 5.06, 6.41 endbox From 39cab9a4391da5ea3115183285af91493f18a61c Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 09:48:59 +0200 Subject: [PATCH 075/104] :wrench: Only return listener-relevant presets if the the listener is queried In preparation for potentially supporting multiple reverb environments at the same time, listener-specific stuff is now only returned when the queried position equals that of the listener --- source/main/audio/SoundScriptManager.cpp | 37 +++++++++++++++--------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 8bd8bc5424..b138c6b422 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -390,21 +390,25 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre::Vector3 position) const { - if (!App::audio_force_listener_efx_preset->getStr().empty()) + // for the listener we do additional checks + if(position == sound_manager->GetListenerPosition()) { - return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); - } + if (!App::audio_force_listener_efx_preset->getStr().empty()) + { + return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); + } - if (m_listener_is_inside_the_player_coupled_actor) - { - // the player is in a vehicle - // there is no reverb preset for trucks, but this seems ok - return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); - } + if (m_listener_is_inside_the_player_coupled_actor) + { + // the player is in a vehicle + // there is no reverb preset for trucks, but this seems ok + return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); + } - if(m_listener_is_underwater) - { - return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); + if(m_listener_is_underwater) + { + return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); + } } // check if position is inside a collision box with a reverb_preset assigned to it @@ -421,7 +425,14 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: } } - return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); + if(position == sound_manager->GetListenerPosition()) + { + return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); + } + else + { + return nullptr; + } } void SoundScriptManager::SetDopplerFactor(float doppler_factor) From 9b908a336a64d985664c455f8bad8425169af3ab Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 10:12:17 +0200 Subject: [PATCH 076/104] :wrench: Return water reverb preset for any position below water level/waves --- source/main/audio/SoundScriptManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index b138c6b422..d52b6a8710 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -404,11 +404,13 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: // there is no reverb preset for trucks, but this seems ok return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); } + } - if(m_listener_is_underwater) - { - return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); - } + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool position_is_underwater = (water != nullptr ? water->IsUnderWater(position) : false); + if(position_is_underwater) + { + return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); } // check if position is inside a collision box with a reverb_preset assigned to it From 29fbaea341d6c7940100eb68cfbefc383e963485 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 10:17:47 +0200 Subject: [PATCH 077/104] :video_game: Do not return a reverb preset if the listener inside a truck This change was made for two reasons: The DRIVING_INCAR_SPORTS preset had too much reverb as became obvious with the obstruction filter enabled. Most importantly though, not all trucks (always) have a closed cabin; hence some differentiation would be needed. --- source/main/audio/SoundScriptManager.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index d52b6a8710..dc092080d8 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -397,13 +397,6 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: { return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); } - - if (m_listener_is_inside_the_player_coupled_actor) - { - // the player is in a vehicle - // there is no reverb preset for trucks, but this seems ok - return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS"); - } } const auto water = App::GetGameContext()->GetTerrain()->getWater(); From b0495318a9e1bca981402dcc652ab0ccca43541b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 15:36:51 +0200 Subject: [PATCH 078/104] :video_game: Also consider nearby collision boxes and actors for reflection panning --- source/main/audio/SoundManager.cpp | 47 ++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 2b02eb1bbd..5dd956eafb 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -523,27 +523,64 @@ std::tuple SoundManager::ComputeEarlyReflectionsPro * To detect surfaces around the listener within the vicinity of * max_distance, we cast rays counter-clockwise in a 360° circle * around the listener on a horizontal plane realative to the listener. - */ + */ bool nearby_surface_detected = false; const float angle_step_size = 90; float closest_surface_distance = std::numeric_limits::max(); for (float angle = 0; angle < 360; angle += angle_step_size) { + float closest_surface_distance_in_this_direction = std::numeric_limits::max(); Ogre::Vector3 raycast_direction = Quaternion(Ogre::Degree(angle), m_listener_up) * m_listener_direction; raycast_direction.normalise(); // accompany direction vector for how the intersectsTris function works + + // check for nearby collision meshes Ray ray = Ray(m_listener_position, raycast_direction * max_distance * App::GetGameContext()->GetTerrain()->GetCollisions()->GetCellSize()); std::pair intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(ray); if (intersection.first) { - nearby_surface_detected = true; - early_reflections_pan += raycast_direction * max_distance * intersection.second; - closest_surface_distance = std::min(intersection.second, closest_surface_distance); + closest_surface_distance_in_this_direction = intersection.second * max_distance; + } + + ray.setDirection(ray.getDirection().normalisedCopy()); + + // check for nearby collision boxes + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + { + if (!collision_box.enabled || collision_box.virt) { continue; } + intersection = ray.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); + if (intersection.first && intersection.second <= max_distance) + { + closest_surface_distance_in_this_direction = std::min(closest_surface_distance_in_this_direction, intersection.second); + } + } + + // check for nearby actors + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + for(const ActorPtr& actor : actors) + { + // ignore own truck if player is driving one + if (actor == App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling()) { continue; } + + intersection = ray.intersects(actor->ar_bounding_box); + if (intersection.first && intersection.second <= max_distance) + { + closest_surface_distance_in_this_direction = std::min(closest_surface_distance_in_this_direction, intersection.second); + } + } + + closest_surface_distance = std::min(closest_surface_distance, closest_surface_distance_in_this_direction); + + if(closest_surface_distance_in_this_direction <= max_distance) + { + early_reflections_pan += raycast_direction * (max_distance - closest_surface_distance_in_this_direction); } } + nearby_surface_detected = closest_surface_distance <= max_distance; + // TODO vertical raycasts if (!nearby_surface_detected) @@ -563,7 +600,7 @@ std::tuple SoundManager::ComputeEarlyReflectionsPro early_reflections_gain = std::min( (m_listener_efx_reverb_properties->flReflectionsGain + reflections_gain_boost_max - - (reflections_gain_boost_max * (1.0f - magnitude))), + - (reflections_gain_boost_max * (magnitude))), AL_EAXREVERB_MAX_REFLECTIONS_GAIN); } From e40982fc454227729ac40c1359aae8e77102054b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 20 Oct 2024 16:26:49 +0200 Subject: [PATCH 079/104] :video_game: Add reverb presets to office rooms of prefabs --- resources/meshes/hangar.odef | 1 + resources/meshes/marina.odef | 1 + resources/meshes/truckshop.odef | 1 + source/main/audio/SoundManager.cpp | 1 + 4 files changed, 4 insertions(+) diff --git a/resources/meshes/hangar.odef b/resources/meshes/hangar.odef index 2f81334d9d..2021ce5e22 100644 --- a/resources/meshes/hangar.odef +++ b/resources/meshes/hangar.odef @@ -10,6 +10,7 @@ beginbox boxcoords -23.75, -21.75, -0.2, 2.1, -3.07, -0.19 virtual event shopplane avatar +reverb_preset EFX_REVERB_PRESET_WOODEN_ALCOVE endbox beginbox diff --git a/resources/meshes/marina.odef b/resources/meshes/marina.odef index a0d9f1af8a..532901f749 100644 --- a/resources/meshes/marina.odef +++ b/resources/meshes/marina.odef @@ -8,6 +8,7 @@ endmesh beginbox boxcoords -25, -17, 0, 3, -11, 11 virtual +reverb_preset EFX_REVERB_PRESET_WOODEN_MEDIUMROOM event shopboat avatar endbox diff --git a/resources/meshes/truckshop.odef b/resources/meshes/truckshop.odef index 961949088a..79b03a8163 100644 --- a/resources/meshes/truckshop.odef +++ b/resources/meshes/truckshop.odef @@ -15,6 +15,7 @@ beginbox boxcoords -11.5, -2.1, -0.5, 3.0, -9.70, -7.5 virtual event shoptruck avatar +reverb_preset EFX_REVERB_PRESET_WOODEN_ALCOVE endbox beginbox diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5dd956eafb..f49c4c774d 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -338,6 +338,7 @@ void SoundManager::PrepopulateEfxPropertiesMap() m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_LONGPASSAGE"] = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE; m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_HALL"] = EFX_REVERB_PRESET_WOODEN_HALL; m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_COURTYARD"] = EFX_REVERB_PRESET_WOODEN_COURTYARD; + m_efx_properties_map["EFX_REVERB_PRESET_WOODEN_ALCOVE"] = EFX_REVERB_PRESET_WOODEN_ALCOVE; m_efx_properties_map["EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM"] = EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM; m_efx_properties_map["EFX_REVERB_PRESET_SPORT_FULLSTADIUM"] = EFX_REVERB_PRESET_SPORT_FULLSTADIUM; m_efx_properties_map["EFX_REVERB_PRESET_SPORT_STADIUMTANNOY"] = EFX_REVERB_PRESET_SPORT_STADIUMTANNOY; From 8db0f732a387269d96d89097c952fed792f57cd5 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 23 Oct 2024 19:27:09 +0200 Subject: [PATCH 080/104] :video_game: Smoothly change reverb properties --- source/main/audio/SoundManager.cpp | 216 ++++++++++++++++++----------- source/main/audio/SoundManager.h | 11 +- 2 files changed, 147 insertions(+), 80 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f49c4c774d..43be46ffc8 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -270,10 +270,10 @@ void SoundManager::CleanUp() this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); } - for (const auto& entry : m_efx_effect_id_map) + for (auto it = m_efx_effect_id_map.begin(); it != m_efx_effect_id_map.end();) { - this->DeleteAlEffect(entry.second); - m_efx_effect_id_map.erase(entry.first); + this->DeleteAlEffect(it->second); + it = m_efx_effect_id_map.erase(it); } } @@ -425,90 +425,148 @@ void SoundManager::SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener void SoundManager::UpdateListenerEffectSlot(const float dt_sec) { - if (m_listener_efx_reverb_properties == nullptr) + if(m_listener_efx_reverb_properties == nullptr) { - this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + this->SmoothlyUpdateAlAuxiliaryEffectSlot(dt_sec, m_listener_slot, nullptr); + return; } - else + + EFXEAXREVERBPROPERTIES current_environmental_properties = *m_listener_efx_reverb_properties; + + current_environmental_properties.flAirAbsorptionGainHF = App::audio_air_absorption_gain_hf->getFloat(); + + // early reflections panning, delay and strength + if (App::audio_enable_reflection_panning->getBool() && m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) { - ALuint efx_effect_id; + std::tuple target_early_reflections_properties = this->ComputeEarlyReflectionsProperties(); - // create new effect if not existing - if(m_efx_effect_id_map.find(m_listener_efx_reverb_properties) == m_efx_effect_id_map.end()) - { - efx_effect_id = this->CreateAlEffect(m_listener_efx_reverb_properties); - m_efx_effect_id_map[m_listener_efx_reverb_properties] = efx_effect_id; - } - else - { - efx_effect_id = m_efx_effect_id_map.find(m_listener_efx_reverb_properties)->second; - } + // convert panning vector from RHS to EAXREVERB's LHS + current_environmental_properties.flReflectionsPan[0] = std::get<0>(target_early_reflections_properties).x; + current_environmental_properties.flReflectionsPan[1] = 0; + current_environmental_properties.flReflectionsPan[2] = -std::get<0>(target_early_reflections_properties).z; - // update air absorption gain hf of effect - if (m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) - { - this->alEffectf(efx_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); - } - else if (m_efx_reverb_engine == EfxReverbEngine::REVERB) - { - this->alEffectf(efx_effect_id, AL_REVERB_AIR_ABSORPTION_GAINHF, App::audio_air_absorption_gain_hf->getFloat()); - } + current_environmental_properties.flReflectionsGain = std::get<1>(target_early_reflections_properties); + current_environmental_properties.flReflectionsDelay = std::get<2>(target_early_reflections_properties); + } - // early reflections panning, delay and strength - if ( - App::audio_enable_reflection_panning->getBool() && - m_efx_reverb_engine == EfxReverbEngine::EAXREVERB && - App::app_state->getEnum() == AppState::SIMULATION // required to avoid crash when returning to main menu - ) - { - // smoothly pan from the current properties to the target properties over several timesteps (frames) - const float time_to_target = 0.100f; // seconds to reach the target properties from the current properties - const float step = std::min(dt_sec / time_to_target, 1.0f); - static std::tuple target_early_reflections_properties; - static std::tuple current_early_reflections_properties = - std::make_tuple(Ogre::Vector3(m_listener_efx_reverb_properties->flReflectionsPan[0], - m_listener_efx_reverb_properties->flReflectionsPan[1], - m_listener_efx_reverb_properties->flReflectionsPan[2]), - m_listener_efx_reverb_properties->flReflectionsGain, - m_listener_efx_reverb_properties->flReflectionsDelay); - - target_early_reflections_properties = this->ComputeEarlyReflectionsProperties(); - - const Ogre::Vector3 current_early_reflections_pan = - std::get<0>(current_early_reflections_properties) - + step * ( std::get<0>(target_early_reflections_properties) - - std::get<0>(current_early_reflections_properties)); - - const float current_early_reflections_gain = - std::get<1>(current_early_reflections_properties) - + step * ( std::get<1>(target_early_reflections_properties) - - std::get<1>(current_early_reflections_properties)); - - const float current_early_reflections_delay = - std::get<2>(current_early_reflections_properties) - + step * ( std::get<2>(target_early_reflections_properties) - - std::get<2>(current_early_reflections_properties)); - - current_early_reflections_properties = - std::make_tuple(Ogre::Vector3(current_early_reflections_pan.x, - current_early_reflections_pan.y, - current_early_reflections_pan.z), - current_early_reflections_gain, - current_early_reflections_delay); - - // convert panning vector to EAXREVERB's LHS - const float eaxreverb_early_reflections_pan[3] = - { current_early_reflections_pan.x, - 0, // TODO - -current_early_reflections_pan.z }; - this->alEffectfv(efx_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, eaxreverb_early_reflections_pan); - this->alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, std::get<1>(current_early_reflections_properties)); - this->alEffectf(efx_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, std::get<2>(current_early_reflections_properties)); - } + this->SmoothlyUpdateAlAuxiliaryEffectSlot(dt_sec, m_listener_slot, ¤t_environmental_properties); +} + +void SoundManager::SmoothlyUpdateAlAuxiliaryEffectSlot(const float dt_sec, const ALuint slot_id, const EFXEAXREVERBPROPERTIES* target_efx_properties) +{ + const float time_to_target = 0.100f; // seconds to reach the target properties from the current properties + const float step = std::min(dt_sec / time_to_target, 1.0f); + static std::map current_efx_properties_of_slot; + + if (target_efx_properties == nullptr) + { + this->alAuxiliaryEffectSloti(slot_id, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + return; + } + + const auto it = current_efx_properties_of_slot.find(slot_id); + if (it == current_efx_properties_of_slot.end()) + { + // previously unseen effect slot, set a starting point + current_efx_properties_of_slot[slot_id] = *target_efx_properties; + } + + ALuint efx_effect_id; + // create new AL effect if not existing + if(m_efx_effect_id_map.find(slot_id) == m_efx_effect_id_map.end()) + { + efx_effect_id = this->CreateAlEffect(target_efx_properties); + m_efx_effect_id_map[slot_id] = efx_effect_id; + } + else + { + efx_effect_id = m_efx_effect_id_map.find(slot_id)->second; + } - // update the effect on the listener effect slot - this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, efx_effect_id); + // compute intermediate step between current and target properties using linear interpolation based on time step + current_efx_properties_of_slot[slot_id] = + { + current_efx_properties_of_slot[slot_id].flDensity + step * (target_efx_properties->flDensity - current_efx_properties_of_slot[slot_id].flDensity), + current_efx_properties_of_slot[slot_id].flDiffusion + step * (target_efx_properties->flDiffusion - current_efx_properties_of_slot[slot_id].flDiffusion), + current_efx_properties_of_slot[slot_id].flGain + step * (target_efx_properties->flGain - current_efx_properties_of_slot[slot_id].flGain), + current_efx_properties_of_slot[slot_id].flGainHF + step * (target_efx_properties->flGainHF - current_efx_properties_of_slot[slot_id].flGainHF), + current_efx_properties_of_slot[slot_id].flGainLF + step * (target_efx_properties->flGainLF - current_efx_properties_of_slot[slot_id].flGainLF), + current_efx_properties_of_slot[slot_id].flDecayTime + step * (target_efx_properties->flDecayTime - current_efx_properties_of_slot[slot_id].flDecayTime), + current_efx_properties_of_slot[slot_id].flDecayHFRatio + step * (target_efx_properties->flDecayHFRatio - current_efx_properties_of_slot[slot_id].flDecayHFRatio), + current_efx_properties_of_slot[slot_id].flDecayLFRatio + step * (target_efx_properties->flDecayLFRatio - current_efx_properties_of_slot[slot_id].flDecayLFRatio), + current_efx_properties_of_slot[slot_id].flReflectionsGain + step * (target_efx_properties->flReflectionsGain - current_efx_properties_of_slot[slot_id].flReflectionsGain), + current_efx_properties_of_slot[slot_id].flReflectionsDelay + step * (target_efx_properties->flReflectionsDelay - current_efx_properties_of_slot[slot_id].flReflectionsDelay), + current_efx_properties_of_slot[slot_id].flReflectionsPan[0] + step * (target_efx_properties->flReflectionsPan[0] - current_efx_properties_of_slot[slot_id].flReflectionsPan[0]), + current_efx_properties_of_slot[slot_id].flReflectionsPan[1] + step * (target_efx_properties->flReflectionsPan[1] - current_efx_properties_of_slot[slot_id].flReflectionsPan[1]), + current_efx_properties_of_slot[slot_id].flReflectionsPan[2] + step * (target_efx_properties->flReflectionsPan[2] - current_efx_properties_of_slot[slot_id].flReflectionsPan[2]), + current_efx_properties_of_slot[slot_id].flLateReverbGain + step * (target_efx_properties->flLateReverbGain - current_efx_properties_of_slot[slot_id].flLateReverbGain), + current_efx_properties_of_slot[slot_id].flLateReverbDelay + step * (target_efx_properties->flLateReverbDelay - current_efx_properties_of_slot[slot_id].flLateReverbDelay), + current_efx_properties_of_slot[slot_id].flLateReverbPan[0] + step * (target_efx_properties->flLateReverbPan[0] - current_efx_properties_of_slot[slot_id].flLateReverbPan[0]), + current_efx_properties_of_slot[slot_id].flLateReverbPan[1] + step * (target_efx_properties->flLateReverbPan[1] - current_efx_properties_of_slot[slot_id].flLateReverbPan[1]), + current_efx_properties_of_slot[slot_id].flLateReverbPan[2] + step * (target_efx_properties->flLateReverbPan[2] - current_efx_properties_of_slot[slot_id].flLateReverbPan[2]), + current_efx_properties_of_slot[slot_id].flEchoTime + step * (target_efx_properties->flEchoTime - current_efx_properties_of_slot[slot_id].flEchoTime), + current_efx_properties_of_slot[slot_id].flEchoDepth + step * (target_efx_properties->flEchoDepth - current_efx_properties_of_slot[slot_id].flEchoDepth), + current_efx_properties_of_slot[slot_id].flModulationTime + step * (target_efx_properties->flModulationTime - current_efx_properties_of_slot[slot_id].flModulationTime), + current_efx_properties_of_slot[slot_id].flModulationDepth + step * (target_efx_properties->flModulationDepth - current_efx_properties_of_slot[slot_id].flModulationDepth), + current_efx_properties_of_slot[slot_id].flAirAbsorptionGainHF + step * (target_efx_properties->flAirAbsorptionGainHF - current_efx_properties_of_slot[slot_id].flAirAbsorptionGainHF), + current_efx_properties_of_slot[slot_id].flHFReference + step * (target_efx_properties->flHFReference - current_efx_properties_of_slot[slot_id].flHFReference), + current_efx_properties_of_slot[slot_id].flLFReference + step * (target_efx_properties->flLFReference - current_efx_properties_of_slot[slot_id].flLFReference), + current_efx_properties_of_slot[slot_id].flRoomRolloffFactor + step * (target_efx_properties->flRoomRolloffFactor - current_efx_properties_of_slot[slot_id].flRoomRolloffFactor), + static_cast(std::round(current_efx_properties_of_slot[slot_id].iDecayHFLimit + step * (target_efx_properties->iDecayHFLimit - current_efx_properties_of_slot[slot_id].iDecayHFLimit))), + }; + + // update AL effect to intermediate values + switch (m_efx_reverb_engine) + { + case EfxReverbEngine::EAXREVERB: + this->alEffectf( efx_effect_id, AL_EAXREVERB_DENSITY, current_efx_properties_of_slot[slot_id].flDensity); + this->alEffectf( efx_effect_id, AL_EAXREVERB_DIFFUSION, current_efx_properties_of_slot[slot_id].flDiffusion); + this->alEffectf( efx_effect_id, AL_EAXREVERB_GAIN, current_efx_properties_of_slot[slot_id].flGain); + this->alEffectf( efx_effect_id, AL_EAXREVERB_GAINHF, current_efx_properties_of_slot[slot_id].flGainHF); + this->alEffectf( efx_effect_id, AL_EAXREVERB_GAINLF, current_efx_properties_of_slot[slot_id].flGainLF); + this->alEffectf( efx_effect_id, AL_EAXREVERB_DECAY_TIME, current_efx_properties_of_slot[slot_id].flDecayTime); + this->alEffectf( efx_effect_id, AL_EAXREVERB_DECAY_HFRATIO, current_efx_properties_of_slot[slot_id].flDecayHFRatio); + this->alEffectf( efx_effect_id, AL_EAXREVERB_DECAY_LFRATIO, current_efx_properties_of_slot[slot_id].flDecayLFRatio); + this->alEffectf( efx_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, current_efx_properties_of_slot[slot_id].flReflectionsGain); + this->alEffectf( efx_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, current_efx_properties_of_slot[slot_id].flReflectionsDelay); + this->alEffectfv(efx_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, current_efx_properties_of_slot[slot_id].flReflectionsPan); + this->alEffectf( efx_effect_id, AL_EAXREVERB_LATE_REVERB_GAIN, current_efx_properties_of_slot[slot_id].flLateReverbGain); + this->alEffectf( efx_effect_id, AL_EAXREVERB_LATE_REVERB_DELAY, current_efx_properties_of_slot[slot_id].flLateReverbDelay); + this->alEffectfv(efx_effect_id, AL_EAXREVERB_LATE_REVERB_PAN, current_efx_properties_of_slot[slot_id].flLateReverbPan); + this->alEffectf( efx_effect_id, AL_EAXREVERB_ECHO_TIME, current_efx_properties_of_slot[slot_id].flEchoTime); + this->alEffectf( efx_effect_id, AL_EAXREVERB_ECHO_DEPTH, current_efx_properties_of_slot[slot_id].flEchoDepth); + this->alEffectf( efx_effect_id, AL_EAXREVERB_MODULATION_TIME, current_efx_properties_of_slot[slot_id].flModulationTime); + this->alEffectf( efx_effect_id, AL_EAXREVERB_MODULATION_DEPTH, current_efx_properties_of_slot[slot_id].flModulationDepth); + this->alEffectf( efx_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, current_efx_properties_of_slot[slot_id].flAirAbsorptionGainHF); + this->alEffectf( efx_effect_id, AL_EAXREVERB_HFREFERENCE, current_efx_properties_of_slot[slot_id].flHFReference); + this->alEffectf( efx_effect_id, AL_EAXREVERB_LFREFERENCE, current_efx_properties_of_slot[slot_id].flLFReference); + this->alEffectf( efx_effect_id, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, current_efx_properties_of_slot[slot_id].flRoomRolloffFactor); + this->alEffecti( efx_effect_id, AL_EAXREVERB_DECAY_HFLIMIT, current_efx_properties_of_slot[slot_id].iDecayHFLimit); + break; + + case EfxReverbEngine::REVERB: + this->alEffectf( efx_effect_id, AL_REVERB_DENSITY, current_efx_properties_of_slot[slot_id].flDensity); + this->alEffectf( efx_effect_id, AL_REVERB_DIFFUSION, current_efx_properties_of_slot[slot_id].flDiffusion); + this->alEffectf( efx_effect_id, AL_REVERB_GAIN, current_efx_properties_of_slot[slot_id].flGain); + this->alEffectf( efx_effect_id, AL_REVERB_GAINHF, current_efx_properties_of_slot[slot_id].flGainHF); + this->alEffectf( efx_effect_id, AL_REVERB_DECAY_TIME, current_efx_properties_of_slot[slot_id].flDecayTime); + this->alEffectf( efx_effect_id, AL_REVERB_DECAY_HFRATIO, current_efx_properties_of_slot[slot_id].flDecayHFRatio); + this->alEffectf( efx_effect_id, AL_REVERB_REFLECTIONS_GAIN, current_efx_properties_of_slot[slot_id].flReflectionsGain); + this->alEffectf( efx_effect_id, AL_REVERB_REFLECTIONS_DELAY, current_efx_properties_of_slot[slot_id].flReflectionsDelay); + this->alEffectf( efx_effect_id, AL_REVERB_LATE_REVERB_GAIN, current_efx_properties_of_slot[slot_id].flLateReverbGain); + this->alEffectf( efx_effect_id, AL_REVERB_LATE_REVERB_DELAY, current_efx_properties_of_slot[slot_id].flLateReverbDelay); + this->alEffectf( efx_effect_id, AL_REVERB_AIR_ABSORPTION_GAINHF, current_efx_properties_of_slot[slot_id].flAirAbsorptionGainHF); + this->alEffectf( efx_effect_id, AL_REVERB_ROOM_ROLLOFF_FACTOR, current_efx_properties_of_slot[slot_id].flRoomRolloffFactor); + this->alEffectf( efx_effect_id, AL_REVERB_DECAY_HFLIMIT, current_efx_properties_of_slot[slot_id].iDecayHFLimit); + break; + + case EfxReverbEngine::NONE: + this->alAuxiliaryEffectSloti(slot_id, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); + return; } + + // make the slot use the updated AL effect + this->alAuxiliaryEffectSloti(slot_id, AL_EFFECTSLOT_EFFECT, efx_effect_id); } std::tuple SoundManager::ComputeEarlyReflectionsProperties() const diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 4a6bd3a35f..fe7eca2aea 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -236,7 +236,7 @@ class SoundManager EfxReverbEngine m_efx_reverb_engine = EfxReverbEngine::NONE; const EFXEAXREVERBPROPERTIES* m_listener_efx_reverb_properties = nullptr; std::map m_efx_properties_map; - std::map m_efx_effect_id_map; + std::map m_efx_effect_id_map; // Date: Sat, 2 Nov 2024 16:49:10 +0100 Subject: [PATCH 081/104] :triangular_ruler: Align parameters --- source/main/audio/SoundManager.cpp | 51 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 43be46ffc8..dc740a8c7c 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -695,32 +695,31 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties switch (m_efx_reverb_engine) { case EfxReverbEngine::EAXREVERB: - this->alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - this->alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); - - this->alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); - this->alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); - this->alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); - this->alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); - this->alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); - this->alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); - this->alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); - this->alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); - this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); - this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); - this->alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); - this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); - this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); - this->alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); - this->alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); - this->alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); - this->alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); - this->alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); - this->alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); - this->alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); - this->alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); - this->alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); - this->alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); + this->alEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + + this->alEffectf( effect, AL_EAXREVERB_DENSITY, efx_properties->flDensity); + this->alEffectf( effect, AL_EAXREVERB_DIFFUSION, efx_properties->flDiffusion); + this->alEffectf( effect, AL_EAXREVERB_GAIN, efx_properties->flGain); + this->alEffectf( effect, AL_EAXREVERB_GAINHF, efx_properties->flGainHF); + this->alEffectf( effect, AL_EAXREVERB_GAINLF, efx_properties->flGainLF); + this->alEffectf( effect, AL_EAXREVERB_DECAY_TIME, efx_properties->flDecayTime); + this->alEffectf( effect, AL_EAXREVERB_DECAY_HFRATIO, efx_properties->flDecayHFRatio); + this->alEffectf( effect, AL_EAXREVERB_DECAY_LFRATIO, efx_properties->flDecayLFRatio); + this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_GAIN, efx_properties->flReflectionsGain); + this->alEffectf( effect, AL_EAXREVERB_REFLECTIONS_DELAY, efx_properties->flReflectionsDelay); + this->alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, efx_properties->flReflectionsPan); + this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_GAIN, efx_properties->flLateReverbGain); + this->alEffectf( effect, AL_EAXREVERB_LATE_REVERB_DELAY, efx_properties->flLateReverbDelay); + this->alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, efx_properties->flLateReverbPan); + this->alEffectf( effect, AL_EAXREVERB_ECHO_TIME, efx_properties->flEchoTime); + this->alEffectf( effect, AL_EAXREVERB_ECHO_DEPTH, efx_properties->flEchoDepth); + this->alEffectf( effect, AL_EAXREVERB_MODULATION_TIME, efx_properties->flModulationTime); + this->alEffectf( effect, AL_EAXREVERB_MODULATION_DEPTH, efx_properties->flModulationDepth); + this->alEffectf( effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, efx_properties->flAirAbsorptionGainHF); + this->alEffectf( effect, AL_EAXREVERB_HFREFERENCE, efx_properties->flHFReference); + this->alEffectf( effect, AL_EAXREVERB_LFREFERENCE, efx_properties->flLFReference); + this->alEffectf( effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, efx_properties->flRoomRolloffFactor); + this->alEffecti( effect, AL_EAXREVERB_DECAY_HFLIMIT, efx_properties->iDecayHFLimit); break; case EfxReverbEngine::REVERB: From 3b8c016976ae477afa15a31cd1ba73cafaa1cbcf Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 2 Nov 2024 16:59:24 +0100 Subject: [PATCH 082/104] :video_game: Make reverb preset transitions smoother With 100ms some pop sounds were still audible for some preset changes, 333ms seems like a better choice. --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index dc740a8c7c..19a48ff6da 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -454,7 +454,7 @@ void SoundManager::UpdateListenerEffectSlot(const float dt_sec) void SoundManager::SmoothlyUpdateAlAuxiliaryEffectSlot(const float dt_sec, const ALuint slot_id, const EFXEAXREVERBPROPERTIES* target_efx_properties) { - const float time_to_target = 0.100f; // seconds to reach the target properties from the current properties + const float time_to_target = 0.333f; // seconds to reach the target properties from the current properties const float step = std::min(dt_sec / time_to_target, 1.0f); static std::map current_efx_properties_of_slot; From 2dbc4825e5699df08bc2b33c3402b769204e1c54 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 2 Nov 2024 17:31:42 +0100 Subject: [PATCH 083/104] :video_game: Rework frequency-dependent absorption for sound * No longer expose corresponding CVars since internal handling should suffice * the previous calculation for the air absorption factor for underwater environments incorrectly targeted 5 MHz instead of 5 kHz * AirAbsorptionGainHF is no longer adjusted since it should be determined by the preset --- source/main/Application.cpp | 2 -- source/main/Application.h | 2 -- source/main/audio/SoundManager.cpp | 4 +--- source/main/audio/SoundManager.h | 12 ++++++++++++ source/main/audio/SoundScriptManager.cpp | 14 ++++++-------- source/main/system/CVar.cpp | 2 -- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index b88b192d93..fe3151bd6d 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -206,8 +206,6 @@ CVar* io_discord_rpc; CVar* io_invert_orbitcam; // Audio -CVar* audio_air_absorption_factor; -CVar* audio_air_absorption_gain_hf; CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; diff --git a/source/main/Application.h b/source/main/Application.h index f834fec7cd..b4c2830f8e 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -453,8 +453,6 @@ extern CVar* io_discord_rpc; extern CVar* io_invert_orbitcam; // Audio -extern CVar* audio_air_absorption_factor; -extern CVar* audio_air_absorption_gain_hf; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 19a48ff6da..1c0c9a55c3 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -384,7 +384,7 @@ void SoundManager::Update(const float dt_sec) for(int hardware_index = 0; hardware_index < hardware_sources_num; hardware_index++) { // update air absorption factor - alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, App::audio_air_absorption_factor->getFloat()); + alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, m_air_absorption_factor); this->UpdateObstructionFilter(hardware_index); } @@ -433,8 +433,6 @@ void SoundManager::UpdateListenerEffectSlot(const float dt_sec) EFXEAXREVERBPROPERTIES current_environmental_properties = *m_listener_efx_reverb_properties; - current_environmental_properties.flAirAbsorptionGainHF = App::audio_air_absorption_gain_hf->getFloat(); - // early reflections panning, delay and strength if (App::audio_enable_reflection_panning->getBool() && m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) { diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index fe7eca2aea..00319a4746 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -138,6 +138,17 @@ class SoundManager */ void SetDopplerFactor(const float doppler_factor) const { alDopplerFactor(doppler_factor); } + /** + * Sets the air absorptions factor for the direct path of all sounds. + * @param air_absorption_factor Air absorption factor within the range of AL_AIR_ABSORPTION_FACTOR. + */ + void SetAirAbsorptionFactor(const float air_absorption_factor) { m_air_absorption_factor = air_absorption_factor; } + + /** + * @return current value set for the air absorption factor for the direct path of sounds + */ + float GetAirAbsorptionFactor() const { return m_air_absorption_factor; } + /** * Returns the number of currently used hardware sources. In a typical scenario, * this value changes dynamically. @@ -233,6 +244,7 @@ class SoundManager bool m_efx_is_available = false; ALuint m_listener_slot = 0; ALuint m_efx_outdoor_obstruction_lowpass_filter_id = 0; + float m_air_absorption_factor = 1.0f; EfxReverbEngine m_efx_reverb_engine = EfxReverbEngine::NONE; const EFXEAXREVERBPROPERTIES* m_listener_efx_reverb_properties = nullptr; std::map m_efx_properties_map; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index dc092080d8..e85d244d32 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -361,18 +361,16 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) { sound_manager->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) /* - According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in water - and assuming the Air Absorption Gain HF property of OpenAL is set to the minimum of 0.892, - the absorption factor should be ~11.25, which is just slightly above the maximum of 10.0. - */ - App::audio_air_absorption_factor->setVal(10.0f); - App::audio_air_absorption_gain_hf->setVal(0.892f); + * According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in seawater, + * the absorption should be 0.334 db/km. OpenAL multiplies the Air Absorption Factor with an internal + * value of 0.05dB/m, so we need a factor of 0.00668f. + */ + sound_manager->SetAirAbsorptionFactor(0.00668f); } else { sound_manager->SetSpeedOfSound(343.3f); // assume listener is in air at 20° celsius - App::audio_air_absorption_factor->setVal(1.0f); - App::audio_air_absorption_gain_hf->setVal(0.994f); + sound_manager->SetAirAbsorptionFactor(1.0f); } if (App::audio_enable_efx->getBool()) diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index a1322f736e..fca9c1acd4 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -149,8 +149,6 @@ void Console::cVarSetupBuiltins() App::io_discord_rpc = this->cVarCreate("io_discord_rpc", "Discord Rich Presence", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::io_invert_orbitcam = this->cVarCreate("io_invert_orbitcam", "Invert orbit camera", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); - App::audio_air_absorption_factor = this->cVarCreate("audio_air_absorption_factor", "Air absorption factor", CVAR_TYPE_FLOAT, "1.0"); - App::audio_air_absorption_gain_hf = this->cVarCreate("audio_air_absorption_gain_hf", "Air absorption Gain HF", CVAR_TYPE_FLOAT, "0.994"); App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); From 135303f9bcb92437e187541b266dcd11a309cbd6 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 24 Nov 2024 08:57:29 +0100 Subject: [PATCH 084/104] :video_game: no longer apply the obstruction filter if the listener is inside an actor The implementation did not differentiate whether the actor had an open or closed cabin. For instace, it incorrectly applied the obstruction effect when the listener was in actors with open cabins, e.g. buggies. There does not seem to be an easy way to determine whether an actor has an open or closed cabin. An expensive(?) alternative might be to check against collisions with the mesh of an actor. --- source/main/audio/SoundManager.cpp | 128 +++++++++++------------ source/main/audio/SoundScriptManager.cpp | 10 -- source/main/audio/SoundScriptManager.h | 6 -- 3 files changed, 60 insertions(+), 84 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 1c0c9a55c3..780e71943d 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -834,91 +834,83 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const // TODO: Simulate diffraction path. - // always obstruct sounds if the player is in a vehicle - if(App::GetSoundScriptManager()->ListenerIsInsideThePlayerCoupledActor()) - { - obstruction_detected = true; + /* + * Perform various line of sight checks until either a collision was detected + * and the filter has to be applied or no obstruction was detected. + */ + + std::pair intersection; + // no normalisation due to how the intersectsTris function determines its number of steps + Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; + Ogre::Real distance_to_sound = direction_to_sound.length(); + Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); + obstruction_detected = intersection.first; + + if(!obstruction_detected) + { + // perform line of sight check against collision meshes + // for this to work correctly, the direction vector of the ray must have + // the length of the distance from the listener to the sound + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); + obstruction_detected = intersection.first; } - else - { - /* - * Perform various line of sight checks until either a collision was detected - * and the filter has to be applied or no obstruction was detected. - */ - - std::pair intersection; - // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; - Ogre::Real distance_to_sound = direction_to_sound.length(); - Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); - // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); - obstruction_detected = intersection.first; + // do not normalise before intersectsTris() due to how that function works + direction_to_sound.normalise(); + direct_path_to_sound.setDirection(direction_to_sound); - if(!obstruction_detected) + if(!obstruction_detected) + { + // perform line of sight check agains collision boxes + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) { - // perform line of sight check against collision meshes - // for this to work correctly, the direction vector of the ray must have - // the length of the distance from the listener to the sound - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstruction_detected = intersection.first; - } - - // do not normalise before intersectsTris() due to how that function works - direction_to_sound.normalise(); - direct_path_to_sound.setDirection(direction_to_sound); + if (!collision_box.enabled || collision_box.virt) { continue; } - if(!obstruction_detected) - { - // perform line of sight check agains collision boxes - for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); + if (intersection.first && intersection.second <= distance_to_sound) { - if (!collision_box.enabled || collision_box.virt) { continue; } - - intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); - if (intersection.first && intersection.second <= distance_to_sound) - { - obstruction_detected = true; - break; - } + obstruction_detected = true; + break; } } + } - if(!obstruction_detected) + if(!obstruction_detected) + { + // perform line of sight check against actors + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + bool soundsource_belongs_to_current_actor = false; + for(const ActorPtr actor : actors) { - // perform line of sight check against actors - const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); - bool soundsource_belongs_to_current_actor = false; - for(const ActorPtr actor : actors) + // Trucks shouldn't obstruct their own sound sources since the + // obstruction is most likely already contained in the recording. + for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) { - // Trucks shouldn't obstruct their own sound sources since the - // obstruction is most likely already contained in the recording. - for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) + const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; + const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); + for (int num_sound = 0; num_sound < num_sounds; ++num_sound) { - const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; - const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); - for (int num_sound = 0; num_sound < num_sounds; ++num_sound) + if (soundsource.ssi->getSound(num_sound) == corresponding_sound) { - if (soundsource.ssi->getSound(num_sound) == corresponding_sound) - { - soundsource_belongs_to_current_actor = true; - } + soundsource_belongs_to_current_actor = true; } - if (soundsource_belongs_to_current_actor) { break; } } + if (soundsource_belongs_to_current_actor) { break; } + } - if (soundsource_belongs_to_current_actor) - { - continue; - } + if (soundsource_belongs_to_current_actor) + { + continue; + } - intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); - obstruction_detected = intersection.first; - if (obstruction_detected) - { - break; - } + intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); + obstruction_detected = intersection.first; + if (obstruction_detected) + { + break; } } } diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index e85d244d32..57075117e1 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -326,16 +326,6 @@ void SoundScriptManager::update(float dt_sec) const auto water = App::GetGameContext()->GetTerrain()->getWater(); m_listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); - ActorPtr actor_of_player = App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling(); - if (actor_of_player != nullptr) - { - m_listener_is_inside_the_player_coupled_actor = actor_of_player->ar_bounding_box.contains(listener_position); - } - else - { - m_listener_is_inside_the_player_coupled_actor = false; - } - SetListenerEnvironment(camera_position); sound_manager->Update(dt_sec); } diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index c8065433e6..583c223898 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -345,11 +345,6 @@ class SoundScriptManager : public Ogre::ScriptLoader */ bool ListenerIsUnderwater() const { return m_listener_is_underwater; } - /** - * @return True if the listener position is inside the AABB of the actor the player character is coupled to. False otherwise. - */ - bool ListenerIsInsideThePlayerCoupledActor() const { return m_listener_is_inside_the_player_coupled_actor; } - SoundManager* getSoundManager() { return sound_manager; } private: @@ -361,7 +356,6 @@ class SoundScriptManager : public Ogre::ScriptLoader bool disabled; bool loading_base; bool m_listener_is_underwater = false; - bool m_listener_is_inside_the_player_coupled_actor = false; float max_distance; float reference_distance; float rolloff_factor; From f9e26fc44a081f3dbdb0f470002fe44df97b7f53 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 24 Nov 2024 09:12:02 +0100 Subject: [PATCH 085/104] :video_game: Remove dopplerfactor console command The console command was largely redundant to working with the audio_doppler_factor CVar. Instead of the previous way of triggering updates of the doppler factor via the message queue, the doppler factor is now updated each frame from the audio_doppler_factor CVar. --- doc/angelscript/Script2Game/globals.h | 2 - source/main/Application.cpp | 2 - source/main/Application.h | 2 - source/main/audio/SoundManager.cpp | 2 + source/main/audio/SoundScriptManager.cpp | 7 --- source/main/audio/SoundScriptManager.h | 1 - source/main/main.cpp | 10 ---- source/main/scripting/GameScript.cpp | 18 +----- .../bindings/MsgQueueAngelscript.cpp | 2 - source/main/system/ConsoleCmd.cpp | 55 ------------------- 10 files changed, 3 insertions(+), 98 deletions(-) diff --git a/doc/angelscript/Script2Game/globals.h b/doc/angelscript/Script2Game/globals.h index ceb908adea..aa7f918348 100644 --- a/doc/angelscript/Script2Game/globals.h +++ b/doc/angelscript/Script2Game/globals.h @@ -664,8 +664,6 @@ enum MsgType MSG_EDI_RELOAD_BUNDLE_REQUESTED, //!< This deletes all actors using that bundle (= ZIP or directory)! Params: 'cache_entry' (CacheEntryClass@) MSG_EDI_UNLOAD_BUNDLE_REQUESTED, //!< This deletes all actors using that bundle (= ZIP or directory)! Params: 'cache_entry' (CacheEntryClass@) MSG_EDI_CREATE_PROJECT_REQUESTED, //!< Creates a subdir under 'projects/', pre-populates it and adds to modcache. Params: 'name' (string), 'ext' (string, optional), 'source_entry' (CacheEntryClass@) - // Audio - MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED //!< Request change of doppler factor. Params: 'doppler_factor' (float). doppler_factor must not be negative.NAL }; } // namespace Script2Game diff --git a/source/main/Application.cpp b/source/main/Application.cpp index fe3151bd6d..247e4fed60 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -646,8 +646,6 @@ const char* MsgTypeToString(MsgType type) case MSG_EDI_MODIFY_PROJECT_REQUESTED : return "MSG_EDI_MODIFY_PROJECT_REQUESTED"; case MSG_EDI_DELETE_PROJECT_REQUESTED : return "MSG_EDI_DELETE_PROJECT_REQUESTED"; - case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED : return "MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED"; - default: return ""; } } diff --git a/source/main/Application.h b/source/main/Application.h index b4c2830f8e..fd6a6285db 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -150,8 +150,6 @@ enum MsgType MSG_EDI_CREATE_PROJECT_REQUESTED, //!< Payload = RoR::CreateProjectRequest* (owner) MSG_EDI_MODIFY_PROJECT_REQUESTED, //!< Payload = RoR::UpdateProjectRequest* (owner) MSG_EDI_DELETE_PROJECT_REQUESTED, //!< Payload = RoR::CacheEntryPtr* (owner) - // Audio - MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED, //!< Payload = float* }; const char* MsgTypeToString(MsgType type); diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 780e71943d..f406f17355 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -375,6 +375,8 @@ void SoundManager::Update(const float dt_sec) if (!audio_device) return; + this->SetDopplerFactor(App::audio_doppler_factor->getFloat()); + recomputeAllSources(); UpdateAlListener(); diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 57075117e1..ac8c20263d 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -418,13 +418,6 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: } } -void SoundScriptManager::SetDopplerFactor(float doppler_factor) -{ - if (disabled) - return; - sound_manager->SetDopplerFactor(doppler_factor); -} - const StringVector& SoundScriptManager::getScriptPatterns(void) const { return script_patterns; diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 583c223898..b9cad924b9 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -332,7 +332,6 @@ class SoundScriptManager : public Ogre::ScriptLoader void setEnabled(bool state); - void SetDopplerFactor(float doppler_factor); void SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); void setLoadingBaseSounds(bool value) { loading_base = value; }; diff --git a/source/main/main.cpp b/source/main/main.cpp index 647d5522a6..27947524e0 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -1582,16 +1582,6 @@ int main(int argc, char *argv[]) break; } - // -- Audio events -- - case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED: - { - float* doppler_factor_ptr = static_cast(m.payload); - LOG(fmt::format("Changing doppler factor to '{}' (from message bus)", *doppler_factor_ptr)); - App::GetSoundScriptManager()->getSoundManager()->SetDopplerFactor(*doppler_factor_ptr); - delete doppler_factor_ptr; - break; - } - default:; } diff --git a/source/main/scripting/GameScript.cpp b/source/main/scripting/GameScript.cpp index 6ae28de72f..ffcd8fd451 100644 --- a/source/main/scripting/GameScript.cpp +++ b/source/main/scripting/GameScript.cpp @@ -1704,23 +1704,7 @@ bool GameScript::pushMessage(MsgType type, AngelScript::CScriptDictionary* dict) } break; } - // Audio - case MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED: - { - float* doppler_factor_ptr = new float(); - if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "doppler_factor", "float", doppler_factor_ptr) && - !(*doppler_factor_ptr < 0.0f)) - { - m.payload = static_cast(doppler_factor_ptr); - } - else - { - delete doppler_factor_ptr; - return false; - } - break; - } - + default:; } diff --git a/source/main/scripting/bindings/MsgQueueAngelscript.cpp b/source/main/scripting/bindings/MsgQueueAngelscript.cpp index 04ae7922cc..bfc91846c6 100644 --- a/source/main/scripting/bindings/MsgQueueAngelscript.cpp +++ b/source/main/scripting/bindings/MsgQueueAngelscript.cpp @@ -98,8 +98,6 @@ void RoR::RegisterMessageQueue(asIScriptEngine* engine) result = engine->RegisterEnumValue("MsgType", "MSG_EDI_RELOAD_BUNDLE_REQUESTED", MSG_EDI_RELOAD_BUNDLE_REQUESTED); ROR_ASSERT(result >= 0); result = engine->RegisterEnumValue("MsgType", "MSG_EDI_UNLOAD_BUNDLE_REQUESTED", MSG_EDI_UNLOAD_BUNDLE_REQUESTED); ROR_ASSERT(result >= 0); result = engine->RegisterEnumValue("MsgType", "MSG_EDI_CREATE_PROJECT_REQUESTED", MSG_EDI_CREATE_PROJECT_REQUESTED); ROR_ASSERT(result >= 0); - // Audio - result = engine->RegisterEnumValue("MsgType", "MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED", MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED); ROR_ASSERT(result >= 0); // enum FreeForceType result = engine->RegisterEnum("FreeForceType"); ROR_ASSERT(result>=0); diff --git a/source/main/system/ConsoleCmd.cpp b/source/main/system/ConsoleCmd.cpp index 99c4b4b679..75cdb2eaf4 100644 --- a/source/main/system/ConsoleCmd.cpp +++ b/source/main/system/ConsoleCmd.cpp @@ -383,60 +383,6 @@ class SpeedOfSoundCmd: public ConsoleCmd } }; -class DopplerFactorCmd: public ConsoleCmd -{ -public: - DopplerFactorCmd(): ConsoleCmd("dopplerfactor", "[]", _L("Get or set doppler factor (1.0 for realistic effect, 0 for disabling).")) {} - - void Run(Ogre::StringVector const& args) override - { - if (!this->CheckAppState(AppState::SIMULATION)) - return; - - Str<200> reply; - Console::MessageType reply_type; - reply << m_name << ": "; - - if (!(args.size() >= 1 && args.size() <= 2)) - { - reply_type = Console::CONSOLE_HELP; - reply <<_L("usage: dopplerfactor [doppler factor (float)]"); - } - else - { - SoundManager* sound_manager = App::GetSoundScriptManager()->getSoundManager(); - if (sound_manager == nullptr) - { - reply << _L("unable to get sound manager"); - } - else - { - if(args.size() == 2) - { - float doppler_factor = std::stof(args[1]); - if (doppler_factor < 0.0f) - { - reply << _L("doppler factor must not be negative"); - } - else - { - Message m(MSG_AUD_MODIFY_DOPPLER_FACTOR_REQUESTED); - float* doppler_factor_ptr = new float(doppler_factor); - m.payload = static_cast(doppler_factor_ptr); - App::GetGameContext()->PushMessage(m); - reply << _L("Queued update of doppler factor to: ") << doppler_factor; - } - } - else - { - reply << _L("Doppler Factor is configured as: ") << "CVar (change requires restart): " << App::audio_doppler_factor->getFloat() << ", currently used by OpenAL: " << sound_manager->GetDopplerFactor(); - } - } - } - App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, reply_type, reply.ToCStr()); - } -}; - class QuitCmd: public ConsoleCmd { public: @@ -749,7 +695,6 @@ void Console::regBuiltinCommands() cmd = new ClearCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new LoadScriptCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new SpeedOfSoundCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); - cmd = new DopplerFactorCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); // CVars cmd = new SetCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); cmd = new SetstringCmd(); m_commands.insert(std::make_pair(cmd->getName(), cmd)); From 39108eca0b5262b9b85231a016f5e30eab2212e6 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 30 Nov 2024 07:18:06 +0100 Subject: [PATCH 086/104] :triangular_ruler: Add space between if and opening bracket --- source/main/audio/SoundScriptManager.cpp | 10 +++++----- source/main/gui/panels/GUI_GameSettings.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index ac8c20263d..88ef7cacce 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -347,7 +347,7 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) if (App::audio_engine_controls_environmental_audio->getBool()) { - if(ListenerIsUnderwater()) + if (ListenerIsUnderwater()) { sound_manager->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) /* @@ -379,7 +379,7 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre::Vector3 position) const { // for the listener we do additional checks - if(position == sound_manager->GetListenerPosition()) + if (position == sound_manager->GetListenerPosition()) { if (!App::audio_force_listener_efx_preset->getStr().empty()) { @@ -389,7 +389,7 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: const auto water = App::GetGameContext()->GetTerrain()->getWater(); bool position_is_underwater = (water != nullptr ? water->IsUnderWater(position) : false); - if(position_is_underwater) + if (position_is_underwater) { return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); } @@ -401,14 +401,14 @@ const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre:: { const Ogre::AxisAlignedBox collision_box_aab = Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi); - if(collision_box_aab.contains(position)) + if (collision_box_aab.contains(position)) { return sound_manager->GetEfxProperties(collision_box.reverb_preset_name); } } } - if(position == sound_manager->GetListenerPosition()) + if (position == sound_manager->GetListenerPosition()) { return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); } diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 9f0fa47f05..5c6cf78860 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -343,7 +343,7 @@ void GameSettings::DrawAudioSettings() DrawGCheckbox(App::audio_engine_controls_environmental_audio, _LC("GameSettings", "Engine exerts automatic control over environmental audio")); - if(App::audio_engine_controls_environmental_audio) + if (App::audio_engine_controls_environmental_audio) { DrawGTextEdit(App::audio_default_listener_efx_preset, _LC("GameSettings", "Default EFX Reverb Preset"), m_buf_audio_default_listener_efx_preset); DrawGTextEdit(App::audio_force_listener_efx_preset, _LC("GameSettings", "Force EFX Reverb Preset"), m_buf_audio_force_listener_efx_preset); From e191dff55d42bbdb21f6fe394903d539503e6dc6 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 30 Nov 2024 07:44:28 +0100 Subject: [PATCH 087/104] :wrench: Move ListenerIsUnderwater method from SoundScriptManager to SoundManager class --- source/main/audio/SoundManager.cpp | 4 ++++ source/main/audio/SoundManager.h | 7 +++++++ source/main/audio/SoundScriptManager.cpp | 9 +++------ source/main/audio/SoundScriptManager.h | 6 ------ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index f406f17355..253a01dda6 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -24,6 +24,7 @@ #include "SoundManager.h" #include "Application.h" +#include "IWater.h" #include "Sound.h" #include @@ -377,6 +378,9 @@ void SoundManager::Update(const float dt_sec) this->SetDopplerFactor(App::audio_doppler_factor->getFloat()); + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + m_listener_is_underwater = (water != nullptr ? water->IsUnderWater(m_listener_position) : false); + recomputeAllSources(); UpdateAlListener(); diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 00319a4746..9a2e72c269 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -74,6 +74,11 @@ class SoundManager */ Ogre::Vector3 GetListenerPosition() const { return m_listener_position; } + /** + * @return True if the listener position is below water level. False otherwise. + */ + bool ListenerIsUnderwater() const { return m_listener_is_underwater; } + /** * Does the per-frame update of sounds and listener environment. With the help of other functions it * determines and then submits the current state of the audio world to OpenAL. @@ -233,10 +238,12 @@ class SoundManager ALuint audio_buffers[MAX_AUDIO_BUFFERS]; Ogre::String audio_buffer_file_name[MAX_AUDIO_BUFFERS]; + bool m_listener_is_underwater = false; Ogre::Vector3 m_listener_position = Ogre::Vector3::ZERO; Ogre::Vector3 m_listener_direction = Ogre::Vector3::ZERO; Ogre::Vector3 m_listener_up = Ogre::Vector3::ZERO; Ogre::Vector3 m_listener_velocity = Ogre::Vector3::ZERO; + ALCdevice* audio_device = nullptr; ALCcontext* sound_context = nullptr; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index 88ef7cacce..a8400080d3 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -320,13 +320,10 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 camera_up = camera_node->getOrientation() * Ogre::Vector3::UNIT_Y; // Direction points down -Z by default (adapted from Ogre::Camera) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; - SetListener(camera_position, camera_direction, camera_up, camera_velocity); - Ogre::Vector3 listener_position = sound_manager->GetListenerPosition(); - - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - m_listener_is_underwater = (water != nullptr ? water->IsUnderWater(listener_position) : false); + SetListener(camera_position, camera_direction, camera_up, camera_velocity); SetListenerEnvironment(camera_position); + sound_manager->Update(dt_sec); } } @@ -347,7 +344,7 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) if (App::audio_engine_controls_environmental_audio->getBool()) { - if (ListenerIsUnderwater()) + if (sound_manager->ListenerIsUnderwater()) { sound_manager->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) /* diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index b9cad924b9..752cc6c744 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -339,11 +339,6 @@ class SoundScriptManager : public Ogre::ScriptLoader void update(float dt_sec); - /** - * @return True if the listener position is below water level. False otherwise. - */ - bool ListenerIsUnderwater() const { return m_listener_is_underwater; } - SoundManager* getSoundManager() { return sound_manager; } private: @@ -354,7 +349,6 @@ class SoundScriptManager : public Ogre::ScriptLoader bool disabled; bool loading_base; - bool m_listener_is_underwater = false; float max_distance; float reference_distance; float rolloff_factor; From bb9cb7c15ce40cd044c4b59381ad84144fdb8787 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 30 Nov 2024 08:03:46 +0100 Subject: [PATCH 088/104] :wrench: Move GetReverbPresetAt method from SoundScriptManager to SoundManager class --- source/main/audio/SoundManager.cpp | 42 ++++++++++++++++++++++ source/main/audio/SoundManager.h | 7 ++++ source/main/audio/SoundScriptManager.cpp | 45 +----------------------- source/main/audio/SoundScriptManager.h | 6 ---- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 253a01dda6..a487a04201 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -424,6 +424,48 @@ void SoundManager::UpdateAlListener() alListenerfv(AL_ORIENTATION, orientation); } +const EFXEAXREVERBPROPERTIES* SoundManager::GetReverbPresetAt(const Ogre::Vector3 position) const +{ + // for the listener we do additional checks + if (position == m_listener_position) + { + if (!App::audio_force_listener_efx_preset->getStr().empty()) + { + return this->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); + } + } + + const auto water = App::GetGameContext()->GetTerrain()->getWater(); + bool position_is_underwater = (water != nullptr ? water->IsUnderWater(position) : false); + if (position_is_underwater) + { + return this->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); + } + + // check if position is inside a collision box with a reverb_preset assigned to it + for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) + { + if (!collision_box.reverb_preset_name.empty()) + { + const Ogre::AxisAlignedBox collision_box_aab = Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi); + + if (collision_box_aab.contains(position)) + { + return this->GetEfxProperties(collision_box.reverb_preset_name); + } + } + } + + if (position == m_listener_position) + { + return this->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); + } + else + { + return nullptr; + } +} + void SoundManager::SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_reverb_properties) { m_listener_efx_reverb_properties = listener_reverb_properties; diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 9a2e72c269..cac3df76e5 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -175,6 +175,13 @@ class SoundManager */ const EFXEAXREVERBPROPERTIES* GetEfxProperties(const std::string& efx_preset_name) const; + /** + * Determines which reverb preset corresponds to the provided position and returns its properties. + * @param position Position for which the reverb preset of the encompassing environment will be returned. + * @return Reverb properties for the provided position. + */ + const EFXEAXREVERBPROPERTIES* GetReverbPresetAt(Ogre::Vector3 position) const; + static const float MAX_DISTANCE; static const float ROLLOFF_FACTOR; static const float REFERENCE_DISTANCE; diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index a8400080d3..da5d8e82a4 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -25,7 +25,6 @@ #include "Actor.h" #include "CameraManager.h" #include "GameContext.h" -#include "IWater.h" #include "Sound.h" #include "SoundManager.h" #include "Utils.h" @@ -362,7 +361,7 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) if (App::audio_enable_efx->getBool()) { - listener_reverb_properties = GetReverbPresetAt(listener_position); + listener_reverb_properties = sound_manager->GetReverbPresetAt(listener_position); } } @@ -373,48 +372,6 @@ void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) } } -const EFXEAXREVERBPROPERTIES* SoundScriptManager::GetReverbPresetAt(const Ogre::Vector3 position) const -{ - // for the listener we do additional checks - if (position == sound_manager->GetListenerPosition()) - { - if (!App::audio_force_listener_efx_preset->getStr().empty()) - { - return sound_manager->GetEfxProperties(App::audio_force_listener_efx_preset->getStr()); - } - } - - const auto water = App::GetGameContext()->GetTerrain()->getWater(); - bool position_is_underwater = (water != nullptr ? water->IsUnderWater(position) : false); - if (position_is_underwater) - { - return sound_manager->GetEfxProperties("EFX_REVERB_PRESET_UNDERWATER"); - } - - // check if position is inside a collision box with a reverb_preset assigned to it - for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) - { - if (!collision_box.reverb_preset_name.empty()) - { - const Ogre::AxisAlignedBox collision_box_aab = Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi); - - if (collision_box_aab.contains(position)) - { - return sound_manager->GetEfxProperties(collision_box.reverb_preset_name); - } - } - } - - if (position == sound_manager->GetListenerPosition()) - { - return sound_manager->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); - } - else - { - return nullptr; - } -} - const StringVector& SoundScriptManager::getScriptPatterns(void) const { return script_patterns; diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 752cc6c744..092b90d28f 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -372,12 +372,6 @@ class SoundScriptManager : public Ogre::ScriptLoader // soundLinks, soundItems, actor_ids, triggers std::map > > > state_map; - /** - * Determines which environment in terms of reverb corresponds to the provided position and returns - * its properties. - * @return Reverb properties for the provided position. - */ - const EFXEAXREVERBPROPERTIES* GetReverbPresetAt(Ogre::Vector3 position) const; void SetListenerEnvironment(Ogre::Vector3 position); SoundManager* sound_manager; From db43be99eb05997f16ce8232cb6ea49017e19876 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 30 Nov 2024 08:21:39 +0100 Subject: [PATCH 089/104] :wrench: Move SetListenerEnvironment method from SoundScriptManager to SoundManager class and rename it to UpdateListenerEnvironment --- source/main/audio/SoundManager.cpp | 39 ++++++++++++++++++----- source/main/audio/SoundManager.h | 13 ++++---- source/main/audio/SoundScriptManager.cpp | 40 ------------------------ source/main/audio/SoundScriptManager.h | 6 ---- 4 files changed, 38 insertions(+), 60 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index a487a04201..9ddf14b088 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -381,8 +381,9 @@ void SoundManager::Update(const float dt_sec) const auto water = App::GetGameContext()->GetTerrain()->getWater(); m_listener_is_underwater = (water != nullptr ? water->IsUnderWater(m_listener_position) : false); - recomputeAllSources(); - UpdateAlListener(); + this->recomputeAllSources(); + this->UpdateAlListener(); + this->UpdateListenerEnvironment(); if(App::audio_enable_efx->getBool()) { @@ -407,6 +408,35 @@ void SoundManager::SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, m_listener_velocity = velocity; } +void SoundManager::UpdateListenerEnvironment() +{ + const EFXEAXREVERBPROPERTIES* listener_reverb_properties = nullptr; + + if (App::audio_engine_controls_environmental_audio->getBool()) + { + if (this->ListenerIsUnderwater()) + { + this->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) + /* + * According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in seawater, + * the absorption should be 0.334 db/km. OpenAL multiplies the Air Absorption Factor with an internal + * value of 0.05dB/m, so we need a factor of 0.00668f. + */ + this->SetAirAbsorptionFactor(0.00668f); + } + else + { + this->SetSpeedOfSound(343.3f); // assume listener is in air at 20° celsius + this->SetAirAbsorptionFactor(1.0f); + } + + if (App::audio_enable_efx->getBool()) + { + m_listener_efx_reverb_properties = this->GetReverbPresetAt(m_listener_position); + } + } +} + void SoundManager::UpdateAlListener() { float orientation[6]; @@ -466,11 +496,6 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetReverbPresetAt(const Ogre::Vector } } -void SoundManager::SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_reverb_properties) -{ - m_listener_efx_reverb_properties = listener_reverb_properties; -} - void SoundManager::UpdateListenerEffectSlot(const float dt_sec) { if(m_listener_efx_reverb_properties == nullptr) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index cac3df76e5..7bd0ec2967 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -95,13 +95,6 @@ class SoundManager */ void SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity); - /** - * Updates the EFX/EAX reverb preset that is used as a base for updating the listener's effect slot. - * @param listener_environment The preset that will be used for the listener environment. - * @see UpdateListenerEffectSlot() - */ - void SetListenerEnvironment(const EFXEAXREVERBPROPERTIES* listener_efx_reverb_properties); - /** * Unlike the name suggests, this sets the listener's gain to 0, essentially muting all sounds. */ @@ -194,6 +187,12 @@ class SoundManager * @see SetListener() */ void UpdateAlListener(); + + /** + * Determines several properties of the environment of the listener and updates OpenAL to use them. + */ + void UpdateListenerEnvironment(); + void recomputeAllSources(); /** diff --git a/source/main/audio/SoundScriptManager.cpp b/source/main/audio/SoundScriptManager.cpp index da5d8e82a4..4654ee205b 100644 --- a/source/main/audio/SoundScriptManager.cpp +++ b/source/main/audio/SoundScriptManager.cpp @@ -24,7 +24,6 @@ #include "Actor.h" #include "CameraManager.h" -#include "GameContext.h" #include "Sound.h" #include "SoundManager.h" #include "Utils.h" @@ -321,7 +320,6 @@ void SoundScriptManager::update(float dt_sec) Ogre::Vector3 camera_direction = camera_node->getOrientation() * -Ogre::Vector3::UNIT_Z; SetListener(camera_position, camera_direction, camera_up, camera_velocity); - SetListenerEnvironment(camera_position); sound_manager->Update(dt_sec); } @@ -334,44 +332,6 @@ void SoundScriptManager::SetListener(Vector3 position, Vector3 direction, Vector sound_manager->SetListener(position, direction, up, velocity); } -void SoundScriptManager::SetListenerEnvironment(Vector3 listener_position) -{ - if (disabled) - return; - - const EFXEAXREVERBPROPERTIES* listener_reverb_properties = nullptr; - - if (App::audio_engine_controls_environmental_audio->getBool()) - { - if (sound_manager->ListenerIsUnderwater()) - { - sound_manager->SetSpeedOfSound(1522.0f); // assume listener is in sea water (i.e. salt water) - /* - * According to the Francois-Garrison formula for frequency-dependant absorption at 5kHz in seawater, - * the absorption should be 0.334 db/km. OpenAL multiplies the Air Absorption Factor with an internal - * value of 0.05dB/m, so we need a factor of 0.00668f. - */ - sound_manager->SetAirAbsorptionFactor(0.00668f); - } - else - { - sound_manager->SetSpeedOfSound(343.3f); // assume listener is in air at 20° celsius - sound_manager->SetAirAbsorptionFactor(1.0f); - } - - if (App::audio_enable_efx->getBool()) - { - listener_reverb_properties = sound_manager->GetReverbPresetAt(listener_position); - } - } - - if (App::audio_enable_efx->getBool()) - { - // always update the environment in case it was changed via console or script - sound_manager->SetListenerEnvironment(listener_reverb_properties); - } -} - const StringVector& SoundScriptManager::getScriptPatterns(void) const { return script_patterns; diff --git a/source/main/audio/SoundScriptManager.h b/source/main/audio/SoundScriptManager.h index 092b90d28f..a6bc061dd2 100644 --- a/source/main/audio/SoundScriptManager.h +++ b/source/main/audio/SoundScriptManager.h @@ -31,12 +31,6 @@ #include -#ifdef __APPLE__ - #include -#else - #include -#endif - #define SOUND_PLAY_ONCE(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigOnce ( (_ACTOR_), (_TRIG_) ) #define SOUND_START(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigStart ( (_ACTOR_), (_TRIG_) ) #define SOUND_STOP(_ACTOR_, _TRIG_) App::GetSoundScriptManager()->trigStop ( (_ACTOR_), (_TRIG_) ) From bc5977aadb5dc73def371a566b35c59775a8e539 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 1 Dec 2024 15:58:38 +0100 Subject: [PATCH 090/104] :triangular_ruler: No longer declare sound obstruction as experimental While the current implementation could be improved in terms of filter parameters and line of sight checks against actors, it is solid enough to no longer be considered experimental. --- source/main/gui/panels/GUI_GameSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 5c6cf78860..593685b7dd 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -335,7 +335,7 @@ void GameSettings::DrawAudioSettings() if (App::audio_enable_efx->getBool()) { DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); - DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction (experimental)")); + DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction")); if (App::audio_efx_reverb_engine->getEnum() == EfxReverbEngine::EAXREVERB) { DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); From f0980805be165e62359d0becf6c42c0e79f24f8b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 11 Dec 2024 06:37:09 +0100 Subject: [PATCH 091/104] :bug: Ensure that limits of reverb parameters are not exceeded if timestep is too large --- source/main/audio/SoundManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 9ddf14b088..43ba24342f 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -526,7 +526,8 @@ void SoundManager::UpdateListenerEffectSlot(const float dt_sec) void SoundManager::SmoothlyUpdateAlAuxiliaryEffectSlot(const float dt_sec, const ALuint slot_id, const EFXEAXREVERBPROPERTIES* target_efx_properties) { const float time_to_target = 0.333f; // seconds to reach the target properties from the current properties - const float step = std::min(dt_sec / time_to_target, 1.0f); + // ensure to not exceed limits of reverb parameters if timestep is too large + const float step = std::min(dt_sec / time_to_target, 0.5f); static std::map current_efx_properties_of_slot; if (target_efx_properties == nullptr) From 02ca1275924c17d3d0ec7809d165ff7b7e7015ad Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Wed, 11 Dec 2024 06:44:34 +0100 Subject: [PATCH 092/104] :triangular_ruler: Add missing this-> to follow coding style guidelines --- source/main/audio/SoundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 43ba24342f..4b67c144c5 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -726,7 +726,7 @@ std::tuple SoundManager::ComputeEarlyReflectionsPro magnitude = 1.0f - early_reflections_pan.length() / Ogre::Math::Sqrt(2.0f * Ogre::Math::Pow(max_distance, 2)); // set delay based on distance to the closest surface - early_reflections_delay = closest_surface_distance / GetSpeedOfSound(); + early_reflections_delay = closest_surface_distance / this->GetSpeedOfSound(); early_reflections_gain = std::min( (m_listener_efx_reverb_properties->flReflectionsGain From 4393bb9e3374b460fcc5a30f850d0a0705ab9c7d Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 14 Dec 2024 07:17:10 +0100 Subject: [PATCH 093/104] :wrench: Express the distance to the intersection in the ray's direction vector's unit This behavior more closely resembles that of Ogre's intersects methods. --- source/main/audio/SoundManager.cpp | 2 +- source/main/physics/collision/Collisions.cpp | 21 ++++++++++++++------ source/main/physics/collision/Collisions.h | 8 +++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 4b67c144c5..2a7b954f8b 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -920,7 +920,7 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound, distance_to_sound); + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound); obstruction_detected = intersection.first; if(!obstruction_detected) diff --git a/source/main/physics/collision/Collisions.cpp b/source/main/physics/collision/Collisions.cpp index e4c8523a82..d07528239b 100644 --- a/source/main/physics/collision/Collisions.cpp +++ b/source/main/physics/collision/Collisions.cpp @@ -674,22 +674,31 @@ std::pair Collisions::intersectsTris(Ogre::Ray ray) return std::make_pair(false, 0.0f); } -std::pair Collisions::intersectsTerrain(Ogre::Ray ray, const Ogre::Real distance_limit, const Ogre::Real step_size) +std::pair Collisions::intersectsTerrain(Ogre::Ray ray) { + const Ogre::Real raydir_length = ray.getDirection().length(); + const Ogre::Real step_size = Ogre::Real(0.1); + + /* + * Normalise ray's direction vector, follow it and take sample points after each step_size. + * Check for an intersection at each sample point. + */ ray.setDirection(ray.getDirection().normalisedCopy()); - for (Ogre::Real distance = Ogre::Real(0); distance < distance_limit; distance += step_size) + for (Ogre::Real distance = Ogre::Real(0); distance <= raydir_length; distance += step_size) { - Ogre::Vector3 position = ray.getPoint(distance); - Ogre::Real terrain_height = App::GetGameContext()->GetTerrain()->GetHeightAt(position.x, position.z); + Ogre::Vector3 position = ray.getPoint(distance); + Ogre::Real terrain_height = App::GetGameContext()->GetTerrain()->GetHeightAt(position.x, position.z); if (terrain_height > position.y) { - return std::make_pair(true, distance); + Ogre::Real distance_in_raydir_units = distance / raydir_length; + + return std::make_pair(true, distance_in_raydir_units); } } - return std::make_pair(false, 0.0f); + return std::make_pair(false, Ogre::Real(0)); } float Collisions::getSurfaceHeight(float x, float z) diff --git a/source/main/physics/collision/Collisions.h b/source/main/physics/collision/Collisions.h index 97059da654..04602888bb 100644 --- a/source/main/physics/collision/Collisions.h +++ b/source/main/physics/collision/Collisions.h @@ -181,13 +181,11 @@ class Collisions std::pair intersectsTris(Ogre::Ray ray); /** - * Checks whether a Ray intersects the terrain. The accuracy of the results largely depends on the step_size parameter. + * Checks whether a Ray intersects the terrain. Intersection tests are only performed for the length of the direction vector of the ray. * @param ray The ray that is checked for an intersection with the terrain. - * @param distance_limit No intersection check is performed beyond this distance starting from the ray's origin toward its direction. - * @param step_size Defines the interval between points of the ray at which intersection checks will be performed. - * @return Pair of whether an intersection was found and the distance to the point of the intersection. + * @return Pair of whether an intersection was found and the distance to the point of the intersection. The distance is measured in the ray's direction vector's unit and cannot be larger than 1.0. */ - std::pair intersectsTerrain(Ogre::Ray ray, Ogre::Real distance_limit, Ogre::Real step_size = Ogre::Real(0.1)); + std::pair intersectsTerrain(Ogre::Ray ray); float getSurfaceHeight(float x, float z); float getSurfaceHeightBelow(float x, float z, float height); From cd2b1efe0d17a30b3861e23079b67a7e7d263d63 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 14 Dec 2024 07:35:47 +0100 Subject: [PATCH 094/104] :wrench: Eliminate an unnecessary vector normalisation --- source/main/audio/SoundManager.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 2a7b954f8b..c9b97ea587 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -914,10 +914,8 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const */ std::pair intersection; - // no normalisation due to how the intersectsTris function determines its number of steps - Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; - Ogre::Real distance_to_sound = direction_to_sound.length(); - Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; + const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); // perform line of sight check against terrain intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound); @@ -932,10 +930,6 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const obstruction_detected = intersection.first; } - // do not normalise before intersectsTris() due to how that function works - direction_to_sound.normalise(); - direct_path_to_sound.setDirection(direction_to_sound); - if(!obstruction_detected) { // perform line of sight check agains collision boxes @@ -944,9 +938,9 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const if (!collision_box.enabled || collision_box.virt) { continue; } intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); - if (intersection.first && intersection.second <= distance_to_sound) + obstruction_detected = intersection.first && intersection.second <= 1.0f; + if (obstruction_detected) { - obstruction_detected = true; break; } } @@ -981,7 +975,7 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const } intersection = direct_path_to_sound.intersects(actor->ar_bounding_box); - obstruction_detected = intersection.first; + obstruction_detected = intersection.first && intersection.second <= 1.0f; if (obstruction_detected) { break; From d25d63ca1f07cb0e35e5afde1919f0ff3ff07151 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 14 Dec 2024 10:47:42 +0100 Subject: [PATCH 095/104] :video_game: Rename audio_default_listener_efx_preset to audio_default_efx_preset Return the default efx preset not just for the listener position but for any position in the game that has no other efx preset set --- source/main/Application.cpp | 2 +- source/main/Application.h | 2 +- source/main/audio/SoundManager.cpp | 4 ++-- source/main/gui/panels/GUI_GameSettings.cpp | 2 +- source/main/gui/panels/GUI_GameSettings.h | 2 +- source/main/system/CVar.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 247e4fed60..50a42b2199 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -213,7 +213,7 @@ CVar* audio_enable_reflection_panning; CVar* audio_enable_efx; CVar* audio_engine_controls_environmental_audio; CVar* audio_efx_reverb_engine; -CVar* audio_default_listener_efx_preset; +CVar* audio_default_efx_preset; CVar* audio_force_listener_efx_preset; CVar* audio_device_name; CVar* audio_doppler_factor; diff --git a/source/main/Application.h b/source/main/Application.h index fd6a6285db..a61908c703 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -458,7 +458,7 @@ extern CVar* audio_enable_reflection_panning; extern CVar* audio_enable_efx; extern CVar* audio_engine_controls_environmental_audio; extern CVar* audio_efx_reverb_engine; -extern CVar* audio_default_listener_efx_preset; +extern CVar* audio_default_efx_preset; extern CVar* audio_force_listener_efx_preset; extern CVar* audio_device_name; extern CVar* audio_doppler_factor; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index c9b97ea587..5981b7cc16 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -486,9 +486,9 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetReverbPresetAt(const Ogre::Vector } } - if (position == m_listener_position) + if (!App::audio_default_efx_preset->getStr().empty()) { - return this->GetEfxProperties(App::audio_default_listener_efx_preset->getStr()); + return this->GetEfxProperties(App::audio_default_efx_preset->getStr()); } else { diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 593685b7dd..a514a43707 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -345,7 +345,7 @@ void GameSettings::DrawAudioSettings() if (App::audio_engine_controls_environmental_audio) { - DrawGTextEdit(App::audio_default_listener_efx_preset, _LC("GameSettings", "Default EFX Reverb Preset"), m_buf_audio_default_listener_efx_preset); + DrawGTextEdit(App::audio_default_efx_preset, _LC("GameSettings", "Default EFX Reverb Preset"), m_buf_audio_default_efx_preset); DrawGTextEdit(App::audio_force_listener_efx_preset, _LC("GameSettings", "Force EFX Reverb Preset"), m_buf_audio_force_listener_efx_preset); } } diff --git a/source/main/gui/panels/GUI_GameSettings.h b/source/main/gui/panels/GUI_GameSettings.h index c84e7671d9..1f895970b8 100644 --- a/source/main/gui/panels/GUI_GameSettings.h +++ b/source/main/gui/panels/GUI_GameSettings.h @@ -52,7 +52,7 @@ class GameSettings Str<1000> m_buf_diag_preset_veh_config; Str<1000> m_buf_app_extra_mod_dir; Str<1000> m_buf_io_outgauge_ip; - Str<1000> m_buf_audio_default_listener_efx_preset; + Str<1000> m_buf_audio_default_efx_preset; Str<1000> m_buf_audio_force_listener_efx_preset; // Pre-formatted combobox items diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index fca9c1acd4..342671a35a 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -159,7 +159,7 @@ void Console::cVarSetupBuiltins() App::audio_enable_efx = this->cVarCreate("audio_enable_efx", "Enable OpenAL EFX", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_engine_controls_environmental_audio = this->cVarCreate("audio_engine_controls_environmental_audio", "Engine-controlled environm. audio", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true"); App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE | CVAR_TYPE_INT, "2"/*(int)EfxReverbEngine::EAXREVERB*/); - App::audio_default_listener_efx_preset = this->cVarCreate("audio_default_listener_efx_preset", "OpenAL default listener EFX preset",CVAR_ARCHIVE); + App::audio_default_efx_preset = this->cVarCreate("audio_default_efx_preset", "OpenAL default EFX preset", CVAR_ARCHIVE); App::audio_force_listener_efx_preset = this->cVarCreate("audio_force_listener_efx_preset", "OpenAL forced listener EFX preset", CVAR_ARCHIVE); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); From 993050660fb44e8c8c39030757f68d39701e569b Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 14 Dec 2024 11:00:59 +0100 Subject: [PATCH 096/104] :sparkles: Implement environmental occlusion of sounds --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 81 ++++++++++++++++++++- source/main/audio/SoundManager.h | 16 +++- source/main/gui/panels/GUI_GameSettings.cpp | 1 + source/main/system/CVar.cpp | 1 + 6 files changed, 96 insertions(+), 5 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 50a42b2199..0f08ca7004 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -209,6 +209,7 @@ CVar* io_invert_orbitcam; CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; +CVar* audio_enable_occlusion; CVar* audio_enable_reflection_panning; CVar* audio_enable_efx; CVar* audio_engine_controls_environmental_audio; diff --git a/source/main/Application.h b/source/main/Application.h index a61908c703..42119e2d33 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -454,6 +454,7 @@ extern CVar* io_invert_orbitcam; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; +extern CVar* audio_enable_occlusion; extern CVar* audio_enable_reflection_panning; extern CVar* audio_enable_efx; extern CVar* audio_engine_controls_environmental_audio; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 5981b7cc16..621ddf1292 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -189,6 +189,28 @@ SoundManager::SoundManager() this->alFilterf(m_efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAIN, 0.33f); this->alFilterf(m_efx_outdoor_obstruction_lowpass_filter_id, AL_LOWPASS_GAINHF, 0.25f); } + + /* + Create wet path filter for occlusion + Currently we don't check for how much high-frequency content the encompassing walls + let through. We assume it's a hard surface with significant absorption + of high frequencies (which should be true for most types of buildings). + */ + alGetError(); + + this->alGenFilters(1, &m_efx_occlusion_wet_path_lowpass_filter_id); + e = alGetError(); + + if (e != AL_NO_ERROR) + { + m_efx_occlusion_wet_path_lowpass_filter_id = AL_FILTER_NULL; + } + else + { + this->alFilteri(m_efx_occlusion_wet_path_lowpass_filter_id, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + this->alFilterf(m_efx_occlusion_wet_path_lowpass_filter_id, AL_LOWPASS_GAIN, 0.33f); + this->alFilterf(m_efx_occlusion_wet_path_lowpass_filter_id, AL_LOWPASS_GAINHF, 0.25f); + } } } else @@ -239,6 +261,11 @@ SoundManager::~SoundManager() this->alDeleteFilters(1, &m_efx_outdoor_obstruction_lowpass_filter_id); } + if(this->alIsFilter(m_efx_occlusion_wet_path_lowpass_filter_id)) + { + this->alDeleteFilters(1, &m_efx_occlusion_wet_path_lowpass_filter_id); + } + if (this->alIsAuxiliaryEffectSlot(m_listener_slot)) { this->alAuxiliaryEffectSloti(m_listener_slot, AL_EFFECTSLOT_EFFECT, AL_EFFECTSLOT_NULL); @@ -393,7 +420,23 @@ void SoundManager::Update(const float dt_sec) // update air absorption factor alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, m_air_absorption_factor); - this->UpdateObstructionFilter(hardware_index); + bool obstruction_detected = this->UpdateObstructionFilter(hardware_index); + + /* + * If an obstruction was detected, also check for occlusions. + * The current implementation ignores the case of exclusion since + * it compares the reverb environments of the source and listener. + * This would not be enough to reliably detect exclusion in outdoor environments. + */ + if (obstruction_detected) + { + this->UpdateOcclusionFilter(hardware_index, m_listener_slot, m_listener_efx_reverb_properties); + } + else + { + // disable occlusion filter just in case it was previously active + alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, m_listener_slot, m_efx_occlusion_wet_path_send_id, AL_FILTER_NULL); + } } this->UpdateListenerEffectSlot(dt_sec); @@ -892,15 +935,15 @@ void SoundManager::recomputeAllSources() #endif } -void SoundManager::UpdateObstructionFilter(const int hardware_index) const +bool SoundManager::UpdateObstructionFilter(const int hardware_index) const { - if(hardware_sources_map[hardware_index] == -1) { return; } // no sound assigned to hardware source + if(hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source if(!App::audio_enable_obstruction->getBool()) { // detach the obstruction filter in case it was attached when the feature was previously enabled alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); - return; + return false; } bool obstruction_detected = false; @@ -993,6 +1036,34 @@ void SoundManager::UpdateObstructionFilter(const int hardware_index) const // reset direct filter for the source in case it has been set previously alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); } + + return obstruction_detected; +} + +bool SoundManager::UpdateOcclusionFilter(const int hardware_index, const ALuint effect_slot_id, const EFXEAXREVERBPROPERTIES* reference_efx_reverb_properties) const +{ + if (hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source + + if (!App::audio_enable_occlusion->getBool()) + { + // detach the occlusion filter in case it was attached when the feature was previously enabled + alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, effect_slot_id, m_efx_occlusion_wet_path_send_id, AL_FILTER_NULL); + return false; + } + + const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; + bool occlusion_detected = this->GetReverbPresetAt(corresponding_sound->getPosition()) != reference_efx_reverb_properties; + + if (occlusion_detected) + { + alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, effect_slot_id, m_efx_occlusion_wet_path_send_id, m_efx_occlusion_wet_path_lowpass_filter_id); + } + else + { + alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, effect_slot_id, m_efx_occlusion_wet_path_send_id, AL_FILTER_NULL); + } + + return occlusion_detected; } void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vector3* vvec) @@ -1021,6 +1092,7 @@ void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vect { case Sound::REASON_PLAY: this->UpdateObstructionFilter(audio_sources[source_index]->hardware_index); + this->UpdateOcclusionFilter (audio_sources[source_index]->hardware_index, m_listener_slot, m_listener_efx_reverb_properties); alSourcePlay(hw_source); break; case Sound::REASON_STOP: alSourceStop(hw_source); @@ -1101,6 +1173,7 @@ void SoundManager::assign(int source_index, int hardware_index) if (audio_source->should_play) { this->UpdateObstructionFilter(hardware_index); + this->UpdateOcclusionFilter (hardware_index, m_listener_slot, m_listener_efx_reverb_properties); alSourcePlay(hw_source); } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 7bd0ec2967..4130107b34 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -257,6 +257,8 @@ class SoundManager bool m_efx_is_available = false; ALuint m_listener_slot = 0; ALuint m_efx_outdoor_obstruction_lowpass_filter_id = 0; + ALuint m_efx_occlusion_wet_path_send_id = 0; + ALuint m_efx_occlusion_wet_path_lowpass_filter_id = 0; float m_air_absorption_factor = 1.0f; EfxReverbEngine m_efx_reverb_engine = EfxReverbEngine::NONE; const EFXEAXREVERBPROPERTIES* m_listener_efx_reverb_properties = nullptr; @@ -330,8 +332,20 @@ class SoundManager * To decide whether the filter should be applied or not, the function performs * various checks against the environment of the listener. * @param hardware_index The index of the hardware source. + * @return True if an obstruction was detected, false otherwise. */ - void UpdateObstructionFilter(const int hardware_index) const; + bool UpdateObstructionFilter(const int hardware_index) const; + + /** + * Applies an occlusion filter to the provided source if certain conditions apply. + * To decide whether the filter should be applied or not, the function checks + * whether the reverb preset of the sound differs from that provided as a parameter. + * @param hardware_index The index of the hardware source. + * @param effect_slot_id The id of the AL effect slot that will be used as a send target + * @param reference_efx_reverb_properties The reverb preset that the reverb preset of the sound location is compared against + * @return True if occlusion was detected, false otherwise. + */ + bool UpdateOcclusionFilter(const int hardware_index, const ALuint effect_slot_id, const EFXEAXREVERBPROPERTIES* reference_efx_reverb_properties) const; }; /// @} diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index a514a43707..e782134dac 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -336,6 +336,7 @@ void GameSettings::DrawAudioSettings() { DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction")); + DrawGCheckbox(App::audio_enable_occlusion, _LC("GameSettings", "Sound occlusion")); if (App::audio_efx_reverb_engine->getEnum() == EfxReverbEngine::EAXREVERB) { DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 342671a35a..28b94be48c 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -152,6 +152,7 @@ void Console::cVarSetupBuiltins() App::audio_master_volume = this->cVarCreate("audio_master_volume", "Sound Volume", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_occlusion = this->cVarCreate("audio_enable_occlusion", "Occlusion of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_reflection_panning = this->cVarCreate("audio_enable_reflection_panning", "Pan reflections", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); From 0745b8ecb87f99ee9a1084008f376333a83f51f8 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 15 Dec 2024 06:49:54 +0100 Subject: [PATCH 097/104] :triangular_ruler: Add spaces to adhere to coding style --- source/main/audio/SoundManager.cpp | 50 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 621ddf1292..d858de9867 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -125,7 +125,7 @@ SoundManager::SoundManager() if (App::audio_enable_efx->getBool()) { // allow user to change reverb engines at will - switch(App::audio_efx_reverb_engine->getEnum()) + switch (App::audio_efx_reverb_engine->getEnum()) { case EfxReverbEngine::EAXREVERB: m_efx_reverb_engine = EfxReverbEngine::EAXREVERB; break; case EfxReverbEngine::REVERB: m_efx_reverb_engine = EfxReverbEngine::REVERB; break; @@ -134,7 +134,7 @@ SoundManager::SoundManager() LOG("SoundManager: Reverb engine disabled"); } - if(m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) + if (m_efx_reverb_engine == EfxReverbEngine::EAXREVERB) { if (alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) { @@ -146,13 +146,13 @@ SoundManager::SoundManager() m_efx_reverb_engine = EfxReverbEngine::REVERB; } } - else if(m_efx_reverb_engine == EfxReverbEngine::REVERB) + else if (m_efx_reverb_engine == EfxReverbEngine::REVERB) { LOG("SoundManager: Using OpenAL standard reverb"); } // create effect slot for the listener - if(!this->alIsAuxiliaryEffectSlot(m_listener_slot)) + if (!this->alIsAuxiliaryEffectSlot(m_listener_slot)) { alGetError(); @@ -231,7 +231,7 @@ SoundManager::SoundManager() alSourcef(hardware_sources[hardware_sources_num], AL_MAX_DISTANCE, MAX_DISTANCE); // connect source to listener slot effect - if(App::audio_enable_efx->getBool()) + if (App::audio_enable_efx->getBool()) { alSource3i(hardware_sources[hardware_sources_num], AL_AUXILIARY_SEND_FILTER, m_listener_slot, 0, AL_FILTER_NULL); } @@ -254,14 +254,14 @@ SoundManager::~SoundManager() alDeleteSources(MAX_HARDWARE_SOURCES, hardware_sources); alDeleteBuffers(MAX_AUDIO_BUFFERS, audio_buffers); - if(m_efx_is_available) + if (m_efx_is_available) { - if(this->alIsFilter(m_efx_outdoor_obstruction_lowpass_filter_id)) + if (this->alIsFilter(m_efx_outdoor_obstruction_lowpass_filter_id)) { this->alDeleteFilters(1, &m_efx_outdoor_obstruction_lowpass_filter_id); } - if(this->alIsFilter(m_efx_occlusion_wet_path_lowpass_filter_id)) + if (this->alIsFilter(m_efx_occlusion_wet_path_lowpass_filter_id)) { this->alDeleteFilters(1, &m_efx_occlusion_wet_path_lowpass_filter_id); } @@ -290,7 +290,7 @@ SoundManager::~SoundManager() void SoundManager::CleanUp() { - if(m_efx_is_available) + if (m_efx_is_available) { m_listener_efx_reverb_properties = nullptr; if (this->alIsAuxiliaryEffectSlot(m_listener_slot)) @@ -412,10 +412,10 @@ void SoundManager::Update(const float dt_sec) this->UpdateAlListener(); this->UpdateListenerEnvironment(); - if(App::audio_enable_efx->getBool()) + if (App::audio_enable_efx->getBool()) { // apply filters to sources when appropriate - for(int hardware_index = 0; hardware_index < hardware_sources_num; hardware_index++) + for (int hardware_index = 0; hardware_index < hardware_sources_num; hardware_index++) { // update air absorption factor alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, m_air_absorption_factor); @@ -541,7 +541,7 @@ const EFXEAXREVERBPROPERTIES* SoundManager::GetReverbPresetAt(const Ogre::Vector void SoundManager::UpdateListenerEffectSlot(const float dt_sec) { - if(m_listener_efx_reverb_properties == nullptr) + if (m_listener_efx_reverb_properties == nullptr) { this->SmoothlyUpdateAlAuxiliaryEffectSlot(dt_sec, m_listener_slot, nullptr); return; @@ -588,7 +588,7 @@ void SoundManager::SmoothlyUpdateAlAuxiliaryEffectSlot(const float dt_sec, const ALuint efx_effect_id; // create new AL effect if not existing - if(m_efx_effect_id_map.find(slot_id) == m_efx_effect_id_map.end()) + if (m_efx_effect_id_map.find(slot_id) == m_efx_effect_id_map.end()) { efx_effect_id = this->CreateAlEffect(target_efx_properties); m_efx_effect_id_map[slot_id] = efx_effect_id; @@ -733,7 +733,7 @@ std::tuple SoundManager::ComputeEarlyReflectionsPro // check for nearby actors const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); - for(const ActorPtr& actor : actors) + for (const ActorPtr& actor : actors) { // ignore own truck if player is driving one if (actor == App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling()) { continue; } @@ -747,7 +747,7 @@ std::tuple SoundManager::ComputeEarlyReflectionsPro closest_surface_distance = std::min(closest_surface_distance, closest_surface_distance_in_this_direction); - if(closest_surface_distance_in_this_direction <= max_distance) + if (closest_surface_distance_in_this_direction <= max_distance) { early_reflections_pan += raycast_direction * (max_distance - closest_surface_distance_in_this_direction); } @@ -861,11 +861,11 @@ ALuint SoundManager::CreateAlEffect(const EFXEAXREVERBPROPERTIES* efx_properties } error = alGetError(); - if(error != AL_NO_ERROR) + if (error != AL_NO_ERROR) { LOG("SoundManager: Could not create EFX effect:" + TOSTRING(alGetString(error))); - if(this->alIsEffect(effect)) + if (this->alIsEffect(effect)) this->alDeleteEffects(1, &effect); return 0; } @@ -881,7 +881,7 @@ void SoundManager::DeleteAlEffect(const ALuint efx_effect_id) const this->alDeleteEffects(1, &efx_effect_id); error = alGetError(); - if(error != AL_NO_ERROR) + if (error != AL_NO_ERROR) { LOG("SoundManager: Could not delete EFX effect: " + TOSTRING(alGetString(error))); } @@ -937,9 +937,9 @@ void SoundManager::recomputeAllSources() bool SoundManager::UpdateObstructionFilter(const int hardware_index) const { - if(hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source + if (hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source - if(!App::audio_enable_obstruction->getBool()) + if (!App::audio_enable_obstruction->getBool()) { // detach the obstruction filter in case it was attached when the feature was previously enabled alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); @@ -964,7 +964,7 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound); obstruction_detected = intersection.first; - if(!obstruction_detected) + if (!obstruction_detected) { // perform line of sight check against collision meshes // for this to work correctly, the direction vector of the ray must have @@ -973,7 +973,7 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const obstruction_detected = intersection.first; } - if(!obstruction_detected) + if (!obstruction_detected) { // perform line of sight check agains collision boxes for (const collision_box_t& collision_box : App::GetGameContext()->GetTerrain()->GetCollisions()->getCollisionBoxes()) @@ -989,12 +989,12 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const } } - if(!obstruction_detected) + if (!obstruction_detected) { // perform line of sight check against actors const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); bool soundsource_belongs_to_current_actor = false; - for(const ActorPtr actor : actors) + for (const ActorPtr actor : actors) { // Trucks shouldn't obstruct their own sound sources since the // obstruction is most likely already contained in the recording. @@ -1026,7 +1026,7 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const } } - if(obstruction_detected) + if (obstruction_detected) { // Apply obstruction filter to the source alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, m_efx_outdoor_obstruction_lowpass_filter_id); From eb2d677a74cdddec1dc00aac6666c383a8b4dc14 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 15 Dec 2024 07:05:45 +0100 Subject: [PATCH 098/104] :wrench: Add helper function for updating source filters --- source/main/audio/SoundManager.cpp | 44 ++++++++++++++++-------------- source/main/audio/SoundManager.h | 6 ++++ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index d858de9867..592421408b 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -420,23 +420,7 @@ void SoundManager::Update(const float dt_sec) // update air absorption factor alSourcef(hardware_sources[hardware_index], AL_AIR_ABSORPTION_FACTOR, m_air_absorption_factor); - bool obstruction_detected = this->UpdateObstructionFilter(hardware_index); - - /* - * If an obstruction was detected, also check for occlusions. - * The current implementation ignores the case of exclusion since - * it compares the reverb environments of the source and listener. - * This would not be enough to reliably detect exclusion in outdoor environments. - */ - if (obstruction_detected) - { - this->UpdateOcclusionFilter(hardware_index, m_listener_slot, m_listener_efx_reverb_properties); - } - else - { - // disable occlusion filter just in case it was previously active - alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, m_listener_slot, m_efx_occlusion_wet_path_send_id, AL_FILTER_NULL); - } + this->UpdateSourceFilters(hardware_index); } this->UpdateListenerEffectSlot(dt_sec); @@ -935,6 +919,26 @@ void SoundManager::recomputeAllSources() #endif } +void SoundManager::UpdateSourceFilters(const int hardware_index) const +{ + bool source_is_obstructed = this->UpdateObstructionFilter(hardware_index); + /* + * If an obstruction was detected, also check for occlusions. + * The current implementation ignores the case of exclusion since + * it compares the reverb environments of the source and listener. + * This would not be enough to reliably detect exclusion in outdoor environments. + */ + if (source_is_obstructed) + { + this->UpdateOcclusionFilter(hardware_index, m_listener_slot, m_listener_efx_reverb_properties); + } + else + { + // disable occlusion filter just in case it was previously active + alSource3i(hardware_sources[hardware_index], AL_AUXILIARY_SEND_FILTER, m_listener_slot, m_efx_occlusion_wet_path_send_id, AL_FILTER_NULL); + } +} + bool SoundManager::UpdateObstructionFilter(const int hardware_index) const { if (hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source @@ -1091,8 +1095,7 @@ void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vect switch (reason) { case Sound::REASON_PLAY: - this->UpdateObstructionFilter(audio_sources[source_index]->hardware_index); - this->UpdateOcclusionFilter (audio_sources[source_index]->hardware_index, m_listener_slot, m_listener_efx_reverb_properties); + this->UpdateSourceFilters(audio_sources[source_index]->hardware_index); alSourcePlay(hw_source); break; case Sound::REASON_STOP: alSourceStop(hw_source); @@ -1172,8 +1175,7 @@ void SoundManager::assign(int source_index, int hardware_index) if (audio_source->should_play) { - this->UpdateObstructionFilter(hardware_index); - this->UpdateOcclusionFilter (hardware_index, m_listener_slot, m_listener_efx_reverb_properties); + this->UpdateSourceFilters(audio_sources[source_index]->hardware_index); alSourcePlay(hw_source); } diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 4130107b34..823bfc5e9c 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -327,6 +327,12 @@ class SoundManager */ std::tuple ComputeEarlyReflectionsProperties() const; + /** + * Helper function to call several other functions to update source filters. + * @param hardware_index The index of the hardware source. + */ + void UpdateSourceFilters(const int hardware_index) const; + /** * Applies an obstruction filter to the provided source if certain conditions apply. * To decide whether the filter should be applied or not, the function performs From 055584448be93ef28c1dd5c1c38dd033ad8ffdaf Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 15 Dec 2024 07:34:53 +0100 Subject: [PATCH 099/104] :wrench: Check for obstruction by terrain after all other checks On most maps, obstruction by terrain might be the least likely option; for optimization purposes it is checked for last --- source/main/audio/SoundManager.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 592421408b..254659abc5 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -964,19 +964,12 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); - // perform line of sight check against terrain - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound); + // perform line of sight check against collision meshes + // for this to work correctly, the direction vector of the ray must have + // the length of the distance from the listener to the sound + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); obstruction_detected = intersection.first; - if (!obstruction_detected) - { - // perform line of sight check against collision meshes - // for this to work correctly, the direction vector of the ray must have - // the length of the distance from the listener to the sound - intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTris(direct_path_to_sound); - obstruction_detected = intersection.first; - } - if (!obstruction_detected) { // perform line of sight check agains collision boxes @@ -1030,6 +1023,13 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const } } + if (!obstruction_detected) + { + // perform line of sight check against terrain + intersection = App::GetGameContext()->GetTerrain()->GetCollisions()->intersectsTerrain(direct_path_to_sound); + obstruction_detected = intersection.first; + } + if (obstruction_detected) { // Apply obstruction filter to the source From 6e44dc15284bcb4834b1c7953b6f46c160b5d289 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sun, 15 Dec 2024 08:24:27 +0100 Subject: [PATCH 100/104] :bug: Skip cases where the obstruction filter might become unstable While this fixes driving over the ramp on nHelens modded, there are still some cases where the obstruction filter is unstable, e.g. when driving with some vehicles on the roads which use collision boxes on nHelens modded --- source/main/audio/SoundManager.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 254659abc5..1d5734d728 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -977,7 +977,16 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const { if (!collision_box.enabled || collision_box.virt) { continue; } - intersection = direct_path_to_sound.intersects(Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi)); + Ogre::AxisAlignedBox collision_box_aab = Ogre::AxisAlignedBox(collision_box.lo, collision_box.hi); + + // Skip cases where the obstruction filter detection becomes unstable + if ( collision_box_aab.contains(corresponding_sound->getPosition()) + || collision_box_aab.distance(corresponding_sound->getPosition()) < 0.1f) + { + continue; + } + + intersection = direct_path_to_sound.intersects(collision_box_aab); obstruction_detected = intersection.first && intersection.second <= 1.0f; if (obstruction_detected) { From df1906a27c5f47c34ae43ccdc32ede529b2afced Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 21 Dec 2024 07:37:12 +0100 Subject: [PATCH 101/104] :sparkles: Implement directed sounds for exhausts, turboprops and -jets For the sake of performance, it might make sense to cache which nodes are attached to exhausts/turboprops/-jets in the future. --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 138 ++++++++++++++++++++ source/main/audio/SoundManager.h | 23 ++++ source/main/gui/panels/GUI_GameSettings.cpp | 7 +- source/main/physics/air/AeroEngine.h | 2 + source/main/physics/air/TurboJet.h | 2 + source/main/physics/air/TurboProp.h | 2 + source/main/system/CVar.cpp | 1 + 9 files changed, 174 insertions(+), 3 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index 0f08ca7004..f2426ee684 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -210,6 +210,7 @@ CVar* audio_master_volume; CVar* audio_enable_creak; CVar* audio_enable_obstruction; CVar* audio_enable_occlusion; +CVar* audio_enable_directed_sounds; CVar* audio_enable_reflection_panning; CVar* audio_enable_efx; CVar* audio_engine_controls_environmental_audio; diff --git a/source/main/Application.h b/source/main/Application.h index 42119e2d33..b4b93e6cac 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -455,6 +455,7 @@ extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; extern CVar* audio_enable_occlusion; +extern CVar* audio_enable_directed_sounds; extern CVar* audio_enable_reflection_panning; extern CVar* audio_enable_efx; extern CVar* audio_engine_controls_environmental_audio; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 1d5734d728..4c4bab3d11 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -23,6 +23,7 @@ #include "SoundManager.h" +#include "AeroEngine.h" #include "Application.h" #include "IWater.h" #include "Sound.h" @@ -425,6 +426,11 @@ void SoundManager::Update(const float dt_sec) this->UpdateListenerEffectSlot(dt_sec); } + + if (App::audio_enable_directed_sounds->getBool()) + { + this->UpdateDirectedSounds(); + } } void SoundManager::SetListener(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity) @@ -1079,6 +1085,138 @@ bool SoundManager::UpdateOcclusionFilter(const int hardware_index, const ALuint return occlusion_detected; } +void SoundManager::UpdateDirectedSounds() const +{ + for (int hardware_index = 0; hardware_index < hardware_sources_num; hardware_index++) + { + if (hardware_sources_map[hardware_index] == -1) { continue;; } // no sound assigned to hardware source at this index + + const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; + const ActorPtrVec& actors = App::GetGameContext()->GetActorManager()->GetActors(); + + for (const ActorPtr& actor : actors) + { + NodeNum_t sound_node = 0; + bool sound_belongs_to_current_actor = false; + + // check if the sound corresponding to this hardware source belongs to the actor + for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) + { + const soundsource_t& soundsource = actor->ar_soundsources[soundsource_index]; + const int num_sounds = soundsource.ssi->getTemplate()->getNumSounds(); + for (int num_sound = 0; num_sound < num_sounds; ++num_sound) + { + if (soundsource.ssi->getSound(num_sound) == corresponding_sound) + { + sound_node = soundsource.nodenum; + } + } + if (sound_node > 0) { break; } + } + + // if the sound does not belong to a node of the current actor, there is no need for further checks + if (sound_node == 0) { continue; } + + // Check if the sound corresponding to the hardware source is attached to an exhaust node of the actor + const std::vector& exhausts = actor->exhausts; + for (const exhaust_t& exhaust : exhausts) + { + if ( sound_node == exhaust.emitterNode + || sound_node == exhaust.directionNode) + { + const Ogre::Vector3 emitter_node_pos = actor->getNodePosition(exhaust.emitterNode); + const Ogre::Vector3 direction_node_pos = actor->getNodePosition(exhaust.directionNode); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + emitter_node_pos - direction_node_pos, + 60.0f, + 170.0f, + 0.85f, + 0.80f); + + break; + } + } + + // Check if the sound corresponding to the hardware source is attached to an AeroEngine + for (int engine_num = 0; engine_num < actor->ar_num_aeroengines; ++engine_num) + { + const auto& aero_engine = actor->ar_aeroengines[engine_num]; + + if (aero_engine->getType() == AeroEngineType::AE_XPROP) + { + if ( sound_node == aero_engine->getNoderef() + || sound_node == aero_engine->GetBackNode()) + { + const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); + const Ogre::Vector3 aero_engine_back_node = actor->getNodePosition(aero_engine->GetBackNode()); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + aero_engine_ref_node - aero_engine_back_node, + 170.0f, + 270.0f, + 0.85f, + 0.70f); + + break; + } + } + else if (aero_engine->getType() == AeroEngineType::AE_TURBOJET) + { + /* + * Since turbojets currently have no high-pitched noise sounds + * for the air intake, we currently assume all sounds are + * directed rearwards of the engine. + * Should air intake noises be added, a front-directed cone should + * be set for them with significant high-frequency dropoff outside. + */ + + if ( sound_node == aero_engine->getNoderef() + || sound_node == aero_engine->GetFrontNode()) + { + const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); + const Ogre::Vector3 aero_engine_front_node = actor->getNodePosition(aero_engine->GetFrontNode()); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + aero_engine_ref_node - aero_engine_front_node, + 60.0f, + 240.0f, + 0.60f, + 0.60f); + } + + break; + } + else { continue; } + } + } + } +} + +void SoundManager::UpdateConeProperties( + const ALuint source, + const Ogre::Vector3& cone_direction, + const float cone_inner_angle, + const float cone_outer_angle, + const float cone_outer_gain, + const float cone_outer_gain_hf + ) const +{ + alSource3f(source, AL_DIRECTION, cone_direction.x, cone_direction.y, cone_direction.z); + + alSourcef (source, AL_CONE_INNER_ANGLE, cone_inner_angle); + alSourcef (source, AL_CONE_OUTER_ANGLE, cone_outer_angle); + alSourcef (source, AL_CONE_OUTER_GAIN, cone_outer_gain); + + if (App::audio_enable_efx->getBool()) + { + alSourcef(source, AL_CONE_OUTER_GAINHF, cone_outer_gain_hf); + } +} + void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vector3* vvec) { if (!audio_device) diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 823bfc5e9c..0f7f9d054e 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -352,6 +352,29 @@ class SoundManager * @return True if occlusion was detected, false otherwise. */ bool UpdateOcclusionFilter(const int hardware_index, const ALuint effect_slot_id, const EFXEAXREVERBPROPERTIES* reference_efx_reverb_properties) const; + + /** + * Updates AL Cones for sources of directed sound emissions (exhausts, turboprops and turbojets). + */ + void UpdateDirectedSounds() const; + + /** + * Updates the Cone properties for the hardware source. + * @param source The AL source of which the cone properties will be modified. + * @param cone_direction The direction the cone will face. + * @param cone_inner_angle Angle for the inner zone. + * @param cone_outer_angle Angle that marks the border between transitional and outside zone of the cone + * @param cone_outer_gain Gain for the outside zone. + * @param cone_outer_gain_hf High-frequency gain for the outside zone. + */ + void UpdateConeProperties( + const ALuint source, + const Ogre::Vector3& cone_direction, + const float cone_inner_angle, + const float cone_outer_angle, + const float cone_outer_gain, + const float cone_outer_gain_hf + ) const; }; /// @} diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index e782134dac..691638232e 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -334,9 +334,10 @@ void GameSettings::DrawAudioSettings() if (App::audio_enable_efx->getBool()) { - DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); - DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction")); - DrawGCheckbox(App::audio_enable_occlusion, _LC("GameSettings", "Sound occlusion")); + DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); + DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction")); + DrawGCheckbox(App::audio_enable_occlusion, _LC("GameSettings", "Sound occlusion")); + DrawGCheckbox(App::audio_enable_directed_sounds, _LC("GameSettings", "Directed sounds (exhausts etc.)")); if (App::audio_efx_reverb_engine->getEnum() == EfxReverbEngine::EAXREVERB) { DrawGCheckbox(App::audio_enable_reflection_panning, _LC("GameSettings", "Early reflections panning (experimental)")); diff --git a/source/main/physics/air/AeroEngine.h b/source/main/physics/air/AeroEngine.h index e58a1b6c5a..4d4dac121b 100644 --- a/source/main/physics/air/AeroEngine.h +++ b/source/main/physics/air/AeroEngine.h @@ -63,6 +63,8 @@ class AeroEngine virtual bool getIgnition() =0; virtual void setIgnition(bool val) =0; virtual int getNoderef() =0; + virtual NodeNum_t GetFrontNode() const =0; + virtual NodeNum_t GetBackNode() const =0; virtual bool getWarmup() =0; virtual float getRadius() =0; diff --git a/source/main/physics/air/TurboJet.h b/source/main/physics/air/TurboJet.h index 424f35d2b1..70254c8dcb 100644 --- a/source/main/physics/air/TurboJet.h +++ b/source/main/physics/air/TurboJet.h @@ -91,6 +91,8 @@ class Turbojet: public AeroEngine float getThrottle(); float getpropwash() { return m_propwash; }; int getNoderef() { return m_node_back; }; + NodeNum_t GetFrontNode() const override { return m_node_front; }; + NodeNum_t GetBackNode() const override { return m_node_back; }; AeroEngineType getType() { return AeroEngineType::AE_TURBOJET; }; // AeroEngine visuals diff --git a/source/main/physics/air/TurboProp.h b/source/main/physics/air/TurboProp.h index f5616270f0..5b31a87b5d 100644 --- a/source/main/physics/air/TurboProp.h +++ b/source/main/physics/air/TurboProp.h @@ -86,6 +86,8 @@ class Turboprop: public AeroEngine bool getIgnition() { return ignition; }; void setIgnition(bool val) { ignition = val; }; int getNoderef() { return noderef; }; + NodeNum_t GetFrontNode() const override { return RoR::NODENUM_INVALID; }; // turboprops have no front node + NodeNum_t GetBackNode() const override { return nodeback; }; bool getWarmup() { return warmup; }; float getRadius() { return radius; }; diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 28b94be48c..6fef8fbb3b 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -153,6 +153,7 @@ void Console::cVarSetupBuiltins() App::audio_enable_creak = this->cVarCreate("audio_enable_creak", "Creak Sound", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_obstruction = this->cVarCreate("audio_enable_obstruction", "Obstruction of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_occlusion = this->cVarCreate("audio_enable_occlusion", "Occlusion of sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); + App::audio_enable_directed_sounds = this->cVarCreate("audio_enable_directed_sounds", "Directed sounds", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_enable_reflection_panning = this->cVarCreate("audio_enable_reflection_panning", "Pan reflections", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::audio_device_name = this->cVarCreate("audio_device_name", "AudioDevice", CVAR_ARCHIVE); App::audio_doppler_factor = this->cVarCreate("audio_doppler_factor", "Doppler Factor", CVAR_ARCHIVE | CVAR_TYPE_FLOAT, "1.0"); From 055d20e3a0047d9ad217016bb9a39c246dd19d8f Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 21 Dec 2024 11:30:11 +0100 Subject: [PATCH 102/104] :sparkles: Implement directivity for sounds attached to screwprop nodes --- source/main/audio/SoundManager.cpp | 140 ++++++++++++++++---------- source/main/physics/water/ScrewProp.h | 4 + 2 files changed, 92 insertions(+), 52 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 4c4bab3d11..1ae0666d8b 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -26,6 +26,7 @@ #include "AeroEngine.h" #include "Application.h" #include "IWater.h" +#include "ScrewProp.h" #include "Sound.h" #include @@ -1096,8 +1097,7 @@ void SoundManager::UpdateDirectedSounds() const for (const ActorPtr& actor : actors) { - NodeNum_t sound_node = 0; - bool sound_belongs_to_current_actor = false; + NodeNum_t sound_node = RoR::NODENUM_INVALID; // check if the sound corresponding to this hardware source belongs to the actor for (int soundsource_index = 0; soundsource_index < actor->ar_num_soundsources; ++soundsource_index) @@ -1109,15 +1109,18 @@ void SoundManager::UpdateDirectedSounds() const if (soundsource.ssi->getSound(num_sound) == corresponding_sound) { sound_node = soundsource.nodenum; + break; } } - if (sound_node > 0) { break; } } - // if the sound does not belong to a node of the current actor, there is no need for further checks - if (sound_node == 0) { continue; } + if ( sound_node == RoR::NODENUM_INVALID // if the sound does not belong to a node of the current actor, there is no need for further checks + || sound_node == 0) // node 0 might have several default (and undirected) sounds assigned, so skip it + { + continue; + } - // Check if the sound corresponding to the hardware source is attached to an exhaust node of the actor + // Update directivity if the sound corresponding to the hardware source is attached to an exhaust node of the actor const std::vector& exhausts = actor->exhausts; for (const exhaust_t& exhaust : exhausts) { @@ -1139,58 +1142,91 @@ void SoundManager::UpdateDirectedSounds() const } } - // Check if the sound corresponding to the hardware source is attached to an AeroEngine - for (int engine_num = 0; engine_num < actor->ar_num_aeroengines; ++engine_num) + switch(actor->getTruckType()) { - const auto& aero_engine = actor->ar_aeroengines[engine_num]; - - if (aero_engine->getType() == AeroEngineType::AE_XPROP) - { - if ( sound_node == aero_engine->getNoderef() - || sound_node == aero_engine->GetBackNode()) + case ActorType::AIRPLANE: + // Update directivity if the sound corresponding to the hardware source is attached to an AeroEngine + for (int engine_num = 0; engine_num < actor->ar_num_aeroengines; ++engine_num) { - const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); - const Ogre::Vector3 aero_engine_back_node = actor->getNodePosition(aero_engine->GetBackNode()); - - this->UpdateConeProperties( - hardware_sources[hardware_index], - aero_engine_ref_node - aero_engine_back_node, - 170.0f, - 270.0f, - 0.85f, - 0.70f); - - break; + const auto& aero_engine = actor->ar_aeroengines[engine_num]; + + switch(aero_engine->getType()) + { + case AeroEngineType::AE_XPROP: + if ( sound_node == aero_engine->getNoderef() + || sound_node == aero_engine->GetBackNode()) + { + const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); + const Ogre::Vector3 aero_engine_back_node = actor->getNodePosition(aero_engine->GetBackNode()); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + aero_engine_ref_node - aero_engine_back_node, + 170.0f, + 270.0f, + 0.85f, + 0.70f); + } + + break; + + case AeroEngineType::AE_TURBOJET: + /* + * Since turbojets currently have no high-pitched noise sounds + * for the air intake, we currently assume all sounds are + * directed rearwards of the engine. + * Should air intake noises be added, a front-directed cone should + * be set for them with significant high-frequency dropoff outside. + */ + + if ( sound_node == aero_engine->getNoderef() + || sound_node == aero_engine->GetFrontNode()) + { + const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); + const Ogre::Vector3 aero_engine_front_node = actor->getNodePosition(aero_engine->GetFrontNode()); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + aero_engine_ref_node - aero_engine_front_node, + 60.0f, + 240.0f, + 0.60f, + 0.60f); + } + + break; + + default: continue; + } } - } - else if (aero_engine->getType() == AeroEngineType::AE_TURBOJET) - { - /* - * Since turbojets currently have no high-pitched noise sounds - * for the air intake, we currently assume all sounds are - * directed rearwards of the engine. - * Should air intake noises be added, a front-directed cone should - * be set for them with significant high-frequency dropoff outside. - */ - - if ( sound_node == aero_engine->getNoderef() - || sound_node == aero_engine->GetFrontNode()) - { - const Ogre::Vector3 aero_engine_ref_node = actor->getNodePosition(aero_engine->getNoderef()); - const Ogre::Vector3 aero_engine_front_node = actor->getNodePosition(aero_engine->GetFrontNode()); + break; - this->UpdateConeProperties( - hardware_sources[hardware_index], - aero_engine_ref_node - aero_engine_front_node, - 60.0f, - 240.0f, - 0.60f, - 0.60f); + case ActorType::BOAT: + // Update directivity if the sound corresponding to the hardware source is attached to a Screwprop + for (int screwprop_num = 0; screwprop_num < actor->ar_num_screwprops; ++screwprop_num) + { + const auto& screwprop = actor->ar_screwprops[screwprop_num]; + + if ( sound_node == screwprop->GetRefNode() + || sound_node == screwprop->GetBackNode()) + { + const Ogre::Vector3 screwprop_ref_node = actor->getNodePosition(screwprop->GetRefNode()); + const Ogre::Vector3 screwprop_back_node = actor->getNodePosition(screwprop->GetBackNode()); + + this->UpdateConeProperties( + hardware_sources[hardware_index], + screwprop_ref_node - screwprop_back_node, + 70.0f, + 170.0f, + 0.80f, + 0.70f); + + break; + } } - break; - } - else { continue; } + + default: continue; } } } diff --git a/source/main/physics/water/ScrewProp.h b/source/main/physics/water/ScrewProp.h index 13a48fa65e..9285222407 100644 --- a/source/main/physics/water/ScrewProp.h +++ b/source/main/physics/water/ScrewProp.h @@ -45,6 +45,10 @@ class Screwprop void reset(); void toggleReverse(); + NodeNum_t GetRefNode() const { return noderef; }; + NodeNum_t GetBackNode() const { return nodeback; }; + NodeNum_t GetUpNode() const { return nodeup; }; + private: DustPool *splashp, *ripplep; From 7c7ae4313dbba2c9b1e78deb8f8f58a8bd5b076f Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 21 Dec 2024 16:12:11 +0100 Subject: [PATCH 103/104] :wrench: Handle checks for obstructions in a separate function --- source/main/audio/SoundManager.cpp | 46 ++++++++++++++---------------- source/main/audio/SoundManager.h | 16 +++++++---- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 1ae0666d8b..071771130f 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -928,7 +928,10 @@ void SoundManager::recomputeAllSources() void SoundManager::UpdateSourceFilters(const int hardware_index) const { - bool source_is_obstructed = this->UpdateObstructionFilter(hardware_index); + bool source_is_obstructed = this->IsHardwareSourceObstructed(hardware_index); + + this->UpdateObstructionFilter(hardware_index, source_is_obstructed); + /* * If an obstruction was detected, also check for occlusions. * The current implementation ignores the case of exclusion since @@ -946,30 +949,21 @@ void SoundManager::UpdateSourceFilters(const int hardware_index) const } } -bool SoundManager::UpdateObstructionFilter(const int hardware_index) const +bool SoundManager::IsHardwareSourceObstructed(const int hardware_index) const { if (hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source - if (!App::audio_enable_obstruction->getBool()) - { - // detach the obstruction filter in case it was attached when the feature was previously enabled - alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); - return false; - } - - bool obstruction_detected = false; const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; - - // TODO: Simulate diffraction path. + bool obstruction_detected = false; /* - * Perform various line of sight checks until either a collision was detected - * and the filter has to be applied or no obstruction was detected. - */ + * Perform various line of sight checks until either a collision was detected + * and the filter has to be applied or no obstruction was detected. + */ std::pair intersection; - const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; - const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; + const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); // perform line of sight check against collision meshes // for this to work correctly, the direction vector of the ray must have @@ -1046,18 +1040,20 @@ bool SoundManager::UpdateObstructionFilter(const int hardware_index) const obstruction_detected = intersection.first; } - if (obstruction_detected) + return obstruction_detected; +} + +void SoundManager::UpdateObstructionFilter(const int hardware_index, const bool enable_obstruction_filter) const +{ + if (!App::audio_enable_obstruction->getBool() || !enable_obstruction_filter) { + // detach the obstruction filter in case it was attached when the feature was previously enabled + alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); + } + else { // Apply obstruction filter to the source alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, m_efx_outdoor_obstruction_lowpass_filter_id); } - else - { - // reset direct filter for the source in case it has been set previously - alSourcei(hardware_sources[hardware_index], AL_DIRECT_FILTER, AL_FILTER_NULL); - } - - return obstruction_detected; } bool SoundManager::UpdateOcclusionFilter(const int hardware_index, const ALuint effect_slot_id, const EFXEAXREVERBPROPERTIES* reference_efx_reverb_properties) const diff --git a/source/main/audio/SoundManager.h b/source/main/audio/SoundManager.h index 0f7f9d054e..30899712a0 100644 --- a/source/main/audio/SoundManager.h +++ b/source/main/audio/SoundManager.h @@ -334,13 +334,19 @@ class SoundManager void UpdateSourceFilters(const int hardware_index) const; /** - * Applies an obstruction filter to the provided source if certain conditions apply. - * To decide whether the filter should be applied or not, the function performs - * various checks against the environment of the listener. + * Performs various checks against the environment of the listener to determine + * whether the sound belonging to a hardware source is obstructed or not. * @param hardware_index The index of the hardware source. - * @return True if an obstruction was detected, false otherwise. + * @return True if the sound is obstructed from the listener's point of view, false otherwise. */ - bool UpdateObstructionFilter(const int hardware_index) const; + bool IsHardwareSourceObstructed(const int hardware_index) const; + + /** + * Applies an obstruction filter to the provided hardware source. + * @param hardware_index The index of the hardware source. + * @param enable_obstruction_filter Whether the obstruction filter should be enabled for the hardware source or not. + */ + void UpdateObstructionFilter(const int hardware_index, const bool enable_obstruction_filter) const; /** * Applies an occlusion filter to the provided source if certain conditions apply. From 470eb85c6eedbe6300891ba891fc85516ab54b22 Mon Sep 17 00:00:00 2001 From: Niklas Kersten Date: Sat, 21 Dec 2024 16:37:58 +0100 Subject: [PATCH 104/104] :sparkles: Add option to force obstruction filter when inside an actor There is no simple way to tell whether a truck has a closed cabin or not. This option exists to force the obstruction filter inside an actor if desired. Since the check if the listener is inside the player's coupled actor is based on the actor's AAB, the obstruction filter might get enabled if the listener is close to but not inside the actor. Future work: it might be better to perform line of sight checks against the mesh of a vehicle, which could solve both problems. --- source/main/Application.cpp | 1 + source/main/Application.h | 1 + source/main/audio/SoundManager.cpp | 21 +++++++++++++++++---- source/main/gui/panels/GUI_GameSettings.cpp | 4 ++++ source/main/system/CVar.cpp | 1 + 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/source/main/Application.cpp b/source/main/Application.cpp index f2426ee684..e07c47c2db 100644 --- a/source/main/Application.cpp +++ b/source/main/Application.cpp @@ -217,6 +217,7 @@ CVar* audio_engine_controls_environmental_audio; CVar* audio_efx_reverb_engine; CVar* audio_default_efx_preset; CVar* audio_force_listener_efx_preset; +CVar* audio_force_obstruction_inside_vehicles; CVar* audio_device_name; CVar* audio_doppler_factor; CVar* audio_menu_music; diff --git a/source/main/Application.h b/source/main/Application.h index b4b93e6cac..6b9d06db28 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -454,6 +454,7 @@ extern CVar* io_invert_orbitcam; extern CVar* audio_master_volume; extern CVar* audio_enable_creak; extern CVar* audio_enable_obstruction; +extern CVar* audio_force_obstruction_inside_vehicles; extern CVar* audio_enable_occlusion; extern CVar* audio_enable_directed_sounds; extern CVar* audio_enable_reflection_panning; diff --git a/source/main/audio/SoundManager.cpp b/source/main/audio/SoundManager.cpp index 071771130f..bf82c0b53b 100644 --- a/source/main/audio/SoundManager.cpp +++ b/source/main/audio/SoundManager.cpp @@ -953,8 +953,19 @@ bool SoundManager::IsHardwareSourceObstructed(const int hardware_index) const { if (hardware_sources_map[hardware_index] == -1) { return false; } // no sound assigned to hardware source - const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; - bool obstruction_detected = false; + /* + * There is no simple way to know whether a truck has a closed cabin or not; hence + * provide an option to always force obstruction if the player is inside a vehicle. + */ + if + ( + App::audio_force_obstruction_inside_vehicles->getBool() + && App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling() != nullptr + && App::GetGameContext()->GetPlayerCharacter()->GetActorCoupling()->ar_bounding_box.contains(m_listener_position) + ) + { + return true; + } /* * Perform various line of sight checks until either a collision was detected @@ -962,8 +973,10 @@ bool SoundManager::IsHardwareSourceObstructed(const int hardware_index) const */ std::pair intersection; - const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; - const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + const SoundPtr& corresponding_sound = audio_sources[hardware_sources_map[hardware_index]]; + const Ogre::Vector3 direction_to_sound = corresponding_sound->getPosition() - m_listener_position; + const Ogre::Ray direct_path_to_sound = Ray(m_listener_position, direction_to_sound); + bool obstruction_detected = false; // perform line of sight check against collision meshes // for this to work correctly, the direction vector of the ray must have diff --git a/source/main/gui/panels/GUI_GameSettings.cpp b/source/main/gui/panels/GUI_GameSettings.cpp index 691638232e..cabd3758a4 100644 --- a/source/main/gui/panels/GUI_GameSettings.cpp +++ b/source/main/gui/panels/GUI_GameSettings.cpp @@ -336,6 +336,10 @@ void GameSettings::DrawAudioSettings() { DrawGCombo(App::audio_efx_reverb_engine, _LC("GameSettings", "OpenAL Reverb engine"), m_combo_items_efx_reverb_engine.c_str()); DrawGCheckbox(App::audio_enable_obstruction, _LC("GameSettings", "Sound obstruction")); + if (App::audio_enable_obstruction->getBool()) + { + DrawGCheckbox(App::audio_force_obstruction_inside_vehicles, _LC("GameSettings", "Force obstruction inside vehicles")); + } DrawGCheckbox(App::audio_enable_occlusion, _LC("GameSettings", "Sound occlusion")); DrawGCheckbox(App::audio_enable_directed_sounds, _LC("GameSettings", "Directed sounds (exhausts etc.)")); if (App::audio_efx_reverb_engine->getEnum() == EfxReverbEngine::EAXREVERB) diff --git a/source/main/system/CVar.cpp b/source/main/system/CVar.cpp index 6fef8fbb3b..6f3b7dd7b1 100644 --- a/source/main/system/CVar.cpp +++ b/source/main/system/CVar.cpp @@ -163,6 +163,7 @@ void Console::cVarSetupBuiltins() App::audio_efx_reverb_engine = this->cVarCreate("audio_efx_reverb_engine", "OpenAL EFX Reverb Engine", CVAR_ARCHIVE | CVAR_TYPE_INT, "2"/*(int)EfxReverbEngine::EAXREVERB*/); App::audio_default_efx_preset = this->cVarCreate("audio_default_efx_preset", "OpenAL default EFX preset", CVAR_ARCHIVE); App::audio_force_listener_efx_preset = this->cVarCreate("audio_force_listener_efx_preset", "OpenAL forced listener EFX preset", CVAR_ARCHIVE); + App::audio_force_obstruction_inside_vehicles = this->cVarCreate("audio_force_obstruction_inside_vehicles", "Force obstruction inside vehicles", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false"); App::gfx_flares_mode = this->cVarCreate("gfx_flares_mode", "Lights", CVAR_ARCHIVE | CVAR_TYPE_INT, "4"/*(int)GfxFlaresMode::ALL_VEHICLES_ALL_LIGHTS*/); App::gfx_polygon_mode = this->cVarCreate("gfx_polygon_mode", "Polygon mode", CVAR_TYPE_INT, "1"/*(int)Ogre::PM_SOLID*/);