Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/Jennys-Drumste / audio-visualizer.js |
| Date | Not specified in source |
| Repository | Janady13/Jennys-Drumste |
| Revision | 01c36ac1a180916e11864b4573b8c1999e2c5db3 |
| Branch | claude/complete-integration-feature-011CUkTzyyk8bKmXaRXJAR61 |
| Path or archive member | audio-visualizer.js |
| Original SHA-256 | 796bfc465b05cdf487e5407c2c3a23be714d2881a55567827510f01b0c1fdaaf |
| Git blob SHA | d26711de1dcf1044707100c5c609b577f4f42af7 |
| Reading-copy SHA-256 | 796bfc465b05cdf487e5407c2c3a23be714d2881a55567827510f01b0c1fdaaf |
Recovered source transcript
Download complete source text ↓352 lines · 10.4 KB
/**
* AUDIO VISUALIZER - Waveform & Spectrum Analysis
* Creates stunning audio-reactive visualizations
*/
class AudioVisualizer {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
if (!this.canvas) {
console.error('Canvas not found:', canvasId);
return;
}
this.ctx = this.canvas.getContext('2d');
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.analyser = this.audioContext.createAnalyser();
this.analyser.fftSize = 2048;
this.bufferLength = this.analyser.frequencyBinCount;
this.dataArray = new Uint8Array(this.bufferLength);
this.waveformData = new Uint8Array(this.bufferLength);
this.visualizationMode = 'spectrum'; // spectrum, waveform, circular, bars
this.colors = {
primary: [0, 255, 204],
secondary: [255, 0, 255],
accent: [255, 255, 0]
};
this.particles = [];
this.isActive = false;
this.resize();
window.addEventListener('resize', () => this.resize());
console.log('🎨 Audio Visualizer initialized');
}
/**
* Connect audio source (microphone, audio element, etc.)
*/
async connectMicrophone() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = this.audioContext.createMediaStreamSource(stream);
source.connect(this.analyser);
this.isActive = true;
this.render();
console.log('🎤 Microphone connected');
} catch (error) {
console.error('Microphone access denied:', error);
}
}
connectAudioElement(audioElement) {
const source = this.audioContext.createMediaElementSource(audioElement);
source.connect(this.analyser);
this.analyser.connect(this.audioContext.destination);
this.isActive = true;
this.render();
console.log('🔊 Audio element connected');
}
/**
* Render visualizations
*/
render() {
if (!this.isActive) return;
requestAnimationFrame(() => this.render());
this.analyser.getByteFrequencyData(this.dataArray);
this.analyser.getByteTimeDomainData(this.waveformData);
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
switch (this.visualizationMode) {
case 'spectrum':
this.drawSpectrum();
break;
case 'waveform':
this.drawWaveform();
break;
case 'circular':
this.drawCircular();
break;
case 'bars':
this.drawBars();
break;
case 'particles':
this.drawParticles();
break;
}
}
/**
* Spectrum Analyzer - Frequency bars
*/
drawSpectrum() {
const width = this.canvas.width;
const height = this.canvas.height;
const barWidth = width / this.bufferLength * 2.5;
let x = 0;
for (let i = 0; i < this.bufferLength; i++) {
const barHeight = (this.dataArray[i] / 255) * height;
const hue = (i / this.bufferLength) * 360;
this.ctx.fillStyle = `hsla(${hue}, 100%, 50%, 0.8)`;
// Draw bar with gradient
const gradient = this.ctx.createLinearGradient(0, height, 0, height - barHeight);
gradient.addColorStop(0, `hsla(${hue}, 100%, 50%, 0.8)`);
gradient.addColorStop(1, `hsla(${hue}, 100%, 70%, 0.4)`);
this.ctx.fillStyle = gradient;
this.ctx.fillRect(x, height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
/**
* Waveform - Time-domain visualization
*/
drawWaveform() {
const width = this.canvas.width;
const height = this.canvas.height;
this.ctx.lineWidth = 3;
this.ctx.strokeStyle = `rgba(${this.colors.primary.join(',')}, 0.8)`;
this.ctx.beginPath();
const sliceWidth = width / this.bufferLength;
let x = 0;
for (let i = 0; i < this.bufferLength; i++) {
const v = this.waveformData[i] / 128.0;
const y = v * height / 2;
if (i === 0) {
this.ctx.moveTo(x, y);
} else {
this.ctx.lineTo(x, y);
}
x += sliceWidth;
}
this.ctx.lineTo(width, height / 2);
this.ctx.stroke();
// Add glow effect
this.ctx.shadowBlur = 20;
this.ctx.shadowColor = `rgba(${this.colors.primary.join(',')}, 0.8)`;
this.ctx.stroke();
this.ctx.shadowBlur = 0;
}
/**
* Circular Visualization - Radial spectrum
*/
drawCircular() {
const width = this.canvas.width;
const height = this.canvas.height;
const centerX = width / 2;
const centerY = height / 2;
const radius = Math.min(width, height) / 3;
for (let i = 0; i < this.bufferLength; i++) {
const value = this.dataArray[i];
const percent = value / 255;
const angle = (i / this.bufferLength) * Math.PI * 2;
const barLength = radius * percent;
const x1 = centerX + Math.cos(angle) * radius;
const y1 = centerY + Math.sin(angle) * radius;
const x2 = centerX + Math.cos(angle) * (radius + barLength);
const y2 = centerY + Math.sin(angle) * (radius + barLength);
const hue = (i / this.bufferLength) * 360;
this.ctx.strokeStyle = `hsla(${hue}, 100%, 50%, 0.8)`;
this.ctx.lineWidth = 3;
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.stroke();
}
// Draw center circle
this.ctx.beginPath();
this.ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
this.ctx.strokeStyle = `rgba(${this.colors.primary.join(',')}, 0.5)`;
this.ctx.lineWidth = 2;
this.ctx.stroke();
}
/**
* 3D-style Bars
*/
drawBars() {
const width = this.canvas.width;
const height = this.canvas.height;
const barCount = 64;
const barWidth = width / barCount;
for (let i = 0; i < barCount; i++) {
const value = this.dataArray[i * Math.floor(this.bufferLength / barCount)];
const barHeight = (value / 255) * height;
const x = i * barWidth;
const hue = (i / barCount) * 360;
// 3D effect with multiple layers
for (let layer = 0; layer < 3; layer++) {
const offset = layer * 3;
const alpha = 1 - (layer * 0.3);
const gradient = this.ctx.createLinearGradient(0, height, 0, height - barHeight);
gradient.addColorStop(0, `hsla(${hue}, 100%, 50%, ${alpha})`);
gradient.addColorStop(1, `hsla(${hue}, 100%, 70%, ${alpha * 0.5})`);
this.ctx.fillStyle = gradient;
this.ctx.fillRect(
x + offset,
height - barHeight + offset,
barWidth - 2,
barHeight
);
}
}
}
/**
* Particle System - Audio-reactive particles
*/
drawParticles() {
const width = this.canvas.width;
const height = this.canvas.height;
// Create new particles based on audio
const avg = this.dataArray.reduce((a, b) => a + b, 0) / this.bufferLength;
if (avg > 50 && this.particles.length < 200) {
for (let i = 0; i < 5; i++) {
this.particles.push({
x: Math.random() * width,
y: height,
vx: (Math.random() - 0.5) * 4,
vy: -Math.random() * 5 - 2,
size: Math.random() * 4 + 2,
life: 1.0,
color: [
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255)
]
});
}
}
// Update and draw particles
this.particles = this.particles.filter(particle => {
particle.x += particle.vx;
particle.y += particle.vy;
particle.vy += 0.1; // Gravity
particle.life -= 0.01;
if (particle.life <= 0 || particle.y > height) return false;
this.ctx.beginPath();
this.ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(${particle.color.join(',')}, ${particle.life})`;
this.ctx.fill();
// Glow effect
this.ctx.shadowBlur = 15;
this.ctx.shadowColor = `rgba(${particle.color.join(',')}, ${particle.life})`;
this.ctx.fill();
this.ctx.shadowBlur = 0;
return true;
});
// Draw waveform background
this.ctx.globalAlpha = 0.3;
this.drawWaveform();
this.ctx.globalAlpha = 1.0;
}
/**
* Change visualization mode
*/
setMode(mode) {
this.visualizationMode = mode;
}
/**
* Get current audio levels
*/
getAudioLevel() {
const avg = this.dataArray.reduce((a, b) => a + b, 0) / this.bufferLength;
return avg / 255;
}
/**
* Get dominant frequency
*/
getDominantFrequency() {
let maxIndex = 0;
let maxValue = 0;
for (let i = 0; i < this.bufferLength; i++) {
if (this.dataArray[i] > maxValue) {
maxValue = this.dataArray[i];
maxIndex = i;
}
}
const nyquist = this.audioContext.sampleRate / 2;
const frequency = (maxIndex / this.bufferLength) * nyquist;
return frequency;
}
/**
* Resize canvas
*/
resize() {
this.canvas.width = this.canvas.clientWidth * window.devicePixelRatio;
this.canvas.height = this.canvas.clientHeight * window.devicePixelRatio;
}
/**
* Start/stop visualization
*/
start() {
this.isActive = true;
this.render();
}
stop() {
this.isActive = false;
}
}
// Export
if (typeof module !== 'undefined' && module.exports) {
module.exports = AudioVisualizer;
}