From 896b4bb1fa1919a7addb01cea1f7c6adb8e3715d Mon Sep 17 00:00:00 2001 From: TryTwo Date: Thu, 10 Oct 2024 17:00:41 -0700 Subject: [PATCH 1/2] AudioPanel: Refactor to use Config system. Some options were changed to a different format, for easier compatibility. Removed VolumeChanged signal, as ConfigChanged will trigger what is needed. Only applies UpdateSoundStream to things that can change during emulation. Settings::SetVolume might no longer be used, but left it in. --- Source/Core/AudioCommon/Enums.h | 2 +- Source/Core/DolphinQt/Settings.cpp | 5 - Source/Core/DolphinQt/Settings.h | 1 - Source/Core/DolphinQt/Settings/AudioPane.cpp | 414 +++++++------------ Source/Core/DolphinQt/Settings/AudioPane.h | 40 +- 5 files changed, 156 insertions(+), 306 deletions(-) diff --git a/Source/Core/AudioCommon/Enums.h b/Source/Core/AudioCommon/Enums.h index 7151213b2c..66cd89d627 100644 --- a/Source/Core/AudioCommon/Enums.h +++ b/Source/Core/AudioCommon/Enums.h @@ -5,7 +5,7 @@ namespace AudioCommon { -enum class DPL2Quality +enum class DPL2Quality : int { Lowest = 0, Low = 1, diff --git a/Source/Core/DolphinQt/Settings.cpp b/Source/Core/DolphinQt/Settings.cpp index 5fc424f32d..bc807c7d26 100644 --- a/Source/Core/DolphinQt/Settings.cpp +++ b/Source/Core/DolphinQt/Settings.cpp @@ -438,22 +438,17 @@ int Settings::GetVolume() const void Settings::SetVolume(int volume) { if (GetVolume() != volume) - { Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, volume); - emit VolumeChanged(volume); - } } void Settings::IncreaseVolume(int volume) { AudioCommon::IncreaseVolume(Core::System::GetInstance(), volume); - emit VolumeChanged(GetVolume()); } void Settings::DecreaseVolume(int volume) { AudioCommon::DecreaseVolume(Core::System::GetInstance(), volume); - emit VolumeChanged(GetVolume()); } bool Settings::IsLogVisible() const diff --git a/Source/Core/DolphinQt/Settings.h b/Source/Core/DolphinQt/Settings.h index ad7be608c3..39337ceb5b 100644 --- a/Source/Core/DolphinQt/Settings.h +++ b/Source/Core/DolphinQt/Settings.h @@ -197,7 +197,6 @@ signals: void CursorVisibilityChanged(); void LockCursorChanged(); void KeepWindowOnTopChanged(bool top); - void VolumeChanged(int volume); void NANDRefresh(); void RegistersVisibilityChanged(bool visible); void ThreadsVisibilityChanged(bool visible); diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index b457fe382a..e28b463409 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -3,8 +3,6 @@ #include "DolphinQt/Settings/AudioPane.h" -#include -#include #include #include #include @@ -12,9 +10,7 @@ #include #include #include -#include #include -#include #include #include "AudioCommon/AudioCommon.h" @@ -24,8 +20,11 @@ #include "Core/Config/MainSettings.h" #include "Core/Core.h" #include "Core/System.h" - #include "DolphinQt/Config/ConfigControls/ConfigBool.h" +#include "DolphinQt/Config/ConfigControls/ConfigChoice.h" +#include "DolphinQt/Config/ConfigControls/ConfigRadio.h" +#include "DolphinQt/Config/ConfigControls/ConfigSlider.h" + #include "DolphinQt/Config/SettingsWindow.h" #include "DolphinQt/Settings.h" @@ -33,10 +32,10 @@ AudioPane::AudioPane() { CheckNeedForLatencyControl(); CreateWidgets(); - LoadSettings(); + AddDescriptions(); ConnectWidgets(); + OnBackendChanged(); - connect(&Settings::Instance(), &Settings::VolumeChanged, this, &AudioPane::OnVolumeChanged); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); @@ -46,29 +45,31 @@ AudioPane::AudioPane() void AudioPane::CreateWidgets() { - auto* dsp_box = new QGroupBox(tr("DSP Emulation Engine")); - auto* dsp_layout = new QVBoxLayout; + auto* dsp_box = new QGroupBox(tr("DSP Options")); + auto* dsp_layout = new QHBoxLayout; dsp_box->setLayout(dsp_layout); - m_dsp_hle = new QRadioButton(tr("DSP HLE (recommended)")); - m_dsp_lle = new QRadioButton(tr("DSP LLE Recompiler (slow)")); - m_dsp_interpreter = new QRadioButton(tr("DSP LLE Interpreter (very slow)")); + QLabel* dsp_combo_label = new QLabel(tr("DSP Emulation Engine:")); + m_dsp_combo = new ConfigComplexChoice(Config::MAIN_DSP_HLE, Config::MAIN_DSP_JIT); + m_dsp_combo->Add(tr("HLE (recommended)"), true, true); + m_dsp_combo->Add(tr("LLE Recompiler (slow)"), false, true); + m_dsp_combo->Add(tr("LLE Interpreter (very slow)"), false, false); + m_dsp_combo->Refresh(); + // The state true/false shouldn't normally happen and forces no option to be selected. + if (m_dsp_combo->currentIndex() == -1) + m_dsp_combo->setCurrentIndex(0); - dsp_layout->addStretch(1); - dsp_layout->addWidget(m_dsp_hle); - dsp_layout->addWidget(m_dsp_lle); - dsp_layout->addWidget(m_dsp_interpreter); - dsp_layout->addStretch(1); + dsp_layout->addWidget(dsp_combo_label); + dsp_layout->addWidget(m_dsp_combo, Qt::AlignLeft); auto* volume_box = new QGroupBox(tr("Volume")); auto* volume_layout = new QVBoxLayout; - m_volume_slider = new QSlider; - m_volume_indicator = new QLabel(); + m_volume_slider = new ConfigSlider(0, 100, Config::MAIN_AUDIO_VOLUME); + m_volume_indicator = new QLabel(tr("%1 %").arg(m_volume_slider->value())); volume_box->setLayout(volume_layout); - m_volume_slider->setMinimum(0); - m_volume_slider->setMaximum(100); + m_volume_slider->setOrientation(Qt::Vertical); m_volume_indicator->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); m_volume_indicator->setFixedWidth(QFontMetrics(font()).boundingRect(tr("%1 %").arg(100)).width()); @@ -80,63 +81,49 @@ void AudioPane::CreateWidgets() auto* backend_layout = new QFormLayout; backend_box->setLayout(backend_layout); m_backend_label = new QLabel(tr("Audio Backend:")); - m_backend_combo = new QComboBox(); - m_dolby_pro_logic = new QCheckBox(tr("Dolby Pro Logic II Decoder")); - - if (m_latency_control_supported) - { - m_latency_label = new QLabel(tr("Latency:")); - m_latency_spin = new QSpinBox(); - m_latency_spin->setMinimum(0); - m_latency_spin->setMaximum(200); - m_latency_spin->setToolTip( - tr("Sets the latency in milliseconds. Higher values may reduce audio " - "crackling. Certain backends only.")); - } - - 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_backend_combo = + new ConfigStringChoice(AudioCommon::GetSoundBackends(), Config::MAIN_AUDIO_BACKEND); + m_dolby_pro_logic = new ConfigBool(tr("Dolby Pro Logic II Decoder"), Config::MAIN_DPL2_DECODER); 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); + QStringList quality_options{tr("Lowest (Latency ~10 ms)"), tr("Low (Latency ~20 ms)"), + tr("High (Latency ~40 ms)"), tr("Highest (Latency ~80 ms)")}; - 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); + m_dolby_quality_combo = new ConfigChoice(quality_options, Config::MAIN_DPL2_QUALITY); backend_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop); backend_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); backend_layout->addRow(m_backend_label, m_backend_combo); - if (m_latency_control_supported) - backend_layout->addRow(m_latency_label, m_latency_spin); #ifdef _WIN32 - m_wasapi_device_label = new QLabel(tr("Device:")); - m_wasapi_device_combo = new QComboBox; + std::vector> wasapi_options; + wasapi_options.push_back( + std::pair{tr("Default Device"), QStringLiteral("default")}); + + for (auto string : WASAPIStream::GetAvailableDevices()) + { + wasapi_options.push_back(std::pair{QString::fromStdString(string), + QString::fromStdString(string)}); + } + + m_wasapi_device_label = new QLabel(tr("Output Device:")); + m_wasapi_device_combo = new ConfigStringChoice(wasapi_options, Config::MAIN_WASAPI_DEVICE); backend_layout->addRow(m_wasapi_device_label, m_wasapi_device_combo); #endif + if (m_latency_control_supported) + { + m_latency_slider = new ConfigSlider(0, 200, Config::MAIN_AUDIO_LATENCY); + m_latency_label = new QLabel(tr("Latency: %1 ms").arg(m_latency_slider->value())); + m_latency_label->setFixedWidth( + QFontMetrics(font()).boundingRect(tr("Latency: 000 ms")).width()); + + backend_layout->addRow(m_latency_label, m_latency_slider); + } + 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); + backend_layout->addRow(m_dolby_quality_label, m_dolby_quality_combo); dsp_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); @@ -145,14 +132,9 @@ void AudioPane::CreateWidgets() misc_box->setLayout(misc_layout); m_audio_fill_gaps = new ConfigBool(tr("Fill Audio Gaps"), Config::MAIN_AUDIO_FILL_GAPS); - m_audio_fill_gaps->SetDescription( - tr("Repeat existing audio during lag spikes to prevent stuttering." - "

If unsure, leave this checked.")); m_speed_up_mute_enable = new ConfigBool(tr("Mute When Disabling Speed Limit"), Config::MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT); - m_speed_up_mute_enable->SetDescription( - tr("Mutes the audio when overriding the emulation speed limit (default hotkey: Tab).")); misc_layout->addWidget(m_audio_fill_gaps, 0, 0, 1, 1); misc_layout->addWidget(m_speed_up_mute_enable, 1, 0, 1, 1); @@ -173,186 +155,43 @@ void AudioPane::CreateWidgets() void AudioPane::ConnectWidgets() { - connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &AudioPane::SaveSettings); - connect(m_volume_slider, &QSlider::valueChanged, this, &AudioPane::SaveSettings); - if (m_latency_control_supported) - { - connect(m_latency_spin, &QSpinBox::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_dsp_hle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); - connect(m_dsp_lle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); - connect(m_dsp_interpreter, &QRadioButton::toggled, this, &AudioPane::SaveSettings); - -#ifdef _WIN32 - connect(m_wasapi_device_combo, &QComboBox::currentIndexChanged, this, &AudioPane::SaveSettings); -#endif -} - -void AudioPane::LoadSettings() -{ - auto& settings = Settings::Instance(); - - // DSP - if (Config::Get(Config::MAIN_DSP_HLE)) - { - m_dsp_hle->setChecked(true); - } - else - { - m_dsp_lle->setChecked(Config::Get(Config::MAIN_DSP_JIT)); - m_dsp_interpreter->setChecked(!Config::Get(Config::MAIN_DSP_JIT)); - } - - // Backend - const auto current = Config::Get(Config::MAIN_AUDIO_BACKEND); - bool selection_set = false; - for (const auto& backend : AudioCommon::GetSoundBackends()) - { - m_backend_combo->addItem(tr(backend.c_str()), QVariant(QString::fromStdString(backend))); - if (backend == current) - { - m_backend_combo->setCurrentIndex(m_backend_combo->count() - 1); - selection_set = true; - } - } - if (!selection_set) - m_backend_combo->setCurrentIndex(-1); - - OnBackendChanged(); - - // Volume - OnVolumeChanged(settings.GetVolume()); - - // DPL2 - m_dolby_pro_logic->setChecked(Config::Get(Config::MAIN_DPL2_DECODER)); - 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) && !m_dsp_hle->isChecked()) - { - EnableDolbyQualityWidgets(m_dolby_pro_logic->isChecked()); - } - - // Latency - if (m_latency_control_supported) - m_latency_spin->setValue(Config::Get(Config::MAIN_AUDIO_LATENCY)); - -#ifdef _WIN32 - if (Config::Get(Config::MAIN_WASAPI_DEVICE) == "default") - { - m_wasapi_device_combo->setCurrentIndex(0); - } - else - { - m_wasapi_device_combo->setCurrentText( - QString::fromStdString(Config::Get(Config::MAIN_WASAPI_DEVICE))); - } -#endif -} - -void AudioPane::SaveSettings() -{ - auto& settings = Settings::Instance(); - - // DSP - if (Config::Get(Config::MAIN_DSP_HLE) != m_dsp_hle->isChecked() || - Config::Get(Config::MAIN_DSP_JIT) != m_dsp_lle->isChecked()) - { - OnDspChanged(); - } - Config::SetBaseOrCurrent(Config::MAIN_DSP_HLE, m_dsp_hle->isChecked()); - Config::SetBaseOrCurrent(Config::MAIN_DSP_JIT, m_dsp_lle->isChecked()); - - // Backend - const auto selection = - m_backend_combo->itemData(m_backend_combo->currentIndex()).toString().toStdString(); - std::string backend = Config::Get(Config::MAIN_AUDIO_BACKEND); - - if (selection != backend) - { - backend = selection; - Config::SetBaseOrCurrent(Config::MAIN_AUDIO_BACKEND, selection); - OnBackendChanged(); - } - - // Volume - if (m_volume_slider->value() != settings.GetVolume()) - { - settings.SetVolume(m_volume_slider->value()); - OnVolumeChanged(settings.GetVolume()); - } - - // DPL2 - Config::SetBaseOrCurrent(Config::MAIN_DPL2_DECODER, 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) - Config::SetBaseOrCurrent(Config::MAIN_AUDIO_LATENCY, m_latency_spin->value()); - - // Misc - Config::SetBaseOrCurrent(Config::MAIN_AUDIO_FILL_GAPS, m_audio_fill_gaps->isChecked()); - Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT, - m_speed_up_mute_enable->isChecked()); - -#ifdef _WIN32 - std::string device = "default"; - - if (m_wasapi_device_combo->currentIndex() != 0) - device = m_wasapi_device_combo->currentText().toStdString(); - - Config::SetBaseOrCurrent(Config::MAIN_WASAPI_DEVICE, device); -#endif - - AudioCommon::UpdateSoundStream(Core::System::GetInstance()); + connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &AudioPane::OnBackendChanged); + connect(m_dolby_pro_logic, &ConfigBool::toggled, this, &AudioPane::OnDspChanged); + connect(m_dsp_combo, &ConfigComplexChoice::currentIndexChanged, this, &AudioPane::OnDspChanged); + connect(m_volume_slider, &QSlider::valueChanged, this, [this](int value) { + m_volume_indicator->setText(tr("%1%").arg(value)); + AudioCommon::UpdateSoundStream(Core::System::GetInstance()); + }); + connect(m_latency_slider, &QSlider::valueChanged, this, + [this](int value) { m_latency_label->setText(tr("Latency: %1 ms").arg(value)); }); } void AudioPane::OnDspChanged() { const auto backend = Config::Get(Config::MAIN_AUDIO_BACKEND); - - m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend) && - !m_dsp_hle->isChecked()); - EnableDolbyQualityWidgets(AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked() && - m_dolby_pro_logic->isChecked()); + const bool enabled = + AudioCommon::SupportsDPL2Decoder(backend) && !Config::Get(Config::MAIN_DSP_HLE); + m_dolby_pro_logic->setEnabled(enabled); + m_dolby_quality_label->setEnabled(enabled && m_dolby_pro_logic->isChecked()); + m_dolby_quality_combo->setEnabled(enabled && m_dolby_pro_logic->isChecked()); } void AudioPane::OnBackendChanged() { + OnDspChanged(); + const auto backend = Config::Get(Config::MAIN_AUDIO_BACKEND); - m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend) && - !m_dsp_hle->isChecked()); - EnableDolbyQualityWidgets(AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked() && - m_dolby_pro_logic->isChecked()); if (m_latency_control_supported) { m_latency_label->setEnabled(AudioCommon::SupportsLatencyControl(backend)); - m_latency_spin->setEnabled(AudioCommon::SupportsLatencyControl(backend)); + m_latency_slider->setEnabled(AudioCommon::SupportsLatencyControl(backend)); } #ifdef _WIN32 bool is_wasapi = backend == BACKEND_WASAPI; m_wasapi_device_label->setHidden(!is_wasapi); m_wasapi_device_combo->setHidden(!is_wasapi); - - if (is_wasapi) - { - m_wasapi_device_combo->clear(); - m_wasapi_device_combo->addItem(tr("Default Device")); - - for (const auto device : WASAPIStream::GetAvailableDevices()) - m_wasapi_device_combo->addItem(QString::fromStdString(device)); - } #endif m_volume_slider->setEnabled(AudioCommon::SupportsVolumeChanges(backend)); @@ -361,22 +200,21 @@ void AudioPane::OnBackendChanged() void AudioPane::OnEmulationStateChanged(bool running) { - m_dsp_hle->setEnabled(!running); - m_dsp_lle->setEnabled(!running); - m_dsp_interpreter->setEnabled(!running); + m_dsp_combo->setEnabled(!running); m_backend_label->setEnabled(!running); m_backend_combo->setEnabled(!running); if (AudioCommon::SupportsDPL2Decoder(Config::Get(Config::MAIN_AUDIO_BACKEND)) && - !m_dsp_hle->isChecked()) + !Config::Get(Config::MAIN_DSP_HLE)) { m_dolby_pro_logic->setEnabled(!running); - EnableDolbyQualityWidgets(!running && m_dolby_pro_logic->isChecked()); + m_dolby_quality_label->setEnabled(!running && m_dolby_pro_logic->isChecked()); + m_dolby_quality_combo->setEnabled(!running && m_dolby_pro_logic->isChecked()); } if (m_latency_control_supported && AudioCommon::SupportsLatencyControl(Config::Get(Config::MAIN_AUDIO_BACKEND))) { m_latency_label->setEnabled(!running); - m_latency_spin->setEnabled(!running); + m_latency_slider->setEnabled(!running); } #ifdef _WIN32 @@ -384,53 +222,79 @@ void AudioPane::OnEmulationStateChanged(bool running) #endif } -void AudioPane::OnVolumeChanged(int volume) -{ - m_volume_slider->setValue(volume); - m_volume_indicator->setText(tr("%1%").arg(volume)); -} - void AudioPane::CheckNeedForLatencyControl() { std::vector backends = AudioCommon::GetSoundBackends(); m_latency_control_supported = std::ranges::any_of(backends, AudioCommon::SupportsLatencyControl); } -QString AudioPane::GetDPL2QualityLabel(AudioCommon::DPL2Quality value) const +void AudioPane::AddDescriptions() { - 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"); - } -} + static const char TR_DSP_DESCRIPTION[] = QT_TR_NOOP( + "Selects how the Digital Signal Processor (DSP) is emulated. Determines how the audio is " + "processed and what system features are available.

" + "HLE - High Level Emulation of the DSP. Fast, but not always accurate. Lacks Dolby " + "Pro Logic II decoding.

" + "LLE Recompiler - Low Level Emulation of the DSP, via a recompiler. Slower, but more " + "accurate. Enables Dolby Pro Logic II decoding on certain audio backends.

" + "LLE Interpreter - Low Level Emulation of the DSP, via an interpreter. Slowest, for " + "debugging purposes only. Not recommended.

If unsure, select " + "HLE."); + static const char TR_AUDIO_BACKEND_DESCRIPTION[] = + QT_TR_NOOP("Selects which audio API to use internally.

If unsure, " + "select %1."); + static const char TR_WASAPI_DEVICE_DESCRIPTION[] = + QT_TR_NOOP("Selects an output device to use.

If unsure, select " + "Default Device."); + static const char TR_LATENCY_SLIDER_DESCRIPTION[] = QT_TR_NOOP( + "Sets the audio latency in milliseconds. Higher values may reduce audio crackling. Certain " + "backends only.

If unsure, leave this at 20 ms."); + static const char TR_DOLBY_DESCRIPTION[] = + QT_TR_NOOP("Enables Dolby Pro Logic II emulation using 5.1 surround. Certain backends only. " + "

If unsure, leave this unchecked."); + static const char TR_DOLBY_OPTIONS_DESCRIPTION[] = QT_TR_NOOP( + "Adjusts the quality setting of the Dolby Pro Logic II decoder. Higher presets increases " + "audio latency.

If unsure, select High."); + static const char TR_VOLUME_DESCRIPTION[] = + QT_TR_NOOP("Adjusts audio output volume.

If unsure, leave this at " + "100%."); + static const char TR_FILL_AUDIO_GAPS_DESCRIPTION[] = QT_TR_NOOP( + "Repeat existing audio during lag spikes to prevent stuttering.

If " + "unsure, leave this checked."); + static const char TR_SPEED_UP_MUTE_DESCRIPTION[] = + QT_TR_NOOP("Mutes the audio when overriding the emulation speed limit (default hotkey: Tab). " + "

If unsure, leave this unchecked."); -QString AudioPane::GetDPL2ApproximateLatencyLabel(AudioCommon::DPL2Quality value) const -{ - switch (value) - { - case AudioCommon::DPL2Quality::Lowest: - return tr("Latency: ~10 ms"); - case AudioCommon::DPL2Quality::Low: - return tr("Latency: ~20 ms"); - case AudioCommon::DPL2Quality::Highest: - return tr("Latency: ~80 ms"); - default: - return tr("Latency: ~40 ms"); - } -} + m_dsp_combo->SetTitle(tr("DSP Emulation Engine")); + m_dsp_combo->SetDescription(tr(TR_DSP_DESCRIPTION)); -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); + m_backend_combo->SetTitle(tr("Audio Backend")); + m_backend_combo->SetDescription( + tr(TR_AUDIO_BACKEND_DESCRIPTION) + .arg(QString::fromStdString(AudioCommon::GetDefaultSoundBackend()))); + + m_dolby_pro_logic->SetTitle(tr("Dolby Pro Logic II Decoder")); + m_dolby_pro_logic->SetDescription(tr(TR_DOLBY_DESCRIPTION)); + + m_dolby_quality_combo->SetTitle(tr("Decoding Quality")); + m_dolby_quality_combo->SetDescription(tr(TR_DOLBY_OPTIONS_DESCRIPTION)); + +#ifdef _WIN32 + m_wasapi_device_combo->SetTitle(tr("Output Device")); + m_wasapi_device_combo->SetDescription(tr(TR_WASAPI_DEVICE_DESCRIPTION)); +#endif + m_volume_slider->SetTitle(tr("Volume")); + m_volume_slider->SetDescription(tr(TR_VOLUME_DESCRIPTION)); + + if (m_latency_control_supported) + { + m_latency_slider->SetTitle(tr("Latency")); + m_latency_slider->SetDescription(tr(TR_LATENCY_SLIDER_DESCRIPTION)); + } + + m_speed_up_mute_enable->SetTitle(tr("Mute When Disabling Speed Limit")); + m_speed_up_mute_enable->SetDescription(tr(TR_SPEED_UP_MUTE_DESCRIPTION)); + + m_audio_fill_gaps->SetTitle(tr("Fill Audio Gaps")); + m_audio_fill_gaps->SetDescription(tr(TR_FILL_AUDIO_GAPS_DESCRIPTION)); } diff --git a/Source/Core/DolphinQt/Settings/AudioPane.h b/Source/Core/DolphinQt/Settings/AudioPane.h index 825865eafe..40c8c4edb1 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.h +++ b/Source/Core/DolphinQt/Settings/AudioPane.h @@ -10,13 +10,15 @@ namespace AudioCommon enum class DPL2Quality; } -class QCheckBox; -class QComboBox; +class ConfigBool; +class ConfigChoice; +class ConfigComplexChoice; +class ConfigRadioBool; +class ConfigSlider; +class ConfigStringChoice; class QHBoxLayout; class QLabel; class QRadioButton; -class QSlider; -class QSpinBox; class SettingsWindow; class ConfigBool; @@ -29,47 +31,37 @@ public: private: void CreateWidgets(); void ConnectWidgets(); - - void LoadSettings(); - void SaveSettings(); + void AddDescriptions(); 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; - QHBoxLayout* m_main_layout; // DSP Engine - QRadioButton* m_dsp_hle; - QRadioButton* m_dsp_lle; - QRadioButton* m_dsp_interpreter; + ConfigComplexChoice* m_dsp_combo; // Volume - QSlider* m_volume_slider; + ConfigSlider* m_volume_slider; QLabel* m_volume_indicator; // Backend QLabel* m_backend_label; - QComboBox* m_backend_combo; - QCheckBox* m_dolby_pro_logic; + ConfigStringChoice* m_backend_combo; + + ConfigBool* 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; + ConfigChoice* m_dolby_quality_combo; + QLabel* m_latency_label; - QSpinBox* m_latency_spin; + ConfigSlider* m_latency_slider; #ifdef _WIN32 QLabel* m_wasapi_device_label; - QComboBox* m_wasapi_device_combo; + ConfigStringChoice* m_wasapi_device_combo; #endif // Misc Settings From e5608c6ca5d594e1de25997b1b87d68287892661 Mon Sep 17 00:00:00 2001 From: TryTwo Date: Wed, 26 Mar 2025 13:15:57 -0700 Subject: [PATCH 2/2] ConfigControl fix: Add invalid index check to ConfigComplexChoice. Resolve with a default index that can be set. If more control is needed, it could be changed to allow multiple states to point to the same index. --- .../DolphinQt/Config/ConfigControls/ConfigChoice.cpp | 12 +++++++++++- .../DolphinQt/Config/ConfigControls/ConfigChoice.h | 2 ++ Source/Core/DolphinQt/Settings/AudioPane.cpp | 5 ++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp index 68592a1ce2..5db63dfc0e 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp @@ -153,13 +153,23 @@ void ConfigComplexChoice::UpdateComboIndex() }; auto it = std::find_if(m_options.begin(), m_options.end(), is_correct_option); - int index = static_cast(std::distance(m_options.begin(), it)); + int index; + + if (it == m_options.end()) + index = m_default_index; + else + index = static_cast(std::distance(m_options.begin(), it)); // Will crash if not blocked const QSignalBlocker blocker(this); setCurrentIndex(index); } +void ConfigComplexChoice::SetDefault(int index) +{ + m_default_index = index; +} + const std::pair ConfigComplexChoice::GetLocation() const { auto visit = [](auto& v) { return v.GetLocation(); }; diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h index 93ca06953f..4ef02ab569 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h @@ -62,6 +62,7 @@ public: void Add(const QString& name, const OptionVariant option1, const OptionVariant option2); void Refresh(); void Reset(); + void SetDefault(int index); const std::pair GetLocation() const; private: @@ -73,4 +74,5 @@ private: const InfoVariant m_setting1; const InfoVariant m_setting2; std::vector> m_options; + int m_default_index = -1; }; diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index e28b463409..6ec374b4a2 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -54,10 +54,9 @@ void AudioPane::CreateWidgets() m_dsp_combo->Add(tr("HLE (recommended)"), true, true); m_dsp_combo->Add(tr("LLE Recompiler (slow)"), false, true); m_dsp_combo->Add(tr("LLE Interpreter (very slow)"), false, false); + // The state true/false shouldn't normally happen, but is HLE (index 0) when it does. + m_dsp_combo->SetDefault(0); m_dsp_combo->Refresh(); - // The state true/false shouldn't normally happen and forces no option to be selected. - if (m_dsp_combo->currentIndex() == -1) - m_dsp_combo->setCurrentIndex(0); dsp_layout->addWidget(dsp_combo_label); dsp_layout->addWidget(m_dsp_combo, Qt::AlignLeft);