From ace4c77bdc897ae6112bc288e55a3b2e794486e9 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 3 Jan 2026 00:47:41 -0800 Subject: [PATCH] add missing cleanup functions on visualizers --- .../audiomotionanalyzer/visualizer.tsx | 12 ++++++--- .../components/butternchurn/visualizer.tsx | 26 ++++++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/renderer/features/visualizer/components/audiomotionanalyzer/visualizer.tsx b/src/renderer/features/visualizer/components/audiomotionanalyzer/visualizer.tsx index a2968e7ed..4b671800e 100644 --- a/src/renderer/features/visualizer/components/audiomotionanalyzer/visualizer.tsx +++ b/src/renderer/features/visualizer/components/audiomotionanalyzer/visualizer.tsx @@ -187,6 +187,7 @@ const VisualizerInner = () => { useEffect(() => { const { context, gains } = webAudio || {}; + let audioMotion: AudioMotionAnalyzer | undefined; if (gains && context && canvasRef.current && !motion) { // Reset gradients registered flag on new instance setGradientsRegistered(false); @@ -208,7 +209,7 @@ const VisualizerInner = () => { } } - const audioMotion = new AudioMotionAnalyzer(canvasRef.current, { + audioMotion = new AudioMotionAnalyzer(canvasRef.current, { ...initOptions, audioCtx: context, }); @@ -220,16 +221,21 @@ const VisualizerInner = () => { for (const gain of gains) audioMotion.connectInput(gain); } - return () => {}; + return () => { + if (motion) { + motion.destroy(); + setMotion(undefined); + } + }; }, [ accent, canvasRef, - motion, registerCustomGradients, webAudio, visualizer, options, isCustomGradient, + motion, ]); // Re-register custom gradients when they change diff --git a/src/renderer/features/visualizer/components/butternchurn/visualizer.tsx b/src/renderer/features/visualizer/components/butternchurn/visualizer.tsx index 1157f7860..83bd1e8f1 100644 --- a/src/renderer/features/visualizer/components/butternchurn/visualizer.tsx +++ b/src/renderer/features/visualizer/components/butternchurn/visualizer.tsx @@ -112,7 +112,31 @@ const VisualizerInner = () => { } } - return () => {}; + return () => { + if (animationFrameRef.current) { + cancelAnimationFrame(animationFrameRef.current); + animationFrameRef.current = undefined; + } + + if (cycleTimerRef.current) { + clearInterval(cycleTimerRef.current); + cycleTimerRef.current = undefined; + } + + if (pauseTimerRef.current) { + clearTimeout(pauseTimerRef.current); + pauseTimerRef.current = undefined; + } + + if (resizeObserverRef.current) { + resizeObserverRef.current.disconnect(); + resizeObserverRef.current = undefined; + } + + if (visualizer) { + setVisualizer(undefined); + } + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [webAudio, canvasRef, containerRef, visualizer, isPlaying]);