ebdb4eae66
isOnManualLane predicate now correctly treats unnamed fixed-lane lanes as manual; item-side C_LANEPLAYS loop removed (SDK read-only); explicit #include <set> in view_mode_model.cpp; undo-block omission in detectNewContent documented as intentional.
78 lines
4.7 KiB
C++
78 lines
4.7 KiB
C++
#pragma once
|
|
// lane_keys — the pure, REAPER-free convention that maps a REAPER fixed lane's
|
|
// durable NAME (P_LANENAME:n) to the opaque lane-key the pure view_mode_model uses,
|
|
// and the managed/manual heuristic that rides on it.
|
|
//
|
|
// PURE MODULE (CLAUDE.md §load-bearing split): NO REAPER types, NO SWELL. std only.
|
|
// Unit-tested outside the DAW. The shell (view.cpp) reads each lane's P_LANENAME:n
|
|
// string from REAPER and asks this module whether the lane is tool-managed and what
|
|
// its stable lane-key is; the shell never re-derives the prefix rule itself.
|
|
//
|
|
// -- Design point #2 (lane-identity robustness) resolution --------------------
|
|
//
|
|
// REAPER exposes no durable per-lane GUID. The only lane identity is the ordinal
|
|
// I_FIXEDLANE, which REAPER RENUMBERS when lanes are reordered or deleted — so keying
|
|
// the ownership index by raw ordinal would silently corrupt managed/manual ownership
|
|
// on any reorder. REAPER DOES expose a writable, durable lane NAME (P_LANENAME:n) that
|
|
// travels with the lane across renumber. So the tool names each lane it mints with a
|
|
// stable, prefixed identity ("reasampler:<mode>") and keys the ownership index by that
|
|
// NAME, not the ordinal. On each apply the shell walks the track's lanes by current
|
|
// ordinal, reads each name, and reconciles ordinal<->laneKey — so a C_LANEPLAYS:N
|
|
// write always targets the lane's CURRENT ordinal for a given durable key even after a
|
|
// reorder. A lane WITHOUT the prefix was not minted by the tool: it is manual and
|
|
// off-limits (the fixed-lane analog of "never touch mute/solo").
|
|
//
|
|
// -- Design point #1 (manual-lane exemption) resolution -----------------------
|
|
//
|
|
// The SAME prefix rule is the manual/managed heuristic for auto-tag: an item on a lane
|
|
// whose name lacks the "reasampler:" prefix is on a manual lane and is EXEMPT from
|
|
// auto-tag. isManagedLaneName is the single predicate both the toggle-apply path and
|
|
// the new-content detection path consult, so the boundary is defined in one place and
|
|
// unit-tested.
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
|
|
namespace reasampler {
|
|
|
|
// The prefix the tool stamps on every lane NAME it mints. A lane name carrying this
|
|
// prefix is a managed lane the tool created; any other name (or an empty/unnamed lane)
|
|
// is a user-minted manual lane. Stable-forever: changing it would strand the ownership
|
|
// of every lane in every already-saved project, so treat it like an action id string.
|
|
inline constexpr const char* kManagedLanePrefix = "reasampler:";
|
|
|
|
// True iff `laneName` is a tool-minted managed-lane name (carries kManagedLanePrefix).
|
|
// This is the load-bearing managed/manual predicate for BOTH design points #1 and #2.
|
|
bool isManagedLaneName(const std::string& laneName);
|
|
|
|
// The opaque lane-key the pure model keys by, for a lane with REAPER name `laneName`.
|
|
// For a managed lane the key IS the durable name (stable across ordinal renumber). For
|
|
// a manual/unnamed lane there is no managed key: returns std::nullopt so the caller
|
|
// treats the lane as manual (never driven, items on it exempt from auto-tag).
|
|
std::optional<std::string> managedLaneKey(const std::string& laneName);
|
|
|
|
// The lane NAME the tool mints for the lane owned by `modeId` (kManagedLanePrefix +
|
|
// modeId). The inverse of managedLaneKey for a managed lane: managedLaneKey(
|
|
// laneNameForMode(m)) == kManagedLanePrefix + m. Exposed for the Wave-3 lane-minting
|
|
// path and for tests; the apply path in this wave only READS names, but the round-trip
|
|
// contract is asserted here so minting and reading cannot drift.
|
|
std::string laneNameForMode(const std::string& modeId);
|
|
|
|
// True iff an item on a fixed-lane track with the given lane name is on a MANUAL lane
|
|
// (i.e. exempt from auto-tag). The two inputs are:
|
|
// isFixedLaneTrack — whether the item's track has I_FREEMODE==2. On a normal
|
|
// (non-fixed-lane) track the concept of a "manual lane" does not
|
|
// apply; the item follows the normal auto-tag rule (return false).
|
|
// laneName — the durable P_LANENAME of the lane the item sits on. A lane
|
|
// that carries kManagedLanePrefix is a tool-minted managed lane
|
|
// (not manual); any other name — including empty (unnamed) — is
|
|
// a user-minted manual lane (exempt from auto-tag).
|
|
//
|
|
// This is the SINGLE predicate that governs BOTH the apply path (which lanes may be
|
|
// driven) and the auto-tag exemption path (which items are exempt). It is unit-tested
|
|
// here so both paths share exactly one definition; the shell supplies the two REAPER
|
|
// inputs (I_FREEMODE result, P_LANENAME string) and never re-derives this logic.
|
|
bool isOnManualLane(bool isFixedLaneTrack, const std::string& laneName);
|
|
|
|
} // namespace reasampler
|