Γ-W1-T1 review fixes: mode-independent taper rounding, sharper drag-step test, reset-sweep verifies stored fields
Swap nearbyint for std::round (MXCSR-independent); derive the finest-drag test from the editor floor, not the knob; verify resets against fields, not norms; record the spline-point modifier exclusion.
This commit is contained in:
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "../src/core/instrument/ui/param_taper.h"
|
||||
|
||||
#include "../src/core/instrument/ui/envelope_overlay.h" // gateStageSlotPx: finest drag surface
|
||||
#include "../src/core/instrument/ui/sample_bands.h" // kEditorMinWidth/kPad: the editor floor
|
||||
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
@@ -78,10 +82,15 @@ static void testStageTimeIsMonotone() {
|
||||
}
|
||||
}
|
||||
|
||||
// The FINEST drag a user can make — Ctrl's 1/20 rate over the 128 px knob travel — must still
|
||||
// move the value, or the output quantum would be observable as a dead zone.
|
||||
// The FINEST drag a user can make on ANY surface this taper serves — not the knob's own 128 px
|
||||
// travel, which is coarser than the AHDSR schematic's node drag at the editor floor. Derived from
|
||||
// the floor constant and the overlay's own slot-width formula, so a later floor change sharpens
|
||||
// (or coarsens) the step this test exercises automatically instead of leaving a copied number
|
||||
// silently stale.
|
||||
static void testEveryFinestDragStepMovesTheValue() {
|
||||
const int steps = static_cast<int>(1.0 / kFineDragScale) * 128;
|
||||
const Rect floorArea = Rect::ltrb(0, 0, kEditorMinWidth - 2 * kPad, 100);
|
||||
const double slot = gateStageSlotPx(floorArea);
|
||||
const int steps = static_cast<int>(slot / kFineDragScale);
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
const double lo = timeSecondsFromNorm(static_cast<double>(i) / steps);
|
||||
const double hi = timeSecondsFromNorm(static_cast<double>(i + 1) / steps);
|
||||
@@ -108,6 +117,32 @@ static void testEveryWholeMicrosecondRoundTripsExactly() {
|
||||
}
|
||||
}
|
||||
|
||||
// MODE-INDEPENDENCE, the whole point of resolveTo's std::round over std::nearbyint. First shows
|
||||
// the defect directly, generically: under round-toward-zero, the RETIRED std::nearbyint reads
|
||||
// that mode and truncates a value whose fraction is well past half, while std::round (specified
|
||||
// to round half-away-from-zero REGARDLESS of the current mode) does not. Then proves the
|
||||
// production round trip itself — not a stand-in — survives the same hostile mode across the grid.
|
||||
static void testRoundingSurvivesAHostileFpRoundingMode() {
|
||||
const int saved = std::fegetround();
|
||||
CHECK(std::fesetround(FE_TOWARDZERO) == 0);
|
||||
|
||||
CHECK(std::nearbyint(12.9) == 12.0); // the RETIRED behaviour: mode-dependent, wrong here
|
||||
CHECK(std::round(12.9) == 13.0); // the fix: mode-independent, rounds to nearest
|
||||
|
||||
for (int us = 0; us <= 200000; us += 7) {
|
||||
const double seconds = static_cast<double>(us) / 1e6;
|
||||
CHECK(timeSecondsFromNorm(timeNormFromSeconds(seconds)) == seconds);
|
||||
if (timeSecondsFromNorm(timeNormFromSeconds(seconds)) != seconds) break;
|
||||
}
|
||||
for (int milli = -24000; milli <= 24000; milli += 37) {
|
||||
const double d = static_cast<double>(milli) / 1000.0;
|
||||
CHECK(depthSemitonesFromNorm(depthNormFromSemitones(d, kDepth), kDepth) == d);
|
||||
if (depthSemitonesFromNorm(depthNormFromSemitones(d, kDepth), kDepth) != d) break;
|
||||
}
|
||||
|
||||
std::fesetround(saved); // restore — every other test in this binary assumes the default
|
||||
}
|
||||
|
||||
// The converse round trip is NOT required, but its residual is worth pinning: it is bounded by
|
||||
// the output quantum read back through the map, which stays four orders below one drag pixel.
|
||||
// Pinned so a future quantum change cannot make the needle visibly lag the hand unnoticed.
|
||||
@@ -239,6 +274,7 @@ int main() {
|
||||
testStageTimeIsMonotone();
|
||||
testEveryFinestDragStepMovesTheValue();
|
||||
testEveryWholeMicrosecondRoundTripsExactly();
|
||||
testRoundingSurvivesAHostileFpRoundingMode();
|
||||
testNormRoundTripResidualStaysBelowOneDragPixel();
|
||||
testTheStageTimeDefaultsRoundTripExactly();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user