Commit 98d073f2 by PLN (Algolia)

fix(boot): bake the live-validated prelude into BootTidal.hs — disarm the gF mute-bomb permanently

The problem: `gF1/gF2/gF3` in BootTidal.hs sent a value into `djfbus`, which is
NOT a registered SuperDirt effect. The LCXL faders REST AT 0, so every gF-wrapped
stream shipped an extreme value into a missing bus the moment it was launched —
sound muted mid-set with no way back. Every mature ParVagues track wraps its
streams in gF1/gF2/gF3, so this was armed on essentially the whole set.

It was fixed and live-confirmed on 2026-07-25 ("f123 djfs seem to work great
overall") — but only as a shadow-eval from live/lib/prelude.tidal. That fix lived
in the running ghci and nowhere else: one SuperCollider reboot before OPAL and the
footgun rearmed itself silently. J-10 is the wrong time to depend on remembering
to eval a file.

Approach — three blocks promoted from prelude.tidal into the boot file:

1. SAFE-AT-REST global filters. Swap the phantom djfbus for CORE params that are
   always registered, mapped so fader-rest(0) == BYPASS:
     gHPF = range 20 8000   (rest ⇒ hpf 20, effectively open)
     gLPF = range 20000 180 (rest ⇒ lpf 20k, effectively open)
   gF3 is now literally `id` — a spare fader that cannot touch sound at all.
   Untouched ⇒ no effect, ever. Fader up ⇒ the filter sweeps in. Cannot mute you.

2. DEFAULT-XFADE dN launches. d1-d12 become `xfade N . (|< orbit N-1)`. The orbit
   composition is the load-bearing part: a naive `xfade N` DROPS the orbit that dN
   bakes in, so transitions landed on the wrong LCXL column and the wrong Ardour
   stem. Added an orbit-correct `jumpTo N` for hard cuts. d13-d16 deliberately
   stay plain `p` — orbit 13 is the tidal-ears capture vsink and must not blend.

3. gPanic — the ^93 gate the start_and_midi.scd panic-chord (73+74+91+92) flips.

Validation: type-checked in a throwaway ghci against the real tidal-1.9.5 install.
All signatures resolve as intended — gF1/gF2 :: Pattern ValueMap -> Pattern ValueMap,
gF3 :: a -> a (proving the safe identity), d1 keeps its original
Pattern ValueMap -> IO () shape so no track file needs an edit, d13 stays
ControlPattern -> IO (), jumpTo :: ID -> Pattern ValueMap -> IO ().

prelude.tidal is demoted from "source of truth we forgot to promote" to an
explicit RESCUE SHEET: it now documents the stale-boot symptom (push fader 49,
sound mutes instead of sweeping) and stays evaluable as an in-session hot-patch.
One source of truth, one less thing to remember mid-set.
parent 29ce1039
......@@ -114,18 +114,38 @@ let p = streamReplace tidal
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
-- DEFAULT-XFADE track launches (#13). Every dN crossfades in over 4
-- cycles AND keeps its orbit. The naive `xfade N` LOSES the orbit that
-- dN bakes in → sound lands on the wrong LCXL column / Ardour stem, so
-- the `(|< orbit N-1)` must stay composed in here. Fits the livemidi
-- model: dN evals are track LAUNCHES, so auto-blend has ~zero downside
-- and makes every track→track move clean with no code edit.
-- d1 $ <track A> … later … d1 $ <track B> ⇒ B xfades over A.
-- For an INSTANT set (fast iteration on one line) use p N $ …
-- For an orbit-correct HARD CUT use jumpTo N $ … (below).
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
-- d13-d16 stay plain `p` (no orbit offset): utility/capture streams,
-- orbit 13 is the tidal-ears capture vsink — do NOT give these xfade.
d13 = p 13
d14 = p 14
d15 = p 15
......@@ -281,10 +301,28 @@ let -- DPV specific parameters
midiG' ch l h = _gainG (range l h ch) -- midiGain control
midiGdef = midiG' 1 0 1 -- midiGain default
midiG ch = midiG' ch 0 1 -- midiGain default
-- Global filters
gF1 = (# djfbus 1 (range 0.05 0.95 "^49"))
gF2 = (# djfbus 2 (range 0.05 0.95 "^50"))
gF3 = (# djfbus 3 (range 0.05 0.95 "^51"))
-- =============================================
-- Global filters (#21) — SAFE-AT-REST
-- The old form was gF1 = (# djfbus 1 (range 0.05 0.95 "^49")) and it
-- was a live footgun: `djfbus` is NOT a registered SuperDirt effect, and
-- the LCXL fader RESTS AT 0 → every gF-wrapped stream got an extreme
-- value into a missing bus → sound muted mid-set with no way back.
-- Fix: use CORE params (hpf/lpf, always registered) mapped so that
-- REST (fader down = 0) == BYPASS. Untouched ⇒ no effect, ever.
-- Push a fader up ⇒ the filter sweeps in. Cannot mute you.
-- Live-confirmed 2026-07-25 ("f123 djfs seem to work great overall").
-- =============================================
gHPF ch = (# hpf (range 20 8000 ch)) -- fader up ⇒ high-pass climbs; rest(0)=hpf 20 ≈ open
gLPF ch = (# lpf (range 20000 180 ch)) -- fader up ⇒ low-pass closes; rest(0)=lpf 20k ≈ open
gF1 = gHPF "^49" -- CC49 fader = high-pass build (tension riser)
gF2 = gLPF "^50" -- CC50 fader = low-pass sweep (muffle/drop)
gF3 = id -- CC51 spare, held safe (id = never touches sound)
-- PANIC CHORD (#34) — hold LCXL push buttons 73+74+91+92 together; the SC
-- bridge (start_and_midi.scd) edge-detects the chord and flips a persistent
-- "^93" toggle, echoed on the LCXL LEDs (lit = active). Tidal side is just
-- a plain 0/1 gain gate. Not applied to any stream by default — wrap it on
-- whichever track you're actively composing: d1 $ gPanic $ gF1 $ …
gPanic = (# gain (range 1 0 "^93")) -- ^93=0 normal, ^93=1 silent
-- Global masks (defaults)
gMask = (midiOn "^41" (mask "t!7 f"))
gMute1 = (midiOn "^73" (mask "f*16"))
......
-- ParVagues live prelude — TRY blocks (nucleus of the #23 lib)
-- Open in Pulsar, eval a block (Ctrl-Enter inside the :{ … :}) to try it LIVE.
-- These shadow the BootTidal.hs defs in the running session — no reboot needed.
-- Once a block feels right, we bake it into BootTidal.hs (or load this file at boot).
-- 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 — SAFE global filters (gF). The footgun: `djfbus` is NOT a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment