Ω-W1-T3: run the master meter on its own 60 FPS timer, and make a meter frame cost one rect

This commit is contained in:
2026-08-03 12:39:36 -04:00
parent 0eb2c67875
commit 4320bfdb08
7 changed files with 248 additions and 88 deletions
+28 -5
View File
@@ -7,6 +7,7 @@
#pragma once
#include <chrono>
#include <optional>
#include <string>
#include <unordered_map>
@@ -118,7 +119,13 @@ private:
FaceLayout faceLayout(int w, int h) const;
#ifdef _WIN32
void paint(HDC hdc);
// `dirty` is the host's WM_PAINT update rect: a region inside the meter's bar field redraws
// that field alone, anything else re-composes the face, and either way only the dirty region
// is blitted out of the retained back buffer (a per-paint client-area LICE_SysBitmap is what
// the meter's rate would otherwise cost).
void paint(HDC hdc, const RECT& dirty);
LICE_IBitmap* ensureBackBuffer(int w, int h);
void releaseBackBuffer();
void paintSample(LICE_IBitmap* bmp, int w, int h); // home face (band composition)
void paintBrowse(LICE_IBitmap* bmp, int w, int h); // modal picker overlay
void paintEmptyState(LICE_IBitmap* bmp, const Rect& area);
@@ -137,6 +144,7 @@ private:
// Decks: the group fence + caption + compact caption toggles + radial knobs with
// label<->value swap on hover/drag.
void paintDeck(LICE_IBitmap* bmp, const FaceLayout& fl);
void paintMeterField(LICE_IBitmap* bmp); // the bar field alone, off meterRects_
// A deck cell's mini curve thumbnail (the VELOCITY group) and the modal editor it summons.
void paintCurveButton(LICE_IBitmap* bmp, const Rect& r, CurveTarget target, bool disabled,
@@ -231,10 +239,16 @@ private:
// never yanks the edit surface.
void onSyncTimer();
// The meter tick (its own WM_TIMER id, UI thread only): drains the bus, advances the
// ballistics, repaints the bar field. Its own clock — see editor_platform.cpp's timer ids.
void onMeterTimer();
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void invalidate();
void invalidateMeter(); // the bar field only; falls back to invalidate() before first paint
HWND childHwnd_ = nullptr;
LICE_IBitmap* backBuffer_ = nullptr; // owned; see ensureBackBuffer
#endif
// Re-read the bank (samples + banks) from the live bridge and snapshot the instrument's
@@ -280,10 +294,16 @@ private:
// thread only (file I/O); cleared with the thumbnail cache on refresh.
const std::vector<AudioSample>& monoPcmFor(const std::string& sampleId);
// The hero waveform's binned envelope: the band's most expensive draw, and a function of the
// capture and the bin count alone. UI thread only (may decode).
const Envelope& heroEnvelope(std::size_t bins, int laneCount);
// The interleaved source PCM behind the stereo waveform lanes.
struct ChannelPcm {
std::vector<AudioSample> interleaved; // frame-interleaved source frames
int channelCount = 0; // 0 = nothing decoded
Envelope heroEnv; // binned from `interleaved`, so every path that drops the
std::size_t heroBins = 0; // decode drops it too. 0 = not computed
std::int64_t frameCount() const {
return channelCount > 0
? static_cast<std::int64_t>(interleaved.size()) / channelCount
@@ -471,11 +491,14 @@ private:
std::string searchQuery_; // type-to-filter narrow; "" = no search
bool searchFocused_ = false; // whether the search box has keyboard focus
// The MASTER deck's meter, advanced from the published block magnitudes on the sync tick
// (see onSyncTimer for why it runs mid-drag too, and why the first read is discarded).
// meterTickMs_ 0 = never ticked.
// The MASTER deck's meter, advanced from the published block magnitudes on its own timer
// (see onMeterTimer for why it runs mid-drag too, and why the first read is discarded).
// A default-constructed meterTick_ means never ticked. meterRects_ is the column interior
// resolved at the last FULL paint; an empty field means "not on screen" (no layout yet, the
// empty state, a modal sheet over it) and sends the tick down the whole-client path.
instrument::ui::MasterMeterUi masterMeter_;
unsigned long long meterTickMs_ = 0;
std::chrono::steady_clock::time_point meterTick_{};
instrument::ui::MeterRects meterRects_;
// Hover state (transient, never persisted).
HoverTarget hover_; // the interactive element under the pointer