Skip to content

Mixer state survives track reloads — EngineState.mixerVersion (#501)

Choose a tag to compare

Fixes #501PlaylistEngine's per-track mixer setters (setTrackVolume, setTrackMute, setTrackSolo, setTrackPan) never emitted statechange, so a consumer caching a track snapshot (notably @dawcore/components' <daw-editor> _engineTracks) went stale. A later, unrelated engine.setTracks([...staleCache.values()]) — triggered by something as ordinary as loading one more track — then rebuilt from that stale snapshot and silently reverted live mute / solo / volume / pan. PR #514.

Published packages

Package Version
@waveform-playlist/engine 13.5.0
@dawcore/components 0.0.25

What changed

New EngineState.mixerVersion counter (@waveform-playlist/engine)

The four per-track mixer setters now bump a dedicated mixerVersion counter and emit statechange. tracksVersion stays structural-only (setTracks, addTrack, removeTrack, moveClip, trimClip, splitClip).

Separating the two signals lets a consumer refresh a cached track snapshot on mixer edits without re-running the expensive structural work (audio-graph rewire, peak regeneration) that tracksVersion gates — which matters because the mixer setters fire continuously during a volume/pan slider drag. mixerVersion is an additive, backward-compatible field on the returned snapshot.

<daw-editor> keeps live mixer state (@dawcore/components)

The editor now refreshes its _engineTracks cache when either counter changes, so mute/solo/volume/pan survive a later setTracks rebuild — but it runs rewireTrackChains() and peak regeneration only on structural (tracksVersion) changes, never on per-frame mixer edits. The engine peer dependency is raised to >=13.5.0 so the fix is guaranteed end-to-end.

React is unaffected

@waveform-playlist/browser already persists mixer state via trackStates, and tracksVersion keeps its prior meaning — so onTracksChange does not fire on mixer edits and there is no behavior change for React consumers.

Tests

New engine unit tests pin the mixerVersion contract (starts at 0, increments per setter, never on structural/other changes; tracksVersion unaffected; statechange carries the updated mixer values; absent-track and interleaved-counter cases). A new @dawcore/components integration test reproduces the revert scenario (mute survives an unrelated addTrack) and guards that no audio-graph rewire runs on a mixer-only change. Every new test was verified failing against the pre-fix code first. Suites green: engine 206, dawcore 660, browser 225.

Also in @dawcore/components 0.0.25

This dawcore publish also carries the transport display elements (<daw-time-display>, <daw-time-format>, daw-timeupdate) from #498, which merged after 0.0.24 shipped and had not been published until now. See the dedicated release for details.