main_window.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. """
  2. Main Window — Main application shell with tabbed interface.
  3. """
  4. from PyQt6.QtWidgets import QMainWindow, QTabWidget, QVBoxLayout, QWidget, QLabel
  5. from PyQt6.QtCore import Qt
  6. from core.audio_device import DeviceManager
  7. from core.eq_engine import EQEngine
  8. from core.tape_processor import TapeProcessor
  9. from core.audio_player import AudioPlayer
  10. from core.audio_recorder import AudioRecorder
  11. from ui.device_panel import DevicePanel
  12. from ui.player_panel import PlayerPanel
  13. from ui.calibration_panel import CalibrationPanel
  14. from ui.eq_panel import EQPanel
  15. class MainWindow(QMainWindow):
  16. def __init__(self):
  17. super().__init__()
  18. self.setWindowTitle("Tape Recorder Pro - Auto-Calibrating EQ")
  19. self.resize(1000, 700)
  20. # --- Initialize Core Audio Engine ---
  21. self.device_manager = DeviceManager.instance()
  22. self.device_manager.auto_select_defaults()
  23. self.eq_engine = EQEngine()
  24. self.tape_processor = TapeProcessor(self.device_manager.sample_rate)
  25. self.player = AudioPlayer(self.eq_engine, self.tape_processor, self.device_manager)
  26. self.recorder = AudioRecorder(self.device_manager)
  27. self._init_ui()
  28. self._update_status()
  29. def _init_ui(self):
  30. # Central widget and layout
  31. central_widget = QWidget()
  32. self.setCentralWidget(central_widget)
  33. layout = QVBoxLayout(central_widget)
  34. layout.setContentsMargins(10, 10, 10, 10)
  35. # Tabs
  36. self.tabs = QTabWidget()
  37. # 1. Device Setup Tab
  38. self.device_panel = DevicePanel(self.device_manager)
  39. self.device_panel.devices_changed.connect(self._update_status)
  40. self.tabs.addTab(self.device_panel, "🔊 Devices")
  41. # 2. Calibration Tab
  42. self.calibration_panel = CalibrationPanel(self.device_manager, self.eq_engine, self.tape_processor)
  43. self.calibration_panel.calibration_complete.connect(self._on_calibration_complete)
  44. self.tabs.addTab(self.calibration_panel, "📐 Calibrate")
  45. # 3. EQ Tab
  46. self.eq_panel = EQPanel(self.eq_engine, self.tape_processor)
  47. self.tabs.addTab(self.eq_panel, "🎚️ EQ")
  48. # 4. Player Tab
  49. self.player_panel = PlayerPanel(self.player)
  50. self.tabs.addTab(self.player_panel, "▶️ Player")
  51. layout.addWidget(self.tabs)
  52. # Status Bar
  53. self.statusBar().showMessage("Ready")
  54. # Persistent device info labels in status bar
  55. self.in_status_lbl = QLabel("Input: None")
  56. self.out_status_lbl = QLabel("Output: None")
  57. self.statusBar().addPermanentWidget(self.in_status_lbl)
  58. self.statusBar().addPermanentWidget(self.out_status_lbl)
  59. def _update_status(self):
  60. """Update status bar with current device names."""
  61. in_id = self.device_manager.input_device_id
  62. if in_id is not None:
  63. dev = self.device_manager.get_device_by_index(in_id)
  64. name = dev.name if dev else "Unknown"
  65. # truncate long names
  66. if len(name) > 30: name = name[:27] + "..."
  67. self.in_status_lbl.setText(f"In: {name}")
  68. else:
  69. self.in_status_lbl.setText("In: None")
  70. out_id = self.device_manager.output_device_id
  71. if out_id is not None:
  72. dev = self.device_manager.get_device_by_index(out_id)
  73. name = dev.name if dev else "Unknown"
  74. if len(name) > 30: name = name[:27] + "..."
  75. self.out_status_lbl.setText(f"Out: {name}")
  76. else:
  77. self.out_status_lbl.setText("Out: None")
  78. def _on_calibration_complete(self, bands):
  79. """Called when calibration finishes successfully."""
  80. # Refresh the EQ UI to show the newly computed bands
  81. self.eq_panel.refresh_ui()
  82. # Switch to the EQ tab so the user can see the result
  83. self.tabs.setCurrentWidget(self.eq_panel)