AMEN AUDIO
AMEN AUDIO / MANUALDownload Markdown ↓

NEUROPOD — screen optional, 21 September 2026

Click the encoder to cycle pages; turn it to select a row. Knob 1 edits the left column and Knob 2 the right, with pickup to prevent jumps. Hold Button 1 to play; choose TRIG NOTE and VELOCITY on PERFORM. Hold Button 2 to record knob motion, or tap to clear the selected row’s lanes. PRESETS: B2 tap loads and hold saves. VISION: B2 cycles visuals. Hold the encoder for the motion panel.

Requires the Daisy bootloader and its QSPI DFU mode. Keeps the bootloader installed. If read-back fails after a complete write, the flasher offers an explicitly unverified restart; check the device before relying on it.

No screen is required. Use the NEUROPOD web editor in desktop Chrome or Edge to see and change settings over USB MIDI. Allow MIDI access when prompted. Audio still comes from the Pod audio output.

The Waveshare 2.42-inch SSD1309 OLED is an optional display for on-device control and feedback. The page and row controls above describe operation with that display. If you add one, see the PRISM wiring guide.


NEUROPOD

MIDI-fed dual-path neuro bass synthesizer for the Electrosmith Daisy Pod (Rev5, Seed / STM32H750), with a host-side measurement harness that drives it over MIDI, records its analog output, and asserts numeric pass criteria.

