dbd7c2cece
midi-bridge.py: - Auto-detect rawmidi device (gadget f_midi > env override > fallback) - Reconnect on ENODEV (device hotplug) - No longer needs MIDI_BRIDGE_DEV env var in common cases start-synth.sh: - Remove all -alsamidi/-midiadddev flags (kernel lacks CONFIG_SND_SEQUENCER) - MIDI handled entirely by midi-bridge.service → UDP → netreceive - Host mode: same approach, no ALSA sequencer needed mpk-mini-sim.pd: - New MPK Mini Mk II simulator (25 keys, 8 pads, 8 CC knobs) - Proper Pd #X obj format for all objects (bng, hsl, t, del, netsend, loadbang) - UDP output to board:8081, matching midi-bridge format system: enable usb-gadget-audio.service at boot, load dwc3 module at boot
135 lines
3.9 KiB
Bash
Executable File
135 lines
3.9 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 handled by midi-bridge.service → UDP → Pd netreceive
|
|
AUDIO_OPTS=(-audiooutdev 4 -audioindev 4)
|
|
PD_ARGS=(
|
|
-nogui -alsa
|
|
-send "pd dsp 1"
|
|
"${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=()
|
|
|
|
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 handled by midi-bridge.service → UDP → Pd netreceive
|
|
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
|
|
-send "pd dsp 1"
|
|
"${AUDIO_OPTS[@]}"
|
|
-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: $?)"
|