4CM split routing: stereo pipeline + breakpoint + Web UI
Pipeline: - process() dispatches to _process_mono() or _process_4cm() based on routing_mode - _process_4cm() splits chain at routing_breakpoint: pre blocks on ch0, post on ch1 - _process_single_block() extracted for reuse in both mono and 4cm paths - routing_mode/routing_breakpoint load from preset via load_preset() - set_routing() for runtime configuration - Properties: routing_mode (mono|4cm), routing_breakpoint with validation Web server: - GET /api/routing — current routing mode and breakpoint - POST /api/routing — set routing mode/breakpoint, persist to current preset, WS broadcast - _gather_state() includes routing_mode and routing_breakpoint Web UI: - Settings page: 4CM toggle + breakpoint slider with routing description - Dashboard: routing badge (4CM/Mono) with breakpoint info - app.js: WebSocket handler, updateRoutingUI(), toggle4cm(), set4cmBreakpoint() - style.css: .badge, .badge-4cm, .badge-mono, .routing-status, .routing-desc Tests: mock pipeline fixture updated with routing_mode/routing_breakpoint
This commit is contained in:
@@ -356,6 +356,53 @@ class WebServer:
|
||||
pl._master_volume = vol
|
||||
return {"ok": True, "volume": vol}
|
||||
|
||||
# ── 4CM routing endpoints ────────────────────────────────
|
||||
|
||||
@app.get("/api/routing")
|
||||
async def get_routing():
|
||||
"""Get current routing mode and breakpoint."""
|
||||
pl = self.deps.pipeline
|
||||
if not pl:
|
||||
raise HTTPException(status_code=503)
|
||||
return {
|
||||
"routing_mode": pl.routing_mode,
|
||||
"routing_breakpoint": pl.routing_breakpoint,
|
||||
}
|
||||
|
||||
@app.post("/api/routing")
|
||||
async def set_routing(data: dict):
|
||||
"""Set routing mode and/or breakpoint.
|
||||
|
||||
Body:
|
||||
routing_mode (optional): ``\"mono\"`` or ``\"4cm\"``.
|
||||
routing_breakpoint (optional): chain index for split.
|
||||
"""
|
||||
pl = self.deps.pipeline
|
||||
pm = self.deps.presets
|
||||
if not pl:
|
||||
raise HTTPException(status_code=503)
|
||||
mode = data.get("routing_mode", pl.routing_mode)
|
||||
bp = int(data.get("routing_breakpoint", pl.routing_breakpoint))
|
||||
pl.set_routing(mode, bp)
|
||||
|
||||
# Persist to current preset if preset manager is available
|
||||
if pm:
|
||||
try:
|
||||
bank = pm.current_bank
|
||||
program = pm.current_program
|
||||
preset = pm.load(bank, program)
|
||||
pm.set_4cm_config(preset, mode=mode, breakpoint=bp)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
await self._manager.broadcast({
|
||||
"type": "routing_changed",
|
||||
"routing_mode": pl.routing_mode,
|
||||
"routing_breakpoint": pl.routing_breakpoint,
|
||||
})
|
||||
return {"ok": True, "routing_mode": pl.routing_mode,
|
||||
"routing_breakpoint": pl.routing_breakpoint}
|
||||
|
||||
@app.get("/api/models")
|
||||
async def list_models():
|
||||
"""List available NAM models."""
|
||||
@@ -578,6 +625,8 @@ class WebServer:
|
||||
"bypass": pl._bypassed if pl else False,
|
||||
"tuner_enabled": pl._tuner_enabled if pl else False,
|
||||
"master_volume": pl._master_volume if pl else 0.8,
|
||||
"routing_mode": pl.routing_mode if pl else "mono",
|
||||
"routing_breakpoint": pl.routing_breakpoint if pl else 7,
|
||||
"nam_loaded": bool(nam and nam.is_loaded) if nam else False,
|
||||
"nam_model": current_model_name,
|
||||
"ir_loaded": bool(ir and ir.is_loaded) if ir else False,
|
||||
|
||||
Reference in New Issue
Block a user