Commit b101c415 by PLN (Algolia)

docs(board): the LCXL3 answers three open questions and opens a new one

The board carried 'can third-party SysEx paint arbitrary text to the OLED?'
as UNVERIFIED, with a note that it mattered: HUD v2's alarms are derived
state, not control values, so a closed OLED meant the alarms stayed on
screen. The official programmer's reference settles it — arbitrary 128x64
bitmaps, and the firmware ACKs each frame specifically so you can animate.

Two more close the same way. LED brightness is CC 111 and non-volatile, so
open taste call #11 stops being an argument about whether a bypassed filter
should be bright and becomes a knob. And endless encoders emit deltas, so
pot-pickup does not exist to solve.

The new one is worse than the ones it closed. DAW mode is the only mode the
guide documents paint in, and DAW mode's CC map is fixed and PARTLY OVERLAPS
v2's with different meanings: v2's row-B knobs 29-36 are v3's row 3, and
v2's faders 77-84 are v3's relative-encoder row 1. Nothing errors. Controls
just move one row. That is the exact failure class b5ad8b6c spent 169 files
fixing, so that branch does not merge until this is settled.

Also retracted, with evidence: DIN is not our answer to the USB-hub single
point of failure. aconnect shows only Midi Through and the controller — this
machine has no MIDI DIN input at all, so DAW mode disabling the DIN outputs
costs nothing today.

And snare is still not cleared. 'Also a default tidalcycles CC0 pack' is a
name collision: upstream tracks 52 files under sn/ and zero under snare/.
The 90-file snare bank is local and unidentified, and still gates 4 tracks.

