Add MIDI device persistence functionality

- Add configuration file system to remember MIDI device selection
- Load saved MIDI device preference on application startup
- Automatically save MIDI device selection when changed
- Handle device disconnection gracefully with fallback
- Smart initialization with validation and error handling
- Create config.json for storing device preferences
- Improve user experience by eliminating need to re-select device
This commit is contained in:
2025-09-27 23:29:06 +12:00
parent f9c3d08b0f
commit ed5bbb8c18

View File

@@ -2,6 +2,7 @@ import asyncio
import tkinter as tk
from tkinter import ttk, messagebox # Import messagebox for confirmations
import json
import os
from async_tkinter_loop import async_handler, async_mainloop
from networking import WebSocketClient
import color_utils
@@ -10,6 +11,9 @@ import mido # Import mido for MIDI port detection
import time
from midi import MidiHandler # Import MidiHandler
# Configuration file path
CONFIG_FILE = "config.json"
# Dark theme colors (unchanged)
bg_color = "#2e2e2e"
fg_color = "white"
@@ -36,11 +40,11 @@ class App:
# --- MIDI Configuration ---
self.available_midi_ports = self.get_midi_ports()
self.current_midi_port_index = 0 # Default to first port
self.current_midi_port_index = self.load_midi_device_preference() # Load saved preference
self.midi_handler: MidiHandler | None = None
self.midi_task: asyncio.Task | None = None
# Initialize MIDI handler with first available port (will be done after GUI is created)
# Initialize MIDI handler with saved port (will be done after GUI is created)
self.pending_midi_init = True if self.available_midi_ports else False
# Configure ttk style (unchanged)
@@ -61,7 +65,12 @@ class App:
# MIDI port dropdown
self.midi_port_var = tk.StringVar()
if self.available_midi_ports:
self.midi_port_var.set(self.available_midi_ports[0])
# Set to saved preference if available, otherwise first port
if 0 <= self.current_midi_port_index < len(self.available_midi_ports):
self.midi_port_var.set(self.available_midi_ports[self.current_midi_port_index])
else:
self.midi_port_var.set(self.available_midi_ports[0])
self.current_midi_port_index = 0
midi_dropdown = ttk.Combobox(
midi_frame,
@@ -230,6 +239,32 @@ class App:
async_mainloop(self.root)
def load_midi_device_preference(self):
"""Load saved MIDI device preference from config file"""
try:
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, 'r') as f:
config = json.load(f)
saved_index = config.get('midi_device_index', 0)
print(f"Loaded MIDI device preference: index {saved_index}")
return saved_index
except Exception as e:
print(f"Error loading MIDI device preference: {e}")
return 0 # Default to first port
def save_midi_device_preference(self):
"""Save current MIDI device preference to config file"""
try:
config = {
'midi_device_index': self.current_midi_port_index,
'midi_device_name': self.available_midi_ports[self.current_midi_port_index] if self.available_midi_ports else None
}
with open(CONFIG_FILE, 'w') as f:
json.dump(config, f, indent=2)
print(f"Saved MIDI device preference: {config['midi_device_name']} (index {config['midi_device_index']})")
except Exception as e:
print(f"Error saving MIDI device preference: {e}")
def get_midi_ports(self):
"""Get list of available MIDI input ports"""
try:
@@ -286,6 +321,7 @@ class App:
# Current selection is no longer available, select first available
self.midi_port_var.set(self.available_midi_ports[0])
self.current_midi_port_index = 0
self.save_midi_device_preference() # Save the new preference
self.restart_midi_handler()
elif not self.available_midi_ports:
# No ports available
@@ -305,6 +341,7 @@ class App:
if selected_port in self.available_midi_ports:
self.current_midi_port_index = self.available_midi_ports.index(selected_port)
print(f"MIDI port changed to: {selected_port} (index: {self.current_midi_port_index})")
self.save_midi_device_preference() # Save the new preference
self.restart_midi_handler()
@async_handler