#pragma once // Scope/source resolution shared by every capture entry point. Three concerns: // * range inference — razor union else time selection, orthogonal to scope; // * source-track collection — selected tracks (Track scope) or selected items' // owning tracks (Item scope), deduped, with canonical GUIDs; // * provenance-assembly inputs — resample-from-sample detection + the thin // capture-recipe fingerprint built from the live (un-bypassed) chain. // // All reads are non-destructive: selection, razor, and time selection are read, // never mutated. The .cpp includes reaper_plugin_functions.h WITHOUT // REAPERAPI_IMPLEMENT (main.cpp owns the API pointers). MediaTrack is forward- // declared (via capture.h) so this header stays SDK-lite. #include #include #include #include "shell/capture/capture.h" // CaptureRequest, MediaTrack fwd #include "core/capture/render_settings.h" // CaptureScope #include "core/model/provenance.h" // model::Provenance namespace reasampler { class BankBook; } namespace reasampler::capture { // The resolved source: exact bounds + the source tracks (for FX-bypass + Sample // provenance GUIDs). `sourceTracks` holds the item-owning tracks (Item scope) or the // selected tracks (Track scope). struct ResolvedSource { double startSeconds = 0.0; double endSeconds = 0.0; std::vector sourceTracks; std::vector trackGuids; // Parallel to sourceTracks (one entry per track, in the same order) — the names the // capture is labeled and filed after. trackGuids is NOT parallel: an unreadable GUID // is dropped there, while an unreadable name still holds its track's slot. std::vector trackNames; // Item scope only: does the selected items' own extent already print // [startSeconds, endSeconds)? Feeds sourceModeForScope. Defaults false so a // hand-built source fails closed to the time-bounded render — a caller whose // range IS the item extent (batch item capture) says so explicitly. bool itemExtentIsWindow = false; }; // Reads every track's P_RAZOREDITS and returns the union of parsed track-audio // areas. Reads only — never clears the razor selection. bool resolveRazorRange(double& start, double& end); // Infers the render range for any scope: razor union when present, else the time // selection. Returns false with a reason when neither yields a non-empty range. bool resolveRange(double& start, double& end, std::string& why); // Collects the selected tracks (Track scope) into out.sourceTracks + GUIDs + names. bool collectSelectedTracks(ResolvedSource& out); // The track's display name. GetTrackName (SDK header ~3626) is used rather than P_NAME // because it already answers REAPER's own convention for an unnamed track ("Track N"), // which is exactly the deterministic fallback a capture label wants; P_NAME would hand // back an empty string instead. `[verify]` the SDK header states neither that the read is // non-mutating nor what a `false` return means; the call site treats it as read-only and // treats `false` (or a `true` with an untouched buffer) the same way — an empty name, which // falls through to the scope literal fallback either way, so both readings are safe. // Callers that build a ResolvedSource by hand (batch capture) use this directly. std::string trackName(MediaTrack* tr); // Resolves the source for a scope: the selection tracks (item/track), plus the // inferred range. Returns false with a reason on nothing to do. bool ResolveScopeSource(CaptureScope scope, ResolvedSource& out, std::string& why); // Current project's directory (parent of its .rpp), forward-slashed, no trailing // slash. Empty for an unsaved project (no false parentage). Read-only. std::string currentProjectDir(); // Builds the provenance for a capture if it genuinely resamples from a bank sample // (detectParent over `book`'s resolved file refs), else returns nullopt (the common, // non-resample case). Must run BEFORE the FxBypassGuard neutralizes the in-scope // chain — the source FX-chain identity is read from the live chain. std::optional buildCaptureProvenance( const BankBook& book, const CaptureRequest& req, CaptureScope scope, const ResolvedSource& src); } // namespace reasampler::capture