Close three critical review findings on the render-bounds-channel verdict

Verdict can no longer print a false EXACT on an on-grid end, no longer names a
bounds channel a content-derived render never consulted, and the grid-align doc
premise is corrected without implementing it.
This commit is contained in:
2026-08-02 15:56:57 -04:00
parent a0fd931dcb
commit 5f971e60cd
14 changed files with 750 additions and 81 deletions
+55 -8
View File
@@ -1,10 +1,10 @@
#pragma once
// render_window — pure frame arithmetic for a capture's requested window: the
// frame count a project-time range occupies, whether a render whose bounds come
// from the selected items' own extent already prints that window, and the two
// diagnostics that bound a short render without locating it: whether the stored
// RENDER_* bounds round-tripped, and whether the shortfall matches a millisecond-
// floor coincidence.
// from the selected items' own extent already prints that window, and the
// diagnostics that bound a short render: whether the stored bounds round-tripped,
// whether the shortfall matches a millisecond-floor coincidence, and the verdict on
// which bounds channel a capture used and what it produced.
// NO REAPER types; unit-tested by tests/test_render_window.cpp.
#include <string>
@@ -50,18 +50,65 @@ bool itemExtentPrintsWindow(double reqStart, double reqEnd,
// --- Diagnostics: where a short render lost its frames ------------------------
// The frames this window would hold if its END were resolved on a whole-millisecond
// grid, floored, instead of exactly. Two live short renders (48 kHz, TailMode::None)
// matched this count to the frame, which is the entire reason it exists.
// grid, floored, instead of exactly. That is what REAPER's offline render does: two
// live short renders (48 kHz, TailMode::None) printed this count to the frame, and the
// after-render read-back showed REAPER's own resolved end floored to the same value.
//
// A COINCIDENCE OF COUNTS, not a claim about how anything resolved the end: nothing
// renders from this number and no capture path asks for it. Whole-millisecond values
// Still a DESCRIPTION, never a request: nothing renders from this number and no capture
// path asks for it — a refusal quotes it to say the shortfall has the known shape, which
// is not the same as proving that this particular render took it. Whole-millisecond values
// are recognized within a nanosecond, because a decimal millisecond is not always one
// in binary (1.007 * 1000 lands just below 1007) and a bare floor would drop a
// millisecond from a window already on the grid. A nanosecond is far under one frame
// at any rate we render, so a real sub-millisecond remainder still floors.
//
// The tolerance is ours, not REAPER's: on a `1.007`-class grid point, a REAPER floor
// that does NOT carry the same epsilon would miss this shape entirely, and a real
// floored render would then read as an unmatched SHORT rather than the known one —
// silence here is not proof the floor didn't happen (docs/TODO.md records why this
// premise needs a DAW measurement before anything is built on it).
long long msFlooredEndFrameCount(double startSeconds, double endSeconds,
int sampleRate);
// True when `seconds` sits on a whole-millisecond boundary, under the same nanosecond
// tolerance msFlooredEndFrameCount uses and for the same reason (stated there).
//
// Load-bearing for reading a bounds observation: an on-grid edge is left alone by
// floor, ceil and round alike, so a window whose START is on the grid can say nothing
// about whether REAPER resolves the start edge the way it resolves the end.
bool isOnMillisecondGrid(double seconds);
// The one-line verdict on what a capture's bounds channel did with its window: which
// channel carried it (or, when the render source defines the window itself, which
// source bypassed the channel entirely), the frames the landed file holds against the
// frames the window asks for, and whether this run could test the START and END edges
// at all. Always non-empty — a capture that answered nothing has to say so, or its
// silence reads as a pass.
//
// EXACT never stands alone as proof: an END that sits on the millisecond grid prints
// the SAME EXACT count whether the channel honored the window or floored it and landed
// back on the grid by coincidence, so that case is called out in the sentence rather
// than left to read as settled — same principle as the existing START-edge caveat.
//
// A non-zero delta that still falls inside the gate's own tolerance (renderHonoredBounds)
// is tagged "(WITHIN TOLERANCE)" — that is the gate's ordinary edge-convention slack, not
// evidence of the millisecond floor; a bare SHORT/LONG, or a delta matching
// msFlooredEndFrameCount exactly, is the floor's signature.
//
// `sampleRate <= 0` means the landed file was never measured: a tail mode adds frames by
// design and is not judged, an empty render has none, and a render whose layout failed to
// parse or declared no sample rate is refused before it can be judged either — the
// sentence then says the run answered nothing rather than inventing a comparison.
//
// `bypassingSourceLabel`, when non-null and non-empty, means the render source itself
// defined the window (render_settings::sourceBypassesBoundsChannel) — `channelLabel` was
// never consulted, so the verdict names the source instead and reads NOT JUDGED
// regardless of how the frame counts compare.
std::string describeBoundsExperiment(const char* channelLabel,
double reqStart, double reqEnd,
long long actualFrames, int sampleRate,
const char* bypassingSourceLabel = nullptr);
// The sentence a capture prints when the render bounds it handed REAPER did not read
// back unchanged — the requested window, what came back, and both frame counts at
// `sampleRate` (omitted when the rate is unknown). EMPTY when both edges read back