Merge Ψ-W2-T2: a bit-identical capture collapses to one lossless mono channel

# Conflicts:
#	src/shell/capture/CLAUDE.md
#	src/shell/capture/capture.cpp
#	src/shell/capture/capture.h
This commit is contained in:
2026-08-01 22:23:06 -04:00
14 changed files with 444 additions and 22 deletions
+18 -4
View File
@@ -1,6 +1,7 @@
#pragma once
// The shared capture seam: CaptureRequest/CaptureResult (types both backends
// speak), OfflineRenderBackend, and the makeUniqueTag/stampCaptureSample helpers.
// speak), OfflineRenderBackend, and the helpers both backends share (naming, the
// mono collapse, the Sample stamp).
// 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
@@ -54,6 +55,9 @@ struct CaptureRequest {
// 0 sampleRate => follow project rate.
int sampleRate = 0;
// What the RENDER is asked for (RENDER_CHANNELS / the realtime record mode), not
// what the capture lands as: a dual-mono render is collapsed to 1 channel after
// the fact, and the Sample's count comes from the produced file.
int channelCount = 2;
WavBitDepth bitDepth = WavBitDepth::Float32;
@@ -118,9 +122,19 @@ std::string makeUniqueTag(const std::string& prefix);
CaptureName captureNameFor(const std::vector<std::string>& sourceNames,
int ordinal, const std::string& fallback);
// 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
// Rewrites a just-captured WAV in place as a 1-channel file when its channels are
// bit-identical (the pure `collapseToMono` decides). Every other file is left
// untouched, byte for byte, so the not-collapsed path is exactly what the backend
// produced. Must run BEFORE stampCaptureSample, which measures the landed file.
// Returns whether the file was actually rewritten (collapsed AND the write landed) —
// callers use it to make the collapse observable in the reported CaptureResult.
bool collapseCapturedFileToMono(const std::string& absolutePath);
// Stamps the metadata shared by both backends onto `s`: trackGuids (echoed from the
// request) + channelCount (measured from the produced file's `fmt`; 0/unknown as the
// fallback for a file that cannot be parsed — never the request's value, which is
// always 2 and was never actually measured), 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.