Close derived-bake-window review findings: NaN-guard remaining wire doubles, pin Trigger-span agreement, retire dead quantizer

Guards params_payload.cpp's filter-tail seconds and both keyTrack sites against NaN; pins Voice::start's Trigger-span formula against trigger_seam; retires unused shortestDivisionAtLeast.
This commit is contained in:
2026-08-01 21:32:05 -04:00
parent 65f6070348
commit eb6093e085
7 changed files with 84 additions and 92 deletions
+34 -3
View File
@@ -954,25 +954,41 @@ static void testV13HardFlagCountThatStrandsAlignmentLeavesTheHoldAbsentNotFabric
// Numeric domains are established at the DOOR, not at each consumer. A NaN pitch depth reaches
// the bake's pow() and the voice's ratio multiply; a NaN %-length and a NaN stage time reach
// narrowing casts that are undefined on one; and a root override outside MIDI range makes the
// narrowing casts that are undefined on one; a NaN keyTrack reaches keyTrackedRatio ->
// baseRatio_ -> readPos_'s per-sample static_cast<std::int64_t> (voice.h); a NaN v9 filter
// env second reaches secToFrames the same way the trigAhd/filter.trigEnv pair already covered
// by testNonFiniteAhdSecondsLiftToZero do; and a root override outside MIDI range makes the
// bake's render note and the sample's own root disagree, which is a read rate other than 1 and
// therefore a window sized in the truncating direction.
static void testOutOfDomainWireValuesAreBoundedAtTheCodec() {
const PlaySeconds defaults;
const InstrumentParams paramDefaults;
ComponentState in;
in.selectionId = "pad";
in.params.keyTrack = 0.5; // a neighbouring field, to show the guards are per-field
in.params.keyTrack = std::numeric_limits<double>::quiet_NaN();
in.params.rootOverride = 9999;
in.params.play.pitchEnv.peakSemitones = std::numeric_limits<double>::quiet_NaN();
in.params.play.trigger.lengthFraction = std::numeric_limits<double>::quiet_NaN();
in.params.play.adsr.releaseSeconds = std::numeric_limits<double>::infinity();
in.params.play.filter.enabled = true;
in.params.play.filter.env.attackSeconds = std::numeric_limits<double>::quiet_NaN();
in.params.play.filter.env.holdSeconds = std::numeric_limits<double>::infinity();
in.params.play.filter.env.decaySeconds = -std::numeric_limits<double>::infinity();
in.params.play.filter.env.sustainLevel = std::numeric_limits<double>::quiet_NaN();
in.params.play.filter.env.releaseSeconds = std::numeric_limits<double>::quiet_NaN();
const ComponentState out = deserializeComponentState(serializeComponentState(in), 48000.0);
CHECK(out.params.rootOverride && *out.params.rootOverride == 127);
CHECK(out.params.play.pitchEnv.peakSemitones == defaults.pitchEnv.peakSemitones);
CHECK(out.params.play.trigger.lengthFraction == defaults.trigger.lengthFraction);
CHECK(out.params.play.adsr.releaseSeconds == defaults.adsr.releaseSeconds);
CHECK(out.params.keyTrack == 0.5);
CHECK(out.params.keyTrack == paramDefaults.keyTrack);
CHECK(out.params.play.filter.enabled); // the fallback is per-field, not per-record
CHECK(out.params.play.filter.env.attackSeconds == defaults.filter.env.attackSeconds);
CHECK(out.params.play.filter.env.holdSeconds == defaults.filter.env.holdSeconds);
CHECK(out.params.play.filter.env.decaySeconds == defaults.filter.env.decaySeconds);
CHECK(out.params.play.filter.env.sustainLevel == defaults.filter.env.sustainLevel);
CHECK(out.params.play.filter.env.releaseSeconds == defaults.filter.env.releaseSeconds);
ComponentState low = in;
low.params.rootOverride = -5;
@@ -980,6 +996,20 @@ static void testOutOfDomainWireValuesAreBoundedAtTheCodec() {
CHECK(lowOut.params.rootOverride && *lowOut.params.rootOverride == 0);
}
// The keyTrack guard's OTHER site: a pre-v7 (legacy zone-list) blob's own keyTrack field
// (params_payload.cpp's readLegacyZonePayload, pv >= 6) is a second, independent read of the
// same wire double — same hazard, same fallback, must not be missed just because the v8+
// single-record reader above was fixed.
static void testLegacyZoneKeyTrackNaNLiftsToDefault() {
legacy::Zone z;
z.sampleId = "kick";
z.keyTrack = std::numeric_limits<double>::quiet_NaN();
const ComponentState out =
deserializeComponentState(legacy::envelopeWithZones("kick", {z}, 7), 48000.0);
CHECK(out.params.keyTrack == InstrumentParams{}.keyTrack);
}
// A hard-flag tail truncated mid-COUNT-FIELD (only 2 of its 4 length bytes present, and
// nothing else after) is a different failure shape than a declared-huge count: the u32 read
// itself fails, tripping r.ok inside readHardFlags rather than its own bound check. That must
@@ -1935,6 +1965,7 @@ int main() {
testV13HardFlagOutOfBoundsCountSurvivesWithoutWipingTheRecord();
testV13HardFlagCountThatStrandsAlignmentLeavesTheHoldAbsentNotFabricated();
testOutOfDomainWireValuesAreBoundedAtTheCodec();
testLegacyZoneKeyTrackNaNLiftsToDefault();
testV13HardFlagTailTruncatedMidCountSurvivesWithoutWipingTheRecord();
testBakeHoldRoundTripsAndDisturbsNothingElse();
testV13BlobLiftsToTheDefaultHold();