Rig

 Host (macOS) ── USB ──► EP-136 K.O. Sidekick (multi mode, cue enabled)
     │                     │  ch1 in L/R  ◄── Pod OUT L (SUB) / R (GROWL)
     │                     │  cue out ────► Pod IN L/R (EXT stimulus)
     │                     └  USB captures: 0/1 master, 2/3 main bus (Pod),
     │                        4/5 cue echo (digital stimulus reference)
     └── USB ─────────────► Pod (Seed port): DFU at boot, class-compliant
                            USB-MIDI + SysEx telemetry at runtime
 microSD (FAT32/MBR) in the Pod: /foley/*.wav -> 32 SDRAM slots at boot

Channel map lives in host/nphost.toml — never in test code.

Build & flash (firmware)

cd NEUROPOD/firmware
make                   # app -> QSPI image (Daisy bootloader, APP_TYPE=BOOT_QSPI)
make program-boot      # ONE-TIME: install the Daisy bootloader (device in DFU)
make program-dfu       # flash the app (device in bootloader DFU)

Hands-free reflash: dev builds jump to the bootloader on CC 118 = 127 (infinite DFU window), so make program-dfu needs no button presses. make NP_RELEASE=1 strips telemetry + dev CCs (115/116/118).

Native DSP unit tests (no hardware): make -C firmware/test.

Harness

cd NEUROPOD/host
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/nphost devices          # sanity: EP-136 + "Daisy Seed Built In"
caffeinate -i .venv/bin/nphost cal   # rig calibration (cached in .cal/)

Run one stage:

caffeinate -i .venv/bin/pytest tests/test_t07_mod.py -v

Full hardware suite (~8 min): caffeinate -i .venv/bin/pytest tests/ -q. Headless (CI) tests — analysis self-tests, telemetry codec, report logic, FatFS-in-callback source scan — run without the rig and are never skipped.

Reports & goldens

Every hardware test writes reports/<utc>/<test>.json (measurements, tolerances, verdict). Golden references are committed under golden/:

.venv/bin/nphost report --last    # table of the most recent run
.venv/bin/nphost report --diff    # compare against golden/
.venv/bin/nphost report --bless   # promote the last run to golden/ (explicit)

Authorized gate derates (restore when the rig improves)

Gate Spec Current Restore condition
T4 alias floor (hardware) −60 dB −45 dB HW (+ rig-health < −55 dBFS); −60 dB enforced natively break the USB ground loop (isolated hub / balanced lines)
T9 SD load time < 5 s < 20 s modern Class-10/UHS card (loader measured optimal at 252 KB DMA bursts)

Web editor

webapp/index.html — single-file Web MIDI editor (Chrome/Edge). Open it directly (file:// works) or serve it:

cd NEUROPOD/webapp && python3 -m http.server 8123

Grant the MIDI + SysEx permission when prompted; it auto-connects to "Daisy Seed Built In". Features: full CC map with real-unit readouts (Hz/ct/ms, firmware mapping formulas mirrored), packed-CC decomposition (shapers, texture flags, slot rate/div), live SysEx telemetry (CPU, clock, grains, active preset, motion state, scene RMS trims), device slots (click = recall, alt-click = write editor state into the slot via PC + full push + CC 119), local preset library with JSON export/import, init patch, factory restore, and a play keyboard (A–L keys, Z/X octave).

Motion engine surface (spec changelog #15): XY morph pad (CC 2/3), scene select + alt-click capture, dice bar (tone/family/motion/seq/nudge), spice/chaos/gesture/morph-time, bank select + motion-store save/revert/factory-restore/reset, a full sequencer editor (transport, pattern config, step grid with per-step scene/note/glide/gate/morph/ curve/cond/gesture over SysEx, user p-lock writer, seeds), freeze panel (mix/repitch/playback mode/slices/arm/undo/clear) and frequency-shifter sliders. The step grid is a write-only mirror — dice rolls and pattern loads change the device without updating the view.

FX section (spec changelog #9)

Growl-path-only post chain (sub stays clean): CC 93 growl level; two serial FX slots — CC 94/98 type (OFF/DRIVE/CHORUS/REVERB), 95/99 p1, 96/100 p2, 97/101 mix. Texture voicing: CC 103 pre-injection high-pass (off/20 Hz–2 kHz), CC 104 bake gain (0..+12 dB into the band shapers). CPU valve order: shaper OS 4x->2x first (2x alias floor −97.7 dB native), then grains 16->8.

NOLOAD-section rule (hard-won): .dtcmram_bss and DSY_SDRAM_BSS objects are never zeroed by startup — C++ member initializers on statics placed there silently don't happen. Anything in those sections must be fully initialized by explicit code before the audio callback starts (see FxSlot::Init / Freeverb::Attach).

Motion engine (spec changelog #15)

Scene-based motion layer per the Motion Engine Spec v1.1 delta (docs/MOTION_SPEC_v1.1.md; reconciliation in spec changelog #15): capture scenes A–D (explore mode drunk-walk + encoder capture, RMS-normalized), morph on a vector plane (CC 2/3) with per-param interpolation domains, on-device 64-step sequencer (scenes, standalone notes, gates/glides, trig conditions, Elektron-style signed p-lock deltas), 4-level seeded dice (tone/family/motion/sequence + nudge), punch-in recording into user locks with slide playback, bar-quantized freeze/resample generations, Bode frequency shifter, gesture bus with velocity mapping.

  • Surface: hold encoder >1.5 s to toggle motion UI ↔ legacy pages. Motion CCs: 2 morph X, 3 macro Y/motion, 4 scene sel, 5 morph time, 6 spice, 8 chaos, 10 dice (value=level), 11 gesture, 12/13 freeze mix/repitch, 14/15 shifter Hz/mix. Everything deeper is SysEx F0 7D 4E 50 … (host/nphost/motion.py has builders) — NRPN was impossible (CCs 6/38/98/99 taken).
  • Persistence: 16 banks + 16 patterns at QSPI 0x740000; patterns store seeds + user locks, the generative layer re-derives on load.
  • Tests: make -C firmware/test (dice stats, seed determinism, lock exclusion, SSB rejection, freeze timing, persistence round-trip); tests/test_t17_motion.py for the rig gates (morph safety, loudness invariant, pitch coherence, punch/freeze round-trips).

Known manual checks

  • Encoder click with MIDI active (PB6 share) — verified via telemetry enc.
  • Knob pages / pickup / preset menu — physical (spec §8); knobs write only on motion, MIDI and knobs share ApplyCC.
  • Boot without SD card hangs in the SD probe (T9 known issue; time-boxed probe is future work). Boot WITH card verified.
  • Preset save (CC 119 / Button-2 hold in menu) stalls audio briefly (QSPI erase under XIP) — recall is glitch-gated, save is not.