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:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
|
||||
// peaks implementation.
|
||||
//
|
||||
@@ -63,4 +64,31 @@ Envelope computeEnvelope(const std::vector<AudioSample>& interleaved,
|
||||
return envelope;
|
||||
}
|
||||
|
||||
std::size_t lastFrameAboveThreshold(const std::vector<AudioSample>& interleaved,
|
||||
std::size_t channelCount,
|
||||
std::size_t frameCount,
|
||||
AudioSample linearThreshold) {
|
||||
if (channelCount == 0) return kNoFrameAboveThreshold;
|
||||
|
||||
// Clamp to what the buffer actually holds — a caller frameCount that overstates
|
||||
// the buffer must never read past the end (mirror of computeEnvelope's guard).
|
||||
const std::size_t availableFrames = interleaved.size() / channelCount;
|
||||
const std::size_t frames = std::min(frameCount, availableFrames);
|
||||
if (frames == 0) return kNoFrameAboveThreshold;
|
||||
|
||||
// Scan backward: the first frame (from the end) whose loudest channel exceeds the
|
||||
// threshold is the last audible frame. `f` runs frames..1 so `f-1` never wraps.
|
||||
for (std::size_t f = frames; f > 0; --f) {
|
||||
const std::size_t frame = f - 1;
|
||||
const std::size_t base = frame * channelCount;
|
||||
AudioSample peak = 0.0f;
|
||||
for (std::size_t c = 0; c < channelCount; ++c) {
|
||||
const AudioSample a = std::fabs(interleaved[base + c]);
|
||||
peak = std::max(peak, a);
|
||||
}
|
||||
if (peak > linearThreshold) return frame;
|
||||
}
|
||||
return kNoFrameAboveThreshold;
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
|
||||
Reference in New Issue
Block a user