116 lines
5.2 KiB
C++
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
|