docs: research complete

This commit is contained in:
Claude
2026-04-03 12:14:03 +02:00
parent 136a6c877d
commit c3680306ee
5 changed files with 1296 additions and 0 deletions

View File

@@ -0,0 +1,227 @@
# Project Research Summary
**Project:** LED Sync Studio
**Domain:** Terminal-based LED choreography / music-synced light show controller (Raspberry Pi + ESP32)
**Researched:** 2026-04-03
**Confidence:** MEDIUM-HIGH
## Executive Summary
LED Sync Studio is a music-synchronized LED choreography system built around two physical components: a Raspberry Pi running a cyberpunk-themed TUI application (over SSH), and an ESP32-C3 SuperMini executing animation commands on two LED strips (300x SK6812 RGBW and 160x WS2801 RGB). The defining architectural constraint is that the Pi never streams raw pixel frames — it sends only named animation commands with parameters over UDP, and the ESP32 runs animations autonomously. This command-based approach sidesteps the WiFi jitter problem that makes frame-streaming systems unreliable for real-time music sync.
The recommended stack is: Python 3.11 + Textual 8.2.1 for the TUI (asyncio-native, CSS-themeable, SSH-compatible); sounddevice + aubio for audio capture and beat detection; miniaudio for song playback with exact position tracking; JSON-over-UDP as the Pi-to-ESP32 protocol; and PlatformIO + NeoPixelBus (RMT) + ArduinoJson on the ESP32 side. This combination was selected to avoid known failure modes: pygame conflicts with sounddevice, librosa is batch-only not real-time, WebSocket has documented crash bugs on single-core ESP32-C3, and ESPAsyncWebServer was archived in January 2025.
The highest-risk area is the ESP32-C3's single RISC-V core — standard dual-core WiFi/LED isolation advice does not apply, and WiFi interrupts are documented to corrupt RMT timing for SK6812 strips without careful DMA buffer sizing and power-save disabling. Power delivery is a close second: 300 SK6812 + 160 WS2801 LEDs peak at ~27A at 5V and require dedicated supplies per strip with a firmware-enforced brightness cap. Both issues must be validated in hardware before any application-layer development begins.
---
## Key Findings
### Recommended Stack
The Pi-side application is pure Python with minimal dependencies: Textual handles the full TUI without threading complexity (asyncio-native), sounddevice captures system audio via PipeWire's PulseAudio compatibility layer, aubio processes audio frames in C with ~11ms latency at 512-sample hop size, and miniaudio decodes and plays song files with sample-accurate position tracking (avoiding the pygame/sounddevice device conflict). Pydantic v2 validates choreography JSON files with zero-cost schema generation.
On the ESP32, PlatformIO with the Arduino framework provides reproducible builds. NeoPixelBus uses the RMT peripheral (hardware-timed, DMA-driven) for SK6812 RGBW output. WS2801 uses hardware SPI directly from Arduino's `SPI.h`. ArduinoJson v7 parses command payloads in under 1ms. AsyncUDP (built into arduino-esp32 core) receives commands without the stability issues of the archived ESPAsyncWebServer.
**Core technologies:**
- Python 3.11 + Textual 8.2.1: TUI runtime — asyncio-native, CSS-themeable, runs cleanly over SSH
- sounddevice 0.5.x: System audio capture — PipeWire-compatible, asyncio callback support, no ALSA header build issues
- aubio 0.4.9: Beat/onset detection — C-backed, streaming/causal design, 11ms per-frame latency
- miniaudio: Song playback — sample-accurate position, no SDL, no device conflict with sounddevice
- UDP + stdlib json: Pi-to-ESP32 transport — fire-and-forget, 1-5ms local WiFi latency
- NeoPixelBus 2.8.x (RMT): SK6812 output — hardware-timed via DMA, interrupt-safe
- ArduinoJson 7.4.x: ESP32 JSON parsing — heap-elastic documents, sub-1ms for command payloads
- PlatformIO: ESP32 build system — dependency lockfiles, CLI, OTA support
- Pydantic v2: Choreography file validation — Rust-backed, auto JSON schema
### Expected Features
The feature landscape is informed by xLights (timeline sequencer), WLED (ESP32 preset/segment model), LedFx (live reactive audio engine), and Jinx! (beat detection baseline). Choreography-mode features are the higher-value deliverable; live reactive mode is secondary but expected by users familiar with WLED/LedFx.
**Must have (table stakes):**
- Audio waveform display on timeline — blind timing without it; every sequencer has this
- Play / pause / seek transport — fundamental, must work with live LED preview
- Per-zone independent control (WS2801 + SK6812 as named zones)
- Block-based timeline editor — drag/place/resize animation blocks on a horizontal track
- Animation library (8-12 built-in effects: chase, pulse, rainbow, strobe, color wash)
- Per-animation parameter configuration (speed, color, intensity per block)
- Save / load choreography files (JSON)
- Live reactive mode (system audio capture + beat detection → animation trigger)
- Playback position cursor (playhead)
- Loop / repeat per block
- Manual timing mark placement (tapper: press key on beat to stamp marks)
**Should have (competitive differentiators):**
- Cyberpunk TUI aesthetics over SSH — no equivalent exists in LED sequencer space
- Dual-mode in one tool (timeline + live reactive without restart)
- Zone-aware beat-reactive routing (bass → Zone A, treble → Zone B)
- Auto-beat detection timing marks (aubio stamps marks automatically, user refines)
- Undo / redo (painful without it; all quality DAWs have it)
- Per-block transition effects (crossfade, cut, dissolve)
- Animation preview in-terminal (ASCII block-character LED simulation)
**Defer (v2+):**
- Spotify integration — complex auth, unclear system-level audio loopback is simpler
- xLights .xsq import/export — complex format, unclear demand
- Scripted effect DSL (Jinx!Script-style) — advanced power-user feature
### Architecture Approach
The system divides cleanly into Pi (all intelligence) and ESP32 (dumb executor). The Pi runs an asyncio event loop anchored by Textual; audio processing runs in a thread with a `call_soon_threadsafe` bridge into the async loop; the playback clock is an asyncio task that fires choreography events using absolute `time.monotonic()` timestamps (not relative sleep chains); the UDP transport is a non-blocking asyncio DatagramProtocol. The ESP32 runs three FreeRTOS tasks: high-priority LED output, medium-priority WiFi/JSON receive, and low-priority animation tick at 50fps posting frame buffers to a queue.
**Major components:**
1. TUI Layer (Textual) — renders all views, accepts keystrokes, subscribes to reactive state from App Core
2. App Core — asyncio state machine: playback clock, choreography scheduler, event dispatch
3. Audio Layer — song playback (miniaudio) + beat detection (sounddevice + aubio), thread-isolated
4. Transport — async UDP socket, JSON serialization, heartbeat, connection health
5. Choreography Engine — load/save JSON files, event sequence management
6. ESP32 Animation Engine — effect registry, parameter system, zone routing, FreeRTOS task structure
7. ESP32 LED Drivers — NeoPixelBus RMT for SK6812, hardware SPI for WS2801
### Critical Pitfalls
1. **WiFi interrupts corrupt SK6812 RMT timing on single-core ESP32-C3** — Enable DMA with full-frame buffer size, disable WiFi power saving (`WIFI_PS_NONE`), test WiFi+LED simultaneously on day 1 of firmware work. This is actively documented in FastLED #1657 (February 2026).
2. **Choreography timeline drift over long songs** — Never use relative sleep chains. Record `start_wall_time = time.monotonic()` at play, compute `fire_at = start_wall_time + event.timestamp`, recalculate remaining sleep each iteration. Validate drift stays under 20ms/minute at 60s and 120s.
3. **SK6812 is RGBW (4 bytes/LED), not RGB** — Explicit 4-byte configuration in firmware before any animation code. Include white channel in JSON protocol from day one; adding it later requires a protocol version bump.
4. **Power budget: 300 SK6812 + 160 WS2801 = ~27A peak at 5V** — Dedicated 5V supply per strip (not from ESP32 VIN/USB), firmware-enforced brightness cap at 40%, 1000µF capacitor at each strip input. Brown-out resets mid-performance otherwise.
5. **Audio thread safety with Textual** — Audio callbacks are OS-thread-level; never call Textual widget methods from audio thread. Use `self.app.call_from_thread()` or a `queue.Queue` polled by an asyncio task.
---
## Implications for Roadmap
Based on the dependency graph in FEATURES.md and build order in ARCHITECTURE.md, six phases are recommended. Hardware must be validated first because every other component is validated against a real ESP32.
### Phase 1: Hardware Foundation + ESP32 Firmware
**Rationale:** The ESP32 is the validation target for all subsequent work. Developing the Pi app against a mock ESP32 risks discovering protocol mismatches only after building everything. Ship firmware first, test with netcat/curl, then build the Pi app around proven commands.
**Delivers:** Working LED hardware: both strips driving correctly with WiFi receiving JSON commands. All hardware risks retired.
**Addresses:** Per-zone control model, animation library (8-12 effects), JSON command protocol
**Avoids:**
- Pitfall 1 (WiFi+RMT coexistence): test simultaneously on day 1
- Pitfall 2 (WS2801 SPI signal integrity): set clock to 1MHz with series resistors before firmware
- Pitfall 7 (SK6812 RGBW 4-byte framing): configure explicitly before animation code
- Pitfall 8 (power budget): dedicated supplies before first flash
- Pitfall 12 (flash size): check binary size before adding many animation effects
**Research flag:** Needs phase research — ESP32-C3 RMT+WiFi coexistence has conflicting documentation; GPIO pin assignment for simultaneous RMT+SPI needs hardware validation.
### Phase 2: Transport + App Core (Headless)
**Rationale:** A testable Pi-side core without TUI allows validating the protocol and choreography engine against real hardware before the UI complexity is introduced. CLI-testable with simple scripts.
**Delivers:** UDP transport client, JSON command builder, heartbeat, choreography data model (Pydantic), playback clock with absolute timestamp scheduling, event scheduler.
**Addresses:** Save/load choreography files, per-zone command routing, protocol versioning
**Avoids:**
- Pitfall 3 (timeline drift): implement absolute monotonic timestamp scheduling from the start
- Pitfall 4 (WiFi jitter): UDP with `WIFI_PS_NONE`, small payloads, timestamp in payload
- Pitfall 9 (JSON protocol versioning): `protocol_version` field in first command
**Research flag:** Standard patterns — asyncio UDP client and Pydantic data models are well-documented.
### Phase 3: Audio Layer
**Rationale:** Beat detection and song playback have no UI dependency. Prototype as standalone scripts, then integrate. This keeps the complex audio threading isolated before TUI is introduced.
**Delivers:** Song playback (MP3/FLAC/WAV via miniaudio with position tracking), system audio capture (sounddevice), beat/onset detection (aubio), thread-safe event bridge to asyncio.
**Addresses:** Audio waveform data source, beat events for live reactive mode, playback position for choreography clock
**Avoids:**
- Pitfall 6 (Textual thread safety): design the `call_from_thread` bridge before TUI exists
- Pitfall 10 (beat detection false positives): moving energy average + sub-bass focus + sensitivity params
**Research flag:** Needs phase research — aubio 0.4.9 ARM pip wheel availability on Raspberry Pi OS bookworm is unverified; sounddevice + miniaudio simultaneous PipeWire device access needs early testing.
### Phase 4: TUI Layer
**Rationale:** App Core and Audio Layer must have stable APIs before the TUI is built on top of them. The timeline view is the most complex widget — build transport controls and event list first.
**Delivers:** Full Textual application: Header, TransportBar, TimelineView (TimeRuler + ZoneTrack x2), EventListView, AnimationPanel sidebar, StatusBar. Cyberpunk visual theme.
**Addresses:** Audio waveform display, block-based timeline editor, playback cursor, animation parameter configuration panel, manual timing mark (tapper)
**Avoids:**
- Pitfall 6 (Textual thread safety): use established audio bridge from Phase 3
- Pitfall 11 (SSH rendering throughput): set `REFRESH_RATE = 30` from the start; do not default to Textual maximum
- Anti-pattern: polling playback position from TUI (App Core owns authoritative state)
**Research flag:** Standard patterns — Textual docs are comprehensive for reactive widgets and worker threads.
### Phase 5: Live Reactive Mode
**Rationale:** Depends on both the Audio Layer (beat events) and the TUI (mode switching). Both must be complete first. This is the "second major mode" that users familiar with WLED/LedFx expect.
**Delivers:** System audio capture → beat detection → animation dispatch pipeline. Zone-aware routing (bass → Zone A, treble → Zone B). Mode toggle in TUI without restart. Calibration UI for sensitivity.
**Addresses:** Live reactive mode, zone-aware beat-reactive routing
**Avoids:**
- Pitfall 10 (beat detection false positives): expose sensitivity and frequency band in calibration UI
- Pitfall 4 (WiFi jitter): design animations with ±20ms tolerance (quick fades mask arrival variance)
**Research flag:** Standard patterns — LedFx architecture and WLED audio-reactive docs provide clear precedent.
### Phase 6: Polish + Editor Completeness
**Rationale:** Quality-of-life features that make the tool pleasant to use long-term, not required for core function.
**Delivers:** Undo/redo, loop/repeat per block, per-block transition effects, auto-beat detection timing marks (aubio stamps on analysis, user refines), choreography file browser.
**Addresses:** Undo/redo, loop/repeat, transitions, auto-beat marks
**Research flag:** Standard patterns — undo/redo command stack is well-documented; aubio batch analysis for timing mark generation uses same library already integrated.
### Phase Ordering Rationale
- Hardware first because every other component validates against real ESP32 behavior, not a mock
- Transport + App Core second because the CLI-testable layer validates the protocol before UI complexity
- Audio Layer third because it has no UI dependency and threading design must precede TUI integration
- TUI fourth because it depends on stable App Core and Audio Layer APIs
- Live Reactive fifth because it requires both Audio Layer and TUI to be complete
- Polish last because it adds no new system capability, only ergonomics
The groupings follow the architectural component boundaries in ARCHITECTURE.md: firmware → headless Pi core → audio → UI → integration → refinement. This order ensures each phase has a working validation target from the phase before it.
### Research Flags
Phases needing deeper research during planning:
- **Phase 1 (ESP32 Firmware):** ESP32-C3 RMT+WiFi coexistence has conflicting community reports; GPIO pin mapping for simultaneous RMT (SK6812) + SPI (WS2801) on the specific SuperMini board needs hardware validation. Firmware size budget vs. animation library scope needs early sizing.
- **Phase 3 (Audio Layer):** aubio 0.4.9 ARM pip wheel on Raspberry Pi OS bookworm — may need to build from source. Simultaneous sounddevice + miniaudio access to PipeWire — needs early testing before building the full layer.
Phases with standard patterns (skip research-phase):
- **Phase 2 (Transport + App Core):** asyncio UDP, Pydantic data models, JSON choreography format — all well-documented with abundant examples.
- **Phase 4 (TUI Layer):** Textual has comprehensive official documentation; reactive widget patterns and worker thread safety are explicitly covered.
- **Phase 5 (Live Reactive):** LedFx architecture and WLED audio-reactive docs provide clear, tested precedent for the audio-to-LED pipeline.
- **Phase 6 (Polish):** Standard patterns for undo/redo (command stack) and loop control.
---
## Confidence Assessment
| Area | Confidence | Notes |
|------|------------|-------|
| Stack | MEDIUM-HIGH | Core choices verified against official docs and GitHub releases. Two gaps: aubio ARM pip wheel availability, sounddevice + miniaudio PipeWire simultaneous access. |
| Features | MEDIUM | Informed by xLights/WLED/LedFx analysis; this is a novel TUI product so user expectations are partially inferred. Table stakes list is solid; differentiator value is harder to confirm without users. |
| Architecture | HIGH | Component boundaries and data flow patterns are well-established. Event-driven async core with thread-isolated audio is the correct pattern; WLED validates UDP command architecture at scale. |
| Pitfalls | HIGH | Most pitfalls are actively documented in ESP32 issue trackers with recent activity (February 2026). The RMT+WiFi coexistence issue is particularly well-evidenced across multiple library ecosystems. |
**Overall confidence:** MEDIUM-HIGH
### Gaps to Address
- **aubio ARM wheel:** Test `pip install aubio` on actual Raspberry Pi hardware before Phase 3 begins. If it fails, build from source (documented procedure exists, adds ~30min to setup).
- **Simultaneous PipeWire device access:** sounddevice (capture) + miniaudio (playback) both accessing PipeWire's default sink. Test early in Phase 3 — multiple readers on a PipeWire loopback monitor source should work but is not officially documented for this combination.
- **GPIO pin assignment:** ESP32-C3 SuperMini has limited broken-out pins. Exact RMT GPIO + SPI GPIO combination for simultaneous operation needs hands-on hardware validation in Phase 1.
- **WiFi latency floor:** Measured RTT on actual home network environment may exceed the 10-30ms estimate. If 95th-percentile one-way latency exceeds 50ms, the timestamp-in-payload approach (Phase 2) becomes mandatory rather than optional.
- **Animation library scope vs. flash budget:** ESP32-C3 SuperMini has ~1.25MB usable firmware space. Scope the animation library (targeted 8-12 effects) against actual compiled firmware size early in Phase 1.
---
## Sources
### Primary (HIGH confidence)
- https://github.com/Textualize/textual/releases — Textual 8.2.1 confirmed latest stable
- https://aubio.org/doc/ — aubio causal/streaming design confirmed
- https://components.espressif.com/components/bblanchon/arduinojson/versions/7.4.2 — ArduinoJson 7.4.x confirmed
- https://docs.platformio.org/en/latest/boards/espressif32/esp32-c3-devkitm-1.html — PlatformIO ESP32-C3 support
- https://kno.wled.ge/ — WLED protocol architecture (industry reference for ESP32 LED control)
- https://textual.textualize.io/guide/workers/ — Textual thread safety patterns
- https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf — ESP32-C3 hardware specs
### Secondary (MEDIUM confidence)
- https://github.com/FastLED/FastLED/issues/1657 — ESP32-C3 RMT flicker with WiFi (February 2026)
- https://esp32.com/viewtopic.php?t=41170 — RMT transaction corrupted by WiFi interrupts
- https://python-sounddevice.readthedocs.io/ — sounddevice docs (PipeWire PulseAudio compat layer not explicitly documented)
- https://github.com/irmen/pyminiaudio — miniaudio position tracking confirmed
- https://docs.ledfx.app/en/latest/ — LedFx reactive architecture reference
- https://manual.xlights.org/xlights/ — xLights feature baseline
- https://www.espboards.dev/esp32/esp32-c3-super-mini/ — ESP32-C3 SuperMini pinout and flash specs
### Tertiary (LOW confidence — community sources)
- https://www.oreateai.com/blog/diy-wifi-light-shows-syncing-your-leds-without-breaking-the-bank — WiFi jitter figures (~12ms variance on ESP32)
- https://deepwiki.com/LedFx/LedFx — LedFx architecture (DeepWiki auto-generated, verify critical claims)
---
*Research completed: 2026-04-03*
*Ready for roadmap: yes*