diff --git a/client/src/App.tsx b/client/src/App.tsx index c407245..3bd3413 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -17,6 +17,7 @@ import UploadPage from './Pages/UploadPage'; import PreviewPage from './Pages/PreviewPage'; import ProcessingPage from './Pages/ProcessingPage'; import ResultsPage from './Pages/ResultsPage'; +import AudioVisualizer from './components/AudioVisualizer'; // Custom Link component for AppBar const App: React.FC = () => { @@ -39,6 +40,7 @@ const App: React.FC = () => { } /> } /> } /> + }/> diff --git a/client/src/Pages/UploadPage.tsx b/client/src/Pages/UploadPage.tsx index 553d03f..ffccebe 100644 --- a/client/src/Pages/UploadPage.tsx +++ b/client/src/Pages/UploadPage.tsx @@ -108,6 +108,7 @@ function UploadPage() { onChange={handleFileChange} accept="audio/*,video/*" /> + {file ? file.name : 'Drop your file here or click to browse'} @@ -135,6 +136,7 @@ function UploadPage() { + ); } diff --git a/client/src/assets/female-female-mixture.wav b/client/src/assets/female-female-mixture.wav new file mode 100644 index 0000000..2137997 Binary files /dev/null and b/client/src/assets/female-female-mixture.wav differ diff --git a/client/src/components/AudioVisualizer.tsx b/client/src/components/AudioVisualizer.tsx new file mode 100644 index 0000000..bffcb67 --- /dev/null +++ b/client/src/components/AudioVisualizer.tsx @@ -0,0 +1,93 @@ +import audioFile from "../assets/female-female-mixture.wav"; +import { useEffect, useRef, useState } from "react"; + +const AudioVisualizer: React.FC = () => { + const audioRef = useRef(null); + const canvasRef = useRef(null); + const audioContextRef = useRef(null); + const sourceRef = useRef(null); + const analyserRef = useRef(null); + const [isPlaying, setIsPlaying] = useState(false); + const [audioSrc, setAudioSrc] = useState(""); + + useEffect(() => { + setAudioSrc(audioFile); + }, []); + + useEffect(() => { + if (!audioRef.current || !canvasRef.current) return; + + if (!audioContextRef.current) { + audioContextRef.current = new (window.AudioContext || window.AudioContext)(); + } + const audioContext = audioContextRef.current; + + if (!analyserRef.current) { + analyserRef.current = audioContext.createAnalyser(); + analyserRef.current.fftSize = 256; + } + const analyser = analyserRef.current; + + if (!sourceRef.current) { + sourceRef.current = audioContext.createMediaElementSource(audioRef.current); + sourceRef.current.connect(analyser); + analyser.connect(audioContext.destination); + } + + const bufferLength = analyser.frequencyBinCount; + const dataArray = new Uint8Array(bufferLength); + const canvas = canvasRef.current; + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + const draw = () => { + if (!isPlaying) return; + + analyser.getByteFrequencyData(dataArray); + ctx.clearRect(0, 0, canvas.width, canvas.height); + + const barWidth = canvas.width / bufferLength; // Fit bars within canvas width + const maxBarHeight = canvas.height * 0.9; // Scale bars relative to canvas height + + let x = 0; + for (let i = 0; i < bufferLength; i++) { + const barHeight = (dataArray[i] / 255) * maxBarHeight; // Normalize height + + ctx.fillStyle = `rgb(${barHeight + 100}, 50, 100)`; + ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight); + x += barWidth + 2; // Add spacing between bars + } + + requestAnimationFrame(draw); + }; + + if (isPlaying) { + audioContext.resume(); + draw(); + } + }, [isPlaying]); + + const togglePlay = () => { + const audio = audioRef.current; + if (!audio) return; + + if (audio.paused) { + audio.play(); + setIsPlaying(true); + } else { + audio.pause(); + setIsPlaying(false); + } + }; + + return ( +
+ {audioSrc &&
+ ); +}; + +export default AudioVisualizer;