- 27 Jul, 2026 3 commits
-
-
Rehearsal/play session on the UMC rig (SOF->UMC migration validated end to end tonight): electric_hammer, bombe_dj, ete_a_mauerpark, vague_de_crime, gimme_acid, take_5_drops tuned; raph collab tracks (desire, mafia_sans_serif, piment_bresilien) touched; backlog.md and armada calibration catalogs regenerated alongside. Committing as a clean checkpoint before starting the d1-d12 channel harmonization + LCXL fader remap (task #46) and the sample/synth reference cleanup (task #45), so those land as reviewable diffs against a known-good base rather than mixed in with tonight's live tuning.
PLN (Algolia) authored -
Archives #38, #39, #40 with full learnings, per the document-as-you-go discipline. The thread: the onboard SOF codec stopped answering IPC mid-session and took the whole audio stack down with it — WirePlumber wedged in uninterruptible D-state inside ipc3_tx_msg_unlocked, unkillable by SIGKILL, scsynth dead, reboot the only exit. That escalated the UMC202HD from "nice upgrade" to "resilience fix", and the move onto it is now done: default sink switched, the SOF internal DMIC (card3 pcm4c, the exact PCM that hung) disabled by a scoped WirePlumber rule that leaves all five SOF playback sinks alone. The archive's real value is the pattern that runs through all three entries. Every failure this session had the same shape: a binding resolved once at startup, invalidated by a device event, failing with NO error surfaced. Ardour's master port (twice — it restores its own saved ports and ignores the default sink, then loses the link entirely on a wireplumber restart). SuperCollider's cached MIDIOut after a replug moved the LCXL 20:0 -> 24:0. The HUD's aseqdump, still ALIVE on the dead port, which is why its respawn-on-death recovery never fired — liveness is not health. And the session layer itself: after an overnight suspend the UMC re-enumerated 118 times, came back healthy at the hardware level, and WirePlumber simply never rebuilt its node. Also recorded: a wireplumber restart resets sink volume to the device default (87%), which turned a routine verification tone into a painfully loud one. Attenuate before making sound, always. Corrected doctrine while here — commits belong on master by default. PLN is a lone dev who reviews his own work; branches are for cloud agents, parallel sessions and genuine prototypes. The memory claiming otherwise was wrong and cost real time.
PLN (Algolia) authored -
The LED work (#11) had been stuck for two days on "some nonzero value lights it", with no reliable palette and buttons that refused to light at all. Today's live session found out why, and it was not a bug in our code. THE ROOT CAUSE. The Launchpad Note-On protocol only lights a control if the CURRENTLY SELECTED template maps that exact note/CC on that exact MIDI channel. On User 1 the LCXL's buttons are CC-mapped, so every Note-On we sent to notes 73/74/91/92 had no matching target and was silently discarded. The knobs are note-mapped, which is why they lit and the buttons never did — a split that looked like flaky hardware and was actually the protocol working as documented. THE FIX. The SysEx "Set LEDs" message updates any control regardless of its note/CC value or MIDI channel: F0 00 20 29 02 11 78 <template> <index> <value> [<index> <value> ...] F7 Verified on hardware: top button row went red and bottom row green on the first try, after Note-On had failed on those same buttons all morning. Indices are contiguous (00-07/08-0F/10-17 knob rows, 18-1F and 20-27 button rows, 28-2B side, 2C-2F arrows), which is far easier to generate role-family colours over than the scattered note numbers. PALETTE, MEASURED NOT GUESSED. colour = (16 * green) + red + flags, each channel 0-3, flags 12 normal / 8 flashing. Confirmed by lighting the top knob row with the full ramp and having PLN read the colours back left to right: off, red low, red full, green low, green full, amber low, amber full, yellow — matching the Programmer's Reference table exactly. Also ran the built-in brightness tests (B0 00 7F / 7D): all-orange then all-dim-yellow, which proves the unit is NOT in low-power mode and that dim-vs-full is simply hard to read by eye. Conclusion for the design: use FLASH, not brightness, when a state must be unmissable. STALE-BINDING FIX. ~lcxlOut was resolved once at boot. A replug moves the ALSA port (we watched it go 20:0 -> 24:0) and the cached MIDIOut then points at a device that no longer exists — LEDs die silently while input keeps working. It now re-resolves lazily on every write, and drops the cache on error so the next write retries. Added ~lcxlReconnect for explicit post-replug recovery, kept manual on purpose: MIDIClient.init re-scans the whole MIDI world and is not something to fire mid-set on a guess. This is the fourth instance today of one failure shape: a device binding resolved once at startup, invalidated by a device event, failing with NO error. The others were Ardour's master port (twice) and the HUD's aseqdump sitting alive on a dead port. Tracked in #41. Validation: delimiter balance checked; full compile is proven at the next SC boot, not before — deliberately not restarting SuperCollider mid-rehearsal.
PLN (Algolia) authored
-
- 26 Jul, 2026 1 commit
-
-
Two findings, one of which unblocked a task that had been stuck on a false premise. THE FALSE PREMISE. visuals/slop/README.md said Slopmotion was "not installed here yet — this is the real blocker", after a thorough machine search on 2026-07-25. That was wrong. Kevin Granger IS Shipow (git log on the repo shows both identities authoring the same commits), so Slopmotion is hydra-live-hexa — a registered working directory of this workspace all along. Task #28 was blocked on nothing. The lesson worth keeping: resolve the PERSON before concluding the SOFTWARE is missing. README corrected in place, with the wrong claim quoted rather than silently deleted. WHAT THAT UNLOCKS. Everything needed to generate is already on disk, no network at all: 764 loop mp4s across 23 playsets (including a `parvagues` pack of PLN's own imagery); a 24-pack catalog in src/data/playsetPacks.json which is a generated snapshot of the online Supabase `packs` table; playwright 1.60 + chromium; and a working headless harness to copy in scripts/capture_fx_previews.mjs. This matters because the online route is CLOSED: shipow.io is NXDOMAIN, hydra-live-hexa.vercel.app returns DEPLOYMENT_NOT_FOUND, and .env carries only HEXA_LOGIN/HEXA_PASS with no VITE_SUPABASE_URL — so the DB can't be reached from here, and doesn't need to be. THE PLANNER. visuals/slop/plan_clips.py joins three sources to answer "which shareable clips can we make right now, for tracks actually in the OPAL set?" Answer: 7 of 13. - setlist from backlog.md § OPAL 2026, with MEASURED setcps from the BPM-arc doc rather than the backlog's annotations (which were wrong on three tracks). - recordings = Take89 (Montreuil Algorave V3, 2026-05-22): PLN-ear-validated boundaries, plus per-track peak-anchored 30s/90s promo_cuts already computed by the drops detector. - visuals = the playset catalog. Cuttable: WAP, Take 5 Drops, Piment Bresilien, Mafia, Sunshine, Desire, Revolution. The 6 that aren't (Bombe, Doing it Right, Perfect, Gimme Acid, Vague de CRIME, Electric Hammer) are the newer/reworked tracks with no Take89 take — they need a fresh recording, which gig_record.sh will produce at the next rehearsal or at OPAL itself. Playset/FX pairing is driven by MEASURED features, not vibes: tilt_mean (spectral tilt) picks the dark/mid/bright playset family, kick_density_p70 decides whether the chain is trigger-heavy (jumpCut/vibration/flash on kick) or breathing (liquix/wetLens/slowmo), and ssm_novelty_max sets the Automix interval. Thresholds are the terciles of THIS set's observed range (tilt 0.13..0.54, kick 1.75..3.75), so they split real material rather than an abstract scale. The one frankly aesthetic layer — which pack names read as "dark" vs "bright" — is marked as such in the source. VALIDATION. Master-timeline offsets cross-check against an independent source: the planner derives Desire's track start from the studio bundle's boundaries_ground_truth.json and lands on 2926s, which is exactly the 48:46 cut in armada's separately-authored boundaries_take89_validated.json. Two files, two provenances, same number. Renderer (audio slice + playset -> mp4 via the real Hydra engine) is NOT built yet.PLN (Algolia) authored
-
- 25 Jul, 2026 17 commits
-
-
The /pre-compact ritual archives completed board tasks somewhere durable before clearing them, so the learnings survive the task disappearing. armada/tasks/ completed-archive.md already does this — but its header scopes it explicitly to L'Armada, the media/marketing toolbox. Gig prep is a different thread, and mixing two documentary trails in one file makes both worse to mine later. Same discipline, separate file. Seven finished tasks captured in the established description/done/learnings/deps shape: #15 runbook, #21 mute-bomb, #32 recorder, #19 disk archive, #9 launcher, #27 highlight jitter, #5 HUD version control. The learnings are the point, not the inventory. The ones worth re-reading: - #21: a fix that lives only in a running process is not a fix. The gF rewrite was correct and live-validated for a full day while still being one SuperCollider reboot away from silently rearming. "Live-confirmed" and "durable" are different states and the gap between them is where this class of bug hides. The deeper design lesson: make rest position == no effect. The bug was never really the missing djfbus, it was that the hardware's DEFAULT state sent an EXTREME value. - #9: order beats retry. The MIDI dance was a race symptom; gating on observable readiness (three independent checks, not a sleep) removed the race rather than automating the workaround. And idempotence is the property you want from anything you might run while panicking. - #15: a frozen Pulsar does not stop the audio — patterns live in ghci, not the renderer — which inverts the instinct to panic-kill the editor. - #19: du-deleted (436GB) vs df-freed (160GB) disagreed sharply; btrfs zstd + reflink sharing explains it, df is authoritative, don't chase the gap. - #27: border participates in layout and reflows text, outline does not — for any decoration toggling at performance rates, outline is the correct primitive. - #5: the HUD, pulsar-tidalcycles, and ~/.pulsar/styles.less are three separate version-control domains (the last untracked entirely, as user config). One visual bug can need coordinated edits across all three, which is exactly what #35 hit.
PLN (Algolia) authored -
Two gig-prep deliverables that needed no ears, written at J-10. RUNBOOK.md (#15) — the "when it breaks" playbook, organised symptom-first because that is how it actually gets read: you don't know the cause, you know the sound stopped. Ordered cheapest-first, with an explicit rule zero that rebooting SuperCollider is the LAST resort (30-120s of dead air and every pattern lost) and almost nothing needs it. The section worth having written down is 2b, the zombie control port. Observed live today: a leftover ghc process holds Tidal's port 6010, so a fresh Tidal boots, fails to bind, prints "Can't handshake with SuperCollider without control port" — and Pulsar looks completely normal. You eval and nothing happens, with NO error surfaced in the editor. That is the nastiest class of failure: silent, and indistinguishable from "my code is wrong". Detection is one line (ss -lunp | grep 6010, expect exactly one ghc and it should be the current one), so it's now in the pre-set checklist rather than only in the recovery section. Also captured: the mute-bomb rescue path (prelude.tidal as in-session hot-patch on a stale boot, with the tell that pulling fader 49 to 0 makes it WORSE not better); fader 77 being down as a silent global-gain failure that looks like nothing is broken; Pulsar being frozen NOT stopping audio, since patterns live in ghci and not the renderer, so Window: Reload keeps the music playing; and the LCXL USB-OUT endpoint stall where LEDs die but input survives (replug). Every procedure is labelled by how well it's actually established — §1a/2a/2b/2c/7 have commands verified by running them today, §4/§6 come from documented prior incidents with known-good fixes but weren't re-tested tonight, and §5's gig-up.sh path was read from source rather than exercised end to end. A runbook you have never executed is a hypothesis, and it should say so. docs/2026-07-25-opal-bpm-arc.md (#12 input) — read setcps out of all 12 setlist tracks instead of trusting the backlog's [bpm] markers, and three disagree: - Gimme Acid: 80 measured vs 160 written — almost certainly the standard dnb half-time convention, but it decides where the track sits in the arc. - Sunshine: 144 measured vs 166 written. 22 BPM is far too big to be a rounding note, and it inverts the end of the set: the backlog plans Mafia(160) -> Sunshine(166) as a rising finish, but measured it is a 16 BPM DROP. Either the file drifted or the number was aspirational — needs a decision, since the shape of the finale depends on it. - Desire: 127 vs 129. Trivial, but it's the FINALE, so make them agree. Charted the measured arc and flagged three >40 BPM cliffs (->89, ->80, ->160). The 89 and 80 ones look deliberate — a slow track between fast ones is a real dramatic move — and they are only a problem if the transition is unprepared, which is precisely what the riser audit (#33) and default-xfade (#13) exist to fix. Also noted the 124/124/128 plateau as the most transition-safe stretch in the set. Ordering itself is left as PLN's call; this is only the tempo dimension.
PLN (Algolia) authored -
Second pass on the audit. "Am i Doing it Right?" was reported as file-not-located; it exists as live/techno/do_it_right.tidal. No slug guess matched the title — it was identified by `setcps (89/60/4)` = 89 BPM against the backlog's [89*] marker. Recording that as a method: when title-to-slug guessing fails on this repo, the tempo line is the reliable identifier, not the filename. It changes the finding in a way that strengthens the conclusion rather than weakening it. The track DOES have a riser, so the count is 3/12 not 2/12 — but it is a third, mutually incompatible idiom: d10 $ mask "<f!4 t f!3>" $ loopAt 4 $ "risers:8" # gain 1 # cut 10 An 8-cycle period firing on cycle 5, but loopAt 4 stretches the sample over 4 cycles while the mask only opens for 1 — so what plays is a slice of a slowed riser, not a complete build. Could be deliberate (at 89 BPM a full 4-cycle build is very long) or a leftover; flagged for PLN either way. So the real headline is not the absence of risers, it's the inconsistency of the ones that exist. Three tracks, three idioms, disagreeing on all three axes: - phase: fires-last-8 (Take Five) vs fires-first-1 (Vague de CRIME) vs fires-cycle-5-of-8 (Do It Right); - gain: 0.8 vs unset vs 1 — the riser will not read consistently to the room across three tempos; - wrapping: Take Five AND Do It Right both lack gF/gM, so they are the only streams in the set the global filters and mutes cannot touch. Reach for gF1 during either build and everything ducks except the riser. That third point is the one that could actually bite live, and it now affects two tracks rather than one. It also makes the gRiser proposal stronger: harmonizing is no longer "add the missing 9", it's "reconcile 3 disagreeing implementations and then add the missing 9", which is exactly the kind of thing worth doing once in a helper instead of nine times by hand at J-10.
PLN (Algolia) authored -
Task #33 asked "does every OPAL track have a riser, and are they harmonized?". Answering it needed the setlist (backlog.md § OPAL 2026, 12 tracks with BPMs) resolved to actual .tidal files, then every d10 / riser / sweep / impact hit read in context. Result is worse than expected and worth having in writing before rehearsal rather than discovering it on stage. Findings: - Only 2 of 12 tracks have a riser: Take Five Drops and Vague de CRIME. - 5 tracks have d10 completely free (Bombe, WAP, Mafia, Sunshine, Desire) — a riser drops straight in. - 4 tracks have d10 already occupied by non-riser material (Piment's "Menace", Perfect's euclidian arps, Gimme Acid's "GIMME THAT", Revolution's sweet trigger) — those need a different stream, not a d10 paste. - Track 3, "Am i Doing it Right?", has NO .tidal file matching any slug I tried. Per the repo convention it must exist under a name I didn't guess. Flagged as an open question — the set is incomplete until it's found. The two existing risers disagree with each other, which is the actual #33 problem: Take Five sleeps 24 cycles and builds over the final 8 (a build-up INTO a drop), while Vague de CRIME fires on cycle 1 of 8 at the sample's natural length (an accent OUT of a downbeat). Same folder, opposite musical function — exactly the muscle-memory hazard when you're moving track to track mid-set. Also caught: Take Five's d10 is the only stream in the whole set with no gF/gM wrapper, so global filters and mutes cannot touch it — reach for gF1 during that build and everything ducks except the riser. Proposed one house helper, `gRiser period build`, derived verbatim from PLN's own working Take Five block rather than invented. loopAt is the load-bearing trick: it makes the riser's length independent of the sample's natural length, so one helper lands correctly from 120 to 166 BPM. Validated the proposal two ways before recommending it, per build-the-katana-first: - compiles clean against the real tidal-1.9.5 (ghc -fno-code, no stream started); - the generated mask is BIT-IDENTICAL to the hand-written "<f!24 t!8>" — queryArc over cycles 0-32 gives exactly 24 False then 8 True for both, compared elementwise, mine == theirs -> True. It's a faithful refactor, not a lookalike. Deliberately NOT committed to BootTidal.hs and NOT applied to any track: what the grep cannot answer is whether stock gain 0.8 / room 0.4 sits right under a 166 BPM liquid dnb track. That's ears. Suggested trial order is Desire (the FINALE, where a missing build costs most), then Mafia and Sunshine (the set's peak). Ties to #13: with default-xfade dN now baked in (98d073f2), every track launch already blends over 4 cycles. A riser is the musical counterpart to that structural crossfade — the xfade stops the seam being abrupt, the riser tells the room a change is coming. Together they're what turn "ctrl+enter and pray" into a transition.
PLN (Algolia) authored -
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.PLN (Algolia) authored -
Three independent pieces landing together from tonight's live-debug/build session: 1. Panic chord (task #34): holding LCXL push-buttons 73+74+91+92 together now flips a persistent silence toggle. These are momentary Note buttons (not latching CC), so a simultaneous hold is a natural chord — detected with an edge-triggered flip-flop in start_and_midi.scd (the only layer that sees raw per-button press/release state cleanly). Flips are echoed to Tidal as a new virtual control "^93", and to the LCXL's own LEDs via the Note-On method already validated in this project (reference_lcxl_led_stall memory). Tidal side is a plain gPanic gate in live/lib/prelude.tidal — PLN wires it into whichever track he's actively composing/testing, not applied globally. Not yet live-verified (needs a fresh boot) — tracked as task #34. 2. tools/gig_record.sh: a lean, reusable, always-on stereo-master capture, answering "I want to always record all play, compressed." Auto-resolves whatever the current default PipeWire sink is at start time (so it follows the rig from onboard SOF SoundWire onto the UMC202HD arriving tomorrow with zero config changes) and encodes to Opus at 160kbps in hourly segments (~72MB/hr — 188GB free buys thousands of hours). start/stop/status/slice subcommands; slice does a fast stream-copy excerpt for quick auditioning or feeding into Slopmotion once that's available. Smoke-tested end to end (start, 8s live capture, ffprobe-verified valid opus, stop) before wiring into anything. NOT yet wired into gig-up.sh's auto-launch — PLN wants silent-by-default on every boot; that wiring is the next step. 3. Local disk freed from 28GB (98%) to 188GB (81%) free. Root-caused why the session had crept there: the 436GB Ardour "Tidal Multi" session (deprecated in favor of the lean "Tidal Live" the gig now boots) was still sitting locally despite the freebox mirror already holding it byte-identical. Verified via fbk --dry-run (0 audiofiles needing transfer; the 1530-file, 449,260,749,448-byte audiofiles tree matched exactly on both sides) before asking PLN to bless the delete — freed via `rm -rf` of audiofiles/export/ peaks, keeping the tiny .ardour session file + midifiles as structural reference. (Real gain was 160GB not the naive 436GB sum — this machine's root is Btrfs with zstd compression, so du-reported sizes don't equal freed space 1:1; 188GB real free per df is still the number that matters.) Also: visuals/slop/README.md — documented the staged first test clip (Opal2024's 12_Mauerpark.flac, loudest 60s window at 2:53-3:53, chosen because it's the same track lineage as ete_a_mauerpark.tidal currently being edited) while the actual Slopmotion repo remains unlocated (org has 0 repos; asked PLN to get the real URL from Kevin/Shipow).
PLN (Algolia) authored -
#21 gF footgun fixed and #13 xfade confirmed live this session: - live/lib/prelude.tidal: nucleus of the ParVagues lib (#23). Two eval-blocks PLN can shadow into a running session (no reboot): * gF1/gF2/gF3 rebuilt on CORE hpf/lpf mapped so fader-at-rest (CC=0) == BYPASS. The old (# djfbus N …) referenced an UNregistered SuperDirt effect and rested at an extreme → muted the orbit with no recovery. New form structurally cannot mute: untouched = transparent, push fader = sweep in. PLN confirmed 'work great'. * d1..d12 = xfade N . (|< orbit N-1): every track LAUNCH crossfades 4 cycles AND keeps its orbit (old bare xfade N lost the orbit → wrong LCXL column/stem). Plus orbit-correct jumpTo i for hard cuts. PLN confirmed 'no more abrupt cut boom!'. - visuals/slop/: scaffold for Kevin's Slopmotion — README (NOW=generate shareable MP4s, LATER=gig visual engine) + FEEDBACK.md log to hand back to him. Not yet baked into BootTidal.hs — kept as evaluable prelude until fully road-tested.PLN (Algolia) authored -
Two live-play problems, both auto-handled by gig-up.sh so nothing lives in PLN's head at gig time: 1. MIDI-burst CRACKS — root cause was NOT samples or RT priority (rtprio 95 is fine): the CPU was capped at max_perf_pct=55 (the quiet/cool desk regime), so a control sweep's CPU burst starved the audio thread -> xrun. gig-up now ASSERTS Standard (uncapped, governor performance) on launch via perf.set_mode('standard') — which also writes the desired-state file so the Bridge watcher holds it. Revert to Cool in the tray when done; skip with GIG_PERF=off. Confirmed live: toggling to Standard killed the cracks. 2. LAZY-LOAD cracks — gen_preload() runs setlist_samples.py --last N --emit-sc into preload.scd before boot; start_and_midi.scd loads it after SCLOrkSynths.load, warming just the recent set's samples (last 15 tracks = 55 folders vs the whole library). setlist_samples.py also gained bare-name track resolution (find under live/). preload.scd + gig-sclang.log gitignored.PLN (Algolia) authored -
Live play cracked from lazy sample loading (~dirt.doNotReadYet=true): each sample reads from disk on first play mid-set → crackle + xrun spikes (764→1085 xruns during a track). Loading the whole library = slow boot + RAM; lazy = cracks. This tool finds the middle path: parse a set's .tidal tracks (or --last N by mtime), extract every token from every quoted string, and keep only those that resolve to a real sample folder (Dirt-Samples, extra/, tidal-drum-machines) — the library itself is the filter, robust against ParVagues' bare-string/# dialect that defeats s"..."-based parsing. --emit-sc prints a ~dirt.loadSoundFiles preload snippet. Validated: last 15 tracks → 55 folders (vs hundreds in the library); bombe_dj → 8. Foundation for #26 (wire into boot) + #24 (soundcheck). t/f excluded (Tidal booleans).
PLN (Algolia) authored -
fix(gig): boot the real start_and_midi.scd, not stale main_fairbanks — root of silent synths & orbit errors gig-boot.scd chained main_fairbanks.scd (scratch: 8 output channels, 8 orbits) BEFORE start_and_midi.scd. main_fairbanks booted the server first, so PLN's real boot found it already up and its options were ignored — losing the 28 channels, 14 orbits (d1..d12 + ears test), SCLOrkSynths.load, the MI global effects, StageLimiter + s.volume=2. Net live: d9-d12 silent, bassWarsaw/ FMRhodes1 never loaded, orbit 8/10/11 errors spamming the post window. Fix (#18 simplification): launcher runs PLN's canonical sclang start_and_midi.scd directly; gig-boot.scd retired; main_fairbanks.scd kept as reference only. Apply = FULL sclang/scsynth restart (running scsynth keeps 8-ch options).
PLN (Algolia) authored -
Snapshot of the live-set material and gig docs before the planned lib restructure (dedup + a proper loaded ParVagues prelude so gF/gM/djf live in one place, not re-defined in scratchpads). Also protects secrets: .env + build noise now gitignored. Includes FOH_MASTER.md (master-bus hardening recipe) and the ordered-202HD shopping update. Track edits: desire, vague_de_crime, + new network_zero_un / bombe_dj / ca_fait_rien / electric_hammer.
PLN (Algolia) authored -
Save-As-empty produced Tidal Live (no audiofiles — the 419G stems were NOT copied). Retargeted the launcher from the fat archival 'Tidal Multi' to the lean go-forward session. Tidal Multi stays put for the freebox stem archive (#19), then retires.
PLN (Algolia) authored -
Follow-up to the live launch test: re-running gig-up while the rig was already up would have opened a SECOND Ardour on the same session (an 'already open / locked' dialog) and a second Pulsar. Only SuperDirt was guarded (skip if scsynth up). Added ardour_up() (pgrep -f 'ardour-[0-9]', since the real binary is ardour-9.2.0 behind the ardour9 wrapper script) and pulsar_up(), and gated both launches on them. Now gig-up is a converge-to-ready button: run it at any point and it starts only what's missing. Verified live with the full rig up — SuperDirt/Ardour/Pulsar all correctly reported 'already running, skipping', nothing duplicated. Serves #18 (dance with sound, not setup).
PLN (Algolia) authored -
First real end-to-end run of the ordered launcher aborted immediately at "starting SuperDirt": open_term() carried a vestigial `local cmd="$1"` (the sclang command is hardcoded inside the function), but the function is called with no arguments, so `set -u` turned the unused positional into a fatal 'unbound variable' before sclang ever spawned. Dropped the dead parameter. Re-ran: SuperDirt boots headless, claims the LaunchControl XL (aconnect 16:0 -> SuperCollider 128:3) BEFORE Ardour opens, then Ardour 9.2.0 (Tidal Multi) + Pulsar come up — the whole rig from one command, no disconnect/reconnect MIDI dance. Task #9 validated live.
PLN (Algolia) authored -
Per-item 2-line rationale + 3 example search queries, constrained to few-days Amazon or a Pigalle scavenge (deadline ~Aug 1). Priority = a USB interface with balanced line outs (the real fix for "you're too quiet": today FOH is fed from the laptop headphone jack). Then powered USB hub (LCXL LED stability), a DI-box fallback, a cable/adapter kit, and an optional passive monitor controller for the fine volume control the KRK wheel lacks. A sub is noted as post-gig — metering solves the bass blind spot for now.
PLN (Algolia) authored -
Start-of-gig pain: whichever of SuperDirt or Ardour opens the LaunchControl XL first wins it, and when Ardour wins, sclang can't get the controller → the manual "disconnect MIDI / reconnect MIDI" dance mid-setup. The fix is ordering + a real readiness gate. gig-up.sh (repo root): brings SuperDirt up FIRST and WAITS until it has actually claimed the controller, then launches Ardour + Pulsar. Readiness = three unambiguous signals, all of which appear during main_fairbanks.scd's boot: scsynth alive + UDP :57120 listening (SuperDirt.start) + a "SuperCollider" ALSA-seq client present (MIDIClient.init has run). 120s timeout (sample loads can be slow) → proceeds with a clear warning rather than hanging. Best-effort throughout: terminal auto-detected (konsole/kitty/…, background-log fallback), Ardour/Pulsar binaries probed by name, skips SuperDirt if scsynth is already up. gig-boot.scd: one eval that runs the real boot (main_fairbanks.scd) + the LaunchControl CC->OSC bridge (start_and_midi.scd) so the rig comes up fully armed in a single file; loaded by relative path to stay portable. Validated offline: bash -n clean; the three probes correctly read 'down' with SuperDirt dead; ardour9 + pulsar resolve; the Tidal Multi session path exists. End-to-end (the live MIDI gate) to be confirmed on the next real boot.
PLN (Algolia) authored -
Root-caused the 2026-07-25 overnight-sleep crash where the music (and Ardour) died on resume. It was NOT an audio-hardware failure — it was the *display stack* taking down the sound. Evidence (all at resume, ~11:17): 11:17:31 kwin_wayland (pid 2603) SIGABRT — the Wayland compositor aborted on resume-from-suspend (deep internal assertion; core shows abort→libc). Plasma respawned the whole session (new kwin/plasmashell/Xwayland, confirmed by their ~1h40m uptime vs the machine's 1d+). 11:17:35 ardour9: "Fatal IO error 104 (Connection reset by peer) on X server :1" — Ardour, an X11 client on Xwayland, died with the session. 11:17:35→44 scsynth SIGABRT via std::terminate — ~4s after kwin, in the cascade: sclang is a Qt6/Wayland client, so it lost its display connection when kwin died and crashed, and scsynth (which it hosts) aborted on the broken IPC. Why short naps survive but an overnight one didn't: a quick suspend/resume just pauses the Wayland connection; the long/overnight cycle triggered a GPU/DRM reset that made kwin actually crash — and a crashed compositor severs every client at once. Fix: sclang doesn't need a display. QT_QPA_PLATFORM=offscreen runs its Qt without connecting to any display server, so a compositor crash/restart can no longer reach it — the SuperDirt brain becomes immune to the entire Wayland/X lifecycle. SuperDirt uses no GUI; the interpreter and post window still work in the terminal. Validated: `QT_QPA_PLATFORM=offscreen sclang` compiles the class library and reaches the SuperCollider 3.14.1 banner with zero wayland/qpa errors. collide.sh is the only launcher (perf.sh only reprioritizes a *running* sclang, it doesn't spawn one), so this single line closes the gap. Not addressed here (harder, separate levers): kwin's resume-crash itself is a Plasma/GPU-driver issue — the standing mitigation is running dGPU-off (./gpu-mode.sh integrated), which removes the Xwayland-on-dGPU DRM reset that's the likely abort trigger and would also spare Ardour's :1 connection.PLN (Algolia) authored
-
- 24 Jul, 2026 3 commits
-
-
The last unclaimed thermal lever. Our 2026-07-24 finding: on this Plasma-Wayland box Xwayland pins the RTX 2060 'active' regardless of runtime-PM (control=auto, --rtd3), so the dGPU never actually suspends live and keeps drawing ~4-5 W + idle heat. The ONLY real off is EnvyControl's 'integrated' mode (blacklist nvidia) — but that's a persistent config change that needs a re-login, categorically unlike the instant perf.sh modes (governor/EPP/RAPL). So it gets its own tool, not a perf-mode. gpu-mode.sh (new, at repo root beside perf.sh) ---------------------------------------------- A guarded EnvyControl front-end: `query` (default — manager mode + live dGPU runtime state, with the right advice per mode), `integrated` (dGPU off; warns you lose CUDA/NVENC for demucs/audio-ML until you switch back), `hybrid` (restore with aggressive --rtd3 3 = D3cold-when-idle). Every switch confirms (skip with -y), runs `sudo envycontrol ...` (prompts for your password), then prints the exact re-login step (reboot safest; verify with `./gpu-mode.sh query` + `nvidia-smi`). Deliberately NOT added to the passwordless perf-audio sudoers whitelist: this is a rare, considered, re-login-required switch — the web Bridge and tray must never be able to power-cycle the GPU config unattended. Runs by hand only. Cockpit surfacing (Bridge + tray) --------------------------------- - perf.py: gpu_manager_mode() reads `envycontrol --query`, cached 300s (the mode is static within a login session; a re-login restarts this --user service and refreshes the cache), defensive → None if envycontrol absent. Added to snapshot() as `gpu_manager`. - Bridge UI: the `gpu` chip folds it in — shows `off↻` when integrated-but-pending- re-login (dot green: this is the quiet goal), and in hybrid its title now names the manager mode and points at `./gpu-mode.sh integrated` for a real off. - Tray tooltip mirrors it (`gpu awake·hybrid`, or `off↻` when armed). Validation: 24 perf tests pass (2 new — parse+cache, and absent→None; snapshot-shape now asserts dgpu/gpu_manager/thermald). Live: `./gpu-mode.sh query` reads hybrid + active(0000:01:00.0) and fires the Xwayland warning; Bridge /api/perf serves gpu_manager=hybrid; both services restarted clean.
PLN (Algolia) authored -
The playing counterpart to the July-18 idle capture: mid-set highlight-stats shows 580 markers live vs 16 active, accumulating ~40/min (matches July's 34/min idle) — the position-marker pool still never evicts, so the 07-19 "marker leak fixed" is incomplete and the idle 82% renderer burn (the break-time heat) shares this exact root. UI-smoothness only; audio untouched.
PLN (Algolia) authored -
Problem: the laptop ran hot even idle, and the bafd3133 RAPL watt caps were committed but NEVER deployed — the live /usr/local/sbin/perf-audio predated them, so every --cool set clock-% while RAPL sat at the BIOS 135W (measured 90C under an all-core encode). Watts are the thermal lever, not percent. - perf.sh: new --silent ("smart-silent") — powersave + EPP power + 55% clock ceiling + a hard 12W/25W RAPL cap + allow_dgpu_suspend (nudge the discrete GPU toward D3cold) + audio still RT. Quieter than --cool without disabling turbo (low PL2 keeps SuperDirt DSP transients from xrunning). Tunable via SILENT_PL1_W / SILENT_MAX_PCT. - perf-audio.sudoers: whitelist --silent (flag-scoped, no wildcard). - tools/bridge/perf.py: MODES gains silent (tray + web inherit it); detect_mode disambiguates silent vs cool by EPP; snapshot() gains cores_pct (per-cpu util deltas), dgpu (runtime_status), thermald, watts (live RAPL caps), power_w (actual draw — null until energy_uj is unlocked, then lights). - ui/index.html: the bar is a cockpit now — 16 "dancing cores" (height=util, colour=temp, hover=cpu/util/temp), folded chips (watt cap / dGPU asleep-awake / thermald), a distinct teal+snowflake tint for Silent, and a 60s temp+power sparkline. - perf-tray.py: the icon's decorative sine is now a REAL temp-history sparkline; tooltip + menu fold in cap/gpu/thermald. Verified: POST /api/perf {silent} -> live RAPL 12/25W; {cool} -> 28/50W; the 135W furnace is leashed. perf tests 7-pass.
PLN (Algolia) authored
-
- 23 Jul, 2026 2 commits
-
-
Field-caught by the watcher itself. The laptop suspended ~10:11 and resumed 11:21:46; resume reset the pstate cap (a brief 4.4 GHz clock spike in the monitor log), and the watcher DID restore cool — but at 11:22:04 via the ~30s periodic drift check ("[perf-watch] drift: reasserted cool"), not the fast 2s resume path. Cause: the resume detector used time.monotonic(), and CLOCK_MONOTONIC does not advance while the system is suspended — so on thaw the thread saw only its normal ~5s sleep, gap << threshold, resume missed. The periodic safety net (belt-and- suspenders) is what actually caught it. Fix: measure the gap with CLOCK_BOOTTIME, which counts suspended time, so a resume now shows as a large gap and triggers the immediate force-reassert (2s settle). Falls back to monotonic if CLOCK_BOOTTIME is unavailable. Verified present on this box (uptime read OK); watcher restarts clean with on_ac=True desired=cool.PLN (Algolia) authored -
The incident: mid-session on battery the pstate held turbo down (~2.5 GHz, 60°C, CPU pressure ~0 — the set never needed more). Plugging in on AC at 4% silently lifted that limit; the SAME workload jumped to 4.4–4.5 GHz and 85–93°C with fans maxed. Nothing was working harder — the platform just reset the frequency cap underneath our "cool" mode, and the tooling never noticed. set_mode() was fire-and-forget: it wrote the cap once and moved on. Fix: treat the perf mode as DESIRED STATE and reconcile it whenever the platform can drift it (AC/battery flip, resume-from-suspend), with a periodic drift check as the safety net. perf.py - write_desired()/read_desired(): persist the user-chosen mode (~/.cache/ parvagues/perf-desired). "normal"/absent == maintenance off, so we never fight a deliberate switch back to platform defaults. - set_mode() records intent on every successful switch. - on_ac(): mains state from /sys/class/power_supply/A*/online. - reconcile(force): reassert desired if detect_mode() drifted (idempotent — "cool holding" when already in force, so no thrash). - run_watcher(): daemon loop. Reasserts (force) on a power-source edge and on resume (detected via a monotonic-clock gap), settling 2s for the platform; periodic force=False drift check otherwise. Seeds desired from the live mode on startup so an already-cool session is maintained immediately. bridge.py: launch run_watcher() as a daemon thread from `serve` (the always-on --user service is the right home; the tray is just a face). perf-tray.py: record intent (write_desired) on a successful tray switch too, so both faces agree and the watcher respects tray-initiated changes. Bonus: because "cool" also RT-schedules scsynth/sclang/Ardour/PipeWire, every reassert re-guarantees audio-chain priority after a power event — cheap insurance against post-transition xruns. Validated: compiles; reconcile idempotent; force reassert exercises the real perf-audio path (cool->cool, no disturbance); watcher thread confirmed live in the daemon with "on_ac=True desired=cool". Real power-transition proof lands on the next unplug/replug (logged to the bridge journal).PLN (Algolia) authored
-
- 19 Jul, 2026 1 commit
-
-
PLN re-listened to the forged hammer kit: vox cuts weren't voice-only, 06_vox_breakitdown didn't loop, kit felt below the track's stature. All three confirmed by measurement and fixed in a v2 rebuild (catch report.md has the full story): demucs-stem vox bleed sat just −2.4 dB under the cut RMS on the worst file; the energy-corrected cut bounds were themselves bleed-biased (06 started a full second before the word); the rotated loop exports had never been promoted. v2 = roformer-vocals re-cuts on true onsets, a roformer-instrumental→demucs cascade for ghost-free instrument loops, the missing 2-bar breakitdown loop, and the rotation finally shipped.
PLN (Algolia) authored
-
- 18 Jul, 2026 2 commits
-
-
Discovery 2026-07-19: the Dell BIOS ships PL1=PL2=135W on this 45W-TDP i7-10875H. With no sustained-power brake, the only thing that ever slows the CPU is the 100C thermal limiter — which is how a set peaked at 91C and had to be aborted. Percent clock caps (--cool's max_perf_pct) don't bound multi-core power; watt caps do. All three modes now set package power limits via RAPL, saved/restored by --stop: - --optimize / --extreme: PL1 45W (chip spec) / PL2 90W — full nominal performance, bursts stay snappy, sustained runaway impossible. - --cool: PL1 28W / PL2 50W by default (~2.5GHz all-core), tunable with COOL_PL1_W / COOL_PL2_W. - --diagnose now prints the current PL1/PL2 against spec.
PLN (Algolia) authored -
Records of the editor-lag deep-dive: local root-cause analysis (renderer main-thread saturation, console DOM growth, three marker leaks, .line transition churn, Electron 12 ceiling, thermal state) and the companion web-research report on the 2026 TidalCycles editor ecosystem (uzu/Codeberg migration, upstream issue #229, vim/VSCode/browser alternatives, no prior art for Pulsar forks). Fixes landed in the pulsar-tidalcycles fork, branch perf/event-highlighter, commit 6e9f374.
PLN (Algolia) authored
-
- 11 Jul, 2026 8 commits
-
-
Two refinements from measuring the first rotated re-cuts of the real kits: 1. Junction in the pre-attack pocket. The rotation point was zc-snapped ±symmetrically around the downbeat, which could land the loop wrap mid-transient (rotated hammer drums read seam 0.50 / click_db −0.03: physically continuous, but the junction sat in busy material and a re-trigger clipped into the groove). _pocket_zc() searches [−25 ms, +2 ms] around the target and picks the zero crossing with the smallest local 2 ms RMS — the natural cut point in the quiet dip before the hit. Re-trigger catches the full attack; hammer drums grade recovered A 0.808 → S 0.988, bass 0.861 → S 0.916. 2. Exports ship DC-free (B2), mirroring vox._finish_clip (4a74213c): the demucs stems' ~1e-4 DC bias was flowing into every exported loop (all three OLD superfreak kit files flag dc-offset on re-grade today). Mean-subtract after mono-sum, before write; shifts the zc-snapped edges by ≤1e-4 — inaudible, still effectively zero. 86 tests green.
PLN (Algolia) authored -
Refinement caught before re-cutting the real kits: superfreak drums and bass ship from the SAME window (107.21s, 4 bars). If each stem rotated to its own strongest attack, their relative groove could shift by whole beats — bass's phrase-start is not necessarily on the drums' 1, and the kit is played together (loopAt on a common cycle), so relative phase between kit loops is musical content. export_take now derives the downbeat slot ONCE per shared time window from its most rhythmic stem (drums > bass > other > vocals priority) and applies that same slot to every stem of the window (_rotate_to_downbeat force_slot; per-stem roll still zc-snaps within ±10 ms on the stem's own mono ref). Stems at different windows keep independent rotation. Stem reads are cached (each stem was loaded twice otherwise). Test: two-stem synthetic window, drums downbeat at slot 3, other's own loudest attack at slot 6 — drums' marker must land at 0 and other's at 3 (= 6−3, following drums), not 0. 86 passed.
PLN (Algolia) authored -
PLN's kit audition (logged 6cfc7af0): loops felt 'timed ok but cut BCDA/DABC — not at a good start'. Measured and confirmed — the PLP beat grid has no downbeat anchor, so candidate windows start on an arbitrary beat: superfreak other_skank's strongest onset sat on slot 2/8 (its first 30 ms −23 dB below its own peak 30 ms), bass_deep's on slot 4/16, drums_dub's on slot 1/16. Bar-exact and tempo-locked, but musically rotated. The key insight that makes the fix free: for a verified clean-seam, bar-exact loop, ROTATION IS SAFE BY CONSTRUCTION. Looped playback of a rotated loop is the same audio cycle — the old wrap junction plays interiorly, and the new wrap (the rotation point) joins samples that were contiguous in the source, i.e. perfectly continuous. Rotation only changes where the loop STARTS, never how it wraps. _rotate_to_downbeat(): score each beat slot by its circular low-band (<200 Hz, kick-weighted) attack — RMS just after minus just before — plus a small full-band term; roll the winning slot to position 0, zc-snapping the roll offset (B1) so a re-trigger starts at a crossing. Length untouched (np.roll) ⇒ the <1 ms bar-multiple guarantee (0759def5) holds through rotation. Wired into export_take (on by default, rotate=False opts out; chops bars=0 never rotate). Verify-rerank stays export-faithful: _true_seam now returns min(old-wrap seam, rotated-wrap seam) — both junctions of the shipped cycle are measured, so rotation can never hide a bad wrap by moving it inside the file. Tests: +3 (downbeat at slot 5 → rotated to 0; slot-0 no-op; rotating a continuous loop never breaks the seam). 85 passed.
PLN (Algolia) authored -
docs(ear-feedback): superfreak/hammer kit audition — sub-only bass, BCDA loop rotation, demucs vocal high-pass PLN's on-disk verify of the forged kits, with measured confirmation of all three reactions: bass_deep is a pure-sub layer (99% <150 Hz at −12.8 dBFS — equal-loudness invisibility, not a level bug); loops are bar-exact but musically ROTATED (strongest onset lands on beat-slot 1/2/4 instead of 0; other_skank opens −23 dB below its own peak 30 ms — the 'cut DABC' feel); vox thinness is htdemucs routing vocal low end into bass/other (vocal stems carry ~0 energy <150 Hz). Fix directions logged: rotate-to-downbeat export post-pass, BS-Roformer vocals re-cut, harmonic-saturation bass variant.
PLN (Algolia) authored -
Two defects surfaced while shipping the hammer (U Can't Touch This) vox kit extension — both fixed in the shared cut tail, now factored as _finish_clip(): 1. DC offset. Demucs vocal stems carry a small DC bias (measured −9.6e-5 stem-wide on the hammer catch); every cut inherits it and longer phrases tripped the grader's B2 dc-offset flag (|mean|>1e-4, 'break it down' cut measured −1.1e-4). Subtlety: a naive mean-subtract BEFORE fading is undone by the fades — the edge ramps remove signal asymmetrically and re-introduce up to ~1e-3 DC (caught by the new regression test, not by the real-data smoke run). Fix: subtract the FADE-WEIGHTED mean c = Σ(w·x)/Σw (w = fade envelope), then fade — post-fade mean is exactly 0 per channel AND edges are exactly 0. On-disk verify of the shipped hammer vox files reads dc = −0.0e+00, edge = 0.0e+00 across all six. 2. Loop-length drift. cut_phrase_loop placed the tail at exactly loop_beats × beat_s … then zc-snapped it (±12 ms), re-introducing the very grid deviation the length-preserving export rule (0759def5) forbids. The end snap is unnecessary — the fades already guarantee clickless edges — so the tail is now length-rigid: shipped 08_vox_stophammertime_loop is 4.00 beats to 0.02 ms at BPM 132.51. Tests: tightened test_cut_phrase_loop_is_exact_beat_multiple from 0.06-beat slack to <1 ms, added test_cut_removes_source_dc_offset (biased source ⇒ DC-free, unflagged cut). 82 passed.
PLN (Algolia) authored -
The B1 zc-snap moved each loop edge independently (±10ms tolerance), so exported loop DURATIONS drifted off the bar grid: measured −4.2ms on a 4-bar (superfreak bass) and −11.4ms on 2-bar loops (hammer kit, both edges snapped inward). loopAt absorbs the drift, but the kit contract we want is stronger: every exported loop's duration == bars × bar_len. Fix — _snap_length_preserving(): hold the exact bar-multiple sample count RIGID (bar_len_samples from the take's grid BPM) and slide the WHOLE window by a single common offset δ ∈ ±ZC_TOL_MS, picking the δ that minimizes combined edge amplitude |y[start]|+|y[end]| (tie-break: smallest |δ|). Both edges move together ⇒ duration is preserved by construction; guarantee |exported_dur − bars·bar_len| < 1ms (measured <0.02ms on real stems). Chops (bars=0) keep the per-edge snap. _snapped_window/_true_seam (verify-rerank, 791a0d78) now mirror the same scheme so the finder still measures the exact window export writes — export-faithfulness is preserved through the change. kit_multiples_check() makes the guarantee explicit per forge: after export, each file's duration-in-bars at the shared grid BPM is compared to the nearest integer multiple; >0.5% deviation warns with numbers. export_take_report() bundles export + check; the server /api/export now returns the multiples block. Spot-check on real stems (old per-edge vs new length-preserving snap, top-5 finder candidates re-graded on the exact export window): superfreak drums: dev +0.4…+3.6ms → ≤0.01ms; grades C→S, A→A, S→A, S→S superfreak bass: dev −1.1…+3.7ms → ≤0.01ms; grades A→S, B→C, S→B, A→A hammer drums: dev −1.8…+1.9ms → ≤0.01ms; all S stay S hammer bass: dev −2.9…+6.9ms → ≤0.01ms; C→B, A→S, D→C, B→C Net: duration guarantee achieved; grade moves are the rigid-length window exposing true seams (some old windows only looked seamless because per-edge snap trimmed the tail). No systematic regression; existing superfreak/hammer kit exports untouched (validated, in use). Tests: +4 (snap length invariance, bar_len_samples, end-to-end exported- duration-is-exact-bar-multiple on a synthetic stem, multiples-check flags off-grid). 81 passed.
PLN (Algolia) authored -
feat(foundry): lyric-aware vocal sampler (engine/vox.py) — phrase-level, hook-ranked, loop-capable vox one-shots PROBLEM. The Foundry's vocal path (loops.analyze_chops) cuts vocals blind to what is sung — onset→onset slices scored on seam/zc mechanics. But a vocal one-shot's value to a livecoder IS the lyric. The freshly-shipped superfreak dub kit had four tiny 0.35-0.65s onset chops (03-06) with no idea they sat on top of some of the most iconic lyrics in funk ("she's a super freak", "kinky girl", "the kind you read about"). APPROACH. engine/vox.py: transcribe → phrase-segment → iconicity-rank → cut → grade → lyric-name, DRY-reusing grade.py sub-scorers and naming.py convention. - transcribe: whisper word-level timestamps, shelled out like separate.py→demucs, cached at workspace/vox_transcript.json so re-runs are instant. Model escalates small→medium empirically when the known hooks don't surface (small garbled the patois delivery; medium recovers the real lyrics). - segment: group words on inter-word gaps (>=0.45s), cap 6s, split over-long phrases at their widest interior gap; keep per-phrase avg ASR confidence. - iconicity: feature-engineered rank = repetition (normalized phrase text + content n-grams recurring across the track — hooks repeat) + hook keywords (title-derived or --hooks) + clarity (ASR prob) + energy (RMS vs stem median) + duration sweet-spot. - cut: pre-pad + post-pad (clamped to next phrase), zero-crossing snap both edges, 3-10ms fades so edge samples are ~0 regardless of where the snap landed; as-cut level. - kit-level loopability: report each phrase's duration in BEATS at the kit BPM; flag loop-capable phrases (within ±3% of a 1/2/4-bar multiple) and emit a bar-quantized _loop variant (tail pulled to the exact beat grid, still zc-snapped) for the best hooks, so a vocal can loopAt alongside instrument loops. - name: NN_vox_<lyricslug> (naming.lint-clean), dedup identical texts (best-graded instance, up to 2 takes of THE hook). VALIDATION. 17 new mocked-transcription tests (whisper never runs in tests): gap segmentation, over-long split, iconicity repetition-beats-oneoff + hook-keyword boost, beat/loop annotation, cut edges ~0 after zc+fade, next-start clamp, exact-beat loop variant, lyric-slug + lint contract. Full suite 60->77 green. Applied to the superfreak stem: medium transcript contains every iconic line; shipped 6 curated vox files (S/B tier) replacing the 4 blind chops, incl. one 2-bar (8.00-beat) loop variant. All re-graded on disk: no clip (peaks <0.8), no DC (<2e-4), edges exactly 0.0.PLN (Algolia) authored -
Problem — the finder's rank didn't reflect true seam quality. On a real end-to-end run over the Super freak dub kit (Soul Sugar meets Dub Shepherds), several top-scored 2-bar windows CLICKED at the wrap after export while cleaner windows ranked below them. Root cause: analyze_stem scores the seam on the RAW candidate window, but export_take zero-crossing-snaps both boundaries (B1) AND slices at the 3-decimal-rounded start_s/end_s — and both transforms move the wrap. A beat-exact window measuring seam 0.79 read 0.07 once rounded, and that rounded, snapped slice is what actually ships. So the finder's seam proxy diverged from the grader (grade.py), which measures the window that exists on disk — the ground truth. Approach — a verify-rerank pass (loops._verify_rerank) after candidate generation, before dedup/top_n. It re-measures the ~3×top_n survivors' seam on the TRUE post-snap window — the exact zc-snapped, rounded-bounds slice export writes — reusing grade.seam_score (DRY, no duplicated DSP). The proxy seam term is swapped for the true seam in the composite (same weights), and any candidate whose true seam falls below VERIFY_SEAM_FLOOR is hard-demoted so a click can never top the list. Gated behind a new analyze_stem(..., verify=True) kwarg (default on; False reproduces the pre-#19 raw-proxy ranking for autotune baselines). Public signatures (analyze_stem, find_takes, weights dict) unchanged — autotune.py/server.py intact. Also fixed a sparse-material seam false-positive in grade.seam_score: the wrap curvature was normalized by the MEAN |2nd-diff|, which collapses to ~0 on sparse dub percussion (mostly silence + a few hits), blowing the click ratio up (129× on a genuinely clean loop). Now normalized by the 90th-percentile |2nd-diff|, amplitude-floored — 2–3× on the same clean loop. Validation (drums+other stems, bars 1/2/4, shared 132.5 BPM grid, export-faithful grades): drums top-3 BEFORE C 0.65 / C 0.63 / A 0.80 (clicks @93.08s, @24.06s) AFTER S 0.98 / S 0.95 / A 0.81 other top-3 BEFORE B 0.72 / B 0.72 / B 0.70 (bad favorite @56.74s clicks) AFTER S 1.00 / S 0.98 / S 0.99 The known-good drums 4-bar @107.21 (S) and other regions surface; the clicking other @56.74 is demoted out of the top entirely. Tests: +2 verify-rerank regression tests (a proxy-clean but discontinuous wrap that survives the snap is demoted below a seamless one; verify=False leaves the proxy untouched) and +1 sparse-percussion test (a clean sparse loop is NOT flagged clicking). Suite 57 → 60 green.PLN (Algolia) authored
-
- 29 Jun, 2026 3 commits
-
-
Refreshed the onboarding template (rendered PDF is gitignored, carries live tokens): -
✨ NEW §3 "The YouTube → emotion pipeline": /sources fetch → /jobs poll → /artifacts download → /analyze/emotion, the showcase end-to-end flow (curl + the @nech/api TS shape), idempotent-on-repeat noted. - Credentials block now carries BOTH tokens: the api:* Bearer AND the npm read token for installing @nech/api from npm.nech.pl. - Endpoint table gains /sources, /jobs/{id} (+DELETE), /artifacts/{cid}/{name}. - §1 surfaces the live /docs + /openapi.json links and corrects "access": only /healthz is public now; docs/spec need api:docs (covered by api:*). - Sections renumbered (pipeline=3, client=4, good-to-know=5, support=6).PLN (Algolia) authored -
So the session task board survives a push to git.nech.pl (it is local harness state, not in git). Two cold-readable TODOs next to their code: - armada/api/TODO.md — Fourier audio-API remaining: heavy chain #30 /separate + #31 /loops/grade/correlate (need a GPU runner), optional #47 X-Accel + #46 Grafana, follow-ups (nech_api python client, hexa npm read token); EPIC #21 closes with the chain. - tools/foundry/TODO.md — #19 auto-tune loop (in-progress, harness validated +10.5%, exact resume steps) + #20 batch-explore corpus. Plus archived #44 (Verdaccio + @nech/api live) to completed-archive.md. Root TODO.md left untouched (it is the paused Pulsar livecoding-perf session).
PLN (Algolia) authored -
Verdaccio is live on npm.nech.pl and @nech/api@0.1.0 is published + install-verified (AudioApi/Configuration import clean as a consumer). So the hand-written zero-dep nech.ts drop-in is retired (git rm); @nech/api is the one true client. README + onboarding.html now show the @nech scope install with the read token, and the docs row reflects that /docs + /openapi.json are bearer-gated (api:docs) not public. VERDACCIO.md marked DEPLOYED with the three gotchas folded in (listen 0.0.0.0, chown 10001, TLSv1.2-only) + the auth-gated-reads note.
PLN (Algolia) authored
-