M10: provenance populate + re-capture from source (bank-only)

Pure provenance core (recipe fingerprint, FX-chain identity, parent
detection) + shell reads; capture stamps provenance on resample-from-sample;
re-capture regenerates a provenanced sample from its source, never touching
the timeline. Adds BankIndex/BankBook in-place update. CTest-covered.
This commit is contained in:
2026-07-26 17:33:22 -04:00
parent 399dafa859
commit 20018c1df2
13 changed files with 1368 additions and 11 deletions
+71
View File
@@ -0,0 +1,71 @@
#pragma once
// provenance_shell — the REAPER-facing reads Milestone 10 needs, in one place.
//
// The PURE provenance module (provenance.h) owns the fingerprint encoding, the
// recipe model, the FX-identity fold, and the parent-detection DECISION — all over
// plain strings/values. This shell gathers those strings/values FROM REAPER:
// * the in-scope FX-chain identity of a source track (name/GUID/enabled rows),
// * the media-file paths of a resolved capture's source items,
// * the active book's bank samples resolved to absolute file paths,
// * a canonical track-GUID string back to a live MediaTrack*.
//
// REAPER-facing: the .cpp includes reaper_plugin_functions.h WITHOUT
// REAPERAPI_IMPLEMENT (main.cpp owns the API pointers; here they are extern —
// CLAUDE.md §contract). MediaTrack is forward-declared so this header stays
// SDK-lite. It depends on the pure provenance module (FxIdentityEntry / recipe /
// BankFileRef) and bank_book (to enumerate the active book's samples).
#include <optional>
#include <string>
#include <vector>
#include "provenance.h"
class MediaTrack;
namespace reasampler {
class BankBook;
// The in-scope FX-chain identity of a source track, folded to the pure
// provenance string. For TRACK scope this is the track's own FX chain; for ITEM
// scope the take/item FX are the in-scope chain — but item/take FX are not
// enumerable via the TrackFX_* family, so an item-scope capture folds an EMPTY
// chain identity (the drift signal then keys on scope + range only, which is
// honest: we do not claim to fingerprint take FX we cannot read). TRACK scope reads
// TrackFX_GetCount / GetFXName / GetFXGUID / GetEnabled in chain order.
std::string fxChainIdentityForTrack(MediaTrack* tr);
// Reads the media-file path of every SELECTED media item's active take source
// (GetMediaItemTake_Source -> GetMediaSourceFileName), normalized to forward-slash.
// Unresolvable items (no take / no source / empty name) are omitted — never an
// empty string in the result, so detectParent's "not in bank" branch is honest.
// The active-project selection is read directly (mirrors main.cpp's collectors).
// This is the ITEM-scope source set (the user selected the items being resampled).
std::vector<std::string> selectedItemSourceFiles();
// The TRACK-scope source set: the media-file paths of the items ON `tracks` that
// OVERLAP the capture range [startSeconds, endSeconds). For a track capture the user
// selects the track, not the item, so the "what audio is being captured" set is the
// range-overlapping items on the source tracks. Same normalize + omit-unresolvable
// contract as selectedItemSourceFiles. An item overlaps iff its [pos, pos+len)
// intersects the range with positive overlap (a zero-length touch does not count).
std::vector<std::string> trackItemSourceFiles(const std::vector<MediaTrack*>& tracks,
double startSeconds, double endSeconds);
// Enumerates the ACTIVE book's samples across every bank (pool + named) as pure
// BankFileRefs — each sample id paired with its file resolved to a normalized
// ABSOLUTE path against `projectDir` (resolveBankFile + normalizeSlashes). A sample
// whose path cannot be resolved (empty projectDir / empty relativePath) is emitted
// with an empty absolutePath, which detectParent never matches. `projectDir` is the
// current .rpp parent (the shell resolves it; empty -> all refs unresolved).
std::vector<BankFileRef> bankFileRefs(const BankBook& book, const std::string& projectDir);
// Resolves a canonical track-GUID string (guidString form) to a live MediaTrack*
// in the active project by scanning tracks and comparing guidString(tr). Returns
// nullptr when no live track carries that GUID (the source track was deleted since
// capture — a re-capture failure mode the caller reports). The master track is not
// scanned (it has no membership GUID and is never a capture source).
MediaTrack* trackByGuid(const std::string& guid);
} // namespace reasampler