4a3551b3b9
Per-instance mono|stereo (default mono, byte-identical). Stereo grows SampleData a 2nd channel + a per-channel VoiceEngine render; decodeChannels applies the cross-mode policy; setBusArrangements pins the mode's arrangement and restartComponent(kIoChanged) re-negotiates.
137 lines
6.6 KiB
C++
137 lines
6.6 KiB
C++
// 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 <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#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 <windows.h>
|
|
#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<SampleChoice> samples_; // every bank sample, bank order
|
|
std::vector<BankChoice> banks_; // the named banks, for the filter tab strip
|
|
std::vector<SampleChoice> 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<std::string, Envelope> thumbCache_;
|
|
};
|
|
|
|
} // namespace reasampler::vst
|