File size: 11,841 Bytes
b2e4883 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | # 02 β Architecture
## System overview
PatternTalk is two services plus a shared data layer.
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Next.js Web App (TypeScript) β β
β β ββ Voice UI (Web Speech API: STT + TTS) β β
β β ββ Prompt parser β β
β β ββ Pattern engine (loads templates) β β
β β ββ MIDI generator (@tonejs/midi) β β
β β ββ Audio context analyzer (Meyda/Essentia.js) β β
β β ββ Reaper Web Control client β β
β β ββ Visual grid (optional, layered on top) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββ¬βββββββββββββββββββββββββββββββββββ¬ββββββββββββββββ
β HTTP β WebSocket
βΌ βΌ
ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββ
β Audio Service β β Reaper (user's machine) β
β (Python, FastAPI) β β Web Control surface β
β ββ SA3 inference β β + ReaScript bridge β
β ββ LoRA loader β ββββββββββββββββββββββββββββββ
β ββ Sample generator β
ββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β Stable Audio 3 weights (local FS) β
β + Brutal-drum LoRA adapter β
ββββββββββββββββββββββββββββββββββββββββ
```
## Services
### 1. Web app (`apps/web`)
**Stack:** Next.js 14+ (App Router), TypeScript, Tailwind CSS, Radix UI primitives, @tonejs/midi, Meyda.
**Responsibilities:**
- Render the voice-first UI
- Capture microphone input β text via Web Speech API (`SpeechRecognition`)
- Speak responses via `SpeechSynthesis`
- Parse prompts β structured requests (see [`docs/03-data-model.md`](03-data-model.md))
- Load pattern templates, generate MIDI in-browser
- Optional: analyze uploaded audio for BPM (Meyda/Essentia.js)
- Talk to Reaper via Web Control (when available)
- Talk to audio service for sample generation
**State management:** Zustand or React state. Avoid Redux. State is small.
**Why Next.js:**
- Server components let us split render work from interactive shell
- Easy deploy to Vercel
- TS support is first-class
- Accessibility ecosystem (react-aria, Radix) is mature
### 2. Audio service (`services/audio`)
**Stack:** Python 3.10+, FastAPI, PyTorch 2.x, diffusers/transformers for SA3.
**Responsibilities:**
- Load Stable Audio 3 weights (base model)
- Load LoRA adapter (brutal-drums)
- Run inference on prompts β audio buffers
- Stream or return audio as WAV
- Cache generated samples (LRU + disk-backed)
**Why separate service:**
- Python ML ecosystem is non-negotiable for SA3
- Decoupling lets us run on different machines (Vega for dev, cloud GPU for demo)
- Browser can't run SA3 inference efficiently
- Service can be scaled or replaced without touching the web app
### 3. Reaper integration (in user's DAW)
**Stack:** Reaper Web Control surface (built-in HTTP server) + optional ReaScript.
**Responsibilities:**
- Expose project tempo (BPM), time signature, play state
- Accept MIDI files dropped onto tracks
**Why this is not a "service":**
- Reaper runs on the user's machine
- PatternTalk is a client to its Web Control API
- No persistent server-side integration needed
## Data flow
### Happy path: voice prompt β MIDI + sample
```
User voice: "tupatupatupa on the hihat, 4 bars"
β
βΌ
[Web Speech API] ββtextβββΆ "tupatupatupa on the hihat, 4 bars"
β
βΌ
[Onomatopoeia matcher] βββΆ { onomatopoeia: "tupatupatupa", mappedTo: "skank-beat" }
β
βΌ
[Prompt parser] βββΆ {
β pattern: "skank-beat",
β bars: 4,
β tempo: null, // not specified
β timeSignature: "4/4", // default
β cymbalHint: "hi-hat upstrokes"
β }
βΌ
[Tempo resolver] βββΆ tempo: 174
β (priority: explicit in prompt > Reaper project BPM > uploaded audio BPM > 120 default)
βΌ
[Pattern engine] βββΆ MIDI events[] (loaded from skank-beat template, expanded to 4 bars at 174 BPM)
β
βΌ
[MIDI generator] βββΆ .mid file (Blob in browser)
β
βββΆ [Download to user]
β
βββΆ [Audio service request]
POST /generate-sample
{ prompt: "skank beat, hi-hat upstrokes, brutal drums", duration: 8 }
β
βΌ
[SA3 + LoRA inference] βββΆ audio buffer
β
βΌ
[Response] βββΆ .wav file (Blob in browser)
β
βββΆ [Download to user]
```
### Voice response flow
After generation, PatternTalk speaks back:
```
"Skank beat, hi-hat upstrokes on the upbeats, 4 bars at 174 BPM.
MIDI ready. Sample ready. Say 'play' to preview, 'regenerate' to try again,
or 'download' to save the MIDI."
```
### Reaper sync flow
```
Web app mounts β checks for Reaper Web Control at localhost:8080
β
ββ present β fetch /_/project/tempo β use as tempo default
β
ββ absent β use uploaded audio BPM or 120 default
```
## Folder structure
```
patterntalk/
βββ apps/
β βββ web/ # Next.js app
β βββ app/ # App Router pages
β β βββ page.tsx # Main voice UI
β β βββ library/ # Pattern library
β β βββ layout.tsx
β βββ components/
β β βββ voice/ # Voice UI primitives
β β βββ grid/ # Visual grid (optional)
β β βββ ui/ # Radix wrappers
β βββ lib/
β β βββ parser/ # Prompt + onomatopoeia parser
β β βββ patterns/ # Pattern engine + template loader
β β βββ midi/ # MIDI generation (@tonejs/midi)
β β βββ audio/ # Web Audio, Meyda analyzer
β β βββ reaper/ # Reaper Web Control client
β βββ data/
β β βββ patterns/ # JSON pattern templates
β β βββ onomatopoeia.json # Onomatopoeia mapping table
β βββ public/
β βββ package.json
βββ services/
β βββ audio/ # FastAPI service
β βββ sa3/ # SA3 wrapper
β β βββ inference.py
β β βββ lora.py
β β βββ server.py
β βββ training/ # LoRA fine-tuning scripts
β β βββ train_lora.py
β βββ models/ # SA3 base weights (gitignored)
β βββ loras/ # Trained LoRA adapters
β βββ cache/ # Generated sample cache
β βββ requirements.txt
βββ data/
β βββ training/ # Brutal drum samples for LoRA
β βββ oneshots/ # Kick, snare, china, etc.
β βββ loops/ # Short brutal loops
β βββ manifest.yaml # Training data manifest
βββ docs/ # This directory
βββ scripts/
β βββ reaper/ # ReaScript helpers
β βββ verify/ # Accessibility + smoke tests
βββ .github/
β βββ workflows/ # CI (axe-core, lint, build)
βββ package.json # Workspace root
βββ README.md
```
## Why monorepo
- Single repo for web + audio service + training data
- Shared types between TS and Python (via JSON Schema + codegen, or just hand-written TS interfaces mirrored in Pydantic)
- Single CI pipeline
- Easier to ship as one artifact at the demo
**Tooling:** pnpm workspaces + a simple Python venv per service. Avoid Turborepo/Nx overhead for a 2-day project.
## Deployment
| Component | Target |
|---|---|
| Web app | Vercel (free tier) |
| Audio service | RunPod / Vast.ai during hackathon, optional Fly.io / Modal for inference |
| Models + LoRA weights | HuggingFace Hub (public, for the LoRA at least) |
| Training data | Small dataset, commit directly to repo or HuggingFace dataset |
## Key technical decisions
### Decision 1: Voice-first, not visual-first
The voice UI is the primary surface. The visual grid is optional and layered.
**Rationale:** Differentiates from every other drum plugin, hits the accessibility theme head-on, and matches how drummers actually think.
### Decision 2: Pattern engine decoupled from audio engine
The pattern (MIDI events) is hand-coded from templates. The audio (samples) is generated by SA3.
**Rationale:** Your domain expertise lives in the patterns. SA3's strength is sample quality. Don't conflate them. Each can be evaluated independently.
### Decision 3: Cloud GPU for inference during demo
Vega 56 can run SA3 small but slowly. Use cloud for demo-day inference to guarantee snappy response.
**Rationale:** Live inference during a 3-minute demo is high-risk if hardware is slow. A $20 cloud spend buys reliability.
### Decision 4: Open weights and open code
MIT code, public LoRA weights, public training manifest.
**Rationale:** Stability challenge explicitly rewards "open development." Showing the weights and training data is itself part of the demo.
### Decision 5: Reaper-first DAW integration
Web Control surface + MIDI export, not a full VST/CLAP.
**Rationale:** Web Control + drag-MIDI is 80% of the value at 20% of the work. CLAP wrap is stretch.
## What this architecture doesn't do
- No multi-user real-time collaboration (out of scope for 2 days)
- No pattern saving to cloud accounts (localStorage only for now)
- No mobile-first UI (desktop browser is the target)
- No offline mode (Vega inference can run offline, but the demo assumes network for cloud inference)
- No AU plugin format (Mac pain, not worth it for the demo)
## Open architectural questions
1. **Where does the pattern library live?** Browser-only (static JSON) vs. served from the audio service? *Lean: browser-only, simpler.*
2. **Should variations be pre-generated or on-demand?** Pre-generated is faster demo, on-demand is more impressive. *Lean: pre-generate for safety, on-demand as a "show your work" feature.*
3. **Real-time WebSocket for inference progress, or just polling?** WebSocket is nicer UX, polling is simpler. *Lean: WebSocket if time, polling if not.*
|