Add 8-channel mixer with master compressor/limiter, MIDI learn system, separate deck outputs
- Mixer: 8 renamable stereo input channels with VU meter, volume fader, mute/solo - Master bus: compressor (threshold, ratio, attack, release, makeup) + limiter (ceiling), LUFS metering - Decks/carts keep their own JACK outputs, completely separate from mixer - MIDI learn: configurable bindings saved to ~/.gti_radiostudio/midi_map.json - mixer_widget.py: QDial-based DSP controls, scrollable channel strips
This commit is contained in:
@@ -15,7 +15,7 @@ from playlist_widget import PlaylistWidget
|
||||
from midi_engine import MidiEngine
|
||||
from top_bar_widget import TopBarWidget, THEMES
|
||||
from history_widget import HistoryWidget
|
||||
from lufs_meter_widget import LUFSMeterWidget
|
||||
from mixer_widget import MixerWidget
|
||||
|
||||
|
||||
class RadioPanelWindow(QMainWindow):
|
||||
@@ -70,29 +70,30 @@ class RadioPanelWindow(QMainWindow):
|
||||
|
||||
self.history_widget = HistoryWidget()
|
||||
|
||||
self.lufs_meter = LUFSMeterWidget(self.engine)
|
||||
self.mixer = MixerWidget(self.engine)
|
||||
|
||||
# ── Centre column ─────────────────────────────────────────────────
|
||||
centre_col = QHBoxLayout()
|
||||
# ── Centre column (decks + carts + mixer) ─────────────────────────
|
||||
centre_col = QVBoxLayout()
|
||||
centre_col.setSpacing(8)
|
||||
|
||||
# Decks column
|
||||
deck_col = QVBoxLayout()
|
||||
deck_col.setSpacing(8)
|
||||
# Top: decks row + carts
|
||||
deck_area = QWidget()
|
||||
deck_area.setStyleSheet("background: transparent; border: none;")
|
||||
deck_layout = QVBoxLayout(deck_area)
|
||||
deck_layout.setContentsMargins(0, 0, 0, 0)
|
||||
deck_layout.setSpacing(8)
|
||||
|
||||
deck_row = QHBoxLayout()
|
||||
deck_row.setSpacing(8)
|
||||
deck_row.addWidget(self.deck1)
|
||||
deck_row.addWidget(self.deck2)
|
||||
deck_col.addLayout(deck_row)
|
||||
deck_layout.addLayout(deck_row)
|
||||
deck_layout.addWidget(self.cart_bank)
|
||||
deck_layout.addStretch()
|
||||
|
||||
deck_col.addWidget(self.cart_bank)
|
||||
deck_col.addStretch()
|
||||
|
||||
centre_col.addLayout(deck_col)
|
||||
|
||||
# LUFS meter on right of centre section
|
||||
centre_col.addWidget(self.lufs_meter)
|
||||
# Bottom: mixer
|
||||
centre_col.addWidget(deck_area, stretch=1)
|
||||
centre_col.addWidget(self.mixer)
|
||||
|
||||
centre_widget = QWidget()
|
||||
centre_widget.setStyleSheet("background: transparent; border: none;")
|
||||
@@ -138,6 +139,7 @@ class RadioPanelWindow(QMainWindow):
|
||||
self.deck2.apply_theme(theme)
|
||||
self.cart_bank.apply_theme(theme)
|
||||
self.history_widget.apply_theme(theme)
|
||||
self.mixer.apply_theme(theme)
|
||||
|
||||
def _apply_global_style(self, theme: dict):
|
||||
self.setStyleSheet(f"""
|
||||
@@ -164,6 +166,8 @@ class RadioPanelWindow(QMainWindow):
|
||||
self.midi.deck_cue.connect(self._on_midi_cue)
|
||||
self.midi.deck_jog.connect(self._on_midi_jog)
|
||||
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.controller_connected.connect(self._on_midi_status)
|
||||
|
||||
self.midi.start()
|
||||
@@ -189,6 +193,12 @@ class RadioPanelWindow(QMainWindow):
|
||||
def _on_midi_cart(self, slot: int):
|
||||
self.cart_bank.slots[slot].toggle()
|
||||
|
||||
def _on_midi_mixer_volume(self, channel: int, value: float):
|
||||
self.engine.set_channel_volume(channel, value)
|
||||
|
||||
def _on_midi_mixer_mute(self, channel: int, muted: bool):
|
||||
self.engine.set_channel_mute(channel, muted)
|
||||
|
||||
def _on_midi_status(self, connected: bool, name: str):
|
||||
if connected:
|
||||
print(f"[MIDI] Connected: {name}")
|
||||
@@ -225,4 +235,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user