diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index a8f09c2688..467406dd9c 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -101,6 +101,11 @@ std::string GetDefaultSoundBackend() return backend; } +DPL2Quality GetDefaultDPL2Quality() +{ + return DPL2Quality::High; +} + std::vector GetSoundBackends() { std::vector backends; diff --git a/Source/Core/AudioCommon/AudioCommon.h b/Source/Core/AudioCommon/AudioCommon.h index d4dbd84a48..a294057590 100644 --- a/Source/Core/AudioCommon/AudioCommon.h +++ b/Source/Core/AudioCommon/AudioCommon.h @@ -9,6 +9,7 @@ #include #include +#include "AudioCommon/Enums.h" #include "AudioCommon/SoundStream.h" class Mixer; @@ -21,6 +22,7 @@ void InitSoundStream(); void ShutdownSoundStream(); std::string GetDefaultSoundBackend(); std::vector GetSoundBackends(); +DPL2Quality GetDefaultDPL2Quality(); bool SupportsDPL2Decoder(std::string_view backend); bool SupportsLatencyControl(std::string_view backend); bool SupportsVolumeChanges(std::string_view backend); diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj b/Source/Core/AudioCommon/AudioCommon.vcxproj index 419cfa4ea6..09c8734b7d 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj @@ -53,6 +53,7 @@ + diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters index 7f4c74fed6..0d9a4818ad 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters @@ -56,6 +56,7 @@ SoundStreams + diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt index cac46b6b33..908c60ed5e 100644 --- a/Source/Core/AudioCommon/CMakeLists.txt +++ b/Source/Core/AudioCommon/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(audiocommon CubebStream.h CubebUtils.cpp CubebUtils.h + Enums.h Mixer.cpp Mixer.h SurroundDecoder.cpp diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp index da515aa8f3..5c3100c52c 100644 --- a/Source/Core/AudioCommon/CubebStream.cpp +++ b/Source/Core/AudioCommon/CubebStream.cpp @@ -37,7 +37,7 @@ bool CubebStream::Init() if (!m_ctx) return false; - m_stereo = !SConfig::GetInstance().bDPL2Decoder; + m_stereo = !SConfig::GetInstance().ShouldUseDPL2Decoder(); cubeb_stream_params params; params.rate = m_mixer->GetSampleRate(); diff --git a/Source/Core/AudioCommon/Enums.h b/Source/Core/AudioCommon/Enums.h new file mode 100644 index 0000000000..ec979ff941 --- /dev/null +++ b/Source/Core/AudioCommon/Enums.h @@ -0,0 +1,16 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +namespace AudioCommon +{ +enum class DPL2Quality +{ + Lowest = 0, + Low = 1, + High = 2, + Highest = 3 +}; +} // namespace AudioCommon diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index 5c1cb3a33f..e414538613 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "AudioCommon/Mixer.h" +#include "AudioCommon/Enums.h" #include #include @@ -12,11 +13,28 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Swap.h" +#include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" +static u32 DPL2QualityToFrameBlockSize(AudioCommon::DPL2Quality quality) +{ + switch (quality) + { + case AudioCommon::DPL2Quality::Lowest: + return 512; + case AudioCommon::DPL2Quality::Low: + return 1024; + case AudioCommon::DPL2Quality::Highest: + return 4096; + default: + return 2048; + } +} + Mixer::Mixer(unsigned int BackendSampleRate) : m_sampleRate(BackendSampleRate), m_stretcher(BackendSampleRate), - m_surround_decoder(BackendSampleRate, SURROUND_BLOCK_SIZE) + m_surround_decoder(BackendSampleRate, + DPL2QualityToFrameBlockSize(Config::Get(Config::MAIN_DPL2_QUALITY))) { INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized"); } diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 83a13cf5d6..b38ab7f47a 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -54,7 +54,6 @@ private: static constexpr u32 CONTROL_AVG = 32; // In freq_shift per FIFO size offset const unsigned int SURROUND_CHANNELS = 6; - const unsigned int SURROUND_BLOCK_SIZE = 512; class MixerFifo final { diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 4852495d23..887e0f97f2 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -221,7 +221,7 @@ void OpenALStream::SoundLoop() bool float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0; bool surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi(); - bool use_surround = SConfig::GetInstance().bDPL2Decoder && surround_capable; + bool use_surround = SConfig::GetInstance().ShouldUseDPL2Decoder() && surround_capable; // As there is no extension to check for 32-bit fixed point support // and we know that only a X-Fi with hardware OpenAL supports it, diff --git a/Source/Core/AudioCommon/PulseAudioStream.cpp b/Source/Core/AudioCommon/PulseAudioStream.cpp index e480ed9e6e..8372683a25 100644 --- a/Source/Core/AudioCommon/PulseAudioStream.cpp +++ b/Source/Core/AudioCommon/PulseAudioStream.cpp @@ -19,7 +19,7 @@ PulseAudio::PulseAudio() = default; bool PulseAudio::Init() { - m_stereo = !SConfig::GetInstance().bDPL2Decoder; + m_stereo = !SConfig::GetInstance().ShouldUseDPL2Decoder(); m_channels = m_stereo ? 2 : 6; // will tell PA we use a Stereo or 5.0 channel setup NOTICE_LOG(AUDIO, "PulseAudio backend using %d channels", m_channels); diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 4ab3f0733a..86e8f0a4a9 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -32,6 +32,8 @@ const ConfigInfo MAIN_GC_LANGUAGE{{System::Main, "Core", "SelectedLanguage" const ConfigInfo MAIN_OVERRIDE_REGION_SETTINGS{ {System::Main, "Core", "OverrideRegionSettings"}, false}; const ConfigInfo MAIN_DPL2_DECODER{{System::Main, "Core", "DPL2Decoder"}, false}; +const ConfigInfo MAIN_DPL2_QUALITY{{System::Main, "Core", "DPL2Quality"}, + AudioCommon::GetDefaultDPL2Quality()}; const ConfigInfo MAIN_AUDIO_LATENCY{{System::Main, "Core", "AudioLatency"}, 20}; const ConfigInfo MAIN_AUDIO_STRETCH{{System::Main, "Core", "AudioStretch"}, false}; const ConfigInfo MAIN_AUDIO_STRETCH_LATENCY{{System::Main, "Core", "AudioStretchMaxLatency"}, @@ -141,5 +143,4 @@ const ConfigInfo MAIN_RESOURCEPACK_PATH{{System::Main, "General", " ""}; const ConfigInfo MAIN_FS_PATH{{System::Main, "General", "NANDRootPath"}, ""}; const ConfigInfo MAIN_SD_PATH{{System::Main, "General", "WiiSDCardPath"}, ""}; - } // namespace Config diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 8172e5c23c..8278578a9c 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -13,6 +13,11 @@ namespace PowerPC enum class CPUCore; } +namespace AudioCommon +{ +enum class DPL2Quality; +} + namespace Config { // Main.Core @@ -32,6 +37,7 @@ extern const ConfigInfo MAIN_ENABLE_CHEATS; extern const ConfigInfo MAIN_GC_LANGUAGE; extern const ConfigInfo MAIN_OVERRIDE_REGION_SETTINGS; extern const ConfigInfo MAIN_DPL2_DECODER; +extern const ConfigInfo MAIN_DPL2_QUALITY; extern const ConfigInfo MAIN_AUDIO_LATENCY; extern const ConfigInfo MAIN_AUDIO_STRETCH; extern const ConfigInfo MAIN_AUDIO_STRETCH_LATENCY; @@ -108,5 +114,4 @@ extern const ConfigInfo MAIN_LOAD_PATH; extern const ConfigInfo MAIN_RESOURCEPACK_PATH; extern const ConfigInfo MAIN_FS_PATH; extern const ConfigInfo MAIN_SD_PATH; - } // namespace Config diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index 9483aed414..629bba3a2d 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -35,6 +35,8 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location) Config::MAIN_MEMCARD_A_PATH.location, Config::MAIN_MEMCARD_B_PATH.location, Config::MAIN_AUTO_DISC_CHANGE.location, + Config::MAIN_DPL2_DECODER.location, + Config::MAIN_DPL2_QUALITY.location, // Main.Display Config::MAIN_FULLSCREEN_DISPLAY_RES.location, @@ -145,7 +147,6 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location) // UI.General Config::MAIN_USE_DISCORD_PRESENCE.location, - }; return std::find(s_setting_saveable.begin(), s_setting_saveable.end(), config_location) != diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 1915a7eb5f..44a85b0de4 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -1065,3 +1065,8 @@ IniFile SConfig::LoadGameIni(const std::string& id, std::optional revision) game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); return game_ini; } + +bool SConfig::ShouldUseDPL2Decoder() const +{ + return bDPL2Decoder && !bDSPHLE; +} diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 36f7ac353a..6de44b41e1 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -173,6 +173,9 @@ struct SConfig bool bEnableCustomRTC; u32 m_customRTCValue; + // DPL2 + bool ShouldUseDPL2Decoder() const; + DiscIO::Region m_region; std::string m_strVideoBackend; diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index 8c3df4ec76..a43e845265 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -18,6 +18,7 @@ #include #include "AudioCommon/AudioCommon.h" +#include "AudioCommon/Enums.h" #include "AudioCommon/WASAPIStream.h" #include "Core/Config/MainSettings.h" @@ -93,6 +94,29 @@ void AudioPane::CreateWidgets() m_dolby_pro_logic->setToolTip( tr("Enables Dolby Pro Logic II emulation using 5.1 surround. Certain backends only.")); + auto* dolby_quality_layout = new QHBoxLayout; + + m_dolby_quality_label = new QLabel(tr("Decoding Quality:")); + + m_dolby_quality_slider = new QSlider(Qt::Horizontal); + m_dolby_quality_slider->setMinimum(0); + m_dolby_quality_slider->setMaximum(3); + m_dolby_quality_slider->setPageStep(1); + m_dolby_quality_slider->setTickPosition(QSlider::TicksBelow); + m_dolby_quality_slider->setToolTip( + tr("Quality of the DPLII decoder. Audio latency increases with quality.")); + m_dolby_quality_slider->setTracking(true); + + m_dolby_quality_low_label = new QLabel(GetDPL2QualityLabel(AudioCommon::DPL2Quality::Lowest)); + m_dolby_quality_highest_label = + new QLabel(GetDPL2QualityLabel(AudioCommon::DPL2Quality::Highest)); + m_dolby_quality_latency_label = + new QLabel(GetDPL2ApproximateLatencyLabel(AudioCommon::DPL2Quality::Highest)); + + dolby_quality_layout->addWidget(m_dolby_quality_low_label); + dolby_quality_layout->addWidget(m_dolby_quality_slider); + dolby_quality_layout->addWidget(m_dolby_quality_highest_label); + backend_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop); backend_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); backend_layout->addRow(m_backend_label, m_backend_combo); @@ -107,6 +131,9 @@ void AudioPane::CreateWidgets() #endif backend_layout->addRow(m_dolby_pro_logic); + backend_layout->addRow(m_dolby_quality_label); + backend_layout->addRow(dolby_quality_layout); + backend_layout->addRow(m_dolby_quality_latency_label); auto* stretching_box = new QGroupBox(tr("Audio Stretching Settings")); auto* stretching_layout = new QGridLayout; @@ -154,6 +181,7 @@ void AudioPane::ConnectWidgets() } connect(m_stretching_buffer_slider, &QSlider::valueChanged, this, &AudioPane::SaveSettings); connect(m_dolby_pro_logic, &QCheckBox::toggled, this, &AudioPane::SaveSettings); + connect(m_dolby_quality_slider, &QSlider::valueChanged, this, &AudioPane::SaveSettings); connect(m_stretching_enable, &QCheckBox::toggled, this, &AudioPane::SaveSettings); connect(m_dsp_hle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); connect(m_dsp_lle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); @@ -203,6 +231,13 @@ void AudioPane::LoadSettings() // DPL2 m_dolby_pro_logic->setChecked(SConfig::GetInstance().bDPL2Decoder); + m_dolby_quality_slider->setValue(int(Config::Get(Config::MAIN_DPL2_QUALITY))); + m_dolby_quality_latency_label->setText( + GetDPL2ApproximateLatencyLabel(Config::Get(Config::MAIN_DPL2_QUALITY))); + if (AudioCommon::SupportsDPL2Decoder(current)) + { + EnableDolbyQualityWidgets(m_dolby_pro_logic->isChecked()); + } // Latency if (m_latency_control_supported) @@ -232,6 +267,11 @@ void AudioPane::SaveSettings() auto& settings = Settings::Instance(); // DSP + if (SConfig::GetInstance().bDSPHLE != m_dsp_hle->isChecked() || + SConfig::GetInstance().m_DSPEnableJIT != m_dsp_lle->isChecked()) + { + OnDspChanged(); + } SConfig::GetInstance().bDSPHLE = m_dsp_hle->isChecked(); Config::SetBaseOrCurrent(Config::MAIN_DSP_HLE, m_dsp_hle->isChecked()); SConfig::GetInstance().m_DSPEnableJIT = m_dsp_lle->isChecked(); @@ -257,6 +297,14 @@ void AudioPane::SaveSettings() // DPL2 SConfig::GetInstance().bDPL2Decoder = m_dolby_pro_logic->isChecked(); + Config::SetBase(Config::MAIN_DPL2_QUALITY, + static_cast(m_dolby_quality_slider->value())); + m_dolby_quality_latency_label->setText( + GetDPL2ApproximateLatencyLabel(Config::Get(Config::MAIN_DPL2_QUALITY))); + if (AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked()) + { + EnableDolbyQualityWidgets(m_dolby_pro_logic->isChecked()); + } // Latency if (m_latency_control_supported) @@ -283,11 +331,22 @@ void AudioPane::SaveSettings() AudioCommon::UpdateSoundStream(); } +void AudioPane::OnDspChanged() +{ + const auto backend = SConfig::GetInstance().sBackend; + + m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend) && + !m_dsp_hle->isChecked()); + EnableDolbyQualityWidgets(AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked()); +} + void AudioPane::OnBackendChanged() { const auto backend = SConfig::GetInstance().sBackend; - m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend)); + m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend) && + !m_dsp_hle->isChecked()); + EnableDolbyQualityWidgets(AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked()); if (m_latency_control_supported) { m_latency_label->setEnabled(AudioCommon::SupportsLatencyControl(backend)); @@ -318,9 +377,13 @@ void AudioPane::OnEmulationStateChanged(bool running) m_dsp_hle->setEnabled(!running); m_dsp_lle->setEnabled(!running); m_dsp_interpreter->setEnabled(!running); - m_dolby_pro_logic->setEnabled(!running); m_backend_label->setEnabled(!running); m_backend_combo->setEnabled(!running); + if (AudioCommon::SupportsDPL2Decoder(SConfig::GetInstance().sBackend) && !m_dsp_hle->isChecked()) + { + m_dolby_pro_logic->setEnabled(!running); + EnableDolbyQualityWidgets(!running); + } if (m_latency_control_supported) { m_latency_label->setEnabled(!running); @@ -344,3 +407,42 @@ void AudioPane::CheckNeedForLatencyControl() m_latency_control_supported = std::any_of(backends.cbegin(), backends.cend(), AudioCommon::SupportsLatencyControl); } + +QString AudioPane::GetDPL2QualityLabel(AudioCommon::DPL2Quality value) const +{ + switch (value) + { + case AudioCommon::DPL2Quality::Lowest: + return tr("Lowest"); + case AudioCommon::DPL2Quality::Low: + return tr("Low"); + case AudioCommon::DPL2Quality::Highest: + return tr("Highest"); + default: + return tr("High"); + } +} + +QString AudioPane::GetDPL2ApproximateLatencyLabel(AudioCommon::DPL2Quality value) const +{ + switch (value) + { + case AudioCommon::DPL2Quality::Lowest: + return tr("Latency: ~10ms"); + case AudioCommon::DPL2Quality::Low: + return tr("Latency: ~20ms"); + case AudioCommon::DPL2Quality::Highest: + return tr("Latency: ~80ms"); + default: + return tr("Latency: ~40ms"); + } +} + +void AudioPane::EnableDolbyQualityWidgets(bool enabled) const +{ + m_dolby_quality_label->setEnabled(enabled); + m_dolby_quality_slider->setEnabled(enabled); + m_dolby_quality_low_label->setEnabled(enabled); + m_dolby_quality_highest_label->setEnabled(enabled); + m_dolby_quality_latency_label->setEnabled(enabled); +} diff --git a/Source/Core/DolphinQt/Settings/AudioPane.h b/Source/Core/DolphinQt/Settings/AudioPane.h index 45bd6d6c60..3348e5e908 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.h +++ b/Source/Core/DolphinQt/Settings/AudioPane.h @@ -6,6 +6,11 @@ #include +namespace AudioCommon +{ +enum class DPL2Quality; +} + class QCheckBox; class QComboBox; class QLabel; @@ -30,11 +35,16 @@ private: void OnEmulationStateChanged(bool running); void OnBackendChanged(); + void OnDspChanged(); void OnVolumeChanged(int volume); void CheckNeedForLatencyControl(); bool m_latency_control_supported; + QString GetDPL2QualityLabel(AudioCommon::DPL2Quality value) const; + QString GetDPL2ApproximateLatencyLabel(AudioCommon::DPL2Quality value) const; + void EnableDolbyQualityWidgets(bool enabled) const; + QGridLayout* m_main_layout; // DSP Engine @@ -50,6 +60,11 @@ private: QLabel* m_backend_label; QComboBox* m_backend_combo; QCheckBox* m_dolby_pro_logic; + QLabel* m_dolby_quality_label; + QSlider* m_dolby_quality_slider; + QLabel* m_dolby_quality_low_label; + QLabel* m_dolby_quality_highest_label; + QLabel* m_dolby_quality_latency_label; QLabel* m_latency_label; QSpinBox* m_latency_spin; #ifdef _WIN32