# main.py import sys from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QSplitter ) from PySide6.QtCore import Qt from PySide6.QtGui import QFont, QColor, QPalette from audio_engine import AudioEngine from deck_widget import DeckWidget from cart_widget import CartBankWidget from playlist_widget import PlaylistWidget from fingerprint_widget import FingerprintWidget from midi_engine import MidiEngine from top_bar_widget import TopBarWidget, THEMES from history_widget import HistoryWidget # ───────────────────────────────────────── # AcoustID API Key # ───────────────────────────────────────── ACOUSTID_API_KEY = "Y0RZoLiEmr" class RadioPanelWindow(QMainWindow): def __init__(self): super().__init__() self.engine = AudioEngine() self.setWindowTitle("Radio Panel") self.setMinimumSize(1280, 720) self.resize(1920, 1080) self._apply_global_style(THEMES[0]) central = QWidget() self.setCentralWidget(central) outer = QVBoxLayout(central) outer.setContentsMargins(8, 8, 8, 8) outer.setSpacing(8) # Top bar self.top_bar = TopBarWidget() self.top_bar.theme_changed.connect(self._on_theme_changed) outer.addWidget(self.top_bar) # ── Build widgets ───────────────────────────────────────────────── self.deck1 = DeckWidget( deck_key="deck1", label="DECK 1", accent_color="#00897b", engine=self.engine ) self.deck2 = DeckWidget( deck_key="deck2", label="DECK 2", accent_color="#f9ca24", engine=self.engine ) self.cart_bank = CartBankWidget(self.engine) self.cart_bank.setFixedHeight(280) self.playlist_widget = PlaylistWidget( engine=self.engine, deck_widgets={ "deck1": self.deck1, "deck2": self.deck2, }, cart_slots=self.cart_bank.slots ) self.history_widget = HistoryWidget() self.fingerprint_panel = FingerprintWidget( engine=self.engine, api_key=ACOUSTID_API_KEY ) self.fingerprint_panel.setFixedHeight(240) # ── Centre column ───────────────────────────────────────────────── centre_col = QVBoxLayout() centre_col.setSpacing(8) deck_row = QHBoxLayout() deck_row.setSpacing(8) deck_row.addWidget(self.deck1) deck_row.addWidget(self.deck2) centre_col.addLayout(deck_row) centre_col.addWidget(self.cart_bank) centre_col.addWidget(self.fingerprint_panel) centre_col.addStretch() centre_widget = QWidget() centre_widget.setStyleSheet("background: transparent; border: none;") centre_widget.setLayout(centre_col) # ── Splitter ────────────────────────────────────────────────────── self.splitter = QSplitter(Qt.Horizontal) self.splitter.setHandleWidth(6) self._style_splitter(THEMES[0]) self.splitter.addWidget(self.playlist_widget) self.splitter.addWidget(centre_widget) self.splitter.addWidget(self.history_widget) self.splitter.setSizes([400, 1120, 400]) outer.addWidget(self.splitter) # ── Wire signals ────────────────────────────────────────────────── self.deck1.track_started.connect(self.history_widget.add_track) self.deck2.track_started.connect(self.history_widget.add_track) # ── MIDI ────────────────────────────────────────────────────────── self._setup_midi() def _style_splitter(self, theme: dict): self.splitter.setStyleSheet(f""" QSplitter::handle {{ background-color: #333333; border-radius: 3px; }} QSplitter::handle:hover {{ background-color: {theme['accent']}; }} QSplitter::handle:pressed {{ background-color: {theme['accent_dim']}; }} """) def _on_theme_changed(self, theme: dict): self._apply_global_style(theme) self._style_splitter(theme) def _apply_global_style(self, theme: dict): self.setStyleSheet(f""" QMainWindow {{ background-color: {theme['bg']}; }} QWidget {{ background-color: {theme['bg']}; color: {theme['text']}; font-family: Arial; }} QToolTip {{ background-color: {theme['bg2']}; color: {theme['text']}; border: 1px solid #444; padding: 4px; }} """) def _setup_midi(self): self.midi = MidiEngine() self.midi.deck_play_pause.connect(self._on_midi_play_pause) 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.controller_connected.connect(self._on_midi_status) self.midi.start() def _on_midi_play_pause(self, deck: str): if deck == 'deck1': self.deck1.toggle_play() elif deck == 'deck2': self.deck2.toggle_play() def _on_midi_cue(self, deck: str): if deck == 'deck1': self.deck1.cue() elif deck == 'deck2': self.deck2.cue() def _on_midi_jog(self, deck: str, delta: float): if deck == 'deck1': self.deck1.scrub(delta) elif deck == 'deck2': self.deck2.scrub(delta) def _on_midi_cart(self, slot: int): self.cart_bank.slots[slot].toggle() def _on_midi_status(self, connected: bool, name: str): if connected: print(f"[MIDI] Connected: {name}") else: print(f"[MIDI] Not connected: {name}") def closeEvent(self, event): self.midi.stop() self.engine.shutdown() event.accept() def main(): app = QApplication(sys.argv) app.setApplicationName("Radio Panel") app.setOrganizationName("GTI") palette = QPalette() palette.setColor(QPalette.Window, QColor("#0d0d0d")) palette.setColor(QPalette.WindowText, QColor("#cccccc")) palette.setColor(QPalette.Base, QColor("#111111")) palette.setColor(QPalette.AlternateBase, QColor("#1a1a1a")) palette.setColor(QPalette.Text, QColor("#cccccc")) palette.setColor(QPalette.Button, QColor("#2a2a2a")) palette.setColor(QPalette.ButtonText, QColor("#cccccc")) palette.setColor(QPalette.Highlight, QColor("#1a3a5a")) palette.setColor(QPalette.HighlightedText, QColor("#ffffff")) app.setPalette(palette) window = RadioPanelWindow() window.show() sys.exit(app.exec()) if __name__ == "__main__": main()