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:
@@ -90,18 +90,21 @@ namespace reasampler::instrument::map {
|
||||
// prefix and lifts to 0 — the hard seam it always played.
|
||||
//
|
||||
// v12 (CURRENT WRITE FORMAT) is v11 PLUS the velocity->PITCH transfer curve (count + points,
|
||||
// the same shape as v7's), appended after the loop crossfade. It also RE-INTERPRETS two frozen
|
||||
// slots inside the v9 filter tail — the byte shape is untouched, only the meaning at v12+:
|
||||
// the same shape as v7's), appended after the loop crossfade. Its y is a normalized fraction
|
||||
// of kVelocityPitchRangeSemitones (play_params.h) — a full-scale constant that lives OUTSIDE
|
||||
// this frozen ladder, so retuning it re-tunes every saved v12 project's pitch-curve throw. It
|
||||
// also RE-INTERPRETS two frozen slots inside the v9 filter tail — the byte shape is untouched,
|
||||
// only the meaning at v12+:
|
||||
// * the filter's velocity curve is now BIPOLAR [-1,+1] and is the whole velocity->cutoff
|
||||
// amount, not a [0,1] shape scaled by a separate depth;
|
||||
// * the retired filter velAmount slot is written as a constant 1.0 and ignored on read.
|
||||
// PRE-v12 LIFT: the stored [0,1] filter curve has every knot's y multiplied by that blob's
|
||||
// velAmount and is re-read as bipolar. eval is homogeneous in y, so the lifted curve evaluates
|
||||
// to exactly velAmount * oldCurve(v) — the product the voice used to compute per note — and a
|
||||
// pre-v12 project sounds identical. A pre-v12 blob carries no pitch curve at all and lifts to
|
||||
// the bipolar flat-at-zero default, which transposes nothing. A DOWNGRADE to a pre-v12 binary
|
||||
// reads the constant 1.0 depth against a curve whose negative half clamps away, so it
|
||||
// reproduces the curve's positive half only.
|
||||
// velAmount and is re-read as bipolar. eval is homogeneous in y to within double rounding (see
|
||||
// velocity_curve.h), so the lifted curve evaluates to velAmount * oldCurve(v) — the product the
|
||||
// voice used to compute per note — and a pre-v12 project sounds identical. A pre-v12 blob
|
||||
// carries no pitch curve at all and lifts to the bipolar flat-at-zero default, which transposes
|
||||
// nothing. A DOWNGRADE to a pre-v12 binary reads the constant 1.0 depth against a curve whose
|
||||
// negative half clamps away, so it reproduces the curve's positive half only.
|
||||
//
|
||||
// The two int64 slots the v5 play tail spends on the RETIRED Trigger fade pair are frozen in
|
||||
// shape and still read: a pre-v10 blob's fade-in/fade-out become the Trigger AHD that replaced
|
||||
|
||||
@@ -140,8 +140,13 @@ void readFilterTail(ByteReader& r, InstrumentParams& p, bool preVelocityVersion)
|
||||
f.env.decaySeconds = bitsToDouble(r.u64());
|
||||
f.env.sustainLevel = bitsToDouble(r.u64());
|
||||
f.env.releaseSeconds = bitsToDouble(r.u64());
|
||||
// velAmount feeds a MULTIPLIER on the stored curve's knots (below), not a param the engine
|
||||
// clamps on its own — the UI never dials it outside [-1,1] (deckBipolarFromNorm), so a
|
||||
// corrupt-but-finite blob value outside that range must clamp here rather than silently
|
||||
// scaling the lifted curve past what fromPoints' own [-1,1] box-clamp would then truncate.
|
||||
const double velFold =
|
||||
preVelocityVersion ? (std::isfinite(velAmount) ? velAmount : 0.0) : 1.0;
|
||||
preVelocityVersion ? std::clamp(std::isfinite(velAmount) ? velAmount : 0.0, -1.0, 1.0)
|
||||
: 1.0;
|
||||
readCurveTail(r, f.velocityCurve, reasampler::instrument::engine::CurveDomain::Bipolar,
|
||||
velFold);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user