From 8551c187775fdca9e27dc46aac4e671085fafc44 Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Thu, 16 May 2024 15:53:13 +0100 Subject: [PATCH] Improve playback consistency for realtime audio during inconsistent framerates Implements and uses `GetStableFrameTimeScale` instead of `GetLastFrameTimeScale` for realtime audio playback --- src/audio_core/hle/hle.cpp | 2 +- src/core/core.cpp | 4 ++-- src/core/core.h | 2 +- src/core/perf_stats.cpp | 11 +++++++++++ src/core/perf_stats.h | 6 ++++++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index a5e2cf63a..3687f9647 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -419,7 +419,7 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) { // Reschedule recurrent event const double time_scale = Settings::values.enable_realtime_audio - ? std::clamp(Core::System::GetInstance().GetLastFrameTimeScale(), 1.0, 3.0) + ? std::clamp(Core::System::GetInstance().GetStableFrameTimeScale(), 1.0, 3.0) : 1.0; s64 adjusted_ticks = static_cast(audio_frame_ticks / time_scale - cycles_late); core_timing.ScheduleEvent(adjusted_ticks, tick_event); diff --git a/src/core/core.cpp b/src/core/core.cpp index 3a3f2f551..7f0d6c4d1 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -392,8 +392,8 @@ PerfStats::Results System::GetLastPerfStats() { return perf_stats ? perf_stats->GetLastStats() : PerfStats::Results{}; } -double System::GetLastFrameTimeScale() { - return perf_stats->GetLastFrameTimeScale(); +double System::GetStableFrameTimeScale() { + return perf_stats->GetStableFrameTimeScale(); } void System::Reschedule() { diff --git a/src/core/core.h b/src/core/core.h index 7b2f00784..a5587edf3 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -193,7 +193,7 @@ public: [[nodiscard]] PerfStats::Results GetLastPerfStats(); - double GetLastFrameTimeScale(); + double GetStableFrameTimeScale(); /** * Gets a reference to the emulated CPU. diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index c05cf80e5..9f694f75f 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -129,6 +129,17 @@ double PerfStats::GetLastFrameTimeScale() const { return duration_cast(previous_frame_length).count() / FRAME_LENGTH; } +double PerfStats::GetStableFrameTimeScale() const { + std::scoped_lock lock{object_mutex}; + + constexpr double FRAME_LENGTH_MILLIS = (1.0 / SCREEN_REFRESH_RATE) * 1000; + const short num_frames = std::min(50ul, current_index + 1); + const double sum = std::accumulate(perf_history.begin() + current_index - num_frames, + perf_history.begin() + current_index, 0.0); + const double stable_frame_length = sum / num_frames; + return stable_frame_length / FRAME_LENGTH_MILLIS; +} + void FrameLimiter::WaitOnce() { if (frame_advancing_enabled) { // Frame advancing is enabled: wait on event instead of doing framelimiting diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h index 5cd69afb2..a6ecc7004 100644 --- a/src/core/perf_stats.h +++ b/src/core/perf_stats.h @@ -82,6 +82,12 @@ public: */ double GetLastFrameTimeScale() const; + /** + * Has the same functionality as GetLastFrameTimeScale, but uses the mean frame time over the + * last 50 frames rather than only the frame time of the previous frame. + */ + double GetStableFrameTimeScale() const; + void AddArticBaseTraffic(u32 bytes) { artic_transmitted += bytes; }