- 25 Jul, 2026 9 commits
-
-
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 10 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 -
Rich entry for the documentary: the anonymous-exposure finding, the cross-cutting api:docs design (read-specs decoupled from call-API), the lockstep drift-guard dance, and the shared-repo rebase + diff-before-tee discipline that kept SRE work intact.
PLN (Algolia) authored -
Mirrors the merged platform canonical: required_for() maps docs|openapi.json|redoc → {realm}:docs. Byte-identical to nechapi/_platform/scopes.py (drift guard green). Part of #48; deploy = nechapi-platform redeploy + nginx reload.PLN (Algolia) authored -
Rich entries for the documentary trail: the freebox-deferred simplification of #27, the open-url-scope-with-apikey-trust decision on #29, the SSRF block set, and how #25/#26 pre-built the seams (result_ref/gc, alias table, born-done path) that made both mostly wiring.
PLN (Algolia) authored -
Two links of the heavy chain, built on the #25 job backbone. Both ship the CODE now; they go live the moment erable ssh is back (yt-dlp install) — no GPU needed. #27 — artifact store (artifacts.py). Big binaries (fetched sources, later stems/ loops) live content-addressed on local disk under FOURIER_ARTIFACTS, tracked as ordinary cache rows (kind→result_ref), so the existing LRU cache.gc() already evicts the coldest under a cap. Freebox was the original SSOT plan — deferred per PLN; erable-local for now. Serving is zero-copy via nginx X-Accel-Redirect (FOURIER_X_ACCEL), FileResponse fallback in dev. resolve() refuses path traversal / anything outside the root. #29 — /sources (engines/sources.py + POST /sources). The worker shells out to yt-dlp → bestaudio → 44.1k WAV (analysis-ready for /separate, /loops, features), content-addresses it, stores it, and aliases url→content_id so a repeat URL is an idempotent born-done job (no re-download). Submit returns 202 {job_id}; poll /jobs/{id}. URL scope is OPEN (any http(s)) per PLN — gated by the platform apikey + nechapi monitoring — but we still hard-block the SSRF footguns (non-http(s), localhost, RFC1918/link-local/reserved IPs; incl. the 169.254.169.254 metadata classic). The fetch is a thin seam so tests mock the network with a synthetic WAV. Also: GET /artifacts/{cid}/{name} serving endpoint; healthz reports yt-dlp presence; _meter now counts by ROUTE TEMPLATE not concrete path (else /jobs/{id} & /artifacts/{id} would mint unbounded Prometheus series). OpenAPI refreshed 13→17 ops, @nech/api regenerated (submitSource/getArtifact/getJob/cancelJob). yt-dlp added to requirements-deploy; DEPLOY.md §5b documents the yt-dlp+ffmpeg install and the nginx internal location. 78→95 tests green.PLN (Algolia) authored -
The audio API was internally codenamed "Douanier" (Le Douanier Rousseau — a customs-officer pun on edge auth). Renamed to "Fourier": the FFT is literally the transform behind /spectrum and most of the feature stack, and central auth is the platform’s job now, not ours — so the name should point at the signal work, not the gate. Internal-codename-only: the public contract (/audio/v1, gateway headers) is untouched. Mechanical case-aware sweep across armada/api + the completed-archive, plus hand-rewritten prose (the Rousseau attribution → Joseph Fourier; dropped the customs-gate /
🛂 metaphors). Renames: douanier.py → fourier.py, deploy/douanier-worker.service → deploy/fourier-worker.service. Env prefix DOUANIER_* → FOURIER_* (config contract; safe — nech.pl is pre-users), dev venv ~/.virtualenvs/douanier → fourier (shebangs fixed). 78 tests green after.PLN (Algolia) authored -
PLN (Algolia) authored
-
The async spine for the heavy chain (sources/separate/loops): the API enqueues and returns a job_id; a worker runs it out-of-band so the API never blocks. Built to the four decisions taken with PLN: - HYBRID sync/async: the 11 cheap analyses stay synchronous (cache-backed); only heavy work becomes a job. The line is wall-clock cost, not endpoint kind. - PER-ENGINE submit + SHARED poll: engines return 202 {job_id} (wired in #29/#30/#31); GET /jobs/{id} polls, DELETE /jobs/{id} cancels. Typed JobStatus response_model so the generated client gets audio.getJob()/cancelJob(). - SINGLE serialized worker: one job at a time (erable is 2 GB / no GPU; two demucs runs would OOM). The atomic claim is still race-safe for N workers. - Identity = gateway tenant; a job is visible only to its owner (cross-tenant poll/cancel → 404, not 403, so existence doesn't leak). Pieces: - db.py: jobs table (status/priority/progress/result/attempts/webhook) + a claim-ordered index. - jobs.py: enqueue (incl. born-done idempotent fast path when the cache already has the result), atomic claim (candidate → guarded UPDATE WHERE status= 'pending'; rowcount-0 retry; WAL serializes writers so no double-claim), progress/finish/fail-with-requeue-under-cap, crash recovery (running→pending on boot), cooperative cancel + is_cancelled checkpoints. - worker.py: serialized loop — recover → claim → dispatch by type → finish/fail → optional webhook; SIGTERM-graceful; imports engine handler modules (none yet, idles politely); engines register via @jobs.handler. - deploy/douanier-worker.service: systemd --user unit (linger) — the durable run path (harness/nohup jobs die on teardown). Prod container-vs-host wiring is the paved-road call (SRE/#34). VALIDATION: tests/test_jobs.py — submit→claim→done; born-done fast path; finish/requeue-to-cap; crash recovery; NO double-claim across 6 threads × 25 jobs (each claimed exactly once); worker dispatch to done; missing-handler error; exception→requeue; cancel mid-flight; HTTP poll + ownership 404 + idempotent cancel. 11 new tests, full suite 67→78 green. OpenAPI snapshot refreshed (15 ops) + @nech/api regenerated (getJob/cancelJob); noImplicitAny relaxed for the 100%-generated client (typescript-fetch's camel/snake guard trips TS7053).PLN (Algolia) authored
-
- 28 Jun, 2026 5 commits
-
-
The hand-written nech.ts was always interim; this replaces it with a client GENERATED from the OpenAPI spec, so the SDK can never drift from the API. Source-of-truth fixes (the spec drives the ergonomics): - Clean operationIds on all 13 routes (operation_id="analyzeEmotion" etc.) so the generator emits `audio.analyzeEmotion({file})`, not the default `analyzeEmotionAnalyzeEmotionPost`. Also cleans /docs. - One router tag ["audio"] so the generated class is AudioApi, not DefaultApi. - refresh_openapi.py: the canonical snapshot dump. app.openapi() omits the public `servers` block (only injected when served behind root_path), and the old README recipe silently dropped it — test_openapi_snapshot guards it, so the refresh now injects https://api.nech.pl/audio/v1 itself. The package (@nech/api, clients/nech-api/): - typescript-fetch generator → src/audio/ (checked in; regenerate via codegen.sh), bundled with tsup to a single ESM file + .d.ts. - Umbrella package, per-domain SUBPATH exports: `import {AudioApi} from '@nech/api/audio'` — one install/version, tree-shakeable, geo/iris slot in as siblings later (codegen.sh + exports map have the stubs). - Build via tsup not bare tsc: the generated code uses extensionless relative imports (./runtime) that Node ESM can't resolve from plain tsc output; bundling sidesteps it entirely. Verified end-to-end: `@nech/api/audio` resolves through the exports map, 13/13 methods present. - publishConfig + .npmrc point the @nech scope at https://npm.nech.pl. VERDACCIO.md: copy-paste runbook to stand the private registry up on erable (container :4873, nginx TLS vhost for npm.nech.pl, seed publisher + lock signups, publish). NOT yet run — `ssh erable` failed with publickey from the build host; needs the key loaded. DNS for npm.nech.pl is already set. README reframed: @nech/api is the official client; nech.ts stays documented as the working drop-in until the registry is live, then it's retired. Scrubbed a $DOUANIER_TOKEN codename leak in the curl example. 67 API tests still green.PLN (Algolia) authored -
PLN (Algolia) authored
-
The platform moved under us between sessions. SRE.md now records the landscape the audio service actually deploys into: - nechapi got its own repo (git@git.nech.pl:pln/nechapi.git) with a golden base image (nechapi/py) + a `nechapi ship` CLI — the paved road. Onboarding is FROM nechapi/py:1 + NECHAPI_ROOT_PATH + `nechapi ship`, not the old hand-rolled docker save/load. - A sibling tenant (geo/v1, Verniquet) is already live through it. - Correction to the 2026-06-25 "CLAP is the wrong engine" line: CLAP is right, used the canonical way — embeddings precomputed OFFLINE, a compact ANN index shipped to erable, request-time = tiny text-embed + cosine. What's wrong is running CLAP at request time on a GPU-less 2GB host. This closes the ops task (#34): observability shipped on the platform side (per-call capture, /admin analytics, public uptime status page — nechapi f89d7f9, now rebased onto the paved road and pushed), and the systemd-restart / deploy-runbook half is subsumed by `nechapi ship` + the golden base, owned in the SRE repo. No bespoke systemd units to write here.
PLN (Algolia) authored -
The 67-test suite existed and was green, but only under a --system-site-packages venv — which made it quietly host-dependent. A system python bump to 3.14 dropped fastapi/httpx from that venv and the whole suite went to "no tests collected" (red, but for an env reason, not a code reason). CI that inherits the host's site-packages would hide exactly this class of breakage. Fix = make the suite hermetic and prove it: - requirements-test.txt pins the real test surface — fastapi/uvicorn/ multipart (via requirements.txt) + numpy + soundfile + librosa + pyloudnorm + httpx + pytest. NOT --system-site-packages. - The heavy ML stack (torch, laion_clap, demucs) is deliberately absent: those engines aren't exercised by the tests, so CI installs in seconds- to-a-minute instead of pulling multi-GB wheels. - Rehearsed in a clean throwaway venv: first run surfaced two masked deps the system venv had been silently supplying — librosa (lazy-imported by signal/feats/ears/grade) and pyloudnorm (the LUFS loudness engine). Pinned both; clean-venv run is now 67 passed. - .gitea/workflows/api-ci.yml runs it on git.plnech.fr for any push/PR touching armada/api/**. Dormant until an act_runner is registered for the repo; the workflow is correct and locally rehearsed. Closes the test-suite + CI task (#35): the suite is reproducible and the pipeline is declared.
PLN (Algolia) authored -
Rich entries for the api.nech.pl platform build-out: first erable deploy + clone3/seccomp gotcha, the realm:domain:path scope convention + central enforcement, Shipow onboarding, and the observability stack (capture + admin analytics + public uptime). Source material for the documentary.
PLN (Algolia) authored
-