Merge pull request #13122 from TryTwo/PR_Audio_Configs

AudioPanel: Refactor to use Config system.
This commit is contained in:
JMC47 2025-03-28 14:52:54 -04:00 committed by GitHub
commit e0032b3e2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 168 additions and 307 deletions

View file

@ -5,7 +5,7 @@
namespace AudioCommon namespace AudioCommon
{ {
enum class DPL2Quality enum class DPL2Quality : int
{ {
Lowest = 0, Lowest = 0,
Low = 1, Low = 1,

View file

@ -153,13 +153,23 @@ void ConfigComplexChoice::UpdateComboIndex()
}; };
auto it = std::find_if(m_options.begin(), m_options.end(), is_correct_option); auto it = std::find_if(m_options.begin(), m_options.end(), is_correct_option);
int index = static_cast<int>(std::distance(m_options.begin(), it)); int index;
if (it == m_options.end())
index = m_default_index;
else
index = static_cast<int>(std::distance(m_options.begin(), it));
// Will crash if not blocked // Will crash if not blocked
const QSignalBlocker blocker(this); const QSignalBlocker blocker(this);
setCurrentIndex(index); setCurrentIndex(index);
} }
void ConfigComplexChoice::SetDefault(int index)
{
m_default_index = index;
}
const std::pair<Config::Location, Config::Location> ConfigComplexChoice::GetLocation() const const std::pair<Config::Location, Config::Location> ConfigComplexChoice::GetLocation() const
{ {
auto visit = [](auto& v) { return v.GetLocation(); }; auto visit = [](auto& v) { return v.GetLocation(); };

View file

@ -62,6 +62,7 @@ public:
void Add(const QString& name, const OptionVariant option1, const OptionVariant option2); void Add(const QString& name, const OptionVariant option1, const OptionVariant option2);
void Refresh(); void Refresh();
void Reset(); void Reset();
void SetDefault(int index);
const std::pair<Config::Location, Config::Location> GetLocation() const; const std::pair<Config::Location, Config::Location> GetLocation() const;
private: private:
@ -73,4 +74,5 @@ private:
const InfoVariant m_setting1; const InfoVariant m_setting1;
const InfoVariant m_setting2; const InfoVariant m_setting2;
std::vector<std::pair<OptionVariant, OptionVariant>> m_options; std::vector<std::pair<OptionVariant, OptionVariant>> m_options;
int m_default_index = -1;
}; };

View file

@ -438,22 +438,17 @@ int Settings::GetVolume() const
void Settings::SetVolume(int volume) void Settings::SetVolume(int volume)
{ {
if (GetVolume() != volume) if (GetVolume() != volume)
{
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, volume); Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, volume);
emit VolumeChanged(volume);
}
} }
void Settings::IncreaseVolume(int volume) void Settings::IncreaseVolume(int volume)
{ {
AudioCommon::IncreaseVolume(Core::System::GetInstance(), volume); AudioCommon::IncreaseVolume(Core::System::GetInstance(), volume);
emit VolumeChanged(GetVolume());
} }
void Settings::DecreaseVolume(int volume) void Settings::DecreaseVolume(int volume)
{ {
AudioCommon::DecreaseVolume(Core::System::GetInstance(), volume); AudioCommon::DecreaseVolume(Core::System::GetInstance(), volume);
emit VolumeChanged(GetVolume());
} }
bool Settings::IsLogVisible() const bool Settings::IsLogVisible() const

View file

@ -197,7 +197,6 @@ signals:
void CursorVisibilityChanged(); void CursorVisibilityChanged();
void LockCursorChanged(); void LockCursorChanged();
void KeepWindowOnTopChanged(bool top); void KeepWindowOnTopChanged(bool top);
void VolumeChanged(int volume);
void NANDRefresh(); void NANDRefresh();
void RegistersVisibilityChanged(bool visible); void RegistersVisibilityChanged(bool visible);
void ThreadsVisibilityChanged(bool visible); void ThreadsVisibilityChanged(bool visible);

