<div class="container">
<h1>Audio Visualizer</h1>
<p class="subtitle">Click below to start capturing microphone audio</p>
<canvas id="visualizer" width="600" height="200"></canvas>
<div class="controls">
<button id="startBtn">Start Visualizer</button>
<button id="stopBtn" style="display: none;">Stop Visualizer</button>
</div>
<div class="status" id="status"></div>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
color: #fff;
}
.container {
text-align: center;
padding: 40px;
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
h1 {
font-size: 2rem;
margin-bottom: 10px;
background: linear-gradient(135deg, #FF1493, #ff69b4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle {
color: #aaa;
margin-bottom: 30px;
font-size: 0.9rem;
}
canvas {
display: block;
margin: 30px auto;
border-radius: 10px;
background: rgba(0, 0, 0, 0.3);
box-shadow: 0 4px 20px rgba(255, 20, 147, 0.2);
}
.controls {
margin-top: 30px;
}
button {
background: linear-gradient(135deg, #FF1493, #ff69b4);
color: white;
border: none;
padding: 15px 40px;
font-size: 1rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(255, 20, 147, 0.4);
font-weight: 600;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(255, 20, 147, 0.6);
}
button:active {
transform: translateY(0);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.status {
margin-top: 20px;
font-size: 0.9rem;
color: #888;
min-height: 20px;
}
.status.active {
color: #FF1493;
font-weight: 600;
}
const canvas = document.getElementById('visualizer');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const status = document.getElementById('status');
let audioContext;
let analyser;
let microphone;
let dataArray;
let bufferLength;
let animationId;
startBtn.addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
microphone = audioContext.createMediaStreamSource(stream);
analyser.fftSize = 256;
bufferLength = analyser.frequencyBinCount;
dataArray = new Uint8Array(bufferLength);
microphone.connect(analyser);
startBtn.style.display = 'none';
stopBtn.style.display = 'inline-block';
status.textContent = '🎤 Listening...';
status.classList.add('active');
visualize();
} catch (err) {
status.textContent = 'Error: Microphone access denied';
console.error('Error accessing microphone:', err);
}
});
stopBtn.addEventListener('click', () => {
if (animationId) {
cancelAnimationFrame(animationId);
}
if (audioContext) {
audioContext.close();
}
startBtn.style.display = 'inline-block';
stopBtn.style.display = 'none';
status.textContent = '';
status.classList.remove('active');
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
function visualize() {
animationId = requestAnimationFrame(visualize);
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const barWidth = (canvas.width / bufferLength) * 2.5;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
const barHeight = (dataArray[i] / 255) * canvas.height;
const gradient = ctx.createLinearGradient(0, canvas.height - barHeight, 0, canvas.height);
gradient.addColorStop(0, '#FF1493');
gradient.addColorStop(0.5, '#ff69b4');
gradient.addColorStop(1, '#ffb6d9');
ctx.fillStyle = gradient;
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
No comments yet. Be the first!