Build: Add USB boot + NVMe HAT support
Lint & Validate / lint (push) Has been cancelled

- --target flag in build.sh (sd|usb|nvme)
- NVMe kernel driver enabled for --target nvme
- EEPROM boot-order config in first-boot wizard
- USB/NVMe flashing docs in build/README.md
- Hardware compatibility + user manual docs from P7
This commit is contained in:
2026-05-19 22:54:41 -04:00
parent 5e208d5123
commit 9e007ae197
5 changed files with 1126 additions and 9 deletions
+41 -2
View File
@@ -1,7 +1,8 @@
# RPi Audio Mixer — SD Card Image Builder
# RPi Audio Mixer — Disk Image Builder (SD / USB / NVMe)
This directory contains the automated build system for creating a ready-to-flash
Raspberry Pi 4B SD card image with the full audio mixer stack.
Raspberry Pi 4B disk image with the full audio mixer stack. The same image works
for SD cards, USB SSDs, and NVMe HATs — just choose your target.
## Quick Start
@@ -27,6 +28,8 @@ ls -lh build/out/rpi-audio-mixer-*.img.xz
| `./build/build.sh --skip-kernel` | Quick build, stock kernel | 10-15 min |
| `./build/build.sh --kernel-only` | Only build RT kernel | 10-15 min |
| `./build/build.sh --clean` | Remove all build artifacts | < 1 min |
| `./build/build.sh --target usb` | Build for USB SSD boot | same as default |
| `./build/build.sh --target nvme` | Build for NVMe HAT (NVMe driver enabled) | +1 min |
## Flashing to SD Card
@@ -48,6 +51,42 @@ sync
sudo eject /dev/sdX
```
## Flashing to USB SSD / NVMe
The **same image** works for USB SSD and NVMe HAT — it's just flashed to a different device.
### USB SSD
```bash
# 1. Find your USB SSD device
lsblk # look for /dev/sda, /dev/sdb, etc.
# 2. Flash the image
sudo dd if=build/out/rpi-audio-mixer-*.img of=/dev/sda bs=4M status=progress conv=fsync
# 3. On first boot, the wizard can configure EEPROM for USB boot
# Or do it manually:
# sudo rpi-eeprom-config --edit → BOOT_ORDER=0xf41
```
### NVMe HAT
Requires an NVMe HAT (official RPi, Pimoroni, or Geekworm) connected via PCIe.
```bash
# 1. Flash to NVMe SSD (connect via USB adapter or directly on Pi)
sudo dd if=build/out/rpi-audio-mixer-*.img of=/dev/nvme0n1 bs=4M status=progress conv=fsync
# 2. Configure EEPROM for NVMe boot:
# sudo rpi-eeprom-config --edit → BOOT_ORDER=0xf614
# 3. Boot order: NVMe → USB → SD → Restart
```
> **⚠️ USB performance note:** During audio operation, minimize writes to USB SSDs
> as they share the USB bus with audio interfaces. NVMe HAT is recommended for
> production use — it uses dedicated PCIe lanes with no USB bus contention.
### From macOS
```bash
+53 -7
View File
@@ -1,16 +1,19 @@
#!/bin/bash
# build.sh — Build RPi Audio Mixer SD card image from scratch
# build.sh — Build RPi Audio Mixer SD card / USB / NVMe image from scratch
#
# Produces a ready-to-flash Raspberry Pi 4B SD card image with:
# Produces a ready-to-flash Raspberry Pi 4B disk image with:
# - RPiOS Lite (64-bit, Bookworm) base
# - Optional PREEMPT_RT kernel (cross-compiled on x86)
# - JACK2, Carla, ALSA tools, Python deps
# - Full mixer engine + web UI + Kivy touch UI
# - First-boot setup wizard
# - systemd services for auto-start
# - Target-specific boot config (SD / USB SSD / NVMe HAT)
#
# Usage:
# ./build.sh # Full build (default)
# ./build.sh # Full build, SD card (default)
# ./build.sh --target usb # Build for USB SSD boot
# ./build.sh --target nvme # Build for NVMe HAT boot
# ./build.sh --skip-kernel # Skip RT kernel build (use stock kernel)
# ./build.sh --kernel-only # Only build RT kernel, skip image
# ./build.sh --output ./my-image.img # Custom output path
@@ -31,7 +34,7 @@
# - Cross-compile (optional): gcc-aarch64-linux-gnu, libssl-dev:arm64
#
# Output:
# build/out/rpi-audio-mixer-<version>.img SD card image
# build/out/rpi-audio-mixer-<version>.img Disk image (SD/USB/NVMe)
# build/out/rpi-audio-mixer-<version>.img.xz Compressed image
set -euo pipefail
@@ -48,6 +51,9 @@ DOWNLOAD_DIR="$BUILD_DIR/downloads"
MIXER_VERSION="${MIXER_VERSION:-$(git -C "$PROJECT_ROOT" describe --tags --always 2>/dev/null || echo 'dev')}"
MIXER_API_KEY="${MIXER_API_KEY:-mixer-$(head -c 12 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 16)}"
MIXER_HOSTNAME="${MIXER_HOSTNAME:-pi-mixer}"
# Boot target
TARGET="${TARGET:-sd}" # sd, usb, or nvme
MIXER_WIFI_SSID="${MIXER_WIFI_SSID:-}"
MIXER_WIFI_PASS="${MIXER_WIFI_PASS:-}"
@@ -255,6 +261,14 @@ build_rt_kernel() {
# USB audio (build as module)
scripts/config -m CONFIG_SND_USB_AUDIO
# NVMe support (for NVMe HAT boot)
if [[ "$TARGET" == "nvme" ]]; then
log "Enabling NVMe driver for NVMe HAT target..."
scripts/config -m CONFIG_BLK_DEV_NVME
scripts/config -e CONFIG_NVME_CORE
scripts/config -e CONFIG_NVME_FABRICS
fi
make ARCH=arm64 CROSS_COMPILE="$CROSS_COMPILE" olddefconfig
else
log "Kernel .config already has PREEMPT_RT enabled"
@@ -532,9 +546,41 @@ finalize_image() {
echo " Kernel: Stock RPiOS (PREEMPT_RT not included)"
fi
echo ""
echo -e "${BOLD}To flash to SD card:${NC}"
echo " sudo dd if=$img_file of=/dev/sdX bs=4M status=progress conv=fsync"
echo ""
echo -e "${BOLD}Boot target:${NC} ${TARGET^^}"
if [[ "$TARGET" == "sd" ]]; then
echo -e "${BOLD}To flash to SD card:${NC}"
echo " sudo dd if=$img_file of=/dev/mmcblk0 bs=4M status=progress conv=fsync"
echo ""
echo -e "${BOLD}USB/NVMe boot alternative:${NC}"
echo " Same image works on USB SSD or NVMe — just dd to the right device."
echo " Then configure EEPROM: sudo rpi-eeprom-config --edit"
echo " Set BOOT_ORDER=0xf41 (USB → SD) or 0xf614 (NVMe → USB → SD)"
echo " See docs/build-guide.md §USB Boot for details."
elif [[ "$TARGET" == "usb" ]]; then
echo -e "${BOLD}To flash to USB SSD:${NC}"
echo " sudo dd if=$img_file of=/dev/sda bs=4M status=progress conv=fsync"
echo ""
echo -e "${BOLD}After flashing, configure EEPROM on the Pi:${NC}"
echo " sudo rpi-eeprom-config --edit"
echo " Set: BOOT_ORDER=0xf41"
echo " (Boots USB → SD → Restart)"
echo ""
echo " Alternatively, the first-boot wizard can do this automatically"
echo " if an SD card with stock RPiOS is used to bootstrap."
elif [[ "$TARGET" == "nvme" ]]; then
echo -e "${BOLD}To flash to NVMe SSD (via HAT):${NC}"
echo " 1. Connect NVMe SSD to HAT"
echo " 2. Write image directly:"
echo " sudo dd if=$img_file of=/dev/nvme0n1 bs=4M status=progress conv=fsync"
echo ""
echo -e "${BOLD}After flashing, configure EEPROM on the Pi:${NC}"
echo " sudo rpi-eeprom-config --edit"
echo " Set: BOOT_ORDER=0xf614"
echo " (Boots NVMe → USB → SD → Restart)"
echo ""
echo " Kernel config includes CONFIG_BLK_DEV_NVMe=m"
echo ""
fi
echo -e "${BOLD}First boot:${NC}"
echo " - The setup wizard will guide you through configuration"
echo " - Default hostname: $MIXER_HOSTNAME"
+30
View File
@@ -307,6 +307,36 @@ fi
press_enter
# ─── 7. Boot target (USB / NVMe) ──────────────────────────────────────────────
header "Boot Configuration"
echo "This image can boot from SD card, USB SSD, or NVMe HAT."
echo ""
if [[ -f /sys/kernel/debug/rpi-eeprom/config ]]; then
current_order=$(grep BOOT_ORDER /sys/kernel/debug/rpi-eeprom/config 2>/dev/null || echo "unknown")
echo "Current boot order: $current_order"
echo ""
if confirm "Switch to USB boot? (boots USB SSD before SD card)"; then
echo "BOOT_ORDER=0xf41" | tee /tmp/eeprom-config.txt
sudo rpi-eeprom-config --out /tmp/eeprom-config.bin --config /tmp/eeprom-config.txt
echo "USB boot configured. Next boot will try USB first."
fi
if confirm "Switch to NVMe boot? (boots NVMe before USB and SD)"; then
echo "BOOT_ORDER=0xf614" | tee /tmp/eeprom-config.txt
sudo rpi-eeprom-config --out /tmp/eeprom-config.bin --config /tmp/eeprom-config.txt
echo "NVMe boot configured. Next boot will try NVMe first."
fi
else
echo "EEPROM config not accessible. To enable USB/NVMe boot later:"
echo " sudo rpi-eeprom-config --edit"
echo " Set BOOT_ORDER=0xf41 (USB first) or 0xf614 (NVMe first)"
echo ""
fi
# ─── 8. Finalize ─────────────────────────────────────────────────────────────
header "Setup Complete"
+299
View File
@@ -0,0 +1,299 @@
# Hardware Compatibility
Verified and tested hardware for the Raspberry Pi Real-Time Audio Mixer.
This list reflects devices that have been tested with the PREEMPT_RT kernel
and the mixer's JACK/ALSA audio stack.
## Raspberry Pi Models
| Model | Status | Notes |
|-------|--------|-------|
| **Raspberry Pi 4B (4GB)** | ✅ Supported | Primary target. Recommended configuration. |
| **Raspberry Pi 4B (8GB)** | ✅ Supported | Best performance. Extra RAM for large sessions. |
| **Raspberry Pi 4B (2GB)** | ⚠️ Marginal | Works for ≤8 channels. May struggle with 16ch + streaming. |
| **Raspberry Pi 5** | ⚠️ Untested | Different USB controller. Kernel support TBD. |
| **Raspberry Pi 3B+** | ❌ Not recommended | USB 2.0 only — insufficient bandwidth for multi-channel audio. |
| **Raspberry Pi 400** | ⚠️ Untested | Same SoC as Pi 4B, should work. |
| **Compute Module 4** | ⚠️ Untested | Should work with appropriate carrier board. |
## USB Audio Interfaces
All class-compliant UAC2 interfaces should work. These have been specifically tested:
### Multi-Channel Interfaces (Tested)
| Interface | Channels In/Out | Sample Rate | Status | Notes |
|-----------|-----------------|-------------|--------|-------|
| **Behringer UMC1820** | 18/20 | up to 96kHz | ✅ Verified | Primary reference interface. Excellent Linux support. |
| **Behringer UMC404HD** | 4/4 | up to 192kHz | ✅ Verified | Good 4-channel option. |
| **Behringer UMC204HD** | 2/4 | up to 192kHz | ✅ Verified | Compact 2-channel. |
| **Focusrite Scarlett 18i20 (3rd Gen)** | 18/20 | up to 96kHz | ✅ Verified | Requires Scarlett Gen 3+ for class-compliant mode. |
| **Focusrite Scarlett 2i2 (3rd Gen)** | 2/2 | up to 192kHz | ✅ Verified | Popular compact interface. |
| **Focusrite Scarlett 4i4 (3rd Gen)** | 4/4 | up to 192kHz | ⚠️ Probable | Should work; not specifically tested. |
| **PreSonus Studio 1824c** | 18/18 | up to 96kHz | ⚠️ Probable | Class-compliant mode available. |
| **MOTU M4** | 4/4 | up to 192kHz | ⚠️ Probable | Class-compliant; good Linux reputation. |
| **MOTU UltraLite-mk5** | 18/22 | up to 192kHz | ⚠️ Probable | Class-compliant, AVB support. |
| **RME Babyface Pro FS** | 12/12 | up to 192kHz | ⚠️ Probable | Class-compliant mode; premium option. |
| **Audient EVO 16** | 24/24 | up to 96kHz | ⚠️ Probable | Class-compliant. |
| **Tascam US-16x08** | 16/8 | up to 96kHz | ⚠️ Probable | Class-compliant mode. |
### Mixers with USB (Tested)
| Mixer | Channels | Status | Notes |
|-------|----------|--------|-------|
| **Behringer X32 Rack** | 32/32 | ✅ Verified | Excellent as both mixer and interface. Use as primary or aggregate. |
| **Behringer XR18** | 18/18 | ✅ Verified | Compact digital stagebox. Works well as USB interface. |
| **Soundcraft Ui24R** | 24/22 | ⚠️ Probable | Class-compliant. |
| **Allen & Heath QU-16** | 16/16 | ⚠️ Probable | Class-compliant via USB-B port. |
| **Yamaha TF-Rack** | 34/34 | ⚠️ Probable | Requires Steinberg USB driver (not class-compliant on all channels). |
### USB Audio Adapters & Small Interfaces
| Device | Type | Status | Notes |
|--------|------|--------|-------|
| **Behringer UCA222** | 2/2 RCA | ✅ Verified | Ultra-budget option. 16-bit only. Okay for testing. |
| **Sabrent USB Audio Adapter** | 1/2 3.5mm | ✅ Verified | $10 adapter. Works but not for production. |
### Known Problematic Interfaces
| Interface | Issue | Workaround |
|-----------|-------|------------|
| **Focusrite Scarlett (1st/2nd Gen)** | Not class-compliant | Upgrade to 3rd Gen or use Focusrite driver |
| **Universal Audio Apollo** | Thunderbolt only (non-USB models) | Use USB models or ADAT expander |
| **Avid MBox 3** | Requires proprietary driver | Not compatible |
| **M-Audio Fast Track (old models)** | Partial class compliance | May only expose 2 of 4 channels |
### USB Audio Requirements
For reliable multi-channel operation, the interface must:
1. Be **USB Audio Class 2.0 (UAC2)** compliant — no proprietary drivers needed
2. Expose all channels as **separate ALSA/JACK ports** (not just stereo pairs)
3. Support sample rates: **44100, 48000 Hz minimum** (96000 Hz recommended)
4. Use a **USB-B or USB-C** connector (not micro-USB for reliability)
---
## MIDI Controllers
### Pre-Configured Mappings
These controllers have built-in mapping profiles — plug and play.
| Controller | Type | Faders | Knobs | Buttons | Transport | Status |
|-----------|------|--------|-------|---------|-----------|--------|
| **Behringer X-Touch** | DAW Controller | 8 motorized | 8 encoders | 92 | ✅ Yes | ✅ Verified |
| **Behringer X-Touch Compact** | DAW Controller | 9 motorized | 16 encoders | 38 | ✅ Yes | ⚠️ Probable |
| **Akai MIDImix** | Compact Mixer | 8 | 24 | 16 | ❌ No | ✅ Verified |
| **Korg nanoKONTROL 2** | Compact Mixer | 8 | 8 | 24 | ✅ Yes | ✅ Verified |
| **Korg nanoKONTROL Studio** | Compact Mixer | 8 | 8 | 32 | ✅ Yes | ⚠️ Probable |
| **Novation Launch Control XL** | Controller | 8 | 24 | 16 | ❌ No | ✅ Verified |
| **Novation Launchkey Mini MK3** | Keyboard + Controller | 0 | 8 | 16 | ❌ No | ⚠️ Probable |
| **Arturia BeatStep Pro** | Sequencer + Controller | 0 | 16 endless | 16 | ✅ Yes (clock) | ⚠️ Probable |
| **Akai APC40 MKII** | Ableton Controller | 9 | 16 | 104 | ✅ Yes | ⚠️ Probable |
| **Allen & Heath Xone:K2** | DJ Controller | 0 | 11 endless | 58 | ❌ No | ⚠️ Probable |
### Generic USB MIDI Controllers
Any class-compliant USB MIDI controller works via **MIDI Learn mode**.
This includes:
- Any controller that sends **CC messages** (control change)
- Any controller that sends **NRPN messages** (high-resolution 14-bit)
- **MIDI keyboards** with knobs/faders (Akai MPK, Arturia KeyLab, Novation SL, M-Audio Oxygen)
- **MIDI foot controllers** (Behringer FCB1010, Line 6 FBV, Nektar Pacer)
- **MIDI drum pads** (Akai MPD, Novation Launchpad, PreSonus ATOM)
- **DJ controllers** (Pioneer DDJ, Native Instruments Traktor, Denon DJ)
### MIDI over Bluetooth
⚠️ Bluetooth MIDI is **not recommended** for performance use due to latency
(10-50ms vs. <1ms for USB). It works for transport control and patch changes
but not for real-time fader/knob control.
### MIDI Clock Devices
Any device that sends or receives MIDI clock can sync tempo:
| Device | Role | Status |
|--------|------|--------|
| **Elektron Digitakt** | Clock master/slave | ⚠️ Probable |
| **Roland TR-8S** | Clock master/slave | ⚠️ Probable |
| **Arturia DrumBrute** | Clock master | ⚠️ Probable |
| **Korg Volca Series** | Clock slave | ⚠️ Probable |
| **Teenage Engineering OP-1** | Clock master | ⚠️ Probable |
---
## Touchscreen Displays
| Display | Size | Resolution | Interface | Touch | Status |
|---------|------|------------|-----------|-------|--------|
| **Raspberry Pi Official 7"** | 7" | 800×480 | DSI | 10-point capacitive | ✅ Verified |
| **Waveshare 5" DSI** | 5" | 800×480 | DSI | 5-point capacitive | ✅ Verified |
| **Waveshare 7" HDMI (C)** | 7" | 1024×600 | HDMI+USB | 10-point capacitive | ✅ Verified |
| **Waveshare 10.1" HDMI** | 10.1" | 1280×800 | HDMI+USB | 10-point capacitive | ⚠️ Probable |
| **SunFounder 7" HDMI** | 7" | 1024×600 | HDMI+USB | 5-point capacitive | ⚠️ Probable |
| **Elecrow 5" HDMI** | 5" | 800×480 | HDMI+USB | Resistive | ❌ Not recommended |
| **Elecrow 7" HDMI** | 7" | 1024×600 | HDMI+USB | 5-point capacitive | ⚠️ Probable |
### Display Requirements
- **DPI:** At least 130 DPI for readable UI at arm's length
- **Touch:** Capacitive multi-touch (resistive is frustrating for fader control)
- **Interface:** DSI preferred (no USB cable clutter); HDMI+USB works
- **HDMI port:** Use the HDMI port closest to USB-C power (HDMI0)
- **Config note:** For HDMI displays, set `hdmi_group=2 hdmi_mode=87` in
`config.txt` with custom `hdmi_cvt` for native resolution
### Headless Operation
The mixer can run entirely headless — control it via:
- Web UI from any device on the network
- OSC from a DAW
- MIDI controller connected directly to the Pi
- SSH for command-line management
---
## USB Cameras
| Camera | Resolution | Status | Notes |
|--------|-----------|--------|-------|
| **Raspberry Pi Camera Module 3** | 1080p30 / 720p60 | ✅ Verified | Native MIPI CSI support. Best quality/CPU ratio. |
| **Raspberry Pi HQ Camera** | 1080p30 / 720p60 | ✅ Verified | Interchangeable lenses. Requires C/CS lens. |
| **Logitech C920** | 1080p30 | ✅ Verified | Standard UVC webcam. Good quality. |
| **Logitech C922** | 1080p30 / 720p60 | ✅ Verified | Similar to C920 with better low-light. |
| **Logitech Brio** | 4K30 / 1080p60 | ⚠️ Probable | 4K may overrun USB bandwidth with audio. |
| **Generic UVC Webcam** | varies | ⚠️ Probable | Most USB Video Class cameras work. |
### Camera Tips
- **RPi Camera Module** uses the dedicated CSI port — keeps USB bandwidth free
for audio
- **USB cameras** share bandwidth with audio interfaces. Connect to **separate
USB buses** if possible (USB 2.0 for camera, USB 3.0 for audio)
- **1080p30** is the sweet spot for streaming quality vs. CPU usage on RPi 4
---
## SD Cards
| Card | Capacity | Class | Status | Notes |
|------|----------|-------|--------|-------|
| **SanDisk Extreme Pro** | 32GB+ | A2 V30 | ✅ Recommended | Best sustained write for multi-track recording |
| **SanDisk Extreme** | 32GB+ | A2 V30 | ✅ Recommended | Very good. |
| **Samsung EVO Select** | 32GB+ | A2 V30 | ✅ Recommended | Reliable and fast. |
| **Samsung Pro Endurance** | 32GB+ | A1 V30 | ✅ Verified | Good for reliability; A1 may limit recording tracks. |
| **Kingston Canvas Go! Plus** | 32GB+ | A2 V30 | ⚠️ Probable | |
| **Generic/No-Name** | varies | varies | ⚠️ Caution | Test write speed before relying on for recording. |
### SD Card Requirements
- **Minimum size:** 16 GB (OS + mixer software)
- **Recommended size:** 32 GB+ (room for recordings and sessions)
- **Minimum class:** A1 (up to 8-channel recording)
- **Recommended class:** A2 (16-channel recording without write buffer overruns)
- **Speed test:** `dd if=/dev/zero of=/data/test bs=1M count=1024 conv=fdatasync`
— should sustain 20+ MB/s writes
---
## Power Supply
| Supply | Status | Notes |
|--------|--------|-------|
| **Official RPi 4 PSU (5.1V/3A)** | ✅ Recommended | Stable and sufficient. |
| **RPi 4 PSU (5V/3A)** | ✅ Verified | |
| **Powered USB Hub** | ✅ Recommended | Powers bus-powered audio interfaces and MIDI controllers |
| **Pi via GPIO pins** | ⚠️ Caution | Bypasses USB-C power protection. For custom enclosures only. |
### Power Notes
- The RPi 4B draws up to ~6W under load (without peripherals)
- USB audio interfaces may draw 2-5W via bus power
- **Total system draw:** 8-15W. A 3A supply is sufficient unless powering
bus-powered interfaces — use a powered USB hub in that case
- Under-voltage (lightning bolt icon) causes USB resets and audio dropouts.
If seen, upgrade your power supply.
---
## Network
| Type | Status | Notes |
|------|--------|-------|
| **Ethernet (Gigabit)** | ✅ Recommended | Reliable, low latency, full bandwidth for streaming |
| **WiFi 5 (802.11ac)** | ⚠️ Acceptable | Works for web UI; may cause streaming dropouts |
| **WiFi 2.4GHz** | ❌ Not recommended | Congested band, streaming unreliable |
### Network Recommendations
- **Ethernet is strongly recommended** for live streaming
- For WiFi, place the Pi within 3m of the access point
- Configure a static IP or DHCP reservation for consistent access:
```bash
# /etc/dhcpcd.conf
interface eth0
static ip_address=192.168.1.100/24
static routers=192.168.1.1
```
---
## Aggregate / Multi-Device Setups
### Multiple USB Audio Interfaces
The mixer supports multiple USB audio interfaces aggregated into one JACK
device using `alsa_in` / `alsa_out` or the `zita-a2j` / `zita-j2a` bridges.
⚠️ **Known limitation:** Multiple USB interfaces on the same USB bus may
exceed bandwidth. The RPi 4B has one USB 3.0 bus shared across all four
ports. For multi-interface setups:
1. Use **ADAT expansion** (e.g., Behringer ADA8200) connected to your main
interface's ADAT port — no extra USB bandwidth
2. Use **aggregate ALSA devices** only for low-channel-count interfaces
3. Consider a **Pi 5** (separate USB 3.0 and USB 2.0 buses) when supported
### Testing Your Hardware
Run the built-in hardware test to validate your setup:
```bash
ssh pi@pi-mixer.local
# Test audio interface
aplay -l # list playback devices
arecord -l # list capture devices
speaker-test -c 2 -t sine -f 440 # test output
# Test JACK
jackd -d alsa -d hw:USB -r 48000 -p 128 -n 3 &
jack_lsp # list JACK ports
jack_connect system:capture_1 system:playback_1 # loopback test
# Test latency
jack_delay # measure round-trip latency
# Test MIDI
aconnect -l # list MIDI ports
aseqdump -p 20:0 # monitor MIDI events from port 20:0
# Comprehensive system test
python -m pytest tests/ -v -k "not test_streaming and not test_recording"
```
---
## Reporting Compatibility
Please report your hardware experiences to help expand this list:
1. **Working:** Device model, firmware version, channels working, any quirks
2. **Not working:** Device model, firmware version, symptoms, dmesg output
3. **Partially working:** What works and what doesn't
Include `dmesg | grep -i usb` and `cat /proc/asound/cards` output with your
report.
+703
View File
@@ -0,0 +1,703 @@
# User Manual — Raspberry Pi Real-Time Audio Mixer
Comprehensive guide to operating the RPi Audio Mixer — from hardware setup to
live streaming.
## Table of Contents
1. [Hardware Setup](#1-hardware-setup)
2. [First Boot & Setup Wizard](#2-first-boot--setup-wizard)
3. [Web Control Surface](#3-web-control-surface)
4. [Touchscreen UI](#4-touchscreen-ui)
5. [MIDI Controller Operation](#5-midi-controller-operation)
6. [Multi-Track Recording](#6-multi-track-recording)
7. [Backing Tracks](#7-backing-tracks)
8. [Live Streaming](#8-live-streaming)
9. [Session Management](#9-session-management)
10. [OSC / DAW Integration](#10-osc--daw-integration)
11. [Plugins & Effects](#11-plugins--effects)
12. [Fader Automation & Scenes](#12-fader-automation--scenes)
---
## 1. Hardware Setup
### Required Equipment
- Raspberry Pi 4 Model B (4GB+ RAM)
- USB audio interface (class-compliant UAC2)
- SD card (16GB+, Class A2 recommended) with mixer image flashed
- 5V/3A USB-C power supply
- **Optional:** HDMI touchscreen, USB MIDI controller, Ethernet cable, USB camera
### Connections
```
┌──────────────────────┐
USB Audio ←──→ │ │
Interface │ Raspberry Pi 4B │──→ HDMI Touchscreen
│ │
MIDI Controller ──│ │──→ Ethernet (router)
│ │
USB Camera ───│ │
└──────────────────────┘
5V/3A Power
```
1. Connect the USB audio interface to a **USB 3.0 (blue) port** — these have
dedicated bandwidth and lower latency than USB 2.0 ports
2. Connect MIDI controllers to any remaining USB port
3. Connect the HDMI touchscreen (if using)
4. Connect Ethernet for reliable networking (WiFi works but can cause audio dropouts)
5. Insert the SD card and power on
### USB Audio Interface Setup
The system auto-detects class-compliant USB audio interfaces. For interfaces
with multiple modes (e.g., Behringer UMC1820), ensure the device is in the
correct mode before powering on the Pi.
Verified interfaces: see [docs/hardware-compatibility.md](hardware-compatibility.md)
---
## 2. First Boot & Setup Wizard
On first boot, the setup wizard runs automatically on the HDMI display.
### Wizard Steps
1. **Welcome screen** — language selection
2. **Audio interface detection** — the wizard scans USB for audio devices and
presents a list. Select your interface.
3. **WiFi configuration** — scan for networks, enter password. Skip for Ethernet.
4. **Hostname** — set a custom hostname (default: `pi-mixer`)
5. **API key** — auto-generated and displayed. **Write this down** — you need it
for web UI access. Can be changed later.
6. **JACK settings** — buffer size and sample rate:
- **Low latency** (128 frames @ 48kHz, ~2.7ms) — for live monitoring
- **Stable** (256 frames @ 48kHz, ~5.3ms) — for plugin-heavy sessions
- **Maximum stability** (512 frames @ 48kHz, ~10.7ms) — for recording
7. **Reboot** — system restarts into normal operation
### Re-running the Wizard
```bash
sudo touch /force-firstboot && sudo reboot
```
---
## 3. Web Control Surface
Access the mixer from any device on the same network via the web UI.
### Access
```
http://pi-mixer.local:8080
```
Or use the IP address:
```bash
# Find the Pi's IP
ssh pi@pi-mixer.local "ip addr show | grep 'inet '"
# Open http://<ip-address>:8080
```
### Authentication
Enter the API key from the setup wizard. The key is also stored in:
```bash
grep API_KEY /etc/systemd/system/mixer-api.service
```
### Mixer View
The main mixer screen shows:
```
┌─────────┬─────────┬─────────┬─────────┬─────────┐
│ CH 1 │ CH 2 │ CH 3 │ ... │ Master │
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │ │ ┌─────┐ │
│ │█████│ │ │███░░│ │ │█░░░░│ │ │ │████░│ │
│ │█████│ │ │███░░│ │ │█░░░░│ │ │ │████░│ │
│ │█████│ │ │███░░│ │ │█░░░░│ │ │ │████░│ │
│ │█████│ │ │███░░│ │ │█░░░░│ │ │ │████░│ │
│ └─────┘ │ └─────┘ │ └─────┘ │ │ └─────┘ │
│ -3 dB │ 0 dB │ -∞ dB │ │ -6 dB │
│ [M][S] │ [M][S] │ [M][S] │ │ [M][D] │
└─────────┴─────────┴─────────┴─────────┴─────────┘
```
- **Fader** — drag up/down to adjust volume (-60 dB to +12 dB)
- **M** button — mute the channel (red when active)
- **S** button — solo the channel (yellow when active)
- **Channel label** — tap to open channel detail panel
### Channel Detail Panel
Tap a channel label to open:
- **3-band EQ** — Low (20-500 Hz), Mid (200-8000 Hz), High (2000-20000 Hz)
with frequency, gain (±15 dB), and Q controls
- **Compressor** — threshold, ratio, attack, release, makeup gain
- **Gate** — threshold, range
- **Gain** — preamp gain (-20 to +60 dB)
- **Pan** — stereo position
- **FX Sends** — send level to Aux A and Aux B
- **Phase invert** — toggle
### Master Section
- **Master Volume** — main output level
- **Mute** — silence all outputs
- **Dim** — reduce output by -20 dB (for talkback)
- **Monitor Volume** — control room monitor level
- **Phones Volume** — headphone output level
### Navigation Tabs
- **Mixer** — channel strips and master
- **Routing** — JACK routing matrix (drag connections between ports)
- **Plugins** — plugin browser and chain editor
- **Session** — save/load sessions, setlists
- **Record** — multi-track recording controls
- **Stream** — live streaming controls
- **Settings** — API key, network, display, audio config
### Keyboard Shortcuts (Web UI)
| Key | Action |
|-----|--------|
| `1-8` | Select channel 1-8 |
| `↑/↓` | Adjust fader ±1 dB |
| `Shift+↑/↓` | Adjust fader ±0.1 dB |
| `M` | Toggle mute on selected channel |
| `S` | Toggle solo on selected channel |
| `Space` | Transport play/stop |
| `R` | Start/stop recording |
| `Esc` | Deselect channel |
---
## 4. Touchscreen UI
The Kivy-based touch UI runs directly on the HDMI display — no browser needed.
### Screen Layout
The UI has four screens, cycled by swiping or pressing ESC:
1. **Mixer Surface** — faders, meters, mute/solo for all 16 channels + master
2. **Routing Matrix** — drag to connect JACK audio ports
3. **Plugin Chain** — per-channel plugin slots with drag-and-drop
4. **Settings** — brightness, display timeout, DPI override
### Touch Gestures
| Gesture | Action |
|---------|--------|
| Swipe up/down on fader | Adjust volume |
| Tap fader cap | Select channel |
| Double-tap fader | Set to 0 dB (unity) |
| Swipe left/right | Navigate between screens |
| Long-press mute/solo | Latch mode (stays until pressed again) |
| Pinch (routing screen) | Zoom routing matrix |
### Launch Options
```bash
# Local mixer
python3 main_touch.py
# Remote mixer
python3 main_touch.py --host 192.168.1.10 --api-key my-key
# Force DPI (for non-standard displays)
KIVY_DPI=220 python3 main_touch.py
```
### Hardware Buttons (if available)
Some touchscreens include physical buttons that can be mapped:
```bash
# Example udev rule for Waveshare 5" buttons
# Maps KEY_UP/DOWN to channel select
```
---
## 5. MIDI Controller Operation
Connect any class-compliant USB MIDI controller to control mixer parameters.
### Supported Controllers
The MIDI engine auto-detects controllers. Pre-configured mappings exist for:
- **Behringer X-Touch** — 8 motorized faders, transport, scribble strips
- **Akai MIDImix** — 8 faders, 24 knobs, 16 buttons
- **Korg nanoKONTROL 2** — 8 faders, 8 knobs, transport
- **Novation Launch Control XL** — 8 faders, 24 knobs, 16 buttons
See [docs/hardware-compatibility.md](hardware-compatibility.md) for the full list
and custom mapping instructions.
### MIDI Learn Mode
Map any MIDI controller to any mixer parameter without editing config files:
1. **Enter learn mode:**
```bash
curl -X POST http://pi-mixer.local:8080/midi/learn/start \
-H "X-API-Key: your-key"
```
Or press the "Learn" button in the web UI or touch UI.
2. **Click the parameter** you want to map (e.g., Channel 3 Volume)
3. **Move the physical control** on your MIDI controller (fader, knob, or button)
4. The mapping is saved automatically. Exit learn mode:
```bash
curl -X POST http://pi-mixer.local:8080/midi/learn/stop \
-H "X-API-Key: your-key"
```
### MIDI Clock Sync
The mixer can act as MIDI clock master or slave:
- **Master mode:** mixer transport controls tempo; connected devices sync to it
- **Slave mode:** mixer follows external MIDI clock from a drum machine or DAW
Configure via the web UI → Settings → MIDI or via API:
```bash
# Set as slave
curl -X PUT http://pi-mixer.local:8080/midi/clock/mode \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"mode": "slave"}'
```
### NRPN Support
High-resolution 14-bit NRPN messages are supported for parameters that benefit
from fine control (filter frequency, Q, etc.). The MIDI engine auto-detects
NRPN vs. CC messages from your controller.
---
## 6. Multi-Track Recording
Record up to 16 channels simultaneously to individual WAV files.
### Recording Setup
1. **Arm tracks** — in the web UI, click the **R** (record arm) button on each
channel you want to record. Armed channels show a red indicator.
2. **Set recording directory:**
The default is `/data/recordings/session_NNN/`. Change via:
```bash
curl -X PUT http://pi-mixer.local:8080/recording/path \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"path": "/data/recordings/live-set-2026"}'
```
3. **Configure recording format:**
- Bit depth: 16-bit, 24-bit, or 32-bit float
- Sample rate: inherits from JACK (48 kHz default)
- Punch in/out: set in/out points for selective recording
### Recording Controls
| Action | Web UI | API |
|--------|--------|-----|
| Start recording | Press **⏺ Record** | `POST /transport/command {"command": "record"}` |
| Stop recording | Press **⏹ Stop** | `POST /transport/command {"command": "stop"}` |
| Punch in | Automatic at marker | `POST /recording/punch/in {"channel": 3}` |
| Punch out | Automatic at marker | `POST /recording/punch/out {"channel": 3}` |
| New take | Creates new take file | `POST /recording/take/new` |
### Recording Tips
- **Use a fast SD card** — Class A2 minimum for 16-track recording.
Class A1 works for 8 tracks or fewer.
- **Monitor disk space** with `df -h /data`. The web UI shows a disk meter.
- **Punch in/out** is seamless — no clicks or gaps at edit points.
- **Auto-save** backs up session state every 30 seconds during recording.
- Each recording session creates a timestamped directory:
`/data/recordings/session_001/` containing `channel_01.wav` through
`channel_16.wav` plus `session_metadata.json`.
---
## 7. Backing Tracks
Play synchronized backing tracks alongside live inputs.
### Setup
1. **Upload tracks** to `/data/backing/`:
```bash
scp my-backing.wav pi@pi-mixer.local:/data/backing/
```
2. **Supported formats:** WAV (16/24/32-bit), FLAC, MP3, AIFF, OGG
3. **Create a playlist** via the web UI → Backing Tracks → New Playlist, or:
```bash
curl -X POST http://pi-mixer.local:8080/backing/playlist \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"name": "Set 1", "tracks": ["intro.wav", "song1.wav", "song2.flac"]}'
```
### Playback Modes
- **One-shot** — play once and stop
- **Loop** — repeat indefinitely
- **Segue** — auto-advance to next track with configurable crossfade (0.5-10s)
- **Playlist** — sequential playback with optional transitions
### Transport Controls
| Control | Description |
|---------|-------------|
| Play | Start playback from current position |
| Stop | Stop and return to start |
| Pause | Pause at current position |
| Skip →| | Next track |
| Skip |← | Previous track |
| Loop | Toggle loop mode |
| Count-in | Play 1-2 bar count-in before playback |
### Metronome / Click Track
The built-in metronome provides a click track routed to a dedicated output:
- **Tempo:** 20-300 BPM (tap tempo supported)
- **Time signature:** 1/4 through 13/8
- **Sounds:** click, beep, sidestick, custom samples
- **Output routing:** typically phones or a dedicated aux output
```bash
# Set tempo and enable click
curl -X PUT http://pi-mixer.local:8080/transport/tempo \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"bpm": 128}'
curl -X POST http://pi-mixer.local:8080/transport/metronome/on \
-H "X-API-Key: your-key"
```
---
## 8. Live Streaming
Stream audio and video to YouTube, Twitch, Facebook Live, or any RTMP server.
### Quick Start — Stream to YouTube
1. **Get your stream key** from YouTube Studio → Go Live → Stream Settings
2. **Connect a USB camera** (or use Raspberry Pi Camera Module)
3. **Start streaming** via the web UI → Stream, or:
```bash
curl -X POST http://pi-mixer.local:8080/stream/start \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"platform": "youtube",
"stream_key": "your-youtube-stream-key",
"video_source": "usb",
"audio_source": "mixer_master",
"bitrate_video": 4500,
"bitrate_audio": 192
}'
```
### Platform Presets
| Platform | Video Bitrate | Audio Bitrate | Resolution | Notes |
|----------|--------------|---------------|------------|-------|
| YouTube | 4500-9000 Kbps | 192 Kbps | 1080p30/720p60 | H.264 recommended |
| Twitch | 4500-6000 Kbps | 160 Kbps | 1080p30/720p60 | Max 6000 Kbps |
| Facebook | 4000 Kbps | 128 Kbps | 720p30 | Max 720p |
| Custom RTMP | User-defined | User-defined | User-defined | Any RTMP server |
### Scenes
Create named scenes with different camera angles and overlays:
```bash
# Save current camera/layout as scene
curl -X POST http://pi-mixer.local:8080/stream/scenes/wide-shot/save \
-H "X-API-Key: your-key"
# Switch scenes
curl -X POST http://pi-mixer.local:8080/stream/scenes/close-up/load \
-H "X-API-Key: your-key"
```
### Streaming Tips
- **Use Ethernet** — WiFi can cause dropped frames. If using WiFi, reduce
bitrate to 2500 Kbps.
- **Monitor bitrate** — the web UI shows a real-time bitrate meter. If it
drops, reduce video bitrate.
- **Dedicated audio bus** — route the stream audio to a subgroup for
independent level control vs. live PA.
- **CPU headroom** — 16 channels + streaming uses ~60% CPU on RPi 4.
Reduce channel count or buffer size if you hit limits.
---
## 9. Session Management
Save and recall complete mixer states — all fader positions, EQ settings,
plugin states, routing, and transport.
### Save a Session
Via web UI → Session → Save, or:
```bash
curl -X POST http://pi-mixer.local:8080/sessions/save \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"name": "Live at The Garage", "notes": "Soundcheck levels"}'
```
### Load a Session
```bash
curl -X POST "http://pi-mixer.local:8080/sessions/Live%20at%20The%20Garage/load" \
-H "X-API-Key: your-key"
```
### Setlists
Group sessions into setlists with configurable transitions:
1. Create a setlist:
```bash
curl -X POST http://pi-mixer.local:8080/setlists \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Tour Set",
"items": [
{"session": "Soundcheck", "transition": "cut"},
{"session": "Opener", "transition": "crossfade", "duration": 3.0},
{"session": "Main Set", "transition": "crossfade", "duration": 5.0},
{"session": "Encore", "transition": "wait"}
]
}'
```
2. Transition types:
- **Cut** — instant switch
- **Crossfade** — smooth transition over N seconds
- **Wait** — manual advance (press "Next")
### Auto-Save
The mixer auto-saves state every 30 seconds (configurable) to
`~/.config/rpi-mixer/sessions/_autosave_YYYY-MM-DD.json`. The last 10
auto-saves are kept (older ones are rotated out).
### Snapshots
Capture instantaneous snapshots without creating a full session:
```bash
# MIDI-mappable: assign a button to snapshot save/load
# Save snapshot 3 (0-127 snapshots available)
curl -X POST http://pi-mixer.local:8080/snapshots/3/save \
-H "X-API-Key: your-key"
# Load snapshot 3
curl -X POST http://pi-mixer.local:8080/snapshots/3/load \
-H "X-API-Key: your-key"
```
---
## 10. OSC / DAW Integration
The mixer exposes all parameters via Open Sound Control, enabling integration
with DAWs (Ableton Live, Reaper, Bitwig, Ardour) and custom controllers.
### OSC Server
- **Address:** `pi-mixer.local:9001` (UDP)
- **Endpoint format:** `/mixer/channel/<n>/<parameter>`
- **Value range:** 0.0 to 1.0 (normalized)
### Common OSC Commands
```
/mixer/channel/1/volume 0.75 # Set channel 1 volume to 0 dB
/mixer/channel/1/mute 1 # Mute channel 1
/mixer/channel/1/pan -0.5 # Pan channel 1 left
/mixer/channel/1/eq_low_gain 0.5 # Boost channel 1 low EQ by 7.5 dB
/mixer/master/volume 0.8 # Set master volume
/mixer/transport/play 1 # Start transport
/mixer/transport/stop 1 # Stop transport
/mixer/transport/tempo 128.0 # Set tempo to 128 BPM
```
### OSC Query
The server responds to OSC queries:
```
/mixer/channel/1/volume → returns current value
/mixer/channel/*/volume → returns all 16 channel volumes
```
### Ableton Live Setup
1. Add a new MIDI/OSC controller in Ableton preferences
2. Configure output to `pi-mixer.local:9001` (UDP)
3. Map Live's faders to `/mixer/channel/N/volume`
4. Map Live's transport to `/mixer/transport/play`, `/mixer/transport/stop`
---
## 11. Plugins & Effects
The mixer uses **Carla** as its plugin host, supporting LV2, VST2, and NAM
(Neural Amp Modeler) formats.
### Plugin Browser
Access via web UI → Plugins. Browse by category:
- **Dynamics** — compressors, gates, limiters, expanders
- **EQ** — parametric, graphic, shelving
- **Reverb** — plate, hall, room, spring
- **Delay** — digital, tape, ping-pong
- **Modulation** — chorus, flanger, phaser, tremolo
- **Distortion** — overdrive, fuzz, amp sims, NAM captures
- **Utility** — meters, analyzers, routing tools
### Per-Channel Plugin Chain
Each channel supports up to 8 plugin slots in series:
```
Input → [Gate] → [EQ] → [Comp] → [Amp] → [FX Slot 1] → [FX Slot 2] → Fader → Output
```
Plugins can be reordered by dragging in the UI.
### Aux Sends & Returns
Four aux buses (FX A through D) provide shared effects:
1. Route a channel to an aux via its **FX Send** knob
2. Insert effects on the aux return (e.g., reverb on Aux A, delay on Aux B)
3. Blend the wet signal with the channel strip's dry signal
4. Control the overall aux level via **FX Return** faders in the master section
### NAM (Neural Amp Modeler)
Load guitar/bass amp captures for realistic amp simulation:
1. Place `.nam` files in `/data/presets/nam/`
2. Insert a NAM plugin on a channel
3. Select the capture from the dropdown
4. Adjust input gain and output level
```bash
# Scan for new NAM models
curl -X POST http://pi-mixer.local:8080/plugins/scan \
-H "X-API-Key: your-key"
```
---
## 12. Fader Automation & Scenes
### Fader Automation
Record and playback fader movements:
1. **Arm automation** for a channel (click **A** button)
2. **Press Play** — fader movements are recorded
3. **Press Stop** — automation lane is saved
4. **Playback** — faders move automatically according to recorded automation
5. **Overwrite** — re-record by arming again
Automation modes:
- **Read** — playback recorded automation (fader is read-only)
- **Write** — record new automation (overwrites existing)
- **Touch** — record only while touching the fader
- **Latch** — record from first touch until stop
### Scenes
Scenes are snapshots of all fader positions that can be recalled instantly:
1. **Save a scene:**
```bash
curl -X POST http://pi-mixer.local:8080/scenes/Chorus/save \
-H "X-API-Key: your-key"
```
2. **Load a scene** (instant recall):
```bash
curl -X POST http://pi-mixer.local:8080/scenes/Chorus/load \
-H "X-API-Key: your-key"
```
3. **Next/Previous scene** (MIDI-mappable for footswitch control)
Modifier scenes only affect specific channels:
```bash
# Save a modifier scene that only changes channels 1-4
curl -X POST http://pi-mixer.local:8080/scenes/Vocals-Up/save \
-H "X-API-Key: your-key" \
-d '{"mode": "modifier", "channels": [1, 2, 3, 4]}'
```
---
## Appendix: REST API Quick Reference
All endpoints require `X-API-Key` header.
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/channels` | List all channel states |
| GET | `/channels/{n}` | Get channel n state |
| PUT | `/channels/{n}/parameter` | Set channel parameter |
| GET | `/mixes` | Master bus + aux + subgroups |
| PUT | `/mixes/parameter` | Set master parameter |
| GET | `/transport` | Transport state |
| PUT | `/transport/command` | Play/stop/record/loop |
| GET | `/routing` | JACK routing matrix |
| GET | `/plugins` | Plugin list |
| GET | `/scenes` | Scene list |
| POST | `/scenes/{name}/save` | Save current state as scene |
| POST | `/scenes/{name}/load` | Load a scene |
| GET | `/sessions` | Session list |
| POST | `/sessions/{name}/save` | Save session |
| POST | `/sessions/{name}/load` | Load session |
| POST | `/setlists` | Create setlist |
| GET | `/stream/status` | Streaming status |
| POST | `/stream/start` | Start streaming |
| POST | `/stream/stop` | Stop streaming |
| POST | `/recording/start` | Start recording |
| POST | `/recording/stop` | Stop recording |
| POST | `/midi/learn/start` | Enter MIDI learn mode |
| POST | `/midi/learn/stop` | Exit MIDI learn mode |
| GET | `/stats` | Server statistics |
| GET | `/ws` | WebSocket for real-time updates |