View file

@ -3,8 +3,6 @@
#include "DolphinQt/Settings/AudioPane.h" #include "DolphinQt/Settings/AudioPane.h"
#include <QCheckBox>
#include <QComboBox>
#include <QFontMetrics> #include <QFontMetrics>
#include <QFormLayout> #include <QFormLayout>
#include <QGridLayout> #include <QGridLayout>
@ -12,9 +10,7 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QRadioButton> #include <QRadioButton>
#include <QSlider>
#include <QSpacerItem> #include <QSpacerItem>
#include <QSpinBox>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "AudioCommon/AudioCommon.h" #include "AudioCommon/AudioCommon.h"
@ -24,8 +20,11 @@
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/System.h" #include "Core/System.h"
#include "DolphinQt/Config/ConfigControls/ConfigBool.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/Config/SettingsWindow.h"
#include "DolphinQt/Settings.h" #include "DolphinQt/Settings.h"
@ -33,10 +32,10 @@ AudioPane::AudioPane()
{ {
CheckNeedForLatencyControl(); CheckNeedForLatencyControl();
CreateWidgets(); CreateWidgets();
LoadSettings(); AddDescriptions();
ConnectWidgets(); ConnectWidgets();
OnBackendChanged();
connect(&Settings::Instance(), &Settings::VolumeChanged, this, &AudioPane::OnVolumeChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
OnEmulationStateChanged(state != Core::State::Uninitialized); OnEmulationStateChanged(state != Core::State::Uninitialized);
}); });
@ -46,29 +45,30 @@ AudioPane::AudioPane()
void AudioPane::CreateWidgets() void AudioPane::CreateWidgets()
{ {
auto* dsp_box = new QGroupBox(tr("DSP Emulation Engine")); auto* dsp_box = new QGroupBox(tr("DSP Options"));
auto* dsp_layout = new QVBoxLayout; auto* dsp_layout = new QHBoxLayout;
dsp_box->setLayout(dsp_layout); dsp_box->setLayout(dsp_layout);
m_dsp_hle = new QRadioButton(tr("DSP HLE (recommended)")); QLabel* dsp_combo_label = new QLabel(tr("DSP Emulation Engine:"));
m_dsp_lle = new QRadioButton(tr("DSP LLE Recompiler (slow)")); m_dsp_combo = new ConfigComplexChoice(Config::MAIN_DSP_HLE, Config::MAIN_DSP_JIT);
m_dsp_interpreter = new QRadioButton(tr("DSP LLE Interpreter (very slow)")); 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();
dsp_layout->addStretch(1); dsp_layout->addWidget(dsp_combo_label);
dsp_layout->addWidget(m_dsp_hle); dsp_layout->addWidget(m_dsp_combo, Qt::AlignLeft);
dsp_layout->addWidget(m_dsp_lle);
dsp_layout->addWidget(m_dsp_interpreter);
dsp_layout->addStretch(1);
auto* volume_box = new QGroupBox(tr("Volume")); auto* volume_box = new QGroupBox(tr("Volume"));
auto* volume_layout = new QVBoxLayout; auto* volume_layout = new QVBoxLayout;
m_volume_slider = new QSlider; m_volume_slider = new ConfigSlider(0, 100, Config::MAIN_AUDIO_VOLUME);
m_volume_indicator = new QLabel(); m_volume_indicator = new QLabel(tr("%1 %").arg(m_volume_slider->value()));
volume_box->setLayout(volume_layout); volume_box->setLayout(volume_layout);
m_volume_slider->setMinimum(0); m_volume_slider->setOrientation(Qt::Vertical);
m_volume_slider->setMaximum(100);
m_volume_indicator->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); m_volume_indicator->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
m_volume_indicator->setFixedWidth(QFontMetrics(font()).boundingRect(tr("%1 %").arg(100)).width()); m_volume_indicator->setFixedWidth(QFontMetrics(font()).boundingRect(tr("%1 %").arg(100)).width());
@ -80,63 +80,49 @@ void AudioPane::CreateWidgets()
auto* backend_layout = new QFormLayout; auto* backend_layout = new QFormLayout;
backend_box->setLayout(backend_layout); backend_box->setLayout(backend_layout);
m_backend_label = new QLabel(tr("Audio Backend:")); m_backend_label = new QLabel(tr("Audio Backend:"));
m_backend_combo = new QComboBox(); m_backend_combo =
m_dolby_pro_logic = new QCheckBox(tr("Dolby Pro Logic II Decoder")); new ConfigStringChoice(AudioCommon::GetSoundBackends(), Config::MAIN_AUDIO_BACKEND);
m_dolby_pro_logic = new ConfigBool(tr("Dolby Pro Logic II Decoder"), Config::MAIN_DPL2_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_dolby_quality_label = new QLabel(tr("Decoding Quality:")); m_dolby_quality_label = new QLabel(tr("Decoding Quality:"));
m_dolby_quality_slider = new QSlider(Qt::Horizontal); QStringList quality_options{tr("Lowest (Latency ~10 ms)"), tr("Low (Latency ~20 ms)"),
m_dolby_quality_slider->setMinimum(0); tr("High (Latency ~40 ms)"), tr("Highest (Latency ~80 ms)")};
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_combo = new ConfigChoice(quality_options, Config::MAIN_DPL2_QUALITY);
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->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
backend_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); backend_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
backend_layout->addRow(m_backend_label, m_backend_combo); 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 #ifdef _WIN32
m_wasapi_device_label = new QLabel(tr("Device:")); std::vector<std::pair<QString, QString>> wasapi_options;
m_wasapi_device_combo = new QComboBox; wasapi_options.push_back(
std::pair<QString, QString>{tr("Default Device"), QStringLiteral("default")});
for (auto string : WASAPIStream::GetAvailableDevices())
{
wasapi_options.push_back(std::pair<QString, QString>{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); backend_layout->addRow(m_wasapi_device_label, m_wasapi_device_combo);
#endif #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_pro_logic);
backend_layout->addRow(m_dolby_quality_label); backend_layout->addRow(m_dolby_quality_label, m_dolby_quality_combo);
backend_layout->addRow(dolby_quality_layout);
backend_layout->addRow(m_dolby_quality_latency_label);
dsp_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); dsp_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@ -145,14 +131,9 @@ void AudioPane::CreateWidgets()
misc_box->setLayout(misc_layout); misc_box->setLayout(misc_layout);
m_audio_fill_gaps = new ConfigBool(tr("Fill Audio Gaps"), Config::MAIN_AUDIO_FILL_GAPS); 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."
"<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>"));
m_speed_up_mute_enable = new ConfigBool(tr("Mute When Disabling Speed Limit"), m_speed_up_mute_enable = new ConfigBool(tr("Mute When Disabling Speed Limit"),
Config::MAIN_AUDIO_MUTE_ON_DISABLED_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_audio_fill_gaps, 0, 0, 1, 1);
misc_layout->addWidget(m_speed_up_mute_enable, 1, 0, 1, 1); misc_layout->addWidget(m_speed_up_mute_enable, 1, 0, 1, 1);
@ -173,186 +154,43 @@ void AudioPane::CreateWidgets()
void AudioPane::ConnectWidgets() void AudioPane::ConnectWidgets()
{ {
connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &AudioPane::SaveSettings); connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &AudioPane::OnBackendChanged);
connect(m_volume_slider, &QSlider::valueChanged, this, &AudioPane::SaveSettings); connect(m_dolby_pro_logic, &ConfigBool::toggled, this, &AudioPane::OnDspChanged);
if (m_latency_control_supported) connect(m_dsp_combo, &ConfigComplexChoice::currentIndexChanged, this, &AudioPane::OnDspChanged);
{ connect(m_volume_slider, &QSlider::valueChanged, this, [this](int value) {
connect(m_latency_spin, &QSpinBox::valueChanged, this, &AudioPane::SaveSettings); m_volume_indicator->setText(tr("%1%").arg(value));
} AudioCommon::UpdateSoundStream(Core::System::GetInstance());
connect(m_dolby_pro_logic, &QCheckBox::toggled, this, &AudioPane::SaveSettings); });
connect(m_dolby_quality_slider, &QSlider::valueChanged, this, &AudioPane::SaveSettings); connect(m_latency_slider, &QSlider::valueChanged, this,
connect(m_dsp_hle, &QRadioButton::toggled, this, &AudioPane::SaveSettings); [this](int value) { m_latency_label->setText(tr("Latency: %1 ms").arg(value)); });
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<AudioCommon::DPL2Quality>(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());
} }
void AudioPane::OnDspChanged() void AudioPane::OnDspChanged()
{ {
const auto backend = Config::Get(Config::MAIN_AUDIO_BACKEND); const auto backend = Config::Get(Config::MAIN_AUDIO_BACKEND);
const bool enabled =
m_dolby_pro_logic->setEnabled(AudioCommon::SupportsDPL2Decoder(backend) && AudioCommon::SupportsDPL2Decoder(backend) && !Config::Get(Config::MAIN_DSP_HLE);
!m_dsp_hle->isChecked()); m_dolby_pro_logic->setEnabled(enabled);
EnableDolbyQualityWidgets(AudioCommon::SupportsDPL2Decoder(backend) && !m_dsp_hle->isChecked() && m_dolby_quality_label->setEnabled(enabled && m_dolby_pro_logic->isChecked());
m_dolby_pro_logic->isChecked()); m_dolby_quality_combo->setEnabled(enabled && m_dolby_pro_logic->isChecked());
} }
void AudioPane::OnBackendChanged() void AudioPane::OnBackendChanged()
{ {
OnDspChanged();
const auto backend = Config::Get(Config::MAIN_AUDIO_BACKEND); 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) if (m_latency_control_supported)
{ {
m_latency_label->setEnabled(AudioCommon::SupportsLatencyControl(backend)); m_latency_label->setEnabled(AudioCommon::SupportsLatencyControl(backend));
m_latency_spin->setEnabled(AudioCommon::SupportsLatencyControl(backend)); m_latency_slider->setEnabled(AudioCommon::SupportsLatencyControl(backend));
} }
#ifdef _WIN32 #ifdef _WIN32
bool is_wasapi = backend == BACKEND_WASAPI; bool is_wasapi = backend == BACKEND_WASAPI;
m_wasapi_device_label->setHidden(!is_wasapi); m_wasapi_device_label->setHidden(!is_wasapi);
m_wasapi_device_combo->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 #endif
m_volume_slider->setEnabled(AudioCommon::SupportsVolumeChanges(backend)); m_volume_slider->setEnabled(AudioCommon::SupportsVolumeChanges(backend));
@ -361,22 +199,21 @@ void AudioPane::OnBackendChanged()
void AudioPane::OnEmulationStateChanged(bool running) void AudioPane::OnEmulationStateChanged(bool running)
{ {
m_dsp_hle->setEnabled(!running); m_dsp_combo->setEnabled(!running);
m_dsp_lle->setEnabled(!running);
m_dsp_interpreter->setEnabled(!running);
m_backend_label->setEnabled(!running); m_backend_label->setEnabled(!running);
m_backend_combo->setEnabled(!running); m_backend_combo->setEnabled(!running);
if (AudioCommon::SupportsDPL2Decoder(Config::Get(Config::MAIN_AUDIO_BACKEND)) && 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); 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 && if (m_latency_control_supported &&
AudioCommon::SupportsLatencyControl(Config::Get(Config::MAIN_AUDIO_BACKEND))) AudioCommon::SupportsLatencyControl(Config::Get(Config::MAIN_AUDIO_BACKEND)))
{ {
m_latency_label->setEnabled(!running); m_latency_label->setEnabled(!running);
m_latency_spin->setEnabled(!running); m_latency_slider->setEnabled(!running);
} }
#ifdef _WIN32 #ifdef _WIN32
@ -384,53 +221,79 @@ void AudioPane::OnEmulationStateChanged(bool running)
#endif #endif
} }
void AudioPane::OnVolumeChanged(int volume)
{
m_volume_slider->setValue(volume);
m_volume_indicator->setText(tr("%1%").arg(volume));
}
void AudioPane::CheckNeedForLatencyControl() void AudioPane::CheckNeedForLatencyControl()
{ {
std::vector<std::string> backends = AudioCommon::GetSoundBackends(); std::vector<std::string> backends = AudioCommon::GetSoundBackends();
m_latency_control_supported = std::ranges::any_of(backends, AudioCommon::SupportsLatencyControl); m_latency_control_supported = std::ranges::any_of(backends, AudioCommon::SupportsLatencyControl);
} }
QString AudioPane::GetDPL2QualityLabel(AudioCommon::DPL2Quality value) const void AudioPane::AddDescriptions()
{ {
switch (value) static const char TR_DSP_DESCRIPTION[] = QT_TR_NOOP(
{ "Selects how the Digital Signal Processor (DSP) is emulated. Determines how the audio is "
case AudioCommon::DPL2Quality::Lowest: "processed and what system features are available.<br><br>"
return tr("Lowest"); "<b>HLE</b> - High Level Emulation of the DSP. Fast, but not always accurate. Lacks Dolby "
case AudioCommon::DPL2Quality::Low: "Pro Logic II decoding.<br><br>"
return tr("Low"); "<b>LLE Recompiler</b> - Low Level Emulation of the DSP, via a recompiler. Slower, but more "
case AudioCommon::DPL2Quality::Highest: "accurate. Enables Dolby Pro Logic II decoding on certain audio backends.<br><br>"
return tr("Highest"); "<b>LLE Interpreter</b> - Low Level Emulation of the DSP, via an interpreter. Slowest, for "
default: "debugging purposes only. Not recommended.<br><br><dolphin_emphasis>If unsure, select "
return tr("High"); "HLE.</dolphin_emphasis>");
} static const char TR_AUDIO_BACKEND_DESCRIPTION[] =
} QT_TR_NOOP("Selects which audio API to use internally.<br><br><dolphin_emphasis>If unsure, "
"select %1.</dolphin_emphasis>");
static const char TR_WASAPI_DEVICE_DESCRIPTION[] =
QT_TR_NOOP("Selects an output device to use.<br><br><dolphin_emphasis>If unsure, select "
"Default Device.</dolphin_emphasis>");
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.<br><br><dolphin_emphasis>If unsure, leave this at 20 ms.</dolphin_emphasis>");
static const char TR_DOLBY_DESCRIPTION[] =
QT_TR_NOOP("Enables Dolby Pro Logic II emulation using 5.1 surround. Certain backends only. "
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
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.<br><br><dolphin_emphasis>If unsure, select High.</dolphin_emphasis>");
static const char TR_VOLUME_DESCRIPTION[] =
QT_TR_NOOP("Adjusts audio output volume.<br><br><dolphin_emphasis>If unsure, leave this at "
"100%.</dolphin_emphasis>");
static const char TR_FILL_AUDIO_GAPS_DESCRIPTION[] = QT_TR_NOOP(
"Repeat existing audio during lag spikes to prevent stuttering.<br><br><dolphin_emphasis>If "
"unsure, leave this checked.</dolphin_emphasis>");
static const char TR_SPEED_UP_MUTE_DESCRIPTION[] =
QT_TR_NOOP("Mutes the audio when overriding the emulation speed limit (default hotkey: Tab). "
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
QString AudioPane::GetDPL2ApproximateLatencyLabel(AudioCommon::DPL2Quality value) const m_dsp_combo->SetTitle(tr("DSP Emulation Engine"));
{ m_dsp_combo->SetDescription(tr(TR_DSP_DESCRIPTION));
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");
}
}
void AudioPane::EnableDolbyQualityWidgets(bool enabled) const m_backend_combo->SetTitle(tr("Audio Backend"));
{ m_backend_combo->SetDescription(
m_dolby_quality_label->setEnabled(enabled); tr(TR_AUDIO_BACKEND_DESCRIPTION)
m_dolby_quality_slider->setEnabled(enabled); .arg(QString::fromStdString(AudioCommon::GetDefaultSoundBackend())));
m_dolby_quality_low_label->setEnabled(enabled);
m_dolby_quality_highest_label->setEnabled(enabled); m_dolby_pro_logic->SetTitle(tr("Dolby Pro Logic II Decoder"));
m_dolby_quality_latency_label->setEnabled(enabled); 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));
} }

