Quick answer: Pygame mixer.music.load called rapidly cuts off previous track without fadeout? Music channel is singleton - fade-out manually before each load or use Sound on a dedicated channel.
Crossfade between menu themes sounds like a hard cut because music.load immediately stops the previous track.
Fade before load
pygame.mixer.music.fadeout(500)
pygame.time.wait(500)
pygame.mixer.music.load(next_track)Sequential fade then load. Blocks the main thread for 500ms; usually acceptable for menu transitions.
Or use two Sound channels
Load both tracks as Sound objects, play on two channels, crossfade volume. More memory; smooth crossfade.
Pre-load tracks
For known transitions, pre-load destination tracks during the source track's playback. Reduces the load-time gap.
“Pygame's music channel is a single-stream API. Crossfade needs two streams.”
For ambient-music-heavy games, build a small AudioController that owns both channels and the crossfade timer. Reusable across scenes.