diff --git a/gui.md b/gui.md new file mode 100644 index 0000000..50d39cd --- /dev/null +++ b/gui.md @@ -0,0 +1,121 @@ +# GUI Architecture + +This document defines the high-level architectural decisions for the real-time display system. +The display must provide smooth visual feedback for metronome position, column progress, and track states +while maintaining responsive updates from OSC messages without blocking the rendering thread. + +## Overview + +The GUI architecture uses two threads to maintain responsive visual updates. +The OSC receiver thread handles incoming state messages from the audio engine and updates shared state. +The GUI thread runs the egui rendering loop and interpolates time-based animations independently. + +These subsystems communicate through Tokio watch channels for efficient state synchronization. +The audio engine acts as an OSC server, with the display connecting as a client and automatically reconnecting on failures. + +```mermaid +graph LR + AudioEngine[Audio Engine
OSC Server
Unix Socket] + OSCThread[OSC Receiver Thread
tokio + rosc
State Updates] + GUIThread[GUI Thread
egui Rendering
Animation Interpolation] + + AudioEngine -->|OSC Messages| OSCThread + OSCThread -->|Watch Channel| GUIThread + + subgraph "Display Process" + OSCThread + GUIThread + end +``` + +The system receives state updates through standardized OSC messages and renders them using a hierarchical state structure. +Time-critical animations like metronome movement and progress bars use local interpolation to maintain smooth 60fps updates +independent of the OSC message frequency. + +## Technology Stack + +The display uses egui as the immediate mode GUI framework, +providing excellent performance for real-time updates and straightforward integration with Rust's async ecosystem. + +**Core Libraries:** +- **egui**: Immediate mode GUI framework for rendering +- **tokio**: Async runtime for OSC message handling +- **rosc**: OSC message parsing and Unix socket communication +- **tokio::sync::watch**: Lock-free state sharing between threads + +## Threading Architecture + +### OSC Receiver Thread +The OSC receiver thread manages the Unix socket connection to the audio engine and processes incoming state messages. +This thread runs a tokio async loop that handles connection establishment, message parsing, and state updates. + +### GUI Thread +The GUI thread owns the egui context and handles all rendering operations. +This thread polls the watch channel receiver for state changes and triggers repaints when updates arrive. +Time interpolation for smooth animations happens during the render loop using stored timestamps and elapsed time calculations. + +## State Management + +### Hierarchical State Structure +The display state mirrors the audio engine's organization to maintain consistency and simplify message parsing. + +``` +DisplayState +├── global +│ ├── mode: OperationMode (Menu | Performance) +│ ├── tempo: f32 (BPM) +│ ├── selected_cell: (usize, usize) +│ ├── click_enabled: bool +│ ├── click_volume: f32 +│ └── master_volume: f32 +├── columns: [ColumnState; 5] +│ ├── beats: usize (Total beats, 0 = not set) +│ ├── current_beat: usize (1-based position) +│ └── tracks: [TrackState; 5] +│ ├── state: TrackDisplayState (Empty | Ready | Recording | Playing | Solo) +│ └── volume: f32 +└── metronome + ├── position: f32 (0.0-1.0 within current beat) + └── timestamp: Instant (When received) +``` + +### State Updates +The OSC receiver thread modifies the state directly based on incoming messages and sends the complete updated state through the watch channel. +This approach ensures atomic updates and eliminates complex synchronization logic. + +## OSC Message Processing + +### Message Parsing Flow +Incoming OSC messages map directly to state field updates using a straightforward parsing pipeline. +Initial connection triggers a complete state dump from the audio engine using the same message format as regular updates. + +### Time-Sensitive Messages +Metronome position messages include timestamp capture to enable smooth interpolation in the GUI thread. +This allows the display to show fluid metronome movement despite receiving position updates at MIDI PPQN rate rather than display refresh rate. + +## Time Interpolation Strategy + +### Metronome Animation +The metronome requires smooth movement between received position updates to maintain visual continuity. +Time interpolation happens during the render loop by calculating elapsed time since the last position update and advancing the visual position accordingly. +This maintains frame-rate independence and ensures smooth animations regardless of system load. + +### Column Progress Animation +Column progress bars use similar interpolation to show smooth advancement between beat boundaries. +The current beat position provides the discrete timing reference, with interpolation filling the gaps for fluid visual feedback. + +## Connection Management + +### Client Connection Pattern +The display connects to the audio engine's Unix socket server and handles connection lifecycle automatically. +Connection failures trigger retry attempts to avoid overwhelming the system during startup sequences. + +### Error States and Recovery +The GUI displays connection status to provide user feedback during system startup or audio engine restarts. +Connection recovery happens transparently in the background, with the GUI resuming normal operation once the OSC stream resumes. + +## Process Lifecycle + +The display process operates independently of the audio engine, connecting as needed and handling temporary disconnections gracefully. +External process management tools handle startup coordination and service lifecycle, +keeping the display implementation focused on its core visualization responsibilities. \ No newline at end of file diff --git a/interface_spec.md b/interface_spec.md index 700cdc1..b82f84d 100644 --- a/interface_spec.md +++ b/interface_spec.md @@ -164,7 +164,7 @@ SPP (F2H): Reset to 0 on Start message ```osc /looper/metronome/position Range: 0.0 - 1.0 (position within current beat) - Update frequency: 60 FPS + Update frequency: same as PPQN midi signal ``` ### OSC Implementation Details