#!/usr/bin/env python3 """ MIDI Arpeggiator - Main Application Entry Point A modular MIDI arpeggiator with lighting control and Native Instruments Maschine integration """ import sys import os from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import QTimer from gui.main_window import MainWindow from core.output_manager import OutputManager from core.arpeggiator_engine import ArpeggiatorEngine from core.midi_channel_manager import MIDIChannelManager from core.synth_router import SynthRouter from core.volume_pattern_engine import VolumePatternEngine from simulator.simulator_engine import SimulatorEngine from config.configuration import Configuration from maschine.maschine_controller import MaschineController class ArpeggiatorApp: def __init__(self): self.app = QApplication(sys.argv) self.config = Configuration() # Initialize core modules self.channel_manager = MIDIChannelManager() self.volume_engine = VolumePatternEngine() self.synth_router = SynthRouter(self.channel_manager) self.simulator = SimulatorEngine() self.output_manager = OutputManager(self.simulator) self.arpeggiator = ArpeggiatorEngine( self.channel_manager, self.synth_router, self.volume_engine, self.output_manager ) # Initialize Maschine controller self.maschine_controller = MaschineController( self.arpeggiator, self.channel_manager, self.volume_engine, self.synth_router, self.output_manager ) # Initialize GUI self.main_window = MainWindow( self.arpeggiator, self.channel_manager, self.volume_engine, self.output_manager, self.simulator, self.maschine_controller ) # Volume changes are now handled once per note-on in arpeggiator engine # Setup update timer for real-time updates self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_systems) self.update_timer.start(16) # ~60 FPS # Volume updates are now handled directly in update_systems for active channels only def update_systems(self): """Update all systems that need regular refresh""" self.arpeggiator.update() self.simulator.update_lighting_display() # Update volume patterns if arpeggiator is playing if self.arpeggiator.is_playing: # Advance pattern position (16ms delta at 60fps) self.volume_engine.update_pattern(0.016) def run(self): self.main_window.show() return self.app.exec_() if __name__ == "__main__": app = ArpeggiatorApp() sys.exit(app.run())