Sound Visualizer

copy code

Sound Visualizer

CODE:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sci-Fi Ring Sound Visualizer</title>
    <style>
        .scifiringvisualizer3914-body {
            font-family: 'Arial', sans-serif;
            background-color: #000;
            color: #0ff;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            overflow: hidden;
        }
        .scifiringvisualizer3914-container {
            display: flex;
            flex-direction: row;
            max-width: 1200px;
            width: 100%;
        }
        .scifiringvisualizer3914-controls {
            flex: 1;
            padding: 20px;
            background-color: rgba(0, 255, 255, 0.1);
            border-radius: 10px;
            margin-right: 20px;
            z-index: 10;
        }
        .scifiringvisualizer3914-visualizer-container {
            flex: 2;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: rgba(0, 255, 255, 0.05);
            border-radius: 10px;
            overflow: hidden;
            position: relative;
        }
        .scifiringvisualizer3914-visualizer {
            width: 100%;
            height: 100%;
            max-width: 800px;
            max-height: 800px;
        }
        .scifiringvisualizer3914-button {
            background-color: #0ff;
            color: #000;
            border: none;
            padding: 10px 20px;
            margin: 10px 0;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        .scifiringvisualizer3914-button:hover {
            background-color: #00ffff80;
        }
        .scifiringvisualizer3914-file-input {
            display: none;
        }
        .scifiringvisualizer3914-file-label {
            background-color: #0ff;
            color: #000;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            display: inline-block;
            margin: 10px 0;
        }
        .scifiringvisualizer3914-description {
            margin-bottom: 20px;
        }
        .scifiringvisualizer3914-instructions {
            list-style-type: none;
            padding: 0;
        }
        .scifiringvisualizer3914-instructions li {
            margin-bottom: 10px;
        }
        @media (max-width: 768px) {
            .scifiringvisualizer3914-container {
                flex-direction: column;
            }
            .scifiringvisualizer3914-controls {
                margin-right: 0;
                margin-bottom: 20px;
            }
        }
    </style>
</head>
<body class="scifiringvisualizer3914-body">
    <div class="scifiringvisualizer3914-container">
        <div class="scifiringvisualizer3914-controls">
            <h1>Sci-Fi Ring Sound Visualizer</h1>
            <p class="scifiringvisualizer3914-description">
                Experience your music in a futuristic ring-shaped visual spectacle!
            </p>
            <ul class="scifiringvisualizer3914-instructions">
                <li>1. Upload an audio file to start</li>
                <li>2. Use Pause/Resume to control playback</li>
                <li>3. Upload a new file to change the track</li>
            </ul>
            <input type="file" id="audioFile" accept="audio/*" class="scifiringvisualizer3914-file-input">
            <label for="audioFile" class="scifiringvisualizer3914-file-label">Choose Audio File</label>
            <button id="pauseResumeButton" class="scifiringvisualizer3914-button">Pause</button>
        </div>
        <div class="scifiringvisualizer3914-visualizer-container">
            <canvas id="visualizer" class="scifiringvisualizer3914-visualizer"></canvas>
        </div>
    </div>

    <script>
        let audioContext;
        let analyser;
        let source;
        let animationId;
        let isPaused = false;
        let audio;

        const visualizer = document.getElementById('visualizer');
        const ctx = visualizer.getContext('2d');
        const audioFileInput = document.getElementById('audioFile');
        const pauseResumeButton = document.getElementById('pauseResumeButton');

        function initAudio(audioElement) {
            if (audioContext) {
                audioContext.close();
            }
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
            analyser = audioContext.createAnalyser();
            source = audioContext.createMediaElementSource(audioElement);
            source.connect(analyser);
            analyser.connect(audioContext.destination);
            analyser.fftSize = 512;
        }

        function visualize() {
            const bufferLength = analyser.frequencyBinCount;
            const dataArray = new Uint8Array(bufferLength);

            function draw() {
                if (isPaused) return;

                animationId = requestAnimationFrame(draw);
                analyser.getByteFrequencyData(dataArray);

                ctx.clearRect(0, 0, visualizer.width, visualizer.height);

                const centerX = visualizer.width / 2;
                const centerY = visualizer.height / 2;
                const radius = Math.min(centerX, centerY) * 0.8;

                // Draw outer ring
                ctx.beginPath();
                ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
                ctx.strokeStyle = 'rgba(0, 255, 255, 0.2)';
                ctx.lineWidth = 2;
                ctx.stroke();

                // Draw frequency bars
                for (let i = 0; i < bufferLength; i++) {
                    const barHeight = dataArray[i] * 0.7;
                    const angle = (i / bufferLength) * 2 * Math.PI;
                    const x1 = centerX + Math.cos(angle) * radius;
                    const y1 = centerY + Math.sin(angle) * radius;
                    const x2 = centerX + Math.cos(angle) * (radius + barHeight);
                    const y2 = centerY + Math.sin(angle) * (radius + barHeight);

                    const hue = (i / bufferLength) * 360;
                    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
                    ctx.lineWidth = 3;
                    ctx.beginPath();
                    ctx.moveTo(x1, y1);
                    ctx.lineTo(x2, y2);
                    ctx.stroke();

                    // Add pulsating effect
                    const pulseRadius = 4 + Math.sin(Date.now() * 0.01 + i * 0.1) * 3;
                    ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
                    ctx.beginPath();
                    ctx.arc(x2, y2, pulseRadius, 0, 2 * Math.PI);
                    ctx.fill();
                }

                // Add rotating center effect
                const rotationAngle = Date.now() * 0.002;
                const innerRadius = radius * 0.3;
                for (let i = 0; i < 5; i++) {
                    const angle = rotationAngle + (i * 2 * Math.PI / 5);
                    const x = centerX + Math.cos(angle) * innerRadius;
                    const y = centerY + Math.sin(angle) * innerRadius;
                    const size = 6 + Math.sin(Date.now() * 0.005 + i) * 3;
                    ctx.fillStyle = `rgba(0, 255, 255, ${0.8 - i * 0.15})`;
                    ctx.beginPath();
                    ctx.arc(x, y, size, 0, 2 * Math.PI);
                    ctx.fill();
                }

                // Add waveform
                analyser.getByteTimeDomainData(dataArray);
                ctx.beginPath();
                ctx.strokeStyle = 'rgba(0, 255, 255, 0.5)';
                ctx.lineWidth = 2;
                for (let i = 0; i < bufferLength; i++) {
                    const x = (i / bufferLength) * visualizer.width;
                    const y = (dataArray[i] / 128.0) * (visualizer.height / 2);
                    if (i === 0) {
                        ctx.moveTo(x, y);
                    } else {
                        ctx.lineTo(x, y);
                    }
                }
                ctx.stroke();
            }

            draw();
        }

        function resizeCanvas() {
            const container = visualizer.parentElement;
            visualizer.width = container.clientWidth;
            visualizer.height = container.clientHeight;
        }

        window.addEventListener('resize', resizeCanvas);
        resizeCanvas();

        audioFileInput.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                if (audio) {
                    audio.pause();
                }
                audio = new Audio(URL.createObjectURL(file));
                initAudio(audio);
                audio.play();
                visualize();
                pauseResumeButton.disabled = false;
                isPaused = false;
                pauseResumeButton.textContent = 'Pause';
            }
        });

        pauseResumeButton.addEventListener('click', () => {
            if (isPaused) {
                audio.play();
                audioContext.resume();
                visualize();
                pauseResumeButton.textContent = 'Pause';
            } else {
                audio.pause();
                audioContext.suspend();
                cancelAnimationFrame(animationId);
                pauseResumeButton.textContent = 'Resume';
            }
            isPaused = !isPaused;
        });

        pauseResumeButton.disabled = true;
    </script>
</body>
</html>