loop: crossfade the Gate sustain seam, and unshadow the loop handles that made loop points look gone

This commit is contained in:
2026-07-31 17:36:36 -04:00
parent a90ccd9a00
commit 0fe4166d7d
25 changed files with 991 additions and 64 deletions
@@ -319,6 +319,8 @@ void putParamsPayload(std::vector<std::uint8_t>& out, const InstrumentParams& p)
putLE(out, doubleToBits(f.env.decayCurve));
putLE(out, doubleToBits(f.env.releaseCurve));
putAhd(out, f.trigEnv);
// v11: the loop crossfade, in SOURCE frames.
putLE(out, asU64(p.loopCrossfadeFrames));
}
// Read whichever payload shape follows: the single-record shape (v8 onward, growing by
@@ -351,6 +353,12 @@ PayloadRead readParamsPayload(ByteReader& r, double projectRate) {
readCurveTail(r, p.velocityCurve);
if (pv >= kParamsFilterVersion) readFilterTail(r, p);
if (pv >= kParamsCurveVersion) readCurveStageTail(r, p);
if (pv >= kParamsLoopVersion) {
// A negative fade is meaningless and would reach resolveLoop's clamp anyway; refusing
// it here keeps the parameter set itself sane for the editor that reads it back.
const std::int64_t xf = r.i64();
p.loopCrossfadeFrames = xf > 0 ? xf : 0;
}
// A truncated record leaves whatever parsed plus construction defaults for the rest —
// the same degrade-don't-throw contract the zone ladder always had.
if (!r.ok) return PayloadRead{};