Files
shawn 9e007ae197
Lint & Validate / lint (push) Has been cancelled
Build: Add USB boot + NVMe HAT support
- --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
2026-05-19 22:54:41 -04:00

287 lines
8.2 KiB
Markdown

# 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 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
```bash
# Install build dependencies
sudo apt install wget xz-utils dosfstools e2fsprogs qemu-user-static
# Optional: for PREEMPT_RT kernel cross-compilation
sudo apt install gcc-aarch64-linux-gnu
# Build the image
./build/build.sh
# The image lands in:
ls -lh build/out/rpi-audio-mixer-*.img.xz
```
## Build Modes
| Command | Description | Time (approx) |
|---------|-------------|---------------|
| `./build/build.sh` | Full build with PREEMPT_RT kernel | 30-45 min |
| `./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
### From Linux
```bash
# 1. Decompress the image
xz -d build/out/rpi-audio-mixer-*.img.xz
# 2. Find your SD card device
lsblk
# Look for /dev/sdX or /dev/mmcblkX (e.g., /dev/sdb or /dev/mmcblk0)
# 3. Flash the image (WARNING: this overwrites the target device!)
sudo dd if=build/out/rpi-audio-mixer-*.img of=/dev/sdX bs=4M status=progress conv=fsync
# 4. Sync and eject
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
# 1. Decompress
xz -d build/out/rpi-audio-mixer-*.img.xz
# 2. Find the SD card
diskutil list
# Look for /dev/diskX (external, physical)
# 3. Unmount (do NOT eject)
diskutil unmountDisk /dev/diskX
# 4. Flash
sudo dd if=build/out/rpi-audio-mixer-*.img of=/dev/rdiskX bs=4m status=progress
# 5. Eject
diskutil eject /dev/diskX
```
### From Windows
Use [Raspberry Pi Imager](https://www.raspberrypi.com/software/) or [balenaEtcher](https://www.balena.io/etcher/):
1. Decompress the `.img.xz` with 7-Zip or WinRAR
2. Open Raspberry Pi Imager
3. Choose "Use custom" → select the `.img` file
4. Select your SD card and flash
## First Boot
1. Insert the SD card into a Raspberry Pi 4B (4GB+ RAM recommended)
2. Connect your USB audio interface
3. (Optional) Connect HDMI touchscreen + Ethernet
4. Power on
The first-boot setup wizard will appear automatically on the HDMI display
(or serial console). It will guide you through:
- Audio interface detection and selection
- WiFi configuration
- Hostname setting
- API key generation
- JACK buffer/latency settings
After the wizard completes, the system reboots into normal operation.
### Default Access
| Service | URL / Command | Default |
|---------|--------------|---------|
| Web UI | `http://pi-mixer.local:8080` | API key from wizard |
| SSH | `ssh pi@pi-mixer.local` | Password: `raspberry` |
| Touch UI | HDMI display (auto-starts) | — |
**Important:** Change the default password on first login:
```bash
passwd
```
## Image Contents
```
Partition layout:
├── /boot (FAT32, 256MB)
│ ├── kernel8-rt.img PREEMPT_RT kernel (if built)
│ ├── config.txt GPU/boot configuration
│ ├── cmdline.txt Kernel command line
│ └── *.dtb, overlays/ Device Tree Blobs
├── / (ext4, ~4GB used of 6GB)
│ ├── /opt/rpi-mixer/ Mixer source + venv
│ ├── /etc/systemd/system/ Service files
│ └── /home/pi/ pi user home
└── /data (ext4, remaining space)
├── sessions/ Saved mixer sessions
├── recordings/ Multi-track recordings
├── presets/ Plugin presets
└── logs/ System/audio logs
```
## Systemd Services
| Service | Description | Auto-start |
|---------|-------------|-----------|
| `cpu-performance.service` | Lock CPU to max frequency | Boot |
| `jackd.service` | JACK2 real-time audio server | After first-boot |
| `mixer-api.service` | REST API + WebSocket + OSC server | After first-boot |
| `mixer-ui.service` | Kivy touchscreen UI | After first-boot |
| `mixer-firstboot.service` | First-boot setup wizard | First boot only |
```bash
# Check service status
systemctl status jackd mixer-api mixer-ui
# View logs
journalctl -u mixer-api -f
journalctl -u jackd -f
# Manual control
sudo systemctl stop mixer-ui mixer-api jackd
sudo systemctl start jackd && sleep 2 && sudo systemctl start mixer-api
```
## CI / Automated Builds
Build without a Raspberry Pi (CI-friendly):
```bash
# On any x86_64 Linux host with qemu-user-static
export MIXER_VERSION="$(git describe --tags --always)"
export MIXER_HOSTNAME="ci-mixer"
export MIXER_API_KEY="ci-test-key-12345"
./build/build.sh --skip-kernel
```
For GitHub Actions / Gitea CI, add a workflow step:
```yaml
- name: Build SD card image
run: |
sudo apt install -y wget xz-utils dosfstools e2fsprogs qemu-user-static
./build/build.sh --skip-kernel
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: sd-card-image
path: build/out/rpi-audio-mixer-*.img.xz
```
## Customization
### Pre-configure WiFi and hostname
```bash
MIXER_WIFI_SSID="MyNetwork" MIXER_WIFI_PASS="secret123" \
MIXER_HOSTNAME="stage-mixer" ./build/build.sh --skip-kernel
```
### Custom image size
```bash
./build/build.sh --image-size 16384 # 16 GB image
```
### Different Raspberry Pi OS base
```bash
RPIOS_URL="https://example.com/my-custom-base.img.xz" ./build/build.sh
```
## Architecture Decision
This project uses **Raspberry Pi OS Lite (64-bit, Bookworm) + post-install
configuration** rather than Buildroot or Yocto. Rationale:
- Full Debian package ecosystem for rapid audio stack iteration
- `apt install` for JACK, Carla, debugging tools — no image rebuilds
- Standard systemd-based system — familiar and well-documented
- PREEMPT_RT kernel built via cross-compilation on x86 host
- Buildroot/Yocto can be revisited for production appliance images
See [docs/research/base-os-decision.md](../docs/research/base-os-decision.md)
for the full analysis.
## Troubleshooting
### Build fails on "qemu-aarch64-static not found"
```bash
sudo apt install qemu-user-static
sudo update-binfmts --enable qemu-aarch64
```
### Build fails on apt in chroot
This usually means DNS isn't resolving inside the chroot. The configure script
uses the host's `/etc/resolv.conf` — make sure your host has working DNS.
### Image won't boot on RPi
- Check you're using a Raspberry Pi 4B (not Pi 3 or Pi 5)
- Verify the SD card is at least 16 GB (Class A2 recommended)
- Try a different power supply (RPi4 needs 5V/3A)
- Check the HDMI display for kernel panic messages
### No audio on first boot
- Run `sudo systemctl status jackd` to check JACK
- Run `aplay -l` to list audio devices
- Re-run the setup wizard: `sudo touch /force-firstboot && sudo reboot`
### Web UI not accessible
- Check the service: `sudo systemctl status mixer-api`
- Find the IP: `ip addr show | grep inet`
- Check the API key in the service file: `grep API_KEY /etc/systemd/system/mixer-api.service`