memlnaut-nisps/firmware/MEMLNaut-NISPS/glue/output_router.hpp
w1n5t0n 5fc37f760e 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 17:05:38 +03:00

28 lines
842 B
C++

// firmware/glue/output_router.hpp — Drains mode events to hardware sinks.
//
// Two sinks today:
// - MIDI (via midi_io.hpp's `drain_mode_events`)
// - I2C (BreakOr's per-track CV outputs — TODO: integrate USeqI2C once
// stream 12 lands the legacy USeqI2C cleanup)
//
// Called from loop1() at audio-rate-adjacent cadence (sub-millisecond is
// fine; MIDI bytes pace themselves through the UART DMA queue).
#pragma once
#include <memory>
#include "midi_io.hpp"
namespace nisps_firmware {
template <typename Mode>
inline void drain_outputs(std::shared_ptr<MIDIInOut> midi, Mode& mode) {
// Sequencer modes run their event pump first, then we drain.
if constexpr (requires { mode.pump_engine_events(); }) {
mode.pump_engine_events();
}
drain_mode_events(midi, mode);
}
} // namespace nisps_firmware