Q-W3 review follow-ups: golden hash literal test, CLAUDE.md wav_codec bullet, dead RecordedCapture field comment, makeUniqueTag residual note
This commit is contained in:
@@ -64,7 +64,7 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde
|
||||
- `bank_book` — multi-bank registry: an ordered set of banks each wrapping a `BankIndex`. **Pool privileges (un-deletable/un-renamable/un-evacuable, never zero banks) enforced in-model.** Owns create/rename/reorder/delete of named banks, active-bank id, index-only move/copy/remove of a sample between banks, and JSON round-trip.
|
||||
- `owned_manifest` — the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so the prune path can distinguish the bank system's own orphans from hand-dropped files.
|
||||
- `app_version` — REAPER-free version/channel identity: CMake-sourced semver constant, ext-state stamp value, and the full set of channel-derived identity accessors. All channel strings derive from one `REASAMPLER_CHANNEL_IS_BETA` bit; no scattered `#ifdef`s in the shells.
|
||||
- `wav_trim` — 32-bit-float WAV parse + header-aware truncate plan for the realtime tail's PCM decay-scan trim.
|
||||
- `wav_codec` — chunk walker + layout parse + float32 build + size-field patch + content hashes; the single pure RIFF/WAV owner. (`wav_trim` is now a transitional forwarding alias onto `wav_codec`, kept only so the Q-W2v TUs it feeds compile untouched; retire it once that wave lands.)
|
||||
- `provenance` — capture-recipe fingerprint: build/encode/compare a `rsprov1` fingerprint of scope, range, tail, rate/channels, track GUIDs, and FX-chain identity. **A thin reproducibility fingerprint — NOT a serialized chain to restore.**
|
||||
- `prune_reconcile` — pure prune core: `pruneOrphans(present, referenced, owned)` computes `(owned ∩ present) − referenced`; the safety-critical "which files are orphans" decision, filesystem-free and hard-tested before any I/O exists. Gains `mergeReferenced(bankRefs, liveInstanceHeldPaths)` (pS-usage) — unions live instance holds into the prune referenced-set so the pure orphan computation includes them.
|
||||
- `prune_button` — pure layout/hit-test for the `bank_panel` footer Prune button.
|
||||
|
||||
@@ -114,6 +114,16 @@ struct RecordedCapture {
|
||||
std::vector<std::string> trackGuids;
|
||||
|
||||
int channelCount = 0;
|
||||
|
||||
// TEST-ONLY / dead in production (Q-W3 review follow-up): the shell no longer
|
||||
// populates these five fields before calling sampleFromRecordedCapture — the
|
||||
// finalize path (capture_realtime_finalize.cpp) leaves them at their defaults
|
||||
// and instead calls the shared stampCaptureSample(result.sample, ...) right
|
||||
// after, which writes Sample::sampleRate/captureTempo/captureTimeSigNum/
|
||||
// captureTimeSigDenom/createdTimestamp directly, overwriting whatever
|
||||
// sampleFromRecordedCapture set from these. Kept (not deleted) because the pure
|
||||
// unit tests still construct/assert them directly; removing the fields is a
|
||||
// struct-shape decision out of scope here.
|
||||
int sampleRate = 0; // 0 when the project rate was unknown (as offline)
|
||||
double captureTempo = 0.0; // BPM at capture time (shell reads Master_GetTempo)
|
||||
// Time signature at capture start (L7 F1; shell reads TimeMap_GetTimeSigAtTime).
|
||||
|
||||
@@ -239,6 +239,12 @@ std::string makeUniqueTag(const std::string& prefix) {
|
||||
// session distinct regardless of timing. NOTE: the tag varies the file NAME,
|
||||
// not the audio bytes — bit-identical-repeat is about identical *content* for
|
||||
// identical requests; two deliberate captures naturally live in two files.
|
||||
// RESIDUAL (Q-W3 review follow-up): the counter is per-process, starting over
|
||||
// at 0 on every REAPER launch/extension reload, so two separate REAPER
|
||||
// instances (or a reload mid-session) can still mint the same timestamp+counter
|
||||
// pair in the same wall-clock second — a same-second cross-process collision
|
||||
// remains theoretically possible. Scoped to per-session deliberately: this fix
|
||||
// targets the reachable-in-practice single-process batch-capture case above.
|
||||
static std::atomic<unsigned long long> counter{0};
|
||||
const std::time_t now = std::time(nullptr);
|
||||
return prefix + std::to_string(static_cast<long long>(now)) + "-" +
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
// extraction (whole / tail window / clamp / out-of-range); truncate plan (kept<all,
|
||||
// no-op keep-all, kept==0, grow rejected) with exact size-field values; patchU32LE;
|
||||
// buildFloat32Wav golden header + parse round-trip; hashBytes/hashWavContent
|
||||
// determinism, metadata-skip, fallback, and domain separation.
|
||||
// determinism, metadata-skip, fallback, and domain separation; a golden hash
|
||||
// literal pinning exact hex output for a fixed input (guards persisted
|
||||
// contentHash values against a silent feed-sequence drift).
|
||||
|
||||
#include "../src/core/capture/wav_codec.h"
|
||||
|
||||
@@ -576,6 +578,21 @@ static void testHashMatchesBuildOutput() {
|
||||
CHECK(hashWavContent(wav) == hashWavContent(withMeta));
|
||||
}
|
||||
|
||||
// Golden hash literal (review follow-up, Q-W3): the tests above prove format,
|
||||
// determinism, and relational properties (equal/different) of hashBytes and
|
||||
// hashWavContent, but none of them pins the actual output bytes — a feed-sequence
|
||||
// change (e.g. dropping the 'W' domain-separation prefix, or reordering the
|
||||
// fmt/data feed) would pass every test above while silently invalidating every
|
||||
// contentHash already persisted in existing projects' BankIndex JSON. This test
|
||||
// locks a fixed buildFloat32Wav input's hashes against exact hex literals
|
||||
// captured from the current implementation, so any such drift fails loudly here.
|
||||
static void testGoldenHashLiterals() {
|
||||
const std::vector<double> pcm = {0.0, 0.5, -0.25, 1.0, -1.0, 0.125};
|
||||
auto wav = buildFloat32Wav(2, 48000, 3, pcm);
|
||||
CHECK(hashWavContent(wav) == "7ccf298c166a670a");
|
||||
CHECK(hashBytes(wav.data(), wav.size()) == "68d8a193c958fd44");
|
||||
}
|
||||
|
||||
int main() {
|
||||
testParseCanonicalStereo();
|
||||
testParseMonoAndLeadingChunk();
|
||||
@@ -600,6 +617,7 @@ int main() {
|
||||
testHashWavContentListMetaSkipped();
|
||||
testHashWavContentDomainSeparationFromWholeFile();
|
||||
testHashMatchesBuildOutput();
|
||||
testGoldenHashLiterals();
|
||||
|
||||
if (g_fail == 0) std::printf("wav_codec: all tests passed\n");
|
||||
else std::printf("wav_codec: %d CHECK(s) FAILED\n", g_fail);
|
||||
|
||||
Reference in New Issue
Block a user