-
fix(lcxl3): we were fighting for the wrong screen — every knob owns its own · 78ba7fca
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.PLN (Algolia) authored78ba7fca
×