Initial commit of WhisperVoice
This commit is contained in:
117
src/ui/visualizer.py
Normal file
117
src/ui/visualizer.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user