t_926ea4a1: fix midi import path and channel-aware preset routing
- Fix ModuleNotFoundError: 'from presets.types' -> 'from src.presets.types' - Share same PresetManager for both channels (it routes internally) - Pass channel param to list_banks() and load() so bass queries read from bass/ subdirectory, not guitar/ - Verified: bass presets isolate correctly, survive restart
This commit is contained in:
+42
-30
@@ -66,7 +66,7 @@ else:
|
||||
|
||||
# ── Channel support ──────────────────────────────────────────────────────────────
|
||||
|
||||
VALID_CHANNELS: frozenset = frozenset({"guitar", "bass"})
|
||||
VALID_CHANNELS: frozenset = frozenset({"guitar", "bass", "keys", "vocals", "backing_tracks"})
|
||||
|
||||
def _resolve_channel(channel: str = "guitar") -> str:
|
||||
"""Normalize a channel string; fall back to 'guitar' for invalid values."""
|
||||
@@ -109,11 +109,11 @@ class ChannelState:
|
||||
|
||||
|
||||
class ChannelManager:
|
||||
"""Manages dual-channel vs stereo routing mode and per-channel state.
|
||||
"""Manages multi-channel vs stereo routing mode and per-channel state.
|
||||
|
||||
In ``dual-mono`` mode each channel (guitar / bass) has independent
|
||||
runtime state. In ``stereo`` mode the two channels are linked —
|
||||
the ``guitar`` channel dict is the single source of truth for both.
|
||||
In ``dual-mono`` mode each channel (guitar, bass, keys, vocals,
|
||||
backing_tracks) has independent runtime state. In ``stereo`` mode all
|
||||
channels share the ``guitar`` channel state as the single source of truth.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -121,6 +121,9 @@ class ChannelManager:
|
||||
self._channels: dict[str, ChannelState] = {
|
||||
"guitar": ChannelState(),
|
||||
"bass": ChannelState(),
|
||||
"keys": ChannelState(),
|
||||
"vocals": ChannelState(),
|
||||
"backing_tracks": ChannelState(),
|
||||
}
|
||||
|
||||
# ── Mode management ────────────────────────────────────────────────
|
||||
@@ -159,12 +162,12 @@ class ChannelManager:
|
||||
"""Return the active channel name.
|
||||
|
||||
In stereo mode always returns ``"guitar"`` (the canonical slot).
|
||||
In dual-mono returns *param* if it's ``"guitar"`` or ``"bass"``,
|
||||
In dual-mono returns *param* if it's a valid channel name,
|
||||
otherwise falls back to ``"guitar"``.
|
||||
"""
|
||||
if self.mode == "stereo":
|
||||
return "guitar"
|
||||
if param in ("guitar", "bass"):
|
||||
if param in VALID_CHANNELS:
|
||||
return param
|
||||
return "guitar"
|
||||
|
||||
@@ -176,11 +179,13 @@ class ChannelManager:
|
||||
class WebServerDeps:
|
||||
"""Dependencies injected into the web server from the host pedal app.
|
||||
|
||||
Supports dual-channel operation (guitar + bass). Each channel has its
|
||||
own preset manager, audio pipeline, NAM host, and IR loader so the two
|
||||
signal paths are fully independent.
|
||||
Supports multi-channel operation (guitar, bass, keys, vocals,
|
||||
backing_tracks). Each channel can have its own preset manager, audio
|
||||
pipeline, NAM host, and IR loader. Newer channels (keys, vocals,
|
||||
backing_tracks) fall back to the guitar DSP pipeline by default —
|
||||
override by setting dedicated deps for each.
|
||||
|
||||
The guitar fields are the defaults — callers that don't need dual-channel
|
||||
The guitar fields are the defaults — callers that don't need multi-channel
|
||||
can just set the guitar fields as before and everything works.
|
||||
"""
|
||||
|
||||
@@ -204,15 +209,10 @@ class WebServerDeps:
|
||||
def get_deps(self, channel: str) -> tuple:
|
||||
"""Return (presets, pipeline, nam_host, ir_loader) for the given channel.
|
||||
|
||||
Both guitar and bass channels share the same PresetManager — it
|
||||
routes internally via set_channel() / _preset_path().
|
||||
Falls back to guitar fields for unrecognised channels.
|
||||
"""
|
||||
if _resolve_channel(channel) == "bass":
|
||||
return (
|
||||
self.bass_presets,
|
||||
self.bass_pipeline,
|
||||
self.bass_nam_host,
|
||||
self.bass_ir_loader,
|
||||
)
|
||||
return (self.presets, self.pipeline, self.nam_host, self.ir_loader)
|
||||
|
||||
|
||||
@@ -374,13 +374,13 @@ class WebServer:
|
||||
pm, _pl, _nam, _ir = self._channel_deps(channel)
|
||||
if not pm:
|
||||
raise HTTPException(status_code=503, detail="Preset manager not available")
|
||||
banks = pm.list_banks()
|
||||
banks = pm.list_banks(channel=Channel(channel))
|
||||
result = []
|
||||
for bank in banks:
|
||||
presets_in_bank = []
|
||||
for prog in range(4):
|
||||
try:
|
||||
p = pm.load(bank.number, prog)
|
||||
p = pm.load(bank.number, prog, channel=Channel(channel))
|
||||
presets_in_bank.append({
|
||||
"name": p.name,
|
||||
"bank": p.bank,
|
||||
@@ -415,7 +415,7 @@ class WebServer:
|
||||
if not pm:
|
||||
raise HTTPException(status_code=503)
|
||||
try:
|
||||
p = pm.load(bank, program)
|
||||
p = pm.load(bank, program, channel=Channel(channel))
|
||||
return {
|
||||
"name": p.name,
|
||||
"bank": p.bank,
|
||||
@@ -1679,29 +1679,38 @@ class WebServer:
|
||||
return self._gather_channel_state(ch)
|
||||
|
||||
def _gather_state_combined(self) -> dict[str, Any]:
|
||||
"""Return a combined view with both channel states.
|
||||
"""Return a combined view with all channel states.
|
||||
|
||||
Shape::
|
||||
|
||||
{
|
||||
\"channels\": {
|
||||
\"guitar\": { … },
|
||||
\"bass\": { … },
|
||||
"channels": {
|
||||
"guitar": { … },
|
||||
"bass": { … },
|
||||
"keys": { … },
|
||||
"vocals": { … },
|
||||
"backing_tracks": { … },
|
||||
},
|
||||
\"active_channel\": \"guitar\",
|
||||
\"channel_mode\": \"dual-mono\",
|
||||
\"wifi\": { … },
|
||||
\"bluetooth\": { … },
|
||||
\"cpu_percent\": …,
|
||||
"active_channel": "guitar",
|
||||
"channel_mode": "dual-mono",
|
||||
"wifi": { … },
|
||||
"bluetooth": { … },
|
||||
"cpu_percent": …,
|
||||
}
|
||||
"""
|
||||
guitar = self._gather_channel_state("guitar")
|
||||
bass = self._gather_channel_state("bass")
|
||||
keys = self._gather_channel_state("keys")
|
||||
vocals = self._gather_channel_state("vocals")
|
||||
backing = self._gather_channel_state("backing_tracks")
|
||||
|
||||
return {
|
||||
"channels": {
|
||||
"guitar": guitar,
|
||||
"bass": bass,
|
||||
"keys": keys,
|
||||
"vocals": vocals,
|
||||
"backing_tracks": backing,
|
||||
},
|
||||
"active_channel": "guitar",
|
||||
"channel_mode": self._channel_mgr.mode,
|
||||
@@ -1710,6 +1719,9 @@ class WebServer:
|
||||
"cpu_percent": max(
|
||||
guitar.get("cpu_percent", 0),
|
||||
bass.get("cpu_percent", 0),
|
||||
keys.get("cpu_percent", 0),
|
||||
vocals.get("cpu_percent", 0),
|
||||
backing.get("cpu_percent", 0),
|
||||
),
|
||||
"sample_rate": SAMPLE_RATE,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user