From a3831e37ae00ae030c4891f3d42dd154d154a591 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Fri, 5 Dec 2025 16:37:08 +1000 Subject: [PATCH] fix(audio): Fix buffer underrun handling to prevent buzzing - Repeat last valid frame during underruns instead of fading to silence - Maintain audio continuity when buffers are temporarily unavailable - Prevent harsh audio artifacts during loading screens (0 FPS scenarios) Signed-off-by: Zephyron --- src/audio_core/sink/sink_stream.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 7a039d96f..0f490a507 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -229,10 +231,19 @@ void SinkStream::ProcessAudioOutAndRender(std::span output_buffer, std::siz // If the playing buffer has been consumed or has no frames, we need a new one if (playing_buffer.consumed || playing_buffer.frames == 0) { if (!queue.try_dequeue(playing_buffer)) { - // If no buffer was available we've underrun, fill the remaining buffer with - // the last written frame and continue. - for (size_t i = frames_written; i < num_frames; i++) { - std::memcpy(&output_buffer[i * frame_size], &last_frame[0], frame_size_bytes); + // If no buffer was available we've underrun, repeat the last frame to maintain + // audio continuity. Use the last valid frame we played to avoid harsh transitions. + if (frames_written > 0) { + // We have a valid last_frame, repeat it smoothly + for (size_t i = frames_written; i < num_frames; i++) { + std::memcpy(&output_buffer[i * frame_size], &last_frame[0], frame_size_bytes); + } + } else { + // No frames written yet, fill with silence + static constexpr std::array silence{}; + for (size_t i = frames_written; i < num_frames; i++) { + std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes); + } } frames_written = num_frames; continue;