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
This commit is contained in:
2026-05-19 19:06:12 -04:00
commit 96a6b96b7e
20 changed files with 2141 additions and 0 deletions
+21
View File
@@ -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
+60
View File
@@ -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
+42
View File
@@ -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
View File
+6
View File
@@ -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
+7
View File
@@ -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
+1
View File
@@ -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
+11
View File
@@ -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
+43
View File
@@ -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
+2
View File
@@ -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
+16
View File
@@ -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
+979
View File
@@ -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: 164096 frames
# - Periods: 232
# - Sample rate: 8000192000 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`
View File
View File
+622
View File
@@ -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@<pi-ip>:/boot/kernel8-rt.img
# Copy DTBs
scp arch/arm64/boot/dts/broadcom/*.dtb root@<pi-ip>:/boot/
# Install modules
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
INSTALL_MOD_PATH=./modules modules_install
scp -r modules/lib/modules/* root@<pi-ip>:/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/<version>/ (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
+331
View File
@@ -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
View File
View File
View File
View File