# Carla Integration — Plugin Host for RPi4B Audio Mixer **Date:** 2026-05-19 **Task:** P2-R2 **Parent:** P2-R1 (ALSA + JACK2 Low-Latency Config) **Target Platform:** Raspberry Pi 4B, RPi OS Lite 64-bit (Bookworm), PREEMPT_RT 6.12.y --- ## Table of Contents 1. [Architecture Overview](#1-architecture-overview) 2. [Build Carla from Source](#2-build-carla-from-source) 3. [Build Neural Amp Modeler (NAM) LV2](#3-build-neural-amp-modeler-nam-lv2) 4. [Carla Configuration](#4-carla-configuration) 5. [Default Mixer Rack & Patchbay](#5-default-mixer-rack--patchbay) 6. [JACK Auto-Connection](#6-jack-auto-connection) 7. [Plugin Compatibility Testing](#7-plugin-compatibility-testing) 8. [Preset & Program Management](#8-preset--program-management) 9. [Performance Tuning for RPi4B](#9-performance-tuning-for-rpi4b) 10. [Operational Procedures](#10-operational-procedures) 11. [Troubleshooting](#11-troubleshooting) 12. [File Inventory](#12-file-inventory) --- ## 1. Architecture Overview Carla sits as the plugin host layer between JACK and the audio applications: ``` ┌──────────────────────────────────────────────────────────────┐ │ User Space │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Carla Plugin Host (carla) │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ Rack Mode — 8-channel mixer │ │ │ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐ │ │ │ │ │ │ │Ch1 │ │Ch2 │ │Ch3 │ │AUX 1/2 │ │ │ │ │ │ │ │Gate→ │ │Gate→ │ │NAM→ │ │Reverb │ │ │ │ │ │ │ │EQ→ │ │EQ→ │ │IR │ │Delay │ │ │ │ │ │ │ │Comp │ │Comp │ │ │ │ │ │ │ │ │ │ │ └──┬───┘ └──┬───┘ └──┬───┘ └────┬─────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────┼────────┼───────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌────▼────────▼────┐ │ │ │ │ │ │ │ Master Limiter │ │ │ │ │ │ │ └────────┬────────┘ │ │ │ │ │ └──────────────────┼──────────────────────────┘ │ │ │ │ │ │ │ │ │ ┌──────────────────▼──────────────────────────┐ │ │ │ │ │ Patchbay — dynamic signal routing │ │ │ │ │ │ (system capture → plugin inputs) │ │ │ │ │ │ (plugin outputs → system playback) │ │ │ │ │ └──────────────────┬──────────────────────────┘ │ │ │ └─────────────────────┼──────────────────────────────┘ │ │ │ │ │ ┌─────────────────────▼──────────────────────────────┐ │ │ │ JACK2 (jackd) — SCHED_FIFO prio 70-80 │ │ │ │ ALSA backend (hw:USB), 48kHz, 128f/3p, 8ms │ │ │ └─────────────────────┬──────────────────────────────┘ │ ├─────────────────────────┼──────────────────────────────────────┤ │ Kernel │ │ │ snd-usb-audio (nrpacks=1) → xHCI (IRQ prio 95) │ │ PREEMPT_RT 6.12.y, cores 1-3 isolated for audio │ └─────────────────────────┼──────────────────────────────────────┘ │ ┌────────▼────────┐ │ USB Audio I/F │ │ (class UAC2) │ └─────────────────┘ ``` ### Plugin Format Support | Format | Carla Support | Build Requirement | |--------|--------------|-------------------| | LV2 | ✓ Native | lv2-dev, lilv | | LADSPA | ✓ Native | Built-in | | DSSI | ✓ Native | Built-in | | VST2 | ✓ Via bridge | VST2 SDK (optional) | | VST3 | ✓ Via bridge | VST3 SDK (/opt/vst3sdk) | | SF2/SFZ| ✓ Native | libfluidsynth-dev | | NAM | ✓ LV2 host | See §3 below | ### Key Design Decisions | Parameter | Value | Rationale | |-----------|-------|-----------| | Carla process mode | MultipleClients | Each plugin = separate JACK client for independent patching | | Default channels | 8 (expandable) | 2 mic/line, 1 guitar, 2 aux, master | | Plugin format priority | LV2 | Native Linux, no bridge overhead, best ARM support | | GUI toolkit | PyQt5 (headless supported) | Carla can run without GUI on RPi4B | | ARM optimization | Cortex-A72 + NEON + LTO | -march=armv8-a+crc+crypto -mtune=cortex-a72 | | Transport sync | Disabled | Mixer doesn't need DAW transport | --- ## 2. Build Carla from Source ### Prerequisites - Working JACK2 setup (see parent task P2-R1: `docs/audio-stack-config.md`) - ~500MB free disk space for build - Internet connection for dependency download - **Run directly on the Raspberry Pi 4B** (not cross-compiled) ### Build ```bash cd /home/pi/raspberry-pi-mixer # One-command build chmod +x scripts/carla-build.sh ./scripts/carla-build.sh --install ``` Estimated build time: 30-60 minutes on RPi4B (4 cores). ### What gets built The script: 1. Installs all build dependencies (Qt5, JACK, ALSA, FFmpeg, FluidSynth, OSC, etc.) 2. Clones Carla from `https://github.com/falkTX/Carla.git` 3. Patches the Makefile to add ARM Cortex-A72 optimization flags (`-march=armv8-a+crc+crypto -mtune=cortex-a72`) 4. Builds with `WITH_LTO=true` for smaller, faster binary 5. Optionally installs to `/usr/local` ### Cortex-A72 Optimization The Makefile patch adds ARM64-specific flags to `source/Makefile.mk`: ```makefile ifeq ($(CPU_ARM64_OR_AARCH64),true) BASE_OPTS += -march=armv8-a+crc+crypto -mtune=cortex-a72 endif ``` The original Makefile only has NEON flags for ARM32 (`Cortex-A7`). ARM64/aarch64 uses the compiler's default NEON support (always available on ARMv8-A). ### VST3 Support VST3 plugin hosting requires the Steinberg VST3 SDK: ```bash sudo git clone --recursive https://github.com/steinbergmedia/vst3sdk.git /opt/vst3sdk ``` Then rebuild Carla. Without the SDK, LV2, LADSPA, and DSSI still work. ### Verification ```bash # Check binary file /usr/local/bin/carla # Expected: ELF 64-bit LSB executable, ARM aarch64 # Check features carla --help 2>&1 | head -20 # Test with JACK sudo audio-stack-start carla & ``` --- ## 3. Build Neural Amp Modeler (NAM) LV2 NAM uses the RTNeural library (real-time neural inference, header-only C++) wrapped in an LV2 plugin. It does NOT require libtorch/PyTorch. ### Build ```bash cd /home/pi/raspberry-pi-mixer chmod +x scripts/nam-build.sh ./scripts/nam-build.sh --install ``` ### Critical: Model Sizes Matter | Model Size | Parameters | RPi4B Feasibility | xrun Risk at 128f | |------------|-----------|-------------------|-------------------| | Standard | ~500K+ | ✗ No | Guaranteed xruns | | Feather | ~100-200K | ⚠ Marginal | Occasional | | Nano | ~30-50K | ✓ Yes | Low | | Micro | ~10-20K | ✓ Yes | Very low | **For RPi4B, use nano or feather models from [Tone3000](https://www.tone3000.com/search?sizes=feather).** ```bash # Download models mkdir -p ~/nam-models # Then download .nam files from Tone3000 and place them in ~/nam-models/ ``` ### NAM + IR Chain in Carla The default rack preset places NAM in Channel 3 followed by an IR loader for cabinet simulation: ``` system:capture_3 → [Ch3 NAM] → [Ch3 IR Loader] → Master → system:playback_1/2 ``` --- ## 4. Carla Configuration ### Configuration File Carla's settings are stored at `~/.config/falkTX/Carla.conf` (JSON-format). Key settings for our mixer setup: ```json { "Main": { "AudioDriver": "JACK", "ProcessMode": "MultipleClients", "TransportMode": "Disabled" }, "JACK": { "AutoConnectPorts": false, "RackExportPorts": true }, "LV2": { "UIbridges": false, "BridgedWine": false } } ``` The `scripts/carla-jack-autoconnect` script handles port wiring instead of Carla's built-in auto-connect, giving us precise control. ### Environment Variables ```bash # For headless operation (RPi4B without display) export CARLA_BRIDGE_DUMMY=1 # Disable plugin UIs export QT_QPA_PLATFORM=offscreen # Qt offscreen rendering # Performance export JACK_NO_AUDIO_OUT=0 # Don't mute JACK when jackd starts ``` ### Carla Startup with the Rack ```bash # Start the full audio stack sudo audio-stack-start # Launch Carla with the default mixer rack carla config/carla-8ch-default.carxp & # Auto-wire JACK ports ./scripts/carla-jack-autoconnect --watch ``` --- ## 5. Default Mixer Rack & Patchbay ### Rack Layout (`config/carla-8ch-default.carxp`) ``` Plugin Chain (signal flow top-to-bottom): ───────────────────────────────────────── Channel 1: Gate → 12-Band EQ → Compressor Channel 2: Gate → 8-Band EQ → Compressor Channel 3: NAM → IR Loader (guitar) AUX 1: Hall Reverb AUX 2: Vintage Delay Master: Limiter (ceiling -1.0 dBFS) ───────────────────────────────────────── ``` All plugins use Calf Studio Gear LV2 suite for CPU-efficient DSP on ARM. ### Patchbay Rules (`config/carla-patchbay.xml`) ``` system:capture_1 → Ch1 Gate input system:capture_2 → Ch2 Gate input system:capture_3 → Ch3 NAM input Master Limiter out 1 → system:playback_1 Master Limiter out 2 → system:playback_2 ``` ### Generating Custom Racks ```bash # 4-channel minimal rack python3 scripts/carla-preset-gen.py --channels 4 # Patchbay only python3 scripts/carla-preset-gen.py --patchbay ``` ### Adding/Removing Plugins Edit the rack in Carla's GUI, or modify `scripts/carla-preset-gen.py` and regenerate. The preset uses standard LV2 URIs: - `http://calf.sourceforge.net/plugins/Gate` - `http://calf.sourceforge.net/plugins/Equalizer12Band` - `http://calf.sourceforge.net/plugins/Equalizer8Band` - `http://calf.sourceforge.net/plugins/Compressor` - `http://calf.sourceforge.net/plugins/Reverb` - `http://calf.sourceforge.net/plugins/VintageDelay` - `http://calf.sourceforge.net/plugins/Limiter` - `http://github.com/mikeoliphant/neural-amp-modeler-lv2` --- ## 6. JACK Auto-Connection ### One-shot Connection ```bash ./scripts/carla-jack-autoconnect ``` Connects all currently available Carla ports according to routing rules. ### Persistent Auto-Connect Daemon ```bash ./scripts/carla-jack-autoconnect --watch ``` Monitors JACK for new Carla plugin ports and wires them automatically. Run this in a tmux session or as a systemd user service: ```ini # ~/.config/systemd/user/carla-autoconnect.service [Unit] Description=Carla JACK Auto-Connect After=jackd.service [Service] ExecStart=/home/pi/raspberry-pi-mixer/scripts/carla-jack-autoconnect --watch Restart=on-failure [Install] WantedBy=default.target ``` ```bash systemctl --user daemon-reload systemctl --user enable --now carla-autoconnect.service ``` ### Dry Run ```bash ./scripts/carla-jack-autoconnect --dry-run ``` Shows what would be connected without making changes. ### Disconnect All Carla Ports ```bash ./scripts/carla-jack-autoconnect --disconnect-all ``` --- ## 7. Plugin Compatibility Testing ### LV2 Lint Validation The `lv2lint` tool checks LV2 plugin bundles for spec compliance: ```bash chmod +x scripts/lv2lint-check.sh # Check all installed LV2 plugins ./scripts/lv2lint-check.sh # Check only NAM ./scripts/lv2lint-check.sh --nam-only # Check a specific plugin ./scripts/lv2lint-check.sh /usr/lib/lv2/calf.lv2 # List all installed plugins ./scripts/lv2lint-check.sh --list ``` ### What gets checked | Check | Description | |-------|-------------| | Manifest parsing | Valid `manifest.ttl` exists | | Binary architecture | Must be ARM aarch64 (not x86) | | Shared library deps | All `.so` dependencies resolvable | | URI validity | Unique, well-formed plugin URI | | Port definitions | Valid audio/CV/control port specs | | Parameter ranges | min/max/default values defined | | atom:Path support | Critical for NAM model selection | | Carla extensions | Carla-specific features if present | ### ARM-Specific Checks - Architecture verification: ensures no x86 binaries are present - NEON SIMD detection: checks if plugins use NEON optimization - CPU feature requirements: verifies no SSSE3/AVX instructions ### Runtime Testing Procedure ```bash # 1. Start JACK sudo audio-stack-start # 2. Run Carla with test rack carla config/carla-8ch-default.carxp & # 3. Auto-connect sleep 2 && ./scripts/carla-jack-autoconnect # 4. Check for xruns watch -n 1 "jack_cpu_load; echo '---'; tail -5 /tmp/jackd.log | grep -i xrun || echo 'no xruns'" # 5. Verify audio path jack_lsp -c | grep -E "(Carla|system)" # 6. Test each plugin bypass # Send MIDI CC or use OSC to toggle plugin bypass ``` --- ## 8. Preset & Program Management ### CLI Interface ```bash python3 scripts/carla-preset-manager.py [command] ``` | Command | Description | |---------|-------------| | `list` | List all saved presets | | `save ` | Save current Carla state as preset | | `load ` | Load a preset (overwrites current state) | | `export ` | Export preset + models as .tar.gz bundle | | `import ` | Import a preset bundle | | `set-model ` | Set NAM model path via OSC | ### Preset Storage - **User presets:** `~/carla-presets/*.carxp` - **System presets:** `config/*.carxp` (in repo) - **Metadata:** `~/carla-presets/*.meta.json` - **Models:** `~/nam-models/*.nam` ### Workflow: Save and Restore ```bash # Tweak your rack in Carla GUI, then: python3 scripts/carla-preset-manager.py save "my-live-set" # Later, restore: python3 scripts/carla-preset-manager.py load "my-live-set" # Restart Carla to apply ``` ### Workflow: Export a Full Bundle ```bash # Export preset with model references python3 scripts/carla-preset-manager.py export "my-live-set" /tmp/my-set.tar.gz # Transfer to another RPi4B scp /tmp/my-set.tar.gz pi@other-rpi:/tmp/ ssh pi@other-rpi "python3 ~/raspberry-pi-mixer/scripts/carla-preset-manager.py import /tmp/my-set.tar.gz" ``` --- ## 9. Performance Tuning for RPi4B ### CPU Governor ```bash # Must be 'performance' for audio cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # Expected: performance ``` ### CPU Isolation From parent task — cores 1-3 isolated for audio via `isolcpus=1-3` in cmdline.txt. Carla plugins run on isolated cores. Check with: ```bash taskset -cp $(pgrep carla) # Expected: affinity list includes 1-3 ``` ### Carla Process Priority After Carla starts: ```bash # Set Carla to SCHED_FIFO priority (JACK client) sudo chrt -f -p 80 $(pgrep carla) ``` ### NAM Performance Tuning For the NAM plugin specifically: 1. **Use nano/feather models** — standard models cause xruns at any buffer 2. **Increase buffer if needed** — edit `/etc/jackdrc` and change `-p 128` to `-p 256` 3. **Disable GUI updates** — Carla GUI redraws consume CPU 4. **Bypass unused plugins** — Carla's bypass is true DSP bypass (zero CPU) ### Monitoring ```bash # Real-time CPU load jack_cpu_load # Per-process DSP load top -H -p $(pgrep carla) # Xrun count grep -c xrun /tmp/jackd.log ``` ### Expected Performance | Configuration | CPU Load (idle) | CPU Load (8ch active) | Headroom | |--------------|-----------------|-----------------------|----------| | No NAM, all Calf | ~8% | ~22% | 78% | | 1x Nano NAM | ~12% | ~35% | 65% | | 1x Feather NAM | ~18% | ~52% | 48% | | 1x Standard NAM | ~45% | ~95% | **xruns** | --- ## 10. Operational Procedures ### Startup Sequence ```bash #!/bin/bash # Full audio stack startup with Carla # 1. Start JACK + ALSA sudo audio-stack-start # 2. Wait for JACK to stabilize sleep 3 # 3. Set CPU governor echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor # 4. Launch Carla with default rack carla config/carla-8ch-default.carxp & CARLA_PID=$! # 5. Set realtime priority sleep 2 sudo chrt -f -p 80 $CARLA_PID 2>/dev/null || true # 6. Auto-connect JACK ports ./scripts/carla-jack-autoconnect & AUTOCONNECT_PID=$! echo "Audio stack running. Carla PID: $CARLA_PID" ``` ### Shutdown Sequence ```bash #!/bin/bash # Graceful shutdown # 1. Disconnect all Carla ports ./scripts/carla-jack-autoconnect --disconnect-all # 2. Stop Carla pkill -f carla || true # 3. Stop JACK sudo audio-stack-stop ``` ### Headless Operation For RPi4B without a display, Carla can operate headlessly: ```bash # Run Carla without GUI QT_QPA_PLATFORM=offscreen carla config/carla-8ch-default.carxp & # Control via OSC carla-control --osc-port 22752 set_parameter "Ch1 EQ" 0 0.5 ``` ### OSC Remote Control Carla exposes all parameters via OSC on port 22752 (configurable): ```bash # List plugins oscsend localhost 22752 /Carla/refresh # Set parameter (plugin_id, param_index, value) oscsend localhost 22752 /Carla/set_parameter i 0 i 0 f 0.707 # Bypass plugin oscsend localhost 22752 /Carla/set_active i 0 i 0 ``` --- ## 11. Troubleshooting ### Carla won't start ```bash # Check JACK is running pgrep jackd && echo "JACK OK" || echo "Start JACK first: sudo audio-stack-start" # Check Carla binary ldd $(which carla) | grep "not found" # If any libraries missing, rebuild with: ./scripts/carla-build.sh --clean --install # Run with debug output carla --debug 2>&1 | tail -20 ``` ### No audio (silent, no xruns) ```bash # Check JACK connections jack_lsp -c | grep system # Run auto-connect ./scripts/carla-jack-autoconnect # Check plugin bypass state — all bypassed = silence # In Carla GUI: check each plugin's bypass button ``` ### Xruns with NAM ```bash # 1. Switch to nano model # 2. Increase JACK buffer: edit /etc/jackdrc, change -p 128 to -p 256 sudo systemctl restart jackd # 3. Try feather models with buffer 256 # 4. If still xrunning, skip NAM for live use — use it only for re-amping ``` ### Plugin not loading in Carla ```bash # Refresh LV2 plugin cache rm -f ~/.cache/carla/carla-plugin-cache carla --refresh & # Check lv2ls lv2ls 2>&1 | grep -i # Validate the plugin ./scripts/lv2lint-check.sh /usr/lib/lv2/.lv2 ``` ### VST3 plugins not showing ```bash # VST3 SDK was not installed during build ls /opt/vst3sdk && echo "SDK found" || echo "Install SDK and rebuild" # Rebuild: ./scripts/carla-build.sh --clean --install ``` ### High CPU / thermal throttling ```bash # Check CPU temp vcgencmd measure_temp # Check if throttled vcgencmd get_throttled # If throttling: # - Reduce plugin count # - Bypass unused plugins # - Add active cooling # - Use nano NAM models only ``` --- ## 12. File Inventory ``` raspberry-pi-mixer/ ├── scripts/ │ ├── carla-build.sh # Build Carla from source (ARM Cortex-A72 optimized) │ ├── nam-build.sh # Build NAM LV2 plugin for ARM │ ├── carla-preset-gen.py # Generate default rack + patchbay presets │ ├── carla-jack-autoconnect # Auto-wire JACK ports to Carla plugins │ ├── carla-preset-manager.py # Save/load/export presets │ ├── lv2lint-check.sh # LV2 plugin validation suite │ ├── audio-stack-start # (from P2-R1) Full audio stack startup │ ├── audio-stack-stop # (from P2-R1) Full audio stack shutdown │ ├── jack-latency-test # (from P2-R1) Round-trip latency measurement │ └── jack-route-default # (from P2-R1) Default JACK routing ├── config/ │ ├── carla-8ch-default.carxp # Default 8-channel mixer rack preset │ ├── carla-patchbay.xml # Patchbay connection rules │ ├── jackdrc # (from P2-R1) JACK server config │ ├── alsa-usb.conf # (from P2-R1) ALSA USB config │ └── ... # (other P2-R1 configs) └── docs/ ├── audio-stack-config.md # (from P2-R1) Full audio stack docs └── carla-integration.md # THIS FILE — Carla integration docs ``` ### Lines of Code (new in this task) | File | Lines | Purpose | |------|-------|---------| | scripts/carla-build.sh | 196 | Carla build automation | | scripts/nam-build.sh | 184 | NAM LV2 build automation | | scripts/carla-preset-gen.py | 196 | Preset generation | | scripts/carla-jack-autoconnect | 208 | JACK port auto-wiring | | scripts/carla-preset-manager.py | 246 | Preset save/load/export | | scripts/lv2lint-check.sh | 217 | Plugin validation | | config/carla-8ch-default.carxp | auto-generated | Default rack | | config/carla-patchbay.xml | auto-generated | Patchbay rules | | docs/carla-integration.md | this file | Documentation | | **Total** | **~1,247 lines** | 7 scripts + 2 configs + 1 doc | --- ## Verification Checklist - [ ] Carla builds successfully on RPi4B (`./scripts/carla-build.sh --install`) - [ ] `carla --help` works and shows JACK audio driver - [ ] NAM LV2 builds successfully (`./scripts/nam-build.sh --install`) - [ ] `lv2ls | grep neural` shows NAM plugin - [ ] `./scripts/lv2lint-check.sh` passes with 0 errors - [ ] JACK starts: `sudo audio-stack-start` - [ ] Carla launches with rack: `carla config/carla-8ch-default.carxp` - [ ] Auto-connect wires ports: `./scripts/carla-jack-autoconnect` - [ ] Audio passes through: `jack_lsp -c` shows Carla ↔ system connections - [ ] No xruns at idle: `jack_cpu_load` < 10% - [ ] NAM loads a nano model without xruns (128f buffer) - [ ] Preset save/load works: `./scripts/carla-preset-manager.py save test && load test` - [ ] CPU governor is 'performance': `cat /sys/.../scaling_governor` - [ ] Carla runs at SCHED_FIFO prio 80: `chrt -p $(pgrep carla)`