UNPKG

win-stream-audio

Version:

🎧 Stream Windows system audio to Android devices over WiFi with professional audio controls, EQ, pitch shifting, and effects

113 lines (90 loc) • 4.04 kB
/** * AudioPilot - Visualization Module * Handles waveform display and VU meters */ class AudioVisualizer { constructor(canvasElement, leftMeterElement, rightMeterElement) { this.canvas = canvasElement; this.ctx = canvasElement.getContext('2d'); this.leftMeter = leftMeterElement; this.rightMeter = rightMeterElement; this.animationId = null; this.setupCanvas(); this.startVisualization(); } setupCanvas() { const resizeCanvas = () => { this.canvas.width = this.canvas.offsetWidth; this.canvas.height = this.canvas.offsetHeight; }; resizeCanvas(); window.addEventListener('resize', resizeCanvas); } startVisualization() { const drawVisualization = () => { // Clear canvas with fade effect this.ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); // Get audio processor instance const audioProcessor = window.audioProcessorInstance; if (audioProcessor && audioProcessor.analyser && audioProcessor.dataArray) { audioProcessor.analyser.getByteFrequencyData(audioProcessor.dataArray); this.drawFrequencyBars(audioProcessor.dataArray); this.updateVUMeters(audioProcessor.dataArray); } this.animationId = requestAnimationFrame(drawVisualization); }; drawVisualization(); } drawFrequencyBars(dataArray) { const barWidth = this.canvas.width / dataArray.length; let x = 0; for (let i = 0; i < dataArray.length; i++) { const barHeight = (dataArray[i] / 255) * this.canvas.height; // Create gradient based on frequency const gradient = this.ctx.createLinearGradient(0, this.canvas.height, 0, this.canvas.height - barHeight); gradient.addColorStop(0, '#00ff41'); gradient.addColorStop(0.5, '#ffff00'); gradient.addColorStop(1, '#ff6b35'); this.ctx.fillStyle = gradient; this.ctx.fillRect(x, this.canvas.height - barHeight, barWidth, barHeight); x += barWidth; } } updateVUMeters(dataArray) { if (!dataArray || dataArray.length === 0) return; // Calculate average levels for left and right channels const leftLevel = this.calculateChannelLevel(0, dataArray.length / 2, dataArray); const rightLevel = this.calculateChannelLevel(dataArray.length / 2, dataArray.length, dataArray); // Update meter backgrounds with gradient const leftGradient = `linear-gradient(to top, rgba(0,0,0,0.8) ${100-leftLevel}%, #00ff41 ${100-leftLevel}%, #ffff00 ${Math.max(0, 100-leftLevel-20)}%, #ff6b35 ${Math.max(0, 100-leftLevel-40)}%, #ff0000 ${Math.max(0, 100-leftLevel-60)}%)`; const rightGradient = `linear-gradient(to top, rgba(0,0,0,0.8) ${100-rightLevel}%, #00ff41 ${100-rightLevel}%, #ffff00 ${Math.max(0, 100-rightLevel-20)}%, #ff6b35 ${Math.max(0, 100-rightLevel-40)}%, #ff0000 ${Math.max(0, 100-rightLevel-60)}%)`; this.leftMeter.style.background = leftGradient; this.rightMeter.style.background = rightGradient; } calculateChannelLevel(start, end, dataArray) { let sum = 0; for (let i = start; i < end; i++) { sum += dataArray[i]; } return (sum / (end - start)) / 255 * 100; } destroy() { if (this.animationId) { cancelAnimationFrame(this.animationId); this.animationId = null; } } } // Export for use in other modules window.AudioVisualizer = AudioVisualizer;