CosmicFest is closed as a mastering input by PLN's call. Five probes agree
nothing was captured to this machine; he had a stage mic and rates it poor.
parent b5ad8b6c
......@@ -585,3 +585,226 @@ highlight stylesheet is already proven to set no layout-affecting property
uncommitted edits, untouched all session (`feedback_...` — backlog is never mechanized).
* `Tidal`: `live/midi/nova/breaks/hello_fred.tidal` is a 1-line stub (`d1 $ `) — deliberately
not committed.
---
## AMENDMENT — 2026-08-28, post-CosmicFest reconciliation *(LCXL3 in hand)*
No gig is scheduled. Focus declared by PLN: **mastering, tooling debt, comms** — and
this session is explicitly a **probe/explore/test session** for the new controller:
*"we wanna probe, explore, test stuff. you can even write ad-hoc test soft for us to
explore the interactions, UX, possiblities, OLED displays, visual language, etc. lets
take the time."*
### ✅ EPIC D · LCXL v3 — the UNVERIFIED block is now VERIFIED. Delete the guesswork.
Source: the official [programmer's reference guide v1.0](https://fael-downloads-prod.focusrite.com/customer/prod/downloads/launch_control_xl_3_programmer_s_reference_guide-pdf_en.pdf).
Device confirmed present: USB `1235:0148`, ALSA `client 20: 'LCXL3 1'`, card 1 `L1`.
**The OLED is fully open — the board's biggest open question, answered YES.**
- Bitmap: `F0 00 20 29 02 15 09 <target> <1216 bytes> 7F`. 19 bytes/row x 64 rows,
7 px per byte, MSB = leftmost. Target `20h` stationary, `21h` global-temporary.
- **It ACKs each frame** (`F0 00 20 29 02 15 09 7F`) *"suitable for timing fluid
animations"* — so animation is a designed-in feature, not a hack. DESIGN.md's
"alarms need motion" is therefore satisfiable ON THE DEVICE.
- Text path (cheaper, sharper): `F0 00 20 29 02 15 06 <target> <field> <ascii> F7`,
ASCII 20h-7Eh plus Empty Box 1Bh / Filled Box 1Ch / Flat 1Dh / Heart 1Eh.
Arrangements 1-4; **arrangement 3 = "1 line + 2x4: Title and 8 names"**, i.e. built
for labelling 8 encoders.
- Limits that are real: 1-bit mono, **firmware holds ONE bitmap at a time**.
**True RGB per control:** `F0 00 20 29 02 15 01 53 <idx> <R> <G> <B> F7` (buttons and
encoder rings). Palette path: `B0 <idx> <colour>`, 128 colours.
**Endless encoders are per-ROW opt-in, not default:** `B6 45h/48h/49h 7Fh` for rows
1/2/3. Pivot `40h` = no movement, `41h` = +1 step, `3Fh` = -1 step.
**Feature CCs (DAW in port, ch 7; query on ch 8; reply always ch 7):**
`30` surface-mode select+report · `63` Shift · `69/72/73` per-row relative ·
`70` fader pickup · `71` touch events · **`111` LED brightness (non-volatile)** ·
**`112` screen brightness** · `113` temporary-display timeout · `120` Out2 thru ·
`100` global MIDI channel · `121` encoder curve (slow/med/fast).
Standalone needs `9F 0B 7F` to enable feature controls.
**Modes:** CC 30 both reports AND sets — DAW Mixer `01`, DAW Control `02`,
Custom 1-4 `06-09`, 5-8 `12h-15h`, 8-16 `16h-1Dh`. Shift + Mode opens the on-device
Custom Mode Settings menu.
### 🔴 NEW BLOCKER on the #94/#176 migration — the v3 DAW map SILENTLY OVERLAPS v2
DAW mode's CC map is **fixed**: faders `5-12`, encoders `13-20 / 21-28 / 29-36`,
buttons `37-44 / 45-52`. Compare v2 (`reference_lcxl_column_grid`):
| control | v2 CC | v3 DAW CC | verdict |
|---|---|---|---|
| knob row A | 13-20 | 13-20 | identical |
| knob row B | 29-36 | 21-28 | **v3 reuses 29-36 for row 3** |
| knob row C | 49-56 | 29-36 | shifted |
| faders | 77-84 | 5-12 | **v3 relative-encoder row 1 IS 77-84** |
| buttons | 41-44/57-60/73-76/89-92 | 37-44/45-52 | all move |
Nothing errors; controls just move one row. That is precisely the failure class
`b5ad8b6` spent 169 files fixing. **Consequence: the unmerged migration branch may
need to be re-derived for v3, or deliberately frozen at v2 numbering.** Do not merge
`b5ad8b6` until the mode question below is settled.
### ⚠️ RETRACTED board claim — DIN is NOT our USB-SPOF mitigation
EPIC D and `reference_lcxl_v3_ordered` both claim *"a DIN path is independent of USB,
which is a real gig-reliability win"*. Measured on the live system: `aconnect -l`
shows only `Midi Through` and `LCXL3 1`**there is no MIDI DIN input on this
machine at all** (the UMC202HD has no MIDI jacks). The controller could speak DIN all
night and nothing host-side would hear it. So DAW mode's "DIN outputs disabled"
restriction **currently costs nothing**, and #154's mitigation must come from
elsewhere (a powered hub on its own port, or a second interface).
### THE KEYSTONE PROBE — decides everything above, costs ~10 minutes
The guide places *Colouring the surface* and *Controlling the screen* inside the DAW
mode chapter, prefaced *"only available once DAW mode is enabled"*. **That is a
document claim, not a tested one**, and `feedback_check_the_instrument_first` applies.
- [ ] Send `B0 <idx> <colour>` and the bitmap SysEx to the **MIDI In** port in
standalone mode. If paint works there, we get colour + OLED for **zero corpus
churn** and the whole renumbering problem evaporates.
### CosmicFest — closed as a mastering input
PLN: *"stage mic, and imo we have a bad rec cause the whole soundsystem had effects
and at some points ppl messed with it lol. well see, not a focus important atm."*
Verified absence, five independent probes: Ardour "Tidal Live" newest wav 2026-08-14
(`GetTogether2`); no audio under `Work/Sound/` since 08-20; 0 files in
`~/Videos ~/Music ~/Desktop` since 08-20; newest gig-log `gig-20260820-171315.jsonl`;
no `*cosmic*` dir on the (mounted) freebox.
- **No forensics, no rec-arm gate** — PLN's call, recorded here so nobody re-opens it.
- Still open, unchanged: `content/lives/2026/cosmicfest.md` + `tracks.json` from PLN's
details. **Never backfilled from a commit message** (`feedback_metadata_vs_mastering`).
- So "mastering focus" means **the OPAL-26 release backlog**, not new CosmicFest audio.
### A4 rights ledger — real numbers, replacing "29 of 60"
`armada/tide-table/rights_ledger.json`: **103 banks**`third_party` 43,
`unknown` 31, `dirt_samples` 19, `cleared` 10. The board's "30 of 60 answered" is
stale in both numerator and denominator.
### 🆕 Newly found this session
- **HUD BUG (mechanism known): `scene-off` is an action, not a state.**
`pulsar-parvagues-hud/lib/scenes.js:236 off()` tears down `mediaEl` and returns; the
re-apply path at `:284-289` runs on every buffer parse and does
`spec = _directiveScene || cfg.defaultScene -> show(file)`. So any ctrl+save
resurrects a scene you turned off. Fix: a `_userOff` latch set by the command,
checked at `:284`, cleared on explicit scene-on / mode toggle / track change.
PLN, verbatim: *"bug on scene off in hud when i ctrl+save the tidal track again
scene restarts :facepalk:"*
- **Stale device-name match for v3.** `tools/bridge/rig.py:120` matches `"LCXL"` so it
survives, but `tools/bridge/surface.py:51 SURFACE_NAME = "Launch Control XL"` will
NOT match `LCXL3 1`. Worse: surface.py *"prefers the LOWEST port number"*, which on
v3 is `MIDI In` (port 0) — DAW is port 1. In DAW mode that heuristic picks wrong.
- **Open taste call #11 is now a knob, not a debate.** LED brightness is CC 111 and
non-volatile; screen brightness CC 112. Reframe `project_open_taste_calls`.
- **Firmware:** device inquiry replies `F0 7E 00 06 02 00 20 29 48 01 00 01 01 00 0A 54
F7` — version field `01 00 0A 54`, which *reads* as 1.0.x (pre-v1.1), but that field
is undocumented so it is an inference. Authoritative check is on-device: unplug, hold
both Page buttons, plug in — the screen shows Application + Bootloader versions.
v1.1 (Jan 2026) adds Pro Tools/Reaper/Studio One, USB-to-DIN passthrough, Shift+fader
value on the OLED, adjustable encoder response.
### PLN's OLED priorities (answered 2026-08-28, multi-select)
1. **Floor debt + kick %** — the measured problem (59% of OPAL-26).
2. **Unplayed-orbit alarm** — the d9 SUGAR CHOIR class.
3. **Rig health** — xruns/CPU/scsynth alive/Ardour rec-armed.
4. Verbatim addition: *"unplayed orbit and also unplaued effect, or button, unless we
display already that 'you didnt touch this since that track started' state in the
button color per se"* — i.e. **untouched-since-track-start belongs on the CONTROL,
not the screen.** This merges with C4 (HUD touched/untouched). Constraint that
governs it: `feedback_dark_means_unmapped_outranks_all` — dark already means "not
mapped", so untouched must NOT be dark. With RGB we have room: untouched =
desaturated role hue, touched = saturated. Must stay consistent with
`reference_lcxl_colour_settled`.
---
## AMENDMENT — 2026-08-28 (later): PLN's answers + the playability gate
### Firmware CONFIRMED from the device: **1.0.1364.0**, bootloader same, Easy Start ON
PLN read the bootloader screen (unplug → hold both Page → plug in). This also
validates the decode: the inquiry reply's version field is **7-bit packed**
`01 00 0A 54``1`, `0`, `(10<<7)|84` = **1364**. Record that; it is undocumented.
- [ ] **Update to firmware v1.1.** We are behind. v1.1 adds Pro Tools/Reaper/Studio
One, USB-to-DIN passthrough with channel filtering, **Shift+fader shows the value
on the OLED**, and adjustable encoder response. Components is documented as
Mac/Windows — **untested whether Chromium WebMIDI on Linux works**; that is the
first thing to try, and if it fails the update needs a borrowed machine.
- [ ] **Turn Easy Start OFF** (bootloader mode, Record button). While on, the device
also mounts as Mass Storage — noise we do not want in the rig's device graph.
### ❌ A4 `snare` — NOT cleared. PLN's read was a name collision. Proof:
PLN: *"snare rights its also a default tidalcycles CC0/public domain pack!"*
Checked against the actual upstream checkout
(`…/downloaded-quarks/Dirt-Samples`, a git clone of `github.com/tidalcycles/Dirt-Samples`):
git ls-files -- 'snare/*' -> 0 files tracked upstream
git ls-files -- 'sn/*' -> 52 files tracked upstream
**The default TidalCycles snare bank is `sn`. `snare` is a separate local bank** (90
files, ledger `origin: local`, `status: unknown`). Textbook
`reference_sample_rights_audit`: *"in the Dirt-Samples folder" ≠ a Dirt-Samples bank.*
The ledger entry is therefore left at `unknown`**it still gates 4 tracks.**
Two ways forward, both cheap, PLN's call:
- **Identify it** — fingerprint the 90 files against known packs (`rights_audit.py`,
CLAP tags), or find the download it came from.
- **Substitute it** — swap `snare``sn` in the 4 gated tracks. Mechanically trivial,
but it changes the sound, so it is a taste call, not a chore.
### Priorities set by PLN (supersedes the "Recommended order" above)
> *"lets do the lcxl3 and the tracks repair/migration finish as priorities imo. but for
> this i need be able to play tracks with lxcl3 so prio is that?"*
- **PARKED tonight:** the A3 SoundCloud re-run (*"maybe not tonight"*).
- **STILL TODO, unscheduled:** CosmicFest — the www page + `tracks.json` (metadata from
PLN only). Its audio is a stage-mic recording PLN rates as poor; not a mastering input.
- **1st:** LCXL3 **playable with the existing corpus**. 2nd: finish the track repair /
migration. Everything else waits.
### 🔑 The gate PLN identified, and it is correct
The migration cannot be *judged* without playing it, and it cannot be played without the
LCXL3 driving the rig. So **playability precedes the numbering decision** — the reverse
of what the earlier amendment implied. It also means the numbering question must be
answered in a way that does **not** require touching 169 files before he can play.
### The design that satisfies both: a SURFACE DRIVER (adapter), not a renumber
Put an adapter between the v3 hardware and SuperDirt:
LCXL3 (DAW mode) ──▶ surface driver ──▶ virtual ALSA port ──▶ SC/SuperDirt
v3 fixed CCs translate + integrate v2 CC numbers, absolute
What it buys, all at once:
- **Playable with zero corpus churn** — the 169 tracks, `BootTidal.hs` `_seed`, pvlint
and `lcxl_grid.py` keep the v2 numbering they already agree on. `b5ad8b6` can merge on
its own merits instead of being hostage to the hardware.
- **Paint stays available** — we run in DAW mode, so RGB + OLED are on the table.
- **Relative encoders need an integrator anyway.** Endless encoders emit deltas
(`65` = +1, `63` = -1) and Tidal's `^NN` wants absolute 0-127. Whoever integrates them
*owns the value* — so the driver is the natural home for it, and that also makes
`lcxl-init.py`'s seeding meaningful again instead of obsolete.
- **It is where the paint belongs.** Holding the value is exactly what you need to paint
a ring by value, desaturate an untouched control, or draw the OLED. C2 + C4 land here.
Cost, stated honestly: one more process in the MIDI path, and one more thing that can
break — mitigated by following the existing `midi-autoconnect` systemd-unit pattern
(`reference_rig_reconciler_units`) and by `feedback_verify_the_plumbing` (prove it with
real events, not unit tests on pure functions).
### Session sequence, approved shape
1. `tools/lcxl3-probe.py` — the bench (enumerate, raw SysEx tx/rx, decode every event).
2. **The keystone probe** — does paint work in STANDALONE, or is DAW mode required?
3. OLED sketchpad — render 128x64 frames so the visual language is judged by eye.
4. HUD `scene-off` latch (`scenes.js:236` / `:284`).
5. Then: surface driver → play a track → judge the migration.
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