feat(capture): M11 batch capture - one bank sample per selected item / razor area
Pure batch_capture module (plan + mixed-result aggregation, unit-tested); CAPTURE_BATCH_ITEMS/RAZOR actions with transient per-unit selection restored on all paths, per-unit invariants + provenance, single persist. Conform-on-insert already shipped.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// batch_capture.cpp — pure logic for M11 batch capture. See header.
|
||||
// NO REAPER types; unit-tested by tests/test_batch_capture.cpp.
|
||||
|
||||
#include "batch_capture.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
std::vector<CaptureUnit> planCaptureUnits(const std::vector<BatchRange>& ranges) {
|
||||
std::vector<CaptureUnit> units;
|
||||
units.reserve(ranges.size());
|
||||
int ordinal = 0;
|
||||
for (const BatchRange& r : ranges) {
|
||||
// Drop empty/inverted ranges — the offline backend refuses end<=start too, so
|
||||
// planning one would only manufacture a guaranteed per-unit failure. Ordinals
|
||||
// count kept units so the reported numbering is contiguous.
|
||||
if (!(r.endSeconds > r.startSeconds)) continue;
|
||||
++ordinal;
|
||||
units.push_back({ordinal, r.startSeconds, r.endSeconds});
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
void BatchOutcome::record(int ordinal, bool ok, std::string detail) {
|
||||
results_.push_back({ordinal, ok, std::move(detail)});
|
||||
}
|
||||
|
||||
std::size_t BatchOutcome::succeeded() const {
|
||||
return static_cast<std::size_t>(
|
||||
std::count_if(results_.begin(), results_.end(),
|
||||
[](const BatchUnitResult& r) { return r.ok; }));
|
||||
}
|
||||
|
||||
std::size_t BatchOutcome::failed() const {
|
||||
return results_.size() - succeeded();
|
||||
}
|
||||
|
||||
std::vector<BatchUnitResult> BatchOutcome::failures() const {
|
||||
std::vector<BatchUnitResult> out;
|
||||
for (const BatchUnitResult& r : results_)
|
||||
if (!r.ok) out.push_back(r);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string BatchOutcome::summaryLine(const std::string& noun) const {
|
||||
const std::size_t n = total();
|
||||
const std::size_t ok = succeeded();
|
||||
|
||||
if (n == 0)
|
||||
return "ReaSampler batch capture: nothing to capture.";
|
||||
|
||||
const std::string plural = (n == 1) ? noun : noun + "s";
|
||||
|
||||
if (ok == n)
|
||||
return "ReaSampler batch capture: " + std::to_string(ok) + " " +
|
||||
plural + " captured.";
|
||||
|
||||
// Mixed / all-failed: report the ratio and enumerate the failed ordinals so the
|
||||
// user knows exactly which units to retry. No partial corruption is implied —
|
||||
// each captured unit is a complete, independent bank sample.
|
||||
std::string line = "ReaSampler batch capture: " + std::to_string(ok) + " of " +
|
||||
std::to_string(n) + " " + plural + " captured (" +
|
||||
std::to_string(n - ok) + " failed: ";
|
||||
bool first = true;
|
||||
for (const BatchUnitResult& f : results_) {
|
||||
if (f.ok) continue;
|
||||
if (!first) line += ", ";
|
||||
line += "#" + std::to_string(f.ordinal);
|
||||
first = false;
|
||||
}
|
||||
line += ").";
|
||||
return line;
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
Reference in New Issue
Block a user