- useWaveform: remove globalCurrentTime/globalIsPlaying from useEffect deps;
WaveSurfer was re-initializing every 250ms while audio played. Dep array
is now [url, songId, bandId]. Store reads inside the effect use getState()
snapshots instead of reactive values.
- useWaveform: move animationFrameId outside the async function so the
useEffect cleanup can actually cancel the RAF loop. Previously the cleanup
was returned from the inner async function and React never called it —
loops accumulated on every re-render.
- audioService: remove isDifferentSong + cleanup() call from play(). cleanup()
set this.wavesurfer = null and then play() immediately called
this.wavesurfer.play(), throwing a TypeError on every song switch.
- audioService: replace new Promise(async executor) anti-pattern in
initialize() with a plain executor + extracted onReady().catch(reject) so
errors inside the ready handler are always forwarded to the promise.
- audioService: remove currentPlayingSongId/currentPlayingBandId private
fields whose only reader was the deleted isDifferentSong block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>