2 months ago
e75a5e9Dragging the 4-stem accompaniment master recomputed `ratio = newValue / max(drums, bass, other)` from the last rendered store snapshot on every slider event, then dispatched each sub-stem through its own 20ms trailing limiter into an independent async round-trip. During a fast drag the three stems were scaled by factors sampled at different, partially-committed moments, so they drifted apart; whichever stem saturated at 1 captured the max-derived master and pinned it, and the lossy `Math.min(1, …)` clamp destroyed the mix ratios for good. Freeze a per-gesture base at pointerdown and map every sub-stem as a pure function of the master value from that base, so the mapping is idempotent and reversible through the clamp. Commit the three stems through a single trailing limiter so a throttled flush always carries a consistent triple, and flush on release. While dragging, render the master thumb from the gesture value instead of max(sub-stems) so a saturated stem cannot pin it. Also release the gesture explicitly when the slider disappears without a pointerup (song ends, mixer popup closes) or the track changes mid-drag — otherwise the next drag would scale the new mix by the previous song's ratios — and hold the released value until the store reflects it, so the thumb does not hop backwards for one IPC round-trip. Unmuting now restores each sub-stem's own level instead of collapsing all three to one value. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Parent40f2d5b