""" Main module for MIDI-to-Hue application. Ties together the config, MIDI controller, Hue controller, mapper, and animations. """ import sys import time import threading import signal from config import ConfigManager from hue_controller import HueController from midi_controller import MidiController, DeviceMappingManager from mapper import MidiToHueMapper from animations import AnimationManager, MidiLedAnimation def main(): """Main application entry point.""" # Load configuration config_manager = ConfigManager() # Create animation manager animation_manager = AnimationManager() # Initialize Hue controller try: hue_controller = HueController( config_manager.get_bridge_ip(), config_manager.get_update_interval_sec() ) hue_controller.list_lights() except Exception as e: print(f"Failed to initialize Hue controller: {e}") return 1 # Initialize MIDI controller midi_controller = MidiController(config_manager.get_midi_device_index()) midi_controller.list_devices() # Setup device mappings device_mappings = { "traktor_kontrol_s2": { "note_on/1/3": 'left_deck_1', "note_on/1/4": 'left_deck_2', "note_on/1/5": 'left_deck_3', "note_on/1/6": 'left_deck_4', "note_on/1/7": 'left_deck_5', "note_on/1/8": 'left_deck_6', "note_on/1/9": 'left_deck_7', "note_on/1/10": 'left_deck_8', "note_on/3/3": 'right_deck_1', "note_on/3/4": 'right_deck_2', "note_on/3/5": 'right_deck_3', "note_on/3/6": 'right_deck_4', "note_on/3/7": 'right_deck_5', "note_on/3/8": 'right_deck_6', "note_on/3/9": 'right_deck_7', "note_on/3/10": 'right_deck_8', "control_change/5/1": 'left_volume_slider', "control_change/6/1": 'right_volume_slider', } } device_mapper = DeviceMappingManager(device_mappings) device_mapper.set_active_device("traktor_kontrol_s2") # Bind the device mapper to the MIDI controller midi_controller.get_input_name = device_mapper.get_input_name # Create MIDI-to-Hue mapper with configuration mapper = MidiToHueMapper( hue_controller, midi_controller, config_manager.get_mappings() ) # Setup right deck animation with alternating chase directions print("Setting up right deck animation sequence...") right_deck_animation = animation_manager.create_alternating_chase_animation( name="right_deck_alternating", midi_controller=midi_controller, deck_side="right", interval=0.12, # Animation speed in seconds between steps cycles_per_direction=1 # Number of full cycles in each direction before changing ) # Open MIDI port if not midi_controller.open(): print("Failed to open MIDI port.") return 1 # Start the deck animation print("Starting right deck animation...") animation_manager.start_animation("right_deck_chase") # Handle graceful shutdown def signal_handler(sig, frame): print("\nStopping animations and exiting...") animation_manager.stop_all() midi_controller.close() sys.exit(0) # Register signal handler for Ctrl+C signal.signal(signal.SIGINT, signal_handler) try: # Process MIDI messages in main thread midi_controller.process_messages() except KeyboardInterrupt: print("\nExiting program...") finally: animation_manager.stop_all() midi_controller.close() return 0 if __name__ == "__main__": sys.exit(main())