Ds4 Speaker Audio Rebase Fix (#3607)

* Logic update, no QT ui

* Fixing errors

* Gui boxes

* fixes

* prevent device list refreshing too fast when game not running

* Removed duplicate Socket declarations in kernel/file_system.cpp and fs.h

* Fixed clang-format and micDevice errors

* Ran clang-format and fixed rebase compiler issues

* Settings dialog fix

* Addressed squidbus' concerns

* Update config.cpp to adhere to clang-format

* Removed a space causing clang-format to complain

* Addressed squidbus' concerns and added fallbacks

Concerns:
- Changed dev_name construct to remove unnecessary cast
- Added an invalid AudioDeviceID macro to replace magic number

---------

Co-authored-by: rainmakerv2 <30595646+rainmakerv3@users.noreply.github.com>
This commit is contained in:
nickci2002
2025-09-18 01:28:12 -04:00
committed by GitHub
parent 7101caa80b
commit 0d09c32df9
12 changed files with 304 additions and 106 deletions

View File

@@ -136,10 +136,14 @@ static ConfigEntry<bool> useSpecialPad(false);
static ConfigEntry<int> specialPadClass(1);
static ConfigEntry<bool> isMotionControlsEnabled(true);
static ConfigEntry<bool> useUnifiedInputConfig(true);
static ConfigEntry<string> micDevice("Default Device");
static ConfigEntry<string> defaultControllerID("");
static ConfigEntry<bool> backgroundControllerInput(false);
// Audio
static ConfigEntry<string> micDevice("Default Device");
static ConfigEntry<string> mainOutputDevice("Default Device");
static ConfigEntry<string> padSpkOutputDevice("Default Device");
// GPU
static ConfigEntry<u32> windowWidth(1280);
static ConfigEntry<u32> windowHeight(720);
@@ -302,6 +306,14 @@ string getMicDevice() {
return micDevice.get();
}
std::string getMainOutputDevice() {
return mainOutputDevice.get();
}
std::string getPadSpkOutputDevice() {
return padSpkOutputDevice.get();
}
double getTrophyNotificationDuration() {
return trophyNotificationDuration.get();
}
@@ -581,10 +593,18 @@ void setCursorHideTimeout(int newcursorHideTimeout, bool is_game_specific) {
cursorHideTimeout.set(newcursorHideTimeout, is_game_specific);
}
void setMicDevice(string device, bool is_game_specific) {
void setMicDevice(std::string device, bool is_game_specific) {
micDevice.set(device, is_game_specific);
}
void setMainOutputDevice(std::string device, bool is_game_specific) {
mainOutputDevice.set(device, is_game_specific);
}
void setPadSpkOutputDevice(std::string device, bool is_game_specific) {
padSpkOutputDevice.set(device, is_game_specific);
}
void setTrophyNotificationDuration(double newTrophyNotificationDuration, bool is_game_specific) {
trophyNotificationDuration.set(newTrophyNotificationDuration, is_game_specific);
}
@@ -826,10 +846,17 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
specialPadClass.setFromToml(input, "specialPadClass", is_game_specific);
isMotionControlsEnabled.setFromToml(input, "isMotionControlsEnabled", is_game_specific);
useUnifiedInputConfig.setFromToml(input, "useUnifiedInputConfig", is_game_specific);
micDevice.setFromToml(input, "micDevice", is_game_specific);
backgroundControllerInput.setFromToml(input, "backgroundControllerInput", is_game_specific);
}
if (data.contains("Audio")) {
const toml::value& audio = data.at("Audio");
micDevice.setFromToml(audio, "micDevice", is_game_specific);
mainOutputDevice.setFromToml(audio, "mainOutputDevice", is_game_specific);
padSpkOutputDevice.setFromToml(audio, "padSpkOutputDevice", is_game_specific);
}
if (data.contains("GPU")) {
const toml::value& gpu = data.at("GPU");
@@ -999,10 +1026,13 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
cursorHideTimeout.setTomlValue(data, "Input", "cursorHideTimeout", is_game_specific);
isMotionControlsEnabled.setTomlValue(data, "Input", "isMotionControlsEnabled",
is_game_specific);
micDevice.setTomlValue(data, "Input", "micDevice", is_game_specific);
backgroundControllerInput.setTomlValue(data, "Input", "backgroundControllerInput",
is_game_specific);
micDevice.setTomlValue(data, "Audio", "micDevice", is_game_specific);
mainOutputDevice.setTomlValue(data, "Audio", "mainOutputDevice", is_game_specific);
padSpkOutputDevice.setTomlValue(data, "Audio", "padSpkOutputDevice", is_game_specific);
windowWidth.setTomlValue(data, "GPU", "screenWidth", is_game_specific);
windowHeight.setTomlValue(data, "GPU", "screenHeight", is_game_specific);
isNullGpu.setTomlValue(data, "GPU", "nullGpu", is_game_specific);
@@ -1036,9 +1066,8 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
m_language.setTomlValue(data, "Settings", "consoleLanguage", is_game_specific);
// All other entries
if (!is_game_specific) {
std::vector<string> install_dirs;
std::vector<std::string> install_dirs;
std::vector<bool> install_dirs_enabled;
// temporary structure for ordering
@@ -1077,23 +1106,18 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
data["GUI"]["addonInstallDir"] =
string{fmt::UTF(settings_addon_install_dir.u8string()).data};
data["Debug"]["ConfigVersion"] = config_version;
data["Keys"]["TrophyKey"] = trophyKey;
// Do not save these entries in the game-specific dialog since they are not in the GUI
data["General"]["defaultControllerID"] = defaultControllerID.base_value;
data["Input"]["useSpecialPad"] = useSpecialPad.base_value;
data["Input"]["specialPadClass"] = specialPadClass.base_value;
data["Input"]["useUnifiedInputConfig"] = useUnifiedInputConfig.base_value;
data["GPU"]["internalScreenWidth"] = internalScreenWidth.base_value;
data["GPU"]["internalScreenHeight"] = internalScreenHeight.base_value;
data["GPU"]["patchShaders"] = shouldPatchShaders.base_value;
data["Vulkan"]["validation_gpu"] = vkValidationGpu.base_value;
data["Debug"]["FPSColor"] = isFpsColor.base_value;
}
@@ -1135,9 +1159,11 @@ void setDefaultValues(bool is_game_specific) {
cursorState.set(HideCursorState::Idle, is_game_specific);
cursorHideTimeout.set(5, is_game_specific);
isMotionControlsEnabled.set(true, is_game_specific);
micDevice.set("Default Device", is_game_specific);
backgroundControllerInput.set(false, is_game_specific);
// GS - Audio
micDevice.set("Default Device", is_game_specific);
// GS - GPU
windowWidth.set(1280, is_game_specific);
windowHeight.set(720, is_game_specific);
@@ -1184,11 +1210,14 @@ void setDefaultValues(bool is_game_specific) {
useSpecialPad.base_value = false;
specialPadClass.base_value = 1;
useUnifiedInputConfig.base_value = true;
overrideControllerColor = false;
controllerCustomColorRGB[0] = 0;
controllerCustomColorRGB[1] = 0;
controllerCustomColorRGB[2] = 255;
// TODO: Change to be game specific
mainOutputDevice = "Default Device";
padSpkOutputDevice = "Default Device";
// GPU
shouldPatchShaders.base_value = false;
internalScreenWidth.base_value = 1280;

View File

@@ -90,6 +90,11 @@ double getTrophyNotificationDuration();
void setTrophyNotificationDuration(double newTrophyNotificationDuration,
bool is_game_specific = false);
int getCursorHideTimeout();
void setCursorHideTimeout(int newcursorHideTimeout);
std::string getMainOutputDevice();
void setMainOutputDevice(std::string device);
std::string getPadSpkOutputDevice();
void setPadSpkOutputDevice(std::string device);
std::string getMicDevice();
void setCursorHideTimeout(int newcursorHideTimeout, bool is_game_specific = false);
void setMicDevice(std::string device, bool is_game_specific = false);

View File

@@ -208,7 +208,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
break;
case OrbisAudioOutPort::Personal:
case OrbisAudioOutPort::Padspk:
case OrbisAudioOutPort::PadSpk:
state->output = 4;
state->channel = 1;
break;
@@ -328,7 +328,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
LOG_ERROR(Lib_AudioOut, "Audio out not initialized");
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
}
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::PadSpk) &&
(port_type != OrbisAudioOutPort::Audio3d && port_type != OrbisAudioOutPort::Aux)) {
LOG_ERROR(Lib_AudioOut, "Invalid port type");
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE;

View File

@@ -25,7 +25,7 @@ enum class OrbisAudioOutPort {
Bgm = 1,
Voice = 2,
Personal = 3,
Padspk = 4,
PadSpk = 4,
Audio3d = 126,
Aux = 127,
};

View File

@@ -1,15 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <thread>
#include <SDL3/SDL_audio.h>
#include <SDL3/SDL_hints.h>
#include <common/config.h>
#include "common/config.h"
#include "common/logging/log.h"
#include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_backend.h"
#define SDL_INVALID_AUDIODEVICEID 0 // Defined in SDL_audio.h but not made a macro
namespace Libraries::AudioOut {
class SDLPortBackend : public PortBackend {
@@ -21,8 +23,42 @@ public:
.channels = port.format_info.num_channels,
.freq = static_cast<int>(port.sample_rate),
};
stream =
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
// Determine port type
std::string port_name = port.type == OrbisAudioOutPort::PadSpk
? Config::getPadSpkOutputDevice()
: Config::getMainOutputDevice();
SDL_AudioDeviceID dev_id = SDL_INVALID_AUDIODEVICEID;
if (port_name == "None") {
stream = nullptr;
return;
} else if (port_name == "Default Device") {
dev_id = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
} else {
try {
SDL_AudioDeviceID* dev_array = SDL_GetAudioPlaybackDevices(nullptr);
for (; dev_array != 0;) {
std::string dev_name(SDL_GetAudioDeviceName(*dev_array));
if (dev_name == port_name) {
dev_id = *dev_array;
break;
} else {
dev_array++;
}
}
if (dev_id == SDL_INVALID_AUDIODEVICEID) {
LOG_WARNING(Lib_AudioOut, "Audio device not found: {}", port_name);
dev_id = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
}
} catch (const std::exception& e) {
LOG_ERROR(Lib_AudioOut, "Invalid audio output device: {}", port_name);
stream = nullptr;
return;
}
}
// Open the audio stream
stream = SDL_OpenAudioDeviceStream(dev_id, &fmt, nullptr, nullptr);
if (stream == nullptr) {
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
return;

View File

@@ -408,8 +408,8 @@ public:
}
if (selected == &gameConfigConfigure || selected == &gameConfigCreate) {
auto settingsWindow = new SettingsDialog(m_gui_settings, m_compat_info, widget, true,
serialStr.toStdString());
auto settingsWindow = new SettingsDialog(m_gui_settings, m_compat_info, widget, false,
true, serialStr.toStdString());
settingsWindow->exec();
}

View File

@@ -407,7 +407,8 @@ void MainWindow::CreateConnects() {
&MainWindow::StartGame);
connect(ui->configureAct, &QAction::triggered, this, [this]() {
auto settingsDialog = new SettingsDialog(m_gui_settings, m_compat_info, this);
auto settingsDialog =
new SettingsDialog(m_gui_settings, m_compat_info, this, isGameRunning);
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
&MainWindow::OnLanguageChanged);
@@ -441,7 +442,8 @@ void MainWindow::CreateConnects() {
});
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() {
auto settingsDialog = new SettingsDialog(m_gui_settings, m_compat_info, this);
auto settingsDialog =
new SettingsDialog(m_gui_settings, m_compat_info, this, isGameRunning);
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
&MainWindow::OnLanguageChanged);

View File

@@ -41,6 +41,14 @@ bool Wrapper::ProcessEvent(SDL_Event* event) {
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
emit SDLEvent(SDL_EVENT_GAMEPAD_AXIS_MOTION, event->gaxis.axis, event->gaxis.value);
return true;
case SDL_EVENT_AUDIO_DEVICE_ADDED:
if (event->adevice.recording == 0)
emit audioDeviceChanged(true);
return true;
case SDL_EVENT_AUDIO_DEVICE_REMOVED:
if (event->adevice.recording == 0)
emit audioDeviceChanged(false);
return true;
// block all other SDL events while wrapper is active
default:
return true;

View File

@@ -20,6 +20,7 @@ public:
signals:
void SDLEvent(int Type, int Input, int Value);
void audioDeviceChanged(bool isAdd);
};
} // namespace SdlEventWrapper

View File

@@ -11,6 +11,7 @@
#include <fmt/format.h>
#include "common/config.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "core/libraries/audio/audioout.h"
#include "qt_gui/compatibility_info.h"
@@ -27,6 +28,7 @@
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "log_presets_dialog.h"
#include "sdl_event_wrapper.h"
#include "settings_dialog.h"
#include "ui_settings_dialog.h"
#include "video_core/renderer_vulkan/vk_instance.h"
@@ -82,18 +84,20 @@ static std::vector<QString> m_physical_devices;
SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QWidget* parent, bool is_game_specific, std::string gsc_serial)
QWidget* parent, bool is_running, bool is_specific,
std::string gsc_serial)
: QDialog(parent), ui(new Ui::SettingsDialog), m_gui_settings(std::move(gui_settings)),
game_specific(is_game_specific), gs_serial(gsc_serial) {
is_game_running(is_running), is_game_specific(is_specific), gs_serial(gsc_serial) {
ui->setupUi(this);
ui->tabWidgetSettings->setUsesScrollButtons(false);
initialHeight = this->height();
// Add a small clear "x" button inside the Log Filter input
ui->logFilterLineEdit->setClearButtonEnabled(true);
if (game_specific) {
if (is_game_specific) {
// Paths tab
ui->tabWidgetSettings->setTabVisible(5, false);
ui->chooseHomeTabComboBox->removeItem(5);
@@ -109,7 +113,7 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
}
std::filesystem::path config_file =
game_specific
is_game_specific
? Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (gs_serial + ".toml")
: Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml";
@@ -184,6 +188,7 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
}
InitializeEmulatorLanguages();
onAudioDeviceChange(true);
LoadValuesFromConfig();
defaultTextEdit = tr("Point your mouse at an option to display its description.");
@@ -194,17 +199,17 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
connect(ui->buttonBox, &QDialogButtonBox::clicked, this,
[this, config_file](QAbstractButton* button) {
if (button == ui->buttonBox->button(QDialogButtonBox::Save)) {
is_saving = true;
UpdateSettings(game_specific);
Config::save(config_file, game_specific);
is_game_saving = true;
UpdateSettings(is_game_specific);
Config::save(config_file, is_game_specific);
QWidget::close();
} else if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) {
UpdateSettings(game_specific);
Config::save(config_file, game_specific);
UpdateSettings(is_game_specific);
Config::save(config_file, is_game_specific);
} else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) {
setDefaultValues();
Config::setDefaultValues(game_specific);
Config::save(config_file, game_specific);
Config::setDefaultValues(is_game_specific);
Config::save(config_file, is_game_specific);
LoadValuesFromConfig();
} else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) {
ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup);
@@ -232,7 +237,7 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
{
connect(ui->horizontalVolumeSlider, &QSlider::valueChanged, this, [this](int value) {
VolumeSliderChange(value);
Config::setVolumeSlider(value, game_specific);
Config::setVolumeSlider(value, is_game_specific);
Libraries::AudioOut::AdjustVol();
});
@@ -526,30 +531,52 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
ui->networkConnectedCheckBox->installEventFilter(this);
ui->psnSignInCheckBox->installEventFilter(this);
}
SdlEventWrapper::Wrapper::wrapperActive = true;
if (!is_game_running) {
SDL_InitSubSystem(SDL_INIT_EVENTS);
Polling = QtConcurrent::run(&SettingsDialog::pollSDLevents, this);
} else {
SdlEventWrapper::Wrapper* DeviceEventWrapper = SdlEventWrapper::Wrapper::GetInstance();
QObject::connect(DeviceEventWrapper, &SdlEventWrapper::Wrapper::audioDeviceChanged, this,
&SettingsDialog::onAudioDeviceChange);
}
}
void SettingsDialog::closeEvent(QCloseEvent* event) {
if (!is_saving) {
if (!is_game_saving) {
ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup);
emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup);
ui->BGMVolumeSlider->setValue(bgm_volume_backup);
BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup);
SyncRealTimeWidgetstoConfig();
}
SdlEventWrapper::Wrapper::wrapperActive = false;
if (!is_game_running) {
SDL_Event quitLoop{};
quitLoop.type = SDL_EVENT_QUIT;
SDL_PushEvent(&quitLoop);
Polling.waitForFinished();
SDL_QuitSubSystem(SDL_INIT_EVENTS);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
SDL_Quit();
}
QDialog::closeEvent(event);
}
void SettingsDialog::LoadValuesFromConfig() {
std::filesystem::path config_file;
config_file =
game_specific
is_game_specific
? Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (gs_serial + ".toml")
: Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml";
std::error_code error;
bool is_newly_created = false;
if (!std::filesystem::exists(config_file, error)) {
Config::save(config_file, game_specific);
Config::save(config_file, is_game_specific);
is_newly_created = true;
}
@@ -567,7 +594,7 @@ void SettingsDialog::LoadValuesFromConfig() {
15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 30, 28};
// Entries with no game-specific settings
if (!game_specific) {
if (!is_game_specific) {
const auto save_data_path = Config::GetSaveDataPath();
QString save_data_path_string;
Common::FS::PathToQString(save_data_path_string, save_data_path);
@@ -728,6 +755,11 @@ void SettingsDialog::LoadValuesFromConfig() {
toml::find_or<bool>(data, "Debug", "CollectShader", false));
ui->enableLoggingCheckBox->setChecked(toml::find_or<bool>(data, "Debug", "logEnabled", true));
ui->GenAudioComboBox->setCurrentText(QString::fromStdString(
toml::find_or<std::string>(data, "General", "mainOutputDevice", "")));
ui->DsAudioComboBox->setCurrentText(QString::fromStdString(
toml::find_or<std::string>(data, "General", "padSpkOutputDevice", "")));
std::string chooseHomeTab =
toml::find_or<std::string>(data, "General", "chooseHomeTab", "General");
QString translatedText = chooseHomeTabMap.key(QString::fromStdString(chooseHomeTab));
@@ -979,76 +1011,75 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) {
return QDialog::eventFilter(obj, event);
}
void SettingsDialog::UpdateSettings(bool game_specific) {
void SettingsDialog::UpdateSettings(bool is_specific) {
// Entries with game-specific settings, needs the game-specific arg
Config::setReadbacks(ui->readbacksCheckBox->isChecked(), game_specific);
Config::setReadbackLinearImages(ui->readbackLinearImagesCheckBox->isChecked(), game_specific);
Config::setDirectMemoryAccess(ui->dmaCheckBox->isChecked(), game_specific);
Config::setDevKitConsole(ui->devkitCheckBox->isChecked(), game_specific);
Config::setNeoMode(ui->neoCheckBox->isChecked(), game_specific);
Config::setConnectedToNetwork(ui->networkConnectedCheckBox->isChecked(), game_specific);
Config::setPSNSignedIn(ui->psnSignInCheckBox->isChecked(), game_specific);
Config::setReadbacks(ui->readbacksCheckBox->isChecked(), is_specific);
Config::setReadbackLinearImages(ui->readbackLinearImagesCheckBox->isChecked(), is_specific);
Config::setDirectMemoryAccess(ui->dmaCheckBox->isChecked(), is_specific);
Config::setDevKitConsole(ui->devkitCheckBox->isChecked(), is_specific);
Config::setNeoMode(ui->neoCheckBox->isChecked(), is_specific);
Config::setConnectedToNetwork(ui->networkConnectedCheckBox->isChecked(), is_specific);
Config::setPSNSignedIn(ui->psnSignInCheckBox->isChecked(), is_specific);
Config::setIsFullscreen(
screenModeMap.value(ui->displayModeComboBox->currentText()) != "Windowed", game_specific);
screenModeMap.value(ui->displayModeComboBox->currentText()) != "Windowed", is_specific);
Config::setFullscreenMode(
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString(), game_specific);
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString(), is_specific);
Config::setPresentMode(
presentModeMap.value(ui->presentModeComboBox->currentText()).toStdString(), game_specific);
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked(), game_specific);
presentModeMap.value(ui->presentModeComboBox->currentText()).toStdString(), is_specific);
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked(), is_specific);
Config::setBackgroundControllerInput(ui->backgroundControllerCheckBox->isChecked(),
game_specific);
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked(), game_specific);
Config::setTrophyNotificationDuration(ui->popUpDurationSpinBox->value(), game_specific);
is_specific);
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked(), is_specific);
Config::setTrophyNotificationDuration(ui->popUpDurationSpinBox->value(), is_specific);
if (ui->radioButton_Top->isChecked()) {
Config::setSideTrophy("top", game_specific);
Config::setSideTrophy("top", is_specific);
} else if (ui->radioButton_Left->isChecked()) {
Config::setSideTrophy("left", game_specific);
Config::setSideTrophy("left", is_specific);
} else if (ui->radioButton_Right->isChecked()) {
Config::setSideTrophy("right", game_specific);
Config::setSideTrophy("right", is_specific);
} else if (ui->radioButton_Bottom->isChecked()) {
Config::setSideTrophy("bottom", game_specific);
Config::setSideTrophy("bottom", is_specific);
}
Config::setLoggingEnabled(ui->enableLoggingCheckBox->isChecked(), game_specific);
Config::setAllowHDR(ui->enableHDRCheckBox->isChecked(), game_specific);
Config::setLoggingEnabled(ui->enableLoggingCheckBox->isChecked(), is_specific);
Config::setAllowHDR(ui->enableHDRCheckBox->isChecked(), is_specific);
Config::setLogType(logTypeMap.value(ui->logTypeComboBox->currentText()).toStdString(),
game_specific);
Config::setMicDevice(ui->micComboBox->currentData().toString().toStdString(), game_specific);
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString(), game_specific);
Config::setUserName(ui->userNameLineEdit->text().toStdString(), game_specific);
Config::setCursorState(ui->hideCursorComboBox->currentIndex(), game_specific);
Config::setCursorHideTimeout(ui->hideCursorComboBox->currentIndex(), game_specific);
Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1, game_specific);
Config::setVolumeSlider(ui->horizontalVolumeSlider->value(), game_specific);
Config::setLanguage(languageIndexes[ui->consoleLanguageComboBox->currentIndex()],
game_specific);
Config::setWindowWidth(ui->widthSpinBox->value(), game_specific);
Config::setWindowHeight(ui->heightSpinBox->value(), game_specific);
Config::setVblankFreq(ui->vblankSpinBox->value(), game_specific);
Config::setDumpShaders(ui->dumpShadersCheckBox->isChecked(), game_specific);
Config::setNullGpu(ui->nullGpuCheckBox->isChecked(), game_specific);
Config::setFsrEnabled(ui->FSRCheckBox->isChecked(), game_specific);
Config::setRcasEnabled(ui->RCASCheckBox->isChecked(), game_specific);
Config::setRcasAttenuation(ui->RCASSlider->value(), game_specific);
Config::setShowSplash(ui->showSplashCheckBox->isChecked(), game_specific);
Config::setDebugDump(ui->debugDump->isChecked(), game_specific);
Config::setSeparateLogFilesEnabled(ui->separateLogFilesCheckbox->isChecked(), game_specific);
Config::setVkValidation(ui->vkValidationCheckBox->isChecked(), game_specific);
Config::setVkSyncValidation(ui->vkSyncValidationCheckBox->isChecked(), game_specific);
Config::setRdocEnabled(ui->rdocCheckBox->isChecked(), game_specific);
Config::setVkHostMarkersEnabled(ui->hostMarkersCheckBox->isChecked(), game_specific);
Config::setVkGuestMarkersEnabled(ui->guestMarkersCheckBox->isChecked(), game_specific);
Config::setVkCrashDiagnosticEnabled(ui->crashDiagnosticsCheckBox->isChecked(), game_specific);
Config::setCollectShaderForDebug(ui->collectShaderCheckBox->isChecked(), game_specific);
Config::setCopyGPUCmdBuffers(ui->copyGPUBuffersCheckBox->isChecked(), game_specific);
is_specific);
Config::setMicDevice(ui->micComboBox->currentData().toString().toStdString(), is_specific);
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString(), is_specific);
Config::setUserName(ui->userNameLineEdit->text().toStdString(), is_specific);
Config::setCursorState(ui->hideCursorComboBox->currentIndex(), is_specific);
Config::setCursorHideTimeout(ui->hideCursorComboBox->currentIndex(), is_specific);
Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1, is_specific);
Config::setVolumeSlider(ui->horizontalVolumeSlider->value(), is_specific);
Config::setLanguage(languageIndexes[ui->consoleLanguageComboBox->currentIndex()], is_specific);
Config::setWindowWidth(ui->widthSpinBox->value(), is_specific);
Config::setWindowHeight(ui->heightSpinBox->value(), is_specific);
Config::setVblankFreq(ui->vblankSpinBox->value(), is_specific);
Config::setDumpShaders(ui->dumpShadersCheckBox->isChecked(), is_specific);
Config::setNullGpu(ui->nullGpuCheckBox->isChecked(), is_specific);
Config::setFsrEnabled(ui->FSRCheckBox->isChecked(), is_specific);
Config::setRcasEnabled(ui->RCASCheckBox->isChecked(), is_specific);
Config::setRcasAttenuation(ui->RCASSlider->value(), is_specific);
Config::setShowSplash(ui->showSplashCheckBox->isChecked(), is_specific);
Config::setDebugDump(ui->debugDump->isChecked(), is_specific);
Config::setSeparateLogFilesEnabled(ui->separateLogFilesCheckbox->isChecked(), is_specific);
Config::setVkValidation(ui->vkValidationCheckBox->isChecked(), is_specific);
Config::setVkSyncValidation(ui->vkSyncValidationCheckBox->isChecked(), is_specific);
Config::setRdocEnabled(ui->rdocCheckBox->isChecked(), is_specific);
Config::setVkHostMarkersEnabled(ui->hostMarkersCheckBox->isChecked(), is_specific);
Config::setVkGuestMarkersEnabled(ui->guestMarkersCheckBox->isChecked(), is_specific);
Config::setVkCrashDiagnosticEnabled(ui->crashDiagnosticsCheckBox->isChecked(), is_specific);
Config::setCollectShaderForDebug(ui->collectShaderCheckBox->isChecked(), is_specific);
Config::setCopyGPUCmdBuffers(ui->copyGPUBuffersCheckBox->isChecked(), is_specific);
Config::setChooseHomeTab(
chooseHomeTabMap.value(ui->chooseHomeTabComboBox->currentText()).toStdString(),
game_specific);
is_specific);
// Entries with no game-specific settings
if (!game_specific) {
if (!is_specific) {
std::vector<Config::GameInstallDir> dirs_with_states;
for (int i = 0; i < ui->gameFoldersListWidget->count(); i++) {
QListWidgetItem* item = ui->gameFoldersListWidget->item(i);
@@ -1096,7 +1127,7 @@ void SettingsDialog::SyncRealTimeWidgetstoConfig() {
std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
const toml::value data = toml::parse(userdir / "config.toml");
if (!game_specific) {
if (!is_game_specific) {
ui->gameFoldersListWidget->clear();
if (data.contains("GUI")) {
const toml::value& gui = data.at("GUI");
@@ -1137,7 +1168,7 @@ void SettingsDialog::SyncRealTimeWidgetstoConfig() {
}
toml::value gs_data;
game_specific
is_game_specific
? gs_data = toml::parse(Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) /
(gs_serial + ".toml"))
: gs_data = data;
@@ -1147,8 +1178,8 @@ void SettingsDialog::SyncRealTimeWidgetstoConfig() {
// Since config::set can be called for volume slider (connected to the widget) outside the save
// function, need to null it out if GS GUI is closed without saving
game_specific ? Config::resetGameSpecificValue("volumeSlider")
: Config::setVolumeSlider(sliderValue);
is_game_specific ? Config::resetGameSpecificValue("volumeSlider")
: Config::setVolumeSlider(sliderValue);
if (presenter) {
presenter->GetFsrSettingsRef().enable =
@@ -1161,7 +1192,7 @@ void SettingsDialog::SyncRealTimeWidgetstoConfig() {
}
void SettingsDialog::setDefaultValues() {
if (!game_specific) {
if (!is_game_specific) {
m_gui_settings->SetValue(gui::gl_showBackgroundImage, true);
m_gui_settings->SetValue(gui::gl_backgroundImageOpacity, 50);
m_gui_settings->SetValue(gui::gl_playBackgroundMusic, false);
@@ -1176,3 +1207,59 @@ void SettingsDialog::setDefaultValues() {
m_gui_settings->SetValue(gui::gen_guiLanguage, "en_US");
}
}
void SettingsDialog::pollSDLevents() {
SDL_Event event;
while (SdlEventWrapper::Wrapper::wrapperActive) {
if (!SDL_WaitEvent(&event)) {
return;
}
if (event.type == SDL_EVENT_QUIT) {
return;
}
if (event.type == SDL_EVENT_AUDIO_DEVICE_ADDED) {
onAudioDeviceChange(true);
}
if (event.type == SDL_EVENT_AUDIO_DEVICE_REMOVED) {
onAudioDeviceChange(false);
}
}
}
void SettingsDialog::onAudioDeviceChange(bool isAdd) {
ui->GenAudioComboBox->clear();
ui->DsAudioComboBox->clear();
// prevent device list from refreshing too fast when game not running
if (!is_game_running && isAdd == false)
QThread::msleep(100);
int deviceCount;
QStringList deviceList;
SDL_AudioDeviceID* devices = SDL_GetAudioPlaybackDevices(&deviceCount);
if (!devices) {
LOG_ERROR(Lib_AudioOut, "Unable to retrieve audio device list {}", SDL_GetError());
return;
}
for (int i = 0; i < deviceCount; ++i) {
const char* name = SDL_GetAudioDeviceName(devices[i]);
std::string name_string = std::string(name);
deviceList.append(QString::fromStdString(name_string));
}
ui->GenAudioComboBox->addItem(tr("Default Device"), "Default Device");
ui->GenAudioComboBox->addItems(deviceList);
ui->GenAudioComboBox->setCurrentText(QString::fromStdString(Config::getMainOutputDevice()));
ui->DsAudioComboBox->addItem(tr("Default Device"), "Default Device");
ui->DsAudioComboBox->addItems(deviceList);
ui->DsAudioComboBox->setCurrentText(QString::fromStdString(Config::getPadSpkOutputDevice()));
SDL_free(devices);
}

View File

@@ -23,8 +23,8 @@ class SettingsDialog : public QDialog {
public:
explicit SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QWidget* parent = nullptr, bool is_game_specific = false,
std::string gsc_serial = "");
QWidget* parent = nullptr, bool is_game_running = false,
bool is_game_specific = false, std::string gsc_serial = "");
~SettingsDialog();
bool eventFilter(QObject* obj, QEvent* event) override;
@@ -47,6 +47,8 @@ private:
void closeEvent(QCloseEvent* event) override;
void setDefaultValues();
void VolumeSliderChange(int value);
void onAudioDeviceChange(bool isAdd);
void pollSDLevents();
std::unique_ptr<Ui::SettingsDialog> ui;
@@ -55,9 +57,13 @@ private:
QString defaultTextEdit;
int initialHeight;
bool is_saving = false;
bool game_specific;
std::string gs_serial;
bool is_game_running = false;
bool is_game_specific = false;
bool is_game_saving = false;
std::shared_ptr<gui_settings> m_gui_settings;
QFuture<void> Polling;
};

View File

@@ -77,7 +77,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>501</height>
<height>536</height>
</rect>
</property>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
@@ -381,6 +381,30 @@
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="GenAudioGroupBox">
<property name="title">
<string>Audio Device (general)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QComboBox" name="GenAudioComboBox"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="DsSpeakerGroupBox">
<property name="title">
<string>Audio Device (DS4 speaker)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QComboBox" name="DsAudioComboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
@@ -1010,7 +1034,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>501</height>
<height>536</height>
</rect>
</property>
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
@@ -1417,7 +1441,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>501</height>
<height>536</height>
</rect>
</property>
<layout class="QVBoxLayout" name="userTabVLayout" stretch="0,0,1">
@@ -1632,7 +1656,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>501</height>
<height>536</height>
</rect>
</property>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0,0">
@@ -1918,7 +1942,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>501</height>
<height>536</height>
</rect>
</property>
<layout class="QVBoxLayout" name="pathsTabLayout">
@@ -2087,7 +2111,7 @@
<x>0</x>
<y>0</y>
<width>946</width>
<height>299</height>
<height>536</height>
</rect>
</property>
<property name="sizePolicy">