fix: guard filter tail NaNs, skip static-filter envelope work, pin stereo filter path, correct stale comments

Codec fallback for non-finite filter fields, a modAmount==0 early-out in tickFilterCutoff,
new stereo render tests for the dual-mono mirror, and comment/test accuracy fixes flagged
in review (stale deck-width claims, restated invariants, drifted CMake link comments).
This commit is contained in:
2026-07-30 17:35:45 -04:00
parent 67215509cb
commit 39389c1183
14 changed files with 137 additions and 41 deletions
+2
View File
@@ -15,6 +15,8 @@ reasampler_test(bank_sync LINK bank_sync)
# The state codec is shared with the extension's preset-blob path, so it must link WITHOUT
# the voice engine: velocity_curve (the curve field) and master_gain (the wire gain cap) only.
# play_params.h also pulls in filter/'s headers (FilterSettings, MorphLaw) for the v9 filter
# tail -- plain value types, so no filter symbol is linked and this stays true.
reasampler_pure_library(component_state_io
SOURCES component_state_io.cpp
LINK PUBLIC velocity_curve master_gain)
@@ -162,9 +162,14 @@ void readFilterTail(ByteReader& r, InstrumentParams& p) {
f.settings.driveNorm = static_cast<float>(bitsToDouble(r.u64()));
f.settings.morphLaw = (r.u8() != 0) ? engine::filter::MorphLaw::HighNotchLow
: engine::filter::MorphLaw::HighBandLow;
f.modAmount = bitsToDouble(r.u64());
f.velAmount = bitsToDouble(r.u64());
f.keyTrack = bitsToDouble(r.u64());
// Same non-finite-falls-back-to-neutral guard as the v8 master gain above: these three
// reach Voice::tickFilterCutoff's clamp compares and a static_cast<int>, both UB on NaN.
double modAmount = bitsToDouble(r.u64());
double velAmount = bitsToDouble(r.u64());
double keyTrack = bitsToDouble(r.u64());
f.modAmount = std::isfinite(modAmount) ? modAmount : 0.0;
f.velAmount = std::isfinite(velAmount) ? velAmount : 0.0;
f.keyTrack = std::isfinite(keyTrack) ? keyTrack : 0.0;
f.env.attackSeconds = bitsToDouble(r.u64());
f.env.holdSeconds = bitsToDouble(r.u64());
f.env.decaySeconds = bitsToDouble(r.u64());