instrument: fix AHD DecayEnd overlay/grab defect, pin flaky curve test, close comment/doc findings
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
// pixel delta produces exactly the param a knob would have.
|
||||
//
|
||||
// Covers: nodeAtPoint (every drawn handle grabbable, the anchored ReleaseEnd and the Origin
|
||||
// never grabbed, other-kind nodes rejected, misses outside the radius); resolveNodeDrag
|
||||
// never grabbed, other-kind nodes rejected, misses outside the radius, a dead coincident AHD
|
||||
// DecayEnd excluded while a functional one stays grabbable); resolveNodeDrag
|
||||
// (AHDSR stage times at the schematic scale, the sustain level on Y, the release dragged from
|
||||
// its START with the inverted sign, the caller's clamp domain, AHD stage times at the 1:1
|
||||
// scale, the hold FRACTION); curve-knot drags (the exponent domain, its endpoints, and the
|
||||
@@ -47,6 +48,18 @@ static StageEnvelope ahdsrEnv() {
|
||||
return e;
|
||||
}
|
||||
|
||||
// F1's coincidence cases need attack/decay/fraction/span combinations ahdEnv() doesn't cover.
|
||||
static StageEnvelope ahd(double a, double d, double frac, double origin, double span) {
|
||||
StageEnvelope e;
|
||||
e.kind = EnvKind::Ahd;
|
||||
e.attackSeconds = a;
|
||||
e.decaySeconds = d;
|
||||
e.holdFraction = frac;
|
||||
e.originSeconds = origin;
|
||||
e.spanSeconds = span;
|
||||
return e;
|
||||
}
|
||||
|
||||
static StageEnvelope ahdEnv() {
|
||||
StageEnvelope e;
|
||||
e.kind = EnvKind::Ahd;
|
||||
@@ -117,6 +130,26 @@ static void testAhdHasNoSustainNodes() {
|
||||
CHECK(out.attackSeconds == e.attackSeconds);
|
||||
}
|
||||
|
||||
// F1: at the Trigger default (decay 0, holdFraction 1.0) DecayEnd sits on HoldEnd's own instant
|
||||
// AND cannot move there (resolveNodeDrag's decay branch has derivative 0 — see the denom guard).
|
||||
// A grab at its true (now un-nudged) position must miss rather than resolve to a dead handle;
|
||||
// HoldEnd, the live node underneath, stays fully grabbable.
|
||||
static void testDeadCoincidentDecayEndIsNotGrabbable() {
|
||||
const StageEnvelope e = ahd(0.5, 0.0, 1.0, 0.0, 3.0);
|
||||
CHECK(!grabAt(e, EnvNode::DecayEnd).hit);
|
||||
CHECK(grabAt(e, EnvNode::HoldEnd).hit);
|
||||
CHECK(grabAt(e, EnvNode::HoldEnd).node == EnvNode::HoldEnd);
|
||||
}
|
||||
|
||||
// Coincidence alone does not drop DecayEnd — only holdFraction == 1.0 makes it truly dead. With
|
||||
// holdFraction < 1 the X-drag still moves decaySeconds (denom > 0), so it stays grabbable even
|
||||
// when decay is 0 and it starts out coincident with HoldEnd.
|
||||
static void testFunctionalCoincidentDecayEndStaysGrabbable() {
|
||||
const StageEnvelope e = ahd(0.5, 0.0, 0.5, 0.0, 3.0);
|
||||
CHECK(grabAt(e, EnvNode::DecayEnd).hit);
|
||||
CHECK(grabAt(e, EnvNode::DecayEnd).node == EnvNode::DecayEnd);
|
||||
}
|
||||
|
||||
static void testMissOutsideTheRadius() {
|
||||
const StageEnvelope e = ahdsrEnv();
|
||||
const Rect a = wideArea();
|
||||
@@ -310,6 +343,8 @@ int main() {
|
||||
testEveryDrawnHandleIsGrabbable();
|
||||
testAnchoredEndAndOriginAreNotGrabbable();
|
||||
testAhdHasNoSustainNodes();
|
||||
testDeadCoincidentDecayEndIsNotGrabbable();
|
||||
testFunctionalCoincidentDecayEndStaysGrabbable();
|
||||
testMissOutsideTheRadius();
|
||||
|
||||
testAhdsrStageTimesTrackTheSchematicScale();
|
||||
|
||||
Reference in New Issue
Block a user