fix: full runtime apply for ALL settings — MIDI channel filter, audio device hot-swap via JACK restart, display auto_dim/screen_saver, tempo, brightness, channel_mode

This commit is contained in:
2026-06-14 13:07:23 -04:00
parent 6a14884063
commit 29947702a0
5 changed files with 115 additions and 2 deletions
+65
View File
@@ -44,6 +44,7 @@ from ..system.tonedownload import (
from ..system.audio import AudioSystem, JackAudioClient, LATENCY_PROFILES
from ..system.config import save_config
from ..ui.leds import LEDController
from ..ui.display import DisplayController
from ..midi.handler import MIDIHandler
logger = logging.getLogger(__name__)
@@ -217,6 +218,7 @@ class WebServerDeps:
# Runtime subsystems (for live apply of settings changes)
leds: Optional[LEDController] = None
midi: Optional[MIDIHandler] = None
display: Optional[DisplayController] = None
@property
def is_connected(self) -> bool:
@@ -1608,6 +1610,69 @@ class WebServer:
except Exception as e:
logger.warning("Failed to apply channel_mode: %s", e)
# ── JACK device hot-swap for input_device / output_device ──
if "input_device" in data or "output_device" in data:
try:
audio_sys = self.deps.audio_system
jack_client = self.deps.jack_audio
if jack_client:
jack_client.stop()
if "input_device" in data:
audio_sys.config.input_device = str(data["input_device"])
if "output_device" in data:
audio_sys.config.output_device = str(data["output_device"])
audio_sys.stop_jack()
ok = audio_sys.start_jack(timeout=10)
if not ok:
logger.warning("JACK restart failed after device change — rolling back")
# Restore old devices is complex, just log the failure
if jack_client:
jack_client.start()
logger.info("JACK restarted for device change: input=%s output=%s",
audio_sys.config.input_device, audio_sys.config.output_device)
except Exception as e:
logger.warning("Failed to apply device change: %s", e)
# ── MIDI channel filter ──
if "midi_channel" in data and self.deps.midi is not None:
try:
val = data["midi_channel"]
if val is None or str(val).lower() == "omni":
self.deps.midi.set_channel_filter(None)
logger.info("MIDI channel filter set to omni")
else:
ch = int(val) - 1 # UI sends "1"-"16", store as 0-15
self.deps.midi.set_channel_filter(ch)
logger.info("MIDI channel filter set to %d", ch)
except Exception as e:
logger.warning("Failed to apply midi_channel: %s", e)
# ── Display settings ──
if "auto_dim" in data and self.deps.display is not None:
try:
self.deps.display.set_auto_dim(bool(data["auto_dim"]))
except Exception as e:
logger.warning("Failed to apply auto_dim: %s", e)
if "screen_saver" in data and self.deps.display is not None:
try:
self.deps.display.set_screen_saver(str(data["screen_saver"]))
except Exception as e:
logger.warning("Failed to apply screen_saver: %s", e)
# ── Tempo settings ──
if "tap_tempo" in data and self.deps.pipeline is not None:
try:
self.deps.pipeline.set_tempo(float(data["tap_tempo"]))
except Exception as e:
logger.warning("Failed to apply tap_tempo: %s", e)
if "tempo_division" in data:
logger.info("tempo_division change noted (boot-only): %s", data["tempo_division"])
if "tap_tempo_mute" in data:
logger.info("tap_tempo_mute change noted (boot-only): %s", data["tap_tempo_mute"])
return {"ok": True, "saved": n_saved}
# ── FX block param schemas ───────────────────────────────