audio: Add option to simulate headphones plugged in (#2099)

This commit is contained in:
PabloMK7 2026-05-08 15:19:53 +02:00 committed by GitHub
parent 260f08c497
commit 929a51afc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 66 additions and 26 deletions

View File

@ -109,6 +109,7 @@ foreach(KEY IN ITEMS
"output_device"
"input_type"
"input_device"
"simulate_headphones_plugged"
"delay_start_for_lle_modules"
"use_gdbstub"
"gdbstub_port"

View File

@ -94,6 +94,7 @@ object SettingKeys {
external fun audio_emulation(): String
external fun enable_audio_stretching(): String
external fun enable_realtime_audio(): String
external fun simulate_headphones_plugged(): String
external fun volume(): String
external fun output_type(): String
external fun output_device(): String

View File

@ -44,6 +44,7 @@ enum class BooleanSetting(
PRELOAD_TEXTURES(SettingKeys.preload_textures(), Settings.SECTION_UTILITY, false),
ENABLE_AUDIO_STRETCHING(SettingKeys.enable_audio_stretching(), Settings.SECTION_AUDIO, true),
ENABLE_REALTIME_AUDIO(SettingKeys.enable_realtime_audio(), Settings.SECTION_AUDIO, false),
SIMULATE_HEADPHONES_PLUGGED(SettingKeys.simulate_headphones_plugged(), Settings.SECTION_AUDIO, false),
CPU_JIT(SettingKeys.use_cpu_jit(), Settings.SECTION_CORE, true),
HW_SHADER(SettingKeys.use_hw_shader(), Settings.SECTION_RENDERER, true),
SHADER_JIT(SettingKeys.use_shader_jit(), Settings.SECTION_RENDERER, true),

View File

@ -1713,6 +1713,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
BooleanSetting.ENABLE_REALTIME_AUDIO.defaultValue
)
)
add(
SwitchSetting(
BooleanSetting.SIMULATE_HEADPHONES_PLUGGED,
R.string.simulate_headphones_plugged,
R.string.simulate_headphones_plugged_description,
BooleanSetting.SIMULATE_HEADPHONES_PLUGGED.key,
BooleanSetting.SIMULATE_HEADPHONES_PLUGGED.defaultValue
)
)
add(
SingleChoiceSetting(
IntSetting.AUDIO_INPUT_TYPE,

View File

@ -244,6 +244,7 @@ void Config::ReadValues() {
ReadSetting("Audio", Settings::values.audio_emulation);
ReadSetting("Audio", Settings::values.enable_audio_stretching);
ReadSetting("Audio", Settings::values.enable_realtime_audio);
ReadSetting("Audio", Settings::values.simulate_headphones_plugged);
ReadSetting("Audio", Settings::values.volume);
ReadSetting("Audio", Settings::values.output_type);
ReadSetting("Audio", Settings::values.output_device);

View File

@ -415,6 +415,10 @@ static const char* android_config_default_file_content = (BOOST_HANA_STRING(R"(
# 0 (default): No, 1: Yes
)") DECLARE_KEY(enable_realtime_audio) BOOST_HANA_STRING(R"(
# Simulates whether headphones are plugged in to the emulated 3DS system
# 0 (default): No, 1: Yes
)") DECLARE_KEY(simulate_headphones_plugged) BOOST_HANA_STRING(R"(
# Output volume.
# 1.0 (default): 100%, 0.0; mute
)") DECLARE_KEY(volume) BOOST_HANA_STRING(R"(

View File

@ -340,6 +340,8 @@
<string name="audio_stretch_description">Stretches audio to reduce stuttering. When enabled, increases audio latency and slightly reduces performance.</string>
<string name="realtime_audio">Enable Realtime Audio</string>
<string name="realtime_audio_description">Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the game framerate is low. May cause audio desync issues.</string>
<string name="simulate_headphones_plugged">Simulate Headphones Plugged In</string>
<string name="simulate_headphones_plugged_description">Simulates whether headphones are plugged in to the emulated 3DS system.</string>
<string name="audio_input_type">Audio Input Device</string>
<string name="sound_output_mode">Sound Output Mode</string>

View File

@ -290,6 +290,7 @@ void QtConfig::ReadAudioValues() {
ReadGlobalSetting(Settings::values.audio_emulation);
ReadGlobalSetting(Settings::values.enable_audio_stretching);
ReadGlobalSetting(Settings::values.enable_realtime_audio);
ReadGlobalSetting(Settings::values.simulate_headphones_plugged);
ReadGlobalSetting(Settings::values.volume);
if (global) {
@ -944,6 +945,7 @@ void QtConfig::SaveAudioValues() {
WriteGlobalSetting(Settings::values.audio_emulation);
WriteGlobalSetting(Settings::values.enable_audio_stretching);
WriteGlobalSetting(Settings::values.enable_realtime_audio);
WriteGlobalSetting(Settings::values.simulate_headphones_plugged);
WriteGlobalSetting(Settings::values.volume);
if (global) {

View File

@ -1,4 +1,4 @@
// Copyright 2016 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -67,6 +67,8 @@ void ConfigureAudio::SetConfiguration() {
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue());
ui->toggle_realtime_audio->setChecked(Settings::values.enable_realtime_audio.GetValue());
ui->simulate_headphones_plugged->setChecked(
Settings::values.simulate_headphones_plugged.GetValue());
SetHleFeaturesEnabled();
const s32 volume =
@ -175,6 +177,9 @@ void ConfigureAudio::ApplyConfiguration() {
&Settings::values.volume, ui->volume_combo_box, [this](s32) {
return static_cast<float>(ui->volume_slider->value()) / ui->volume_slider->maximum();
});
ConfigurationShared::ApplyPerGameSetting(&Settings::values.simulate_headphones_plugged,
ui->simulate_headphones_plugged,
simulate_headphones_plugged);
if (Settings::IsConfiguringGlobal()) {
Settings::values.output_type =
@ -252,4 +257,7 @@ void ConfigureAudio::SetupPerGameUI() {
ConfigurationShared::SetColoredTristate(ui->toggle_realtime_audio,
Settings::values.enable_realtime_audio, realtime_audio);
ConfigurationShared::SetColoredTristate(ui->simulate_headphones_plugged,
Settings::values.simulate_headphones_plugged,
simulate_headphones_plugged);
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -41,5 +41,6 @@ private:
ConfigurationShared::CheckState audio_stretching;
ConfigurationShared::CheckState realtime_audio;
ConfigurationShared::CheckState simulate_headphones_plugged;
std::unique_ptr<Ui::ConfigureAudio> ui;
};

View File

@ -85,26 +85,6 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="toggle_audio_stretching">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable audio stretching</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_realtime_audio">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable realtime audio</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="volume_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
@ -192,6 +172,36 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_audio_stretching">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable audio stretching</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_realtime_audio">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Scales audio playback speed to account for drops in emulation framerate. This means that audio will play at full speed even while the application framerate is low. May cause audio desync issues.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable realtime audio</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="simulate_headphones_plugged">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Simulates whether headphones are plugged in to the emulated 3DS system.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Simulate headphones plugged in</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -629,6 +629,7 @@ struct Values {
Setting<std::string> output_device{"Auto", Keys::output_device};
Setting<AudioCore::InputType> input_type{AudioCore::InputType::Auto, Keys::input_type};
Setting<std::string> input_device{"Auto", Keys::input_device};
SwitchableSetting<bool> simulate_headphones_plugged{false, Keys::simulate_headphones_plugged};
// Camera
std::array<std::string, Service::CAM::NumCameras> camera_name;

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -290,9 +290,8 @@ void DSP_DSP::GetHeadphoneStatus(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(ResultSuccess);
rb.Push(false); /// u8, 0 = not inserted, 1 = inserted
LOG_DEBUG(Service_DSP, "called");
rb.Push(Settings::values.simulate_headphones_plugged
.GetValue()); /// u8, 0 = not inserted, 1 = inserted
}
void DSP_DSP::ForceHeadphoneOut(Kernel::HLERequestContext& ctx) {