Bake window derives itself: %-knob fold, declick pad, Gate held to exhaustion, preview velocity; Hold is the one knob a loop needs
This commit is contained in:
@@ -193,6 +193,24 @@ void readHardFlags(ByteReader& r, VelocityCurve& curve) {
|
||||
for (std::size_t i = 0; i < flags.size(); ++i) curve.setHard(i, flags[i] != 0);
|
||||
}
|
||||
|
||||
// Read the v14 bake Hold. Same revive discipline as readHardFlags directly above, and for the
|
||||
// same reason: this tail reaches no audio path, so a blob truncated inside it must cost the
|
||||
// Hold alone and not reset the whole record that parsed cleanly ahead of it. It sits LAST, so
|
||||
// a truncation stranding the hard flags strands this too — reviving in only one of the two
|
||||
// would still wipe the record.
|
||||
void readBakeHold(ByteReader& r, InstrumentParams& p) {
|
||||
const bool enteredOk = r.ok;
|
||||
const std::int32_t exponent = r.i32();
|
||||
const std::uint8_t modifier = r.u8();
|
||||
if (!r.ok) {
|
||||
if (enteredOk) r.ok = true;
|
||||
return;
|
||||
}
|
||||
// makeDivision clamps BOTH fields, so a corrupt pair becomes the nearest legal rung
|
||||
// rather than an unrepresentable one — never a memcpy into the type.
|
||||
p.bakeHold = note::makeDivision(exponent, static_cast<note::DivisionModifier>(modifier));
|
||||
}
|
||||
|
||||
// Read the v9 filter tail into `p`. A blob that stops short leaves the off/neutral default,
|
||||
// which is what makes a v8 blob play bit-identically under the new codec. The curve reads as
|
||||
// bipolar at EVERY version — a pre-v12 blob's y values are already valid bipolar ones, so its
|
||||
@@ -418,6 +436,11 @@ void putParamsPayload(std::vector<std::uint8_t>& out, const InstrumentParams& p)
|
||||
putHardFlags(out, p.velocityCurve);
|
||||
putHardFlags(out, f.velocityCurve);
|
||||
putHardFlags(out, pp.pitchVelocityCurve);
|
||||
// v14: the bake's Hold division, as its {quarterExponent, modifier} pair — never its
|
||||
// picker index, which the ladder gaining a rung would silently re-map.
|
||||
putLE(out, static_cast<std::uint32_t>(
|
||||
static_cast<std::int32_t>(p.bakeHold.quarterExponent())));
|
||||
out.push_back(static_cast<std::uint8_t>(p.bakeHold.modifier()));
|
||||
}
|
||||
|
||||
// Read whichever payload shape follows: the single-record shape (v8 onward, growing by
|
||||
@@ -468,6 +491,7 @@ PayloadRead readParamsPayload(ByteReader& r, double projectRate) {
|
||||
readHardFlags(r, p.play.filter.velocityCurve);
|
||||
readHardFlags(r, p.play.pitchVelocityCurve);
|
||||
}
|
||||
if (pv >= kParamsBakeHoldVersion) readBakeHold(r, p);
|
||||
// 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{};
|
||||
|
||||
Reference in New Issue
Block a user