v0.4 - cockybastard

This commit is contained in:
2026-05-13 20:53:15 +10:00
parent 7de0cc3de0
commit 6067f442b0
5 changed files with 174 additions and 87 deletions
+60 -21
View File
@@ -10,6 +10,7 @@ from PySide6.QtGui import QFont, QPainter, QColor, QLinearGradient, QPen
from audio_engine import NUM_MIXER_CHANNELS
from icons import icon_mute, icon_solo
import math
class VUMeter(QWidget):
@@ -27,23 +28,29 @@ class VUMeter(QWidget):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
rect = self.rect().adjusted(14, 3, -3, -3)
rect = self.rect().adjusted(18, 3, -3, -3)
if rect.width() < 1 or rect.height() < 1:
painter.end()
return
painter.fillRect(rect, QColor("#080808"))
db_markings = [(-40, "#1a1a1a"), (-30, "#1a1a1a"), (-20, "#1a1a1a"),
(-12, "#2a2a1a"), (-6, "#2a1a1a"), (0, "#2a0a0a")]
for db, color in db_markings:
db_markings = [(-40,), (-30,), (-20,), (-12,), (-6,), (0,)]
for (db,) in db_markings:
pct = (db + 46) / 46.0 if db <= 0 else 1.0
pct = max(0.0, min(1.0, pct))
y = rect.bottom() - int(rect.height() * pct)
painter.setPen(QPen(QColor(color), 1))
painter.drawLine(rect.right() - 5, y, rect.right(), y)
painter.setPen(QPen(QColor("#444444"), 1))
painter.drawText(rect.left() - 13, y + 4, f"{db}")
if db == -6:
painter.setPen(QPen(QColor("#00ff88"), 2))
painter.drawLine(rect.right() - 3, y, rect.right(), y)
painter.setFont(QFont("Segoe UI", 8, QFont.Bold))
painter.setPen(QPen(QColor("#ffffff"), 1))
else:
painter.setPen(QPen(QColor("#2a2a2a"), 1))
painter.drawLine(rect.right() - 5, y, rect.right(), y)
painter.setPen(QPen(QColor("#cccccc"), 1))
painter.setFont(QFont("Segoe UI", 7))
painter.drawText(rect.left() - 16, y + 3, f"{db}")
painter.setPen(QPen(QColor("#1a1a1a"), 1))
painter.drawRect(rect)
@@ -63,12 +70,13 @@ class VUMeter(QWidget):
db = -46 * (1 - val) if val < 1.0 else 3
fill_pct = (db + 46) / 49.0 if db <= 0 else 1.0
fill_pct = max(0.0, min(1.0, fill_pct))
fill_pct = math.sqrt(fill_pct)
fill_h = int(rect.height() * fill_pct)
painter.fillRect(rect.x(), rect.bottom() - fill_h,
rect.width(), fill_h, gradient)
for db, _ in db_markings:
for (db,) in db_markings:
pct = (db + 46) / 46.0 if db <= 0 else 1.0
pct = max(0.0, min(1.0, pct))
y = rect.bottom() - int(rect.height() * pct)
@@ -99,7 +107,7 @@ class ChannelStrip(QFrame):
self._connect_signals()
self.timer = QTimer(self)
self.timer.setInterval(80)
self.timer.setInterval(30)
self.timer.timeout.connect(self._refresh)
self.timer.start()
@@ -126,13 +134,15 @@ class ChannelStrip(QFrame):
""")
root.addWidget(self.name_btn)
meter_row = QHBoxLayout()
meter_row.setSpacing(2)
self.vu_meter = VUMeter()
root.addWidget(self.vu_meter, stretch=1)
meter_row.addWidget(self.vu_meter, stretch=1)
self.volume_slider = QSlider(Qt.Vertical)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(100)
self.volume_slider.setFixedHeight(60)
self.volume_slider.setValue(int(math.sqrt(self._channel.volume) * 100))
self.volume_slider.setStyleSheet("""
QSlider::groove:vertical {
background: #22242a;
@@ -147,13 +157,19 @@ class ChannelStrip(QFrame):
border-radius: 2px;
}
QSlider::handle:vertical:hover { background: #b0b8c8; }
QSlider::sub-page:vertical {
QSlider::add-page:vertical {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #00cc66, stop:1 #008844);
border-radius: 2px;
}
QSlider::sub-page:vertical {
background: transparent;
border-radius: 2px;
}
""")
root.addWidget(self.volume_slider, alignment=Qt.AlignCenter)
meter_row.addWidget(self.volume_slider, stretch=1)
root.addLayout(meter_row, stretch=1)
btn_row = QHBoxLayout()
btn_row.setSpacing(3)
@@ -238,7 +254,8 @@ class ChannelStrip(QFrame):
self.name_btn.setText(self._channel.name)
def _on_volume_changed(self, value: int):
self.engine.set_channel_volume(self.channel_index, value / 100.0)
vol = (value / 100.0) ** 2
self.engine.set_channel_volume(self.channel_index, vol)
def _on_mute_toggled(self, checked: bool):
self.engine.set_channel_mute(self.channel_index, checked)
@@ -251,6 +268,8 @@ class ChannelStrip(QFrame):
def _refresh(self):
self.vu_meter.set_value(self._channel.vu_peak)
self.volume_slider.setValue(int(math.sqrt(self._channel.volume) * 100))
self.volume_slider.setValue(int(math.sqrt(self._channel.volume) * 100))
def apply_theme(self, theme: dict):
pass
@@ -262,8 +281,10 @@ class MasterSection(QFrame):
self.engine = engine
self._master = engine.mixer['master']
self._knobs = {}
self.setMinimumWidth(180)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.setStyleSheet("""
MasterSection {
background-color: #181a1e;
@@ -276,7 +297,7 @@ class MasterSection(QFrame):
self._connect_signals()
self.timer = QTimer(self)
self.timer.setInterval(80)
self.timer.setInterval(30)
self.timer.timeout.connect(self._refresh)
self.timer.start()
@@ -355,9 +376,10 @@ class MasterSection(QFrame):
("REL", "release_ms", 100, 10, 1000, "ms"),
("MKG", "makeup_gain_db", 0, 0, 24, "dB"),
]:
k = self._make_knob(label, self._master.compressor, attr,
k, dial, val_label = self._make_knob(label, self._master.compressor, attr,
default, lo, hi, suffix)
knobs.addWidget(k)
self._knobs[('compressor', attr)] = (dial, val_label, lo, hi, suffix)
comp_layout.addLayout(knobs)
root.addWidget(comp_frame)
@@ -402,9 +424,10 @@ class MasterSection(QFrame):
lim_knobs = QHBoxLayout()
lim_knobs.setSpacing(4)
k = self._make_knob("CEIL", self._master.limiter, "ceiling_db",
k, dial, val_label = self._make_knob("CEIL", self._master.limiter, "ceiling_db",
-0.1, -10, 0, "dB")
lim_knobs.addWidget(k)
self._knobs[('limiter', 'ceiling_db')] = (dial, val_label, -10, 0, "dB")
lim_layout.addLayout(lim_knobs)
root.addWidget(lim_frame)
root.addStretch()
@@ -467,7 +490,7 @@ class MasterSection(QFrame):
dial.valueChanged.connect(_on_dial)
layout.addWidget(dial, alignment=Qt.AlignCenter)
layout.addWidget(val_label)
return frame
return frame, dial, val_label
def _connect_signals(self):
self.comp_bypass.toggled.connect(
@@ -493,6 +516,22 @@ class MasterSection(QFrame):
"color: #556; background: transparent; border: none;"
)
for (section, attr), (dial, val_label, lo, hi, suffix) in self._knobs.items():
obj = self._master.compressor if section == 'compressor' else self._master.limiter
val = getattr(obj, attr, lo)
dial.blockSignals(True)
dial.setValue(int((val - lo) / (hi - lo) * 1000))
dial.blockSignals(False)
val_label.setText(f"{val}{suffix}")
for (section, attr), (dial, val_label, lo, hi, suffix) in self._knobs.items():
obj = self._master.compressor if section == 'compressor' else self._master.limiter
val = getattr(obj, attr, lo)
dial.blockSignals(True)
dial.setValue(int((val - lo) / (hi - lo) * 1000))
dial.blockSignals(False)
val_label.setText(f"{val}{suffix}")
def apply_theme(self, theme: dict):
pass