diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt index bcb61a97f1..06680cdf44 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt @@ -31,6 +31,7 @@ enum class BooleanSetting( false ), MAIN_AUDIO_FILL_GAPS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioFillGaps", true), + MAIN_AUDIO_PRESERVE_PITCH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioPreservePitch", false), MAIN_BBA_XLINK_CHAT_OSD( Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt index 09b71966a2..7cf0d0ecad 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt @@ -556,6 +556,14 @@ class SettingsFragmentPresenter( R.string.audio_fill_gaps_description ) ) + sl.add( + SwitchSetting( + context, + BooleanSetting.MAIN_AUDIO_PRESERVE_PITCH, + R.string.audio_preserve_pitch, + R.string.audio_preserve_pitch_description + ) + ) sl.add( IntSliderSetting( context, diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 7ebc5867e3..b1630def81 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -188,6 +188,8 @@ Controls the number of audio samples buffered. Lower values reduce latency but may cause more crackling or stuttering. If unsure, set this to 80 ms. Fill Audio Gaps Repeat existing audio during lag spikes to prevent stuttering. If unsure, leave this checked. + Preserve Audio Pitch + Keeps audio at normal pitch when changing emulation speed. Without this, audio pitch changes proportionally with speed. If unsure, leave this unchecked. Audio Volume diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index eab73fb17c..0d673a9e0d 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -71,7 +71,7 @@ void Mixer::MixerFifo::Mix(s16* samples, std::size_t num_samples) static_cast(FIXED_SAMPLE_RATE_DIVIDEND) / m_input_sample_rate_divisor; const double emulation_speed = m_mixer->m_config_emulation_speed; - if (0 < emulation_speed && emulation_speed != 1.0) + if (!m_mixer->m_config_audio_preserve_pitch && 0 < emulation_speed && emulation_speed != 1.0) in_sample_rate *= emulation_speed; const double base = static_cast(1 << GRANULE_FRAC_BITS); @@ -430,6 +430,7 @@ void Mixer::StopLogDSPAudio() void Mixer::RefreshConfig() { m_config_emulation_speed = Config::Get(Config::MAIN_EMULATION_SPEED); + m_config_audio_preserve_pitch = Config::Get(Config::MAIN_AUDIO_PRESERVE_PITCH); m_config_fill_audio_gaps = Config::Get(Config::MAIN_AUDIO_FILL_GAPS); m_config_audio_buffer_ms = Config::Get(Config::MAIN_AUDIO_BUFFER_SIZE); } diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 808ce540ec..87939895e2 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -163,6 +163,7 @@ private: bool m_log_dsp_audio = false; float m_config_emulation_speed; + bool m_config_audio_preserve_pitch; bool m_config_fill_audio_gaps; int m_config_audio_buffer_ms; diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 3ef8872274..d11d48c898 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -71,6 +71,7 @@ const Info MAIN_DPL2_QUALITY{{System::Main, "Core", "D const Info MAIN_AUDIO_LATENCY{{System::Main, "Core", "AudioLatency"}, 20}; const Info MAIN_AUDIO_BUFFER_SIZE{{System::Main, "Core", "AudioBufferSize"}, 80}; const Info MAIN_AUDIO_FILL_GAPS{{System::Main, "Core", "AudioFillGaps"}, true}; +const Info MAIN_AUDIO_PRESERVE_PITCH{{System::Main, "Core", "AudioPreservePitch"}, false}; const Info MAIN_MEMCARD_A_PATH{{System::Main, "Core", "MemcardAPath"}, ""}; const Info MAIN_MEMCARD_B_PATH{{System::Main, "Core", "MemcardBPath"}, ""}; const Info& GetInfoForMemcardPath(ExpansionInterface::Slot slot) diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 27756d2e2a..00c11ea6dd 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -79,6 +79,7 @@ extern const Info MAIN_DPL2_QUALITY; extern const Info MAIN_AUDIO_LATENCY; extern const Info MAIN_AUDIO_BUFFER_SIZE; extern const Info MAIN_AUDIO_FILL_GAPS; +extern const Info MAIN_AUDIO_PRESERVE_PITCH; extern const Info MAIN_MEMCARD_A_PATH; extern const Info MAIN_MEMCARD_B_PATH; const Info& GetInfoForMemcardPath(ExpansionInterface::Slot slot); diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index f628d8e06e..435e8f24d5 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -181,6 +181,9 @@ void AudioPane::CreateWidgets() m_audio_fill_gaps = new ConfigBool(tr("Fill Audio Gaps"), Config::MAIN_AUDIO_FILL_GAPS); + m_audio_preserve_pitch = + new ConfigBool(tr("Preserve Audio Pitch"), Config::MAIN_AUDIO_PRESERVE_PITCH); + m_speed_up_mute_enable = new ConfigBool(tr("Mute When Disabling Speed Limit"), Config::MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT); @@ -192,8 +195,9 @@ void AudioPane::CreateWidgets() playback_layout->addLayout(buffer_layout, 0, 0); playback_layout->addWidget(m_audio_fill_gaps, 1, 0); - playback_layout->addWidget(m_speed_up_mute_enable, 2, 0); - playback_layout->setRowStretch(3, 1); + playback_layout->addWidget(m_audio_preserve_pitch, 2, 0); + playback_layout->addWidget(m_speed_up_mute_enable, 3, 0); + playback_layout->setRowStretch(4, 1); playback_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); auto* const main_vbox_layout = new QVBoxLayout; @@ -317,6 +321,10 @@ void AudioPane::AddDescriptions() 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_PRESERVE_AUDIO_PITCH_DESCRIPTION[] = QT_TR_NOOP( + "Keeps audio at normal pitch when changing emulation speed. Without this, audio pitch " + "changes proportionally with speed.

If unsure, leave this " + "unchecked."); 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."); @@ -357,4 +365,7 @@ void AudioPane::AddDescriptions() m_audio_fill_gaps->SetTitle(tr("Fill Audio Gaps")); m_audio_fill_gaps->SetDescription(tr(TR_FILL_AUDIO_GAPS_DESCRIPTION)); + + m_audio_preserve_pitch->SetTitle(tr("Preserve Audio Pitch")); + m_audio_preserve_pitch->SetDescription(tr(TR_PRESERVE_AUDIO_PITCH_DESCRIPTION)); } diff --git a/Source/Core/DolphinQt/Settings/AudioPane.h b/Source/Core/DolphinQt/Settings/AudioPane.h index 40c8c4edb1..4896f0e446 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.h +++ b/Source/Core/DolphinQt/Settings/AudioPane.h @@ -66,5 +66,6 @@ private: // Misc Settings ConfigBool* m_audio_fill_gaps; + ConfigBool* m_audio_preserve_pitch; ConfigBool* m_speed_up_mute_enable; };