summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--externals/CMakeLists.txt3
m---------externals/soundtouch0
-rw-r--r--src/audio_core/CMakeLists.txt1
-rw-r--r--src/audio_core/cubeb_sink.cpp7
-rw-r--r--src/audio_core/null_sink.h4
-rw-r--r--src/audio_core/sink_stream.h2
-rw-r--r--src/audio_core/stream.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp3
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/configure_audio.cpp3
-rw-r--r--src/yuzu/configuration/configure_audio.ui10
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h6
15 files changed, 49 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
index 4f4e8690b..e73ca99e3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -31,3 +31,6 @@
[submodule "opus"]
path = externals/opus
url = https://github.com/ogniK5377/opus.git
+[submodule "soundtouch"]
+ path = externals/soundtouch
+ url = https://github.com/citra-emu/ext-soundtouch.git
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index b6eb36f20..600c45f0f 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -47,6 +47,9 @@ target_include_directories(microprofile INTERFACE ./microprofile)
add_library(unicorn-headers INTERFACE)
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
+# SoundTouch
+add_subdirectory(soundtouch)
+
# Xbyak
if (ARCHITECTURE_x86_64)
# Defined before "dynarmic" above
diff --git a/externals/soundtouch b/externals/soundtouch
new file mode 160000
+Subproject 060181eaf273180d3a7e87349895bd0cb6ccbf4
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 82e4850f7..de5c291ce 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -24,6 +24,7 @@ add_library(audio_core STATIC
create_target_directory_groups(audio_core)
target_link_libraries(audio_core PUBLIC common core)
+target_link_libraries(audio_core PRIVATE SoundTouch)
if(ENABLE_CUBEB)
target_link_libraries(audio_core PRIVATE cubeb)
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 5a1177d0c..0f77fd162 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -85,6 +85,13 @@ public:
}
}
+ size_t SamplesInQueue(u32 num_channels) const {
+ if (!ctx)
+ return 0;
+
+ return queue.size() / num_channels;
+ }
+
u32 GetNumChannels() const {
return num_channels;
}
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index f235d93e5..fbb1bc225 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -21,6 +21,10 @@ public:
private:
struct NullSinkStreamImpl final : SinkStream {
void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
+
+ size_t SamplesInQueue(u32 /*num_channels*/) const override {
+ return 0;
+ }
} null_sink_stream;
};
diff --git a/src/audio_core/sink_stream.h b/src/audio_core/sink_stream.h
index 41b6736d8..743a743a3 100644
--- a/src/audio_core/sink_stream.h
+++ b/src/audio_core/sink_stream.h
@@ -25,6 +25,8 @@ public:
* @param samples Samples in interleaved stereo PCM16 format.
*/
virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
+
+ virtual std::size_t SamplesInQueue(u32 num_channels) const = 0;
};
using SinkStreamPtr = std::unique_ptr<SinkStream>;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index dbae75d8c..49c6efc85 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -90,6 +90,7 @@ void Stream::PlayNextBuffer() {
queued_buffers.pop();
VolumeAdjustSamples(active_buffer->Samples());
+
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
diff --git a/src/core/settings.h b/src/core/settings.h
index 5bf1863e6..c25f8ba70 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -146,6 +146,7 @@ struct Values {
// Audio
std::string sink_id;
+ bool enable_audio_stretching;
std::string audio_device_id;
float volume;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 3730e85b8..b0df154ca 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -120,6 +120,9 @@ TelemetrySession::TelemetrySession() {
Telemetry::AppendOSInfo(field_collection);
// Log user configuration information
+ AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);
+ AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
+ Settings::values.enable_audio_stretching);
AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
Settings::values.use_multi_core);
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index c43e79e78..d229225b4 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -95,6 +95,8 @@ void Config::ReadValues() {
qt_config->beginGroup("Audio");
Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
+ Settings::values.enable_audio_stretching =
+ qt_config->value("enable_audio_stretching", true).toBool();
Settings::values.audio_device_id =
qt_config->value("output_device", "auto").toString().toStdString();
Settings::values.volume = qt_config->value("volume", 1).toFloat();
@@ -230,6 +232,7 @@ void Config::SaveValues() {
qt_config->beginGroup("Audio");
qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
+ qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
qt_config->setValue("volume", Settings::values.volume);
qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index fbb813f6c..6ea59f2a3 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -46,6 +46,8 @@ void ConfigureAudio::setConfiguration() {
}
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
+ ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
+
// The device list cannot be pre-populated (nor listed) until the output sink is known.
updateAudioDevices(new_sink_index);
@@ -67,6 +69,7 @@ void ConfigureAudio::applyConfiguration() {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
+ Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
Settings::values.audio_device_id =
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
.toStdString();
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index ef67890dc..a29a0e265 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -31,6 +31,16 @@
</item>
</layout>
</item>
+ <item>
+ <widget class="QCheckBox" name="toggle_audio_stretching">
+ <property name="toolTip">
+ <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
+ </property>
+ <property name="text">
+ <string>Enable audio stretching</string>
+ </property>
+ </widget>
+ </item>
<item>
<layout class="QHBoxLayout">
<item>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index f00b5a66b..991abda2e 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -108,6 +108,8 @@ void Config::ReadValues() {
// Audio
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
+ Settings::values.enable_audio_stretching =
+ sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 6ed9e7962..002a4ec15 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -150,6 +150,12 @@ swap_screen =
# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
output_engine =
+# Whether or not to enable the audio-stretching post-processing effect.
+# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
+# at the cost of increasing audio latency.
+# 0: No, 1 (default): Yes
+enable_audio_stretching =
+
# Which audio device to use.
# auto (default): Auto-select
output_device =