How can I test if a mp3 file has finished playing, so I can play the next one?

78 views Asked by At

I am attempting to create a quick little gui that will let me play mp3 files, pause them, skip to the next in the sequence, and most importantly: play the next mp3 file after the last has finished playing.

That last stipulation has been a problem, however, and I haven't been able to make it work, no matter what I try. I was considering appending all of the mp3 files into one, and skipping around that one, but I'd like to solve it like this if I can.

My question is this: how can I test if a mp3 file has finished playing, so I can play the next one?

Here is my code:

from pygame import mixer 
import os,sys
import tkinter as tk
from tkinter import PhotoImage

#getting song list
song_list = [];
for root, dirs, files in os.walk("/Users/loganjacobs/Desktop/mp3playerFiles"):
  for name in files:
    song_list.append(os.path.join(root, name))


# Starting the mixer 
mixer.init() 

# Loading the song 
song_count = 0;
mixer.music.load(song_list[song_count]) 

# Setting the volume 
mixer.music.set_volume(0.5) 

# Start playing the song 
mixer.music.play()

paused = False

def pause():
    mixer.music.pause()
    
def resume():
    mixer.music.unpause()
    
def stop():
    mixer.music.stop()

def skip(song_count):
    song_count = (song_count + 1) % len(song_list)
    mixer.music.load(song_list[song_count])
    mixer.music.play()
    return song_count

window = tk.Tk()
frame = tk.Frame()

def button_pause():
    global paused
    paused = not paused
    pause() if paused else resume()
    pause_button.config(image= play_image if paused else pause_image)

pause_image = PhotoImage(file='imgs/pause_button.png').subsample(4)
play_image = PhotoImage(file='imgs/play_button.png').subsample(4)
pause_button = tk.Button(frame,image=pause_image,command= lambda: button_pause())
pause_button.pack()

def button_skip():
    global song_count
    global paused
    if paused:
        button_pause()
    song_count = skip(song_count)

skip_image = PhotoImage(file='imgs/skip_button.png').subsample(4)
skip_button = tk.Button(frame,image= skip_image,command= lambda: button_skip())
skip_button.pack()

frame.pack()

window.mainloop()


I tried using window.after to continually test if mixer.music.get_busy() was True, but that didn't seem to work. I tried using mixer.music.get_pos(), but that resulted in stuttering. I tried to use pygame event as well, but I don't really know how to use those, so I let chatGPT give it a try and that didn't work either. Any ideas? I appreciate it greatly.

2

There are 2 answers

3
Akteruzzaman Ashik On

The problem with using mixer.music.get_busy() or mixer.music.get_pos() to determine whether a song has finished playing is that they do not provide real-time feedback and may be inaccurate for your case. Instead, you can utilize Pygame's music_end action to determine when a song has completed playing.

0
acw1668 On

You can use pygame.mixer.music.set_endevent() to set specific event to be generated when a song has finished. You need a loop to check for that event and then load the next song to play.

Below is the required changes:

import pygame
...

# need to call pygame.init() instead of pygame.mixer.init()
pygame.init()
...
# set event to be generated when a song is completed
mixer.music.set_endevent(pygame.USEREVENT) # used USEREVENT for the event
...
# tkinter after loop to check for the event
def pygame_loop():
    global song_count
    for event in pygame.event.get():
        if event.type == pygame.USEREVENT:
            # play next song
            song_count = skip(song_count)
    window.after(100, pygame_loop)

# start the after loop
pygame_loop()
window.mainloop()