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
JavaScript
/**
* 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;