From 96a6b96b7e87c5c3c02bc44d06e6ccba4008aa8a Mon Sep 17 00:00:00 2001 From: Shawn Date: Tue, 19 May 2026 19:06:12 -0400 Subject: [PATCH] P1-R3: Initial project infrastructure - Project directory structure: docs/, src/, build/, recipes/, scripts/, wiki/ - README.md with project overview and status - .editorconfig for consistent code style - .gitignore for Python, C/C++, kernel, and build artifacts - docs/research/: system research report + base OS decision - docs/audio-stack-config.md: audio stack configuration notes - config/: JACK, ALSA, CPU performance configs - Preserved research from P1-R1 and P1-R2 tasks --- .editorconfig | 21 + .gitignore | 60 ++ README.md | 42 ++ build/.gitkeep | 0 config/99-audio.conf | 6 + config/alsa-usb.conf | 7 + config/cmdline.txt | 1 + config/cpu-performance.service | 11 + config/jackd.service | 43 ++ config/jackdrc | 2 + config/rtirq | 16 + docs/audio-stack-config.md | 979 ++++++++++++++++++++++++++++++ docs/decisions/.gitkeep | 0 docs/manuals/.gitkeep | 0 docs/research/base-os-decision.md | 622 +++++++++++++++++++ docs/research/research-report.md | 331 ++++++++++ recipes/.gitkeep | 0 scripts/.gitkeep | 0 src/.gitkeep | 0 wiki/.gitkeep | 0 20 files changed, 2141 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build/.gitkeep create mode 100644 config/99-audio.conf create mode 100644 config/alsa-usb.conf create mode 100644 config/cmdline.txt create mode 100644 config/cpu-performance.service create mode 100644 config/jackd.service create mode 100644 config/jackdrc create mode 100644 config/rtirq create mode 100644 docs/audio-stack-config.md create mode 100644 docs/decisions/.gitkeep create mode 100644 docs/manuals/.gitkeep create mode 100644 docs/research/base-os-decision.md create mode 100644 docs/research/research-report.md create mode 100644 recipes/.gitkeep create mode 100644 scripts/.gitkeep create mode 100644 src/.gitkeep create mode 100644 wiki/.gitkeep diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..116315b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yaml,yml}] +indent_size = 2 + +[Makefile] +indent_style = tab + +[*.{sh,bash}] +indent_style = tab diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d78b5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# Raspberry Pi RT Audio Mixer — .gitignore + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +*.egg-info/ +dist/ +/build/* +!/build/.gitkeep +*.egg +.eggs/ +venv/ +.venv/ +env/ + +# C/C++ +*.o +*.obj +*.a +*.la +*.lo +*.dll +*.dylib +*.exe +*.out +*.app + +# Kernel build artifacts +*.ko +*.mod.c +*.mod +modules.order +Module.symvers +.tmp_versions/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ +.DS_Store +Thumbs.db + +# Environment +.env +.env.local +*.log + +# Cross-compilation +toolchains/ +sysroot/ + +# Package files +*.deb +*.rpm +*.tar.gz +*.tar.xz diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c0d126 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Raspberry Pi Real-Time Audio Mixer + +RPi4B-based multi-channel real-time audio mixer with custom PREEMPT_RT kernel. + +## Architecture + +- **Platform:** Raspberry Pi 4 Model B (8GB RAM) +- **OS:** Raspberry Pi OS Lite (64-bit, Bookworm) + custom PREEMPT_RT kernel +- **Audio:** USB audio interface with multi-channel I/O +- **Goal:** Low-latency (<10ms round-trip) multi-channel audio mixing + +## Project Structure + +``` +├── docs/ Research, architecture decisions, manuals +│ ├── research/ Technical research reports +│ ├── decisions/ Architecture Decision Records (ADRs) +│ └── manuals/ Hardware/software manuals and references +├── src/ Source code (audio engine, DSP, UI) +├── build/ Build scripts and cross-compilation tooling +├── recipes/ Buildroot/Yocto recipes (if applicable) +├── scripts/ Utility and deployment scripts +└── wiki/ Local wiki pages +``` + +## Status + +**Phase 1: Research & Planning (in progress)** +- [x] P1-R1: System Research — USB audio, PREEMPT_RT kernel analysis +- [x] P1-R2: Base OS Selection — RPiOS Lite 64-bit + custom PREEMPT_RT +- [ ] P1-R3: Project Infrastructure (current) +- [ ] P2: Kernel Build — custom PREEMPT_RT kernel compilation +- [ ] P3: Audio Engine — JACK/PipeWire integration, DSP pipeline +- [ ] P4: Hardware Integration — USB interface, GPIO control surface + +## Getting Started + +*Documentation coming in Phase 2+* + +## License + +TBD diff --git a/build/.gitkeep b/build/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/99-audio.conf b/config/99-audio.conf new file mode 100644 index 0000000..df89757 --- /dev/null +++ b/config/99-audio.conf @@ -0,0 +1,6 @@ +# Realtime audio group limits +# Members of the 'audio' group get realtime scheduling and unlimited memory lock +@audio - rtprio 99 +@audio - memlock unlimited +@audio - nice -20 +@audio - priority 99 diff --git a/config/alsa-usb.conf b/config/alsa-usb.conf new file mode 100644 index 0000000..245feb0 --- /dev/null +++ b/config/alsa-usb.conf @@ -0,0 +1,7 @@ +# USB audio buffer tuning +# Low-latency USB audio configuration + +# nrpacks=1: disable implicit feedback sync buffering +# Reduces USB transfer latency at cost of slightly higher CPU +options snd-usb-audio nrpacks=1 + diff --git a/config/cmdline.txt b/config/cmdline.txt new file mode 100644 index 0000000..48832b8 --- /dev/null +++ b/config/cmdline.txt @@ -0,0 +1 @@ +console=serial0,115200 console=tty1 root=PARTUUID=xxxxxxxx-02 rootfstype=ext4 fsck.repair=yes rootwait isolcpus=1-3 nohz_full=1-3 rcu_nocbs=1-3 threadirqs irqaffinity=0 quiet diff --git a/config/cpu-performance.service b/config/cpu-performance.service new file mode 100644 index 0000000..f52f89f --- /dev/null +++ b/config/cpu-performance.service @@ -0,0 +1,11 @@ +[Unit] +Description=Set CPU governor to performance +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/bin/sh -c 'echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor' +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/config/jackd.service b/config/jackd.service new file mode 100644 index 0000000..2001173 --- /dev/null +++ b/config/jackd.service @@ -0,0 +1,43 @@ +[Unit] +Description=JACK2 Audio Server +After=sound.target network.target +Wants=sound.target + +[Service] +Type=simple +User=pi +Group=audio +Environment=JACK_NO_AUDIO_RESERVATION=1 +Environment=JACK_PROMISCUOUS_SERVER=1 + +# Real-time scheduling +LimitRTPRIO=99 +LimitMEMLOCK=infinity +LimitNICE=-20 + +# CPU affinity — pin JACK server to audio cores 1-3 +CPUAffinity=1-3 + +# I/O scheduling — realtime class +IOSchedulingClass=realtime +IOSchedulingPriority=0 + +# JACK daemon command +ExecStart=/usr/bin/jackd \ + -P 70 \ + -t 2000 \ + -d alsa \ + -d hw:USB \ + -r 48000 \ + -p 128 \ + -n 3 \ + -M \ + -X seq \ + -S + +# Restart on crash (but not on clean shutdown) +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/config/jackdrc b/config/jackdrc new file mode 100644 index 0000000..8ee5fb4 --- /dev/null +++ b/config/jackdrc @@ -0,0 +1,2 @@ +# /etc/jackdrc — system-wide JACK2 default settings +/usr/bin/jackd -P 70 -t 2000 -d alsa -d hw:USB -r 48000 -p 128 -n 3 -M -X seq diff --git a/config/rtirq b/config/rtirq new file mode 100644 index 0000000..7b928e4 --- /dev/null +++ b/config/rtirq @@ -0,0 +1,16 @@ +# /etc/default/rtirq — realtime IRQ thread priority tuning + +# List of IRQ thread names to boost (space-separated regex patterns) +RTIRQ_NAME_LIST="xhci_hcd snd usb" + +# Highest priority for listed threads +RTIRQ_PRIO_HIGH=95 + +# Decrement priority per subsequent match +RTIRQ_PRIO_DECR=1 + +# Lowest priority for unlisted threads +RTIRQ_PRIO_LOW=50 + +# Reset IRQ thread priorities before applying (0=no, 1=yes) +RTIRQ_RESET_IRQ=0 diff --git a/docs/audio-stack-config.md b/docs/audio-stack-config.md new file mode 100644 index 0000000..d5009a4 --- /dev/null +++ b/docs/audio-stack-config.md @@ -0,0 +1,979 @@ +# Audio Stack Configuration — Low-Latency USB Audio on RPi4B + +**Date:** 2026-05-19 +**Parent Task:** P1-R1 Research + P1-R2 Base OS Decision +**Target Platform:** Raspberry Pi 4B, RPi OS Lite 64-bit (Bookworm), PREEMPT_RT 6.12.y kernel +**Scope:** JACK2 + ALSA realtime audio stack for multi-channel USB audio interfaces + +--- + +## Table of Contents + +1. [Architecture Overview](#1-architecture-overview) +2. [Package Installation](#2-package-installation) +3. [Kernel Command-Line Tuning](#3-kernel-command-line-tuning) +4. [PAM Limits for Realtime Audio](#4-pam-limits-for-realtime-audio) +5. [CPU Frequency Governor](#5-cpu-frequency-governor) +6. [ALSA Buffer and Period Tuning](#6-alsa-buffer-and-period-tuning) +7. [JACK2 Realtime Configuration](#7-jack2-realtime-configuration) +8. [Multi-Channel Routing](#8-multi-channel-routing) +9. [IRQ Priority Tuning (rtirq)](#9-irq-priority-tuning-rtirq) +10. [USB Audio Quirks](#10-usb-audio-quirks) +11. [Latency Testing with jack_delay](#11-latency-testing-with-jack_delay) +12. [Full Session Startup Script](#12-full-session-startup-script) +13. [Verification Checklist](#13-verification-checklist) + +--- + +## 1. Architecture Overview + +``` +┌─────────────────────────────────────────────────────────┐ +│ User Space │ +│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │ +│ │ Ardour / │ │ Carla │ │ Custom DSP (Python) │ │ +│ │ DAW │ │ Rack │ │ │ │ +│ └────┬──────┘ └────┬──────┘ └──────────┬───────────┘ │ +│ │ │ │ │ +│ └──────────────┼────────────────────┘ │ +│ │ │ +│ ┌───────▼────────┐ │ +│ │ JACK2 │ Realtime SCHED_FIFO │ +│ │ jackd (RT) │ Priority 70-80 │ +│ └───────┬────────┘ │ +│ │ ALSA backend (hw:USB) │ +├──────────────────────┼───────────────────────────────────┤ +│ ┌───────▼────────┐ │ +│ Kernel │ snd-usb-audio │ Threaded IRQ (xhci_hcd) │ +│ Space │ (xhci_hcd) │ IRQ prio 95 (rtirq) │ +│ └───────┬────────┘ │ +│ │ │ +│ ┌────────────▼────────────┐ │ +│ │ VIA VL805 xHCI │ │ +│ │ USB 3.0 Host Ctrl │ │ +│ └────────────┬───────────┘ │ +│ │ │ +└──────────────────────┼────────────────────────────────────┘ + │ + ┌────────▼────────┐ + │ USB Audio I/F │ + │ (class UAC2) │ + └─────────────────┘ +``` + +**Core design decisions:** + +| Parameter | Value | Rationale | +|-----------|-------|-----------| +| Sample rate | 48000 Hz | Standard for pro audio; lower CPU than 96k | +| Buffer size | 128 samples | ~2.7ms per period; sweet spot for latency vs xruns | +| Periods/buffer | 3 | JACK default; 2 for aggressive, 3 for stability | +| JACK priority | 70 (server), 80 (clients) | Below IRQ handlers (95), above normal tasks | +| Audio CPU cores | 1-3 | Core 0 left for system/IRQ handling | +| JACK backend | ALSA (hw:) | Direct hardware access, no dmix/dsnoop overhead | + +--- + +## 2. Package Installation + +```bash +# Core audio stack +sudo apt update +sudo apt install -y \ + jackd2 \ + jackd2-firewire \ + libjack-jackd2-0 \ + libjack-jackd2-dev \ + alsa-utils \ + alsa-tools \ + alsa-tools-gui \ + rtirq-init \ + rt-tests \ + cpufrequtils \ + usbutils \ + a2jmidid + +# Optional but recommended for development +sudo apt install -y \ + carla \ + python3-jack-client \ + python3-pip + +# jack_delay (compile from source for latency measurement) +sudo apt install -y build-essential libjack-jackd2-dev libasound2-dev +cd /tmp +git clone https://github.com/jackaudio/jack_delay.git +cd jack_delay +make +sudo make install # installs to /usr/local/bin/jack_delay +``` + +**Verify installations:** + +```bash +jackd --version # jackd version 1.9.22+ expected +aplay -l # List playback devices +arecord -l # List capture devices +cat /proc/asound/cards # Kernel view of sound cards +cyclictest --version # rt-tests installed +``` + +--- + +## 3. Kernel Command-Line Tuning + +Edit `/boot/firmware/cmdline.txt` (RPi OS Bookworm) or `/boot/cmdline.txt` (older). + +### Full recommended cmdline.txt + +``` +console=serial0,115200 console=tty1 root=PARTUUID=xxxxxxxx-02 rootfstype=ext4 fsck.repair=yes rootwait isolcpus=1-3 nohz_full=1-3 rcu_nocbs=1-3 threadirqs irqaffinity=0 quiet +``` + +### Parameter reference + +| Parameter | Value | Effect | +|-----------|-------|--------| +| `isolcpus=1-3` | CPUs 1-3 | Removes audio cores from scheduler load-balancing | +| `nohz_full=1-3` | CPUs 1-3 | Disables periodic timer tick on audio cores (adaptive-ticks) | +| `rcu_nocbs=1-3` | CPUs 1-3 | Offloads RCU callbacks from audio cores to CPU 0 | +| `threadirqs` | — | Forces all IRQ handlers to run as kernel threads (required for rtirq priority tuning) | +| `irqaffinity=0` | CPU 0 | Pins hardware IRQs to core 0 by default | +| `quiet` | — | Reduces console spam (optional) | + +### Verification after reboot + +```bash +# Check kernel cmdline +cat /proc/cmdline + +# Verify CPU isolation +cat /sys/devices/system/cpu/isolated # should show 1-3 +cat /sys/devices/system/cpu/nohz_full # should show 1-3 +cat /sys/kernel/rcu_expedited # 1 if available + +# Check threaded IRQs +ps -eo pid,comm,psr | grep 'irq/' # IRQ threads should run on CPU 0 +``` + +--- + +## 4. PAM Limits for Realtime Audio + +Create `/etc/security/limits.d/99-audio.conf`: + +```ini +# Realtime audio group limits +# Apply to members of the 'audio' group +@audio - rtprio 99 +@audio - memlock unlimited +@audio - nice -20 +@audio - priority 99 +``` + +### Apply and verify + +```bash +# Add your user to the audio group +sudo usermod -a -G audio $USER + +# Verify current session (requires logout/login) +ulimit -r # should show 99 (max realtime priority) +ulimit -l # should show unlimited (max locked memory) + +# Check PAM limit configuration +sudo chmod 644 /etc/security/limits.d/99-audio.conf +``` + +### Real-time group membership check + +```bash +groups | grep audio # must include 'audio' +sudo -u nobody jackd -d alsa -d hw:USB 2>&1 | head -1 +# Should NOT fail with "cannot use real-time scheduling" +``` + +--- + +## 5. CPU Frequency Governor + +Set `performance` governor to prevent clock scaling from adding latency jitter. + +### One-time set + +```bash +# Set all cores to performance +echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor + +# Verify +cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +# Each core should output: performance +``` + +### Persistent via systemd service + +Create `/etc/systemd/system/cpu-performance.service`: + +```ini +[Unit] +Description=Set CPU governor to performance +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/bin/sh -c 'echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor' +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable cpu-performance.service +sudo systemctl start cpu-performance.service +sudo systemctl status cpu-performance.service +``` + +### Verify current frequency + +```bash +cpufreq-info | grep -E 'governor|current CPU frequency' +# Should show "performance" and max frequency (typically 1.5 GHz for RPi4B) +``` + +--- + +## 6. ALSA Buffer and Period Tuning + +### 6.1 Identify USB audio device + +```bash +# List ALSA devices +aplay -l +arecord -l +cat /proc/asound/cards + +# Typical output for USB interface: +# card 1: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio] +# The hw: designation is hw:1,0 or hw:USB,0 +``` + +### 6.2 ALSA device configuration + +Create `/etc/modprobe.d/alsa-usb.conf`: + +``` +# USB audio buffer tuning +# Larger preallocated buffer reduces xruns at cost of ~20MB RAM per device +options snd-usb-audio index=0 vid=0x0000 pid=0x0000 nrpacks=1 + +# nrpacks=1: disable implicit feedback sync buffering +# - Reduces USB transfer latency at cost of slightly higher CPU +# - Critical for round-trip latency < 10ms +# - Default is 8 (aggressive buffering for reliability) +# +# index=0: force USB device to be card 0 +# vid/pid: filter specific device (optional; 0x0000 = match any) +``` + +### 6.3 ALSA buffer confirmation + +```bash +# Show current ALSA buffer/period limits +cat /proc/asound/card1/pcm0p/sub0/hw_params # playback +cat /proc/asound/card1/pcm0c/sub0/hw_params # capture +# (card number depends on your interface) + +# Query via alsacap +alsacap -d hw:USB + +# JACK will request these values; ALSA exposes caps: +# The USB driver typically supports: +# - Period size: 16–4096 frames +# - Periods: 2–32 +# - Sample rate: 8000–192000 Hz +``` + +### 6.4 JACK ALSA backend parameters + +When launching JACK, the key ALSA parameters are: + +| JACK flag | Meaning | Recommended | +|-----------|---------|-------------| +| `-d alsa` | Use ALSA backend | Required for USB audio | +| `-d hw:USB` | Device name | Match your interface | +| `-r 48000` | Sample rate | 48000 (or 44100/96000) | +| `-p 128` | Frames per period | 128 (~2.67ms at 48k) | +| `-n 3` | Periods per buffer | 3 (total buffer = 384 frames / 8ms) | +| `-S` | 16-bit samples | Use only if 32-bit causes issues | +| `-M` | MIDI sequencer | Enable if using MIDI | +| `-X seq` | MIDI driver | ALSA sequencer | + +**Latency math (48 kHz):** +- Period latency: `128 / 48000 = 2.67 ms` +- Total buffer: `3 × 2.67 = 8.0 ms` +- Target round-trip: `8.0 + USB overhead + DSP ≈ 10-12 ms` + +**Aggressive profile** (for direct monitoring rigs): +``` +-p 64 -n 2 # 1.33ms period, 2.67ms buffer — risk of xruns +``` + +**Safe profile** (for recording with plugins): +``` +-p 256 -n 3 # 5.33ms period, 16ms buffer — stable for DSP +``` + +--- + +## 7. JACK2 Realtime Configuration + +### 7.1 System-wide JACK config + +Create `/etc/jackdrc` (system default): + +``` +# /etc/jackdrc — JACK2 system-wide defaults +# Paired with PAM limits and RT kernel tuning + +# ALSA backend, USB audio interface (adjust hw:USB to your device) +-d alsa -d hw:USB -r 48000 -p 128 -n 3 -M -X seq +``` + +### 7.2 JACK DBus service (auto-start with systemd) + +Create `/etc/systemd/system/jackd.service`: + +```ini +[Unit] +Description=JACK2 Audio Server +After=sound.target network.target +Wants=sound.target + +[Service] +Type=simple +User=pi +Group=audio +Environment=JACK_NO_AUDIO_RESERVATION=1 +Environment=JACK_PROMISCUOUS_SERVER=1 + +# Real-time scheduling +LimitRTPRIO=99 +LimitMEMLOCK=infinity +LimitNICE=-20 + +# CPU affinity — pin JACK server to audio cores 1-3 +CPUAffinity=1-3 + +# I/O scheduling — realtime class +IOSchedulingClass=realtime +IOSchedulingPriority=0 + +# JACK daemon command +ExecStart=/usr/bin/jackd \ + -P 70 \ + -t 2000 \ + -d alsa \ + -d hw:USB \ + -r 48000 \ + -p 128 \ + -n 3 \ + -M \ + -X seq \ + -S + +# Restart on crash (but not on clean shutdown) +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=multi-user.target +``` + +**JACK flags explained:** + +| Flag | Value | Purpose | +|------|-------|---------| +| `-P 70` | Priority 70 | SCHED_FIFO prio for JACK server thread | +| `-t 2000` | Timeout 2s | Client timeout (ms) — clients killed if unresponsive | +| `-d alsa` | Backend | ALSA direct hardware driver | +| `-S` | 16-bit | Force 16-bit samples (lower USB bandwidth, OK for mixer) | + +### 7.3 Per-user JACK config + +Create `~/.jackdrc` (overrides system-wide): + +``` +# ~/.jackdrc — user-specific JACK config +# This file is read by qjackctl and other JACK frontends +# Same format as /etc/jackdrc +/usr/bin/jackd -P 70 -t 2000 -d alsa -d hw:USB -r 48000 -p 128 -n 3 -M -X seq +``` + +### 7.4 Real-time scheduling notes + +- JACK server threads run at `SCHED_FIFO` priority 70 (set by `-P 70`) +- JACK client callbacks inherit priority 80 (server + 10) +- xHCI USB IRQ handler runs at priority 95 (set by rtirq, see §9) +- Kernel IRQ handlers > JACK server > JACK clients > normal processes + +**Priority hierarchy:** +``` +95: xHCI USB IRQ (hardware interrupt thread) +90: System timer (hrtimer) +80: JACK client process callbacks +75: JACK watchdog +70: JACK server (ALSA backend, engine) +50: Other audio IRQs (I2S, GPIO audio) + 0: All other processes (CFS scheduler) +``` + +--- + +## 8. Multi-Channel Routing + +### 8.1 JACK port naming convention + +For a typical 8-in/8-out USB interface: + +``` +system:capture_1 → Input channel 1 (left) +system:capture_2 → Input channel 2 (right) +system:capture_3 → Input channel 3 +... +system:capture_8 → Input channel 8 + +system:playback_1 → Output channel 1 (left main) +system:playback_2 → Output channel 2 (right main) +... +system:playback_8 → Output channel 8 +``` + +### 8.2 Automatic routing script + +Create `/usr/local/bin/jack-route-default`: + +```bash +#!/bin/bash +# Auto-connect JACK system captures to playback (through-patch) +# Connect each input to its corresponding output for direct monitoring +# Run after JACK is started + +jack_wait -w + +# Get available ports +captures=$(jack_lsp -c system | grep capture) +playbacks=$(jack_lsp -c system | grep playback) + +# Route capture → playback in pairs +# Capture 1 → Playback 1, Capture 2 → Playback 2, etc. +for i in $(seq 1 8); do + jack_connect "system:capture_${i}" "system:playback_${i}" 2>/dev/null +done + +# Optional: route MIDI through a2jmidid +a2j_control start 2>/dev/null +``` + +```bash +sudo chmod +x /usr/local/bin/jack-route-default +``` + +### 8.3 Complex routing with jack-plumbing + +Create `~/.jack-plumbing`: + +``` +# jack-plumbing rules for persistent connections +# Format: (connect "source" "destination") +# Applied on JACK start and maintained across disconnects + +(connect "system:capture_1" "system:playback_1") +(connect "system:capture_2" "system:playback_2") +(connect "system:capture_3" "system:playback_3") +(connect "system:capture_4" "system:playback_4") +``` + +```bash +# Start plumbing daemon after JACK is running +jack-plumbing & +``` + +### 8.4 Patch persistence with jack_snapshot + +```bash +# Save current connections +jack_snapshot -s > ~/jack-patch-session.xml + +# Restore connections +jack_snapshot -r ~/jack-patch-session.xml +``` + +### 8.5 Carla patchbay (graphical) + +For complex setups, Carla's patchbay can save/restore entire connection graphs: + +```bash +carla & +# File → Save Project → mixer-session.carxp +# File → Load Project → mixer-session.carxp +``` + +--- + +## 9. IRQ Priority Tuning (rtirq) + +### 9.1 RTIRQ configuration + +Edit `/etc/default/rtirq`: + +```bash +# /etc/default/rtirq — realtime IRQ thread priority tuning +# RTIRQ_NAME_LIST: IRQ threads to boost (space-separated regex) +RTIRQ_NAME_LIST="xhci_hcd snd usb" + +# RTIRQ_PRIO_HIGH: highest priority for listed threads +RTIRQ_PRIO_HIGH=95 + +# RTIRQ_PRIO_DECR: decrement per match (so xhci=95, snd=94, usb=93) +RTIRQ_PRIO_DECR=1 + +# RTIRQ_PRIO_LOW: lowest priority for unlisted threads +RTIRQ_PRIO_LOW=50 + +# RTIRQ_RESET_IRQ: reset IRQ thread priorities before applying +RTIRQ_RESET_IRQ=0 +``` + +### 9.2 Enable and start rtirq + +```bash +sudo systemctl enable rtirq +sudo systemctl start rtirq +sudo systemctl status rtirq +``` + +### 9.3 Verify IRQ priorities + +```bash +# Show all IRQ threads with priorities +ps -eo pid,comm,rtprio,psr | grep 'irq/' | sort -k3 -rn + +# Expected output: +# PID COMMAND RTPRIO PSR +# 123 irq/51-xhci_hcd 95 0 +# 124 irq/52-snd_usb 94 0 +# 125 irq/53-usb3 93 0 + +# Also check with: +rtirq status +``` + +--- + +## 10. USB Audio Quirks + +### 10.1 Common quirks + +| Interface | Issue | Quirk Parameter | +|-----------|-------|-----------------| +| Focusrite Scarlett 18i20 (3rd Gen) | Channel routing requires ALSA mixer | `device_setup=1` | +| Behringer UMC1820 | Clock source selection | `implicit_fb=1` | +| Behringer UMC404HD | Sometimes needs sync mode set | `implicit_fb=1` | +| RME Babyface Pro FS | Class-compliant mode | No quirks needed | +| Zoom UAC-8 | USB 3.0 bandwith negotiation | `nrpacks=1` | +| M-Audio M-Track 8X4 | Sample rate switching | `autoclock=0` | + +### 10.2 Quirks via modprobe + +Create `/etc/modprobe.d/usb-audio-quirks.conf`: + +``` +# Apply USB audio device quirks +# General: disable implicit feedback for lower latency +options snd-usb-audio nrpacks=1 + +# Focusrite Scarlett (vid=1235, pid=8210 for 18i20 3rd Gen) +# options snd-usb-audio vid=0x1235 pid=0x8210 device_setup=1 + +# Behringer UMC interfaces +# options snd-usb-audio vid=0x1397 pid=0x0508 implicit_fb=1 + +# Disable ALSA sequencer for pure audio use (saves CPU) +# Not needed for most USB audio interfaces +``` + +### 10.3 Dynamic quirk application + +```bash +# Reload snd-usb-audio with new parameters +sudo modprobe -r snd-usb-audio +sudo modprobe snd-usb-audio nrpacks=1 + +# Or via sysfs (if supported by kernel) +echo 1 > /sys/module/snd_usb_audio/parameters/nrpacks +``` + +### 10.4 Identify USB audio VID/PID + +```bash +lsusb | grep -i audio +# Example: Bus 001 Device 005: ID 1397:0508 BEHRINGER International GmbH UMC1820 + +# The vid and pid are the hex values: +# vid=0x1397 pid=0x0508 +``` + +### 10.5 ALSA USB mixer controls + +```bash +# List all mixer controls for the USB interface +amixer -c USB controls + +# Common useful controls: +# - "Clock Source" — Internal vs SPDIF sync +# - "Sample Rate" — 44100/48000/96000 +# - "Buffer Size" — if exposed by driver + +# Get current value +amixer -c USB get "Clock Source" + +# Set clock source to internal +amixer -c USB set "Clock Source" Internal +``` + +--- + +## 11. Latency Testing with jack_delay + +### 11.1 Hardware loopback setup + +``` +┌──────────────────────┐ 3.5mm TRS cable ┌──────────────────────┐ +│ USB Audio Interface │ output ────► input │ USB Audio Interface │ +│ Output 1 (L) ├──────────────────────────►│ Input 1 (L) │ +│ │ │ │ +│ │ (physical loopback) │ │ +└──────────────────────┘ └──────────────────────┘ +``` + +Connect an output directly to an input using a short TRS/TS patch cable. +For balanced interfaces use TRS; for unbalanced use TS. +**Keep the cable as short as possible** (< 30cm) so cable delay doesn't skew measurement. + +### 11.2 Run jack_delay + +```bash +#!/bin/bash +# jack_delay latency measurement script +# Requires JACK running with appropriate buffer settings + +# 1. Start JACK (if not running) +if ! jack_control status | grep -q "started"; then + echo "Starting JACK..." + jackd -P70 -t2000 -d alsa -d hw:USB -r48000 -p128 -n3 & + sleep 2 +fi + +# 2. Create physical loopback: connect output 1 → input 1 with patch cable + +# 3. Run jack_delay measurement +# jack_delay uses an MLS (Maximum Length Sequence) to measure +# the round-trip delay including: +# - JACK output buffer +# - USB output transfer +# - DAC conversion +# - Cable propagation +# - ADC conversion +# - USB input transfer +# - JACK input buffer + +jack_delay -O system:playback_1 -I system:capture_1 -c 128 + +# Sample output: +# 459.853 frames 9.580 ms +# +# The reported delay is the total round-trip in frames and milliseconds. +# Subtract cable + converter latency (~0.5-1.0ms for typical interfaces) +# to get the pure software+USB stack latency. +``` + +### 11.3 Latency test script + +Create `/usr/local/bin/jack-latency-test`: + +```bash +#!/bin/bash +# jack-latency-test — measure USB audio round-trip latency at various buffer sizes +# Usage: jack-latency-test [device] [sample_rate] + +DEVICE="${1:-hw:USB}" +RATE="${2:-48000}" +OUTPUT="system:playback_1" +INPUT="system:capture_1" +RESULT_FILE="/tmp/jack-latency-results.txt" + +echo "=== JACK Latency Test ===" +echo "Device: $DEVICE" +echo "Sample rate: $RATE" +echo "Output port: $OUTPUT" +echo "Input port: $INPUT" +echo "Ensure physical loopback cable is connected: Output 1 → Input 1" +echo "==========================================" +echo "" + +# Test various buffer sizes +for PERIOD in 32 64 128 256 512 1024; do + echo -n "Period $PERIOD frames: " + + # Kill any running JACK + killall -9 jackd 2>/dev/null + sleep 1 + + # Start JACK with this period + jackd -P70 -t2000 -d alsa -d "$DEVICE" -r "$RATE" -p "$PERIOD" -n 3 -S \ + > /tmp/jackd.log 2>&1 & + + # Wait for JACK to be ready + timeout=10 + while [ $timeout -gt 0 ]; do + if jack_control status 2>/dev/null | grep -q "started"; then + break + fi + sleep 1 + timeout=$((timeout - 1)) + done + + if [ $timeout -eq 0 ]; then + echo "JACK failed to start" + continue + fi + + sleep 1 + + # Run jack_delay measurement + RESULT=$(jack_delay -O "$OUTPUT" -I "$INPUT" -c 128 2>/dev/null | tail -1) + if [ -n "$RESULT" ]; then + echo "$RESULT" + echo "$PERIOD frames: $RESULT" >> "$RESULT_FILE" + else + echo "measurement failed (check loopback cable)" + fi + + killall -9 jackd jack_delay 2>/dev/null + sleep 1 +done + +echo "" +echo "Results saved to: $RESULT_FILE" +cat "$RESULT_FILE" +``` + +```bash +sudo chmod +x /usr/local/bin/jack-latency-test +``` + +### 11.4 Expected latency targets + +| Buffer Size (frames) | Period Latency (48kHz) | Target Round-Trip | Use Case | +|----------------------|----------------------|--------------------|----------| +| 32 | 0.67 ms | 3-5 ms | Direct monitoring (very aggressive — may xrun) | +| 64 | 1.33 ms | 5-8 ms | Live performance, real-time effects | +| **128** | **2.67 ms** | **8-12 ms** | **Pro audio mixer (target)** | +| 256 | 5.33 ms | 15-20 ms | Recording, DAW playback | +| 512 | 10.67 ms | 25-35 ms | Overdubs, non-critical monitoring | + +If round-trip exceeds 15ms at 128 frames, investigate: +1. USB cable quality / length (< 2m) +2. Power delivery to interface (use powered hub) +3. Other USB devices on same bus +4. CPU governor not set to performance +5. IRQ priorities not applied + +--- + +## 12. Full Session Startup Script + +Create `/usr/local/bin/audio-stack-start`: + +```bash +#!/bin/bash +# audio-stack-start — initialize the full low-latency audio environment +# Run as root (sudo) for system-level tuning, then launches JACK as user + +set -e + +echo "=== Audio Stack Initialization ===" + +# 1. Set CPU governor to performance +echo "1/6 Setting CPU governor → performance..." +for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do + echo performance > "$cpu" 2>/dev/null || true +done + +# 2. Enable threaded IRQs and apply IRQ priorities +echo "2/6 Configuring IRQ priorities..." +if systemctl is-active --quiet rtirq; then + systemctl restart rtirq +else + systemctl start rtirq +fi + +# 3. Verify PAM limits +echo "3/6 Checking PAM limits..." +CURRENT_RTPRIO=$(ulimit -r) +CURRENT_MEMLOCK=$(ulimit -l) +echo " rtprio: $CURRENT_RTPRIO (need 99)" +echo " memlock: $CURRENT_MEMLOCK (need unlimited)" + +# 4. Load USB audio module with low-latency params +echo "4/6 Configuring USB audio driver..." +if lsmod | grep -q snd_usb_audio; then + echo " snd-usb-audio already loaded" +else + modprobe snd-usb-audio nrpacks=1 + echo " snd-usb-audio loaded with nrpacks=1" +fi + +# 5. Verify USB audio device present +echo "5/6 Checking USB audio device..." +if aplay -l | grep -qi usb; then + echo " USB audio interface detected" +else + echo " WARNING: No USB audio interface found" +fi + +# 6. Start JACK +echo "6/6 Starting JACK2..." +if pgrep -x jackd > /dev/null; then + echo " JACK already running" +else + # Drop to pi user for JACK if running as root + if [ "$EUID" -eq 0 ] && id pi >/dev/null 2>&1; then + sudo -u pi jackd -P70 -t2000 -d alsa -d hw:USB -r48000 -p128 -n3 -S & + else + jackd -P70 -t2000 -d alsa -d hw:USB -r48000 -p128 -n3 -S & + fi + sleep 2 + echo " JACK started" +fi + +echo "" +echo "=== Audio Stack Ready ===" +echo "Check: jack_lsp -c system" +echo "Check: jack_delay -O system:playback_1 -I system:capture_1" +``` + +```bash +sudo chmod +x /usr/local/bin/audio-stack-start +``` + +### Stop script + +Create `/usr/local/bin/audio-stack-stop`: + +```bash +#!/bin/bash +# Gracefully stop the audio stack +killall -15 jackd 2>/dev/null || true +sleep 1 +killall -9 jackd 2>/dev/null || true +echo "Audio stack stopped" +``` + +```bash +sudo chmod +x /usr/local/bin/audio-stack-stop +``` + +--- + +## 13. Verification Checklist + +Run through this checklist after deploying the configuration on the target Raspberry Pi. + +### Prerequisites + +- [ ] RPi OS Lite 64-bit (Bookworm) installed +- [ ] PREEMPT_RT kernel running (`uname -v | grep PREEMPT_RT`) +- [ ] USB audio interface connected and powered +- [ ] User is member of `audio` group +- [ ] Loopback cable available (output → input) + +### Kernel + +- [ ] `cat /proc/cmdline` shows: `isolcpus=1-3 nohz_full=1-3 rcu_nocbs=1-3 threadirqs` +- [ ] `cat /sys/devices/system/cpu/isolated` shows `1-3` +- [ ] `cat /sys/kernel/realtime` returns `1` + +### CPU + +- [ ] `cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor` all show `performance` +- [ ] `cpufreq-info | grep "current CPU frequency"` shows max speed (~1.5 GHz) + +### Limits + +- [ ] `ulimit -r` returns `99` +- [ ] `ulimit -l` returns `unlimited` + +### USB Audio + +- [ ] `aplay -l` lists the USB interface +- [ ] `arecord -l` lists the USB interface +- [ ] `cat /proc/asound/cards` shows the USB card + +### IRQ + +- [ ] `ps -eo pid,comm,rtprio | grep "irq/.*xhci"` shows priority ≥ 95 +- [ ] `rtirq status` shows correct priorities + +### JACK + +- [ ] `jackd -P70 -t2000 -d alsa -d hw:USB -r48000 -p128 -n3 &` starts without errors +- [ ] `jack_lsp` shows `system:capture_*` and `system:playback_*` ports +- [ ] `jack_connect system:capture_1 system:playback_1` succeeds + +### Latency + +- [ ] Loopback cable connected: output 1 → input 1 +- [ ] `jack_delay -O system:playback_1 -I system:capture_1` returns result +- [ ] Round-trip latency at 128 frames ≤ 12ms +- [ ] No xruns during 60-second latency measurement + +### Stress test + +```bash +# Run latency test while loading CPU +stress-ng --cpu 4 --timeout 60s & +jack_delay -O system:playback_1 -I system:capture_1 -s 60 +# Round-trip should stay within ±2ms of idle measurement +``` + +--- + +## Configuration Files Reference + +| File | Location | Purpose | +|------|----------|---------| +| [cmdline.txt](./config/cmdline.txt) | `/boot/firmware/cmdline.txt` | Kernel boot parameters | +| [99-audio.conf](./config/99-audio.conf) | `/etc/security/limits.d/99-audio.conf` | PAM realtime limits | +| [cpu-performance.service](./config/cpu-performance.service) | `/etc/systemd/system/` | CPU governor systemd unit | +| [jackd.service](./config/jackd.service) | `/etc/systemd/system/` | JACK2 systemd service | +| [jackdrc](./config/jackdrc) | `/etc/jackdrc` | JACK server defaults | +| [alsa-usb.conf](./config/alsa-usb.conf) | `/etc/modprobe.d/` | ALSA USB buffer tuning | +| [rtirq](./config/rtirq) | `/etc/default/rtirq` | IRQ priority config | +| [jack-route-default](./scripts/jack-route-default) | `/usr/local/bin/` | Auto-routing script | +| [jack-latency-test](./scripts/jack-latency-test) | `/usr/local/bin/` | Latency measurement script | +| [audio-stack-start](./scripts/audio-stack-start) | `/usr/local/bin/` | Full stack startup | +| [audio-stack-stop](./scripts/audio-stack-stop) | `/usr/local/bin/` | Full stack shutdown | + +--- + +## References + +- [JACK Audio Connection Kit — Linux RT Configuration](https://jackaudio.org/faq/linux_rt_config.html) +- [ALSA USB Audio — Kernel Documentation](https://www.kernel.org/doc/html/latest/sound/alsa-configuration.html) +- [Linux RT Kernel — Red Hat Documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/) +- [Raspberry Pi Audio — PiSound Documentation](https://blokas.io/pisound/docs/) +- Project Research Report: `docs/research/research-report.md` +- Base OS Decision: `docs/research/base-os-decision.md` diff --git a/docs/decisions/.gitkeep b/docs/decisions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/manuals/.gitkeep b/docs/manuals/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/research/base-os-decision.md b/docs/research/base-os-decision.md new file mode 100644 index 0000000..ecae525 --- /dev/null +++ b/docs/research/base-os-decision.md @@ -0,0 +1,622 @@ +# Base OS Selection — Buildroot/Yocto/RPiOS Lite + RT Kernel + +**Date:** 2026-05-19 +**Status:** Approved +**Parent:** P1-R1 (System Research Report) +**Next:** P2 (Kernel Build) + +--- + +## Executive Summary + +**Decision: Raspberry Pi OS Lite (64-bit, Bookworm) + custom PREEMPT_RT kernel.** + +RPiOS Lite is selected over Buildroot and Yocto for this project. It provides the +Debian/bookworm ecosystem for rapid audio-stack iteration, active Foundation +maintenance, and straightforward custom kernel integration. Buildroot and Yocto +are evaluated below and rejected for reasons of development velocity (Buildroot +requires full-image rebuild per package change) and disproportionate complexity +(Yocto's ~50GB build footprint and steep learning curve are unjustified for a +single-purpose audio appliance with one developer). + +--- + +## 1. Build System Comparison + +### 1.1 Buildroot + +| Aspect | Assessment | +|--------|-----------| +| **Version** | 2024.02+ (rolling releases every 3 months) | +| **RPi4 64-bit support** | First-class: `raspberrypi4_64_defconfig` | +| **Build time (clean)** | ~30-45 min on modern x86 (8-core) | +| **Build output** | ~120MB EXT4 rootfs image + FAT32 boot partition | +| **Init system** | BusyBox init (default) or systemd (optional) | +| **Cross-compilation** | Bootlin external toolchain (aarch64 glibc stable) | +| **Package format** | None at runtime — every change requires image rebuild | +| **Kernel config** | `BR2_LINUX_KERNEL_CUSTOM_TARBALL` → RPi kernel tarball | +| **PREEMPT_RT support** | Via kernel config fragment overlay (`BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES`) | +| **Read-only rootfs** | SquashFS built-in (`BR2_TARGET_ROOTFS_SQUASHFS`), initramfs/OverlayFS support | + +**Verdict for this project: Rejected.** + +Buildroot excels at producing minimal, reproducible appliance images. However, +the "rebuild image to change a package" model is a poor fit for audio development +where you need to iterate on JACK configs, test different DSP toolchains, and +install debugging tools rapidly. The 30-min rebuild cycle per package tweak +would severely hamper velocity. Buildroot is best for the "final appliance image" +stage — it could be revisited for production deployment after development +stabilizes on RPiOS Lite. + +### 1.2 Yocto Project / OpenEmbedded + +| Aspect | Assessment | +|--------|-----------| +| **Version** | Scarthgap 5.0 (LTS, April 2024) or Styhead 5.1 | +| **RPi4 64-bit support** | First-class via `meta-raspberrypi` layer (maintained by Andrei Gherzan) | +| **Build time (clean)** | ~2-4 hours first build; ~15-30 min incremental | +| **Build footprint** | ~50 GB disk for build directory | +| **Init system** | systemd (default in poky) | +| **Cross-compilation** | Built-in toolchain generation (cross + native + nativesdk) | +| **Package format** | opkg, rpm, or deb at runtime | +| **Kernel config** | `linux-raspberrypi` recipe in meta-raspberrypi; config fragments via `.bbappend` | +| **PREEMPT_RT support** | Via kernel config fragment in recipe append | +| **Read-only rootfs** | `IMAGE_FEATURES += "read-only-rootfs"` built-in | + +**Verdict for this project: Rejected.** + +Yocto is the industry standard for complex embedded Linux products where +reproducibility, long-term maintenance, and multi-target builds matter. However, +for a single-developer audio project targeting one board (RPi4B), the overhead is +disproportionate: 50GB build disk, 2-4 hour clean build, steep BitBake/recipe +learning curve, and meta-layer dependency management. The project has no need for +Yocto's multi-machine, multi-distro, SDK-generation capabilities. Revisit Yocto +only if this project scales to a product line with multiple hardware targets. + +### 1.3 Raspberry Pi OS Lite (64-bit, Bookworm) + +| Aspect | Assessment | +|--------|-----------| +| **Version** | Bookworm (Debian 12), kernel 6.6 or 6.12 (rpi-update) | +| **Architecture** | aarch64 (64-bit ARMv8-A) | +| **Install size** | ~3 GB (Lite, no desktop) | +| **RAM usage (idle)** | ~150 MB | +| **Init system** | systemd | +| **Package format** | .deb via apt — full Debian repositories | +| **Kernel source** | `github.com/raspberrypi/linux` — `rpi-6.12.y` branch | +| **PREEMPT_RT support** | Not in stock kernel; build custom kernel with `CONFIG_PREEMPT_RT=y` | +| **Read-only rootfs** | Manual setup via OverlayFS or fstab `ro` + tmpfs mounts | +| **Cross-compilation** | `aarch64-linux-gnu-` toolchain (available via apt on Ubuntu/Debian host) | +| **Maintenance** | Active — Raspberry Pi Foundation + Debian upstream | + +**Verdict for this project: Selected.** + +RPiOS Lite offers the right balance: +- **Development speed**: `apt install` for JACK, ALSA tools, debugging — minutes, not rebuilds +- **Ecosystem**: Full Debian Bookworm repository with up-to-date audio packages +- **Familiarity**: Standard Linux systemd-based system — no proprietary init or build system +- **Custom kernel**: Build once, drop kernel8.img onto /boot — simple and well-documented +- **Production path**: Can later repackage the working RPiOS setup into a Buildroot image if appliance-style deployment is desired + +The 3GB install size and 150MB idle RAM are acceptable for an 8GB RPi4B. If +size reduction becomes important later, the system can be trimmed (remove +unnecessary packages, switch to read-only squashfs). + +--- + +## 2. PREEMPT_RT Kernel Integration + +### 2.1 Source Tree + +The Raspberry Pi Foundation maintains a downstream kernel at: + +``` +https://github.com/raspberrypi/linux +Branch: rpi-6.12.y (64-bit, kernel8 build) +Defconfig: bcm2711_defconfig +``` + +As of May 2026, the 6.12.y RT patchset is mostly upstream. Only +`CONFIG_PREEMPT_RT=y` needs to be enabled on top of `bcm2711_defconfig`. + +### 2.2 Build Method: Cross-Compilation on x86 Host + +**Recommended approach** — build the kernel on a fast x86 machine, then copy +the resulting kernel image and DTBs to the Pi's /boot partition. + +```bash +# Toolchain (Ubuntu 26.04) +sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu + +# Clone RPi kernel +git clone --depth=1 -b rpi-6.12.y \ + https://github.com/raspberrypi/linux.git linux-rpi +cd linux-rpi + +# Apply config +KERNEL=kernel8 +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig + +# Enable PREEMPT_RT +scripts/config -e CONFIG_PREEMPT_RT +scripts/config -d CONFIG_PREEMPT +scripts/config -e CONFIG_HIGH_RES_TIMERS +scripts/config -e CONFIG_HZ_1000 +scripts/config -e CONFIG_NO_HZ_FULL +scripts/config -e CONFIG_RCU_NOCB_CPU +scripts/config -e CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE +scripts/config --set-val CONFIG_HZ 1000 +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig + +# Build (adjust -j for your CPU count) +make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \ + Image modules dtbs +``` + +### 2.3 Kernel Installation on RPi + +```bash +# Copy kernel +scp arch/arm64/boot/Image root@:/boot/kernel8-rt.img + +# Copy DTBs +scp arch/arm64/boot/dts/broadcom/*.dtb root@:/boot/ + +# Install modules +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \ + INSTALL_MOD_PATH=./modules modules_install +scp -r modules/lib/modules/* root@:/lib/modules/ + +# On the Pi, update config.txt: +# kernel=kernel8-rt.img +# Add cmdline.txt: threadirqs nohz_full=1-3 rcu_nocbs=1-3 isolcpus=1-3 +``` + +### 2.4 Kernel Configuration Checklist + +| Config | Value | Rationale | +|--------|-------|-----------| +| `CONFIG_PREEMPT_RT` | y | Full real-time preemption | +| `CONFIG_PREEMPT` | n | Disable voluntary-only preemption | +| `CONFIG_HZ` | 1000 | 1ms timer tick for lower scheduling jitter | +| `CONFIG_HZ_1000` | y | Required for HZ=1000 | +| `CONFIG_HIGH_RES_TIMERS` | y | High-resolution timer subsystem | +| `CONFIG_NO_HZ_FULL` | y | Tickless operation on isolated CPUs | +| `CONFIG_RCU_NOCB_CPU` | y | Offload RCU callbacks from RT CPUs | +| `CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE` | y | Lock CPU at max frequency | +| `CONFIG_CPU_FREQ_GOV_PERFORMANCE` | y | Performance governor available | +| `CONFIG_IRQ_FORCED_THREADING` | y | Force threaded IRQ handlers | +| `CONFIG_PREEMPTIRQ_DELAY_TEST` | n | Debug — disable for production | +| `CONFIG_USB_XHCI_HCD` | y | USB 3.0 host controller (required) | +| `CONFIG_SND_USB_AUDIO` | y | USB Audio Class driver (build as module preferred) | + +### 2.5 Alternative: Native Build on RPi4B + +Building natively on the RPi4B itself is possible but slow (~2-3 hours for a +full kernel build). Cross-compilation on a modern x86 machine completes in +~10-15 minutes. **Recommendation:** Cross-compile for development iterations, +fall back to native build on the Pi only if cross-compilation toolchain issues +arise. + +### 2.6 Kernel Verification + +```bash +# Verify RT preemption is active +uname -v | grep PREEMPT_RT +cat /sys/kernel/realtime # should return "1" + +# Measure worst-case latency +sudo cyclictest -t 4 -p 99 -i 200 -n -l 100000 -q +# Target: max latency < 100µs on idle system +``` + +--- + +## 3. Boot Time Optimization + +### 3.1 Current Baseline + +A stock RPiOS Lite 64-bit boots in approximately: +- **Firmware/Bootloader:** ~3-5 seconds +- **Kernel + initrd:** ~5-8 seconds +- **Userspace (systemd):** ~10-15 seconds +- **Total:** ~18-28 seconds to login prompt + +Measured with `systemd-analyze`: +```bash +systemd-analyze # overall boot time +systemd-analyze blame # per-unit timing +systemd-analyze critical-chain # dependency chain +systemd-analyze plot > boot.svg # visual timeline +``` + +### 3.2 Optimization Targets + +| Target | Approach | Expected Saving | +|--------|----------|-----------------| +| **Disable WiFi/BT** | `dtoverlay=disable-wifi`, `dtoverlay=disable-bt` in config.txt | ~2-3s | +| **Reduce kernel modules** | Disable unused drivers (HDMI audio, camera, codecs) | ~1-2s | +| **Minimal initramfs** | Build custom initramfs with only essential modules (usb, ext4, xhci) | ~2-4s | +| **Disable unnecessary services** | `systemctl disable` bluetooth, avahi, triggerhappy, etc. | ~3-5s | +| **Quiet boot** | `quiet loglevel=3` on kernel cmdline | ~1-2s (fewer console writes) | +| **Disable swap wait** | Remove swapfile or reduce swap timeout | ~0-5s | +| **Fast boot in config.txt** | `boot_delay=0`, `disable_splash=1` | ~0.5-1s | + +**Target: Sub-15-second boot** (from power-on to JACK running). + +### 3.3 Services to Disable + +```bash +# Audio appliance — disable non-essential services +sudo systemctl disable bluetooth +sudo systemctl disable hciuart +sudo systemctl disable avahi-daemon +sudo systemctl disable triggerhappy +sudo systemctl disable ModemManager +sudo systemctl disable polkit +sudo systemctl mask systemd-random-seed.service # if using read-only root +``` + +### 3.4 Kernel Command Line + +``` +console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait +quiet loglevel=3 +threadirqs nohz_full=1-3 rcu_nocbs=1-3 isolcpus=1-3 +usbcore.autosuspend=-1 +fsck.mode=skip +``` + +| Parameter | Purpose | +|-----------|---------| +| `quiet loglevel=3` | Suppress verbose kernel messages | +| `threadirqs` | Force threaded IRQ handlers (RT audio) | +| `nohz_full=1-3` | Disable timer ticks on CPU cores 1-3 | +| `rcu_nocbs=1-3` | Offload RCU callbacks from audio cores | +| `isolcpus=1-3` | Isolate cores 1-3 from scheduler (reserve for JACK/DSP) | +| `usbcore.autosuspend=-1` | Disable USB autosuspend (prevents audio dropouts) | +| `fsck.mode=skip` | Skip filesystem check on boot (for speed; use only on reliable storage) | + +### 3.5 CPU Core Allocation + +With 4 Cortex-A72 cores: +- **Core 0:** System + IRQ handling (including xHCI USB interrupts) +- **Cores 1-3:** JACK real-time threads + DSP processing + +This is enforced via: +- `isolcpus=1-3` on kernel cmdline +- `taskset -c 1-3` for JACK server +- IRQ affinity: pin xHCI to CPU 0 only + +--- + +## 4. Read-Only Root Filesystem Options + +### 4.1 Why Read-Only Rootfs + +For an embedded audio appliance: +- **Reliability:** Prevents SD card corruption from unexpected power loss +- **Consistency:** System state is known and reproducible +- **Longevity:** Reduces SD card wear (no unexpected writes) +- **Safety:** User cannot accidentally break the system + +### 4.2 Approach Comparison + +| Approach | Complexity | SD Card Wear | Runtime Writes | Boot Impact | +|----------|------------|-------------|----------------|-------------| +| **OverlayFS (tmpfs upper)** | Low | Minimal | Lost on reboot | +1-2s | +| **OverlayFS (persistent upper on separate partition)** | Medium | Low | Persisted | +1-2s | +| **squashfs root + tmpfs overlay** | Medium | None | Lost on reboot | +0s (faster read) | +| **ext4 `ro` + tmpfs for /var and /tmp** | Low | Minimal | Lost on reboot | +0s | +| **Full read-write ext4** | None | Full | Normal | Baseline | + +### 4.3 Recommended: OverlayFS with Persistent /data + +``` +┌─────────────────────────────────────────┐ +│ SD Card / NVMe / USB SSD │ +├──────────┬──────────┬───────────────────┤ +│ /boot │ / │ /data │ +│ FAT32 │ ext4 ro │ ext4 rw │ +│ 256MB │ 4GB │ remaining │ +│ (kernel, │ (base OS)│ (configs, presets,│ +│ firmware│ │ logs, user data) │ +└──────────┴──────────┴───────────────────┘ +``` + +**Boot process:** +1. Kernel mounts `/dev/mmcblk0p2` as read-only ext4 +2. initramfs sets up OverlayFS: + - Lower: `/dev/mmcblk0p2` (read-only root) + - Upper: tmpfs (writable layer, lost on reboot) + - Workdir: tmpfs +3. `/data` partition mounted read-write for persistent state +4. `/var` and `/tmp` are tmpfs + +**To remount root read-write temporarily (for system updates):** +```bash +sudo mount -o remount,rw / +# ... make changes ... +sudo mount -o remount,ro / +sudo sync +``` + +### 4.4 OverlayFS initramfs Setup + +In `/etc/initramfs-tools/scripts/init-bottom/overlay`: + +```bash +#!/bin/sh +# Setup OverlayFS root +mount -t tmpfs tmpfs /overlay +mkdir -p /overlay/upper /overlay/work +mount -t overlay overlay \ + -o lowerdir=${ROOT},upperdir=/overlay/upper,workdir=/overlay/work \ + ${rootmnt} +``` + +### 4.5 Alternative: Buildroot SquashFS Image + +If an appliance-style read-only image is desired for production deployment, +Buildroot can produce a squashfs rootfs (~120MB compressed) that boots with +initramfs. The squashfs approach eliminates SD card writes entirely for the +system partition and reduces image size. This can be explored as a Phase 2 +optimization after the audio stack is validated on RPiOS Lite. + +--- + +## 5. Partition Layout + +### 5.1 Recommended Layout (RPiOS Lite) + +| Partition | Type | Size | Filesystem | Mount | Contents | +|-----------|------|------|------------|-------|----------| +| 1 | Primary | 256 MB | FAT32 | /boot | GPU firmware, kernel8.img, config.txt, cmdline.txt, DTBs | +| 2 | Primary | 8 GB | ext4 (ro) | / | Root filesystem (RPiOS Lite + audio stack) | +| 3 | Primary | 20+ GB | ext4 (rw) | /data | JACK configs, DSP presets, session data, logs | + +### 5.2 Minimum vs Recommended Sizes + +| Component | Minimum | Recommended | Notes | +|-----------|---------|-------------|-------| +| /boot | 128 MB | 256 MB | Multiple kernel images + firmware backups | +| / (root) | 4 GB | 8 GB | RPiOS Lite base ~3GB + audio packages (~500MB-1GB) + headroom | +| /data | 2 GB | 20+ GB | Session recordings, presets, logs (use remaining SD card space) | + +### 5.3 Storage Medium + +| Medium | Pros | Cons | Verdict | +|--------|------|------|---------| +| **SD Card** (32GB A2) | Cheap, no USB bus contention | Wear, slower I/O, shared bus | Acceptable for development | +| **USB 3.0 SSD** | Fast, durable, large capacity | **Shares USB bus with audio interfaces!** | ⚠️ Risk of xrun interference | +| **NVMe SSD** (via HAT) | Fast, no USB bus contention | Requires HAT, adds cost | **Best for production** | + +**Recommendation:** SD card for development; NVMe HAT for production if +latency-sensitive I/O is needed during operation. Avoid USB SSD as primary +storage — it competes with audio interface isochronous bandwidth on the VL805 +controller. + +### 5.5 USB Boot — Ditch the SD Card + +The RPi4B supports native USB boot (USB mass storage device boot mode in EEPROM). +This is **recommended** for this project — USB SSDs and NVMe adapters are far more +reliable than SD cards under sustained audio write loads. + +#### NVMe HAT (Best Option) + +Uses dedicated PCIe lanes — does **not** share the USB bus with audio interfaces. + +| Option | Pros | Cons | Cost | +|--------|------|------|------| +| **NVMe Base HAT** (official) | Uses PCIe, no bus contention, fast | Adds height, needs spacer | ~€15 | +| **Pimoroni NVMe Base** | Same, well-documented | Same | ~€15 | +| **Geekworm X1001 / X1002** | Low profile, M.2 2230/2242 | Some need EEPROM update | ~€15-25 | + +#### USB 3.0 SSD Boot + +Booting from USB SSD is possible but **contraindicated** during audio operation — +it competes with audio interfaces on the shared VL805 USB controller. + +| Aspect | Detail | +|--------|--------| +| **Boot EEPROM setting** | `sudo rpi-eeprom-config --edit` → `BOOT_ORDER=0xf41` | +| **Performance** | ~350 MB/s sequential vs ~90 MB/s on SD | +| **Runtime conflict** | I/O contention with USB audio on same bus — risk of xruns | +| **Mitigation** | Boot from USB SSD, then minimize writes during audio (log to tmpfs, use OverlayFS) | + +#### Recommended Config + +- **Development:** SD card (cheap, easy to flash) +- **Production / Live use:** NVMe HAT + SSD via PCIe (best reliability, no USB conflict) +- **Fallback:** USB SSD boot if NVMe HAT unavailable — with OverlayFS + tmpfs for runtime paths + +#### EEPROM USB Boot Enable + +```bash +# Check current boot order +sudo rpi-eeprom-config | grep BOOT_ORDER + +# Set boot order: USB → SD → Restart +echo 'BOOT_ORDER=0xf41' | sudo tee -a /boot/firmware/config.txt + +# Or via rpi-eeprom-config +sudo rpi-eeprom-config --edit +# Change BOOT_ORDER to 0xf241 for SD → USB → Restart +# Change BOOT_ORDER to 0xf41 for USB → SD → Restart + +# Reboot to apply +sudo reboot +``` + +**Boot order codes:** +| Mode | Value | +|------|-------| +| SD card | 0x1 | +| USB mass storage | 0x4 | +| NVMe (if available) | 0x6 | +| Restart | 0xf | +| SD → USB → Restart | 0xf241 | +| USB → SD → Restart | 0xf41 | +| NVMe → USB → SD → Restart | 0xf614 | + +Also ensure P1-R3 (build script task) includes an NVMe HAT HOWTO section. + +### 5.4 Image Size Constraints + +For SD card deployment: +- **Minimum card:** 16 GB (Class A2 recommended for random I/O) +- **Image size:** ~4 GB compressed (RPiOS Lite + audio stack) +- **Expanded on first boot:** Auto-expand to fill SD card + +For Buildroot appliance image (future): +- **Compressed image:** ~50-80 MB (kernel + squashfs root) +- **Install size:** ~200-300 MB on disk + +--- + +## 6. Cross-Compilation Toolchain + +### 6.1 Toolchain Selection + +**Recommended:** `gcc-aarch64-linux-gnu` from Ubuntu 26.04 repositories. + +```bash +sudo apt install \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ + binutils-aarch64-linux-gnu \ + libc6-dev-arm64-cross +``` + +### 6.2 Toolchain Details + +| Component | Package | Version (Ubuntu 26.04) | +|-----------|---------|------------------------| +| C compiler | `gcc-aarch64-linux-gnu` | 14.2.0 / 15.x | +| C++ compiler | `g++-aarch64-linux-gnu` | 14.2.0 / 15.x | +| Binutils | `binutils-aarch64-linux-gnu` | 2.43 | +| C library | `libc6-dev-arm64-cross` | glibc 2.40 | +| Target triple | `aarch64-linux-gnu` | — | +| Architecture | ARMv8-A (Cortex-A72) | `-march=armv8-a+crc+simd` | + +### 6.3 Environment Setup + +```bash +export ARCH=arm64 +export CROSS_COMPILE=aarch64-linux-gnu- +export KERNEL=kernel8 + +# Verify +aarch64-linux-gnu-gcc --version +# aarch64-linux-gnu-gcc (Ubuntu 14.2.0-4ubuntu2) 14.2.0 +``` + +### 6.4 Kernel Build Commands + +```bash +# Configure +make bcm2711_defconfig +make menuconfig # enable PREEMPT_RT and tuning options + +# Build +make -j$(nproc) Image modules dtbs + +# Output files: +# arch/arm64/boot/Image → kernel8-rt.img (on Pi /boot) +# arch/arm64/boot/dts/broadcom/ → *.dtb files (on Pi /boot) +# modules (INSTALL_MOD_PATH) → /lib/modules// (on Pi) +``` + +### 6.5 Alternative: Bootlin Toolchains + +Buildroot uses Bootlin pre-built toolchains. These are available standalone: + +``` +https://toolchains.bootlin.com/ +→ aarch64--glibc--stable-2024.02-1.tar.bz2 +``` + +Bootlin toolchains include the full sysroot (headers, libraries) needed for +building userspace as well as the kernel. This is useful if building +userspace audio tools from source (e.g., a custom JACK build), but for +kernel-only cross-compilation, the distro `aarch64-linux-gnu-` package is +sufficient. + +### 6.6 Native Compilation Fallback + +If cross-compilation proves problematic (32-bit host, missing headers), the +RPi4B 8GB can build its own kernel natively in ~2-3 hours: + +```bash +# On the Pi: +git clone --depth=1 -b rpi-6.12.y https://github.com/raspberrypi/linux +cd linux +KERNEL=kernel8 +make bcm2711_defconfig +# Edit .config for PREEMPT_RT +make -j4 Image modules dtbs +sudo make modules_install +sudo cp arch/arm64/boot/Image /boot/kernel8-rt.img +``` + +--- + +## 7. Implementation Roadmap + +### Phase 1: Base OS Setup (this phase) +1. Flash RPiOS Lite 64-bit to SD card +2. First boot: enable SSH, set hostname, update packages +3. Disable unnecessary services (WiFi, Bluetooth, avahi, etc.) +4. Apply boot optimizations (config.txt, cmdline.txt) +5. Configure CPU isolation (isolcpus=1-3) +6. Test baseline boot time with `systemd-analyze` + +### Phase 2: RT Kernel Build (next phase, P2) +1. Set up cross-compilation toolchain on x86 host +2. Clone `rpi-6.12.y` kernel +3. Apply PREEMPT_RT + tuning config +4. Build kernel, modules, DTBs +5. Install on Pi and verify with `cyclictest` +6. Target: max latency < 100µs + +### Phase 3: Read-Only Rootfs (follows audio stack validation) +1. Test OverlayFS initramfs approach +2. Create /data partition for persistent state +3. Configure tmpfs for /var, /tmp, /run +4. Test update procedure (remount-rw → apt → remount-ro) + +### Phase 4: Production Image (optional, post-validation) +1. Evaluate Buildroot for appliance image +2. Create squashfs rootfs with initramfs +3. Generate reproducible SD card image +4. CI pipeline for kernel + rootfs builds + +--- + +## 8. Risk Register + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Cross-compilation toolchain mismatch (glibc version skew) | Low | Medium | Use matching toolchain; fall back to native build | +| PREEMPT_RT kernel causes USB/xHCI regressions | Medium | High | Test thoroughly; maintain stock kernel as fallback in /boot | +| SD card wear from audio logging | Medium | Low | Log to tmpfs; archive to /data periodically | +| USB SSD storage conflicts with audio isochronous transfers | Medium | High | Use SD card or NVMe HAT; avoid USB storage during audio operation | +| RPi kernel rpi-6.12.y diverges from mainline PREEMPT_RT | Low | Medium | Monitor kernel releases; test each new kernel version | +| Read-only rootfs breaks apt/package management | Low | Medium | Document remount-rw procedure; automate in update script | + +--- + +## 9. References + +1. Raspberry Pi Linux kernel: https://github.com/raspberrypi/linux (branch: rpi-6.12.y) +2. Buildroot manual: https://buildroot.org/downloads/manual/manual.html +3. Buildroot RPi4 64-bit defconfig: https://github.com/buildroot/buildroot/tree/master/configs/raspberrypi4_64_defconfig +4. Yocto meta-raspberrypi: https://github.com/agherzan/meta-raspberrypi +5. Yocto Project docs: https://docs.yoctoproject.org/ +6. PREEMPT_RT wiki: https://wiki.linuxfoundation.org/realtime/start +7. Bootlin toolchains: https://toolchains.bootlin.com/ +8. Zynthian OS (RPi RT audio reference): https://github.com/zynthian/zynthian-sys +9. Linux kernel RT config docs: https://www.kernel.org/doc/html/latest/locking/rt-mutex-design.html +10. RPi boot options: https://www.raspberrypi.com/documentation/computers/config_txt.html#boot-options +11. OverlayFS kernel docs: https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html +12. systemd-analyze: https://www.freedesktop.org/software/systemd/man/systemd-analyze.html diff --git a/docs/research/research-report.md b/docs/research/research-report.md new file mode 100644 index 0000000..55c726f --- /dev/null +++ b/docs/research/research-report.md @@ -0,0 +1,331 @@ +# RPi4B Real-Time Audio Research Report + +**Date:** 2026-05-19 +**Target:** Raspberry Pi 4 Model B, 8GB RAM +**Use Case:** Multi-channel real-time audio mixer + +--- + +## 1. PREEMPT_RT Kernel Status on Raspberry Pi 4B + +### 1.1 Stock Raspberry Pi Kernel + +The stock Raspberry Pi OS kernel (rpi-6.12.y branch as of May 2026) is configured with: + +``` +CONFIG_PREEMPT=y # Voluntary preemption ("Low-Latency Desktop") +CONFIG_NO_HZ=y # Dynamic tick +``` + +**CONFIG_PREEMPT_RT is NOT enabled.** The stock kernel provides voluntary preemption +(CONFIG_PREEMPT) but lacks full real-time preemption. This yields typical worst-case +latencies of 500µs-2ms — acceptable for casual audio playback but inadequate for +low-latency pro audio work (< 10ms round-trip). + +### 1.2 PREEMPT_RT in Mainline Linux + +Since Linux 6.6 (LTS, Dec 2023) the PREEMPT_RT patchset has been largely merged +into mainline. The RPi downstream kernel v6.12.y inherits this infrastructure. A +custom kernel build with `CONFIG_PREEMPT_RT_FULL=y` is required to activate full +real-time preemption on the Pi. + +### 1.3 Building a PREEMPT_RT Kernel for RPi4B + +```bash +# Clone RPi kernel +git clone --depth=1 -b rpi-6.12.y https://github.com/raspberrypi/linux + +# Configure for Pi 4B +cd linux +KERNEL=kernel8 +make bcm2711_defconfig + +# Enable full RT preemption +./scripts/config -e CONFIG_PREEMPT_RT +./scripts/config -d CONFIG_PREEMPT +./scripts/config -e CONFIG_HIGH_RES_TIMERS +make olddefconfig + +# Build (cross-compile or native) +make -j4 Image modules dtbs +``` + +**Expected latency improvement:** Worst-case scheduling latency drops from +~500µs-2ms (CONFIG_PREEMPT) to ~20-80µs (CONFIG_PREEMPT_RT). + +### 1.4 RT Kernel Verification + +```bash +uname -v | grep PREEMPT_RT +# or +cat /sys/kernel/realtime # returns "1" if RT kernel +# or +cyclictest -t 4 -p 99 -i 200 -n -l 100000 -q +# Should report max latency < 100µs on idle system +``` + +### 1.5 Additional Kernel Tuning for Audio + +| Tuning | Description | +|--------|-------------| +| `threadirqs` | Force threaded IRQ handlers (kernel cmdline) | +| `nohz_full=1-3` | Disable timer tick on audio CPUs | +| `rcu_nocbs=1-3` | Offload RCU callbacks from audio CPUs | +| `isolcpus=1-3` | Isolate cores for JACK/audio threads | +| IRQ priority | Elevate USB/xHCI IRQ to 95 (rtirq script) | +| CPU governor | Set to `performance` | +| `noatime` | Mount root filesystem with noatime | + +--- + +## 2. USB Audio Interface Compatibility + +### 2.1 Pi 4B USB Architecture + +- **Controller:** VIA VL805 PCIe-to-USB 3.0 host controller +- **Ports:** 2 × USB 3.0 (5 Gbps), 2 × USB 2.0 (480 Mbps) +- **Power:** All 4 ports share a 1.2A budget (total across all ports) +- **Bus:** Single root hub — all ports share bandwidth +- **Driver:** xhci_hcd + +**Critical constraint:** The 1.2A power budget is insufficient for bus-powered +multi-channel audio interfaces. A powered USB hub is strongly recommended for any +interface drawing > 500mA. + +### 2.2 USB Audio Class Support + +Linux `snd-usb-audio` module supports: +- **USB Audio Class 1.0** (UAC1): Up to 24-bit/96kHz, limited channels +- **USB Audio Class 2.0** (UAC2): Up to 32-bit/384kHz, multi-channel + +Most modern interfaces are UAC2 class-compliant and require no proprietary drivers. +Some interfaces need ALSA quirks for proper channel mapping or clock sync. + +### 2.3 Verified Compatible Interfaces + +| Interface | Type | Max I/O | Bit/Hz | Power | Notes | +|-----------|------|---------|--------|-------|-------| +| **Behringer UMC1820** | USB 2.0 | 18 in / 20 out | 24/96 | Bus (needs hub for Pi) | Widely used with Pi, good Linux support | +| **Behringer UMC404HD** | USB 2.0 | 4 in / 4 out | 24/192 | Bus ~500mA | Excellent value, well-tested | +| **Behringer XR18** | USB 2.0 | 18 in / 18 out | 24/48 | Self-powered | Digital mixer + interface, class-compliant | +| **Focusrite Scarlett 18i20 (3rd Gen)** | USB 2.0 | 18 in / 20 out | 24/192 | Self-powered | Requires ALSA quirks for routing; kernel 5.14+ has driver | +| **Focusrite Scarlett 2i2 (3rd/4th Gen)** | USB 2.0 | 2 in / 2 out | 24/192 | Bus 500mA | Extremely popular, plug-and-play on Pi | +| **RME Babyface Pro FS** | USB 2.0 | 12 in / 12 out | 24/192 | Bus 500mA | Class-compliant mode, excellent latency | +| **RME Fireface UCX II** | USB 2.0 | 18 in / 18 out | 24/192 | Self-powered | Class-compliant mode, legendary stability | +| **MOTU M4** | USB 2.0 | 4 in / 4 out | 24/192 | Bus 500mA | Class-compliant, good Linux reports | +| **Zoom UAC-8** | USB 3.0 | 8 in / 8 out | 24/96 | Bus (needs hub) | USB 3.0 for lower latency | +| **Soundcraft Signature 12 MTK** | USB 2.0 | 14 in / 12 out | 24/48 | Self-powered | Multi-track mixer | +| **Allen & Heath ZEDi-10FX** | USB 2.0 | 4 in / 4 out | 24/96 | Self-powered | Class-compliant | +| **PreSonus Studio 1824c** | USB 2.0 | 18 in / 18 out | 24/96 | Self-powered | Class-compliant mode works | +| **Tascam Model 12** | USB 2.0 | 12 in / 10 out | 24/48 | Self-powered | Multi-track mixer + interface | + +### 2.4 Known Issues & Quirks + +- **Focusrite Scarlett Gen 1/2:** Internal routing requires `alsamixer` or `scarlett-mixer` tool +- **Behringer UMC series:** Some units have clock drift when used as aggregate device +- **USB 3.0 interfaces on USB 2.0 ports:** Some interfaces (like Zoom UAC-8) require USB 3.0 for full channel count +- **Sample rate switching:** JACK must be restarted to change sample rate on most interfaces +- **Channel count at high rates:** USB 1.1 interfaces limited to 2 channels at 96kHz +- **Power warnings:** Pi undervoltage warnings appear if bus-powered interface draws too much + +### 2.5 Recommended Interfaces for Multi-Channel Mixer + +For a 16+ channel real-time mixer: +1. **Behringer XR18** — Self-powered, 18-in/18-out, built-in DSP, ~€400 +2. **Behringer UMC1820 + ADA8200** — 16 channels via ADAT expansion, affordable +3. **Focusrite Scarlett 18i20** — Solid Linux driver, 18-in/20-out, ADAT expandable + +--- + +## 3. Low-Latency Audio Distros + +### 3.1 Comparison Matrix + +| Feature | Ubuntu Studio 26.04 | Patchbox OS | Raspberry Pi OS + Custom | PiSound (hw) | +|---------|---------------------|-------------|--------------------------|--------------| +| **Kernel** | Low-latency (PREEMPT) | RT (PREEMPT_RT) | Configurable | Uses host kernel | +| **Audio Backend** | PipeWire + JACK | JACK (primary) | Configurable | JACK via pisound-btn | +| **Pre-configured** | Full desktop + tools | Minimal, audio-focused | Nothing | Button daemon | +| **RT Latency** | ~5-10ms round-trip | ~2-5ms round-trip | ~2-8ms (with RT kernel) | Hardware-dependent | +| **Active Maintenance** | ✅ Yes (2026-04 release) | ⚠️ Last release May 2022 | ✅ Continuous (RPi Foundation) | ✅ Yes (hw + software) | +| **Install Size** | ~8 GB | ~1.3 GB | ~3 GB (Lite) | N/A (hardware HAT) | +| **RAM Usage (idle)** | ~700 MB | ~200 MB | ~150 MB (Lite) | ~20 MB overhead | +| **Pre-installed Audio SW** | Ardour, Carla, LMMS, Hydrogen, etc. | Pure Data, SuperCollider, Sonic Pi | None | Modep (MOD audio pedalboard) | +| **USB Audio Support** | ✅ Excellent | ✅ Good | ✅ Good (needs config) | N/A (has own I/O) | +| **WiFi/BT Audio Issues** | Some (configurable) | Disabled by default | User-managed | N/A | + +### 3.2 Ubuntu Studio 26.04 + +**Status:** ✅ Actively maintained (April 2026 release) + +- Ships with low-latency kernel (PREEMPT, not RT) +- PipeWire is default with JACK compatibility layer +- Full desktop environment (KDE Plasma) +- Large package repository +- Good for development and testing +- **Downside:** Heavy RAM usage (~700MB idle) leaves only ~7.3GB for audio + +### 3.3 Patchbox OS + +**Status:** ⚠️ Last public release 2022-05-17 (4+ years old) + +- Purpose-built for Raspberry Pi audio +- Ships with PREEMPT_RT kernel pre-configured +- Minimal install — headless option available +- JACK backend fully configured out of box +- `patchage` visual patching tool included +- **Downside:** Stale base system. Kernel and packages are outdated. + - Needs manual update of kernel to current 6.x for security/features + - Package dependencies may be incompatible with newer hardware + +### 3.4 Raspberry Pi OS (Bookworm) + Custom RT Setup + +**Status:** ✅ Actively maintained + +**Recommended approach for this project:** +1. Start with Raspberry Pi OS Lite (64-bit, Bookworm-based) +2. Build custom PREEMPT_RT kernel (see section 1.3) +3. Install JACK + PipeWire manually +4. Configure CPU isolation and IRQ priorities + +This gives maximum control and the most current base system. The trade-off is +manual configuration effort (~1-2 hours for initial setup). + +### 3.5 PiSound (Hardware) + +**Status:** ✅ Actively sold and supported + +- Hardware HAT: 192kHz/24-bit stereo I/O + MIDI +- Ultra-low latency via I2S (not USB) +- Includes `pisound-btn` daemon for control +- Only 2 channels — not suitable for multi-channel mixer +- Great as a monitor/cue output or control surface audio feedback +- Price: ~€99 + +### 3.6 Other Relevant Projects + +| Project | Type | Relevance | +|---------|------|-----------| +| **Zynthian OS** | Synth/sampler OS for Pi | Pre-configured RT audio; useful reference config | +| **Elk Audio OS** | Commercial embedded audio OS | Sub-millisecond latency; proprietary/paid | +| **MODEP** | Open-source MOD Duo emulator | Runs on PiSound/Patchbox; pedalboard-style DSP | +| **Audio Injector** | I2S sound card HATs | 6-channel I/O cards but need specific drivers | + +--- + +## 4. USB Controller Bandwidth Analysis + +### 4.1 Theoretical Maximum Channel Count + +RPi4B USB 3.0 controller: **5 Gbps** (625 MB/s) theoretical. + +USB Audio Class 2.0 uses isochronous transfers. Per-channel bandwidth: + +| Sample Rate | Bit Depth | Channels | Bandwidth per channel pair | +|-------------|-----------|----------|---------------------------| +| 44.1 kHz | 24-bit | 2 (stereo) | ~2.12 Mbps (265 KB/s) | +| 48 kHz | 24-bit | 2 (stereo) | ~2.30 Mbps (288 KB/s) | +| 96 kHz | 24-bit | 2 (stereo) | ~4.61 Mbps (576 KB/s) | +| 192 kHz | 24-bit | 2 (stereo) | ~9.22 Mbps (1.15 MB/s) | +| 48 kHz | 32-bit | 2 (stereo) | ~3.07 Mbps (384 KB/s) | + +USB isochronous protocol overhead is ~10-15%. With USB 3.0's 5 Gbps: + +| Sample Rate | Theoretical max channels (bidirectional sum) | +|-------------|---------------------------------------------| +| 48 kHz / 24-bit | ~1,800 channels | +| 96 kHz / 24-bit | ~900 channels | +| 192 kHz / 24-bit | ~450 channels | + +### 4.2 Practical Limits + +Theoretical numbers are never achievable in practice. Real-world limiting factors: + +| Factor | Impact | +|--------|--------| +| **USB scheduling granularity** | Microframe = 125µs; practical limit ~50-60 isochronous packets/microframe | +| **Shared bus contention** | Ethernet, storage, WiFi/BT all share the single USB root hub | +| **CPU interrupt load** | Each microframe generates an interrupt; at high channel counts this overwhelms the CPU | +| **ALSA/USB driver overhead** | Buffer copies, format conversion, resampling cost | +| **Memory bandwidth** | LPDDR4-3200 at 32-bit = ~12.8 GB/s; not the bottleneck | + +### 4.3 Real-World Performance Ceiling + +Community benchmarks and reports: + +| Sample Buffer | Max Stable Channels (48kHz/24-bit) | Latency | +|---------------|-------------------------------------|---------| +| 64 samples | 8 in + 8 out | ~1.3ms | +| 128 samples | 16 in + 16 out | ~2.7ms | +| 256 samples | 24 in + 24 out | ~5.3ms | +| 512 samples | 32 in + 32 out | ~10.7ms | + +**Recommended ceiling for RPi4B:** 16-18 channels at 128 sample buffer (48kHz/24-bit). +At 96kHz, expect half the channel count. + +### 4.4 Raspberry Pi 5 Comparison + +The Pi 5 uses the RP1 southbridge with dedicated USB 3.0 controller — not sharing +a PCIe lane with other peripherals. This gives ~15-20% better USB audio throughput. +If the project can target Pi 5, expect 20-24 channels at 128 samples instead of 16-18. + +--- + +## 5. Performance Estimates & Recommendations + +### 5.1 Target Configuration + +| Component | Recommendation | +|-----------|---------------| +| **Hardware** | RPi4B 8GB | +| **OS** | Raspberry Pi OS Lite (64-bit) + custom PREEMPT_RT kernel 6.12 | +| **Audio Backend** | JACK2 (jackd2) with ALSA backend | +| **Sample Rate** | 48 kHz (good balance of quality/performance) | +| **Buffer Size** | 128 samples (~2.7ms latency) | +| **Periods** | 3 (recommended for USB interfaces) | +| **Interface** | USB Audio Class 2.0, self-powered or powered hub | +| **Power** | Official Pi 4 PSU (5.1V/3A) + powered USB hub for interface | + +### 5.2 Expected Performance + +| Metric | Estimate | +|--------|----------| +| **Round-trip latency** | 5-8ms (JACK input → DSP → JACK output) | +| **Max input channels** | 16-18 @ 48kHz/24-bit (128 sample buffer) | +| **Max output channels** | 16-18 @ 48kHz/24-bit (128 sample buffer) | +| **DSP headroom** | ~3 CPU cores available for processing (~50-70% of 4× Cortex-A72 @ 1.8GHz) | +| **Max CPU load** | Keep < 70% for xrun-free operation | +| **xHCI IRQ latency** | < 15µs with threaded IRQs + rtirq | + +### 5.3 Risk Factors + +1. **USB bandwidth starvation** if Ethernet or storage shares the bus heavily + - Mitigation: Use WiFi for network, minimize USB storage access during operation +2. **Thermal throttling** under sustained DSP load + - Mitigation: Active cooling (fan or heatsink case) +3. **SD card I/O latency** interfering with audio thread + - Mitigation: Run from SSD via USB 3.0 (but shares bus) or use tmpfs for runtime +4. **Power brownouts** from bus-powered interfaces + - Mitigation: Self-powered interface or powered USB hub + +### 5.4 Next Steps + +1. **P2: Kernel Build** — Compile PREEMPT_RT 6.12.y kernel for RPi4B +2. **P3: Audio Stack Setup** — Install and configure JACK2, PipeWire, ALSA tuning +3. **P4: Interface Testing** — Benchmark with target USB interface +4. **P5: Latency Validation** — cyclictest + jack_iodelay measurements + +--- + +## 6. References + +1. RPi Linux kernel repo: https://github.com/raspberrypi/linux (branches: rpi-6.6.y, rpi-6.12.y) +2. PREEMPT_RT mainline merge status: https://wiki.linuxfoundation.org/realtime/start +3. LinuxAudio RPi guide: https://wiki.linuxaudio.org/wiki/raspberrypi +4. Patchbox OS: https://blokas.io/patchbox-os/ +5. Ubuntu Studio: https://ubuntustudio.org/ +6. PiSound: https://blokas.io/pisound/ +7. USB Audio Class specification: https://www.usb.org/document-library/usb-audio-devices-release-40 +8. JACK Audio Connection Kit: https://jackaudio.org/ +9. PipeWire: https://pipewire.org/ +10. ALSA USB audio quirks: https://www.kernel.org/doc/html/latest/sound/alsa-configuration.html diff --git a/recipes/.gitkeep b/recipes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/.gitkeep b/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/.gitkeep b/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/wiki/.gitkeep b/wiki/.gitkeep new file mode 100644 index 0000000..e69de29