2a40dc504e
* feat(player): playback speed control (0.5x to 2.0x) Adds a speed slider to the transport footer (desktop) and mixer tab (mobile) so users can slow down or speed up tracks for practice. - audioEngine: store _playbackRate, apply to new AudioBufferSourceNodes on startSources(), and fix getCurrentTime() to account for rate so the waveform playhead and loop detection stay accurate at non-1x speeds - transport: applySpeed() propagates rate to both engine and streaming paths; scroll-wheel support (+-0.25 per tick); double-click resets to 1x - state: playbackSpeed variable + setter; speedEl/speedLabelEl DOM refs - player: resetSpeed() called in destroyPlayer() so a new track always starts at 1x - mobile: speed slider in mixer transport section, state.speed reset on track open * fix(player): move speed control below play button, centered * fix(player): tempo bar full-width below transport, TEMPO label + gold slider * fix(player): center 1.0x on tempo slider (range 0-2, midpoint = 1.0) * feat(audio): pitch-preserving tempo via SoundTouch AudioWorklet Voices and instruments no longer pitch-shift when changing playback speed. A WSOLA time-stretcher runs as an AudioWorkletProcessor on the master bus so a single node handles all stems. Falls back to tape-effect if the worklet API is unavailable. * fix(audio): close array literal in Promise.all ([]) was missing ]