test: S7xS11 compose — stereo+startFrame+loop share one read head; v4 stereo envelope + v2 zone overrides round-trip together

This commit is contained in:
2026-07-26 22:09:45 -04:00
parent 75f717bd47
commit 7a191bde61
2 changed files with 86 additions and 0 deletions
+39
View File
@@ -941,6 +941,44 @@ static void testComponentStateV4TruncatedModeByte() {
CHECK(back.selectionId.empty() && back.map.zones.empty());
}
static void testComponentStateV4StereoWithZoneOverridesRoundTrip() {
// The MERGE composition property (S7 v4 envelope x S11 v2 zones payload): a v4 blob carrying
// channelMode = STEREO AND zones with loopOverride + startPoint must round-trip ALL of it
// losslessly. The channel-mode byte lives on the envelope; the loop/start overrides live in
// the self-versioned zones payload — the two tracks are orthogonal, so both survive one
// serialize/deserialize. (V4RoundTripStereo covers mode with a bare zone; LoopStartRoundTrip
// covers overrides at the default mono mode; this asserts them TOGETHER.)
ComponentState s;
s.selectionId = "pick";
s.channelMode = ChannelMode::Stereo;
PerformanceZone z0 = zone("z0", 12, 48, /*override=*/36);
SampleLoop lp0; lp0.hasLoop = true; lp0.start = 500; lp0.end = 9000;
z0.loopOverride = lp0;
z0.startPoint = 128;
PerformanceZone z1 = zone("z1", 49, 127); // second zone: no overrides (mixed payload)
s.map.zones.push_back(z0);
s.map.zones.push_back(z1);
const ComponentState back = deserializeComponentState(serializeComponentState(s));
CHECK(back.channelMode == ChannelMode::Stereo); // envelope field survives
CHECK(back.selectionId == "pick");
CHECK(back.map.zones.size() == 2);
CHECK(back.map.zones.size() == 2 && back.map.zones[0].sampleId == "z0" &&
back.map.zones[0].lowNote == 12 && back.map.zones[0].highNote == 48);
CHECK(back.map.zones.size() == 2 && back.map.zones[0].rootOverride.has_value() &&
*back.map.zones[0].rootOverride == 36);
CHECK(back.map.zones.size() == 2 && back.map.zones[0].loopOverride.has_value() &&
back.map.zones[0].loopOverride->hasLoop &&
back.map.zones[0].loopOverride->start == 500 &&
back.map.zones[0].loopOverride->end == 9000);
CHECK(back.map.zones.size() == 2 && back.map.zones[0].startPoint.has_value() &&
*back.map.zones[0].startPoint == 128);
// The override-free second zone stays override-free (the payload framing per zone is intact).
CHECK(back.map.zones.size() == 2 && back.map.zones[1].sampleId == "z1" &&
!back.map.zones[1].loopOverride.has_value() &&
!back.map.zones[1].startPoint.has_value());
}
int main() {
testSelectByIdHit();
testSelectEmptyIdIsSilence();
@@ -1010,6 +1048,7 @@ int main() {
testComponentStateV3LiftsToMono();
testComponentStateV1V2LiftToMono();
testComponentStateV4TruncatedModeByte();
testComponentStateV4StereoWithZoneOverridesRoundTrip();
if (g_fail == 0) std::printf("sample_map: all tests passed\n");
return g_fail != 0;