Quick answer: Track elapsed seconds with pygame.mixer.music.get_pos() before pausing. On resume, call play() + set_pos(seconds) if unpause restarted the track on your platform.
Pausing music and unpausing should resume in place. On some backends/platforms the track restarts — pause/unpause isn’t a guaranteed contract.
Save Position Before Pause
music_pos = pygame.mixer.music.get_pos() / 1000.0 # ms -> s
pygame.mixer.music.pause()
get_pos returns milliseconds since playback started — not absolute position. Track your own offset if you’ve called set_pos before.
Resume by Re-Play
pygame.mixer.music.unpause()
# if unpause didn't actually resume (rare backend), fall back:
if pygame.mixer.music.get_pos() < 50:
pygame.mixer.music.play()
pygame.mixer.music.set_pos(music_pos)
If unpause works on your platform, great — the fallback never triggers. Where it doesn’t, play + set_pos restores the spot.
Format Matters
OGG Vorbis supports accurate set_pos. MP3 set_pos is approximate. For seamless resume, prefer OGG — the same recommendation as for gapless looping.
Use a Music Manager
Wrap the get_pos / pause / unpause / re-play logic in one module so the whole game pauses music identically. Easier to fix once if a platform bug crops up.
Verifying
Pause music, wait, unpause — it resumes in place on every target platform. Setting position explicitly via set_pos still works.
“pause/unpause is mostly fine, but track position yourself and fall back to play + set_pos when a backend doesn’t cooperate.”
For long tracks, save the position to disk during the pause — you can resume the same spot even after an app restart.