Data Layer (react_ui/src/data/)
State management, C++↔JS bridge, and real-time metering.
Files
| File | Purpose |
|---|---|
bridge.ts | C++↔JS communication layer. StateStorage for Zustand persistence, addStateListener for C++ events, juceBridge for native function calls. |
meters.ts | Real-time metering: useMeterStore (Zustand), raw rtBuffer, ballistic smoothing engine, subscribeRtBuffer API. |
store.ts | Primary Zustand stores (useTransportStore, useMixerStore, etc.) with C++ persistence. |
plugins.ts | Plugin scanning and management state. |
sliderDrag.ts | Shared slider drag utilities. |
Real-Time Metering Pipeline
Three-Layer Architecture
-
rtBuffer— Raw mutable object, written by the C++ event handler. No subscriptions, no notifications. Just a data landing zone. -
displayBuffer— Smoothed values computed by therequestAnimationFrameloop. Applies ballistic smoothing so meters look fluid even with 30Hz data input. Subscribers receive this. -
useMeterStore(Zustand) — Throttled to ~10Hz for the few React components that still use reactive selectors. Most components usesubscribeRtBufferinstead.
Ballistic Smoothing Constants
| Element | Release Factor | Effective Decay | Rationale |
|---|---|---|---|
| Level meters | 0.88 | ~300ms | Matches professional PPM meter ballistics |
| Spectrum bars | 0.82 | ~200ms | Slightly faster for responsive spectrum display |
| Stereo/phase | 0.85 | ~250ms | Bidirectional smoothing (not attack/release) |
| CPU | 0.95 | ~600ms | Slow-moving data, avoid visual noise |
API
Rendering Best Practices
All meter components use direct DOM manipulation viasubscribeRtBuffer (no React re-renders):
| ✅ Do | ❌ Don’t |
|---|---|
style.transform = 'scaleY(...)' | style.height = '...' |
style.transform = 'scaleX(...)' | style.width = '...' |
style.transform = 'translateX(...)' | style.left = '...' |
will-change: transform | CSS transition-* on high-freq elements |
subscribeRtBuffer() | useMeterStore(selector) for meters |
height/width/left trigger browser layout recalculation (~0.5ms per property). transform is GPU-composited — the browser sends a matrix to the GPU with no layout cost.