Merge ps-w9-t1-sync: S9 bank-generation change-detection + assignment reader
This commit is contained in:
@@ -38,6 +38,14 @@ namespace {
|
||||
#ifdef _WIN32
|
||||
constexpr const wchar_t* kChildClassName = L"ReaSampler9000VstEditor";
|
||||
|
||||
// The S9/S8 change-detection poll (WM_TIMER on the child window). A low-frequency UI-thread
|
||||
// timer: responsive enough that a recapture/ingest/assign refreshes "within a bounded cadence"
|
||||
// (the S9 verify criterion) yet cheap — three small ext-state reads per tick, coalescing many
|
||||
// bumps between ticks into one reload. 500 ms is a deliberate build-time residual: fast enough
|
||||
// to feel hands-free, slow enough to be free. The id is a per-window SetTimer id (any nonzero).
|
||||
constexpr UINT_PTR kSyncTimerId = 1;
|
||||
constexpr UINT kSyncTimerIntervalMs = 500;
|
||||
|
||||
// Top-level band metrics (shell arithmetic — the load-bearing card/tab/key/zone geometry
|
||||
// is in capture_browser / keyboard_strip). The title band names the plugin + a live
|
||||
// readout; the toggle band carries the Browser/Zones switch; the setup band (single-
|
||||
@@ -174,6 +182,35 @@ void ReaSamplerEditor::rebuildVisible() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows-only (the WM_TIMER cadence + invalidate() are the Win32 child-window path). Declared
|
||||
// under the same _WIN32 guard in the header; keep the definition guarded to match (D5 makes
|
||||
// Windows the only build target, but the TU must still compile elsewhere).
|
||||
void ReaSamplerEditor::onSyncTimer() {
|
||||
// UI thread (WM_TIMER). Poll the S9 bank generation + the S8 assignment request via the
|
||||
// processor (off the audio thread — the poll itself never touches process()). NEVER while a
|
||||
// drag is in flight: a reload mid-drag would rebuild the instrument and repaint under the
|
||||
// user's cursor, yanking the edit. The next tick (500 ms) picks up the change after release.
|
||||
if (!processor_) return;
|
||||
if (drag_ != DragKind::kNone) return; // defer past the in-flight edit
|
||||
|
||||
// An open editor marks THIS instance the focused assignment target (the thundering-herd
|
||||
// policy — only an editor-open instance applies a pending assign; see the handoff). Pass
|
||||
// true so this instance consumes the request; instances with no editor open do not poll at
|
||||
// all (the timer is bound to the child window), so they never contend for the request.
|
||||
const ReaSamplerProcessor::BankSyncResult r = processor_->pollBankSync(/*isFocusedTarget=*/true);
|
||||
|
||||
// Re-snapshot the editor's own view only when something changed (a reload from a bank
|
||||
// content change, or an applied assignment). refreshFromBank re-reads the bank blob + the
|
||||
// processor's (possibly just-updated) selection/map and drops the stale thumbnail/PCM
|
||||
// caches, then repaints — so the browser + setup surface reflect the new bank hands-free.
|
||||
if (r.reloaded || r.applied) {
|
||||
refreshFromBank();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void ReaSamplerEditor::commitAndReload() {
|
||||
// UI thread only. Publish the edited selection + zones to the processor, then rebuild
|
||||
// the instrument off the audio thread (reloadFromBank bakes them into the live Keymap).
|
||||
@@ -373,11 +410,21 @@ void ReaSamplerEditor::attachedToParent() {
|
||||
r.getWidth(), r.getHeight(), parent, nullptr, hInst, nullptr);
|
||||
if (childHwnd_) {
|
||||
SetWindowLongPtr(childHwnd_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
// Start the S9/S8 change-detection poll (UI thread). Tied to the child window's
|
||||
// lifetime — created here, killed in removedFromParent — so an instance whose editor
|
||||
// is closed does NOT poll (the editor-open-only cadence; see the handoff limitation).
|
||||
SetTimer(childHwnd_, kSyncTimerId, kSyncTimerIntervalMs, nullptr);
|
||||
// Poll ONCE immediately so a pending assignment (an S8 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
|
||||
// any pending assign/generation so the just-opened editor shows the assigned capture.
|
||||
onSyncTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::removedFromParent() {
|
||||
if (childHwnd_) {
|
||||
KillTimer(childHwnd_, kSyncTimerId); // stop the poll before the window goes away
|
||||
DestroyWindow(childHwnd_);
|
||||
childHwnd_ = nullptr;
|
||||
}
|
||||
@@ -1064,6 +1111,9 @@ LRESULT CALLBACK ReaSamplerEditor::wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
self->invalidate();
|
||||
}
|
||||
return 0;
|
||||
case WM_TIMER:
|
||||
if (self && wParam == kSyncTimerId) self->onSyncTimer();
|
||||
return 0;
|
||||
case WM_ERASEBKGND:
|
||||
return 1; // fully repaint in WM_PAINT; skip the flicker-inducing erase
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user