R1: Dashboard 500 fix, Phase 2/7 uncommitted changes

- Fix dashboard 500 when deps disconnected — _gather_state() now returns
  full defaults instead of bare {'connected': False}
- Phase 2: FX param schemas aligned with DSP implementations
- Phase 7: Pipeline routing, preset manager improvements
- Factory presets: cleanup and normalization

Fixes dashboard crash on disconnected state (dogfood issue #1)
This commit is contained in:
2026-06-12 14:02:13 -04:00
parent 1301a8a128
commit 77a757cee6
62 changed files with 24166 additions and 20 deletions
+38
View File
@@ -34,6 +34,9 @@ AUTO_SAVE_DELAY_S = 1.0
FACTORY_PRESET_DIR = Path(__file__).resolve().parent.parent.parent / "presets" / "factory"
"""Location of bundled factory preset JSON files."""
FACTORY_IR_DIR = FACTORY_PRESET_DIR / "irs"
"""Location of bundled factory cabinet IR .wav files."""
# ── Serialisation helpers ───────────────────────────────────────────────────
@@ -513,6 +516,41 @@ class PresetManager:
logger.info("Installed %d factory presets", count)
return count
def install_factory_irs(self, overwrite: bool = False) -> int:
"""Install bundled factory cabinet IR .wav files into the IR directory.
Copies IR files from ``FACTORY_IR_DIR`` into the IR loader's default
directory (``~/.pedal/irs/``). Existing files are skipped unless
``overwrite=True``.
Args:
overwrite: If True, overwrite existing IR files with the same name.
Returns:
Number of factory IR files installed.
"""
if not FACTORY_IR_DIR.is_dir():
logger.warning("Factory IR directory not found: %s", FACTORY_IR_DIR)
return 0
from ..dsp.ir_loader import DEFAULT_IR_DIR
dest = DEFAULT_IR_DIR
dest.mkdir(parents=True, exist_ok=True)
count = 0
for src in sorted(FACTORY_IR_DIR.glob("*.wav")):
dst = dest / src.name
if dst.exists() and not overwrite:
logger.debug("Skipping existing IR: %s", dst.name)
continue
shutil.copy2(src, dst)
count += 1
logger.debug("Installed factory IR: %s", dst.name)
if count:
logger.info("Installed %d factory cab IRs into %s", count, dest)
return count
# ── Internal helpers ────────────────────────────────────────────────────
def _preset_path(self, bank: int, program: int) -> Path: