You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

173 lines
6.6 KiB

"""
Simulator Display GUI
Simplified visual representation showing only channel volumes.
"""
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
QLabel, QFrame, QPushButton, QSlider, QGroupBox)
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
from PyQt5.QtGui import QPainter, QColor, QBrush, QPen, QFont
class SynthWidget(QFrame):
"""Individual synth display widget - simplified to show only volume"""
def __init__(self, channel: int):
super().__init__()
self.channel = channel
self.channel_volume_midi = 100 # 0-127 MIDI CC7 value
self.setFrameStyle(QFrame.Box)
self.setFixedSize(100, 80)
self.setStyleSheet("""
QFrame {
border: 2px solid #404040;
border-radius: 6px;
background-color: #2a2a2a;
}
""")
def set_channel_volume(self, volume_midi: int):
"""Set channel volume (0-127 MIDI CC7) - this is what controls brightness"""
self.channel_volume_midi = max(0, min(127, volume_midi))
self.update() # Trigger repaint
def paintEvent(self, event):
"""Custom paint for volume-based lighting"""
super().paintEvent(event)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Calculate brightness based on MIDI volume (0-127)
brightness_intensity = int((self.channel_volume_midi / 127.0) * 255)
# Create color based on channel (different hues)
hue = (self.channel - 1) * 360 / 16 # Distribute hues across spectrum
color = QColor.fromHsv(int(hue), 200, brightness_intensity + 20)
# Draw volume-based lighting effect
if self.channel_volume_midi > 6: # Only show if volume is above ~5% (6/127)
# Draw volume glow
glow_rect = self.rect().adjusted(8, 8, -8, -8)
painter.setBrush(QBrush(color))
painter.setPen(QPen(color.lighter(120), 1))
painter.drawRoundedRect(glow_rect, 4, 4)
# Draw channel info
painter.setPen(QPen(QColor(255, 255, 255), 1))
painter.setFont(QFont("Arial", 11, QFont.Bold))
# Channel number
painter.drawText(10, 20, f"Ch {self.channel}")
# Volume level (MIDI CC7 value)
painter.setFont(QFont("Arial", 9))
painter.drawText(10, 65, f"Vol: {self.channel_volume_midi}")
class SimulatorDisplay(QWidget):
"""Simplified simulator display widget"""
def __init__(self, simulator, channel_manager):
super().__init__()
self.simulator = simulator
self.channel_manager = channel_manager
self.synth_widgets = {}
self.current_synth_count = 8
self.setup_ui()
self.connect_signals()
def setup_ui(self):
"""Set up the user interface"""
layout = QVBoxLayout(self)
# Title
title = QLabel("Synth Array - Channel Volume Display")
title.setStyleSheet("font-size: 14px; font-weight: bold; color: #ffffff; margin: 5px;")
title.setAlignment(Qt.AlignCenter)
layout.addWidget(title)
# Synth display grid
self.synth_grid_widget = QWidget()
self.synth_grid_layout = QGridLayout(self.synth_grid_widget)
self.synth_grid_layout.setSpacing(5)
layout.addWidget(self.synth_grid_widget)
# Initialize with default synth count
self.create_synth_widgets(self.current_synth_count)
def connect_signals(self):
"""Connect signals"""
# Channel manager signals
if hasattr(self.channel_manager, 'volume_changed'):
self.channel_manager.volume_changed.connect(self.on_channel_volume_changed)
def create_synth_widgets(self, count: int):
"""Create synth widgets for display"""
# Clear existing widgets
for widget in self.synth_widgets.values():
widget.deleteLater()
self.synth_widgets.clear()
# Clear layout
while self.synth_grid_layout.count():
child = self.synth_grid_layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
# Create new widgets
cols = 4 # 4 synths per row
for i in range(count):
channel = i + 1
widget = SynthWidget(channel)
row = i // cols
col = i % cols
self.synth_grid_layout.addWidget(widget, row, col)
self.synth_widgets[channel] = widget
self.current_synth_count = count
@pyqtSlot(int)
def set_synth_count(self, count: int):
"""Set number of synths to display"""
if count != self.current_synth_count:
self.create_synth_widgets(count)
@pyqtSlot(int, float)
def on_channel_volume_changed(self, channel: int, volume: float):
"""Handle channel volume change"""
if channel in self.synth_widgets:
self.synth_widgets[channel].set_channel_volume(volume)
@pyqtSlot(int, int, int, float)
def on_note_played(self, channel: int, note: int, velocity: int, duration: float):
"""Handle note played - we don't need special handling for this in volume mode"""
# In the simplified version, we only care about volume, not individual notes
pass
@pyqtSlot(int, int)
def on_midi_volume_changed(self, channel: int, volume: int):
"""Handle MIDI volume change (CC7) - channel 1-16, volume 0-127"""
if channel in self.synth_widgets:
self.synth_widgets[channel].set_channel_volume(volume)
@pyqtSlot(int, float, float)
@pyqtSlot(dict)
def update_lighting(self, lighting_data: dict):
"""Update lighting based on channel volume from simulator engine"""
for channel, brightness in lighting_data.items():
if channel in self.synth_widgets:
# Convert brightness (0-1) to MIDI (0-127) for display consistency
midi_volume = int(brightness * 127)
self.synth_widgets[channel].set_channel_volume(midi_volume)
def update_channel_volumes_from_output_manager(self, output_manager):
"""Update all channel volumes from output manager"""
for channel in range(1, self.current_synth_count + 1):
volume = output_manager.get_channel_volume(channel) / 127.0 # Convert from MIDI to 0-1
if channel in self.synth_widgets:
self.synth_widgets[channel].set_channel_volume(volume)