fix: close review findings on the velocity-curve deck and bipolar curves
Cancels the curve-node drag whenever the popup closes so Esc mid-drag can't alias the amp curve; generalizes CurveTarget routing to one switch; fixes stale/overstated comments; clamps a pre-v12 depth fold; adds deck-inertness and filter-fold test coverage.
This commit is contained in:
@@ -25,8 +25,10 @@ enum class CurveDomain { Unipolar, Bipolar };
|
||||
|
||||
constexpr double curveYMin(CurveDomain d) { return d == CurveDomain::Bipolar ? -1.0 : 0.0; }
|
||||
|
||||
// The value that changes nothing in each domain — unity gain, or zero modulation. Every
|
||||
// defensive fallback lands here so a corrupt blob loses the shaping rather than inventing one.
|
||||
// The value that changes nothing in each domain — unity gain, or zero modulation. THE one home
|
||||
// for that value: eval()'s own empty-curve fallback reads it directly, and flat()/zero() (what
|
||||
// fromPoints' sub-2-point fallback constructs) are built from it too, so a corrupt blob always
|
||||
// loses the shaping rather than inventing one, however the fallback is reached.
|
||||
constexpr double curveNeutral(CurveDomain d) { return d == CurveDomain::Bipolar ? 0.0 : 1.0; }
|
||||
|
||||
// A raw-constructed point is NOT auto-clamped (the mutators own that invariant) — build curves
|
||||
@@ -45,7 +47,10 @@ inline constexpr int kCurveNodeGrabRadius = 6;
|
||||
// slope, so the spline reproduces linear()'s straight line to within ~1e-15. The two endpoints
|
||||
// (velocity 0 and 127) are load-bearing: they keep eval total over the domain and are never
|
||||
// deletable. eval is HOMOGENEOUS in y — scaling every knot's value by k scales the whole curve
|
||||
// by k exactly, which is what lets the codec fold a retired depth control into stored knots.
|
||||
// by k TO WITHIN DOUBLE ROUNDING (the Hermite basis and the Fritsch-Carlson tangent are exactly
|
||||
// degree-1 homogeneous in real arithmetic; `fl(k*b) - fl(k*a)` isn't bit-identical to
|
||||
// `k*(b-a)`), which is what lets the codec (component_state_io.h's v12 pre-lift) fold a retired
|
||||
// depth control into stored knots and still sound identical.
|
||||
class VelocityCurve {
|
||||
public:
|
||||
// flat() (endpoints (0,1)/(127,1), every velocity -> unity) is the unipolar default — see
|
||||
@@ -117,6 +122,12 @@ public:
|
||||
bool equals(const VelocityCurve& other, double eps = 1e-9) const;
|
||||
|
||||
private:
|
||||
// Private: an implicit-default curve is empty (no endpoints) and Unipolar, so a stray
|
||||
// default-construction wouldn't fail loudly — it would eval() to unity gain everywhere,
|
||||
// or a full +/-1 (a full-scale transpose / wide-open filter) if ever read as bipolar. Build
|
||||
// through flat()/linear()/zero()/fromPoints(), all of which establish the endpoint invariant.
|
||||
VelocityCurve() = default;
|
||||
|
||||
// Always X-ordered with an endpoint at 0 and 127; constructors + deserialize establish the
|
||||
// invariant, mutators preserve it.
|
||||
std::vector<VelocityPoint> points_;
|
||||
|
||||
Reference in New Issue
Block a user