capture: refuse the multi-track ranged item render, silence the track's children and receives for it, and gate every exact-bounds capture on its frame count

This commit is contained in:
2026-08-01 20:58:33 -04:00
parent 5e3ea6c851
commit 7dc80e7a4f
20 changed files with 525 additions and 27 deletions
+30
View File
@@ -32,6 +32,7 @@
#include "core/capture/wav_codec.h" // hashWavContent — the one WAV/RIFF owner
#include "core/util/file_bytes.h"
#include "core/capture/render_settings.h"
#include "core/capture/render_window.h" // frameCountFor — the exact-bounds number
#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_EnumProjects
@@ -394,6 +395,35 @@ CaptureResult OfflineRenderBackend::capture(const CaptureRequest& request) {
return result;
}
// Exact bounds, made structural: with no tail requested the file must contain
// exactly the requested window's frames, so a source mode that silently widened
// the render fails loudly here instead of landing as a successful capture. Auto
// and Manual add frames by design and are skipped. UNVERIFIED: that REAPER
// resolves the window's two edges to frame indices the same way frameCountFor
// does — a DAW pass decides whether this equality is exact or off by a frame.
// (The file is read again by stampCaptureSample below; the duplicate read is a
// once-per-capture cost on an already-warm file.)
if (request.tailMode == TailMode::None) {
const WavLayout layout =
parseWavLayout(util::readFileBytes(expectedPath));
const long long expectedFrames = layout.valid
? frameCountFor(request.startSeconds, request.endSeconds,
static_cast<int>(layout.sampleRate))
: 0;
const long long actualFrames = static_cast<long long>(layout.frameCount());
if (expectedFrames > 0 && actualFrames != expectedFrames) {
result.status = CaptureStatus::BoundsMismatch;
result.message = "Render produced " + std::to_string(actualFrames) +
" frames but the requested range is " +
std::to_string(expectedFrames) + " at " +
std::to_string(layout.sampleRate) +
" Hz -- the render did not honor the requested bounds. "
"Nothing was added to the bank; the file is at: " +
expectedPath;
return result;
}
}
// Record the request's own bounds (exact) rather than re-measuring the file.
Sample s;
// Same uniqueTag that named the file — calling makeUniqueTag() again could