david 86facfea38
Validate and Test / validate-patches (push) Failing after 12s
clean: remove debug logging, final viz cleanup
2026-06-24 05:14:33 -07:00

Arduino Uno Q — USB Audio Synth

A 2-oscillator subtractive synthesizer running Pure Data on the Arduino Uno Q. Auto-detects its USB role at boot and works in three modes — no config switching needed.

Modes

Mode Connection Audio Out MIDI In Use Case
Gadget USB-C → Host computer UAC1 gadget (virtual sound card) gmidi gadget (over same cable) Plug-and-play with DAWs
Host USB hub → MIDI controller + USB audio interface USB audio interface (your interface) MIDI controller via hub Standalone jamming
I2S DAC I2S DAC on GPIO pins (e.g. PCM5102) Analog line out via DAC USB MIDI controller (gadget) Embedded installs

Auto-Detection

At boot, detect-usb-role.sh probes the USB controller to determine the role:

USB cable plugged into Host?  ─→ gadget mode (UAC1 + gmidi)
USB device plugged into Uno?  ─→ host mode (drives USB audio interface + MIDI)
Neither?                       ─→ defaults to gadget (safe fallback)

A udev rule (99-usb-role.rules) re-runs detection on hotplug events and restarts Pd with the new config — unplug from computer and plug into a hub, it just works.

Architecture

┌─────────────────────────────────────────────────────────┐
│                    GADGET MODE                          │
│  [Host DAW] ←USB-C→ ┌──────────┐                       │
│                      │ gmidi    │←─ ALSA seq ──→ Pd     │
│                      │ UAC1     │── ALSA pcm ──→ Pd     │
│                      └──────────┘                       │
├─────────────────────────────────────────────────────────┤
│                    HOST MODE                             │
│  [MIDI Ctrl] ─┐                                          │
│  [USB Audio] ─┼─USB hub─→ ┌──────────┐                  │
│               │            │ USB host │                  │
│               └──────────→ │ driver   │──→ Pd            │
│                            └──────────┘                  │
├─────────────────────────────────────────────────────────┤
│                    I2S DAC MODE                          │
│  [PCM5102] ←GPIO(I2S)→ ALSA I2S driver ──→ Pd           │
└─────────────────────────────────────────────────────────┘

Project Structure

uno-q-audio-synth/
├── pd/
│   └── synth.pd                     # Pure Data synthesizer patch
├── system/
│   ├── configure-usb-audio.sh       # UAC1 + gmidi gadget setup
│   ├── configure-usb-host.sh        # Host-mode USB audio discovery
│   ├── detect-usb-role.sh           # Boot-time USB role detection
│   ├── detect-i2s-device.sh         # I2S device auto-detection
│   ├── on-usb-role-change.sh        # udev hotplug handler
│   ├── asound.conf                  # ALSA config (gadget mode)
│   ├── asound-i2s.conf              # ALSA config (I2S DAC mode)
│   ├── 99-usb-role.rules            # udev rules for hotplug
│   ├── usb-role-detect.service      # Early-boot role detection
│   ├── usb-gadget-audio.service     # Gadget-only service
│   ├── pd-synth-auto.service        # Unified auto-detect service
│   ├── pd-synth.service             # Gadget-only Pd service
│   ├── pd-synth-i2s.service         # I2S-only Pd service
│   └── detect-i2s-device.service    # I2S probe service
├── scripts/
│   └── start-synth.sh               # Manual dev startup (all modes)
├── install.sh                       # Board-side dependency install
├── justfile                         # Task runner
└── mise.toml                        # Tool version management

Quick Start

Deploy to board

export BOARD_HOST=uno-q.local   # or IP if mDNS not working

just deploy                      # copy all files
just enable-auto                 # enable auto-detect mode
just reboot                      # apply

Once booted, plug into a computer — it appears as "Uno Q Audio Synth" with audio sink + MIDI port. Or plug a USB hub with MIDI controller + audio interface for standalone play.

Development cycle

just cycle    # deploy patch + restart Pd
just log      # tail Pd logs
just status   # role, ALSA cards, MIDI ports

Manual testing

just test-audio              # test gadget audio out
just test-audio-host         # test host-mode USB audio interface
just run-remote              # run Pd in foreground with auto-detect

I2S DAC Wiring

Add a DAC later without reconfiguring. Common I2S DAC modules:

DAC Pins Voltage
PCM5102 BCK, DIN, LCK, 5V, GND 3.3V5V
MAX98357 (speaker amp) BCLK, DIN, LRCLK, Vin, GND 2.7V5.5V
PCM5242 (balanced out) I2S + I2C config 3.3V

Typical PCM5102 wiring to Uno Q GPIO:

PCM5102  →  Uno Q GPIO
VIN      →  5V
GND      →  GND
BCK      →  I2S_BCK (GPIO pin — check board docs)
DIN      →  I2S_DIN
LCK      →  I2S_LCK

Activate I2S mode: just enable-i2s && just reboot

Controls (MIDI)

Control Mapping
MIDI Note On/Off Play notes
Velocity Volume
CC 74 Filter cutoff
GUI sliders (Pd) Detune, volume, ADSR

Requirements (on the Uno Q)

  • Pure Data (apt install puredata)
  • ALSA utilities (apt install alsa-utils)
  • Linux kernel with UAC + gmidi gadget support (Qualcomm DragonWing)

Pd Patch: synth.pd

  • OSC 1: Saw wave, direct pitch
  • OSC 2: Saw wave, detunable (±50 cents)
  • Mix: Balanced stereo mix
  • Filter: Low-pass (lop~) with adjustable cutoff
  • Envelope: env~ (attack, decay, sustain, release)
  • Output: Stereo 48kHz 16-bit via dac~

Open in Pd GUI to adjust slider positions and save.

S
Description
Arduino Uno Q USB Audio Synth
Readme 464 KiB
Languages
Python 43.9%
Shell 24.5%
Just 14.4%
HTML 8.3%
Open Policy Agent 6.5%
Other 2.4%