Files
reasampler/src/shell/capture/capture.h
T

116 lines
5.2 KiB
C++

#pragma once
// The shared capture seam: CaptureRequest/CaptureResult (types both backends
// speak), OfflineRenderBackend, and the makeUniqueTag/stampCaptureSample helpers.
// Realtime's async begin/tick/abort surface lives in capture_realtime_shell.h.
//
// REAPER-free on purpose (bank_model only) so callers can depend on the seam
// without dragging the SDK into every include site; the .cpp is the REAPER TU.
#include <string>
#include <vector>
#include "core/model/bank_model.h"
#include "core/capture/render_settings.h" // TailMode — the three-state tail contract
// Forward-declared, never dereferenced here — only the REAPER-facing .cpp touches these.
class MediaTrack;
class ReaProject;
namespace reasampler::capture {
using model::Sample;
// 32-bit float is the default; rationale lives in capture.cpp next to the sink-config bytes.
enum class WavBitDepth {
Int16,
Int24,
Float32,
};
// One capture, independent of source mode.
struct CaptureRequest {
SourceMode sourceMode = SourceMode::MasterMix;
// Sample-accurate render bounds in project seconds — NO rounding.
double startSeconds = 0.0;
double endSeconds = 0.0;
// 1.0 = fully wet, 0.0 = fully dry. Every current capture action sets 1.0;
// true pre-FX dry isn't available via RENDER_SETTINGS (needs FX-bypass-around-render
// or the realtime pre-FX path) so this stays a seam for that future work.
double wetDry = 1.0;
// Track GUID(s) when source mode is track-scoped (SelectedTracks); empty otherwise.
// The backend only copies these onto the Sample — it never reads selection itself.
std::vector<std::string> trackGuids;
// Render tail (docs/product/capture-tail.md §The three tail states). None = exact
// bounds, no added silence — the only mode valid for null-test/verify captures.
// tailMs applies only to Manual (clamped to 8s by the pure mapping); Auto uses
// the 8s cap + -72 dB trim internally, None ignores it.
TailMode tailMode = TailMode::None;
double tailMs = 0.0;
// 0 sampleRate => follow project rate.
int sampleRate = 0;
int channelCount = 2;
WavBitDepth bitDepth = WavBitDepth::Float32;
// Sanitized by capture_paths. uniqueTag (disambiguator) is supplied by the
// backend caller so the pure naming logic stays testable.
std::string baseName = "capture";
std::string uniqueTag;
};
// Every failure is an explicit code, never a thrown exception across the REAPER boundary.
enum class CaptureStatus {
Ok,
NoProject, // no active project to render / resolve a bank folder
EmptyRange, // start >= end: nothing to render
UnsupportedMode, // backend does not implement this source mode
UnsupportedFormat, // requested bit depth has no known REAPER blob (Float32 only)
RenderFailed, // the render action ran but produced no output file
TransportBusy, // realtime backend: transport already playing/recording — refused
MultiTrackRange, // a ranged item capture whose items span >1 track — would render N files
BoundsMismatch, // the rendered file's frame count is not the requested window's
};
struct CaptureResult {
CaptureStatus status = CaptureStatus::RenderFailed;
Sample sample; // valid only when status == Ok
std::string message; // human-readable detail for the console log
};
// Deterministic offline-render backend: master mix / time selection / selected
// tracks / selected items / razor area, all wet-only, optional tail. Source
// selection + range are resolved by the caller and handed in via CaptureRequest —
// the backend drives RENDER_* and never reads the DAW selection itself.
// SourceMode::Realtime returns UnsupportedMode. Non-destructive: restores every
// RENDER_* setting it touches on every path. Plain concrete class — see the
// no-shared-interface note in capture_realtime_shell.h before adding one back.
class OfflineRenderBackend {
public:
CaptureResult capture(const CaptureRequest& request);
};
// Mints the filesystem-safe disambiguating tag for one capture's file stem +
// Sample id: "<prefix><unix-epoch-seconds>-<n>", <n> a per-session monotonic
// counter. Wall-clock seconds alone collide when batch capture drives short
// renders back-to-back, silently overwriting the first file. `prefix` is the
// backend's family marker ("" offline, "rt-" realtime).
std::string makeUniqueTag(const std::string& prefix);
// Stamps the metadata shared by both backends onto `s`: trackGuids + channelCount
// (echoed from the request), resolved sampleRate (request rate, else PROJECT_SRATE
// from `rateProj`), captureTempo, the capture-start time signature
// (TimeMap_GetTimeSigAtTime against `timeSigProj` — offline passes nullptr for the
// active project, realtime pins the record's own project), the WAV-aware
// contentHash of `absolutePath` (left empty when unreadable), and createdTimestamp.
// Per-backend bits (id, paths, bounds, tier, realtime's length override) stay
// with each caller.
void stampCaptureSample(Sample& s, const CaptureRequest& req,
ReaProject* rateProj, ReaProject* timeSigProj,
const std::string& absolutePath);
} // namespace reasampler::capture