memlnaut-nisps/firmware
monkey-w1n5t0n c19d84619e feat(firmware): bump memllib to current upstream and dissolve the fork
The §7.5 decision was "rebase our commits onto upstream, then vendor". On
inspection there was no rebase to do, and the inventory that recommended it
(7a30da9) was wrong on two counts — both corrected in this commit.

All three fork commits touch only `examples/`. That directory is not in the
sketch symlink forest (firmware/MEMLNaut-NISPS/src/ links exactly audio,
hardware, interface, synth, utils, PicoDefs.hpp), so it is never compiled.
They existed to let the RL code build against nisps/core *while it was being
ported*, and that port is done — nisps/ml/{jolt,ou_noise,feedback,geo_push}.hpp
cite the upstream sources directly. Two of the 31 commits I flagged as
"work we are missing", `9fcd459 jolts` and `d0d8a72 noise`, are precisely the
ones already absorbed.

So the question was never rebase-or-not but which snapshot to vendor. Current
upstream, because the staleness was already costing us:

  - upstream has DisplayDriver::NavigateToView; the pin does not. The SelfTest
    variant called it and had been failing to compile (worked around in
    b953681). It was written against a newer memllib, not against nothing.
  - e291192 "l r input swap" is a hardware bug fix: the physical L/R input
    sockets are wired to opposite codec ADC channels. Every mode on the old
    pin sees its stereo input backwards.

Verified by building all three variants with arduino-cli:

  SLPWorkshop  145348 flash (+320)  87388 RAM (+4)
  PAFSynth     145300 flash (+312) 107060 RAM (+4)
  SelfTest     141840 flash (+320)  12028 RAM (+4)

Exactly one compile error: the .ino used kSampleRate in a constexpr, and
upstream 1997699 made it a runtime `extern size_t` so a mode can pick its own
rate. constexpr -> const; it is a once-per-second diagnostic print. The uniform
+316 is the AudioDriver/DisplayDriver deltas — the bulky new upstream code
(GrainDelayI16, ReverbI16, ModFXI16, CCSelectView, RLView, VUMeterView,
PSRAMManager) is header-only and unreferenced, so the linker drops all of it.

.gitmodules points at upstream again: with the pin on an upstream commit, the
fork holds nothing the firmware compiles. Phase 0 pointed it at the fork only
because b37fc53 existed on no remote. The fork's feat/nisps-core-swap branch
stays pushed; nothing is destroyed.

Refs: plan §5, §7.5; ALIGNMENT Q4.
2026-07-21 17:04:10 +02:00
..
MEMLNaut-NISPS feat(firmware): bump memllib to current upstream and dissolve the fork 2026-07-21 17:04:10 +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/.