PLN, three rounds in: the OLED "still shows values". Move a fader and you get
the firmware's bare 0-127; move a relative encoder and you get "0", because the
wire value of a relative encoder IS 0-ish. "No info at all." Meanwhile our own
overlay — track name, what the control does, a readout — was being re-summoned
every 0.9 s under a 1.2 s firmware timeout, field-diffed, stamped only on real
bring-ups. Three increasingly clever versions of the same losing move.
The programmer's reference says why, in the display chapter's first list:
"• 05h (5) - 24h (36): Temporary display for Analogue controls (same as CC
indices, 05h (5) - 0Ch (12): Faders, 0Dh (13) - 24h (36): Encoders)
• 35h (53): Permanent/Stationary display
• 36h (54): Overlay/Temporary display"
There are not two display targets. There are thirty-four. Every fader and every
encoder owns a display target of its own, addressed by its own DAW-mode CC
index, and THAT is the one the firmware auto-triggers when you touch the
control — not 36h, which is where we had been writing all evening. Config bit 6
is its on-switch and it defaults to on:
"• Bit 6: Allow Launch Control XL 3 to generate temporary display
automatically on Change (default: Set).
• Bit 5: Allow Launch Control XL 3 to generate temporary display
automatically on Touch (default: Set; this is the Shift + rotate)."
So a fader sweep fired target 05h thirty times a second while we re-summoned
36h once a second. Unwinnable by construction, and no amount of keep-alive
tuning was ever going to change that. It also explains the one part of the
symptom that never fit a timeout story — buttons were fine. Buttons live at
25h-34h, outside the analogue range, own no per-control target, and so were
never contested at all.
And the fix is not to win the fight. Arrangement 4 is the firmware's default:
"4 | 2 lines: Parameter Name and Numeric Parameter Value (default) | Yes | 1 | Name"
One field, Name, and a value the firmware draws itself. The Name field was
empty because nobody had ever written it. Write it, and the display we were
trying to suppress becomes the display we wanted: it already tracks the value at
wire speed and already times its own dismissal. So the driver now labels all 32
analogue controls on their own targets at startup — "d4 # crushbus",
"d5 # octerbus", "d1 level [ard]" — and stands down from the overlay for them.
Faders and A1-A4 carry no ^NN in any .tidal, because they are Ardour-learned
levels; their label comes from the grid's role table instead, with an explicit
[ard] mark. Mid-set, "this fader is Ardour's, not Tidal's" is the most useful
sixteen characters the panel can hold. Unmapped controls say "unmapped", because
dark-means-unmapped is the surface's oldest rule and the screen must not
contradict the LED beside it.
Three controls keep our overlay: the DJF knobs. "HPF 3.4kHz !!" and the heart
frames at the zero detent are prose, and arrangement 4's value field is a
number. For exactly those three targets we clear bits 5+6 — which is the
documented, per-control way to make the firmware stand down — and take the
screen back uncontested. Restored on exit, since a next session finding three
knobs that silently refuse to show a value would be a worse bug than this one.
Along the way, three things the per-control screen made visible by being the
first thing to render our labels at full width:
- set_text filtered to `0x20 <= c <= 0x7E` and so dropped the four reassigned
control codes its own docstring advertised. The language module's heart frames
had been arriving as plain spaces this whole time.
- parse_context said "an inline trailing comment IS the best label" and did not
do it: the only `--` strip was anchored at the start of the body, where a
trailing comment never is, so the Haskell always won. C8 of piment_bresilien
read `d8 # n "23")) --` on a line ending in PLN's own `-- Raise COMEON!`.
The comment is split off first now and preferred.
- With no stage note, the body fallback was raw combinator soup. It now reads
the sample name off the first quoted string and the effect off the first
identifier — "break:18", "n 6" — which is what PLN asked the line to say
("sample name or effect like 'rose:4'"). Across live/: 158 syntax-noisy
labels out of 22368 became 3.
Verification I can actually do, given a write-only display and no readback:
--show-oled dry-runs the whole label table offline, opening no port, and fails
on any name over 16 characters; the new test pins the target numbers against the
guide's table, the exact configure/set_text bytes, that a button raises instead
of writing into the void, that the hearts survive the filter, and the three
parse_context cases above. What no test can prove is a pixel. That needs eyes.
Fallbacks kept in case the name field turns out not to render: --oled-overlay
suppresses every native display and restores the uncontested-overlay behaviour
across the whole surface, and --oled-native-all hands even the DJFs to the
firmware, for the eye test that compares the two side by side.
| Name |
Last commit
|
Last update |
|---|---|---|
| .gitea/workflows | Loading commit data... | |
| armada | Loading commit data... | |
| blocks | Loading commit data... | |
| blog | Loading commit data... | |
| config/wireplumber | Loading commit data... | |
| copycat | Loading commit data... | |
| docs | Loading commit data... | |
| gifts | Loading commit data... | |
| lib-parvagues | Loading commit data... | |
| live | Loading commit data... | |
| output | Loading commit data... | |
| releases | Loading commit data... | |
| sandbox | Loading commit data... | |
| study | Loading commit data... | |
| test | Loading commit data... | |
| tools | Loading commit data... | |
| utils | Loading commit data... | |
| visuals/slop | Loading commit data... | |
| viz | Loading commit data... | |
| .gitignore | Loading commit data... | |
| BootTidal.hs | Loading commit data... | |
| BootTidal.hs.broken | Loading commit data... | |
| BootTidal.visuals.broken.hs | Loading commit data... | |
| CLAUDE.md | Loading commit data... | |
| EVENING.md | Loading commit data... | |
| FOH_MASTER.md | Loading commit data... | |
| LAST_THIRD.md | Loading commit data... | |
| LICENSE | Loading commit data... | |
| MORNING.md | Loading commit data... | |
| PatchBay_MultiChannel.xml | Loading commit data... | |
| PatchBay_Perf.xml | Loading commit data... | |
| PatchBay_Perf5.1.xml | Loading commit data... | |
| README.md | Loading commit data... | |
| RUNBOOK.md | Loading commit data... | |
| SHOPPING_LIST.md | Loading commit data... | |
| TASKS_DUMP.md | Loading commit data... | |
| backlog.md | Loading commit data... | |
| bullet_train.tidal | Loading commit data... | |
| collide.sh | Loading commit data... | |
| debug.tidal | Loading commit data... | |
| didacticpatternvisualizer.pde | Loading commit data... | |
| gig-up.sh | Loading commit data... | |
| gpu-mode.sh | Loading commit data... | |
| hello.sc | Loading commit data... | |
| init_midi.sh | Loading commit data... | |
| intro.md | Loading commit data... | |
| library.txt | Loading commit data... | |
| link_jack.sh | Loading commit data... | |
| link_samples.sh | Loading commit data... | |
| link_samples_all.txt | Loading commit data... | |
| main_fairbanks.scd | Loading commit data... | |
| notes.md | Loading commit data... | |
| parvagues-sc.service | Loading commit data... | |
| perf-audio.sudoers | Loading commit data... | |
| perf-tray.py | Loading commit data... | |
| perf-tray.service | Loading commit data... | |
| perf.sh | Loading commit data... | |
| sample_watch.scd | Loading commit data... | |
| samples.txt | Loading commit data... | |
| setlist_opal2026.txt | Loading commit data... | |
| start_and_midi.scd | Loading commit data... | |
| test.tidal | Loading commit data... |