Bake reset: assert the limiter and bake Hold land neutral, prove the loop returns parked, and baseline the render's identity path

resetAfterBake is unchanged — every value already resets by construction. The render prints master gain but not the limiter, so §3.4's rationale is wrong; the invariant is corrected.
This commit is contained in:
2026-08-02 07:21:19 -04:00
parent f60c05c042
commit e2981e83ee
5 changed files with 225 additions and 29 deletions
+36
View File
@@ -231,6 +231,42 @@ int main() {
CHECK(identical);
}
// --- Regression baseline: the neutral render is the source, sample for sample --------
// DERIVED rather than recorded, so it survives a compiler change: a Trigger voice at its
// own root under Varispeed, with the default flat amp and velocity shapes and no filter,
// reads at ratio exactly 1 — so every printed frame must BE its source frame. An added
// stage, a moved default, or a lost early-out anywhere in the chain moves a sample here.
{
SampleData s;
s.frames.resize(4000);
// A ramp, not DC: an off-by-one read or a reversed span is invisible in a constant.
for (std::size_t i = 0; i < s.frames.size(); ++i)
s.frames[i] = static_cast<float>(i) / 4000.f - 0.5f;
s.sampleRate = kRate;
s.rootNote = 60;
s.play.playMode = PlayMode::Trigger;
s.play.pitchEngine = PitchEngine::Varispeed;
// Shorter than the play span, so the window closes before any note-end shaping.
const BakePlan plan = planOf(/*total=*/1000, /*noteOn=*/0, /*noteOff=*/1000);
const BakeAudio audio = renderBake(s, plan, kUnity);
CHECK(audio.channelCount == 1);
CHECK(audio.frameCount() == 1000);
bool identity = audio.frameCount() == 1000;
for (std::size_t f = 0; identity && f < 1000; ++f)
identity = (audio.interleaved[f] == s.frames[f]);
CHECK(identity);
// …and the gain rides that as an exact scalar, which is the only other thing the
// render is permitted to do to the signal.
const BakeAudio halved = renderBake(s, plan, 0.5);
bool scaled = halved.frameCount() == 1000;
for (std::size_t f = 0; scaled && f < 1000; ++f)
scaled = (halved.interleaved[f] == s.frames[f] * 0.5f);
CHECK(scaled);
}
// --- Refusals -----------------------------------------------------------------------
{
SampleData empty; // nothing decoded