Ω-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:
@@ -31,6 +31,15 @@ constexpr const wchar_t* kChildClassName = L"ReaSampler9000VstEditor";
|
||||
// a per-window SetTimer id (any nonzero).
|
||||
constexpr UINT_PTR kSyncTimerId = 1;
|
||||
constexpr UINT kSyncTimerIntervalMs = 500;
|
||||
|
||||
// The meter's own clock on the same child window, because the bus meter is the one surface
|
||||
// whose value changes every block. Raising the poll above to frame rate instead is the REJECTED
|
||||
// alternative: its body costs a bridge read plus a bank parse, and its two tick-counted banners
|
||||
// (the bake message, the drop hint) are calibrated in ticks, so they would silently shorten by
|
||||
// the same factor. 16 ms is 60 FPS; what a frame costs is the meter's bar field, not the client
|
||||
// area — the whole-client invalidate is what made this rate unaffordable before.
|
||||
constexpr UINT_PTR kMeterTimerId = 2;
|
||||
constexpr UINT kMeterTimerIntervalMs = 16;
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
@@ -66,6 +75,17 @@ void ReaSamplerEditor::invalidate() {
|
||||
if (childHwnd_) InvalidateRect(childHwnd_, nullptr, FALSE);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::invalidateMeter() {
|
||||
if (!childHwnd_) return;
|
||||
const Rect& f = meterRects_.field;
|
||||
if (f.empty()) { // nothing cached (see meterRects_) — the whole face has to answer
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
RECT r{f.x, f.y, f.right(), f.bottom()};
|
||||
InvalidateRect(childHwnd_, &r, FALSE);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::attachedToParent() {
|
||||
HWND parent = static_cast<HWND>(systemWindow);
|
||||
if (!parent) return;
|
||||
@@ -111,6 +131,9 @@ void ReaSamplerEditor::attachedToParent() {
|
||||
// created here, killed in removedFromParent — so an instance whose editor is closed
|
||||
// does not poll.
|
||||
SetTimer(childHwnd_, kSyncTimerId, kSyncTimerIntervalMs, nullptr);
|
||||
// Bound to the same window for the same reason: an instance with no editor open runs
|
||||
// neither clock, and the meter's accumulators simply pile up until one opens.
|
||||
SetTimer(childHwnd_, kMeterTimerId, kMeterTimerIntervalMs, nullptr);
|
||||
// Poll once immediately so a pending assignment (an ingest fired while this editor was
|
||||
// closed) or a bank change applies the instant the editor opens, rather than waiting up
|
||||
// to one timer interval. refreshFromBank above already primed the view; this folds in
|
||||
@@ -127,9 +150,11 @@ void ReaSamplerEditor::removedFromParent() {
|
||||
if (processor_) processor_->endParamGesture();
|
||||
if (childHwnd_) {
|
||||
KillTimer(childHwnd_, kSyncTimerId); // stop the poll before the window goes away
|
||||
KillTimer(childHwnd_, kMeterTimerId);
|
||||
DestroyWindow(childHwnd_);
|
||||
childHwnd_ = nullptr;
|
||||
}
|
||||
releaseBackBuffer(); // a client-area bitmap outlives nothing here
|
||||
}
|
||||
|
||||
tresult PLUGIN_API ReaSamplerEditor::onSize(ViewRect* newSize) {
|
||||
@@ -137,6 +162,10 @@ tresult PLUGIN_API ReaSamplerEditor::onSize(ViewRect* newSize) {
|
||||
if (childHwnd_ && newSize) {
|
||||
MoveWindow(childHwnd_, 0, 0, newSize->getWidth(), newSize->getHeight(), TRUE);
|
||||
thumbCache_.clear(); // thumbnails are width-bound; a resize invalidates them
|
||||
ensureBackBuffer(newSize->getWidth(), newSize->getHeight());
|
||||
// The cached meter rects name the OLD layout; drop them so the meter tick takes the
|
||||
// whole-client path until the resize's own full paint resolves them again.
|
||||
meterRects_ = {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -149,7 +178,7 @@ LRESULT CALLBACK ReaSamplerEditor::wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps{};
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
if (self) self->paint(hdc);
|
||||
if (self) self->paint(hdc, ps.rcPaint);
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
@@ -293,7 +322,10 @@ LRESULT CALLBACK ReaSamplerEditor::wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
return 0;
|
||||
}
|
||||
case WM_TIMER:
|
||||
if (self && wParam == kSyncTimerId) self->onSyncTimer();
|
||||
if (self) {
|
||||
if (wParam == kSyncTimerId) self->onSyncTimer();
|
||||
else if (wParam == kMeterTimerId) self->onMeterTimer();
|
||||
}
|
||||
return 0;
|
||||
case WM_ERASEBKGND:
|
||||
return 1; // fully repaint in WM_PAINT; skip the flicker-inducing erase
|
||||
|
||||
Reference in New Issue
Block a user