From 3c41bf42a8aff2ca3c14002bdb93be9cdbc3e793 Mon Sep 17 00:00:00 2001 From: Matthew Mays Date: Wed, 20 May 2026 19:43:58 +0000 Subject: [PATCH] streams: add DEBUG logging to SmartCrossFade build and fallback paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two DEBUG-level log lines to help diagnose smart crossfade behaviour: 1. fades.py — after _build() completes, logs both track BPMs, diff %, bar count, crossfade duration, beat-alignment offset, and whether time-stretch was applied. 2. mixer.py — when falling back to standard crossfade, logs the specific reason (missing BPM, missing beats, no analysis data, etc.) so it is clear in logs why smart crossfade was skipped for a given transition. Validated on nightly build 2.9.0.dev2026052006. --- .../controllers/streams/smart_fades/fades.py | 11 +++++++++++ .../controllers/streams/smart_fades/mixer.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/music_assistant/controllers/streams/smart_fades/fades.py b/music_assistant/controllers/streams/smart_fades/fades.py index 16ffb853c1..e762422876 100644 --- a/music_assistant/controllers/streams/smart_fades/fades.py +++ b/music_assistant/controllers/streams/smart_fades/fades.py @@ -285,6 +285,17 @@ def _build(self) -> None: if is_stretched: self._apply_gradual_time_stretch(bpm_ratio, bpm_diff_percent, crossfade_duration) + self.logger.debug( + "SmartCrossFade: out=%.1f BPM, in=%.1f BPM (diff=%.1f%%), bars=%d, " + "duration=%.1fs, beat_align=%s, time_stretch=%s", + self.fade_out_bpm, + self.fade_in_bpm, + bpm_diff_percent, + crossfade_bars, + crossfade_duration, + f"{fadein_start_pos:.2f}s" if fadein_start_pos is not None else "none", + f"ratio={bpm_ratio:.4f}" if is_stretched else "off", + ) if ( fadein_start_pos is not None and fadein_start_pos + crossfade_duration <= SMART_CROSSFADE_DURATION diff --git a/music_assistant/controllers/streams/smart_fades/mixer.py b/music_assistant/controllers/streams/smart_fades/mixer.py index 80bb0e71e6..affbe1a562 100644 --- a/music_assistant/controllers/streams/smart_fades/mixer.py +++ b/music_assistant/controllers/streams/smart_fades/mixer.py @@ -126,6 +126,25 @@ async def mix( "Smart crossfade failed: %s, falling back to standard crossfade", e ) + # Log why we are falling back to standard crossfade + if mode == SmartFadesMode.SMART_CROSSFADE: + missing: list[str] = [] + if not fade_out_analysis: + missing.append("no analysis for outgoing track") + elif not fade_out_analysis.bpm: + missing.append("outgoing BPM unknown") + elif fade_out_analysis.beats is None: + missing.append("outgoing beats missing") + if not fade_in_analysis: + missing.append("no analysis for incoming track") + elif not fade_in_analysis.bpm: + missing.append("incoming BPM unknown") + elif fade_in_analysis.beats is None: + missing.append("incoming beats missing") + self.logger.debug( + "Falling back to standard crossfade (%s)", + "; ".join(missing) if missing else "unknown reason", + ) # Always fallback to Standard Crossfade in case something goes wrong # StandardCrossFade needs full bytes for slicing fade_in_bytes = await self._ensure_bytes(fade_in_part)