tokechu
tokechu

Reputation: 170

Check if a song has ended in pygame

I am trying to create a MP3-player with Tkinter and PyGame(it's music module). I have written a method to check if the song has finished playing, but the problem is that the programe itself gets cycled in it and I don't know how to implement it differently. Is there any other way to do this?

    self.SONG_END = pygame.USEREVENT
    pygame.mixer.music.set_endevent(self.SONG_END)

    def __wait_for_song_to_end(self):
        while True:
            for event in pygame.event.get():
                if event.type == self.SONG_END:
                    self.__queue_song()
                    self.__set_new_selection() #works with listbox
                    break

UPDATED
Here is the code from relevant methods:

    # Gets called when the 'play' button gets pressed
    def play_song(self):
        if not pygame.mixer.music.get_busy() and self.isPaused:
            pygame.mixer.music.unpause()
            self.isPaused = False
            self.btn_pause.config(image=self.img_pause)
            return

        if len(self.playlist.songsFullPath) > 0:
            # Getting song's full path
            for path in self.playlist.songsFullPath:
                if path.find(self.playlist.songsList.get(tk.ACTIVE)) != -1:
                    self.playlist.currentSongName = path
                    self.playlist.currentSongIndex = self.playlist.songsList.curselection()[0]
                    break

            # Loading the song into the mixer
            pygame.mixer.music.load(self.playlist.currentSongName)

            # Playing the song
            pygame.mixer.music.play(loops=0)
            self.songIsLoaded = True

    def __queue_song(self):
        if self.isOnRepeat:
            pygame.mixer.music.queue(self.playlist.currentSongName)
            return

        if self.playlist.songsListSize > 1 and self.playlist.currentSongIndex < self.playlist.songsListSize - 1:
            queuedSong = self.playlist.songsFullPath[self.playlist.songsList.curselection()[0] + 1]
            self.playlist.currentSongIndex += 1
            pygame.mixer.music.queue(queuedSong)

Upvotes: 3

Views: 1773

Answers (2)

Delrius Euphoria
Delrius Euphoria

Reputation: 15098

What you could do is, call the function with root.after() so the function gets checked continuously for end of the song.

import pygame 

# Same codes and imports
root = Tk() # Don't forget this
pygame.init() # Use this instead of pygame.mixer.init() as you need event
...

def check_event():
    for event in pygame.event.get():
        if event.type == MUSIC_END:
            play() # In your case, run self.__queue_song() and self.__set_new_selection()
    root.after(100,check_event) # Repeat this function every 0.1 second

MUSIC_END = pygame.USEREVENT+1
pygame.mixer.music.set_endevent(MUSIC_END)

play() # Play the first random song
check_event() # Start checking for the end of song

If you could provide more relevant code, then I could give a better example. For now, you should be able to rewrite this to adapt with your code.

Upvotes: 3

Rabbid76
Rabbid76

Reputation: 211186

I recommend reading Tkinter understanding mainloop.

Don't wait for the song to finish, check continuously to see if it has finished. Add an event loop to your main loop and set a status variable when the SONG_END event occurs:

song_end = False

In main loop:

for event in pygame.event.get():
    if event.type == self.SONG_END:
        song_end = True

if song_end:
    # [...]

Upvotes: 4

Related Questions