Commit 73bb18f1 by PLN (Algolia)

midiviz: only the DAW dialect may be translated, and the pip still warns on both

Shipping the translation on raw_port was too wide. That flag means 'the picture
comes from the board, not the driver', which is true in DAW mode AND in custom
mode -- but only DAW mode has a fixed, known numbering we may rewrite. Custom
mode speaks whatever the user assigned, so translating it would have been a
second wrong picture with the opposite sign.

Not hypothetical: midiviz's reader was on 24:0 'LCXL3 1 MIDI In' at the moment
this was written (its aseqdump child, PPID 7049), i.e. exactly the port the
wide rule would have mistranslated.

So two flags for two questions. raw_port keeps the warning pip on any raw LCXL3
read; v3_dialect authorises the rewrite and only DAW satisfies it.
parent cfda4841
......@@ -1124,6 +1124,7 @@ def build_widget(port_label: str, reader: "Reader | None", scale: float = 1.0,
self.col_t = [0.0] * 9 # column 1..8 last-touch, for the glow
self.stream: deque = deque(maxlen=256) # bottom ribbon, newest right
self.raw_port = False # reading the board, untranslated
self.v3_dialect = False # ...and in the one dialect we can fix
self.drops: list[list] = [] # gutter rain
self._drop_t: dict[int, float] = {} # cc -> last token rained
self.hist: deque = deque([0] * 64, maxlen=64) # events per 100 ms
......@@ -1247,6 +1248,18 @@ def build_widget(port_label: str, reader: "Reader | None", scale: float = 1.0,
# front of it, so its raw port IS the right port, and a pip there
# would be a false alarm on a board that is working.
self.raw_port = ("LCXL3" in label) and ("ParVagues" not in label)
# TWO questions, deliberately not one flag. `raw_port` asks "is the
# picture coming from the board instead of the driver" and drives
# the warning pip -- true in DAW mode AND in custom mode, because in
# both the numbers are not guaranteed to be the corpus's.
# `v3_dialect` asks the narrower "may we translate", and only DAW
# mode may: that is the one dialect whose numbering is fixed and
# known. WATCH_PREFERENCE's third entry is the raw CUSTOM-mode port
# ('LCXL3 1 MIDI In'), which speaks user-assigned numbers -- and
# midiviz was reading exactly that port on 2026-09-23, so
# translating on `raw_port` would have been a second wrong picture
# with the opposite sign.
self.v3_dialect = ("DAW" in label) and ("ParVagues" not in label)
# ── palette / fonts / geometry ─────────────────────────────────────
def _build_palette(self):
......@@ -1499,7 +1512,7 @@ def build_widget(port_label: str, reader: "Reader | None", scale: float = 1.0,
# nothing, and E5-E8 lit E1-E4 for as long as the driver was
# down. A viewer that owns the translation is right either way,
# so the picture no longer depends on another process running.
if self.raw_port:
if self.v3_dialect:
cc = grid.V3_TO_V2.get(cc, cc)
cell = grid.CC_TO_CELL.get(cc)
if cell is not None:
......
......@@ -553,7 +553,7 @@ def test_the_publisher_omits_a_fader_it_has_never_observed(tmp_path, monkeypatch
def test_a_raw_port_move_lands_in_the_cell_the_finger_touched(tmp_path):
mv, w = _offscreen_widget(MV, tmp_path / "absent.json")
try:
w.raw_port = True
w.v3_dialect = True
# C1 on the hardware sends v3 CC 29. Untranslated that is row C's *v2*
# number for a different cell -- the exact mislanding PLN saw as
# "it only moves on abc".
......@@ -571,7 +571,7 @@ def test_a_raw_port_move_lands_in_the_cell_the_finger_touched(tmp_path):
def test_the_translated_port_is_left_exactly_alone(tmp_path):
mv, w = _offscreen_widget(MV, tmp_path / "absent.json")
try:
w.raw_port = False # the driver is up; numbers are ours
w.v3_dialect = False # the driver is up; numbers are ours
cc = grid.ROW_CCS["C"][0]
w.ingest(_cc_event(cc, 77))
assert cc in w.cc and w.cc[cc][0] == 77
......@@ -584,7 +584,7 @@ def test_row_d_is_no_longer_rain_on_the_raw_port(tmp_path):
# all -- so every fader move used to spawn a raindrop and light no cell.
mv, w = _offscreen_widget(MV, tmp_path / "absent.json")
try:
w.raw_port = True
w.v3_dialect = True
for v3 in grid.V3_ROWS["D"]:
w.ingest(_cc_event(v3, 64))
lit = {grid.V3_TO_V2[c] for c in grid.V3_ROWS["D"]}
......@@ -592,3 +592,28 @@ def test_row_d_is_no_longer_rain_on_the_raw_port(tmp_path):
assert all(grid.CC_TO_CELL[c][0] == "D" for c in lit)
finally:
w.close()
@pytest.mark.parametrize("label,translate", [
("128:0 · ParVagues LCXL3", False), # already ours; translating twice is a shift
("24:1 · LCXL3 1 DAW", True), # the ONE dialect with a fixed known map
("24:0 · LCXL3 1 MIDI", False), # CUSTOM mode: user-assigned, not v3
("20:0 · Launch Control XL", False), # a v2 board speaks v2 already
("14:0 · Midi Through", False),
("no MIDI source found", False),
])
def test_only_the_daw_dialect_is_ever_translated(label, translate):
"""Narrower than the pip rule on purpose. The pip asks "is this the board?"
and custom mode answers yes; this asks "do we know its numbering?" and only
DAW mode does. midiviz was reading 24:0 when this was written, so the wide
rule would have mistranslated a live stream."""
assert (("DAW" in label) and ("ParVagues" not in label)) is translate
def test_both_flags_exist_and_the_tick_sets_each_one():
src = open(MV.__file__).read()
assert 'self.raw_port = ("LCXL3" in label)' in src, "the pip rule moved"
assert 'self.v3_dialect = ("DAW" in label)' in src, "the translate rule moved"
assert "if self.v3_dialect:" in src, (
"ingest no longer translates on the narrow flag — if this became "
"raw_port again, custom mode would be mistranslated")
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