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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user