8cd796e3dd
- 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)
449 lines
20 KiB
Makefile
449 lines
20 KiB
Makefile
# Arduino Uno Q — USB Audio Synth
|
|
# Run with: just <recipe>
|
|
# Override board host: just BOARD_HOST=192.168.1.100 deploy
|
|
|
|
BOARD_HOST := env_var_or_default('BOARD_HOST', 'uno-q.local')
|
|
BOARD_USER := env_var_or_default('BOARD_USER', 'arduino')
|
|
BOARD_PASS := env_var_or_default('BOARD_PASS', 'arduino')
|
|
SSH_KEY := env_var_or_default('SSH_KEY', '/home/david/.ssh/unoq_deploy_key')
|
|
PD_DIR := "/home/" + BOARD_USER + "/pd"
|
|
SYSTEM_DIR := "/usr/local"
|
|
SSH_OPTS := "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i " + SSH_KEY
|
|
|
|
default:
|
|
@just --list
|
|
|
|
# ─────────────────────────────────────────────────────────
|
|
# FACTORY SETUP — first-time board configuration
|
|
# ─────────────────────────────────────────────────────────
|
|
|
|
# Full factory setup: connect to board via USB (ADB), set password,
|
|
# connect WiFi, enable SSH, install Pd, deploy project
|
|
factory-setup:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
echo "[SETUP] Arduino Uno Q — Factory to Synth"
|
|
echo ""
|
|
|
|
# Check ADB
|
|
if ! command -v adb &>/dev/null; then
|
|
echo "[ERROR] adb not found. Install: sudo apt install adb"
|
|
exit 1
|
|
fi
|
|
|
|
DEVICE=$(adb devices | grep -v "List" | grep "device$" | head -1 | awk '{print $1}')
|
|
if [ -z "$DEVICE" ]; then
|
|
echo "[ERROR] No ADB device found. Connect Uno Q via USB."
|
|
exit 1
|
|
fi
|
|
echo "[OK] Found ADB device: $DEVICE"
|
|
|
|
# Reset expired password
|
|
echo "[STEP] Setting board user password..."
|
|
adb -s "$DEVICE" shell 'printf "{{BOARD_PASS}}\n{{BOARD_PASS}}\n" | passwd' 2>/dev/null
|
|
|
|
# Connect WiFi
|
|
read -p "WiFi SSID: " WIFI_SSID
|
|
read -rsp "WiFi password: " WIFI_PASS
|
|
echo
|
|
adb -s "$DEVICE" shell "echo '{{BOARD_PASS}}' | sudo -S nmcli device wifi connect \"$WIFI_SSID\" password \"$WIFI_PASS\""
|
|
|
|
# Get IP
|
|
IP=$(adb -s "$DEVICE" shell "ip addr show wlan0 2>/dev/null | grep 'inet ' | awk '{print \$2}' | cut -d/ -f1")
|
|
if [ -z "$IP" ]; then
|
|
echo "[ERROR] Could not get IP address"
|
|
exit 1
|
|
fi
|
|
echo "[OK] Board IP: $IP"
|
|
|
|
# Generate SSH host keys + enable SSH
|
|
adb -s "$DEVICE" shell 'echo "{{BOARD_PASS}}" | sudo -S ssh-keygen -A 2>/dev/null'
|
|
adb -s "$DEVICE" shell 'echo "{{BOARD_PASS}}" | sudo -S systemctl enable --now ssh 2>/dev/null'
|
|
|
|
# Install SSH key
|
|
KEY=$(cat "{{SSH_KEY}}.pub" 2>/dev/null || echo "")
|
|
if [ -n "$KEY" ]; then
|
|
adb -s "$DEVICE" shell "mkdir -p ~/.ssh && echo '$KEY' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
|
|
echo "[OK] SSH key installed"
|
|
else
|
|
echo "[WARN] No SSH key at {{SSH_KEY}}.pub — generate with: ssh-keygen -t ed25519 -f {{SSH_KEY}}"
|
|
fi
|
|
|
|
# Install packages
|
|
echo "[STEP] Installing puredata (this may take a while)..."
|
|
ssh {{SSH_OPTS}} "{{BOARD_USER}}@$IP" 'echo "{{BOARD_PASS}}" | sudo -S apt-get install -y -qq puredata alsa-utils 2>&1 | tail -3'
|
|
|
|
echo ""
|
|
echo "[DONE] Board is ready at $IP"
|
|
echo " Run: just BOARD_HOST=$IP setup"
|
|
|
|
# ─────────────────────────────────────────────────────────
|
|
# DEPLOY
|
|
# ─────────────────────────────────────────────────────────
|
|
|
|
# Copy Pd patch to board
|
|
deploy-patch:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[DEPLOY] Patching to {{BOARD_USER}}@{{BOARD_HOST}}:{{PD_DIR}}"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "mkdir -p {{PD_DIR}}"
|
|
scp $SCP_OPTS pd/synth.pd "{{BOARD_USER}}@{{BOARD_HOST}}:{{PD_DIR}}/"
|
|
|
|
# Copy system config files + scripts to board
|
|
deploy-system:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[DEPLOY] System config to {{BOARD_USER}}@{{BOARD_HOST}}"
|
|
for script in configure-usb-audio.sh configure-usb-host.sh detect-usb-role.sh detect-i2s-device.sh on-usb-role-change.sh; do
|
|
scp $SCP_OPTS "system/$script" "{{BOARD_USER}}@{{BOARD_HOST}}:{{SYSTEM_DIR}}/bin/"
|
|
done
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" 'echo "{{BOARD_PASS}}" | sudo -S chmod +x {{SYSTEM_DIR}}/bin/configure-usb-*.sh {{SYSTEM_DIR}}/bin/detect-*.sh {{SYSTEM_DIR}}/bin/on-usb-role-change.sh'
|
|
scp $SCP_OPTS system/asound.conf "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
scp $SCP_OPTS system/asound-i2s.conf "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" 'echo "{{BOARD_PASS}}" | sudo -S mv /tmp/asound.conf /etc/asound.conf && echo "{{BOARD_PASS}}" | sudo -S mv /tmp/asound-i2s.conf /etc/asound-i2s.conf'
|
|
scp $SCP_OPTS scripts/start-synth.sh "{{BOARD_USER}}@{{BOARD_HOST}}:{{SYSTEM_DIR}}/bin/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" 'echo "{{BOARD_PASS}}" | sudo -S chmod +x {{SYSTEM_DIR}}/bin/start-synth.sh'
|
|
|
|
# Deploy everything
|
|
deploy: deploy-patch deploy-system
|
|
@echo "[OK] All files deployed"
|
|
|
|
# Deploy midi-bridge script and service to board
|
|
deploy-midi-bridge:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[DEPLOY] midi-bridge to {{BOARD_USER}}@{{BOARD_HOST}}"
|
|
scp $SCP_OPTS scripts/midi-bridge.py "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo mv /tmp/midi-bridge.py {{SYSTEM_DIR}}/bin/ && sudo chmod +x {{SYSTEM_DIR}}/bin/midi-bridge.py"
|
|
scp $SCP_OPTS system/midi-bridge.service "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo mv /tmp/midi-bridge.service /etc/systemd/system/ && sudo systemctl daemon-reload"
|
|
echo "[OK] midi-bridge deployed"
|
|
|
|
# Deploy LED matrix visualization script and service
|
|
deploy-led-matrix-viz:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[DEPLOY] led-matrix-viz to {{BOARD_USER}}@{{BOARD_HOST}}"
|
|
scp $SCP_OPTS scripts/led-matrix-viz.py "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo mv /tmp/led-matrix-viz.py {{SYSTEM_DIR}}/bin/ && sudo chmod +x {{SYSTEM_DIR}}/bin/led-matrix-viz.py"
|
|
scp $SCP_OPTS system/led-matrix-viz.service "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo mv /tmp/led-matrix-viz.service /etc/systemd/system/ && sudo systemctl daemon-reload"
|
|
echo "[OK] led-matrix-viz deployed"
|
|
|
|
# Deploy everything (patch + system + midi-bridge + led-matrix-viz)
|
|
deploy-all: deploy deploy-midi-bridge deploy-led-matrix-viz
|
|
@echo "[OK] All files and scripts deployed"
|
|
|
|
# Enable midi-bridge service
|
|
enable-midi-bridge:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo systemctl enable midi-bridge && echo '[OK] midi-bridge enabled'"
|
|
|
|
# Enable led-matrix-viz service
|
|
enable-led-matrix-viz:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo systemctl enable led-matrix-viz && echo '[OK] led-matrix-viz enabled'"
|
|
|
|
# Start & enable host mode services (midi-bridge + led-matrix-viz)
|
|
enable-host-mode: deploy-midi-bridge deploy-led-matrix-viz
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo systemctl enable midi-bridge led-matrix-viz && \
|
|
sudo systemctl start midi-bridge led-matrix-viz && \
|
|
echo '[OK] Host mode services enabled and started'"
|
|
|
|
# Install all systemd services
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[INSTALL] Services on {{BOARD_USER}}@{{BOARD_HOST}}"
|
|
for svc in usb-role-detect usb-gadget-audio pd-synth-auto pd-synth detect-i2s-device pd-synth-i2s; do
|
|
scp $SCP_OPTS "system/$svc.service" "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
done
|
|
scp $SCP_OPTS system/99-usb-role.rules "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/"
|
|
ssh $SCP_OPTS "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
for svc in usb-role-detect usb-gadget-audio pd-synth-auto pd-synth detect-i2s-device pd-synth-i2s; do \
|
|
sudo mv /tmp/\$svc.service /etc/systemd/system/; \
|
|
done && \
|
|
sudo mv /tmp/99-usb-role.rules /etc/udev/rules.d/ && \
|
|
sudo udevadm control --reload-rules && \
|
|
sudo systemctl daemon-reload"
|
|
|
|
# Enable auto-detect mode (default — works for both gadget and host)
|
|
enable-auto: install-services
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo systemctl disable usb-gadget-audio pd-synth detect-i2s-device pd-synth-i2s 2>/dev/null; \
|
|
sudo systemctl enable usb-role-detect pd-synth-auto && \
|
|
echo '[OK] Auto-detect mode enabled — reboot to apply'"
|
|
|
|
# Enable fixed USB gadget mode (always acts as peripheral)
|
|
enable-gadget: install-services
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo systemctl disable usb-role-detect pd-synth-auto detect-i2s-device pd-synth-i2s 2>/dev/null; \
|
|
sudo systemctl enable usb-gadget-audio pd-synth && \
|
|
echo '[OK] USB gadget mode enabled — reboot to apply'"
|
|
|
|
# Enable fixed I2S DAC mode
|
|
enable-i2s: install-services
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo systemctl disable usb-role-detect pd-synth-auto usb-gadget-audio pd-synth 2>/dev/null; \
|
|
sudo systemctl enable detect-i2s-device pd-synth-i2s && \
|
|
sudo cp /etc/asound-i2s.conf /etc/asound.conf && \
|
|
echo '[OK] I2S DAC mode enabled — reboot to apply'"
|
|
|
|
# Start Pd (auto-detect or whichever service is enabled)
|
|
start:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo systemctl start pd-synth-auto 2>/dev/null || \
|
|
sudo systemctl start pd-synth 2>/dev/null || \
|
|
sudo systemctl start pd-synth-i2s 2>/dev/null || \
|
|
echo '[ERROR] No Pd service found'"
|
|
|
|
# Stop Pd
|
|
stop:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo killall pd 2>/dev/null; echo '[OK] Pd stopped'"
|
|
|
|
# Restart Pd
|
|
restart: stop start
|
|
|
|
# Reboot board
|
|
reboot:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "echo '{{BOARD_PASS}}' | sudo -S reboot"
|
|
|
|
# Run Pd manually in auto-detect mode (for testing)
|
|
run-remote:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
echo "[RUN] Starting Pd on {{BOARD_USER}}@{{BOARD_HOST}} (auto-detect)"
|
|
ssh $SCP_OPTS -t "{{BOARD_USER}}@{{BOARD_HOST}}" "killall pd 2>/dev/null; sudo {{SYSTEM_DIR}}/bin/start-synth.sh --auto --verbose"
|
|
|
|
# Test audio (gadget mode)
|
|
test-audio:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "speaker-test -D hw:UAC1Gadget,0 -c 2 -t sine -f 440 -l 1"
|
|
|
|
# Test audio (host mode — first USB audio interface)
|
|
test-audio-host:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
card=\$(aplay -l 2>/dev/null | grep -i usb | grep -vi gadget | head -1 | awk '{print \$2}' | tr -d ':'); \
|
|
if [ -n \"\$card\" ]; then \
|
|
speaker-test -D hw:\$card,0 -c 2 -t sine -f 440 -l 1; \
|
|
else \
|
|
echo '[ERROR] No USB audio interface found'; \
|
|
fi"
|
|
|
|
# Deploy diagnostic script to board
|
|
deploy-diag:
|
|
@scp {{SSH_OPTS}} scripts/diag.sh "{{BOARD_USER}}@{{BOARD_HOST}}:{{SYSTEM_DIR}}/bin/diag.sh"
|
|
|
|
# Show system status (quick — uses diag.sh on board)
|
|
status:
|
|
@scp {{SSH_OPTS}} -q scripts/diag.sh "{{BOARD_USER}}@{{BOARD_HOST}}:/tmp/diag.sh" && \
|
|
ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "echo '{{BOARD_PASS}}' | sudo -S bash /tmp/diag.sh 2>/dev/null" | head -60
|
|
|
|
# Test MIDI input (list ALSA sequencer ports)
|
|
midi-test:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "aconnect -i -o -l"
|
|
|
|
# Quick deploy and restart cycle
|
|
cycle: deploy-patch
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo killall -s TERM pd 2>/dev/null; sleep 2; echo '[OK] Pd restarted with new patch'"
|
|
|
|
# Tail Pd logs (auto-detect mode)
|
|
log:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
for svc in pd-synth-auto pd-synth pd-synth-i2s; do \
|
|
if systemctl is-active \$svc &>/dev/null; then \
|
|
sudo journalctl -u \$svc -f -n 50; \
|
|
exit 0; \
|
|
fi; \
|
|
done; \
|
|
echo '[ERROR] No Pd service is running'"
|
|
|
|
# Configure USB gadget manually
|
|
init-usb-audio:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "sudo configure-usb-audio.sh start"
|
|
|
|
# Full setup: deploy + enable auto-detect + reboot
|
|
setup: deploy enable-auto
|
|
@echo "[SETUP] Deployed and auto-detect enabled. Run 'just reboot' to start."
|
|
|
|
# ─────────────────────────────────────────────────────────
|
|
# LOCAL TESTING (on your computer)
|
|
# ─────────────────────────────────────────────────────────
|
|
|
|
# Open local plugdata controller + monitor for Uno Q synth
|
|
play-local:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
echo "[PLAY] Opening plugdata controller for Uno Q synth..."
|
|
echo ""
|
|
|
|
if ! command -v plugdata &>/dev/null; then
|
|
echo "[ERROR] plugdata not found"
|
|
exit 1
|
|
fi
|
|
if ! aconnect -l 2>/dev/null | grep -q "Uno Q Audio Synth"; then
|
|
echo "[ERROR] Uno Q not found in ALSA sequencer — is it connected?"
|
|
exit 1
|
|
fi
|
|
|
|
MIDI_PORT=$(aconnect -l 2>/dev/null | grep "Uno Q Audio Synth" | head -1 | awk '{print $2}' | tr -d ':')
|
|
|
|
echo " MIDI port: $MIDI_PORT (Uno Q Audio Synth)"
|
|
echo " Audio in: hw:Synth,0 (UAC1 gadget — synth return)"
|
|
echo " Patch: pd/controller.pd"
|
|
echo ""
|
|
echo " IN PLUGDATA, configure:"
|
|
echo " Settings → Audio → Device Type: ALSA"
|
|
echo " Settings → Audio → Input: hw:Synth,0"
|
|
echo " Settings → Audio → Output: Default"
|
|
echo " Settings → MIDI Input: all — MIDI Output: Uno Q"
|
|
echo " Enable DSP (Ctrl+D)"
|
|
echo ""
|
|
|
|
plugdata pd/controller.pd
|
|
|
|
# Start interactive play session: on-screen keyboard + audio monitor
|
|
play:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
echo "[PLAY] Starting Uno Q synth test environment..."
|
|
echo ""
|
|
|
|
# Install vmpk if missing
|
|
if ! command -v vmpk &>/dev/null; then
|
|
echo "[STEP] Installing vmpk..."
|
|
sudo apt-get install -y -qq vmpk
|
|
fi
|
|
|
|
# Verify Uno Q is connected via ALSA (should be visible through PipeWire)
|
|
if ! aconnect -l 2>/dev/null | grep -q "Uno Q Audio Synth"; then
|
|
echo "[ERROR] Uno Q not found in ALSA sequencer"
|
|
exit 1
|
|
fi
|
|
if ! pw-cli list-objects 2>/dev/null | grep -q "Uno Q Audio Synth"; then
|
|
echo "[ERROR] Uno Q not found via PipeWire"
|
|
[ -z "$(lsusb -d 2341:006a 2>/dev/null)" ] && echo " Device not showing in lsusb either!"
|
|
exit 1
|
|
fi
|
|
|
|
# Start vmpk in background
|
|
echo "[STEP] Starting on-screen keyboard..."
|
|
vmpk &
|
|
VMPK_PID=$!
|
|
sleep 1
|
|
|
|
# Route vmpk MIDI -> Uno Q via ALSA sequencer
|
|
VMPK_PORT=$(aconnect -l 2>/dev/null | grep -B1 "Virtual MIDI Piano" | head -1 | awk '{print $2}' | tr -d ':')
|
|
UNOQ_PORT=$(aconnect -l 2>/dev/null | grep "Uno Q Audio Synth" | head -1 | awk '{print $2}' | tr -d ':')
|
|
if [ -n "$VMPK_PORT" ] && [ -n "$UNOQ_PORT" ]; then
|
|
aconnect "$VMPK_PORT" "$UNOQ_PORT" 2>/dev/null && echo " MIDI: vmpk -> Uno Q Synth"
|
|
else
|
|
echo " [WARN] Auto-connect failed. Use: aconnect \$VMPK_PORT \$UNOQ_PORT"
|
|
fi
|
|
|
|
# Route Uno Q audio -> host speakers via PipeWire
|
|
UNOQ_CAPTURE=$(pw-cli list-objects 2>/dev/null | grep -B1 "alsa_input.*Uno_Q" | grep "node.name" | head -1 | awk -F'"' '{print $2}')
|
|
HOST_OUTPUT="alsa_output.pci-0000_00_1f.3.analog-stereo"
|
|
if [ -n "$UNOQ_CAPTURE" ]; then
|
|
pw-link "$UNOQ_CAPTURE:capture_MONO" "$HOST_OUTPUT:playback_FL" 2>/dev/null && \
|
|
pw-link "$UNOQ_CAPTURE:capture_MONO" "$HOST_OUTPUT:playback_FR" 2>/dev/null && \
|
|
echo " Audio: Uno Q Synth -> host speakers"
|
|
else
|
|
echo " [WARN] Could not find Uno Q audio capture node"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=============================="
|
|
echo " Synth is LIVE!"
|
|
echo " Click keys in the vmpk window"
|
|
echo " Close vmpk or Ctrl+C to stop"
|
|
echo "=============================="
|
|
echo ""
|
|
|
|
wait $VMPK_PID 2>/dev/null
|
|
echo "[STOP] Cleaning up..."
|
|
pw-disconnect "$UNOQ_CAPTURE:capture_MONO" "$HOST_OUTPUT:playback_FL" 2>/dev/null || true
|
|
pw-disconnect "$UNOQ_CAPTURE:capture_MONO" "$HOST_OUTPUT:playback_FR" 2>/dev/null || true
|
|
kill $VMPK_PID 2>/dev/null || true
|
|
aconnect -x 2>/dev/null || true
|
|
echo "[OK] Done"
|
|
|
|
# Stop test session
|
|
stop-play:
|
|
@pw-disconnect "$(pw-cli list-objects 2>/dev/null | grep -B1 "alsa_input.*Uno_Q" | grep "node.name" | head -1 | awk -F'"' '{print $2}'):capture_MONO" "alsa_output.pci-0000_00_1f.3.analog-stereo:playback_FL" 2>/dev/null; \
|
|
pw-disconnect "$(pw-cli list-objects 2>/dev/null | grep -B1 "alsa_input.*Uno_Q" | grep "node.name" | head -1 | awk -F'"' '{print $2}'):capture_MONO" "alsa_output.pci-0000_00_1f.3.analog-stereo:playback_FR" 2>/dev/null; \
|
|
killall vmpk 2>/dev/null; aconnect -x 2>/dev/null; echo "[OK] Stopped"
|
|
|
|
# Show current MIDI routing
|
|
midi-route:
|
|
@echo "=== ALSA MIDI Connections ===" && aconnect -l && echo "" && echo "=== Active connections ===" && aconnect -lio 2>/dev/null | grep -A1 "Connected From\|Connected To" || echo "(none)"
|
|
|
|
# ─────────────────────────────────────────────────────────
|
|
# DIAGNOSTICS
|
|
# ─────────────────────────────────────────────────────────
|
|
|
|
# Full diagnostic dump of the board
|
|
diag:
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
SCP_OPTS="{{SSH_OPTS}}"
|
|
HOST="{{BOARD_USER}}@{{BOARD_HOST}}"
|
|
|
|
echo "=============================="
|
|
echo " Uno Q Audio Synth Diagnostics"
|
|
echo "=============================="
|
|
|
|
# Push and run the diagnostic script on the board
|
|
scp $SCP_OPTS scripts/diag.sh "$HOST:/tmp/diag.sh" >/dev/null
|
|
ssh $SCP_OPTS "$HOST" "echo '{{BOARD_PASS}}' | sudo -S bash /tmp/diag.sh"
|
|
|
|
echo ""
|
|
echo "--- USB bus (host-side) ---"
|
|
if command -v lsusb &>/dev/null; then
|
|
lsusb -d 2341:006a 2>/dev/null | awk '{print " " $0}' || echo " (no Uno Q device on host bus)"
|
|
lsusb -d 2341:006a -t 2>/dev/null | awk '{print " " $0}'
|
|
else
|
|
echo " (lsusb not available on host)"
|
|
fi
|
|
|
|
echo "--- Host ALSA ---"
|
|
echo " Audio:"
|
|
aplay -l 2>/dev/null | grep -i "synth\|uno" | awk '{print " " $0}' || echo " (not found on host)"
|
|
echo " MIDI:"
|
|
aconnect -l 2>/dev/null | grep -i "synth\|uno\|midi" | awk '{print " " $0}' || echo " (not found on host)"
|
|
amidi -l 2>/dev/null | grep -i "synth\|uno" | awk '{print " " $0}' || echo " (not found on host)"
|
|
|
|
echo ""
|
|
echo "=============================="
|
|
echo " Diagnostics Complete"
|
|
echo "=============================="
|
|
|
|
# Show kernel module info for custom modules
|
|
modinfo:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
for m in usb_f_uac1 usb_f_midi; do \
|
|
echo \"=== \$m ===\"; \
|
|
modinfo \$m 2>/dev/null | grep -E 'filename|description|version|parm' | awk '{print \" \" \$0}'; \
|
|
echo ''; \
|
|
done"
|
|
|
|
# Check kernel config for USB gadget features
|
|
kconfig:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
zgrep -E 'CONFIG_USB_(GADGET|CONFIGFS|F_UAC1|F_MIDI|DWC3|F_ACC|F_SERIAL)' /proc/config.gz 2>/dev/null | awk -F= '{printf \" %-45s %s\\n\", \$1, \$2}'"
|
|
|
|
# Validate all .pd files using Conftest/OPA Rego policies
|
|
validate:
|
|
python3 pd-validator/validate.py pd/*.pd
|
|
|
|
# Install udev rules for hotplug role changes
|
|
install-udev-rules:
|
|
@ssh {{SSH_OPTS}} "{{BOARD_USER}}@{{BOARD_HOST}}" "\
|
|
sudo cp /etc/udev/rules.d/99-usb-role.rules /etc/udev/rules.d/99-usb-role.rules.bak 2>/dev/null; \
|
|
sudo cp /tmp/99-usb-role.rules /etc/udev/rules.d/ && \
|
|
sudo udevadm control --reload-rules && \
|
|
echo '[OK] udev rules installed'"
|