""" Audio Visualizer Module. ======================== High-Fidelity rendering for the 2026 Premium UI. Supports 'Classic Bars' and 'Neon Line' with smooth curves and glows. """ from PySide6.QtWidgets import QWidget from PySide6.QtCore import Qt, QTimer, Slot, QRectF, QPointF from PySide6.QtGui import QPainter, QBrush, QColor, QPainterPath, QPen, QLinearGradient import random from src.ui.styles import Theme class AudioVisualizer(QWidget): """ A premium audio visualizer with smooth physics and neon aesthetics. """ def __init__(self, parent=None): super().__init__(parent) self.amplitude = 0.0 self.bars = 12 self.history = [0.0] * self.bars # High-refresh timer for silky smooth motion self.timer = QTimer(self) self.timer.timeout.connect(self.update_animation) self.timer.start(16) # ~60 FPS @Slot(float) def set_amplitude(self, amp: float): self.amplitude = amp def update_animation(self): self.history.pop(0) # Smooth interpolation + noise jitter = random.uniform(0.01, 0.03) # Decay logic: Gravity-like pull self.history.append(max(self.amplitude, jitter)) self.update() def paintEvent(self, event): from src.core.config import ConfigManager style = ConfigManager().get("visualizer_style") painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) w, h = self.width(), self.height() painter.translate(0, h / 2) if style == "bar": self._draw_bars(painter, w, h) else: self._draw_line(painter, w, h) def _draw_bars(self, painter, w, h): bar_w = w / self.bars spacing = 3 for i, val in enumerate(self.history): bar_h = val * (h * 0.9) x = i * bar_w # Gradient Bar grad = QLinearGradient(0, -bar_h/2, 0, bar_h/2) grad.setColorAt(0, QColor(Theme.ACCENT_PURPLE)) grad.setColorAt(1, QColor(Theme.ACCENT_CYAN)) painter.setBrush(grad) painter.setPen(Qt.NoPen) painter.drawRoundedRect(QRectF(x + spacing, -bar_h/2, bar_w - spacing*2, bar_h), 3, 3) def _draw_line(self, painter, w, h): path = QPainterPath() points = len(self.history) dx = w / (points - 1) path.moveTo(0, 0) def get_path(multi): p = QPainterPath() p.moveTo(0, 0) for i in range(points): curr_x = i * dx curr_y = -self.history[i] * (h * 0.45) * multi if i == 0: p.moveTo(curr_x, curr_y) else: prev_x = (i-1) * dx # Simple lerp or quadTo for smoothness p.lineTo(curr_x, curr_y) return p # Draw Top & Bottom p_top = get_path(1) p_bot = get_path(-1) # Glow layer glow_pen = QPen(QColor(Theme.ACCENT_CYAN)) glow_pen.setWidth(4) glow_alpha = QColor(Theme.ACCENT_CYAN) glow_alpha.setAlpha(60) glow_pen.setColor(glow_alpha) painter.setPen(glow_pen) painter.drawPath(p_top) painter.drawPath(p_bot) # Core layer core_pen = QPen(Qt.white) core_pen.setWidth(2) painter.setPen(core_pen) painter.drawPath(p_top) painter.drawPath(p_bot)