Files
uno-q-audio-synth/scripts/start-synth.sh
T
david 8cd796e3dd Initial commit: Arduino Uno Q USB Audio Synth project
- USB gadget (UAC1 + MIDI) with boot persistence
- USB host mode with auto-detection
- Pure Data synth patch with ALSA + UDP netreceive MIDI input
- MIDI rawmidi-to-UDP bridge (midi-bridge.py)
- LED matrix visualization (led-matrix-viz.py via arduino-router RPC)
- MCU sketch for LED matrix control (Arduino_RouterBridge + ArduinoGraphics)
- Conftest/OPA Rego policy validation suite for .pd files
- gen_synth_pd.py: programmatic .pd file generator
- System services: midi-bridge, led-matrix-viz, pd-synth-auto, usb-role-detect
- Justfile with deploy, enable, diagnostic recipes
- Diagnostic script (diag.sh)
2026-06-22 22:46:36 -07:00

153 lines
4.4 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
PD_DIR="/home/arduino/pd"
PATCH="$PD_DIR/synth.pd"
MODE="usb"
VERBOSE=false
die() { echo "[ERROR] $*" >&2; exit 1; }
info() { echo "[INFO] $*"; }
while [ $# -gt 0 ]; do
case "$1" in
-a|--auto) MODE="auto"; shift ;;
-i|--i2s) MODE="i2s"; shift ;;
-l|--loopback) MODE="loopback"; shift ;;
-v|--verbose) VERBOSE=true; shift ;;
-k|--kill) pkill -x pd 2>/dev/null && info "Pd stopped" || info "Pd not running"; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
if ! command -v pd &>/dev/null; then
die "Pure Data not found. Install: apt install puredata"
fi
if [ ! -f "$PATCH" ]; then
die "Patch not found: $PATCH"
fi
# --- Auto-detect mode ---
if [ "$MODE" = "auto" ]; then
if [ -f /run/usb-role ]; then
ROLE=$(cat /run/usb-role)
else
ROLE=$(/usr/local/bin/detect-usb-role.sh 2>/dev/null && cat /run/usb-role || echo "gadget")
fi
case "$ROLE" in
gadget)
MODE="usb"
if ! aplay -l 2>/dev/null | grep -q "UAC1Gadget"; then
info "Configuring USB gadget..."
/usr/local/bin/configure-usb-audio.sh start 2>/dev/null || true
sleep 1
fi
;;
host)
if [ -f /run/usb-audio-dev ] && [ -s /run/usb-audio-dev ]; then
ALSA_DEV=$(cat /run/usb-audio-dev)
else
info "Detecting USB audio interface..."
/usr/local/bin/configure-usb-host.sh 2>/dev/null || {
die "No USB audio interface found. Plug one in via hub."
}
ALSA_DEV=$(cat /run/usb-audio-dev)
fi
info "Mode: USB host (MIDI controller + USB audio interface)"
MIDI_OPTS=(-alsamidi)
midi_dev=$(amidi -l 2>/dev/null | grep -v "^Dir" | head -1 | awk '{print $2}' | sed 's/\(hw:[0-9]*,[0-9]*\).*/\1/')
if [ -n "$midi_dev" ]; then
MIDI_OPTS+=(-midiadddev "$midi_dev")
info " MIDI device: $midi_dev"
fi
AUDIO_OPTS=(-audiooutdev 4 -audioindev 4)
PD_ARGS=(
-nogui -alsa
-send "pd dsp 1"
"${MIDI_OPTS[@]}"
"${AUDIO_OPTS[@]}"
-audiobuf 20 -blocksize 64 -r 48000
-channels 2 -inchannels 0 -outchannels 2
-path "$PD_DIR" "$PATCH"
)
if [ "$VERBOSE" = true ]; then pd "${PD_ARGS[@]}"
else pd "${PD_ARGS[@]}" > /dev/null 2>&1 &
PID=$!; info "Pd started (PID: $PID)"; info " Stop: kill $PID"
fi
exit 0
;;
*)
info "Auto-detect: unknown role '$ROLE', falling back to gadget"
MODE="usb"
;;
esac
fi
# --- Configure per-mode options ---
AUDIO_OPTS=()
MIDI_OPTS=(-alsamidi)
if [ "$MODE" = "usb" ]; then
info "Mode: USB gadget (UAC1 audio + gmidi MIDI)"
AUDIO_OPTS=(-audiooutdev 2 -audioindev 2)
if aplay -l 2>/dev/null | grep -q "UAC1Gadget"; then
info " USB gadget: OK"
midi_dev=$(amidi -l 2>/dev/null | grep "f_midi" | head -1 | awk '{print $2}')
if [ -n "$midi_dev" ]; then
MIDI_OPTS+=(-midiadddev "$midi_dev")
info " MIDI device: $midi_dev"
fi
else
info " USB gadget: NOT DETECTED (kernel modules needed)"
fi
fi
if [ "$MODE" = "i2s" ]; then
if [ -f /run/i2s-audio-dev ] && [ -s /run/i2s-audio-dev ]; then
ALSA_DEV=$(cat /run/i2s-audio-dev)
else
for dev in "hw:I2S,0" "hw:MI2S,0" "hw:0,0"; do
if aplay -l 2>/dev/null | grep -qi "${dev%,*}"; then
ALSA_DEV="$dev"
break
fi
done
fi
info "Mode: I2S DAC (standalone analog audio)"
AUDIO_OPTS=(-audioadddev "$ALSA_DEV")
fi
if [ "$MODE" = "loopback" ]; then
info "Mode: ALSA loopback (testing)"
AUDIO_OPTS=(-audiodev 2)
fi
PD_ARGS=(
-nogui
-alsa
"${MIDI_OPTS[@]}"
"${AUDIO_OPTS[@]}"
-send "pd dsp 1"
-audiobuf 20
-blocksize 64
-r 48000
-channels 1
-inchannels 0
-outchannels 1
-path "$PD_DIR"
"$PATCH"
)
if [ "$VERBOSE" = true ]; then
pd "${PD_ARGS[@]}" &
else
pd "${PD_ARGS[@]}" > /dev/null 2>&1 &
fi
PID=$!
info "Pd started (PID: $PID)"
info " Stop: kill $PID"
wait $PID
info "Pd exited (code: $?)"