P7-R1: Build Script / SD Card Image — automated build system
Lint & Validate / lint (push) Has been cancelled
Lint & Validate / lint (push) Has been cancelled
Adds complete SD card image builder for the RPi Audio Mixer: - build/build.sh: Main builder (RPiOS Lite base + chroot config + optional RT kernel cross-compile) - build/configure-system.sh: Chroot configuration (packages, services, audio config) - build/first-boot/setup-wizard.sh: Interactive first-boot setup (audio, WiFi, hostname, API key, JACK) - build/README.md: Flashing instructions and build documentation - Updated .gitignore to track build scripts but ignore artifacts - Updated README.md with current project status 735/735 tests pass. Build runs on x86_64 without a Raspberry Pi.
This commit is contained in:
+247
@@ -0,0 +1,247 @@
|
||||
# RPi Audio Mixer — SD Card Image Builder
|
||||
|
||||
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.
|
||||
|
||||
## 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 |
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
### 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`
|
||||
Reference in New Issue
Block a user