feat(take-lens): pack a take so it travels with its performance — and fix the trim PLN caught
Two things in one file, both from the same evening's practice recording. === PART 1: `pack` — the performance must travel with the audio (#106, #107) "ensure recordings have the midi too, keep this from blowing up tracking either ardour rec or compressing to avoid storing hours of no-move?" Today the audio is permanent and the performance is not. Ardour's sources live forever under the session; the MIDI and the track timeline sit in a gig-log directory that prune() deletes on a timer. So the 29862 CC events that explain take 94 were on a countdown while the audio they explain was not. `pack` writes a sidecar next to the audio: meta.json (window, sr, subtype, per-orbit peak dBFS, silent orbits, xrun delta, gear + boot state), midi.jsonl (every cc/note/track/mark record in the window, copied verbatim out of the log so pruning cannot reach it), and edl.json. The sidecar states its own honest limit in a field: gig-log COALESCES CC per (port, channel, controller) per second, keeping count + first/last/min/max. That is a faithful summary of a knob sweep and is what makes the log cheap, but a .mid rendered from it would be a reconstruction, not a recording. The JSONL is the truth. `--compress` then wavpacks every source and verifies each one with `wvunpack -vm` before reporting a single byte saved — an archiver that reports a ratio without checking is reporting a hope. The .wav is NEVER deleted; removal stays a separate human step after the take has been heard. FLAC was rejected outright: it cannot store 32-bit float, and routing through s32 would hard-clip the 8 orbits sitting over 0 dBFS while looking like a win on the silent one. Two measurement bugs found by running it on real data rather than trusting it: - xrun is a RUNNING TOTAL in gig-log's `s` records, not a per-tick delta (its own CUMULATIVE tuple exists for exactly this mistake). Summing it reported 58,668,469 xruns for a 21-minute take. Rebased to last-minus-first: 230, a real number. - Records are not events. A `cc` record is a one-second bucket carrying `n`, so printing the record count understated the performance 25x (1167 vs 29862). === PART 2: the trim threshold was protecting every bad transition PLN heard the first machine-trimmed mix and found the hole: "silence around 18 is not normal its a bad transition ahah in a real mixing work wed cut it proper and fade or at least trim most". The gap he heard WAS detected and reported, and survived anyway. SILENT_RUN_S was 20 s; the three gaps that made it into the mix measured 17 s, 18 s and 11 s. Every one sat just under the bar. A threshold chosen so the trimmer could never eat a musical break had silently become a threshold that preserves every failed transition instead. Three changes, all of them his rule rather than a tuning: 1. CLAMP, don't binary-cut. The bar drops to 10 s, but a detected silence is no longer removed whole — the last 2 s before the music resumes is kept as a breath. That is "or at least trim most" implemented literally, and it makes the lower threshold safe: the worst case if the rule fires on something musical is now a shortened rest, not a missing one. classify() computes both the detected region and the removed region so the report and the mixer cannot disagree. 2. FADE every seam. Every cut this tool had ever made was a butt-join, which in a live room is a click. Each removal now fades out into the cut and back in out of it over 250 ms, applied sample-accurately — the old mixer decided keep/drop per one-second block by its midpoint, quantising every boundary to +-0.5 s. Verified on the re-rendered take: max sample-to-sample step at the five seams is 0.0001-0.0029 against a p99.99 of 0.0562 for the take as a whole, i.e. the joins are 20-100x below ordinary musical transients. 3. BRIDGE blips. A dead patch is rarely clean end to end, and one orbit's tail crossing -60 dBFS for a second splits it into pieces that each fall under the bar. Only single-orbit blips are bridged: a real hit lights several orbits, and that is what keeps this from swallowing a one-shot. Result on take 94: 143 s trimmed instead of 119 s, all five gaps closed including the one at +18.0 min he named, output 18.75 min, peak -3.36 dBFS. === `selftest` Added because two of these rules could not be validated on real material — the bridge fires zero times on take 94 and a correct fade is inaudible by construction. A rule you have never seen fire is a hope, not a rule. It found a bug on the first run, in the test's own arithmetic: asserting "no span survives a multi-orbit hit" was wrong because the left half is exactly SILENT_RUN_S long and qualifies by itself. The property that actually matters is that no trimmed span ever CONTAINS a moment when the music was playing, and that is what it now asserts. Correction to a verification, worth recording: the first check of the re-rendered mix reported an 11 s silence still present. It did not exist. I measured the output against -60 dBFS while the mix carries a uniform -16 dB, so I was testing at an effective -44 dBFS at source. At the matched threshold exactly one rest over 4 s remains, 9.25 s, correctly left alone as musical. The right lens per control, again.
Showing
This diff is collapsed.
Click to expand it.
Please
register
or
sign in
to comment