-
fix(boot): an UNTOUCHED "^NN" yields no events, not 0 — the real mute-bomb (#55) · 3685c743
The bug behind "no sound on d5 in perfect.tidal, meter moves, master silent, plays a bar then slowly fades to zero, then crackles". Also, finally, the true root of #21 — which was diagnosed as a missing `djfbus` and fixed as "safe at rest (0)", when the actual defect was one layer deeper. FINDING, proven by queryArc against an empty controls map (not by ear): gF1 $ sound "bd", knob never touched -> SILENT (no events) gMask untouched -> SILENT gMute3 untouched -> SILENT gain ("^77" * 1.3) untouched -> SILENT gPanic untouched -> SILENT A bare `"^NN"` whose CC has never arrived does NOT default to 0 — it yields NO EVENTS AT ALL. And `#` (i.e. `|>`) cannot emit without a value on its right-hand side, so the entire stream disappears. Every g*-wrapped stream in the corpus is therefore silent until that physical control is moved once. This is why "move all the controls" was always step one of a gig, and why PLN's rig felt fine for months: the habit was masking a mute-bomb. Today's BootTidal restart (to pick up the 77903244 DJF fix) wiped the control map and re-armed it across the whole surface at once — so the fix appeared to make things worse. It also explains the odd "plays one bar then slowly fades to zero": `dN` is `xfade N`, which crossfades the outgoing pattern out over 4 cycles while fading the new one in. The new one had no events, so what PLN heard was the OLD pattern dying gracefully into nothing — meter moving throughout, master quiet once the fade completed. The symptom looked like a filter closing; it was a crossfade to silence. TWO-LAYER FIX, because one layer cannot reach everything: 1. `orDef` in the helper let-block — substitutes a default when a control pattern is empty. Applied to gDJF (0.5 = centre = true bypass), midiOn/midiOff/midiNo/midiBoth (0/1/1/0 = "not pressed"), midiGGlobal (0.769, so *1.3 == unity rather than 0), and gPanic (0 = normal, not silent). It must live at the HELPER level, not per call site, because tracks combine controls arithmetically — `midiOn ("^34" - "^18")` in perfect.tidal:63 — and `touched - untouched` is itself empty, so a per-CC default could never catch it. 2. Boot-time control seeding via `setF` — the corpus-wide half. `orDef` cannot reach the 1860 sites across 343 track files that apply controls directly (`# crushbus 41 (range 16 3.5 "^53")`). Editing those is #46-scale work. Seeding every LCXL control at boot fixes all of them at once while touching no track file; a real CC overwrites its seed the instant the knob moves. Seed policy follows the authoring convention `range <neutral> <extreme>`, so 0 == neutral: A/B knobs 0, C1-C3 0.5 (DJF centre), C4-C8 0, fader 77 0.769 (unity), faders 78-84 1.0 (gains open = audible), all buttons 0. Seed coverage was verified by set-difference, not assumed: 49 seeded vs 54 distinct "^NN" in live/. The 5 stragglers were each resolved rather than waved off — ^45 needs no seed (it flows through midiOn, so orDef covers it), ^6 and ^61 are commented out at their only call sites, and ^1 (an external keyboard modwheel) and ^21 were added explicitly. Verification of the fix, all four knob positions, via an explicit controls map — untouched now bypasses and NO touched behaviour changed: untouched -> cutoff=20000 hcutoff=20 (was: SILENT) at 0.0 -> cutoff=180 hcutoff=20 (low-pass to subbass) at 0.5 -> cutoff=20000 hcutoff=20 (bypass) at 1.0 -> cutoff=20000 hcutoff=8000 (high-pass to superhigh) gMute3 pressed -> SILENT (mute still mutes) gPanic armed -> gain 0.0 (panic still panics) tools/check-boot.sh gains a second pass over the seed block (pinning the `streamSetF :: Stream -> String -> Pattern Double -> IO ()` signature it calls through), so neither half of this can rot silently. Its own first attempt at that pass was itself broken — a sed that produced `_seed = _seed = concat` — and the checker caught it. Same lesson as 77903244: run the guard, don't trust that you wrote it correctly. prelude.tidal (the stale-boot rescue sheet) carries the matching orDef form plus a ready-to-eval `_seedNow` list, for the case where a gig laptop boots silent and the cheapest fix is one paste rather than sweeping 40 controls.PLN (Algolia) authored3685c743
×