7.0 KiB
DAW verification — track-scope capture over a multi-track selection
What a DAW pass must establish for the multi-track track capture, and the exact numbers or strings to read off. Nothing below can be closed by a unit test: every item depends on what REAPER actually does with a render request.
Build to use. Release, installed into UserPlugins/, REAPER restarted — extensions
load at startup only. Set the docked panel's tail toggle to None before every cell;
Auto adds an 8 s window and Manual a fixed one, and both would invalidate the frame-count
readings.
Project to use. One saved project, project sample rate pinned to 48000. Two audio
tracks, A and B, each holding one item at least 30 s long, with audibly different
content (a tone on A, a drum loop on B). One folder track F with A and B as its
children, used only in §5.
1. The regression floor — single-track track capture is unchanged
Select track A only. Make a time selection from 10.000 s to 12.000 s. Run
ReaSampler: capture selected track(s).
Read off:
- A file appears in the project's bank folder, and one new card appears on the panel.
- The card's length reads 2.000 s; its frame count is 96000 (
round(12.0 × 48000) − round(10.0 × 48000)). The backend refuses the capture withBoundsMismatchif the render is more than one frame off that, so a landed capture already proves the number to ±1 — what you are confirming here is that it landed at all. - The REAPER console shows no
ReaSampler capture failed:line. - Track
Ais still the only selected track afterwards.
Repeat with a razor area on A over the same 10–12 s span and no time selection: same
three readings.
This is the byte-identical floor. If either cell now refuses, the change is wrong — the refusal must fire only above one track.
2. The defect cell — two selected tracks now refuse
Select A and B together. Time selection 10.000–12.000 s. Run capture selected
track(s).
Read off:
- The console prints exactly:
ReaSampler capture failed: A track capture renders the selected tracks through the master, and more than one track cannot land as a single file. Capture one track at a time, or route them into a folder/bus track and capture that (a folder's own output is its children summed). - No new card on the panel, and no new
.wavin the bank folder (check the folder directly — a stray file with nothing indexing it would mean the refusal fired too late). AandBare both still selected, both still unmuted, and neither track's fader, pan, or FX-bypass state changed. The refusal returns before any guard is constructed, so there should be nothing to restore — this reading is what confirms that.
Repeat with a razor area spanning both tracks and no time selection: identical
readings. Note that the track selection is what the refusal counts — a razor over two
tracks with only A selected is a one-track capture and must still succeed (§1).
3. The decisive observation — what &128 actually writes
This is the one that retires an inference, and it is the reason docs/TODO.md still
carries an entry. The refusal in §2 rests on reading the SDK header's single-file bit
&(4<<16) as applying to item/razor sources only, never to &128 — so N selected tracks
are believed to produce N files. That has never been observed.
Drive REAPER's own Render dialog by hand, with the extension out of the loop:
- Select
AandB. - File → Render. Source: Selected tracks (stems) — the dialog wording for
&128. Bounds: Custom time range, 10.000 to 12.000 s. - File name: a literal stem with no wildcards at all — e.g.
stemprobe. Clear$track/$item/ anything else from the pattern; the extension writes exactly one literal stem, so the probe must too. - Render to an empty scratch folder.
Read off — the file count in that folder:
- Two files (however REAPER disambiguated them, or one file that visibly got
overwritten): the inference holds, the §2 refusal is correct, and the
docs/TODO.mdentry can be closed by writing this observation intosrc/shell/capture/CLAUDE.mdas fact. - One file containing
AandBsummed (confirm by ear, or by nulling it against a master render of the same range with onlyAandBunmuted): the inference is wrong, the §2 refusal costs a working capture, and the track-scope half should be narrowed back per thedocs/TODO.mdentry. The item-scope half stays either way.
Also record what REAPER named the files — that decides whether a future correct multi-track capture could ever be built on this source at all.
4. Recapture replays the same answer
Take a single-track track capture that carries provenance (capture a range on A
whose source item is itself a bank sample, so detectParent fires), select its card, and
run re-capture from source. It must regenerate — same audio, same 96000 frames.
Then construct the multi-track case: a recorded recipe whose trackGuids names two
tracks. The reachable way to get one is to have captured it before this change; if no such
entry exists in any project, record that this cell was not exercised rather than
inventing one. When it is exercised, read off:
ReaSampler re-capture failed:followed by the same message text as §2.- The bank entry is untouched — same file, same hash, same card.
5. The way out actually works
Route A and B into folder F. Select F only, time selection 10.000–12.000 s,
capture track scope.
Read off: one card, 2.000 s, and the audio contains both A and B. This is what the
refusal message tells the user to do, so it has to be true.
6. Realtime still accepts a multi-track selection
Select A and B. Run ReaSampler: capture selected track(s) in realtime over the same
range. Read off: one card, and its audio contains both tracks. Realtime taps each
source track with a send into one temp track, so it sums where the offline render cannot —
the divergence from §2 is deliberate and this cell is what confirms it is real.
7. Mono collapse — what is and is not reachable
Capture a range on a track whose content is dead-center (a mono source panned center, or a duplicated-channel file). Read off:
- The panel card reports 1 channel.
- The console shows no
the lossless mono collapse ... landed intact, as captured.line.
Not DAW-reachable: the collapse's failure branch. It fires only if the captured file
cannot be read, or its temporary rewrite cannot be written or renamed, inside the same
call that just rendered the file — there is no manual way to inject that fault between the
render and the rename. The branch is covered only at its reporting seam
(tests/test_wav_codec.cpp, testCollapseOutcomesReportDistinctly), and its console line
has never been seen in a running REAPER. If you ever do see it, the capture in question is
intact and correctly measured — only the size win was lost.