-- ParVagues live prelude — RESCUE SHEET (was: TRY blocks, nucleus of the #23 lib)
--
-- ✅ ALL THREE BLOCKS BELOW ARE NOW BAKED INTO BootTidal.hs (2026-07-25).
--    A fresh Tidal boot already has safe gF1/2/3, xfade-dN + jumpTo, and gPanic.
--    You do NOT need to eval this file in a normal session anymore.
--
-- KEEP IT for one reason: it is the hot-patch if you ever find yourself on a
-- STALE boot mid-set (an old ghci still alive, a machine that didn't pick up
-- the new BootTidal.hs, a borrowed laptop). Symptom: push fader 49 and the
-- sound MUTES instead of sweeping ⇒ you're on the old djfbus gF.
-- Rescue: open this file, Ctrl-Enter inside each :{ … :} block. These shadow
-- the boot defs in the running session — no reboot, no lost patterns.
--
-- BootTidal.hs is the source of truth. If you change a def here, change it
-- there too, or delete it here.

-- =====================================================================
-- #21, #48 — SAFE-AT-CENTRE bidirectional DJ filters (gF).  Corrected
-- 2026-07-27 mid-rehearsal: these three knobs (C1/C2/C3, CC49/50/51)
-- are DJ-mixer-style filters — centre = no filtering, sweep down =
-- low-pass closing in (subbass only), sweep up = high-pass climbing
-- (superhigh only). The 2026-07-25 fix made rest(0)=bypass but only as
-- two separate one-directional controls; this makes each knob its own
-- full bidirectional sweep, safe AT THE CENTRE instead of at 0 (an
-- untouched knob's rest position ≈ centre detent, so this is still the
-- same "untouched = no effect, ever" guarantee from #21, just recentred).
-- =====================================================================
:{
let orDef d p = Pattern $ \st -> case query p st of { [] -> query (pure d) st; es -> es }
    gDJF ch = (# lpf (range 180 20000 (fmap (\v -> 1 - 2 * max 0 (0.5 - v)) (orDef 0.5 ch))))
            . (# hpf (range 20   8000  (fmap (\v -> 2 * max 0 (v - 0.5))     (orDef 0.5 ch))))
    gF1 = gDJF "^49"    -- knob C1 = DJ filter (centre=open, left=lpf/subbass, right=hpf/superhigh)
    gF2 = gDJF "^50"    -- knob C2 = DJ filter, same shape
    gF3 = gDJF "^51"    -- knob C3 = DJ filter, same shape
:}
-- try:  d1 $ gF1 $ sound "bd*4"     then sweep knob 49 both ways — bypass at centre.
-- (Old broken form was:  gF1 = (# djfbus 1 (range 0.05 0.95 "^49"))  — do not use.)
--
-- #55 — INSTANT RESCUE if a fresh boot is SILENT on every gF/midiOn stream.
-- An untouched "^NN" yields NO EVENTS (not 0), and `#` can't emit without a
-- right-hand value, so the stream vanishes. Two ways out, cheapest first:
--   1. Move every knob/button once. (This is why "move all the controls" was
--      always step one — the habit was masking this bug.)
--   2. Or eval this one-liner to seed the whole surface at once:
:{
let _seedNow = concat [ [ (show n, 0)   | n <- [13..20] ++ [29..36] ++ [52..56]
                                            ++ [41..44] ++ [57..60]
                                            ++ [73..76] ++ [89..92] ++ [93] ]
                      , [ (show n, 0.5) | n <- [49,50,51] ]
                      , [ ("77", 0.769) ]
                      , [ (show n, 1)   | n <- [78..84] ] ] :: [(String, Double)]
:}
-- then:   mapM_ (\(k,v) -> setF k (pure v)) _seedNow


-- =====================================================================
-- #13 — DEFAULT-XFADE track launches.  Every dN now crossfades in over
-- 4 cycles AND keeps its orbit (the old `xfade N` lost the orbit → sound
-- landed on the wrong LCXL column / Ardour stem).  Fits the livemidi
-- model: dN evals are track LAUNCHES, so auto-xfade has ~zero downside
-- and makes every track→track move a clean crossfade with no code edit.
--   d1 $ <track A>   … then later …   d1 $ <track B>   ⇒ B xfades over A.
-- To hard-cut instead, use  jumpTo 1 $ …  (defined below, orbit-correct).
-- =====================================================================
:{
let d1  = xfade 1  . (|< orbit 0)
    d2  = xfade 2  . (|< orbit 1)
    d3  = xfade 3  . (|< orbit 2)
    d4  = xfade 4  . (|< orbit 3)
    d5  = xfade 5  . (|< orbit 4)
    d6  = xfade 6  . (|< orbit 5)
    d7  = xfade 7  . (|< orbit 6)
    d8  = xfade 8  . (|< orbit 7)
    d9  = xfade 9  . (|< orbit 8)
    d10 = xfade 10 . (|< orbit 9)
    d11 = xfade 11 . (|< orbit 10)
    d12 = xfade 12 . (|< orbit 11)
    -- orbit-correct HARD CUT (when you DON'T want the 4-cycle blend):
    jumpTo i = case i of
        1  -> jump 1  . (|< orbit 0);   2  -> jump 2  . (|< orbit 1)
        3  -> jump 3  . (|< orbit 2);   4  -> jump 4  . (|< orbit 3)
        5  -> jump 5  . (|< orbit 4);   6  -> jump 6  . (|< orbit 5)
        7  -> jump 7  . (|< orbit 6);   8  -> jump 8  . (|< orbit 7)
        9  -> jump 9  . (|< orbit 8);   10 -> jump 10 . (|< orbit 9)
        11 -> jump 11 . (|< orbit 10);  12 -> jump 12 . (|< orbit 11)
        _  -> p i
:}
-- NOTE: while these xfade-dN are active, an *in-track tweak* also blends over
-- 4 cycles (not instant). That's fine for launches; if you're iterating fast on
-- one line, re-eval the plain BootTidal defs (or use  p N $ …  for an instant set).


-- =====================================================================
-- PANIC CHORD — kills the tedium of composing/testing.  Hold LCXL push
-- buttons 73+74+91+92 TOGETHER; the SC bridge (start_and_midi.scd) detects
-- the chord (edge-triggered, since these are momentary Note buttons) and
-- flips a PERSISTENT "^93" toggle, echoed on the LCXL LEDs (lit = active).
-- Tidal side is just a plain 0/1 gate — wire it wherever you want silence
-- while testing. Not applied to any track by default (your call which
-- streams it should mute) — try on whichever you're actively composing:
-- =====================================================================
:{
let gPanic = (# gain (range 1 0 "^93"))  -- ^93=0 normal, ^93=1 silent (gain 0)
:}
-- try:  d1 $ gPanic $ gF1 $ gMute2 $ sound "bd*4"
-- hold 73+74+91+92 -> instant silence + LEDs light; hold again -> back, LEDs off.
-- Wire gPanic into whichever track(s) you're iterating on while composing.
-- To make xfade length live-controllable later:  xfadeIn N <cycles> $ pat.
