97 lines
2.9 KiB
Python
97 lines
2.9 KiB
Python
"""
|
||
vu_meter.py — VU-meter widget der tegner L og R kanaler.
|
||
Opdateres via set_levels(left, right) med værdier 0.0–1.0.
|
||
"""
|
||
|
||
from PyQt6.QtWidgets import QWidget
|
||
from PyQt6.QtCore import Qt, QTimer
|
||
from PyQt6.QtGui import QPainter, QColor
|
||
import random
|
||
|
||
|
||
NUM_BARS = 14
|
||
BAR_W = 14
|
||
BAR_H = 4
|
||
BAR_GAP = 2
|
||
CHAN_GAP = 6
|
||
PADDING = 4
|
||
|
||
COLOR_OFF = QColor("#1a2218")
|
||
COLOR_GREEN = QColor("#28a050")
|
||
COLOR_YELLOW = QColor("#c8a020")
|
||
COLOR_RED = QColor("#c83020")
|
||
|
||
# Grænser for farver (bar-indeks fra bunden)
|
||
YELLOW_FROM = NUM_BARS - 4
|
||
RED_FROM = NUM_BARS - 2
|
||
|
||
|
||
class VUMeter(QWidget):
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
self._left = 0.0
|
||
self._right = 0.0
|
||
self._peak_l = 0.0
|
||
self._peak_r = 0.0
|
||
self._dark = True
|
||
|
||
total_h = NUM_BARS * (BAR_H + BAR_GAP) + PADDING * 2 + 16 # +16 til label
|
||
total_w = (BAR_W + CHAN_GAP) * 2 + PADDING * 2
|
||
self.setFixedSize(total_w, total_h)
|
||
|
||
def set_dark(self, dark: bool):
|
||
self._dark = dark
|
||
self.update()
|
||
|
||
def set_levels(self, left: float, right: float):
|
||
"""Sæt niveauer 0.0–1.0. Kaldes fra afspiller-tråden via signal."""
|
||
self._left = max(0.0, min(1.0, left))
|
||
self._right = max(0.0, min(1.0, right))
|
||
self._peak_l = max(self._peak_l * 0.92, self._left)
|
||
self._peak_r = max(self._peak_r * 0.92, self._right)
|
||
self.update()
|
||
|
||
def reset(self):
|
||
self._left = self._right = self._peak_l = self._peak_r = 0.0
|
||
self.update()
|
||
|
||
def paintEvent(self, event):
|
||
painter = QPainter(self)
|
||
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||
|
||
off_color = QColor("#d0d8cc") if not self._dark else COLOR_OFF
|
||
|
||
for ch_idx, level in enumerate([self._left, self._right]):
|
||
x = PADDING + ch_idx * (BAR_W + CHAN_GAP)
|
||
active_bars = int(level * NUM_BARS)
|
||
|
||
for bar_idx in range(NUM_BARS):
|
||
y = PADDING + (NUM_BARS - 1 - bar_idx) * (BAR_H + BAR_GAP)
|
||
|
||
if bar_idx < active_bars:
|
||
if bar_idx >= RED_FROM:
|
||
color = COLOR_RED
|
||
elif bar_idx >= YELLOW_FROM:
|
||
color = COLOR_YELLOW
|
||
else:
|
||
color = COLOR_GREEN
|
||
else:
|
||
color = off_color
|
||
|
||
painter.fillRect(x, y, BAR_W, BAR_H,
|
||
QColor(color.red(), color.green(), color.blue(), 220))
|
||
|
||
# Kanal-labels
|
||
label_y = PADDING + NUM_BARS * (BAR_H + BAR_GAP) + 4
|
||
painter.setPen(QColor("#5a6070"))
|
||
font = painter.font()
|
||
font.setPointSize(8)
|
||
font.setFamily("Courier New")
|
||
painter.setFont(font)
|
||
|
||
for ch_idx, label in enumerate(["L", "R"]):
|
||
x = PADDING + ch_idx * (BAR_W + CHAN_GAP) + BAR_W // 2
|
||
painter.drawText(x - 4, label_y + 10, label)
|
||
|
||
painter.end()
|