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)