capture: refuse the multi-track ranged item render, silence the track's children and receives for it, and gate every exact-bounds capture on its frame count

This commit is contained in:
2026-08-01 20:58:33 -04:00
parent 5e3ea6c851
commit 7dc80e7a4f
20 changed files with 525 additions and 27 deletions
+86
View File
@@ -0,0 +1,86 @@
// render_isolation.cpp — see the header.
//
// Compiled into the reaper_reasampler module. Includes reaper_plugin_functions.h
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp is the one TU that defines the API
// pointers; here they are extern.
#include "shell/capture/render_isolation.h"
#include <cstddef>
#include "core/capture/track_topology.h" // directChildIndices
#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_CountTracks
#define REAPERAPI_WANT_GetTrack
#define REAPERAPI_WANT_GetMediaTrackInfo_Value
#define REAPERAPI_WANT_SetMediaTrackInfo_Value
#define REAPERAPI_WANT_GetTrackNumSends
#define REAPERAPI_WANT_GetTrackSendInfo_Value
#define REAPERAPI_WANT_SetTrackSendInfo_Value
#include "reaper_plugin_functions.h"
namespace reasampler::capture {
namespace {
// GetTrackNumSends / *TrackSendInfo_Value category: < 0 selects the RECEIVE list
// (SDK header ~3644, ~3676).
constexpr int kReceivesCategory = -1;
} // namespace
UpstreamIsolation::UpstreamIsolation(MediaTrack* track)
: track_(track)
{
if (!track_) return;
// One pass over the track list for both the depth deltas and this track's index;
// the pure walk turns the flat delta list into the direct-child set. The master
// is absent from GetTrack's index space (it is reached only via GetMasterTrack)
// and has no send-to-parent to cut, so nothing is missed by ignoring it.
const int total = CountTracks(nullptr);
std::vector<MediaTrack*> tracks;
std::vector<int> depths;
tracks.reserve(static_cast<std::size_t>(total < 0 ? 0 : total));
depths.reserve(static_cast<std::size_t>(total < 0 ? 0 : total));
int parentIndex = -1;
for (int i = 0; i < total; ++i)
{
MediaTrack* tr = GetTrack(nullptr, i);
tracks.push_back(tr);
depths.push_back(tr ? static_cast<int>(
GetMediaTrackInfo_Value(tr, "I_FOLDERDEPTH"))
: 0);
if (tr == track_) parentIndex = i;
}
for (int idx : directChildIndices(depths, parentIndex))
{
MediaTrack* child = tracks[static_cast<std::size_t>(idx)];
if (!child) continue;
// B_MAINSEND: "track sends audio to parent" (SDK header ~2238/~2957).
children_.push_back({child, GetMediaTrackInfo_Value(child, "B_MAINSEND")});
SetMediaTrackInfo_Value(child, "B_MAINSEND", 0.0);
}
const int receives = GetTrackNumSends(track_, kReceivesCategory);
receiveMutes_.reserve(static_cast<std::size_t>(receives < 0 ? 0 : receives));
for (int i = 0; i < receives; ++i)
{
receiveMutes_.push_back(
GetTrackSendInfo_Value(track_, kReceivesCategory, i, "B_MUTE"));
SetTrackSendInfo_Value(track_, kReceivesCategory, i, "B_MUTE", 1.0);
}
}
UpstreamIsolation::~UpstreamIsolation()
{
for (std::size_t i = 0; i < receiveMutes_.size(); ++i)
SetTrackSendInfo_Value(track_, kReceivesCategory, static_cast<int>(i),
"B_MUTE", receiveMutes_[i]);
for (const ChildSend& c : children_)
SetMediaTrackInfo_Value(c.track, "B_MAINSEND", c.mainSend);
}
} // namespace reasampler::capture