Skip to content

Make MackieBackend an adapter over the shared C translator - #6

Merged
alphonsom merged 1 commit into
mainfrom
mackie-converge
Aug 11, 2026
Merged

Make MackieBackend an adapter over the shared C translator#6
alphonsom merged 1 commit into
mainfrom
mackie-converge

Conversation

@alphonsom

Copy link
Copy Markdown
Owner

The Mackie Control translation existed twice: once in MackieBackend for the
host bridge, once in src/mcu/c8_mcu.c for the dongle firmware. Two copies of a
protocol mapping drift, and they drift silently — each stays correct against
its own tests while producing different bytes on the wire.

MackieBackend now owns no translation logic. It holds a c8_mcu_t, feeds
surface input into it, and routes its two output callbacks to the MCU port and
to the surface.

Deleted from the C++ side: the MCU note map, the Bank/Nudge/Zoom nav group, the
LCD SysEx parser, the V-pot ring and meter encoding, and the selected-track set.
213 lines removed against 290 added, and most of the addition is the test.

The C module survives because it is the tested one, and because the firmware
compiles that exact file rather than a copy.

Two consequences worth being explicit about

Feedback gains raw(), a passthrough for back-ends that emit device bytes
themselves. The translator already produces Command|8 wire format, so routing
its output through the named encoders would mean decoding it only to encode it
again.

The adapter costs one re-encode. Surface decodes device bytes into Events,
Controller hands those to the on_* methods, and they rebuild the bytes the
device sent. That is a genuine inelegance. It is kept because the alternative —
a byte-level path from Surface straight into the translator — touches every
Surface backend, and this is the code path that only just started working on
Windows. A follow-up, not a bundled change.

The re-encode is exhaustively verified

tests/test_mackie_roundtrip.cpp proves it rather than sampling it:

  • all 8192 fader CC/value combinations (8 strips x 8 low-bit groups x 128 values)
  • both encoder detents on all 8 strips
  • every note/velocity pair that decodes to a button (>15000)

each driven through decode_* and back, with the bytes required to match
exactly. The domains are small enough that guessing would be a choice.

A lossy round trip would shift control values by a least-significant bit or
two — a fader that never quite reaches unity, an encoder that stops responding —
which is precisely the kind of fault that gets blamed on hardware.

Verified

All 5 test suites pass. command8-mackie builds and fails cleanly with the
right message when no MCU port exists. The dongle firmware still builds against
the unchanged c8_mcu.c, and its own host tests pass.

The Mackie Control translation existed twice: once in MackieBackend for the
host bridge, once in src/mcu/c8_mcu.c for the dongle firmware. Two copies of
a protocol mapping drift, and they drift silently -- each stays correct
against its own tests while producing different bytes on the wire.
MackieBackend now owns no translation logic at all. It holds a c8_mcu_t,
feeds surface input into it and routes its two output callbacks to the MCU
port and to the surface. The MCU note map, the Bank/Nudge/Zoom nav group,
the LCD SysEx parser, the V-pot ring and meter encoding and the selected-
track set all come out: 213 lines deleted against 290 added, and most of
what is added is the test.
The C module is the one that survives because it is the tested one, and
because the firmware compiles that exact file rather than a copy.
Two consequences worth being explicit about.
Feedback gains raw(), a passthrough for back-ends that emit device bytes
themselves. The translator already produces Command|8 wire format, so
routing its output through the named encoders would mean decoding it only
to encode it again.
The adapter costs one re-encode. Surface decodes device bytes into Events,
Controller hands those to the on_* methods, and they rebuild the bytes the
device sent. That is a genuine inelegance, kept because the alternative --
a byte-level path from Surface into the translator -- touches every Surface
backend, and this is the code path that only just started working on
Windows. The re-encode is exact, and tests/test_mackie_roundtrip.cpp proves
it exhaustively rather than by sampling: all 8192 fader CC/value
combinations, both encoder detents on all 8 strips, and every note/velocity
pair that decodes to a button, each driven through decode_* and back with
the bytes required to match. The domains are small enough that guessing
would be a choice.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alphonsom
alphonsom merged commit d8ba172 into mainAug 11, 2026
4 checks passed
@alphonsom
alphonsom deleted the mackie-converge branch August 11, 2026 12:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@alphonsom