first commit
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# `adapter-track-ops`
|
||||
|
||||
## Purpose
|
||||
|
||||
`adapter-track-ops` packs every track-scoped mutation that the
|
||||
`BrowserTimelineAdapter` exposes — adding, removing, updating, and the
|
||||
five per-track setters (`volume`, `mute`, `solo`, `pan`, plus the chain
|
||||
|
||||
+ subgraph teardown helper) — into pure functions that operate on an
|
||||
explicit `TrackOpEnv` rather than on adapter-private state. The adapter
|
||||
itself becomes a thin coordinator: it owns the lifecycle invariants and
|
||||
the lazy environment, and delegates the actual work here.
|
||||
|
||||
Pulling the work out of the class keeps `browser-adapter.ts` inside the
|
||||
300-line hard cap and makes every track operation unit-testable by
|
||||
passing a hand-built `TrackOpEnv` with deterministic state lambdas. The
|
||||
adapter file still exposes the same public methods; readers should
|
||||
follow the call chain to this module for the implementation.
|
||||
|
||||
## Features
|
||||
|
||||
+ `TrackOpEnv` interface — explicit dependency injection of the track
|
||||
map, graph, context, bus orchestrator, and the four lazy state
|
||||
accessors (`currentTime`, `playState`, `masterVolume`).
|
||||
+ `addTrackImpl` — builds the subgraph, constructs the chain, wires
|
||||
the latency-changed event, applies mixer + ambient state.
|
||||
+ `releaseTrackImpl` — symmetric teardown: dispose chain, tear down
|
||||
subgraph, drop from the map.
|
||||
+ `updateTrackImpl`, `setTrack{Volume,Mute,Solo,Pan}Impl` — small
|
||||
composable mutations sharing the same epilogue (mixer / ambient
|
||||
recompute).
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { addTrackImpl } from "@suaveplan/audio-engine-browser/adapter/adapter-track-ops";
|
||||
|
||||
addTrackImpl(env, track);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
addTrackImpl,
|
||||
releaseTrackImpl,
|
||||
setTrackPanImpl,
|
||||
setTrackVolumeImpl,
|
||||
} from "@suaveplan/audio-engine-browser/adapter/adapter-track-ops";
|
||||
|
||||
addTrackImpl(env, track);
|
||||
setTrackVolumeImpl(env, rec, 0.8);
|
||||
setTrackPanImpl(env, rec, -0.3);
|
||||
releaseTrackImpl(env, track.id);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `TrackOpEnv`
|
||||
|
||||
```ts
|
||||
interface TrackOpEnv {
|
||||
tracks: Map<string, TrackRecord>;
|
||||
graph: WebAudioGraph;
|
||||
context: ContextLike;
|
||||
busOrch: BusOrchestrator;
|
||||
currentTime(): number;
|
||||
playState(): "stopped" | "playing" | "paused";
|
||||
masterVolume(): number;
|
||||
}
|
||||
```
|
||||
|
||||
### `addTrackImpl(env, track) → void`
|
||||
|
||||
Builds the per-track subgraph, constructs a `PluginChain` bound to the
|
||||
project's shared `BusRegistry`, subscribes to `latency-changed`, and
|
||||
applies the mixer + ambient state.
|
||||
|
||||
### `releaseTrackImpl(env, trackId) → void`
|
||||
|
||||
Removes the chain + subgraph for `trackId`. Idempotent for missing ids.
|
||||
|
||||
### `updateTrackImpl(env, rec, track) → void`
|
||||
|
||||
Mutates the `TrackRecord` in place, refreshes the pan node, and
|
||||
re-applies mixer + ambient state.
|
||||
|
||||
### `setTrackVolumeImpl / setTrackMuteImpl / setTrackSoloImpl / setTrackPanImpl`
|
||||
|
||||
Single-purpose updaters. Each mutates the relevant fields and runs the
|
||||
small epilogue: `applyMixerState` then `applyAmbientForTrack`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
+ The OTel counter is module-scoped because every adapter shares the
|
||||
same series; the adapter itself owns the `kind=fx` increment, and
|
||||
this module owns `kind=track-subgraph` (+7 per added track).
|
||||
+ `TrackOpEnv` accessors are lambdas rather than direct fields so the
|
||||
adapter can pass `() => this.currentTime` without leaking `this`
|
||||
binding. This keeps the helpers callable from any code path
|
||||
(top-level, tests, future async restoration).
|
||||
+ `releaseTrackImpl` swallows chain dispose errors so a misbehaving
|
||||
plugin disposal cannot prevent the subgraph teardown — the adapter
|
||||
invariant is "track must be fully released by `removeTrack`".
|
||||
+ Adding the same track id again replays the release path first, which
|
||||
is how the adapter handles `updateTrack` on a recreated chain shape.
|
||||
Reference in New Issue
Block a user