// reasampler_editor.h — the VST3 IPlugView LICE editor for the ReaSampler 9000 // capture-first UI (Phase S10). THIN shell: hosts a LICE-drawn child window inside the // host's IPlugView seat and routes host paint/mouse into the pure geometry modules // (capture_browser, keyboard_strip) + the pure mapping (sample_map). Windows-only (D5). // // The default face is the CAPTURE BROWSER: a bank-filter tab strip over a grid of // scannable capture cards (peak thumbnail + name + root/key badge). A fresh instance with // no pick shows a "pick a capture" EMPTY STATE and plays silence (the S10 policy reversal // of the S4 first-sample auto-play). Picking a card loads that one capture and reveals a // guided SINGLE-CAPTURE SETUP surface (a keyboard strip with the capture's root marker + // a level readout). Multi-zone keymap editing is a demoted, opt-in ZONES panel (S10-Z), // reached by a toggle and driven by the same keyboard_strip drag machine. // // All layout/hit-test/drag math lives in the pure modules; this shell only draws + routes // (a LICE_SysBitmap blitted in WM_PAINT, a WM_LBUTTONDOWN/WM_MOUSEMOVE/WM_LBUTTONUP // drag-state machine hit-testing via the pure resolvers). Peak thumbnails are computed // shell-side from the decoded WAV (bank_model's Sample carries no envelope) and cached — // the mirror of bank_panel::thumbnailFor. Every edit commits OFF the audio thread via the // processor's reloadFromBank (RT path untouched). // // Subclasses CPluginView for the IPlugView boilerplate; overrides the attach/remove hooks // to create/destroy the child window and onSize to resize it. #pragma once #include #include #include #include #include "public.sdk/source/common/pluginview.h" #include "editor_geometry.h" // Rect (the shell's sub-rect type, shared with the pure modules) #include "peaks.h" // Envelope (the cached peak thumbnail) #include "sample_map.h" // SampleChoice, BankChoice, PerformanceMap (the shell's snapshot) #ifdef _WIN32 #include #endif class LICE_IBitmap; // fwd: the paint helpers take one; lice.h is included only in the .cpp namespace reasampler::vst { class ReaSamplerProcessor; class ReaSamplerEditor : public Steinberg::CPluginView { public: // `processor` owns this editor's lifetime domain and outlives it; the editor reads the // live bank through it and drives selection/zone edits + reload on user input. May be // null (defensive — a real host always supplies one). explicit ReaSamplerEditor(ReaSamplerProcessor* processor); ~ReaSamplerEditor() override; Steinberg::tresult PLUGIN_API isPlatformTypeSupported( Steinberg::FIDString type) override; Steinberg::tresult PLUGIN_API canResize() override; protected: void attachedToParent() override; void removedFromParent() override; Steinberg::tresult PLUGIN_API onSize(Steinberg::ViewRect* newSize) override; private: // Which face the editor shows. The browser is the default; the Zones panel is the // demoted opt-in view reached by the toggle. Both draw over the same snapshotted bank. enum class View { kBrowser, kZones }; // What a mouse drag is currently editing (the drag-state machine). kNone = no drag in // flight. The zone-edit grabs mirror keyboard_strip::ZoneGrab; kRootMarker is the // single-capture root drag on the setup strip. enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody }; #ifdef _WIN32 void paint(HDC hdc); void paintBrowser(LICE_IBitmap* bmp, int w, int h); void paintSetup(LICE_IBitmap* bmp, const Rect& area); void paintZones(LICE_IBitmap* bmp, int w, int h); void paintEmptyState(LICE_IBitmap* bmp, const Rect& area); void onMouseDown(int x, int y); void onMouseMove(int x, int y); void onMouseUp(int x, int y); static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); void invalidate(); HWND childHwnd_ = nullptr; #endif // Re-read the bank (samples + banks) from the live bridge and snapshot the instrument's // selection + performance map. Main/UI thread only. Called on attach and after any edit. void refreshFromBank(); // Publish the edited zones/selection to the processor, then rebuild the instrument OFF // the audio thread. UI thread only. One place so every edit commits identically. void commitAndReload(); // Recompute the capture cards visible under the current bank filter (samples_ narrowed by // activeFilterBankId_; "" = All) into visible_. Called on refresh + filter change. void rebuildVisible(); // The peak thumbnail for a bank sample id at `binCount` bins, computed once from the // decoded WAV (mirror of bank_panel::thumbnailFor) and cached by (id, binCount). Returns // an empty envelope when the WAV can't be resolved/decoded. UI thread only (file I/O). const Envelope& thumbnailFor(const std::string& sampleId, int binCount); ReaSamplerProcessor* processor_ = nullptr; // --- Snapshot of the live bank (drawn each paint; refreshed off the audio thread) --- std::vector samples_; // every bank sample, bank order std::vector banks_; // the named banks, for the filter tab strip std::vector visible_; // samples_ narrowed by the active bank filter std::string selectedId_; // the single-capture pick ("" = empty state) PerformanceMap map_; // the opt-in zones (empty = no zones) ChannelMode channelMode_ = ChannelMode::Mono; // S7 mono/stereo toggle snapshot // --- Transient UI state (not persisted; component state carries selection + zones) --- View view_ = View::kBrowser; // default face is the browser std::string activeFilterBankId_; // "" = All; else a bank id from banks_ int selectedZone_ = -1; // highlighted zone in the Zones panel; -1 = none // --- Drag-state machine ------------------------------------------------------ DragKind drag_ = DragKind::kNone; int dragStartX_ = 0; // grab x (px), for the pixel-delta resolver int dragStartLow_ = 0; // the grabbed field's note at grab time int dragStartHigh_ = 0; int dragStartRoot_ = 60; // --- Peak-thumbnail cache (mirror of bank_panel; id -> envelope at a bin width) ------ // Keyed by "id|binCount" so a resize recomputes at the new width. Cleared on refresh so // a bank edit (a re-captured or deleted sample) does not show a stale thumbnail. std::unordered_map thumbCache_; }; } // namespace reasampler::vst