View file

@ -10,13 +10,15 @@ namespace AudioCommon
enum class DPL2Quality; enum class DPL2Quality;
} }
class QCheckBox; class ConfigBool;
class QComboBox; class ConfigChoice;
class ConfigComplexChoice;
class ConfigRadioBool;
class ConfigSlider;
class ConfigStringChoice;
class QHBoxLayout; class QHBoxLayout;
class QLabel; class QLabel;
class QRadioButton; class QRadioButton;
class QSlider;
class QSpinBox;
class SettingsWindow; class SettingsWindow;
class ConfigBool; class ConfigBool;
@ -29,47 +31,37 @@ public:
private: private:
void CreateWidgets(); void CreateWidgets();
void ConnectWidgets(); void ConnectWidgets();
void AddDescriptions();
void LoadSettings();
void SaveSettings();
void OnEmulationStateChanged(bool running); void OnEmulationStateChanged(bool running);
void OnBackendChanged(); void OnBackendChanged();
void OnDspChanged(); void OnDspChanged();
void OnVolumeChanged(int volume);
void CheckNeedForLatencyControl(); void CheckNeedForLatencyControl();
bool m_latency_control_supported; 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; QHBoxLayout* m_main_layout;
// DSP Engine // DSP Engine
QRadioButton* m_dsp_hle; ConfigComplexChoice* m_dsp_combo;
QRadioButton* m_dsp_lle;
QRadioButton* m_dsp_interpreter;
// Volume // Volume
QSlider* m_volume_slider; ConfigSlider* m_volume_slider;
QLabel* m_volume_indicator; QLabel* m_volume_indicator;
// Backend // Backend
QLabel* m_backend_label; QLabel* m_backend_label;
QComboBox* m_backend_combo; ConfigStringChoice* m_backend_combo;
QCheckBox* m_dolby_pro_logic;
ConfigBool* m_dolby_pro_logic;
QLabel* m_dolby_quality_label; QLabel* m_dolby_quality_label;
QSlider* m_dolby_quality_slider; ConfigChoice* m_dolby_quality_combo;
QLabel* m_dolby_quality_low_label;
QLabel* m_dolby_quality_highest_label;
QLabel* m_dolby_quality_latency_label;
QLabel* m_latency_label; QLabel* m_latency_label;
QSpinBox* m_latency_spin; ConfigSlider* m_latency_slider;
#ifdef _WIN32 #ifdef _WIN32
QLabel* m_wasapi_device_label; QLabel* m_wasapi_device_label;
QComboBox* m_wasapi_device_combo; ConfigStringChoice* m_wasapi_device_combo;
#endif #endif
// Misc Settings // Misc Settings