T2: realtime capture tail trimming
Auto/Manual/Off tail handling for realtime track-tap capture. Auto scans recorded PCM backward for last frame above -72 dB and truncates the wav header-aware (8 s cap); Manual pads a fixed tail; Off is byte-identical. wav_trim rejects WAVE_FORMAT_EXTENSIBLE with non-float SubFormat GUID.
This commit is contained in:
+38
@@ -66,4 +66,42 @@ Envelope computeEnvelope(const std::vector<AudioSample>& interleaved,
|
||||
std::size_t frameCount,
|
||||
std::size_t binCount);
|
||||
|
||||
// Sentinel returned by lastFrameAboveThreshold when NO frame in the scanned range
|
||||
// peaks above the threshold (pure silence at that level). SIZE_MAX is unambiguous:
|
||||
// no valid frame index can equal it (a real index is < frameCount <= SIZE_MAX for
|
||||
// any allocatable buffer), so the caller tests `== kNoFrameAboveThreshold` cleanly.
|
||||
inline constexpr std::size_t kNoFrameAboveThreshold =
|
||||
static_cast<std::size_t>(-1);
|
||||
|
||||
// Scans interleaved PCM BACKWARD for the last frame whose per-frame peak (the max
|
||||
// absolute value across all channels of that frame — NO stereo fold, just the
|
||||
// loudest channel that frame) exceeds `linearThreshold`, returning that frame index.
|
||||
// Returns kNoFrameAboveThreshold if no frame exceeds it (or on degenerate input).
|
||||
//
|
||||
// This is the boundary primitive behind the realtime tail's decay-scan trim
|
||||
// (docs/product/capture-tail.md §The realtime path): the recorded tail window is
|
||||
// scanned back from the end for the last frame still above -72 dB, and the file is
|
||||
// truncated one frame past it. Deliberately a separate primitive from
|
||||
// computeEnvelope — that answers "the min/max envelope over bins" (a thumbnail),
|
||||
// this answers "the last frame above a level" (a boundary). Bending the bin-oriented
|
||||
// envelope to a frame-exact boundary question is a worse fit (spec §option a).
|
||||
//
|
||||
// interleaved frame-interleaved samples: [f0c0, f0c1, ..., f1c0, f1c1, ...].
|
||||
// Must hold >= frameCount * channelCount; extra is ignored, and a
|
||||
// short buffer is clamped to what it actually holds (no OOB read).
|
||||
// channelCount channels per frame (the stride). The per-frame test is the max
|
||||
// |sample| over these channels — the frame is "above" if its
|
||||
// loudest channel is above the threshold.
|
||||
// frameCount frames to consider (the scan starts at the last of these).
|
||||
// linearThreshold the comparison level as a LINEAR amplitude ratio (e.g. the
|
||||
// -72 dB ratio from render_settings::autoTrimEndRatio), NOT dB.
|
||||
// A frame counts as above when its peak is STRICTLY > this.
|
||||
//
|
||||
// Pure, stdlib-only, unit-tested (a synthetic decaying ramp, silence, all-above,
|
||||
// and degenerate inputs) so the trim boundary math is locked outside the DAW.
|
||||
std::size_t lastFrameAboveThreshold(const std::vector<AudioSample>& interleaved,
|
||||
std::size_t channelCount,
|
||||
std::size_t frameCount,
|
||||
AudioSample linearThreshold);
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user