Refuse every multi-track selected-tracks render, both scopes; make a failed mono collapse observable
This commit is contained in:
@@ -112,11 +112,27 @@ SourceMode sourceModeForScope(CaptureScope scope, bool itemExtentIsWindow) {
|
||||
return SourceMode::SelectedTracks;
|
||||
}
|
||||
|
||||
bool isMultiTrackRangedItemRender(CaptureScope scope, SourceMode mode,
|
||||
int sourceTrackCount) {
|
||||
return scope == CaptureScope::Item
|
||||
&& mode == SourceMode::SelectedTracks
|
||||
&& sourceTrackCount > 1;
|
||||
bool isMultiTrackStemRender(SourceMode mode, int sourceTrackCount) {
|
||||
return mode == SourceMode::SelectedTracks && sourceTrackCount > 1;
|
||||
}
|
||||
|
||||
std::string multiTrackRefusalMessage(CaptureScope scope) {
|
||||
switch (scope) {
|
||||
case CaptureScope::Item:
|
||||
return "This range is narrower than the selected items, so it renders "
|
||||
"through their tracks -- and those items span more than one track, "
|
||||
"which this shape cannot land as a single file. Capture one track's "
|
||||
"items at a time, or make the range match the items' extent.";
|
||||
case CaptureScope::Track:
|
||||
return "A track capture renders the selected tracks through the master, "
|
||||
"and more than one track cannot land as a single file. Capture one "
|
||||
"track at a time, or route them into a folder/bus track and capture "
|
||||
"that (a folder's own output is its children summed).";
|
||||
}
|
||||
// Unreachable for a valid enum; a refusal with no way out is still better than a
|
||||
// silent one, so fail closed to the scope-agnostic half of the message.
|
||||
return "This selection spans more than one track, which cannot land as a single "
|
||||
"file. Capture one track at a time.";
|
||||
}
|
||||
|
||||
RangeSource inferRangeSource(bool hasRazorArea) {
|
||||
|
||||
@@ -124,19 +124,23 @@ enum class CaptureScope {
|
||||
// track ITSELF is deliberately not isolated; see src/shell/capture/CLAUDE.md.
|
||||
SourceMode sourceModeForScope(CaptureScope scope, bool itemExtentIsWindow);
|
||||
|
||||
// True for the one render shape that cannot land as a single capture: an item-scope
|
||||
// capture re-sourced to the selected-tracks render (its window is not the item
|
||||
// extent) whose selected items span more than one track. That source is read as
|
||||
// rendering one file per selected track — the single-file bit is documented for
|
||||
// item/razor sources only (SDK header ~3041), which is the whole basis for the
|
||||
// reading and is DAW-unverified. If it holds, N tracks collapse N stems onto one
|
||||
// literal render pattern and whichever file survived would land as a successful
|
||||
// capture carrying one track's audio. The caller refuses instead.
|
||||
// True for the one render shape that cannot land as a single capture: a selected-tracks
|
||||
// render covering more than one track — a ranged item capture whose items span several
|
||||
// tracks, or any multi-track track capture. That source is read as rendering one file
|
||||
// per selected track — the single-file bit is documented for item/razor sources only
|
||||
// (SDK header ~3041), which is the whole basis for the reading and is DAW-unverified.
|
||||
// If it holds, N tracks collapse N stems onto one literal render pattern and whichever
|
||||
// file survived would land as a successful capture carrying one track's audio. The
|
||||
// caller refuses instead.
|
||||
//
|
||||
// Track scope is deliberately NOT covered here even though it renders through the
|
||||
// same source — see src/shell/capture/CLAUDE.md §Gotchas.
|
||||
bool isMultiTrackRangedItemRender(CaptureScope scope, SourceMode mode,
|
||||
int sourceTrackCount);
|
||||
// Scope is deliberately NOT a parameter: the exposure comes from the render SOURCE,
|
||||
// which both scopes reach.
|
||||
bool isMultiTrackStemRender(SourceMode mode, int sourceTrackCount);
|
||||
|
||||
// The refusal text for the shape above. Keyed on scope because only the way OUT differs:
|
||||
// an item capture can also widen its range to the items' own extent, which a track
|
||||
// capture has no analog for. Kept beside the predicate so the two read as siblings.
|
||||
std::string multiTrackRefusalMessage(CaptureScope scope);
|
||||
|
||||
// --- Range inference: razor-else-time (orthogonal to scope) -------------------
|
||||
//
|
||||
|
||||
@@ -300,6 +300,16 @@ MonoCollapse collapseToMono(const std::vector<std::uint8_t>& bytes) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string monoCollapseSuffix(MonoCollapseOutcome outcome) {
|
||||
switch (outcome) {
|
||||
case MonoCollapseOutcome::Declined: return {};
|
||||
case MonoCollapseOutcome::Collapsed: return " (collapsed to mono)";
|
||||
case MonoCollapseOutcome::Failed:
|
||||
return " (mono collapse failed -- left as captured)";
|
||||
}
|
||||
return {}; // unreachable for a valid enum; claim nothing rather than a wrong outcome
|
||||
}
|
||||
|
||||
std::string hashBytes(const std::uint8_t* data, std::size_t len) {
|
||||
// FNV-1a 64-bit: deterministic, no dependencies, adequate for dedup identity.
|
||||
std::uint64_t h = kFnvOffsetBasis;
|
||||
|
||||
@@ -117,6 +117,21 @@ struct MonoCollapse {
|
||||
// including the bext/source-position consequence beyond hashing.
|
||||
MonoCollapse collapseToMono(const std::vector<std::uint8_t>& bytes);
|
||||
|
||||
// How applying the collapse to a captured FILE ended. `Declined` is collapseToMono's own
|
||||
// "nothing to do"; `Failed` is a read that never happened or a warranted rewrite that did
|
||||
// not land. The capture is intact and correctly measured in every case — only the report
|
||||
// tells them apart, which is why the two must not share one value.
|
||||
enum class MonoCollapseOutcome {
|
||||
Declined,
|
||||
Collapsed,
|
||||
Failed,
|
||||
};
|
||||
|
||||
// The capture message's collapse suffix — empty for Declined, so a capture that had
|
||||
// nothing to collapse reads exactly as it did before the collapse existed. Shared by
|
||||
// both backends so one outcome cannot be reported two ways.
|
||||
std::string monoCollapseSuffix(MonoCollapseOutcome outcome);
|
||||
|
||||
// --- Content identity (dedup hashes) -----------------------------------------
|
||||
|
||||
// Deterministic FNV-1a 64-bit content hash over `len` bytes, as 16-char lowercase
|
||||
|
||||
Reference in New Issue
Block a user