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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
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.
|
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.**
|
- **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
|
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
|
it out of the Injection panel into `ControllersPanel` and gate it behind
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::uint32_t rows = std::min<std::uint32_t>(status.audio_streams_seen, kMaxAudioStreams);
|
const std::uint32_t rows = std::min<std::uint32_t>(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 &&
|
if (rows > 0 &&
|
||||||
ImGui::BeginTable("audio_streams", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit))
|
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)
|
for (std::uint32_t i = 0; i < rows; ++i)
|
||||||
{
|
{
|
||||||
const AudioStreamInfo& s = status.audio_streams[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;
|
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<double>(s.frames_rendered - rate_base_frames_[i]) / dt : 0.0;
|
||||||
|
rate_base_frames_[i] = s.frames_rendered;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
@@ -158,7 +174,9 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details)
|
|||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
if (live)
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -167,6 +185,10 @@ void AudioPanel::draw_ui(const HookStatusView& status, bool debug_details)
|
|||||||
}
|
}
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
if (resample)
|
||||||
|
{
|
||||||
|
rate_base_time_ = now;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,15 @@ private:
|
|||||||
bool enabled_ = false;
|
bool enabled_ = false;
|
||||||
AudioMirror mirror_;
|
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] = {};
|
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
|
} // namespace coop
|
||||||
|
|||||||
Reference in New Issue
Block a user