@@ -10,7 +10,7 @@ import { extractPeaksFromWaveformData } from './waveformDataLoader';
1010import type WaveformData from 'waveform-data' ;
1111import type { PeakData } from '@waveform-playlist/webaudio-peaks' ;
1212import type { AnnotationData } from '@waveform-playlist/core' ;
13- import { useTimeFormat , useZoomControls , useMasterVolume } from './hooks' ;
13+ import { useTimeFormat , useZoomControls , useMasterVolume , useAnimationFrameLoop } from './hooks' ;
1414
1515// Types
1616export interface ClipPeaks {
@@ -254,7 +254,6 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
254254 const playoutRef = useRef < TonePlayout | null > ( null ) ;
255255 const playStartPositionRef = useRef < number > ( 0 ) ;
256256 const currentTimeRef = useRef < number > ( 0 ) ;
257- const animationFrameRef = useRef < number | null > ( null ) ;
258257 const trackStatesRef = useRef < TrackState [ ] > ( trackStates ) ;
259258 const playbackStartTimeRef = useRef < number > ( 0 ) ; // context.currentTime when playback started
260259 const audioStartPositionRef = useRef < number > ( 0 ) ; // Audio position when playback started
@@ -275,6 +274,7 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
275274 const zoom = useZoomControls ( { initialSamplesPerPixel, zoomLevels } ) ;
276275 const samplesPerPixel = zoom . samplesPerPixel ;
277276 const { masterVolume, setMasterVolume } = useMasterVolume ( { playoutRef, initialVolume : 1.0 } ) ;
277+ const { animationFrameRef, startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop ( ) ;
278278
279279 // Custom setter for continuousPlay that updates BOTH state and ref synchronously
280280 // This ensures the ref is updated immediately, before the animation loop can read it
@@ -384,10 +384,7 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
384384 // Stop current playback and animation before disposing
385385 if ( playoutRef . current && wasPlaying ) {
386386 playoutRef . current . stop ( ) ;
387- if ( animationFrameRef . current ) {
388- cancelAnimationFrame ( animationFrameRef . current ) ;
389- animationFrameRef . current = null ;
390- }
387+ stopAnimationFrameLoop ( ) ;
391388 // Mark that we need to resume playback after playout is rebuilt
392389 pendingResumeRef . current = { position : resumePosition } ;
393390 }
@@ -524,14 +521,12 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
524521 loadAudio ( ) ;
525522
526523 return ( ) => {
527- if ( animationFrameRef . current ) {
528- cancelAnimationFrame ( animationFrameRef . current ) ;
529- }
524+ stopAnimationFrameLoop ( ) ;
530525 if ( playoutRef . current ) {
531526 playoutRef . current . dispose ( ) ;
532527 }
533528 } ;
534- } , [ tracks , onReady , isPlaying ] ) ;
529+ } , [ tracks , onReady , isPlaying , effects , stopAnimationFrameLoop ] ) ;
535530
536531 // Regenerate peaks when zoom or mono changes (without reloading audio)
537532 useEffect ( ( ) => {
@@ -617,12 +612,6 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
617612
618613 // Animation loop
619614 const startAnimationLoop = useCallback ( ( ) => {
620- // Cancel any existing animation frame before starting a new one
621- if ( animationFrameRef . current ) {
622- cancelAnimationFrame ( animationFrameRef . current ) ;
623- animationFrameRef . current = null ;
624- }
625-
626615 const updateTime = ( ) => {
627616 // Calculate current position based on context.currentTime timing
628617 const elapsed = getContext ( ) . currentTime - playbackStartTimeRef . current ;
@@ -720,7 +709,7 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
720709 playoutRef . current ?. play ( timeNow , loopStartRef . current ) ;
721710
722711 // Continue animation loop
723- animationFrameRef . current = requestAnimationFrame ( updateTime ) ;
712+ startAnimationFrameLoop ( updateTime ) ;
724713 return ;
725714 }
726715 }
@@ -736,17 +725,12 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
736725 setActiveAnnotationId ( null ) ;
737726 return ;
738727 }
739- animationFrameRef . current = requestAnimationFrame ( updateTime ) ;
728+ startAnimationFrameLoop ( updateTime ) ;
740729 } ;
741- animationFrameRef . current = requestAnimationFrame ( updateTime ) ;
742- } , [ duration , audioBuffers , samplesPerPixel , continuousPlay ] ) ;
730+ startAnimationFrameLoop ( updateTime ) ;
731+ } , [ duration , audioBuffers , controls . show , controls . width , setActiveAnnotationId , startAnimationFrameLoop ] ) ;
743732
744- const stopAnimationLoop = useCallback ( ( ) => {
745- if ( animationFrameRef . current ) {
746- cancelAnimationFrame ( animationFrameRef . current ) ;
747- animationFrameRef . current = null ;
748- }
749- } , [ ] ) ;
733+ const stopAnimationLoop = stopAnimationFrameLoop ;
750734
751735 // Restart animation loop and reschedule playout when continuousPlay changes during playback
752736 // This ensures the loop always has the current continuousPlay value
@@ -786,7 +770,7 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
786770 } ;
787771
788772 reschedulePlayback ( ) ;
789- } , [ continuousPlay , isPlaying , startAnimationLoop , stopAnimationLoop ] ) ;
773+ } , [ continuousPlay , isPlaying , startAnimationLoop , stopAnimationLoop , animationFrameRef ] ) ;
790774
791775 // Resume playback after tracks change (e.g., after splitting a clip during playback)
792776 useEffect ( ( ) => {
@@ -878,7 +862,7 @@ export const WaveformPlaylistProvider: React.FC<WaveformPlaylistProviderProps> =
878862 currentTimeRef . current = playStartPositionRef . current ;
879863 setCurrentTime ( playStartPositionRef . current ) ;
880864 setActiveAnnotationId ( null ) ;
881- } , [ stopAnimationLoop ] ) ;
865+ } , [ stopAnimationLoop , setActiveAnnotationId ] ) ;
882866
883867 // Seek to a specific time - works whether playing or stopped
884868 const seekTo = useCallback ( ( time : number ) => {
@@ -1154,4 +1138,3 @@ export const usePlaylistData = () => {
11541138 }
11551139 return context ;
11561140} ;
1157-
0 commit comments