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:
+40
-1
@@ -312,6 +312,13 @@ class AudioPipeline:
|
||||
# Cached filter coefficients per block
|
||||
self._coeffs: dict[str, tuple] = {}
|
||||
|
||||
# VU meter level tracking — updated on every process() call
|
||||
# Smoothed RMS levels (0.0–1.0) read by web server for live VU meters
|
||||
self._input_level: float = 0.0
|
||||
self._output_level: float = 0.0
|
||||
# Smoothing factor: ~50ms time constant at 48kHz/256 block
|
||||
self._vu_alpha: float = np.exp(-BLOCK_SIZE / (0.05 * SAMPLE_RATE))
|
||||
|
||||
logger.info("Audio pipeline initialized (block=%d, sr=%d)",
|
||||
BLOCK_SIZE, SAMPLE_RATE)
|
||||
|
||||
@@ -373,12 +380,28 @@ class AudioPipeline:
|
||||
|
||||
def _process_mono(self, audio_in: np.ndarray) -> np.ndarray:
|
||||
"""Process a mono block through the full chain (all blocks)."""
|
||||
# Update input VU level (RMS with envelope smoothing)
|
||||
in_rms = np.sqrt(np.mean(audio_in ** 2) + _EPS)
|
||||
self._input_level = (
|
||||
self._input_level * self._vu_alpha
|
||||
+ in_rms * (1.0 - self._vu_alpha)
|
||||
)
|
||||
|
||||
buf = audio_in.copy()
|
||||
for idx, entry in enumerate(self._chain):
|
||||
if entry["bypass"] or not entry["enabled"]:
|
||||
continue
|
||||
buf = self._process_single_block(buf, idx, entry)
|
||||
return buf * self._master_volume
|
||||
out = buf * self._master_volume
|
||||
|
||||
# Update output VU level
|
||||
out_rms = np.sqrt(np.mean(out ** 2) + _EPS)
|
||||
self._output_level = (
|
||||
self._output_level * self._vu_alpha
|
||||
+ out_rms * (1.0 - self._vu_alpha)
|
||||
)
|
||||
|
||||
return out
|
||||
|
||||
def _process_4cm(self, audio_in: np.ndarray) -> np.ndarray:
|
||||
"""Process stereo block with 4CM split routing.
|
||||
@@ -397,6 +420,14 @@ class AudioPipeline:
|
||||
"""
|
||||
ch0 = audio_in[0, :].copy()
|
||||
ch1 = audio_in[1, :].copy()
|
||||
|
||||
# Update input VU level from the guitar input channel (ch0)
|
||||
in_rms = np.sqrt(np.mean(ch0 ** 2) + _EPS)
|
||||
self._input_level = (
|
||||
self._input_level * self._vu_alpha
|
||||
+ in_rms * (1.0 - self._vu_alpha)
|
||||
)
|
||||
|
||||
bp = self._routing_breakpoint
|
||||
|
||||
for idx, entry in enumerate(self._chain):
|
||||
@@ -413,6 +444,14 @@ class AudioPipeline:
|
||||
out = np.zeros_like(audio_in)
|
||||
out[0, :] = ch0 * self._master_volume
|
||||
out[1, :] = ch1 * self._master_volume
|
||||
|
||||
# Update output VU level from the processed effect return (ch1)
|
||||
out_rms = np.sqrt(np.mean(out ** 2) + _EPS)
|
||||
self._output_level = (
|
||||
self._output_level * self._vu_alpha
|
||||
+ out_rms * (1.0 - self._vu_alpha)
|
||||
)
|
||||
|
||||
return out
|
||||
|
||||
def _process_single_block(self, buf: np.ndarray, idx: int,
|
||||
|
||||
Reference in New Issue
Block a user