diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 984a45d5..ccc9e8ff 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -38,6 +38,7 @@ set(SWA_KERNEL_CXX_SOURCES "kernel/xdm.cpp" "kernel/heap.cpp" "kernel/memory.cpp" + "kernel/platform.cpp" "kernel/xam.cpp" "kernel/io/file_system.cpp" ) diff --git a/UnleashedRecomp/cfg/config.h b/UnleashedRecomp/cfg/config.h index 9422a86c..ea7c40a7 100644 --- a/UnleashedRecomp/cfg/config.h +++ b/UnleashedRecomp/cfg/config.h @@ -27,6 +27,7 @@ public: CONFIG_DEFINE_LOCALISED("Audio", float, EffectsVolume, 1.0f); CONFIG_DEFINE_ENUM_LOCALISED("Audio", EVoiceLanguage, VoiceLanguage, EVoiceLanguage::English); CONFIG_DEFINE_LOCALISED("Audio", bool, Subtitles, true); + CONFIG_DEFINE_LOCALISED("Audio", bool, MusicAttenuation, false); CONFIG_DEFINE_LOCALISED("Audio", bool, BattleTheme, true); CONFIG_DEFINE_ENUM("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI::D3D12); diff --git a/UnleashedRecomp/framework.h b/UnleashedRecomp/framework.h index a8a87599..e870fec3 100644 --- a/UnleashedRecomp/framework.h +++ b/UnleashedRecomp/framework.h @@ -14,6 +14,13 @@ #define SWA_API extern "C" SWA_DLLIMPORT #endif +#define PROC_ADDRESS(libraryName, procName) \ + GetProcAddress(LoadLibrary(TEXT(libraryName)), procName) + +#define LIB_FUNCTION(returnType, libraryName, procName, ...) \ + typedef returnType _##procName(__VA_ARGS__); \ + _##procName* procName = (_##procName*)PROC_ADDRESS(libraryName, #procName); + template void ByteSwap(T& value) { @@ -66,4 +73,4 @@ constexpr size_t FirstBitLow(TValue value) } return 0; -} \ No newline at end of file +} diff --git a/UnleashedRecomp/kernel/platform.cpp b/UnleashedRecomp/kernel/platform.cpp new file mode 100644 index 00000000..97c072f4 --- /dev/null +++ b/UnleashedRecomp/kernel/platform.cpp @@ -0,0 +1,24 @@ +#include + +#if _WIN32 +LIB_FUNCTION(LONG, "ntdll.dll", RtlGetVersion, PRTL_OSVERSIONINFOW); +#endif + +PlatformVersion GetPlatformVersion() +{ + auto result = PlatformVersion{}; + +#if _WIN32 + OSVERSIONINFOEXW osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + + if (RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi) != 0) + return result; + + result.Major = osvi.dwMajorVersion; + result.Minor = osvi.dwMinorVersion; + result.Build = osvi.dwBuildNumber; +#endif + + return result; +} diff --git a/UnleashedRecomp/kernel/platform.h b/UnleashedRecomp/kernel/platform.h new file mode 100644 index 00000000..a03379a1 --- /dev/null +++ b/UnleashedRecomp/kernel/platform.h @@ -0,0 +1,11 @@ +#pragma once + +struct PlatformVersion +{ +public: + uint32_t Major{}; + uint32_t Minor{}; + uint32_t Build{}; +}; + +extern PlatformVersion GetPlatformVersion(); diff --git a/UnleashedRecomp/locale/config_locale.h b/UnleashedRecomp/locale/config_locale.h index aa0c3b72..027976b6 100644 --- a/UnleashedRecomp/locale/config_locale.h +++ b/UnleashedRecomp/locale/config_locale.h @@ -166,6 +166,11 @@ CONFIG_DEFINE_LOCALE(EffectsVolume) { ELanguage::English, { "Effects Volume", "Adjust the volume for sound effects." } } }; +CONFIG_DEFINE_LOCALE(MusicAttenuation) +{ + { ELanguage::English, { "Music Attenuation", "Fade out the game's music when external media is playing." } } +}; + CONFIG_DEFINE_LOCALE(VoiceLanguage) { { ELanguage::English, { "Voice Language", "Change the language used for character voices." } } diff --git a/UnleashedRecomp/locale/locale.h b/UnleashedRecomp/locale/locale.h index 6e3a4253..e7067c4a 100644 --- a/UnleashedRecomp/locale/locale.h +++ b/UnleashedRecomp/locale/locale.h @@ -59,6 +59,12 @@ inline static std::unordered_map #include #include +#include #include #include +#if _WIN32 +#include +#include + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Media::Control; + +GlobalSystemMediaTransportControlsSessionManager m_sessionManager = nullptr; + +GlobalSystemMediaTransportControlsSessionManager GetSessionManager() +{ + if (m_sessionManager) + return m_sessionManager; + + init_apartment(); + + return m_sessionManager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().get(); +} + +GlobalSystemMediaTransportControlsSession GetCurrentSession() +{ + return GetSessionManager().GetCurrentSession(); +} + +bool IsExternalAudioPlaying() +{ + auto session = GetCurrentSession(); + + if (!session) + return false; + + return session.GetPlaybackInfo().PlaybackStatus() == GlobalSystemMediaTransportControlsSessionPlaybackStatus::Playing; +} + +int AudioPatches::m_isAttenuationSupported = -1; +#endif + be* GetVolume(bool isMusic = true) { auto ppUnkClass = (be*)g_memory.Translate(0x83362FFC); @@ -15,6 +54,22 @@ be* GetVolume(bool isMusic = true) return (be*)g_memory.Translate(4 * ((int)isMusic + 0x1C) + ((be*)g_memory.Translate(ppUnkClass->get() + 4))->get()); } +bool AudioPatches::CanAttenuate() +{ +#if _WIN32 + if (m_isAttenuationSupported >= 0) + return m_isAttenuationSupported; + + auto version = GetPlatformVersion(); + + m_isAttenuationSupported = version.Major == 10 && version.Build >= 17763; + + return m_isAttenuationSupported; +#else + return false; +#endif +} + void AudioPatches::Update(float deltaTime) { auto pMusicVolume = GetVolume(); @@ -23,8 +78,27 @@ void AudioPatches::Update(float deltaTime) if (!pMusicVolume || !pEffectsVolume) return; - *pMusicVolume = Config::MusicVolume; - *pEffectsVolume = Config::EffectsVolume; +#if _WIN32 + if (Config::MusicAttenuation && CanAttenuate()) + { + auto time = 1.0f - expf(2.5f * -deltaTime); + + if (IsExternalAudioPlaying()) + { + *pMusicVolume = std::lerp(*pMusicVolume, 0.0f, time); + } + else + { + *pMusicVolume = std::lerp(*pMusicVolume, Config::MusicVolume, time); + } + } + else +#endif + { + *pMusicVolume = Config::MusicVolume; + } + + *pEffectsVolume = Config::SEVolume; } // Stub volume setter. diff --git a/UnleashedRecomp/patches/audio_patches.h b/UnleashedRecomp/patches/audio_patches.h index 4397c391..e28ec90e 100644 --- a/UnleashedRecomp/patches/audio_patches.h +++ b/UnleashedRecomp/patches/audio_patches.h @@ -2,6 +2,10 @@ class AudioPatches { +protected: + static int m_isAttenuationSupported; + public: + static bool CanAttenuate(); static void Update(float deltaTime); }; diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index 16fa6cc4..e16fb42e 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -9,6 +9,8 @@ #include #include +#include + constexpr float COMMON_PADDING_POS_Y = 118.0f; constexpr float COMMON_PADDING_POS_X = 30.0f; constexpr float INFO_CONTAINER_POS_X = 870.0f; @@ -869,6 +871,7 @@ static void DrawConfigOptions() DrawConfigOption(rowCount++, yOffset, &Config::EffectsVolume, true); DrawConfigOption(rowCount++, yOffset, &Config::VoiceLanguage, OptionsMenu::s_pauseMenuType == SWA::eMenuType_WorldMap, cmnReason); DrawConfigOption(rowCount++, yOffset, &Config::Subtitles, true); + DrawConfigOption(rowCount++, yOffset, &Config::MusicAttenuation, AudioPatches::CanAttenuate(), &Localise("Options_Desc_OSNotSupported")); DrawConfigOption(rowCount++, yOffset, &Config::BattleTheme, true); break; case 3: // VIDEO