From 37ba1992dd054fa57396b9e97ef4dd739ab7ee9e Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 23 Mar 2026 09:32:16 +0100 Subject: [PATCH] Qt: Smoothly start/stop audio with fade in and fade out --- rpcs3/rpcs3qt/qt_video_source.cpp | 57 ++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/rpcs3/rpcs3qt/qt_video_source.cpp b/rpcs3/rpcs3qt/qt_video_source.cpp index 191822c7a8..760369ad74 100644 --- a/rpcs3/rpcs3qt/qt_video_source.cpp +++ b/rpcs3/rpcs3qt/qt_video_source.cpp @@ -8,6 +8,7 @@ #include "Loader/ISO.h" #include +#include #include struct qt_audio_instance @@ -24,10 +25,17 @@ struct qt_audio_instance static std::array s_audio_instance = {}; +static constexpr int emu_timeout_start_ms = 0; +static constexpr int gui_timeout_start_ms = 1000; +static constexpr int gui_fade_in_ms = 2000; +static constexpr int gui_fade_out_ms = 1000; + +static_assert(gui_fade_out_ms <= gui_timeout_start_ms); + qt_video_source::qt_video_source(bool is_emulation) : video_source() , m_audio_instance_index(is_emulation ? qt_audio_instance::emu_index : qt_audio_instance::gui_index) - , m_video_timer_timeout_ms(is_emulation ? 0 : 1000) + , m_video_timer_timeout_ms(is_emulation ? emu_timeout_start_ms : gui_timeout_start_ms) { } @@ -301,7 +309,13 @@ void qt_video_source::start_audio() volume = audio::get_volume(); } - audio.output->setVolume(std::clamp(volume, 0.0f, 1.0f)); + QPropertyAnimation* fade_in = new QPropertyAnimation(audio.output.get(), "volume", audio.output.get()); + fade_in->setDuration(gui_fade_in_ms); + fade_in->setStartValue(0.0); + fade_in->setEndValue(std::clamp(volume, 0.0f, 1.0f)); + fade_in->setEasingCurve(QEasingCurve::InSine); + fade_in->start(QAbstractAnimation::DeleteWhenStopped); + audio.player->play(); audio.source = this; } @@ -313,15 +327,42 @@ void qt_video_source::stop_audio() audio.source = nullptr; - if (audio.player) + QMediaPlayer* player = audio.player.release(); + QAudioOutput* output = audio.output.release(); + QBuffer* buffer = audio.buffer.release(); + QByteArray* data = audio.data.release(); + + const auto reset_player = [=]() { - audio.player->stop(); - audio.player.reset(); + if (player) + { + player->stop(); + delete player; + } + + if (output) delete output; + if (buffer) delete buffer; + if (data) delete data; + }; + + if (output) + { + QPropertyAnimation* fade_out = new QPropertyAnimation(output, "volume", output); + fade_out->setDuration(gui_fade_out_ms); + fade_out->setEasingCurve(QEasingCurve::OutSine); + fade_out->setStartValue(output->volume()); + fade_out->setEndValue(0.0); + + QObject::connect(fade_out, &QPropertyAnimation::finished, [reset_player]() + { + reset_player(); + }); + + fade_out->start(QAbstractAnimation::DeleteWhenStopped); + return; } - audio.output.reset(); - audio.buffer.reset(); - audio.data.reset(); + reset_player(); } QPixmap qt_video_source::get_movie_image(const QVideoFrame& frame) const