feat(view): D2 Wave 2 — apply managed-lane ops + timer-diff auto-tag new content
Drives fixed-lane C_LANEPLAYS for managed lanes only (name-keyed, ordinal-renumber safe) in the view shell; diffs live track/item GUIDs on the panel timer to auto-tag new content to the active mode, first-poll-guarded. Pure guid_diff + lane_keys modules unit-tested; folds in Wave-1 polish.
This commit is contained in:
+29
-4
@@ -1,10 +1,12 @@
|
||||
#include "view_mode_model.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
// view_mode_model implementation.
|
||||
//
|
||||
@@ -121,6 +123,13 @@ int laneModeState(const std::string& managedMode, const std::string& activeMode)
|
||||
// and hidden (C_LANEPLAYS = 0). Exclusive membership: only one stance's lane at a
|
||||
// time. Show-both, which keeps a lane audible across modes, is a per-lane opt-out
|
||||
// the shell layers on; the default per-mode decision here is exclusive.
|
||||
//
|
||||
// EXCLUSIVITY ASSUMPTION (one managed lane per mode per track): the model assumes a
|
||||
// given (track, mode) owns AT MOST ONE managed lane. C_LANEPLAYS=1 means "this lane
|
||||
// plays EXCLUSIVELY" — two lanes on the same track both claiming mode M would both
|
||||
// be told to play exclusively on M's toggle, which REAPER cannot honor coherently
|
||||
// (the last write wins in the DAW). The Wave-3 lane-minting path is responsible for
|
||||
// upholding one-lane-per-(track,mode); planToggle asserts it in debug builds.
|
||||
return managedMode == activeMode ? kLanePlaysExclusive : kLaneSilent;
|
||||
}
|
||||
|
||||
@@ -319,8 +328,20 @@ TogglePlan ViewModeModel::planToggle(const FolderTree& tree, const std::string&
|
||||
// "never touch mute/solo"). Lane ownership is not a tree property, so this walks the
|
||||
// ownership index directly, not the FolderTree; a project with no fixed lanes leaves
|
||||
// plan.lanes empty and the plan is byte-identical to a D1 plan.
|
||||
#ifndef NDEBUG
|
||||
// Debug-time guard for the one-managed-lane-per-mode-per-track exclusivity
|
||||
// assumption (see laneModeState). Two managed lanes on the same track claiming the
|
||||
// same mode would both be told to play exclusively on that mode's toggle, which
|
||||
// REAPER cannot honor. Cheap set membership over the (usually tiny) managed-lane
|
||||
// set; compiled out of release builds.
|
||||
std::set<std::pair<std::string, std::string>> seenTrackMode; // (trackGuid, mode)
|
||||
#endif
|
||||
for (const auto& [ref, ownership] : lanes_.all()) {
|
||||
if (!ownership.isManaged()) continue; // manual lanes are off-limits
|
||||
#ifndef NDEBUG
|
||||
assert(seenTrackMode.insert({ref.trackGuid, *ownership.managedMode}).second &&
|
||||
"two managed lanes on one track claim the same mode (exclusivity broken)");
|
||||
#endif
|
||||
const int lanePlays = laneModeState(*ownership.managedMode, targetMode);
|
||||
plan.lanes.push_back(LanePlayOp{ref.trackGuid, ref.laneKey, lanePlays});
|
||||
}
|
||||
@@ -448,7 +469,8 @@ std::string ViewModeModel::serialize() const {
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto& [guid, mem] : membership_.all()) {
|
||||
if (!first) out += ','; first = false;
|
||||
if (!first) out += ',';
|
||||
first = false;
|
||||
ObjWriter e(out);
|
||||
e.keyStr("guid", guid);
|
||||
e.keyBegin("modes");
|
||||
@@ -456,7 +478,8 @@ std::string ViewModeModel::serialize() const {
|
||||
{
|
||||
bool mf = true;
|
||||
for (const auto& id : mem.modeIds) {
|
||||
if (!mf) out += ','; mf = false;
|
||||
if (!mf) out += ',';
|
||||
mf = false;
|
||||
writeEscaped(out, id);
|
||||
}
|
||||
}
|
||||
@@ -472,7 +495,8 @@ std::string ViewModeModel::serialize() const {
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto& [guid, snap] : snapshots_) {
|
||||
if (!first) out += ','; first = false;
|
||||
if (!first) out += ',';
|
||||
first = false;
|
||||
ObjWriter e(out);
|
||||
e.keyStr("guid", guid);
|
||||
e.keyRaw("showInTcp", intToStr(snap.showInTcp));
|
||||
@@ -494,7 +518,8 @@ std::string ViewModeModel::serialize() const {
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto& [ref, ownership] : lanes_.all()) {
|
||||
if (!first) out += ','; first = false;
|
||||
if (!first) out += ',';
|
||||
first = false;
|
||||
ObjWriter e(out);
|
||||
e.keyStr("trackGuid", ref.trackGuid);
|
||||
e.keyStr("laneKey", ref.laneKey);
|
||||
|
||||
Reference in New Issue
Block a user