v0.4 - cockybastard
This commit is contained in:
+60
-21
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user