memlnaut-nisps/firmware/README.md

42 lines
2.7 KiB
Markdown
Raw Normal View History

Stream 6: extract firmware glue under firmware/ Move the Arduino sketch into firmware/MEMLNaut-NISPS/ and bridge the hardware (memllib) to the platform-agnostic nisps/ library through a slim glue layer. Delete the legacy root-level *AudioApp.hpp, modes/MEMLNautMode*.hpp, voicespaces/, IMLInterface.hpp, XiasriAnalysis, and the src/memlp submodule. Glue layout (firmware/MEMLNaut-NISPS/glue/): audio_driver.hpp - bridge memllib block callback to Mode::process via per-Mode templated trampoline (no virtual dispatch) peripherals.hpp - joystick/pots/buttons -> Mode::set_input + ML primitives midi_io.hpp - MIDI in -> mode.note_on/update_bpm/set_playing, drains mode ControlEvent ring -> MIDI UART mode_select.hpp - using-aliases mapping MEMLNautMode<Name> to nisps::modes::*Mode (build script rewrites the #define MEMLNAUT_MODE_TYPE line) input_router.hpp / output_router.hpp - top-level wire/drain entry points The sketch tree uses src/{memllib,daisysp,nisps} symlinks because Arduino-CLI rejects ".." in include paths from sketch-tree headers. mode_select.hpp #undefs Arduino's sq/min/max/abs/round macros before including nisps headers (some nisps engines use those identifiers as method names). The audio bridge struct is extern in the header and defined in the .ino because inline + __not_in_flash section attribute collide at link time. Verification: arduino-cli compile succeeds for PAFSynth, ChannelStrip, and BreakOr (rp2040:rp2040:solderparty_rp2350_stamp_xl:opt=Optimize3, -std=gnu++20). Host C++ tests under nisps/build still pass (3 binaries, 110+ tests). Build script (scripts/build-firmware.sh) updated to point at the new sketch path; mode-rewrite logic unchanged. Closes meml-gkm.
2026-04-29 16:05:38 +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 `ControlEvent`s 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
```bash
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.
refactor(firmware): delete vendored daisysp and the input_router layer Phase 1 group 8 (S8, ST2, L14). - S8: the vendored src/daisysp tree (96 files, 41 .cpp compiled into every firmware build) and its sketch-tree symlink. Zero consumers — nisps replaced daisysp's PitchShifter with a custom granular implementation. Corrected firmware/README.md and setup-firmware-toolchain.sh, which called it a live submodule. The attribution comment in nisps/dsp/pitch_shift.hpp stays: it is an honest provenance note about a port, not a dependency. Noted while verifying: src/memllib/examples/KassiaAudioApp includes ../../daisysp/..., but examples/ is not symlinked into the sketch tree and is never compiled by the firmware build, so the deletion stands. - ST2: input_router.hpp was a zero-logic speculative layer with one consumer; the .ino now calls bind_peripherals directly. - L14: peripherals.hpp — deleted kAnalogInputCount, PeripheralBindings and the unused spread local, and extracted the duplicated commit-and-train block into one helper. The audit's suggested commit_and_train(mode, feedback) signature could NOT be behaviour-identical: repositioning() implies placing() (both live in ExploreState::Placing), so dispatching on feedback state inside the helper would silently reroute a TogB2 press mid-reposition from commit_place to commit_reposition, which differs (no snapshot restore, clears reposition_). Implemented as commit_and_train(mode, feedback, bool reposition) with the branch decided at the call site, preserving behaviour. Firmware is not compiled by any gate yet (that arrives with the PlatformIO migration, plan §5/S9), so this group is verified by reading and grep only. Gates: run-all-tests.sh ALL GREEN.
2026-07-21 12:49:25 +02:00
`src/memllib` is the only git submodule; the `firmware-common.sh` wrapper rejects builds when it drifts from the recorded revision.
Stream 6: extract firmware glue under firmware/ Move the Arduino sketch into firmware/MEMLNaut-NISPS/ and bridge the hardware (memllib) to the platform-agnostic nisps/ library through a slim glue layer. Delete the legacy root-level *AudioApp.hpp, modes/MEMLNautMode*.hpp, voicespaces/, IMLInterface.hpp, XiasriAnalysis, and the src/memlp submodule. Glue layout (firmware/MEMLNaut-NISPS/glue/): audio_driver.hpp - bridge memllib block callback to Mode::process via per-Mode templated trampoline (no virtual dispatch) peripherals.hpp - joystick/pots/buttons -> Mode::set_input + ML primitives midi_io.hpp - MIDI in -> mode.note_on/update_bpm/set_playing, drains mode ControlEvent ring -> MIDI UART mode_select.hpp - using-aliases mapping MEMLNautMode<Name> to nisps::modes::*Mode (build script rewrites the #define MEMLNAUT_MODE_TYPE line) input_router.hpp / output_router.hpp - top-level wire/drain entry points The sketch tree uses src/{memllib,daisysp,nisps} symlinks because Arduino-CLI rejects ".." in include paths from sketch-tree headers. mode_select.hpp #undefs Arduino's sq/min/max/abs/round macros before including nisps headers (some nisps engines use those identifiers as method names). The audio bridge struct is extern in the header and defined in the .ino because inline + __not_in_flash section attribute collide at link time. Verification: arduino-cli compile succeeds for PAFSynth, ChannelStrip, and BreakOr (rp2040:rp2040:solderparty_rp2350_stamp_xl:opt=Optimize3, -std=gnu++20). Host C++ tests under nisps/build still pass (3 binaries, 110+ tests). Build script (scripts/build-firmware.sh) updated to point at the new sketch path; mode-rewrite logic unchanged. Closes meml-gkm.
2026-04-29 16:05:38 +02:00
## 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/`.