Files
uno-q-audio-synth/README.md
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

158 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
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
```bash
just cycle # deploy patch + restart Pd
just log # tail Pd logs
just status # role, ALSA cards, MIDI ports
```
### Manual testing
```bash
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.