From 0ffe836a297cf71867afe1f851d5ada2f199509e Mon Sep 17 00:00:00 2001 From: BlackMark Date: Sun, 21 Jun 2026 01:21:32 +0200 Subject: [PATCH] Debounce the Audio panel "live" column The live indicator compared frames_rendered to the previous UI frame's value, but audio buffers release in bursts so most frames saw no change -- the cell flickered between a green dot and grey "idle". Now each stream remembers when it last advanced and reads "live" for a short window (0.4 s) afterwards, with a ~2 Hz frames/s estimate next to it; otherwise "idle". Steady and readable for multi-stream games. Verified: x64 build green. Full visual confirmation needs an injected, audio-playing game with the per-stream table open (Debug details); logic reviewed. Co-Authored-By: Claude Opus 4.8 --- README.md | 7 ------- host/src/audio_panel.cpp | 26 ++++++++++++++++++++++++-- host/src/audio_panel.hpp | 9 ++++++++- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d5ca9cd..28bf005 100644 --- a/README.md +++ b/README.md @@ -75,13 +75,6 @@ is removed from this list once done — so the top item is always next. The self-verifiable tooling / UI / input items come first; the game-pipeline items that need a real game (and Remote Play) to fully validate come last. -- **Fix the Audio panel "live" column.** It overlays a green dot and grey "idle" - because liveness is recomputed each frame from the per-stream `frames_rendered` - delta, which is zero on most frames (buffers release in bursts), so it flickers. - Replace it with a **debounced activity indicator**: keep a per-stream "last - advanced" timestamp (the panel already stores the previous frame counts) and show - **live** if frames advanced within the last ~300–500 ms, else **idle** — optionally - a small frames/s or activity bar so multi-stream games read clearly. - **Move the synthetic-input toggle to the Controllers panel, under Debug details.** The "Forward synthetic test input" checkbox is a controller-debugging aid, so move it out of the Injection panel into `ControllersPanel` and gate it behind diff --git a/host/src/audio_panel.cpp b/host/src/audio_panel.cpp index 8086688..be6eac9 100644 --- a/host/src/audio_panel.cpp +++ b/host/src/audio_panel.cpp @@ -129,6 +129,8 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details) } const std::uint32_t rows = std::min(status.audio_streams_seen, kMaxAudioStreams); + const double now = ImGui::GetTime(); + const bool resample = (now - rate_base_time_) >= 0.5; // recompute frames/s ~2x a second if (rows > 0 && ImGui::BeginTable("audio_streams", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) { @@ -141,8 +143,22 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details) for (std::uint32_t i = 0; i < rows; ++i) { const AudioStreamInfo& s = status.audio_streams[i]; - const bool live = s.frames_rendered > prev_frames_[i]; + + // Debounced activity: remember when this stream last advanced, and call it + // live for a short window afterwards so bursty releases don't flicker. + if (s.frames_rendered > prev_frames_[i]) + { + last_active_[i] = now; + } prev_frames_[i] = s.frames_rendered; + const bool live = last_active_[i] > 0.0 && (now - last_active_[i]) < 0.4; + if (resample) + { + const double dt = now - rate_base_time_; + frames_per_s_[i] = + dt > 0.0 ? static_cast(s.frames_rendered - rate_base_frames_[i]) / dt : 0.0; + rate_base_frames_[i] = s.frames_rendered; + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -158,7 +174,9 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details) ImGui::TableNextColumn(); if (live) { - ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "●"); + ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "live"); + ImGui::SameLine(); + ImGui::TextDisabled("%.0f/s", frames_per_s_[i]); } else { @@ -167,6 +185,10 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details) } ImGui::EndTable(); } + if (resample) + { + rate_base_time_ = now; + } ImGui::End(); } diff --git a/host/src/audio_panel.hpp b/host/src/audio_panel.hpp index ed9ceaa..6373b91 100644 --- a/host/src/audio_panel.hpp +++ b/host/src/audio_panel.hpp @@ -32,8 +32,15 @@ private: bool enabled_ = false; AudioMirror mirror_; - // Previous per-stream frame counts, to flag streams as live (advancing). + // Per-stream activity tracking for the "live" column. Audio buffers release in + // bursts, so most UI frames see no change; comparing to just the previous frame + // flickers. Instead we remember when each stream last advanced and debounce the + // live/idle indicator over a short window, plus a ~2 Hz frames/s estimate. std::uint64_t prev_frames_[kMaxAudioStreams] = {}; + double last_active_[kMaxAudioStreams] = {}; // ImGui time a stream last advanced + std::uint64_t rate_base_frames_[kMaxAudioStreams] = {}; + double frames_per_s_[kMaxAudioStreams] = {}; + double rate_base_time_ = 0.0; }; } // namespace coop