vst: curve velocity_curve eval with a monotone cubic Hermite (Fritsch-Carlson) spline
True curved response, provably no overshoot outside [0,1]; collinear knots reproduce the exact linear ramp so linear()'s null-response stays bit-exact. Eval-only; v7 wire-format untouched. Adds spline tests.
This commit is contained in:
@@ -59,11 +59,13 @@ struct VelocityPoint {
|
||||
inline constexpr int kCurveNodeGrabRadius = 6;
|
||||
|
||||
// A velocity->amp transfer curve: an X-ORDERED list of control points spanning [0,127], evaluated by
|
||||
// LINEAR interpolation between adjacent points (a monotonic polyline: each velocity maps to exactly
|
||||
// one amp). Linear-between-knots is deliberate — it makes linear() an EXACT straight line y =
|
||||
// velocity/127 (the Option-B / null-response contract) and keeps monotonicity trivial; the "curved"
|
||||
// shape a sound wants comes from placing more control points, not from bending one segment. The two
|
||||
// endpoints (velocity 0 and 127) are load-bearing: they keep eval total and are never deletable.
|
||||
// a MONOTONE cubic Hermite spline (Fritsch–Carlson slope limiting) through the knots — a genuine
|
||||
// curved response (Daniel 2026-07-27: "straight lines sound like shit"), not a polyline. Each
|
||||
// velocity still maps to exactly one amp: the interpolant is single-valued and provably stays within
|
||||
// each segment's amp range, so the curve never overshoots below 0 or above 1. For COLLINEAR knots the
|
||||
// Fritsch–Carlson tangents reduce to the secant slope, so the spline IS the straight line — that
|
||||
// keeps linear() an EXACT y = velocity/127 (the Option-B / null-response contract). The two endpoints
|
||||
// (velocity 0 and 127) are load-bearing: they keep eval total and are never deletable.
|
||||
class VelocityCurve {
|
||||
public:
|
||||
// R10-F1 default (Option A): flat y=1 — endpoints (0,1) and (127,1); every velocity -> unity.
|
||||
@@ -86,8 +88,11 @@ public:
|
||||
|
||||
// Evaluate the curve at `velocity` -> amp in [0,1]. Velocity is box-clamped to [0,127] first,
|
||||
// so an out-of-range note (shouldn't occur) reads the nearest endpoint. Between two adjacent
|
||||
// points the amp interpolates LINEARLY across the normalized X position — monotonic in X. A
|
||||
// degenerate curve (0 or 1 point, shouldn't occur post-construction) returns kAmpMax (flat).
|
||||
// points the amp follows a MONOTONE cubic Hermite spline (Fritsch–Carlson slope limiting) — a
|
||||
// true curve that provably stays within the two knots' amp range (no overshoot below 0 / above
|
||||
// 1) and reduces to the exact straight line for collinear knots. Single-valued / monotonic in X.
|
||||
// Degenerate cases (shouldn't occur post-construction): an EMPTY curve returns kAmpMax (flat
|
||||
// unity); a ONE-point curve returns that point's amp.
|
||||
double eval(double velocity) const;
|
||||
|
||||
// --- Editing (for the S-VIEW-10 editor UI) --------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user