From 56862114ecc3d87a8968f7ad5f021fc04ffc32de Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 21 Dec 2025 13:47:32 +0000 Subject: [PATCH] Changes --- src/components/MiniOscilloscope.tsx | 148 ++++++++++++---------------- src/contexts/MusicContext.tsx | 2 + 2 files changed, 67 insertions(+), 83 deletions(-) diff --git a/src/components/MiniOscilloscope.tsx b/src/components/MiniOscilloscope.tsx index 744444d..e5ac86c 100644 --- a/src/components/MiniOscilloscope.tsx +++ b/src/components/MiniOscilloscope.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useCallback } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import { useSettings } from '@/contexts/SettingsContext'; +import { useMusic } from '@/contexts/MusicContext'; export function MiniOscilloscope() { const canvasRef = useRef(null); @@ -8,76 +9,60 @@ export function MiniOscilloscope() { const analyzerRef = useRef(null); const audioContextRef = useRef(null); const sourceNodeRef = useRef(null); - const connectedElementsRef = useRef>(new Set()); + const connectedElementRef = useRef(null); const navigate = useNavigate(); + const location = useLocation(); const { playSound } = useSettings(); + const { audioElement, isPlaying } = useMusic(); - // Find and connect to all audio elements on the page - const connectToAudioElements = useCallback(() => { - if (!audioContextRef.current || !analyzerRef.current) return; - - const audioElements = document.querySelectorAll('audio, video'); - - audioElements.forEach((element) => { - const mediaElement = element as HTMLMediaElement; - - // Skip if already connected - if (connectedElementsRef.current.has(mediaElement)) return; - - try { - // Create a source node for this element - const source = audioContextRef.current!.createMediaElementSource(mediaElement); - source.connect(analyzerRef.current!); - source.connect(audioContextRef.current!.destination); - connectedElementsRef.current.add(mediaElement); - } catch (e) { - // Element might already be connected to a different context - console.log('Could not connect audio element:', e); - } - }); - }, []); - - // Initialize audio context and analyzer + // Connect to music player's audio element useEffect(() => { - const initAudio = async () => { + if (!audioElement) return; + + // Skip if already connected to this element + if (connectedElementRef.current === audioElement) return; + + const connectToAudio = async () => { try { - audioContextRef.current = new AudioContext(); - analyzerRef.current = audioContextRef.current.createAnalyser(); - analyzerRef.current.fftSize = 256; - analyzerRef.current.smoothingTimeConstant = 0.8; + // Create or resume audio context + if (!audioContextRef.current) { + audioContextRef.current = new AudioContext(); + } - // Connect analyzer to destination for pass-through - // We'll connect sources as we find them + if (audioContextRef.current.state === 'suspended') { + await audioContextRef.current.resume(); + } + + // Create analyzer if needed + if (!analyzerRef.current) { + analyzerRef.current = audioContextRef.current.createAnalyser(); + analyzerRef.current.fftSize = 256; + analyzerRef.current.smoothingTimeConstant = 0.8; + } + + // Disconnect old source if exists + if (sourceNodeRef.current) { + try { + sourceNodeRef.current.disconnect(); + } catch (e) { + // Ignore disconnect errors + } + } + + // Create new source from the audio element + sourceNodeRef.current = audioContextRef.current.createMediaElementSource(audioElement); + sourceNodeRef.current.connect(analyzerRef.current); + sourceNodeRef.current.connect(audioContextRef.current.destination); + connectedElementRef.current = audioElement; + + console.log('MiniOscilloscope connected to audio element'); } catch (e) { - console.log('Could not initialize audio context:', e); + console.log('Could not connect to audio element:', e); } }; - initAudio(); - - // Observe DOM for new audio elements - const observer = new MutationObserver(() => { - connectToAudioElements(); - }); - - observer.observe(document.body, { - childList: true, - subtree: true, - }); - - // Initial connection attempt - connectToAudioElements(); - - return () => { - observer.disconnect(); - if (animationRef.current) { - cancelAnimationFrame(animationRef.current); - } - if (audioContextRef.current) { - audioContextRef.current.close(); - } - }; - }, [connectToAudioElements]); + connectToAudio(); + }, [audioElement]); // Draw waveform useEffect(() => { @@ -118,7 +103,7 @@ export function MiniOscilloscope() { ctx.stroke(); // Draw waveform - if (analyzerRef.current) { + if (analyzerRef.current && isPlaying) { const bufferLength = analyzerRef.current.frequencyBinCount; const dataArray = new Uint8Array(bufferLength); analyzerRef.current.getByteTimeDomainData(dataArray); @@ -151,26 +136,8 @@ export function MiniOscilloscope() { ctx.lineTo(width, height / 2); ctx.stroke(); ctx.shadowBlur = 0; - - // If no audio, draw a subtle idle animation - if (!hasAudio) { - const time = Date.now() / 1000; - ctx.strokeStyle = 'hsl(120, 100%, 50%, 0.5)'; - ctx.lineWidth = 1; - ctx.beginPath(); - - for (let i = 0; i < width; i++) { - const y = height / 2 + Math.sin(i * 0.05 + time * 2) * 3; - if (i === 0) { - ctx.moveTo(i, y); - } else { - ctx.lineTo(i, y); - } - } - ctx.stroke(); - } } else { - // No analyzer - draw idle animation + // No audio playing - draw idle animation const time = Date.now() / 1000; ctx.strokeStyle = 'hsl(120, 100%, 50%, 0.5)'; ctx.lineWidth = 1; @@ -197,7 +164,7 @@ export function MiniOscilloscope() { cancelAnimationFrame(animationRef.current); } }; - }, []); + }, [isPlaying]); // Handle resize useEffect(() => { @@ -220,11 +187,26 @@ export function MiniOscilloscope() { }; }, []); + // Cleanup on unmount + useEffect(() => { + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + // Don't close audio context as it would break the music player + }; + }, []); + const handleClick = () => { playSound('click'); navigate('/oscilloscope'); }; + // Hide on oscilloscope page + if (location.pathname === '/oscilloscope') { + return null; + } + return (
); -} \ No newline at end of file +} diff --git a/src/contexts/MusicContext.tsx b/src/contexts/MusicContext.tsx index d635362..79d5fc3 100644 --- a/src/contexts/MusicContext.tsx +++ b/src/contexts/MusicContext.tsx @@ -18,6 +18,7 @@ interface MusicContextType { currentIndex: number; selectedStation: Station | null; hasFetched: boolean; + audioElement: HTMLAudioElement | null; setVolume: (volume: number) => void; playStation: (station: Station, index: number) => void; togglePlay: () => void; @@ -188,6 +189,7 @@ export const MusicProvider = ({ children }: { children: ReactNode }) => { currentIndex, selectedStation, hasFetched, + audioElement: audioRef.current, setVolume, playStation, togglePlay,