S-VIEW-10: velocity-curve editor UI — draggable spline box beside the Sample hero + in the Zone panel, all math through the pure velocity_curve module

This commit is contained in:
2026-07-27 15:51:36 -04:00
parent c92d82df3a
commit 0e8b1b72cf
5 changed files with 356 additions and 15 deletions
+25 -2
View File
@@ -36,6 +36,7 @@
#include "param_slider.h" // ControlRow (the S12/S15/S16 control-surface geometry)
#include "peaks.h" // Envelope (the cached peak thumbnail)
#include "sample_map.h" // SampleChoice, BankChoice, PerformanceMap (the shell's snapshot)
#include "velocity_curve.h" // VelocityCurve (S-VIEW-10 transfer-curve editor state)
#ifdef _WIN32
#include <windows.h>
@@ -78,9 +79,10 @@ private:
// 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_).
// envNode_); kCurveNode is a draggable velocity-curve control point in the S-VIEW-10
// transfer-curve editor (which point in curvePointIndex_).
enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody, kWaveMarker,
kScrollThumb, kParamSlider, kEnvNode };
kScrollThumb, kParamSlider, kEnvNode, kCurveNode };
// The parameter controls on the setup surface (S12 AHDSR + the S15/S16 control surfaces).
// The int value is the ControlDesc id the pure param_slider hit-test returns; the shell
@@ -133,6 +135,7 @@ private:
kAddZone, // the "+ Add Zone" button
kDeleteZone, // the "Delete" zone button
kControl, // a param-panel control row (index = ControlDesc id)
kCurveNode, // a velocity-curve control point (index = point index, S-VIEW-10)
};
struct HoverTarget {
HoverKind kind = HoverKind::kNone;
@@ -152,6 +155,17 @@ private:
// `zone`'s play params, at the sample's wall-clock duration. Shared by the Sample hero band.
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. Shared by the Sample face (beside the hero) and the Zone param panel; all mapping /
// hit-test / clamp math lives in the pure velocity_curve module. `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).
void handleCurveMouseDown(const Rect& r, int zoneIndex, int x, int y);
void onMouseDown(int x, int y);
void onMouseMove(int x, int y);
@@ -405,6 +419,15 @@ private:
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.
int curvePointIndex_ = -1;
VelocityCurve dragStartCurve_ = VelocityCurve::flat();
Rect dragCurveRect_{};
int dragCurveZone_ = -1;
// --- 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.