capture: render a ranged item capture time-bounded — the selected-items source can't narrow a window, only a full-extent one uses it

sourceModeForScope now takes the item extent vs. the requested window. Full-extent item captures and the batch keep the old path unchanged.
This commit is contained in:
2026-08-01 19:43:06 -04:00
parent 8bf6841f7b
commit 5e3ea6c851
16 changed files with 407 additions and 20 deletions
+41 -9
View File
@@ -203,14 +203,43 @@ static void testRazorUnionBounds() {
// --- sourceModeForScope: scope -> render source mode -------------------------
static void testScopeSourceModes() {
// Each scope drives a distinct render source. Item -> items, Track -> tracks.
// (There is no master scope — to capture the master you render a track.) These
// feed renderSettingsFor and must be supported.
CHECK(sourceModeForScope(CaptureScope::Item) == SourceMode::SelectedItems);
CHECK(sourceModeForScope(CaptureScope::Track) == SourceMode::SelectedTracks);
// Track scope always renders its selected tracks (there is no master scope — to
// capture the master you render a track), whatever the window.
CHECK(sourceModeForScope(CaptureScope::Track, true) == SourceMode::SelectedTracks);
CHECK(sourceModeForScope(CaptureScope::Track, false) == SourceMode::SelectedTracks);
// Item scope renders the selected items only when their extent already prints
// the requested window.
CHECK(sourceModeForScope(CaptureScope::Item, true) == SourceMode::SelectedItems);
// Every scope's source mode is an offline-supported render source.
CHECK(renderSettingsFor(sourceModeForScope(CaptureScope::Item), 1.0).supported);
CHECK(renderSettingsFor(sourceModeForScope(CaptureScope::Track), 1.0).supported);
CHECK(renderSettingsFor(sourceModeForScope(CaptureScope::Item, true), 1.0).supported);
CHECK(renderSettingsFor(sourceModeForScope(CaptureScope::Track, true), 1.0).supported);
}
static void testRangedItemScopeRendersTimeBounded() {
// The Ψ.7 defect pinned at the bit level. A window the item extent does NOT
// print must never reach the &32 selected-items source: that source takes its
// bounds from the item extents, so RENDER_STARTPOS/ENDPOS cannot narrow it and
// the capture widens to the whole item. The ranged item capture renders through
// the selected-tracks source instead, which IS time-bounded.
const SourceMode ranged = sourceModeForScope(CaptureScope::Item, false);
CHECK(ranged == SourceMode::SelectedTracks);
const RenderSettingsChoice c = renderSettingsFor(ranged, 1.0);
CHECK(c.supported);
CHECK((c.settings & kRenderSelItems) == 0); // the widening bit is absent
CHECK((c.settings & kRenderSingleFile) == 0); // and its single-file companion
CHECK(c.settings == kRenderSelTracksViaMaster);
// The regression floor, at the same resolution: an item capture whose window IS
// the item extent still renders through &32 | single-file, unchanged.
const RenderSettingsChoice floorCase =
renderSettingsFor(sourceModeForScope(CaptureScope::Item, true), 1.0);
CHECK((floorCase.settings & kRenderSelItems) != 0);
CHECK((floorCase.settings & kRenderSingleFile) != 0);
// FX scope is orthogonal to the re-source: a ranged item capture still hears
// take/item FX only (this is what makes the swap safe).
CHECK(fxBypassPlanFor(CaptureScope::Item).bypassSelfFx);
}
// --- inferRangeSource: razor-else-time (orthogonal to scope) -----------------
@@ -262,8 +291,10 @@ static void testTableHasBothScopes() {
// double-prefix bug, so assert its ABSENCE.
CHECK(suffix.rfind("CEREBELLUM_REASAMPLER_", 0) != 0);
CHECK(ids.insert(suffix).second); // false if duplicate
// Every scope resolves to a supported offline source.
CHECK(renderSettingsFor(sourceModeForScope(def.scope), 1.0).supported);
// Every scope resolves to a supported offline source, on BOTH the
// extent-prints-the-window path and the time-bounded one.
CHECK(renderSettingsFor(sourceModeForScope(def.scope, true), 1.0).supported);
CHECK(renderSettingsFor(sourceModeForScope(def.scope, false), 1.0).supported);
if (def.scope == CaptureScope::Item) ++item;
if (def.scope == CaptureScope::Track) ++track;
@@ -307,6 +338,7 @@ int main() {
testParseEmptyAndMalformed();
testRazorUnionBounds();
testScopeSourceModes();
testRangedItemScopeRendersTimeBounded();
testRangeInference();
testItemScopeBypassesEverythingButTake();
testTrackScopeKeepsSelfBypassesAncestorsAndMaster();