9e007ae197
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
287 lines
8.2 KiB
Markdown
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`
|