diff --git a/audio_engine.py b/audio_engine.py index d38da8c..fc890a8 100644 --- a/audio_engine.py +++ b/audio_engine.py @@ -532,6 +532,13 @@ class AudioEngine: master_peak = max(np.max(np.abs(master_audio[0])), np.max(np.abs(master_audio[1]))) self.mixer['master'].vu_peak = master_peak + # Apply master volume fader (master bus only – headphone and studio + # maintain independent levels) + vol = self.mixer['master'].volume + if vol < 1.0: + master_buf_L[:] *= vol + master_buf_R[:] *= vol + master = self.mixer['master'] master._lufs_accum += frames if master._lufs_accum >= 512: diff --git a/deck_widget.py b/deck_widget.py index ac0b55a..ad3be56 100644 --- a/deck_widget.py +++ b/deck_widget.py @@ -27,11 +27,11 @@ class LCDDisplay(QFrame): """) layout = QVBoxLayout(self) - layout.setContentsMargins(10, 8, 10, 8) - layout.setSpacing(4) + layout.setContentsMargins(6, 6, 6, 6) + layout.setSpacing(2) self.track_btn = QPushButton("NO TRACK LOADED") - self.track_btn.setFont(QFont("Courier New", 13, QFont.Bold)) + self.track_btn.setFont(QFont("Courier New", 10, QFont.Bold)) self.track_btn.setStyleSheet(""" QPushButton { color: #00ff41; background: transparent; border: none; @@ -46,12 +46,12 @@ class LCDDisplay(QFrame): time_row.setSpacing(4) self.elapsed_label = QLabel("00:00") - self.elapsed_label.setFont(QFont("Courier New", 32, QFont.Bold)) + self.elapsed_label.setFont(QFont("Courier New", 22, QFont.Bold)) self.elapsed_label.setStyleSheet("color: #00ff41; background: transparent;") self.elapsed_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.remaining_label = QLabel("-00:00") - self.remaining_label.setFont(QFont("Courier New", 18, QFont.Bold)) + self.remaining_label.setFont(QFont("Courier New", 13, QFont.Bold)) self.remaining_label.setStyleSheet("color: #00cc33; background: transparent;") self.remaining_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) @@ -62,11 +62,11 @@ class LCDDisplay(QFrame): status_row = QHBoxLayout() self.status_label = QLabel("STOPPED") - self.status_label.setFont(QFont("Courier New", 11, QFont.Bold)) + self.status_label.setFont(QFont("Courier New", 9, QFont.Bold)) self.status_label.setStyleSheet("color: #008822; background: transparent;") self.queue_label = QLabel("QUEUE: EMPTY") - self.queue_label.setFont(QFont("Courier New", 10)) + self.queue_label.setFont(QFont("Courier New", 8)) self.queue_label.setStyleSheet("color: #008822; background: transparent;") self.queue_label.setAlignment(Qt.AlignRight) @@ -175,16 +175,16 @@ class DeckWidget(QWidget): """) root = QVBoxLayout(self) - root.setContentsMargins(10, 10, 10, 10) - root.setSpacing(8) + root.setContentsMargins(6, 6, 6, 6) + root.setSpacing(4) self.header = QLabel(self.deck_label) - self.header.setFont(QFont("Courier New", 24, QFont.Bold)) + self.header.setFont(QFont("Courier New", 16, QFont.Bold)) self.header.setStyleSheet(f""" color: {self.accent_color}; background: transparent; border: none; - padding: 4px; + padding: 2px; """) self.header.setAlignment(Qt.AlignCenter) root.addWidget(self.header) @@ -193,14 +193,14 @@ class DeckWidget(QWidget): root.addWidget(self.lcd) transport = QHBoxLayout() - transport.setSpacing(6) + transport.setSpacing(4) - self.btn_to_start = make_icon_button(icon_skip_start()) - self.btn_back_15 = make_icon_button(icon_skip_back(), icon_color="#aaaaaa") - self.btn_play = make_icon_button(icon_play(), "#1a6b3a", "#00ff41", 68, 48) - self.btn_fwd_15 = make_icon_button(icon_skip_forward(), icon_color="#aaaaaa") - self.btn_to_end = make_icon_button(icon_skip_end()) - self.btn_stop = make_icon_button(icon_stop(), "#8a1a1a", "#ff4444") + self.btn_to_start = make_icon_button(icon_skip_start(), width=44, height=38) + self.btn_back_15 = make_icon_button(icon_skip_back(), icon_color="#aaaaaa", width=44, height=38) + self.btn_play = make_icon_button(icon_play(), "#1a6b3a", "#00ff41", 56, 38) + self.btn_fwd_15 = make_icon_button(icon_skip_forward(), icon_color="#aaaaaa", width=44, height=38) + self.btn_to_end = make_icon_button(icon_skip_end(), width=44, height=38) + self.btn_stop = make_icon_button(icon_stop(), "#8a1a1a", "#ff4444", width=44, height=38) transport.addWidget(self.btn_to_start) transport.addWidget(self.btn_back_15) @@ -450,7 +450,7 @@ class DeckWidget(QWidget): color: {flash_color}; background: transparent; border: none; - padding: 4px; + padding: 2px; """) self.lcd.flash_warning(self.flash_state) else: @@ -458,7 +458,7 @@ class DeckWidget(QWidget): color: {self.accent_color}; background: transparent; border: none; - padding: 4px; + padding: 2px; """) self.lcd.flash_warning(False) diff --git a/main.py b/main.py index 341693b..2256fe6 100644 --- a/main.py +++ b/main.py @@ -60,7 +60,7 @@ class RadioPanelWindow(QMainWindow): self.deck4 = DeckWidget("deck4", "TURN_002", "#e17055", self.engine, mode='turn') self.cart_bank = CartBankWidget(self.engine) - self.cart_bank.setFixedHeight(180) + self.cart_bank.setFixedHeight(150) self.playlist_widget = PlaylistWidget( engine=self.engine, @@ -194,7 +194,6 @@ class RadioPanelWindow(QMainWindow): 'name': ch.name, 'volume': ch.volume, 'muted': ch.muted, - 'solo': ch.solo, 'pfl': ch.pfl, 'mic_on': ch.mic_on, }) @@ -240,8 +239,9 @@ class RadioPanelWindow(QMainWindow): self.midi.cart_trigger.connect(self._on_midi_cart) self.midi.mixer_volume.connect(self._on_midi_mixer_volume) self.midi.mixer_mute.connect(self._on_midi_mixer_mute) - self.midi.mixer_solo.connect(self._on_midi_mixer_solo) self.midi.mixer_pfl.connect(self._on_midi_mixer_pfl) + self.midi.mixer_mic_on.connect(self._on_midi_mixer_mic_on) + self.midi.mixer_mic_on.connect(self._on_midi_mixer_mic_on) self.midi.master_control.connect(self._on_midi_master_control) self.midi.master_volume.connect(self._on_midi_master_volume) self.midi.controller_connected.connect(self._on_midi_status) @@ -284,12 +284,13 @@ class RadioPanelWindow(QMainWindow): def _on_midi_mixer_mute(self, channel: int, muted: bool): self.engine.set_channel_mute(channel, muted) - def _on_midi_mixer_solo(self, channel: int, on: bool): - self.engine.set_channel_solo(channel, on) - def _on_midi_mixer_pfl(self, channel: int, on: bool): self.engine.set_channel_pfl(channel, on) + def _on_midi_mixer_mic_on(self, channel: int, on: bool): + if channel < 2: + self.engine.set_channel_mic_on(channel, on) + def _on_midi_master_control(self, knob: str, val: float): master = self.engine.mixer['master'] attrs = { diff --git a/midi_engine.py b/midi_engine.py index 0e9439c..1d6358d 100644 --- a/midi_engine.py +++ b/midi_engine.py @@ -94,6 +94,7 @@ class MidiEngine(QObject): mixer_mute = Signal(int, bool) mixer_solo = Signal(int, bool) mixer_pfl = Signal(int, bool) + mixer_mic_on = Signal(int, bool) master_control = Signal(str, float) master_volume = Signal(float) controller_connected = Signal(bool, str) @@ -282,6 +283,9 @@ class MidiEngine(QObject): elif action == 'mixer_pfl': on = (value > 63) if not inv else (value < 64) self.mixer_pfl.emit(target_id, on) + elif action == 'mixer_mic_on': + on = (value > 63) if not inv else (value < 64) + self.mixer_mic_on.emit(target_id, on) elif action == 'master_control': knob = str(target_id) if is_rel and 1 <= value <= 63: diff --git a/mixer_widget.py b/mixer_widget.py index 81ff24a..2a07c5a 100644 --- a/mixer_widget.py +++ b/mixer_widget.py @@ -9,7 +9,7 @@ from PySide6.QtCore import Qt, QTimer, QSize from PySide6.QtGui import QFont, QPainter, QColor, QLinearGradient, QPen from audio_engine import NUM_MIXER_CHANNELS -from icons import icon_mute, icon_solo, icon_mic +from icons import icon_mute, icon_mic import math @@ -43,13 +43,13 @@ class VUMeter(QWidget): 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.setFont(QFont("Segoe UI", 9, 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.setFont(QFont("Segoe UI", 8)) painter.drawText(rect.left() - 16, y + 3, f"{db}") painter.setPen(QPen(QColor("#1a1a1a"), 1)) @@ -93,7 +93,7 @@ class ChannelStrip(QFrame): self.channel_index = channel_index self._channel = engine.get_channel(channel_index) - self.setFixedWidth(90) + self.setFixedWidth(100) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.setStyleSheet(""" ChannelStrip { @@ -117,14 +117,14 @@ class ChannelStrip(QFrame): root.setSpacing(4) self.name_btn = QPushButton(self._channel.name) - self.name_btn.setFont(QFont("Segoe UI", 8, QFont.Bold)) + self.name_btn.setFont(QFont("Segoe UI", 9, QFont.Bold)) self.name_btn.setStyleSheet(""" QPushButton { background-color: transparent; color: #999aaa; border: none; padding: 2px; - font-size: 8pt; + font-size: 9pt; } QPushButton:hover { color: #ffffff; @@ -174,6 +174,8 @@ class ChannelStrip(QFrame): btn_row = QHBoxLayout() btn_row.setSpacing(3) + is_mic = self.channel_index < 2 + self.mute_btn = QPushButton() self.mute_btn.setFixedSize(28, 24) self.mute_btn.setIconSize(QSize(16, 16)) @@ -192,28 +194,9 @@ class ChannelStrip(QFrame): } QPushButton:hover { background-color: #343036; } """) + self.mute_btn.setVisible(not is_mic) btn_row.addWidget(self.mute_btn) - self.solo_btn = QPushButton() - self.solo_btn.setFixedSize(28, 24) - self.solo_btn.setIconSize(QSize(16, 16)) - self.solo_btn.setIcon(icon_solo()) - self.solo_btn.setCheckable(True) - self.solo_btn.setToolTip("Solo") - self.solo_btn.setStyleSheet(""" - QPushButton { - background-color: #262420; - border: 1px solid #3a3830; - border-radius: 3px; - } - QPushButton:checked { - background-color: #4a4a1a; - border: 1px solid #ffaa00; - } - QPushButton:hover { background-color: #363430; } - """) - btn_row.addWidget(self.solo_btn) - # Mic ON/OFF button for channels 0 and 1 self.mic_btn = QPushButton() self.mic_btn.setFixedSize(28, 24) @@ -233,12 +216,12 @@ class ChannelStrip(QFrame): } QPushButton:hover { background-color: #303436; } """) - self.mic_btn.setVisible(self.channel_index < 2) + self.mic_btn.setVisible(is_mic) btn_row.addWidget(self.mic_btn) self.pfl_btn = QPushButton("PFL") self.pfl_btn.setFixedSize(28, 24) - self.pfl_btn.setFont(QFont("Segoe UI", 7, QFont.Bold)) + self.pfl_btn.setFont(QFont("Segoe UI", 8, QFont.Bold)) self.pfl_btn.setCheckable(True) self.pfl_btn.setToolTip("Pre-Fader Listen") self.pfl_btn.setStyleSheet(""" @@ -263,7 +246,6 @@ class ChannelStrip(QFrame): self.name_btn.clicked.connect(self._rename) self.volume_slider.valueChanged.connect(self._on_volume_changed) self.mute_btn.toggled.connect(self._on_mute_toggled) - self.solo_btn.toggled.connect(self._on_solo_toggled) self.mic_btn.toggled.connect(self._on_mic_toggled) self.pfl_btn.toggled.connect(self._on_pfl_toggled) @@ -283,9 +265,6 @@ class ChannelStrip(QFrame): def _on_mute_toggled(self, checked: bool): self.engine.set_channel_mute(self.channel_index, checked) - def _on_solo_toggled(self, checked: bool): - self.engine.set_channel_solo(self.channel_index, checked) - def _on_pfl_toggled(self, checked: bool): self.engine.set_channel_pfl(self.channel_index, checked) @@ -331,7 +310,7 @@ class MasterPreSection(QFrame): root.setSpacing(4) header = QLabel("MASTER") - header.setFont(QFont("Segoe UI", 8, QFont.Bold)) + header.setFont(QFont("Segoe UI", 10, QFont.Bold)) header.setAlignment(Qt.AlignCenter) header.setStyleSheet("color: #888; background: transparent; border: none;") root.addWidget(header) @@ -399,7 +378,7 @@ class EffectSection(QFrame): root.setSpacing(2) header = QLabel("FX") - header.setFont(QFont("Segoe UI", 8, QFont.Bold)) + header.setFont(QFont("Segoe UI", 10, QFont.Bold)) header.setAlignment(Qt.AlignCenter) header.setStyleSheet("color: #556670; background: transparent; border: none;") root.addWidget(header) @@ -411,19 +390,19 @@ class EffectSection(QFrame): lufs_layout.setSpacing(2) self.lufs_value = QLabel("-70.0") - self.lufs_value.setFont(QFont("Segoe UI", 13, QFont.Bold)) + self.lufs_value.setFont(QFont("Segoe UI", 14, QFont.Bold)) self.lufs_value.setAlignment(Qt.AlignCenter) self.lufs_value.setStyleSheet("color: #00cc88; background: transparent; border: none;") lufs_layout.addWidget(self.lufs_value) lufs_unit = QLabel("LUFS") - lufs_unit.setFont(QFont("Segoe UI", 6)) + lufs_unit.setFont(QFont("Segoe UI", 7)) lufs_unit.setAlignment(Qt.AlignCenter) lufs_unit.setStyleSheet("color: #556; background: transparent; border: none;") lufs_layout.addWidget(lufs_unit) self.pfl_indicator = QLabel("PFL\n—") - self.pfl_indicator.setFont(QFont("Segoe UI", 5)) + self.pfl_indicator.setFont(QFont("Segoe UI", 7)) self.pfl_indicator.setAlignment(Qt.AlignCenter) self.pfl_indicator.setStyleSheet("color: #556; background: transparent; border: none;") lufs_layout.addWidget(self.pfl_indicator) @@ -490,12 +469,12 @@ class EffectSection(QFrame): dial.setValue(_val_to_pos(default)) lbl = QLabel(label) - lbl.setFont(QFont("Segoe UI", 8, QFont.Bold)) + lbl.setFont(QFont("Segoe UI", 9, QFont.Bold)) lbl.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) lbl.setStyleSheet("color: #889; background: transparent; border: none;") val_label = QLabel(f"{default}{suffix}") - val_label.setFont(QFont("Segoe UI", 7)) + val_label.setFont(QFont("Segoe UI", 8)) val_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) val_label.setStyleSheet("color: #667; background: transparent; border: none;") @@ -561,7 +540,7 @@ class MixerWidget(QFrame): root.setSpacing(4) header = QLabel("MIXER") - header.setFont(QFont("Segoe UI", 9, QFont.Bold)) + header.setFont(QFont("Segoe UI", 11, QFont.Bold)) header.setStyleSheet("color: #556670; background: transparent; border: none; " "letter-spacing: 2px;") root.addWidget(header) @@ -623,5 +602,4 @@ class MixerWidget(QFrame): strip.name_btn.setText(ch.name) strip.volume_slider.setValue(int(ch.volume * 100)) strip.mute_btn.setChecked(ch.muted) - strip.solo_btn.setChecked(ch.solo) strip.pfl_btn.setChecked(ch.pfl) \ No newline at end of file diff --git a/top_bar_widget.py b/top_bar_widget.py index 6c21a46..ff670a4 100644 --- a/top_bar_widget.py +++ b/top_bar_widget.py @@ -198,7 +198,7 @@ POPUP_STYLE = """ border: 1px solid #3a3c44; border-radius: 3px; padding: 3px 8px; - font-size: 7pt; + font-size: 9pt; font-weight: bold; } QPushButton#popupBtn:hover { @@ -211,7 +211,7 @@ POPUP_STYLE = """ border: 1px solid #3a3c44; border-radius: 12px; padding: 2px 10px; - font-size: 7pt; + font-size: 9pt; font-weight: bold; } QPushButton#ratioBtn:hover { @@ -224,8 +224,8 @@ POPUP_STYLE = """ border: 1px solid #3a3c44; border-radius: 3px; padding: 2px 4px; - font-size: 7pt; - min-height: 20px; + font-size: 9pt; + min-height: 24px; } QComboBox#portCombo:hover { border-color: #5a5c64; } QComboBox#portCombo::drop-down { border: none; width: 14px; } @@ -253,65 +253,85 @@ class SettingsPopup(QFrame): self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint) self.setObjectName("settingsPopup") self.setStyleSheet(POPUP_STYLE) - self.setFixedWidth(400) + self.setFixedWidth(620) self._build_ui() def _build_ui(self): root = QVBoxLayout(self) - root.setContentsMargins(12, 10, 12, 10) - root.setSpacing(6) + root.setContentsMargins(14, 12, 14, 12) + root.setSpacing(8) - # Row 1: Save/Load + # Row 1: Save/Load / Clear MIDI row1 = QHBoxLayout() - row1.setSpacing(6) + row1.setSpacing(8) save_btn = QPushButton("SAVE") save_btn.setObjectName("popupBtn") - save_btn.setFixedHeight(24) + save_btn.setFixedHeight(30) save_btn.clicked.connect(self.save_session.emit) row1.addWidget(save_btn) load_btn = QPushButton("LOAD") load_btn.setObjectName("popupBtn") - load_btn.setFixedHeight(24) + load_btn.setFixedHeight(30) load_btn.clicked.connect(self.load_session.emit) row1.addWidget(load_btn) + row1.addStretch() + + clear_midi_btn = QPushButton("CLEAR MIDI") + clear_midi_btn.setObjectName("popupBtn") + clear_midi_btn.setFixedHeight(30) + clear_midi_btn.setStyleSheet(""" + QPushButton { + background-color: #3a1a1a; + color: #ff6666; + border: 1px solid #5a2a2a; + border-radius: 3px; + font-size: 9pt; + font-weight: bold; + padding: 3px 8px; + } + QPushButton:hover { background-color: #5a2a2a; } + """) + clear_midi_btn.clicked.connect(self._clear_all_midi) + row1.addWidget(clear_midi_btn) + root.addLayout(row1) # Row 2: MIDI port row2 = QHBoxLayout() - row2.setSpacing(4) + row2.setSpacing(6) self._port_combo = QComboBox() self._port_combo.setObjectName("portCombo") - self._port_combo.setMinimumWidth(160) + self._port_combo.setMinimumWidth(200) row2.addWidget(self._port_combo) refresh_btn = QPushButton("⟳") refresh_btn.setObjectName("popupBtn") - refresh_btn.setFixedSize(26, 22) + refresh_btn.setFixedSize(30, 26) refresh_btn.clicked.connect(self._refresh_ports) row2.addWidget(refresh_btn) self._connect_btn = QPushButton("CONNECT") self._connect_btn.setObjectName("popupBtn") - self._connect_btn.setFixedHeight(22) + self._connect_btn.setFixedHeight(26) self._connect_btn.clicked.connect(self._connect_midi) row2.addWidget(self._connect_btn) self._midi_status = QLabel("") - self._midi_status.setStyleSheet("color: #888; background: transparent; border: none; font-size: 7pt;") + self._midi_status.setStyleSheet("color: #888; background: transparent; border: none; font-size: 9pt;") row2.addWidget(self._midi_status, stretch=1) root.addLayout(row2) # Row 3: MIDI learn scroll learn_label = QLabel("MIDI LEARN") - learn_label.setStyleSheet("color: #00b894; background: transparent; border: none; font-size: 7pt; font-weight: bold; padding-top: 2px;") + learn_label.setStyleSheet("color: #00b894; background: transparent; border: none; font-size: 10pt; font-weight: bold; padding-top: 4px;") root.addWidget(learn_label) scroll = QScrollArea() scroll.setWidgetResizable(True) - scroll.setFixedHeight(200) + scroll.setFixedHeight(400) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setStyleSheet(POPUP_STYLE) @@ -319,7 +339,7 @@ class SettingsPopup(QFrame): content.setStyleSheet("background: transparent;") grid = QVBoxLayout(content) grid.setContentsMargins(0, 0, 0, 0) - grid.setSpacing(2) + grid.setSpacing(4) learn_actions = [ ("Deck 1 Play/Pause", "deck_play_pause", "deck1"), @@ -340,14 +360,22 @@ class SettingsPopup(QFrame): ("Ch 6 Volume", "mixer_volume", 5), ("Ch 7 Volume", "mixer_volume", 6), ("Ch 8 Volume", "mixer_volume", 7), - ("Ch 1 Solo", "mixer_solo", 0), + ("Ch 1 Mic On", "mixer_mic_on", 0), + ("Ch 2 Mic On", "mixer_mic_on", 1), ("Ch 1 PFL", "mixer_pfl", 0), - ("Ch 2 Solo", "mixer_solo", 1), ("Ch 2 PFL", "mixer_pfl", 1), - ("Ch 3 Solo", "mixer_solo", 2), ("Ch 3 PFL", "mixer_pfl", 2), - ("Ch 4 Solo", "mixer_solo", 3), ("Ch 4 PFL", "mixer_pfl", 3), + ("Ch 5 PFL", "mixer_pfl", 4), + ("Ch 6 PFL", "mixer_pfl", 5), + ("Ch 7 PFL", "mixer_pfl", 6), + ("Ch 8 PFL", "mixer_pfl", 7), + ("Ch 3 Mute", "mixer_mute", 2), + ("Ch 4 Mute", "mixer_mute", 3), + ("Ch 5 Mute", "mixer_mute", 4), + ("Ch 6 Mute", "mixer_mute", 5), + ("Ch 7 Mute", "mixer_mute", 6), + ("Ch 8 Mute", "mixer_mute", 7), ("Master THR", "master_control", "threshold_db"), ("Master RAT", "master_control", "ratio"), ("Master ATK", "master_control", "attack_ms"), @@ -363,12 +391,12 @@ class SettingsPopup(QFrame): row.setSpacing(3) lbl = QLabel(label) - lbl.setStyleSheet("color: #d0d4dc; background: transparent; border: none; font-size: 7pt;") + lbl.setStyleSheet("color: #d0d4dc; background: transparent; border: none; font-size: 9pt;") row.addWidget(lbl, stretch=1) btn = QPushButton("LEARN") btn.setObjectName("popupBtn") - btn.setFixedSize(52, 20) + btn.setFixedSize(64, 24) btn.setCheckable(True) btn.toggled.connect(partial(self._toggle_learn, btn, action, target_id)) row.addWidget(btn) @@ -382,13 +410,13 @@ class SettingsPopup(QFrame): color: #ff6666; border: 1px solid #5a2a2a; border-radius: 3px; - font-size: 7pt; + font-size: 9pt; font-weight: bold; padding: 2px 4px; } QPushButton:hover { background-color: #5a2a2a; } """) - clear_btn.setFixedSize(20, 20) + clear_btn.setFixedSize(28, 24) clear_btn.clicked.connect(partial(self._clear_mapping, action, target_id)) row.addWidget(clear_btn) @@ -398,18 +426,18 @@ QPushButton:hover { background-color: #5a2a2a; } root.addWidget(scroll) monitor_label = QLabel("MIDI MONITOR") - monitor_label.setStyleSheet("color: #556670; background: transparent; border: none; font-size: 7pt; font-weight: bold;") + monitor_label.setStyleSheet("color: #556670; background: transparent; border: none; font-size: 9pt; font-weight: bold;") root.addWidget(monitor_label) self._midi_monitor = QListWidget() - self._midi_monitor.setFixedHeight(80) + self._midi_monitor.setFixedHeight(120) self._midi_monitor.setStyleSheet(""" QListWidget { background-color: #0d0e12; border: 1px solid #22242a; border-radius: 3px; color: #8890a0; - font-size: 7pt; + font-size: 9pt; font-family: monospace; } """) @@ -453,10 +481,10 @@ QPushButton:hover { background-color: #5a2a2a; } success = self._midi_engine.start(port_index=idx) if success: self._midi_status.setText(f"Connected") - self._midi_status.setStyleSheet("color: #00b894; background: transparent; border: none; font-size: 7pt;") + self._midi_status.setStyleSheet("color: #00b894; background: transparent; border: none; font-size: 9pt;") else: self._midi_status.setText("Failed") - self._midi_status.setStyleSheet("color: #ff6666; background: transparent; border: none; font-size: 7pt;") + self._midi_status.setStyleSheet("color: #ff6666; background: transparent; border: none; font-size: 9pt;") # ── MIDI learn ───────────────────────────────────────────────── @@ -485,6 +513,18 @@ QPushButton:hover { background-color: #5a2a2a; } del self._midi_engine.mapping.bindings[key] self._midi_engine.mapping.save() + def _clear_all_midi(self): + if not self._midi_engine: + return + self._midi_engine.mapping.bindings.clear() + self._midi_engine.mapping.save() + + def _clear_all_midi(self): + if not self._midi_engine: + return + self._midi_engine.mapping.bindings.clear() + self._midi_engine.mapping.save() + def _on_mapping_learned(self, action, target_id, midi_type, channel, note, value): btn = self._learn_btns.get((action, target_id)) if btn and btn.isChecked():