Commit 15c2c86a by PLN (Algolia)

docs+fix(lcxl3): the surface register, and a control PLN commented out no longer glows

PLN: "ok lets list my demands not handled yet and ensure we track all tasks and
ergonomic issues to improve". So the register: every open ask with his own words
attached, stable IDs, grouped by what unblocks what — and the honest note that
ONE probe run at the desk unblocks five screen items at once.

The fix came out of writing it. nouvelle_couleur.tidal carries a parked tempo
knob, a commented `# cps ((range 60 180 "^29")/60/4)`, and the mapped-set
scanner read commented lines — so B1 glowed on a board whose oldest rule is
"dark = unmapped". parse_context already skipped comments; parse_track now does
too. Live: 12 controls -> 11, 18 lit cells -> 17, B1 dark. Uncomment the line
and the next follow tick (under a second) lights it and the tempo readout
appears with it.

Also recorded: the v2 lcxl-leds-watch service has been logging "no LCXL
sequencer port" every 30 s since 22:39 — its name regex cannot match "LCXL3 1",
so it has never touched the v3 board. It was my prime suspect for the
paint-reset mystery and it is innocent; that mystery is reopened with no
suspect. The Midi-Through to SuperCollider re-add is explained though:
MIDIIn.connectAll, re-running on sample reload, exactly as
midi-autoconnect.sh's own header warned it would.
parent 7c297a61
...@@ -1046,3 +1046,85 @@ re-adder. Stale artifacts: `.claude/RESUME.md` is the 08-21 checkpoint (old ...@@ -1046,3 +1046,85 @@ re-adder. Stale artifacts: `.claude/RESUME.md` is the 08-21 checkpoint (old
3. **S1 GENERALIZE (the thread):** track-follow + live BPM + lap reset; restart driver on sept1. 3. **S1 GENERALIZE (the thread):** track-follow + live BPM + lap reset; restart driver on sept1.
4. **S2 probe** with PLN's eyes at the desk. 4. **S2 probe** with PLN's eyes at the desk.
Needs PLN async: Ardour fader-1 ear test; mute-group naming confirm; yaxu question; CosmicFest metadata. Needs PLN async: Ardour fader-1 ear test; mute-group naming confirm; yaxu question; CosmicFest metadata.
## THE SURFACE REGISTER — open demands & ergonomics (opened 2026-08-30)
Every ask of PLN's from the LCXL3 sessions that is NOT yet done, with his own
words where they exist. IDs are stable; reference them in commits.
### Screen truth (blocked on ONE probe run — highest leverage)
- **S-1 render semantics.** Home lap clock frozen at `0:00` on glass while the
ghost ticks; DJF Hz "refresh maybe every 1s, not smooth at all". Hypothesis:
a field write to a VISIBLE target does not repaint without a bring-up.
TOOL EXISTS: `tools/lcxl3-probe-display.py` (uncommitted). Run at the desk:
`python3 tools/lcxl3-probe-display.py --dry-run` to review, then stop the
driver and run it for real. Answers land in scratchpad JSON.
- **S-2 arrangement census** (same probe, step 4). Two answers wanted: which
arrangement puts the NAME on ROW 1 (per-control row 1 is EMPTY today — "l1
empty l2 ... l3 0", the best row wasted), and confirmation that host-supplied
value text works on a per-control target. Unlocks S-3 and S-4.
- **S-3 percentages.** PLN: "shouldnt i see the value, or even a percentage when
its a sometimesBy/somecyclesBy/midiOn/midiOff-like construct?" Needs the ctx
parser to type a knob (probability vs continuous) + host text (S-2).
- **S-4 relative numeric stuck at 0.** Row B/C encoders show `0` on the
firmware's numeric; the value echo did NOT fix it (`09aaf05`). Suspected
firmware limit in relative mode → host text is the road, not more echo.
- **S-5 HAZARD found by the probe worker, unverified:** `CFG_BRING_UP = 0x7F`
is `ARR_TRIGGER | AUTO_TOUCH | AUTO_CHANGE`, so every bring-up may RE-ARM the
auto-display bits we clear on the three DJF knobs — silently restoring the
firmware's number over "HPF 3.4kHz !!". Probe step H5 settles it.
- **S-6 OLED latency** ~100-200 ms knob→screen. Profile `oled_touch` (50 ms
throttle + summon + 3 set_text) once S-1 says which writes are even needed.
### Labels & language
- **L-1 fader labels.** PLN: "remove 'level [ard]' its constant hence noise,
rather e.g. 'd8 jungle_breaks'". Take the orbit's SAMPLE identity from its dN
block; keep an `[ard]` mark only where it disambiguates.
- **L-2 three corpus labels are still combinator soup** (ctx parser fallback).
- **L-3 mute-combo overlay** — DONE `7c297a6` ("MUTE x2 / kick+percs", "all"),
awaiting PLN's eyes.
### The edge layer / dawless direction (design + build)
- **E-1 setlist cursor on Track◀▶.** PLN: "can we control next track prior
track on a set from the controler tho? ... sets as true file lists or
canonical names, then control a set from mostly controler". backlog.md is the
SSOT for membership+order. Now much cheaper: the driver already FOLLOWS the
published track, so the cursor only has to PUBLISH one.
- **E-2 OLED pages on Page▲▼.** PLN: "maybe we can have 'pages' somehow".
Candidate pages: HOME, orbit meters, mapped-control map, set position.
- **E-3 Solo/Arm + Mute/Select + Novation + rec/play.** Census done (65/66/104/
103/102/106/107, all press-verified); no functions bound yet.
- **E-4 SC feed (one OSC tap, three features):** true beat phase (replacing the
integrated estimate), orbit-activity meters, silent-orbit alarm.
- **E-5 lap clock tied to a REC state.** PLN: "time played that track
eventually when in a set recording to help know when overstretching".
### Composing ergonomics (today's asks)
- **C-1 compose/perform mode.** PLN: "the crossfade makes composing harder".
Answered for now with a one-line shadow; the real feature is a live ref +
`compose`/`perform` in BootTidal (board #139 Part A) so no re-eval juggling.
- **C-2 `resetCycles` sits in the pattern block**, so every ctrl+enter restarts
the clock and retriggers the kick ("as if it was a once, not a d1"). Fix is
PLN's call: split it above a blank line. Offer a lint (pvlint rule) that flags
`resetCycles` sharing a block with a `dN $`.
- **C-3 driver auto-launch.** It is still started by hand; RIG UP should own it
(no `--track` needed any more — it follows).
### Rig debts
- **R-1 Ardour fader 1 EAR TEST** — the `config=` fix is applied and unverified
by ears. Oldest open question on the board.
- **R-2 Ardour .map hardening** (`ParVagues_LCXL3.map`) so a surface toggle can
never wipe the 12 learned bindings again.
- **R-3 BC regression test.** The classic LCXL must keep working: driver-owned
detents/values/latches are v3-only by construction, but nothing PROVES it.
Add a mock-lcxl case per `reference_pvlint_and_pvat`.
- **R-4 small:** midimon transport parse gap; midiviz d13/14 homes + KWin
always-on-top; `tools/sweep_state.py` untracked (triage).
### Closed this round (for the archive)
- Track-follow + live BPM + carry policy + tempo detents + mute summary
(`7c297a6`); commented-out controls no longer paint as mapped.
- v2 `lcxl-leds-watch` proven DEAF to the v3 board (name regex) — it is not the
paint-reset culprit; that mystery is REOPENED with no suspect.
- Midi-Thru→SC re-add explained: SuperCollider's own `MIDIIn.connectAll`.
- A1 label off-by-one DISPROVEN ("d9 level [ard]" is correct).
...@@ -306,10 +306,20 @@ def parse_context(text: str) -> dict[int, str]: ...@@ -306,10 +306,20 @@ def parse_context(text: str) -> dict[int, str]:
def parse_track(path: pathlib.Path) -> tuple[set[int], set[int]]: def parse_track(path: pathlib.Path) -> tuple[set[int], set[int]]:
"""(^NN control set, dN orbit set) straight out of a .tidal file.""" """(^NN control set, dN orbit set) straight out of a .tidal file.
COMMENTED-OUT lines do not count, for the same reason `parse_context`
already skips them: nouvelle_couleur.tidal carries a parked tempo knob,
`-- # cps ((range 60 180 "^29")/60/4)`, and counting it lit B1 on a board
whose oldest rule is "dark = unmapped". A control PLN has commented out does
nothing, so it must look like nothing. Uncomment the line and the next
follow tick (< 1 s) lights it.
"""
import re import re
text = path.read_text(errors="replace") text = path.read_text(errors="replace")
ccs = {int(m) for m in re.findall(r"\^(\d+)", text)} live = "\n".join(l for l in text.splitlines()
if not l.lstrip().startswith("--"))
ccs = {int(m) for m in re.findall(r"\^(\d+)", live)}
orbits = {int(m) for m in re.findall(r"\bd(\d+)\b(?=\s*\$|\s*<)", text)} or {int(m) for m in re.findall(r"\bd(\d+)\b", text)} orbits = {int(m) for m in re.findall(r"\bd(\d+)\b(?=\s*\$|\s*<)", text)} or {int(m) for m in re.findall(r"\bd(\d+)\b", text)}
return ccs, orbits return ccs, orbits
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment