Cut shell/instrument comment bloat ~34% (comments only, zero code change)
This commit is contained in:
@@ -1,25 +1,8 @@
|
||||
// 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 reloadInstrument (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.
|
||||
// reasampler_editor.h — VST3 IPlugView LICE editor for the ReaSampler 9000 UI. Thin shell:
|
||||
// hosts a LICE child window, routing host paint/mouse into the pure geometry modules
|
||||
// (capture_browser, keyboard_strip, sample_map) — default face is the capture browser, then
|
||||
// single-capture setup, with an opt-in zones panel. All layout/hit-test/drag math lives in
|
||||
// the pure modules; every edit commits off the audio thread via reloadInstrument.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -30,13 +13,13 @@
|
||||
|
||||
#include "public.sdk/source/common/pluginview.h"
|
||||
|
||||
#include "core/instrument/ui/editor_geometry.h" // Rect (the shell's sub-rect type, shared with the pure modules)
|
||||
#include "core/instrument/ui/envelope_edit.h" // EnvClampBounds / NodeHit (S-VIEW-3 envelope node hit-test/edit)
|
||||
#include "core/instrument/ui/envelope_overlay.h" // AmpEnvelope / EnvNode (S-VIEW-3 envelope overlay draw seam)
|
||||
#include "core/instrument/ui/knob_deck.h" // DeckGroupDesc / DeckLayout (r11 knob deck — Sample FB1, Zone FB2)
|
||||
#include "core/instrument/ui/editor_geometry.h" // Rect (shared sub-rect type)
|
||||
#include "core/instrument/ui/envelope_edit.h" // EnvClampBounds / NodeHit (envelope node hit-test/edit)
|
||||
#include "core/instrument/ui/envelope_overlay.h" // AmpEnvelope / EnvNode (envelope overlay draw seam)
|
||||
#include "core/instrument/ui/knob_deck.h" // DeckGroupDesc / DeckLayout (Sample + Zone knob deck)
|
||||
#include "core/audio/peaks.h" // Envelope (the cached peak thumbnail)
|
||||
#include "core/instrument/map/sample_map.h" // SampleChoice, BankChoice, PerformanceMap (the shell's snapshot)
|
||||
#include "core/instrument/engine/velocity_curve.h" // VelocityCurve (S-VIEW-10 transfer-curve editor state)
|
||||
#include "core/instrument/engine/velocity_curve.h" // VelocityCurve (transfer-curve editor state)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -46,10 +29,6 @@ class LICE_IBitmap; // fwd: the paint helpers take one; lice.h is included only
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
// Cross-subsystem deps by their real namespace homes (Q-W2v: the core/namespaces.h shim
|
||||
// is retired from the editor family; engine symbols — ChannelMode, VoiceMode, MonoTrigger,
|
||||
// the voice-count constants, VelocityCurve via the engine re-export — stay in flat
|
||||
// `reasampler` and resolve via the enclosing namespace).
|
||||
using audio::AudioSample;
|
||||
using audio::Envelope;
|
||||
using instrument::map::BankChoice;
|
||||
@@ -69,9 +48,9 @@ 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).
|
||||
// `processor` outlives this editor; 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;
|
||||
|
||||
@@ -86,67 +65,51 @@ protected:
|
||||
Steinberg::tresult PLUGIN_API onSize(Steinberg::ViewRect* newSize) override;
|
||||
|
||||
private:
|
||||
// Which face the editor shows (S-VIEW-1, three-view model). Sample is the HOME/default
|
||||
// face (the loaded capture). Browse is a full-window MODAL picker overlaid on Sample
|
||||
// (select + confirm/cancel changes the loaded capture, then dismisses). Zone is the
|
||||
// dedicated multi-zone keymap surface, button-summoned. All three draw over the same
|
||||
// snapshotted bank; Browse + Zone return to Sample when dismissed.
|
||||
// Sample is the home/default face. Browse is a full-window modal picker overlaid on
|
||||
// Sample. Zone is the dedicated multi-zone keymap surface, button-summoned.
|
||||
enum class View { kSample, kBrowse, kZone };
|
||||
|
||||
// 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; kWaveMarker is a draggable start/loop
|
||||
// marker on the S11 waveform surface (which marker is in waveMarker_); kEnvNode is a
|
||||
// draggable envelope breakpoint on the Sample-view hero overlay (S-VIEW-3, which node in
|
||||
// envNode_); kCurveNode is a draggable velocity-curve control point in the S-VIEW-10
|
||||
// transfer-curve editor (which point in curvePointIndex_); kDeckKnob is a GRAB-ANCHORED
|
||||
// vertical radial-knob drag on an r11 knob deck — the Sample face's deck/cluster (FB1)
|
||||
// or the Zone panel's per-zone deck (FB2) — (which control in dragParamId_; the value at
|
||||
// grab in dragKnobStartValue_ — no jump on grab, FA4).
|
||||
// What a mouse drag is currently editing. kWaveMarker/kEnvNode/kCurveNode track their
|
||||
// grabbed item in waveMarker_/envNode_/curvePointIndex_; kDeckKnob is a grab-anchored
|
||||
// knob drag (control in dragParamId_, grab value in dragKnobStartValue_).
|
||||
enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody, kWaveMarker,
|
||||
kScrollThumb, kEnvNode, kCurveNode, kDeckKnob };
|
||||
|
||||
// The parameter controls on the setup surface (S12 AHDSR + the S15/S16 control surfaces).
|
||||
// The int value is the opaque control id the pure knob_deck hit-test returns; the shell
|
||||
// maps it to the picked zone's play params (or a processor-side per-instance setter).
|
||||
// Controls on the setup surface. The int value is the opaque control id the pure
|
||||
// knob_deck hit-test returns; the shell maps it to the zone's play params or a
|
||||
// processor-side per-instance setter.
|
||||
enum class ParamControl {
|
||||
kPlayMode = 0, // Gate | Trigger toggle (S15)
|
||||
kPitchEngine, // Varispeed | Preserve toggle (S16)
|
||||
kPlayMode = 0, // Gate | Trigger toggle
|
||||
kPitchEngine, // Varispeed | Preserve toggle
|
||||
kAttack, // AHDSR attack (Gate) / —
|
||||
kHold, // AHDSR hold (Gate, S15)
|
||||
kHold, // AHDSR hold (Gate)
|
||||
kDecay, // AHDSR decay (Gate)
|
||||
kSustain, // AHDSR sustain (Gate)
|
||||
kRelease, // AHDSR release (Gate)
|
||||
kTrigLength, // Trigger %-length (Trigger, S15)
|
||||
kTrigFadeIn, // Trigger fade-in (Trigger, S15)
|
||||
kTrigFadeOut, // Trigger fade-out (Trigger, S15)
|
||||
kPitchEnvEnable, // AD pitch envelope on|off (S16)
|
||||
kPitchEnvAttack, // AD pitch attack (S16)
|
||||
kPitchEnvDecay, // AD pitch decay (S16)
|
||||
kPitchEnvDepth, // AD pitch depth in +/- semitones (S16)
|
||||
kKeyTrack, // S-VIEW-6 key-tracking 0..200% (lives on PerformanceZone, not ZonePlaySeconds)
|
||||
// r11 deck-only controls (FB1): processor-side per-instance params, NOT zone params —
|
||||
// routed to the processor setters, never through applyZoneControl / the map.
|
||||
kVoiceCount, // Phase S polyphony bound (1..32) — a stepped knob in the VOICE group
|
||||
kTrigLength, // Trigger %-length
|
||||
kTrigFadeIn, // Trigger fade-in
|
||||
kTrigFadeOut, // Trigger fade-out
|
||||
kPitchEnvEnable, // AD pitch envelope on|off
|
||||
kPitchEnvAttack, // AD pitch attack
|
||||
kPitchEnvDecay, // AD pitch decay
|
||||
kPitchEnvDepth, // AD pitch depth in +/- semitones
|
||||
kKeyTrack, // key-tracking 0..200% (lives on PerformanceZone, not ZonePlaySeconds)
|
||||
// Deck-only controls: processor-side per-instance params, NOT zone params — routed to
|
||||
// the processor setters, never through applyZoneControl / the map.
|
||||
kVoiceCount, // polyphony bound (1..32) — a stepped knob in the VOICE group
|
||||
kVoiceMode, // Poly | Mono caption toggle (VOICE group)
|
||||
kMonoTrigger, // Retrig | Legato row toggle (VOICE group; live only in Mono)
|
||||
kMasterGain, // FB1 post-mixer master gain knob (-inf..+24 dB taper, MASTER group)
|
||||
kMasterGain, // post-mixer master gain knob (-inf..+24 dB taper, MASTER group)
|
||||
kCount
|
||||
};
|
||||
|
||||
// The waveform markers on the single-capture setup surface (S11). Order is the draw + hit
|
||||
// order (start first). Named generically per the spec so S15 can repurpose the surface with
|
||||
// a different marker set; here it is start-point + the sustain loop's two ends.
|
||||
// The waveform markers on the single-capture setup surface: start-point + the sustain
|
||||
// loop's two ends, in draw + hit order.
|
||||
enum class WaveMarker { kStart = 0, kLoopStart = 1, kLoopEnd = 2, kCount = 3 };
|
||||
|
||||
// --- Hover model (Phase L, L3) ------------------------------------------------
|
||||
//
|
||||
// The interactive element under the pointer, resolved live in WM_MOUSEMOVE so the kit
|
||||
// draws its hover state on that element only ("hover on every interactive element" +
|
||||
// "sub-frame feedback = the perception of speed", §3.3/§3.5). Cleared to kNone on
|
||||
// WM_MOUSELEAVE (tracked via TrackMouseEvent). `index` disambiguates within a kind
|
||||
// (tab ordinal, visible-card index, control-row id); -1 when not applicable. Mirror of
|
||||
// bank_panel's L2 hover model.
|
||||
// The interactive element under the pointer, resolved live in WM_MOUSEMOVE. `index`
|
||||
// disambiguates within a kind (tab ordinal, visible-card index, control-row id); -1 when
|
||||
// not applicable.
|
||||
enum class HoverKind {
|
||||
kNone,
|
||||
kNavBrowse, // the Sample-view "Browse" title-band button (opens the Browse modal)
|
||||
@@ -163,10 +126,10 @@ private:
|
||||
kAddZone, // the "+ Add Zone" button
|
||||
kDeleteZone, // the "Delete" zone button
|
||||
kControl, // a knob-deck element (index = control id)
|
||||
kCurveNode, // a velocity-curve control point (index = point index, S-VIEW-10)
|
||||
kVelKnob, // the cluster preview-velocity radial knob (r11)
|
||||
kCurveButton, // the cluster mini curve-preview button (r11 — opens the popup)
|
||||
kPopupClose, // the curve popup's Close (x) button (r11)
|
||||
kCurveNode, // a velocity-curve control point (index = point index)
|
||||
kVelKnob, // the cluster preview-velocity radial knob
|
||||
kCurveButton, // the cluster mini curve-preview button (opens the popup)
|
||||
kPopupClose, // the curve popup's Close (x) button
|
||||
};
|
||||
struct HoverTarget {
|
||||
HoverKind kind = HoverKind::kNone;
|
||||
@@ -177,96 +140,72 @@ private:
|
||||
|
||||
#ifdef _WIN32
|
||||
void paint(HDC hdc);
|
||||
void paintSample(LICE_IBitmap* bmp, int w, int h); // S-VIEW-2/r11 home face
|
||||
void paintBrowse(LICE_IBitmap* bmp, int w, int h); // S-VIEW-5 modal picker overlay
|
||||
void paintZone(LICE_IBitmap* bmp, int w, int h); // S-VIEW-8 zone surface
|
||||
void paintSample(LICE_IBitmap* bmp, int w, int h); // home face
|
||||
void paintBrowse(LICE_IBitmap* bmp, int w, int h); // modal picker overlay
|
||||
void paintZone(LICE_IBitmap* bmp, int w, int h); // zone surface
|
||||
void paintEmptyState(LICE_IBitmap* bmp, const Rect& area);
|
||||
|
||||
// --- r11 knob-deck rendering (FB1 Sample face; FB2 Zone panel) -------------------
|
||||
// The knob deck: the fenced task groups drawn through the L1 kit — group fence + caption +
|
||||
// compact caption toggles + radial knobs (param_slider's FA4 primitive) with label<->value
|
||||
// swap on hover/drag. `descs` picks the group set: the full Sample deck (deckGroupDescs)
|
||||
// or the Zone panel's per-zone groups (zoneDeckGroupDescs). Lays out from deckArea's
|
||||
// top-left; the caller anchors (Sample bottom-anchors, Zone top-anchors).
|
||||
// The knob deck: group fence + caption + compact caption toggles + radial knobs with
|
||||
// label<->value swap on hover/drag. `descs` picks the group set (Sample's deckGroupDescs
|
||||
// or the Zone panel's zoneDeckGroupDescs); caller anchors (Sample bottom, Zone top).
|
||||
void paintKnobDeck(LICE_IBitmap* bmp, const Rect& deckArea, const PerformanceZone& zone,
|
||||
const std::vector<DeckGroupDesc>& descs);
|
||||
// The mini curve-preview button (shared by the Sample cluster + the Zone panel, FB2): a
|
||||
// hairline bg/cell square tracing the zone's live curve; Active border while the popup is up.
|
||||
// The mini curve-preview button shared by the Sample cluster + the Zone panel.
|
||||
void paintCurveButton(LICE_IBitmap* bmp, const Rect& r, const PerformanceZone& zone);
|
||||
// The centered curve-popup sheet (wash + title + close + full-size curve editor). Edits
|
||||
// popupZone() — the Sample face's one-zone site or the Zone surface's selected zone (FB2).
|
||||
// The centered curve-popup sheet. Edits popupZone() — the Sample face's one-zone site
|
||||
// or the Zone surface's selected zone.
|
||||
void paintCurvePopup(LICE_IBitmap* bmp, int w, int h);
|
||||
// Trace the S-VIEW-3 amp-envelope overlay + its draggable node handles over `waveArea` for
|
||||
// `zone`'s play params, at the sample's wall-clock duration. Shared by the Sample hero band.
|
||||
// Traces the amp-envelope overlay + its draggable node handles over `waveArea`.
|
||||
void paintEnvelopeOverlay(LICE_IBitmap* bmp, const Rect& waveArea, const PerformanceZone& zone,
|
||||
std::int64_t frames);
|
||||
// S-VIEW-10: the velocity->amp transfer-curve editor — a bordered box (X = velocity 0-127,
|
||||
// Y = amp 0-1), the monotone spline traced by eval, one draggable node handle per control
|
||||
// point. Since FB2 its ONLY host is the r11 popup sheet (both surfaces summon it via the
|
||||
// mini preview button); all mapping / hit-test / clamp math lives in the pure
|
||||
// velocity_curve module. `r` empty -> draws nothing.
|
||||
// The velocity->amp transfer-curve editor (X = velocity 0-127, Y = amp 0-1); its only
|
||||
// host is the popup sheet. `r` empty -> draws nothing.
|
||||
void paintVelocityCurve(LICE_IBitmap* bmp, const Rect& r, const PerformanceZone& zone);
|
||||
|
||||
// Route a mouse-down inside curve-editor box `r` editing map_.zones[zoneIndex]: a node grab
|
||||
// starts a kCurveNode drag; Alt-click on an interior node deletes it (committed at once);
|
||||
// an empty-space click ADDS a point at the cursor and grabs it for an immediate drag.
|
||||
// `zoneIndex` must be a valid index into map_.zones (callers materialize first).
|
||||
// Mouse-down inside curve-editor box `r` editing map_.zones[zoneIndex]: a node grab
|
||||
// starts a kCurveNode drag; Alt-click on an interior node deletes it at once; an
|
||||
// empty-space click adds a point and grabs it. `zoneIndex` must be valid (callers
|
||||
// materialize first).
|
||||
void handleCurveMouseDown(const Rect& r, int zoneIndex, int x, int y);
|
||||
|
||||
// Route a left-click while the curve popup is open (the popup is MODAL over the Sample
|
||||
// face AND the Zone surface, FB2): Close / outside-wash dismiss, in-box clicks into the
|
||||
// shared curve machinery against popupZoneIndex(), everything else on the sheet swallowed.
|
||||
// Returns true when the popup consumed the click (i.e. whenever it is open).
|
||||
// Left-click while the curve popup is open (modal over both faces): Close /
|
||||
// outside-wash dismiss, in-box clicks route to the curve machinery, else swallowed.
|
||||
// Returns true whenever the popup is open (it consumed the click).
|
||||
bool handlePopupMouseDown(int w, int h, int x, int y);
|
||||
|
||||
void onMouseDown(int x, int y);
|
||||
// The Browse-modal and Zone-surface halves of the mouse-down dispatch (Q-W2v: the
|
||||
// input TUs split along the face axis — onMouseDown keeps the Sample-face branch and
|
||||
// delegates these two; bodies in editor_input_browse_zone.cpp). Behavior-identical
|
||||
// to the former inline branches.
|
||||
// The Browse-modal and Zone-surface halves of the mouse-down dispatch (bodies in
|
||||
// editor_input_browse_zone.cpp).
|
||||
void mouseDownBrowse(int w, int h, int x, int y);
|
||||
void mouseDownZone(int w, int h, int x, int y);
|
||||
void onMouseMove(int x, int y);
|
||||
void onMouseUp(int x, int y);
|
||||
// r11: right-click — the curve popup's PRIMARY node-delete affordance (issue 3c). Only
|
||||
// acts while the popup is open (over the Sample face OR the Zone surface, FB2); a
|
||||
// right-click on a popup curve node deletes it through the same commit path as Alt-click
|
||||
// (deletePoint's endpoint guard makes endpoint right-clicks a safe no-op). Everything
|
||||
// else ignores right-clicks.
|
||||
// Right-click is the curve popup's primary node-delete affordance; only acts while the
|
||||
// popup is open (deletePoint's endpoint guard makes an endpoint right-click a no-op).
|
||||
void onMouseRDown(int x, int y);
|
||||
|
||||
// Apply a knob/toggle interaction to map_.zones[zoneIndex] for control `id`: routes ordinary
|
||||
// controls through applyControl against the zone's play struct, and kKeyTrack against the
|
||||
// zone's keyTrack scalar (0..200% over the knob's 0..1). Used by both the click + drag paths.
|
||||
// Applies a knob/toggle interaction to map_.zones[zoneIndex] for control `id`: ordinary
|
||||
// controls route through applyControl; kKeyTrack writes the zone's keyTrack scalar
|
||||
// (0..200% over the knob's 0..1).
|
||||
void applyZoneControl(int zoneIndex, int id, double value, int segment);
|
||||
|
||||
// Resolve the interactive element under (x, y) into hover_ (Phase L, L3). Called from
|
||||
// WM_MOUSEMOVE (also while a drag is in flight — the resolved element just isn't used
|
||||
// for a hover repaint mid-drag). Repaints only when the hovered element changed, so an
|
||||
// idle mouse-move is free. Windows-only (the hit-tests use the shell's Win32 client rect).
|
||||
// Resolves the interactive element under (x, y) into hover_, called from WM_MOUSEMOVE.
|
||||
// Repaints only on change, so an idle move is free. Windows-only.
|
||||
void resolveHover(int x, int y);
|
||||
// True iff element (kind, index) is the live hover_ target — the shell maps this to the
|
||||
// kit's Hover interaction state when the element has no more-specific state (Active, etc.).
|
||||
bool isHovered(HoverKind kind, int index) const {
|
||||
return hover_.kind == kind && hover_.index == index;
|
||||
}
|
||||
void onMouseWheel(int delta); // S12 browser scroll (wheel)
|
||||
void onSearchChar(unsigned int ch); // S12 type-to-filter search keystroke
|
||||
void onMouseWheel(int delta); // browser scroll (wheel)
|
||||
void onSearchChar(unsigned int ch); // type-to-filter search keystroke
|
||||
|
||||
// S13 (relay degraded): an OS file drop landed on the editor window. We do NOT ingest (the
|
||||
// instrument is a read-only bank consumer and the relay is unshipped) — we flash the "drop
|
||||
// on the ReaSampler panel to add" affordance so the drop is never silently swallowed and the
|
||||
// shipped ingest gesture stays discoverable. `droppedCount` is how many files were dropped
|
||||
// (drawn into the banner). NEVER inserts a timeline item / never touches the bank.
|
||||
// An OS file drop landed on the editor window. We do NOT ingest (read-only bank
|
||||
// consumer) — flash a "drop on the ReaSampler panel to add" affordance instead of
|
||||
// silently swallowing it. Never inserts a timeline item.
|
||||
void onFilesDropped(int droppedCount);
|
||||
|
||||
// The S9/S8 change-detection tick (WM_TIMER on the child window — the UI thread, NEVER the
|
||||
// audio thread). Polls the processor's bank-sync (generation change -> hands-free reload;
|
||||
// a new assignment request -> apply as this instance's selection) and, when anything
|
||||
// changed, re-snapshots the editor's own view (refreshFromBank) + repaints so the browser /
|
||||
// setup surface reflect the new bank. An open editor means THIS instance is the focused
|
||||
// assignment target (the thundering-herd policy — see the handoff), so it passes true.
|
||||
// Suppressed WHILE A DRAG IS IN FLIGHT so a mid-drag reload does not yank the edit surface.
|
||||
// The change-detection tick (WM_TIMER, UI thread only): polls the processor's bank-sync
|
||||
// and re-snapshots + repaints when anything changed. Suppressed mid-drag so a reload
|
||||
// never yanks the edit surface.
|
||||
void onSyncTimer();
|
||||
|
||||
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
@@ -279,37 +218,31 @@ private:
|
||||
// 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.
|
||||
// Publishes the edited zones/selection to the processor, then rebuilds the instrument
|
||||
// off the audio thread. UI thread only.
|
||||
void commitAndReload();
|
||||
|
||||
// Commit `id` as the loaded single-capture selection (the Browse Load confirm and the
|
||||
// double-click accelerator both route here). Runs reconcileSingleCaptureZones first so
|
||||
// the previous sample's materialized full-range zone cannot linger and shadow the new
|
||||
// pick under first-match resolve (the zone-bleed fix, issue 3a), then publishes + reloads.
|
||||
// Commits `id` as the loaded single-capture selection. Runs reconcileSingleCaptureZones
|
||||
// first so the previous sample's materialized full-range zone cannot linger and shadow
|
||||
// the new pick under first-match resolve, then publishes + reloads.
|
||||
void loadSelection(const std::string& id);
|
||||
|
||||
// Recompute the capture cards visible under the current bank filter (samples_ narrowed by
|
||||
// activeFilterBankId_; "" = All) into visible_. Called on refresh + filter change.
|
||||
// Recomputes the visible capture cards (samples_ narrowed by activeFilterBankId_ then
|
||||
// search) 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).
|
||||
// The peak thumbnail for a bank sample id at `binCount` bins, cached by (id, binCount).
|
||||
// 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);
|
||||
|
||||
// The decoded MONO PCM for a bank sample id, decoded once from the WAV and cached by id.
|
||||
// Feeds the S11 waveform surface: the full-res envelope binned at view width AND the
|
||||
// zero-crossing snap (both need the raw frames, not the binned thumbnail). Returns an empty
|
||||
// vector when the WAV can't be resolved/decoded. UI thread only (file I/O). Reuses the same
|
||||
// decode path as thumbnailFor (no new WAV reader), keyed by id (not width — snap is width-
|
||||
// independent). Cleared with the thumbnail cache on refresh.
|
||||
// The decoded mono PCM for a bank sample id, cached by id — feeds both the binned
|
||||
// waveform envelope and the zero-crossing snap. Empty vector on decode failure. UI
|
||||
// thread only (file I/O); cleared with the thumbnail cache on refresh.
|
||||
const std::vector<AudioSample>& monoPcmFor(const std::string& sampleId);
|
||||
|
||||
// The effective loop + start markers for the picked single capture (S11): the per-zone
|
||||
// OVERRIDE for the picked id when one exists in map_, else the bank's S2 loop intrinsic
|
||||
// (loop) / frame 0 (start). Absent loop -> loopStart==loopEnd==0 (the "no loop" state).
|
||||
// frames is the decoded length (for defaulting loopEnd when the bank left the loop empty).
|
||||
// The effective loop + start markers for the picked capture: the per-zone override when
|
||||
// one exists in map_, else the bank's loop intrinsic / frame 0. Absent loop ->
|
||||
// loopStart==loopEnd==0. `frames` defaults loopEnd when the bank left the loop empty.
|
||||
struct SetupMarkers {
|
||||
std::int64_t start = 0;
|
||||
std::int64_t loopStart = 0;
|
||||
@@ -318,125 +251,93 @@ private:
|
||||
};
|
||||
SetupMarkers pickedMarkers(std::int64_t frames) const;
|
||||
|
||||
// Commit an edited marker set for the picked capture as a per-zone loop/start override
|
||||
// (upsert on the picked id — mirror of the root-marker path), then reload off-thread.
|
||||
// Commits an edited marker set for the picked capture as a per-zone loop/start override
|
||||
// (upsert on the picked id), then reloads off-thread.
|
||||
void commitPickedMarkers(const SetupMarkers& m);
|
||||
|
||||
// Write `m` as a loop/start override upsert into map_ for selectedId_ (find-or-append).
|
||||
// Does NOT call commitAndReload — callers decide whether this is a live-drag update or a
|
||||
// final commit. selectedId_ must be non-empty before calling. Returns the zone index
|
||||
// (0-based) that was updated or appended, so callers can set selectedZone_.
|
||||
// Writes `m` as a loop/start override upsert into map_ for selectedId_ (find-or-append).
|
||||
// Does NOT call commitAndReload — callers decide live-drag vs final commit. selectedId_
|
||||
// must be non-empty. Returns the updated/appended zone index.
|
||||
int upsertPickedOverride(const SetupMarkers& m);
|
||||
|
||||
// --- S12/S15/S16 parameter value domains (both deck surfaces) ------------------
|
||||
//
|
||||
// The deck knobs edit a zone's ZonePlaySeconds (S15 play mode + AHDSR; S16 pitch engine +
|
||||
// AD pitch envelope). Wall-clock times are SECONDS (rate-free); the keymap build resolves
|
||||
// them to frames at the live rate. Instrument-owned (D-B), never a bank fact.
|
||||
// Deck knobs edit a zone's ZonePlaySeconds (play mode + AHDSR; pitch engine + AD pitch
|
||||
// envelope) — wall-clock seconds, rate-free; the keymap build resolves to frames.
|
||||
|
||||
// The normalized [0,1] display value for control `id` given `play` (the shell's domain
|
||||
// mapping: seconds->0..1 over a fixed seconds ceiling, sustain 0..1 as-is, %-length/fade
|
||||
// frames->0..1, semitone depth centered at 0.5).
|
||||
// The normalized [0,1] display value for control `id` given `play` (seconds -> 0..1 over
|
||||
// a fixed ceiling, sustain 0..1 as-is, %-length/fade frames -> 0..1, semitone depth
|
||||
// centered at 0.5).
|
||||
double controlValue(int id, const ZonePlaySeconds& play) const;
|
||||
|
||||
// Apply a committed control interaction to `play`: a knob's normalized `value` (mapped back
|
||||
// into the control's stored domain) or a toggle's `segment` (0/1). Mutates `play` in place.
|
||||
// Applies a committed control interaction to `play`: a knob's normalized `value` or a
|
||||
// toggle's `segment` (0/1). Mutates `play` in place.
|
||||
void applyControl(int id, ZonePlaySeconds& play, double value, int segment) const;
|
||||
|
||||
// The Trigger fade-in/out knob full-scale, in SOURCE frames: kFadeMaxSeconds (2 s
|
||||
// wall-clock) resolved against the live rate at use (Q-W0 T3-03 — never a baked-in
|
||||
// rate). 44.1 kHz fallback before setupProcessing has run. Storage stays frames.
|
||||
// The Trigger fade-in/out knob full-scale, in source frames: kFadeMaxSeconds resolved
|
||||
// against the live rate — never a baked-in rate. 44.1 kHz fallback pre-setupProcessing.
|
||||
double fadeMaxFrames() const;
|
||||
|
||||
// --- S-VIEW-3 envelope overlay seam (frames <-> fraction converter) ----------
|
||||
//
|
||||
// envelope_overlay's AmpEnvelope is a DERIVED VIEW, not a TriggerParams copy: it stores the
|
||||
// Trigger fades as FRACTIONS of the played span, while the zone stores them as SOURCE FRAMES.
|
||||
// These two members own the non-trivial conversion on BOTH paths (documented in
|
||||
// envelope_overlay.h's TRIGGER SEAM note). `frames` is the sample's total source frame count;
|
||||
// `rate` is the live sample rate (the wall-clock AHDSR seconds are rate-free and copy 1-to-1,
|
||||
// but the Trigger played-span math needs the frame count).
|
||||
// envelope_overlay's AmpEnvelope stores Trigger fades as fractions of the played span,
|
||||
// while the zone stores source frames — pack/unpack own that conversion (see
|
||||
// envelope_overlay.h's trigger-seam note). `frames` is total source frames; AHDSR
|
||||
// seconds are rate-free and copy 1-to-1.
|
||||
|
||||
// PACK (draw): zone play params -> AmpEnvelope. Copies AHDSR seconds directly; derives the
|
||||
// Trigger fade fractions from the source-frame fades over the played span.
|
||||
// `startFrame` is the zone's effective start point (zone.startPoint.value_or(0)).
|
||||
// PACK (draw): zone play params -> AmpEnvelope. `startFrame` is the zone's effective
|
||||
// start point (zone.startPoint.value_or(0)).
|
||||
AmpEnvelope packEnvelope(const ZonePlaySeconds& play, std::int64_t frames,
|
||||
std::int64_t startFrame) const;
|
||||
|
||||
// UNPACK (commit): an edited AmpEnvelope -> the zone's play params. Copies AHDSR seconds
|
||||
// directly; converts the Trigger fade fractions back to source frames over the played span.
|
||||
// `startFrame` is the zone's effective start point (zone.startPoint.value_or(0)).
|
||||
// Mutates `play` in place; only the mode-relevant fields are written.
|
||||
// UNPACK (commit): an edited AmpEnvelope -> the zone's play params, in place.
|
||||
void unpackEnvelope(const AmpEnvelope& env, std::int64_t frames, std::int64_t startFrame,
|
||||
ZonePlaySeconds& play) const;
|
||||
|
||||
// The clamp bounds envelope_edit uses, matching the control-panel sliders' own domains (so a
|
||||
// node drag can never produce a param a slider couldn't — the S-VIEW-F2 invariant).
|
||||
// Clamp bounds envelope_edit uses, matching the sliders' own domains so a node drag can
|
||||
// never produce a param a slider couldn't.
|
||||
EnvClampBounds envClampBounds() const;
|
||||
|
||||
// --- Sample-view resolution helpers (the ONE storage site, S15-F2) -----------
|
||||
//
|
||||
// The single-capture Sample face reads/writes the same one-zone map site as the Zone surface.
|
||||
// These resolve the effective values for the picked id: effectiveSampleZone returns the picked
|
||||
// id's one-zone override (found in map_) or a product-default PerformanceZone bound to the
|
||||
// picked id (not yet materialized — a control edit materializes it, mirroring the Zone path).
|
||||
// The Sample face and the Zone surface read/write the same one-zone map site.
|
||||
// effectiveSampleZone returns the picked id's override if present in map_, else a
|
||||
// product-default zone (not yet materialized — a control edit does that).
|
||||
PerformanceZone effectiveSampleZone() const;
|
||||
// The effective root: the picked id's rootOverride, else its bank intrinsic, else middle C.
|
||||
// The effective root: rootOverride, else the bank intrinsic, else middle C.
|
||||
int effectiveRoot() const;
|
||||
// The live sample rate from the bridge (for the envelope overlay's seconds<->frames time base),
|
||||
// or 0 when unavailable (the caller guards). Matches the voice engine's resolution rate.
|
||||
// The live sample rate from the bridge, or 0 when unavailable (caller guards).
|
||||
double liveSampleRate() const;
|
||||
// The persisted preview velocity as a 0..1 slider value (MIDI 1..127 mapped onto [0,1]).
|
||||
// Persisted preview velocity as a 0..1 slider value (MIDI 1..127 -> [0,1]).
|
||||
double previewVelocity01() const;
|
||||
|
||||
// Find-or-materialize the one-zone override for the picked id and return a mutable index into
|
||||
// map_.zones (appending a product-default zone if none exists). selectedId_ must be non-empty.
|
||||
// The mirror of upsertPickedOverride for a control edit — used when a Sample-face control edit
|
||||
// needs a concrete zone to write. Returns -1 if selectedId_ is empty.
|
||||
// Find-or-materializes the one-zone override for the picked id, appending a
|
||||
// product-default zone if none exists. Mirror of upsertPickedOverride for a control
|
||||
// edit. Returns -1 if selectedId_ is empty.
|
||||
int ensureSampleZone();
|
||||
|
||||
// --- Curve-popup target resolution (r11 FB1 + FB2) -----------------------------
|
||||
//
|
||||
// The popup edits ONE zone per open: the Zone surface's SELECTED zone (FB2) or the Sample
|
||||
// face's picked one-zone site. popupZone is the read-only resolve (paint/hover/right-click
|
||||
// hit-test); popupZoneIndex is the edit target — it materializes the Sample-face zone via
|
||||
// ensureSampleZone but NEVER materializes on the Zone surface (the button only shows for
|
||||
// an explicit selection). Returns -1 when there is no valid target (callers guard).
|
||||
// The popup edits ONE zone per open: the Zone surface's selected zone or the Sample
|
||||
// face's picked site. popupZone is the read-only resolve; popupZoneIndex is the edit
|
||||
// target — materializes on the Sample face via ensureSampleZone, never on the Zone
|
||||
// surface (button only shows for an explicit selection). -1 = no valid target.
|
||||
PerformanceZone popupZone() const;
|
||||
int popupZoneIndex();
|
||||
|
||||
// --- r11 knob-deck plumbing (FB1 Sample face; FB2 Zone panel) -------------------
|
||||
//
|
||||
// The deck is the r11 replacement for the slider control strips on BOTH surfaces: the pure
|
||||
// knob_deck module lays out the fenced groups, param_slider's FA4 primitive owns the
|
||||
// value<->needle map, and these members own the control-id <-> value binding.
|
||||
|
||||
// The PER-ZONE deck groups (FB2 — the set both surfaces share): AMP ENVELOPE (Gate:
|
||||
// A/H/D/S/R; Trigger: Fade In / Length % / Fade Out + two RESERVED blanks so a mode flip
|
||||
// never reflows the neighbours) / PITCH (Key Track) / PITCH ENV (P.Attack/P.Decay/P.Depth).
|
||||
// The Zone panel renders exactly these — per-instance state stays off it.
|
||||
// The per-zone deck groups both surfaces share: AMP ENVELOPE (Gate A/H/D/S/R; Trigger
|
||||
// Fade In/Length %/Fade Out + two reserved blanks so a mode flip never reflows
|
||||
// neighbours) / PITCH (Key Track) / PITCH ENV (P.Attack/P.Decay/P.Depth).
|
||||
std::vector<DeckGroupDesc> zoneDeckGroupDescs(const ZonePlaySeconds& play) const;
|
||||
|
||||
// The full Sample-face deck: the shared per-zone groups + the per-instance VOICE (Voices
|
||||
// knob + Poly|Mono caption toggle + Retrig|Legato row toggle) and MASTER (the FB1
|
||||
// post-mixer Gain knob) groups.
|
||||
// The full Sample-face deck: the shared groups + the per-instance VOICE (Voices knob +
|
||||
// Poly|Mono + Retrig|Legato) and MASTER (Gain knob) groups.
|
||||
std::vector<DeckGroupDesc> deckGroupDescs(const ZonePlaySeconds& play) const;
|
||||
|
||||
// The normalized [0,1] value a deck knob shows for `zone` — zone params route through
|
||||
// controlValue/keyTrack; the processor-side ids (voice count, master gain, and the
|
||||
// cluster's preview velocity via the -2 sentinel) read the processor's live value, so
|
||||
// the knob and its storage are two views on one model (re-read each paint).
|
||||
// controlValue/keyTrack; processor-side ids (voice count, master gain, preview velocity
|
||||
// via the -2 sentinel) read the processor's live value.
|
||||
double deckControlNorm(int id, const PerformanceZone& zone) const;
|
||||
|
||||
// Apply a deck-knob value: zone params write map_.zones[zoneIndex] (live-drag semantics,
|
||||
// commit on release); processor params (voice count / master gain / preview velocity)
|
||||
// write through the processor setters immediately (transient — no map edit, no reload).
|
||||
// zoneIndex is ignored for processor-side ids.
|
||||
// Applies a deck-knob value: zone params write map_.zones[zoneIndex] (commit on
|
||||
// release); processor params write through the processor setters immediately
|
||||
// (transient — no map edit, no reload). zoneIndex ignored for processor-side ids.
|
||||
void applyDeckKnob(int zoneIndex, int id, double norm);
|
||||
|
||||
// The knob's live value label (shown in place of the name label during hover/drag):
|
||||
// seconds ("0.123s"), percents ("85%"), source frames ("8820f"), signed semitones
|
||||
// ("+3.5st"), a voice count ("16"), or the master-gain dB ("-inf"/"+2.4dB").
|
||||
// The knob's live value label shown during hover/drag: seconds, percents, source
|
||||
// frames, signed semitones, a voice count, or the master-gain dB.
|
||||
std::string deckValueLabel(int id, const PerformanceZone& zone) const;
|
||||
|
||||
ReaSamplerProcessor* processor_ = nullptr;
|
||||
@@ -447,64 +348,51 @@ private:
|
||||
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
|
||||
ChannelMode channelMode_ = ChannelMode::Mono; // mono/stereo toggle snapshot
|
||||
|
||||
// --- Phase S voice-deck snapshot (PROVISIONAL controls — the Wave B recompose owns the
|
||||
// final deck). Mirrors of the processor's persisted voice-system params, refreshed with
|
||||
// the rest of the live snapshot; every edit writes through the processor setters (which
|
||||
// rebuild the engine off-thread via the drain-slot swap).
|
||||
// Mirrors of the processor's persisted voice-system params, refreshed with the rest of the
|
||||
// live snapshot; every edit writes through the processor setters (which rebuild the engine
|
||||
// off-thread via the drain-slot swap).
|
||||
int voiceCount_ = kDefaultVoiceCount;
|
||||
VoiceMode voiceMode_ = VoiceMode::Poly;
|
||||
MonoTrigger monoTrigger_ = MonoTrigger::Retrigger;
|
||||
|
||||
// --- Transient UI state (not persisted; component state carries selection + zones) ---
|
||||
View view_ = View::kSample; // default face is the loaded-sample home (S-VIEW-1)
|
||||
// Transient UI state (not persisted; component state carries selection + zones).
|
||||
View view_ = View::kSample; // default face is the loaded-sample home
|
||||
std::string activeFilterBankId_; // "" = All; else a bank id from banks_
|
||||
int selectedZone_ = -1; // highlighted zone in the Zone surface; -1 = none
|
||||
|
||||
// --- S-VIEW-5 Browse modal picker (a selection PENDING confirm) ---------------
|
||||
// The Browse overlay is a select-then-confirm picker: a click marks a pending pick without
|
||||
// loading it; Confirm (or double-click) commits it to selectedId_ + reloads and returns to
|
||||
// Sample; Cancel discards it and returns to Sample unchanged. "" = nothing picked yet.
|
||||
// The Browse overlay is a select-then-confirm picker: a click marks a pending pick;
|
||||
// Confirm/double-click commits it + reloads; Cancel discards it. "" = nothing picked.
|
||||
std::string browsePendingId_;
|
||||
int lastBrowseClickCard_ = -1; // for double-click-to-load detection (visible_ index)
|
||||
|
||||
// --- S-VIEW-4 preview-trigger note (transient) -------------------------------
|
||||
// The MIDI note the preview button is currently sounding (a held Gate voice), or -1 when the
|
||||
// button is up. Set on preview-button press (note-on posted to the processor), cleared on
|
||||
// release (note-off posted). One note at a time — a fresh press releases the prior.
|
||||
// The MIDI note the preview button is currently sounding (held Gate voice), or -1 when
|
||||
// up. One note at a time — a fresh press releases the prior.
|
||||
int previewingNote_ = -1;
|
||||
|
||||
// --- S13 drop-to-load affordance (relay DEGRADED — transient, never persisted) ----
|
||||
// S13's cross-artifact ingest relay (editor drop -> extension ingest) is NOT shipped: the
|
||||
// instrument's REAPER bridge is deliberately READ-ONLY (it never writes the bank / ext
|
||||
// state), so an editor drop cannot relay a bank-ingest request without a new write seam +
|
||||
// an extension-side poller (surfaced as a decision, not crossed here). The DEGRADE path per
|
||||
// the spec: the editor ACCEPTS the drop (WM_DROPFILES) and, rather than silently swallowing
|
||||
// it, flashes a clear affordance pointing at the shipped ingest gesture (drop onto the
|
||||
// docked ReaSampler panel). When > 0, the affordance banner is shown; each sync tick decays
|
||||
// it so it auto-dismisses. No file is ingested, no timeline item is ever inserted.
|
||||
// The editor-drop -> extension-ingest relay is not shipped (the bridge is read-only):
|
||||
// an OS drop just flashes a "drop on the panel instead" banner (dropHintTicks_ counts
|
||||
// down via the sync tick). Never ingests, never inserts a timeline item.
|
||||
int dropHintTicks_ = 0; // remaining sync ticks to show the drop affordance
|
||||
|
||||
// --- S12 browser scroll + search (transient UI state, never persisted) --------
|
||||
// Browser scroll + search (transient UI state, never persisted).
|
||||
int scrollOffset_ = 0; // vertical px offset into the card grid (clamped)
|
||||
std::string searchQuery_; // type-to-filter narrow; "" = no search
|
||||
bool searchFocused_ = false; // whether the search box has keyboard focus
|
||||
|
||||
// --- S12 numeric note entry (LICE text-entry idiom, transient) ----------------
|
||||
// When >= 0, a low/high/root field is being typed; entryText_ accumulates the keystrokes
|
||||
// and commits (parseNoteEntry) on Enter. -1 = no field editing. The field id is a
|
||||
// ParamControl-independent small enum encoded inline (see the .cpp: 0=low,1=high,2=root).
|
||||
// When >= 0, a low/high/root field is being typed (0=low,1=high,2=root); entryText_
|
||||
// accumulates keystrokes and commits via parseNoteEntry on Enter. -1 = no field editing.
|
||||
int entryField_ = -1;
|
||||
std::string entryText_;
|
||||
|
||||
// --- Hover state (Phase L, L3; transient, never persisted) --------------------
|
||||
// Hover state (transient, never persisted).
|
||||
HoverTarget hover_; // the interactive element under the pointer
|
||||
#ifdef _WIN32
|
||||
bool mouseTracking_ = false; // TrackMouseEvent armed for WM_MOUSELEAVE this "over" cycle
|
||||
#endif
|
||||
|
||||
// --- Drag-state machine ------------------------------------------------------
|
||||
// Drag-state machine.
|
||||
DragKind drag_ = DragKind::kNone;
|
||||
int dragStartX_ = 0; // grab x (px), for the pixel-delta resolver
|
||||
int dragStartY_ = 0; // grab y (px), for the vertical scrollbar-thumb drag
|
||||
@@ -515,54 +403,46 @@ private:
|
||||
int dragStartRoot_ = 60;
|
||||
PerformanceMap dragStartMap_; // map_ snapshotted at grab; restored on capture-loss
|
||||
|
||||
// S11 waveform-marker drag: which marker + the marker set snapshotted at grab time (so the
|
||||
// pixel-delta resolver shifts the grabbed frame from its grab-time value, and inter-marker
|
||||
// clamps use the sibling markers).
|
||||
// Waveform-marker drag: which marker + the marker set snapshotted at grab time, so the
|
||||
// pixel-delta resolver shifts from the grab-time value and inter-marker clamps use the
|
||||
// sibling markers.
|
||||
WaveMarker waveMarker_ = WaveMarker::kStart;
|
||||
SetupMarkers dragStartMarkers_;
|
||||
std::int64_t dragSampleFrames_ = 0; // decoded length of the sample under the drag
|
||||
std::int64_t dragStartFrame_ = 0; // zone startPoint at grab time (0 if absent); for env-node drag
|
||||
|
||||
// S12 scrollbar-thumb drag: the offset held at grab time (the pixel-delta resolver shifts
|
||||
// from it). kDeckKnob drag: which control id + the zone it edits.
|
||||
// Scrollbar-thumb drag: the offset at grab time. kDeckKnob drag: which control id + zone.
|
||||
int dragStartScrollOffset_ = 0;
|
||||
int dragParamId_ = -1; // control id under a kDeckKnob drag; -2 = preview-vel knob
|
||||
int dragParamZone_ = -1; // the zone index a kDeckKnob drag edits; -1 = processor-side
|
||||
|
||||
// S-VIEW-3 envelope-node drag: which node is grabbed + the AmpEnvelope snapshotted at grab
|
||||
// (so the pixel delta is absolute, per envelope_edit's grabEnv contract). The overlay rect +
|
||||
// sample frame count are re-derived at move time from the live Sample-view layout.
|
||||
// Envelope-node drag: which node + the AmpEnvelope snapshotted at grab (absolute-delta
|
||||
// contract, per envelope_edit's grabEnv).
|
||||
EnvNode envNode_ = EnvNode::Origin;
|
||||
AmpEnvelope dragStartEnv_{};
|
||||
|
||||
// S-VIEW-10 velocity-curve node drag: which point is grabbed, the curve snapshotted at grab
|
||||
// (resolvePointDrag's absolute-delta contract), the box rect the grab happened in (the Sample
|
||||
// and Zone views place the editor differently — the drag resolves against the grab-time box),
|
||||
// and which zone the edit lands on. Mirror of the envelope-node drag state.
|
||||
// Velocity-curve node drag: which point, the curve snapshotted at grab
|
||||
// (resolvePointDrag's absolute-delta contract), the grab-time box rect (Sample and Zone
|
||||
// place the editor differently), and which zone the edit lands on.
|
||||
int curvePointIndex_ = -1;
|
||||
VelocityCurve dragStartCurve_ = VelocityCurve::flat();
|
||||
Rect dragCurveRect_{};
|
||||
int dragCurveZone_ = -1;
|
||||
|
||||
// r11 deck-knob drag (FB1): the control's normalized value AT GRAB — knobDragValue maps
|
||||
// the vertical pixel delta from this anchor, so a grab never jumps the value (FA4).
|
||||
// Deck-knob drag: the normalized value at grab — knobDragValue maps the vertical pixel
|
||||
// delta from this anchor, so a grab never jumps the value.
|
||||
double dragKnobStartValue_ = 0.0;
|
||||
|
||||
// r11 curve popup (FB1 + FB2): open flag — editor-local, never persisted. The popup edits
|
||||
// popupZone() — the picked capture's one-zone site on the Sample face, the SELECTED zone
|
||||
// on the Zone surface — re-resolved each paint so a sync-tick refresh mid-open stays
|
||||
// coherent (a refresh that drops the target closes it; see refreshFromBank).
|
||||
// Curve popup open flag, never persisted. Edits popupZone(), re-resolved each paint so a
|
||||
// sync-tick refresh mid-open stays coherent (a refresh that drops the target closes it).
|
||||
bool curvePopupOpen_ = false;
|
||||
|
||||
// --- 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.
|
||||
// Peak-thumbnail cache (mirror of bank_panel), keyed by "id|binCount" so a resize
|
||||
// recomputes at the new width. Cleared on refresh so a stale sample never shows.
|
||||
std::unordered_map<std::string, Envelope> thumbCache_;
|
||||
|
||||
// --- Decoded mono-PCM cache (S11; id -> full-res frames) ------------------------------
|
||||
// Keyed by id (width-independent, unlike thumbCache_). Feeds the waveform envelope binning
|
||||
// + the zero-crossing snap. Cleared alongside thumbCache_ on refresh so a re-captured or
|
||||
// deleted sample does not show/snap against stale PCM.
|
||||
// Decoded mono-PCM cache, keyed by id (width-independent). Feeds the waveform envelope
|
||||
// binning + zero-crossing snap. Cleared alongside thumbCache_ on refresh.
|
||||
std::unordered_map<std::string, std::vector<AudioSample>> pcmCache_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user