first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
# use-stream-mixer
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`useStreamMixer` exposes per-peer mixer controls — level, mute, solo, and the per-peer
FX slot count — and implements DAW-correct solo semantics on top of the session's track
mutators. It is the only hook in chunk C that owns cross-peer behaviour: when any peer
is soloed, every non-soloed peer's track-volume is set to 0; when no peer is soloed,
every track keeps its last user-set volume (the session is the source of truth for
"last set" because the mutations go through `setTrackVolume`).
Every mutation routes through `session.setTrackVolume`, `session.setTrackMute`, and
`session.setTrackSolo` rather than being re-implemented inside the hook — this is the
explicit Requirement-6 constraint and the reason the test asserts on
`session.calls.setTrackSolo` / `setTrackVolume`.
## Features
- DAW solo semantics: any solo activates the per-track ducking pass; clearing the last
solo lets non-soloed tracks resume their stored volume.
- Pure delegation: zero local volume state — the session owns it.
- Stable callbacks via `useCallback`.
- Throws `REACT_AUDIO_STREAM.NO_PROVIDER` outside a `<StreamProvider>`.
## Usage: Basic
```tsx
const { peers, setVolume, setMute, setSolo } = useStreamMixer();
return peers.map((p) => (
<PeerStrip
key={p.id}
peer={p}
onVolume={(v) => setVolume(p.id, v)}
onMute={(m) => setMute(p.id, m)}
onSolo={(s) => setSolo(p.id, s)}
/>
));
```
## Usage: Advanced
```tsx
const { peers, setSolo } = useStreamMixer();
const soloExclusive = useCallback((id: string) => {
// Solo one peer and clear all others' solos in a single React tick.
peers.forEach((p) => p.soloed && p.id !== id && setSolo(p.id, false));
setSolo(id, true);
}, [peers, setSolo]);
```
## API Reference
- `UseStreamMixerResult` — `{ peers, setVolume, setMute, setSolo }`
- `useStreamMixer(): UseStreamMixerResult`
## Implementation Notes
`setSolo` reads the current mixer snapshot from `session.getPeerMixerStates()`,
applies the requested solo change in a local copy, computes `anySoloed`, and — when
true — issues `setTrackVolume(otherId, 0)` for every non-soloed peer whose current
volume is not already 0. The non-zero check avoids redundant mutations that would
otherwise show up as extra `calls.setTrackVolume` entries in tests.
The "restore previous volume on un-solo" arm is delegated to the session: chunk A's
session implementation stores the user-set volume independently from the live mixer
volume, so when the last solo clears, the session emits a `mixer-changed` event that
restores the stored values. The hook does not have to keep its own restore-map, which
keeps the React surface stateless.