feat(lcxl3): the v3 visual language — driver-owned values, latches, and a
surface that breathes at the track's tempo
The design session with PLN, hands on the device, four AskUserQuestion answers
and three live iterations. Everything here is v3-only BY CONSTRUCTION: the
corpus, BootTidal, SC and Ardour still speak v2 absolutes, so the classic LCXL
(PLN's fallback, and his friend's surface) keeps working with zero changes —
"we need to be BC always" is the standing constraint.
THE LANGUAGE (lcxl3_language.py, new — parallel to lcxl-leds.py, replacing
nothing):
- rings: hue = ROLE (per-orbit family anchors, warm rhythm bloc / purple bass /
cool melodics), lightness = VALUE. This is the exact trade v2 could not make
with three LED hues — the settled 2026-07-29 language spent all hue on value
because role had nowhere else to live. RGB dissolves the trade.
- dark = unmapped survives unchanged: it outranks everything on both surfaces.
- DJF row C, PLN's spec after the first blue<->green attempt proved "too
subtle": blue = lows kept, DEEP GREEN BREATHING SLOWLY = the zero mark
(there is no pot ridge on an endless encoder — the 0 must be VISIBLE),
then green -> yellow -> red as the HPF cut grows. Near-silence extremes
breathe to the BEAT — sine, not blink ("a bit aggressive atm"), rate from
the track's setcps (118 BPM for rose_rouge). Wall-clock phase: it breathes
AT tempo without claiming to know Tidal's cycle position — true phase sync
is a feed from SC, later, not a silent assumption now.
DRIVER-OWNED TRUTH (three kinds, one principle):
- encoder VALUES: rows B/C relative, offset-64 decode — MEASURED off PLN's
slow clicks arriving as 63/65/66; the first decoder assumed two's complement
and read +1 as -63, direction inverted, every click a full-range jump. Row A
stays absolute deliberately: A1-A4 are Ardour-learned levels, and integrating
them from a blind seed would yank a live fader toward silence.
- row-E LATCHES: the latch never lived in Tidal (midiOn/midiOff read the last
value) — it lived in the v2 hardware's toggle buttons. v3 DAW buttons are
momentary, so the driver flips state on press, swallows the release, and the
LED paints driver state — which IS what Tidal hears. Row F stays momentary:
gestures are held, and the panic chord needs four simultaneous 127s.
- PAINT as a binding: the device repaints its own defaults on events we cannot
see, so the driver re-asserts the full board every 2 s — same doctrine as
every aconnect link on this rig. Faders are OUT of the paint path: they have
no LEDs, and painting them was a no-op lie this commit stops telling.
OLED:
- touched-control context in CORPUS terms, line 2 parsed from the .tidal:
"# crushbus", "mask <f f f t>", and — best of all — PLN's own inline stage
notes: ^35 shows "HANDS IN THE AIR", ^59 "Le Delay rose!!!", ^36 "Savoy 8/8
Break". His words, on his hardware, at the moment his finger lands.
- anti-blink: fields are diffed and the configure/bring-up pair fires only when
the overlay has likely expired — re-summoning a live overlay every event was
the blink PLN saw.
- gates read ON/off, DJFs read "LPF 43% / BYPASS / HPF 61% !!".
Validated on the live rig across three rounds of PLN's eyes and hands:
translation + paint + OLED coexist in one process; 27 live cells / 13 dark on
rose_rouge; 18/18 controls context-labelled; latch verified against E1.
Showing
tools/lcxl3_language.py
0 → 100644
Please
register
or
sign in
to comment