fearlessTobi 8 лет назад
Родитель
Сommit
a6efff8b02

+ 3 - 0
.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

+ 3 - 0
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

+ 1 - 0
externals/soundtouch

@@ -0,0 +1 @@
+Subproject commit 060181eaf273180d3a7e87349895bd0cb6ccbf4a

+ 1 - 0
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)

+ 7 - 0
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;
     }

+ 4 - 0
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;
 };
 

+ 2 - 0
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>;

+ 1 - 0
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, {});

+ 1 - 0
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;
 

+ 3 - 0
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);

+ 3 - 0
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();

+ 3 - 0
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();

+ 10 - 0
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>

+ 2 - 0
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);
 

+ 6 - 0
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 =