kolaslab/Audio-Visualizer
75
1<!DOCTYPE html>2<html lang="ru">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Audio Visualizer</title>7 <style>8 * {9 margin: 0;10 padding: 0;11 box-sizing: border-box;12 }13 14 body {15 background: #0f0f1a;16 color: #fff;17 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;18 overflow-x: hidden;19 }20 21 .container {22 width: 100%;23 min-height: 100vh;24 padding: 20px;25 position: relative;26 }27 28 header {29 text-align: center;30 padding: 40px 0;31 animation: fadeIn 1s ease-in;32 }33 34 h1 {35 font-size: 3em;36 margin-bottom: 20px;37 background: linear-gradient(45deg, #ff6b6b, #4ecdc4);38 -webkit-background-clip: text;39 -webkit-text-fill-color: transparent;40 }41 42 .visualizer-container {43 width: 100%;44 height: calc(100vh - 200px);45 margin: 0 auto;46 background: rgba(255, 255, 255, 0.05);47 border-radius: 15px;48 padding: 20px;49 position: relative;50 }51 52 canvas {53 width: 100%;54 height: 100%;55 border-radius: 10px;56 background: rgba(0, 0, 0, 0.3);57 }58 59 .controls {60 position: fixed;61 bottom: 20px;62 left: 50%;63 transform: translateX(-50%);64 display: flex;65 gap: 10px;66 flex-wrap: wrap;67 justify-content: center;68 z-index: 100;69 }70 71 button {72 padding: 10px 20px;73 border: none;74 border-radius: 25px;75 background: linear-gradient(45deg, #ff6b6b, #4ecdc4);76 color: white;77 cursor: pointer;78 transition: transform 0.2s;79 }80 81 button:hover {82 transform: scale(1.05);83 }84 85 input[type="file"] {86 display: none;87 }88 89 .visualization-styles {90 position: fixed;91 top: 20px;92 right: 20px;93 display: flex;94 gap: 10px;95 flex-direction: column;96 z-index: 100;97 }98 99 .style-option {100 padding: 8px 15px;101 border-radius: 15px;102 background: rgba(255, 255, 255, 0.1);103 cursor: pointer;104 transition: background 0.3s;105 }106 107 .style-option:hover {108 background: rgba(255, 255, 255, 0.2);109 }110 111 .center-image {112 position: absolute;113 top: 50%;114 left: 50%;115 transform: translate(-50%, -50%);116 max-width: 200px;117 max-height: 200px;118 z-index: 10;119 }120 121 .background-image {122 position: absolute;123 top: 0;124 left: 0;125 width: 100%;126 height: 100%;127 object-fit: cover;128 opacity: 0.3;129 z-index: 1;130 }131 132 .fullscreen-btn {133 position: fixed;134 top: 20px;135 left: 20px;136 z-index: 100;137 }138 139 .credit {140 position: fixed;141 bottom: 10px;142 right: 20px;143 font-size: 14px;144 opacity: 0.7;145 z-index: 100;146 }147 148 @keyframes fadeIn {149 from {150 opacity: 0;151 transform: translateY(-20px);152 }153 to {154 opacity: 1;155 transform: translateY(0);156 }157 }158 159 @media (max-width: 768px) {160 .visualizer-container {161 padding: 10px;162 }163 164 h1 {165 font-size: 2em;166 }167 }168 </style>169</head>170<body>171 <div class="container">172 <header>173 <h1>Audio Visualizer</h1>174 </header>175 176 <div class="visualizer-container" id="visualizer-container">177 <canvas id="visualizer"></canvas>178 <img id="centerImage" class="center-image" style="display: none;">179 <img id="backgroundImage" class="background-image" style="display: none;">180 </div>181 182 <div class="controls">183 <button onclick="document.getElementById('audioInput').click()">Upload Audio</button>184 <button onclick="document.getElementById('imageInput').click()">Upload Center Image</button>185 <button onclick="document.getElementById('bgImageInput').click()">Upload Background</button>186 <button id="playPause">Play</button>187 <input type="file" id="audioInput" accept="audio/*">188 <input type="file" id="imageInput" accept="image/*,video/gif">189 <input type="file" id="bgImageInput" accept="image/*,video/gif">190 </div>191 192 <button class="fullscreen-btn" onclick="toggleFullscreen()">Fullscreen</button>193 194 <div class="visualization-styles">195 <div class="style-option" data-style="bars">Bars</div>196 <div class="style-option" data-style="wave">Wave</div>197 <div class="style-option" data-style="circle">Circle</div>198 </div>199 200 <div class="credit">by Софронов Артемий</div>201 </div>202 203 <script>204 let audioContext, analyser, source;205 const canvas = document.getElementById('visualizer');206 const ctx = canvas.getContext('2d');207 let animationId;208 let currentStyle = 'bars';209 let centerImage = document.getElementById('centerImage');210 let backgroundImage = document.getElementById('backgroundImage');211 let bassValue = 0;212 213 function resizeCanvas() {214 canvas.width = canvas.clientWidth * window.devicePixelRatio;215 canvas.height = canvas.clientHeight * window.devicePixelRatio;216 }217 resizeCanvas();218 window.addEventListener('resize', resizeCanvas);219 220 document.getElementById('audioInput').addEventListener('change', function(e) {221 const file = e.target.files[0];222 const audio = new Audio();223 audio.src = URL.createObjectURL(file);224 setupAudioContext(audio);225 });226 227 document.getElementById('imageInput').addEventListener('change', function(e) {228 const file = e.target.files[0];229 centerImage.src = URL.createObjectURL(file);230 centerImage.style.display = 'block';231 });232 233 document.getElementById('bgImageInput').addEventListener('change', function(e) {234 const file = e.target.files[0];235 backgroundImage.src = URL.createObjectURL(file);236 backgroundImage.style.display = 'block';237 });238 239 function setupAudioContext(audio) {240 if (audioContext) audioContext.close();241 242 audioContext = new (window.AudioContext || window.webkitAudioContext)();243 analyser = audioContext.createAnalyser();244 source = audioContext.createMediaElementSource(audio);245 246 source.connect(analyser);247 analyser.connect(audioContext.destination);248 249 analyser.fftSize = 256;250 251 audio.play();252 draw();253 }254 255 function draw() {256 const bufferLength = analyser.frequencyBinCount;257 const dataArray = new Uint8Array(bufferLength);258 259 function animate() {260 animationId = requestAnimationFrame(animate);261 analyser.getByteFrequencyData(dataArray);262 263 ctx.fillStyle = 'rgba(15, 15, 26, 0.2)';264 ctx.fillRect(0, 0, canvas.width, canvas.height);265 266 // Get bass value for image animation267 bassValue = dataArray.slice(0, 10).reduce((a, b) => a + b) / 10;268 269 if (centerImage.style.display !== 'none') {270 const scale = 1 + (bassValue / 255) * 0.2;271 centerImage.style.transform = `translate(-50%, -50%) scale(${scale})`;272 }273 274 switch(currentStyle) {275 case 'bars':276 drawBars(dataArray, bufferLength);277 break;278 case 'wave':279 drawWave(dataArray, bufferLength);280 break;281 case 'circle':282 drawCircle(dataArray, bufferLength);283 break;284 }285 }286 287 animate();288 }289 290 function drawBars(dataArray, bufferLength) {291 const barWidth = canvas.width / bufferLength;292 293 for(let i = 0; i < bufferLength; i++) {294 const barHeight = dataArray[i] * canvas.height / 255;295 296 const gradient = ctx.createLinearGradient(0, canvas.height, 0, 0);297 gradient.addColorStop(0, '#ff6b6b');298 gradient.addColorStop(1, '#4ecdc4');299 300 ctx.fillStyle = gradient;301 ctx.fillRect(i * barWidth, canvas.height - barHeight, barWidth - 1, barHeight);302 }303 }304 305 function drawWave(dataArray, bufferLength) {306 ctx.beginPath();307 ctx.strokeStyle = '#4ecdc4';308 ctx.lineWidth = 2;309 310 for(let i = 0; i < bufferLength; i++) {311 const x = i * (canvas.width / bufferLength);312 const y = (dataArray[i] / 128.0) * (canvas.height / 2);313 314 if(i === 0) {315 ctx.moveTo(x, y);316 } else {317 ctx.lineTo(x, y);318 }319 }320 321 ctx.stroke();322 }323 324 function drawCircle(dataArray, bufferLength) {325 const centerX = canvas.width / 2;326 const centerY = canvas.height / 2;327 const radius = Math.min(centerX, centerY) - 50;328 329 ctx.beginPath();330 ctx.strokeStyle = '#ff6b6b';331 ctx.lineWidth = 2;332 333 for(let i = 0; i < bufferLength; i++) {334 const angle = i * 2 * Math.PI / bufferLength;335 const amplitude = (dataArray[i] * radius / 255) + radius;336 337 const x = centerX + amplitude * Math.cos(angle);338 const y = centerY + amplitude * Math.sin(angle);339 340 if(i === 0) {341 ctx.moveTo(x, y);342 } else {343 ctx.lineTo(x, y);344 }345 }346 347 ctx.closePath();348 ctx.stroke();349 350 // Draw base circle351 ctx.beginPath();352 ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);353 ctx.strokeStyle = 'rgba(255, 107, 107, 0.3)';354 ctx.stroke();355 }356 357 document.querySelectorAll('.style-option').forEach(option => {358 option.addEventListener('click', function() {359 currentStyle = this.dataset.style;360 });361 });362 363 function toggleFullscreen() {364 if (!document.fullscreenElement) {365 document.documentElement.requestFullscreen();366 } else {367 document.exitFullscreen();368 }369 }370 </script>371</body>372</html>