Q-W2v review follow-ups: golden full-blob fixture test, dead-local cleanup, bool-guard static_assert, explicit VelocityCurve qualification

This commit is contained in:
2026-07-29 11:28:52 -04:00
parent ea86f540b8
commit f0f91f7698
5 changed files with 144 additions and 4 deletions
+142
View File
@@ -101,6 +101,147 @@ static void testComponentStateRoundTrip() {
}
}
// GOLDEN FULL-BLOB FIXTURE (reviewer follow-up, Q-W2v). testEnvelopePrefixBytesFrozen below
// only pins the first 5 bytes of a near-EMPTY blob; it cannot catch a drift anywhere past the
// mode byte (a field re-ordered or dropped inside the voice/gain/refs/guid/zone tail would
// still pass it). This test builds a canonical v11 ComponentState that exercises EVERY field
// family at once (two zones — one Trigger with every optional override set, one Gate with all
// optionals absent — a two-entry sample-refs table, non-default voice/gain/channel-mode
// fields, and a non-flat velocity curve) and asserts the encoded bytes equal an EXACT expected
// vector. The vector below is the current writer's PROVABLY-CORRECT output (proven by the
// round-trip test above) captured as the golden — so the byte layout itself becomes
// un-driftable, not just its first 5 bytes.
static void testGoldenFullBlobFixture() {
ComponentState in;
in.selectionId = "kick";
in.channelMode = ChannelMode::Stereo;
in.channelModeExplicit = true;
in.lastConsumedAssignGeneration = 12345;
in.previewVelocity = 100;
in.voiceCount = 24;
in.voiceMode = VoiceMode::Mono;
in.monoTrigger = MonoTrigger::Legato;
in.masterGainLinear = 2.0;
in.instanceGuid = "guid-1234-5678-abcd";
SampleRefEntry kickRef;
kickRef.sampleId = "kick";
kickRef.ref.relativePath = "bank/kick.wav";
kickRef.ref.rootNote = 36;
kickRef.ref.loop.hasLoop = true;
kickRef.ref.loop.start = 1000;
kickRef.ref.loop.end = 5000;
kickRef.ref.channelCount = 2;
kickRef.displayName = "Kick Drum";
in.sampleRefs.push_back(kickRef);
SampleRefEntry snareRef;
snareRef.sampleId = "snare";
snareRef.ref.relativePath = "bank/snare.wav";
snareRef.ref.rootNote = 38;
snareRef.ref.loop.hasLoop = false;
snareRef.ref.loop.start = 0;
snareRef.ref.loop.end = 0;
snareRef.ref.channelCount = 1;
snareRef.displayName = "Snare";
in.sampleRefs.push_back(snareRef);
// Zone A: every optional field present, Trigger mode, non-flat velocity curve.
PerformanceZone zoneA;
zoneA.sampleId = "kick";
zoneA.lowNote = 24;
zoneA.highNote = 60;
zoneA.rootOverride = 36;
SampleLoop loopA;
loopA.hasLoop = true;
loopA.start = 1000;
loopA.end = 5000;
zoneA.loopOverride = loopA;
zoneA.startPoint = 250;
zoneA.keyTrack = 0.5;
zoneA.velocityCurve = reasampler::instrument::engine::VelocityCurve::fromPoints(
{VelocityPoint{0.0, 0.2}, VelocityPoint{64.0, 0.6}, VelocityPoint{127.0, 1.0}});
zoneA.play.playMode = PlayMode::Trigger;
zoneA.play.adsr.attackSeconds = 0.01;
zoneA.play.adsr.holdSeconds = 0.05;
zoneA.play.adsr.decaySeconds = 0.02;
zoneA.play.adsr.sustainLevel = 0.8;
zoneA.play.adsr.releaseSeconds = 0.15;
zoneA.play.trigger.lengthFraction = 0.75;
zoneA.play.trigger.fadeInFrames = 100;
zoneA.play.trigger.fadeOutFrames = 200;
zoneA.play.pitchEngine = PitchEngine::Preserve;
zoneA.play.pitchEnv.enabled = true;
zoneA.play.pitchEnv.attackSeconds = 0.02;
zoneA.play.pitchEnv.decaySeconds = 0.03;
zoneA.play.pitchEnv.peakSemitones = 5.0;
in.map.zones.push_back(zoneA);
// Zone B: every optional field absent, Gate mode, default flat velocity curve.
PerformanceZone zoneB;
zoneB.sampleId = "snare";
zoneB.lowNote = 61;
zoneB.highNote = 90;
zoneB.keyTrack = 2.0;
zoneB.play.playMode = PlayMode::Gate;
zoneB.play.adsr.attackSeconds = 0.005;
zoneB.play.adsr.holdSeconds = 0.0;
zoneB.play.adsr.decaySeconds = 0.1;
zoneB.play.adsr.sustainLevel = 0.5;
zoneB.play.adsr.releaseSeconds = 0.2;
zoneB.play.pitchEngine = PitchEngine::Varispeed;
in.map.zones.push_back(zoneB);
const std::vector<std::uint8_t> bytes = serializeComponentState(in);
// clang-format off
static const std::uint8_t kGolden[] = {
0x0b,0x00,0x00,0x00,0x01,0x39,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x01,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x02,0x00,0x00,0x00,0x04,0x00,
0x00,0x00,0x6b,0x69,0x63,0x6b,0x0d,0x00,0x00,0x00,0x62,0x61,0x6e,0x6b,0x2f,0x6b,
0x69,0x63,0x6b,0x2e,0x77,0x61,0x76,0x24,0x00,0x00,0x00,0x01,0xe8,0x03,0x00,0x00,
0x00,0x00,0x00,0x00,0x88,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x09,0x00,0x00,0x00,0x4b,0x69,0x63,0x6b,0x20,0x44,0x72,0x75,0x6d,0x05,0x00,0x00,
0x00,0x73,0x6e,0x61,0x72,0x65,0x0e,0x00,0x00,0x00,0x62,0x61,0x6e,0x6b,0x2f,0x73,
0x6e,0x61,0x72,0x65,0x2e,0x77,0x61,0x76,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
0x00,0x05,0x00,0x00,0x00,0x53,0x6e,0x61,0x72,0x65,0x13,0x00,0x00,0x00,0x67,0x75,
0x69,0x64,0x2d,0x31,0x32,0x33,0x34,0x2d,0x35,0x36,0x37,0x38,0x2d,0x61,0x62,0x63,
0x64,0x04,0x00,0x00,0x00,0x6b,0x69,0x63,0x6b,0x00,0xff,0xff,0xff,0x07,0x00,0x00,
0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6b,0x69,0x63,0x6b,0x18,0x00,0x00,
0x00,0x3c,0x00,0x00,0x00,0x01,0x24,0x00,0x00,0x00,0x01,0x01,0xe8,0x03,0x00,0x00,
0x00,0x00,0x00,0x00,0x88,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xfa,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x9a,0x99,0x99,0x99,0x99,0x99,0xa9,0x3f,0x00,0x00,
0x00,0x00,0x00,0x00,0xe8,0x3f,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x7b,0x14,0xae,0x47,0xe1,0x7a,0x94,0x3f,
0xb8,0x1e,0x85,0xeb,0x51,0xb8,0x9e,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,
0x7b,0x14,0xae,0x47,0xe1,0x7a,0x84,0x3f,0x7b,0x14,0xae,0x47,0xe1,0x7a,0x94,0x3f,
0x9a,0x99,0x99,0x99,0x99,0x99,0xe9,0x3f,0x33,0x33,0x33,0x33,0x33,0x33,0xc3,0x3f,
0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x3f,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x9a,0x99,0x99,0x99,0x99,0x99,0xc9,0x3f,0x00,0x00,0x00,0x00,
0x00,0x00,0x50,0x40,0x33,0x33,0x33,0x33,0x33,0x33,0xe3,0x3f,0x00,0x00,0x00,0x00,
0x00,0xc0,0x5f,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f,0x05,0x00,0x00,0x00,
0x73,0x6e,0x61,0x72,0x65,0x3d,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,
0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,0x14,0xae,0x47,0xe1,
0x7a,0x74,0x3f,0x9a,0x99,0x99,0x99,0x99,0x99,0xb9,0x3f,0x00,0x00,0x00,0x00,0x00,
0x00,0xe0,0x3f,0x9a,0x99,0x99,0x99,0x99,0x99,0xc9,0x3f,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xf0,0x3f,0x00,0x00,0x00,0x00,0x00,0xc0,0x5f,0x40,0x00,
0x00,0x00,0x00,0x00,0x00,0xf0,0x3f,
};
// clang-format on
CHECK(bytes.size() == sizeof(kGolden));
if (bytes.size() == sizeof(kGolden)) {
bool same = true;
for (std::size_t i = 0; i < bytes.size(); ++i) {
if (bytes[i] != kGolden[i]) { same = false; break; }
}
CHECK(same);
}
}
// The FROZEN envelope prefix: version tag v11 LE, then the mode byte — a drift in
// either is a byte-format break the round-trip alone can't prove (both sides could
// drift together). Pins the writer's absolute bytes.
@@ -166,6 +307,7 @@ static void testPerformanceRoundTrip() {
int main() {
testComponentStateRoundTrip();
testGoldenFullBlobFixture();
testEnvelopePrefixBytesFrozen();
testV1SelectionLift();
testTruncationDegradesCleanly();