-
fix(xfade): 4 cycles was too slow to work with — and the dip was real · 15695de4
PLN, mid-rehearsal on the last speaker session before OPAL: "atm when i work the track and change eg. a # gain 1.4 to # gain 1.5, it goes whole track all d1-d12 through fadedown-fadeup over a few bars?? its not ok, i cant adjust anymore." Then the good question: "fade d1 X -> d1 X should be constant, as each percent of volume removed from X is added to id?" He is right about the arithmetic and the rig breaks it in three places. WHY CROSSFADING A PATTERN WITH ITSELF DIPS 1. envEq/envEqR are EQUAL-POWER envelopes, g(t) = sqrt(sin(pi/2*t)), so g_in^2 + g_out^2 = 1. Correct — for a LINEAR gain stage. 2. SuperDirt's law is amp = gain^4. At the midpoint both sides sit at g = sqrt(0.7071) = 0.8409, so each half's amplitude is 0.8409^4 = 0.5 EXACTLY. The equal-power promise was made in the wrong domain. 3. `overlay` fires the same sample TWICE. Two coherent voices would sum 0.5 + 0.5 = 1.0 and be flat — that is PLN's model. What actually happens: orbit with `# cut N` 2nd voice releases the 1st (playSynths broadcasts the cut group BEFORE amplitude is read — the same mechanism as the 2026-07-29 ghost bug), one voice survives at amp 0.5 => -6 dB orbit without cut two independent voices, incoherent sum, sqrt(.5^2 + .5^2) = 0.707 => -3 dB + comb Deepest at t/2, unity again at t. With t=4 that is a four-bar swell on twelve orbits at once — because each dN is its own transition and ctrl-enter re-sends the whole blank-line-delimited block, all starting at the same `now`. Editing one `# gain` changes one line but evaluates twelve. THE STANDING CONCLUSION: an overlap crossfade can NEVER be transparent on a cut-group orbit. `cut` means "one voice in this group"; a crossfade means "two". Shortening the fade does not remove the dip, it makes it a blip instead of a swell. The dip-free answer is a NON-overlapping transition (`clutchIn`), which changes the feel of every seam in the set — so it waits for after OPAL (#13). This file's own comment guessed that in July; it is now measured, not guessed. CHANGES - xfade default 4 -> 1 cycle. One token, so it is one token to flip back. - xfadeCutIn gains a `t <= 0` branch returning the incoming pattern untouched. Needed before "0 = instant" can ever be offered: Tidal guards `_slow 0 _ = silence`, and `q |* gain silence` then has no right-hand values to match, so the INCOMING pattern comes out EMPTY. Unguarded, "0 cycles" means silence, not instant. Now `xfadeIn N 0 $ ...` is a real instant swap. - Killed a trap in this file's own guidance: it recommended `p N $ ...` for fast iteration. `p` carries no `|< orbit`, so the sound lands on orbit 0 — wrong LCXL column, wrong Ardour stem, fader that looks dead — the exact failure the lines above it warn about. Points at `jumpTo N` / `xfadeIn N 0` instead. VALIDATION: tools/check-boot.sh (safe mid-set, never grabs 6010) — helper block typechecks against tidal-1.9.5, all 13 g* helpers audible with an untouched controller, and the transition ghost check still reports 0 outgoing onsets after the fade. Takes effect at the next Tidal boot; nothing in the running session changed.PLN (Algolia) authored15695de4
×