memlnaut-nisps/firmware
monkey-w1n5t0n b953681157 fix(firmware): restore the SelfTest build — it called a DisplayDriver method that does not exist
Found by actually building the firmware, which nothing in this repo does: CI
skips it, run-all-tests.sh skips it, and lint skips it (S9). The SelfTest
variant did not compile:

  glue/selftest.hpp:650: error: 'class DisplayDriver' has no member named
  'NavigateToView'

Pre-existing, not caused by this audit's work: no commit in this series touched
selftest.hpp, and `NavigateToView` appears nowhere in memllib at the pinned
commit. DisplayDriver's actual surface is AddView / InsertViewAfter /
ChangeView(delta) over a carousel.

The call was redundant as well as wrong. DisplayDriver::Setup() leaves
currentViewIndex_ at 0 and the selftest adds exactly one view, so that view is
already the one on screen. Deleting the call restores the build with no
behavioural change on device; a comment records why, since the intent
("navigate to my view") reads as necessary.

Worth noting against Phase 1: SineOsc was KEPT there specifically because "the
firmware selftest uses it". That was still the right call — deleting it would
have added a second breakage to a variant that already had one — but the
justification was weaker than it looked, because the selftest had not compiled
for some time.

Verified by building three variants end to end with arduino-cli, which also
constitutes the first real check of this audit's firmware-side deletions
(daisysp, input_router.hpp, the perf macros, the peripherals helper extraction):

  SLPWorkshop  flash 145028 B   RAM  87384 B (16%)
  PAFSynth     flash 144988 B   RAM 107056 B (20%)
  SelfTest     flash 141520 B   RAM  12024 B  (2%)

Those numbers are also the first per-variant size baseline this project has had
(plan §6.5f wants exactly this as a gate).

Incidentally confirms A6 live: `scripts/build-firmware.sh` rewrote the committed
.ino to select each variant, and the working tree had to be restored after every
build. That is what the PlatformIO migration deletes.
2026-07-21 14:10:05 +02:00
..
MEMLNaut-NISPS fix(firmware): restore the SelfTest build — it called a DisplayDriver method that does not exist 2026-07-21 14:10:05 +02:00
useq-celium docs: restructure design docs into docs/specs (adr/plans/recon), update path references 2026-07-13 23:15:46 +03:00
README.md refactor(firmware): delete vendored daisysp and the input_router layer 2026-07-21 12:49:25 +02:00

firmware/ — Arduino sketch + hardware glue

Thin shell around nisps/. The platform-agnostic ML / DSP / engines / modes live there; this directory contains:

  • MEMLNaut-NISPS.ino — entry point. Picks one mode at compile time, hosts the dual-core lifecycle (Core 0: ML + UI, Core 1: audio + MIDI), and connects glue to mode.
  • glue/audio_driver.hpp — bridges memllib's AudioDriver block callback to Mode::process(stereosample_t). Templated trampoline so no virtual dispatch in audio path.
  • glue/peripherals.hpp — wires MEMLNaut joystick / pots / buttons to Mode::set_input(idx, value) and the ML primitives (draw_weights, move_weights, train, reset).
  • glue/midi_io.hpp — binds incoming MIDI to mode.note_on/note_off/update_bpm/set_playing (where supported); drains outgoing ControlEvents from the mode's ring buffer to the MIDI UART.
  • glue/output_router.hpp — drains engine events + mode events; called from loop1().
  • glue/mode_select.hpp — type aliases mapping MEMLNautMode<Name> identifiers to nisps::modes::<Name>Mode C++ types. Build script rewrites MEMLNAUT_MODE_TYPE between the alternatives.

Building

scripts/build-firmware.sh                # interactive variant prompt
scripts/build-firmware.sh PAFSynth       # build a specific variant
scripts/build-and-flash-firmware.sh      # build + flash via UF2

Target: rp2040:rp2040:solderparty_rp2350_stamp_xl:opt=Optimize3 with compiler.cpp.extra_flags=-std=gnu++20.

Include paths

Arduino-CLI compiles every *.cpp / *.hpp reachable from the sketch directory and from any submodule under src/. Headers under nisps/ are included via relative path (#include "../../nisps/..."). No -I flag injection needed.

src/memllib is the only git submodule; the firmware-common.sh wrapper rejects builds when it drifts from the recorded revision.

Verification

You cannot test on hardware from a sandbox. We verify three things:

  1. arduino-cli compile succeeds for at least three modes (PAFSynth, ChannelStrip, BreakOr).
  2. Host C++ tests in nisps/build still pass — the firmware refactor must not perturb the platform-agnostic library.
  3. git grep confirms no remaining references to deleted root-level files.

Removed

  • Root-level MEMLNaut-NISPS.ino, IMLInterface.hpp, *AudioApp.hpp, XiasriAnalysis.{cpp,hpp} — replaced by nisps/engines/* and firmware/MEMLNaut-NISPS.ino.
  • Root-level modes/MEMLNautMode*.hpp and modes/AudioApps/ — replaced by nisps/modes/* and the mode_select.hpp type aliases.
  • Root-level voicespaces/ — replaced by static voice space data inlined into engines (nisps/engines/paf_synth.hpp etc.).
  • src/memlp/ submodule — replaced by nisps/ml/.