Reputation: 99
I'm trying to put some music in my game by making a playlist and when a music ends the next one starts... and after hours searching for a solution i still can't find one... I know how to play one music and how to play the next one by using next_source, but i don't know how to make it do it automatically at the end of a music. And that's why i'm here. I found many websites/forums that tell you to use on_eos but i just can't make it work.
player = pyglet.media.Player()
music1 = pyglet.media.load('somemusic.wav')
music2 = pyglet.media.load('someothermusic.wav')
player.queue(music1)
player.queue(music2)
#the part i'm struggling with (I've tried that)
player.on_eos = pyglet.media.Player.on_eos
@player.event
def on_eos():
#some function
print("on player eos")
player.push_handlers(on_eos)
#
player.play()
Upvotes: 0
Views: 575
Reputation: 99
player = pyglet.media.Player()
music1 = 'somemusic.wav'
music2 = 'someothermusic.wav'
music = [music1, music2]
@player.event
def on_eos():
print("[event] on_eos: end of file")
@player.event
def on_player_eos():
print("[event] on_player_eos: end of queue")
media = []
for filename in music:
print('load:', filename)
item = pyglet.media.load(filename)
media.append(item)
def create_queue():
for item in media:
print('queue:', item)
player.queue(item)
def play():
create_queue()
player.play()
def update(event):
root.update()
def on_close():
clock.unschedule(update)
root.destroy() #edit:useless --> It even creates problems!
pyglet.app.exit() #this line does the work without the previous one
is_paused = False
root.protocol("WM_DELETE_WINDOW", on_close)
clock.schedule(update)
And that give me the error: TypeError: queue() missing 1 required positional argument: 'source' #edit: no more(solved), the problem was somewhere else.
The play button:
Button(StartPage, text="Play", command=play).pack()
Note: If you had keys binded to functions (using tkinter) like i did and they do not work anymore, use window.focus_force() it will solve your problems.
Upvotes: 1
Reputation: 142651
It run it correctly you would have to use pyglet.app.run()
at the end of code. It will run event loop
which will run code which play next music. It will also run code assigned to on_eos
, etc.
import pyglet
files = [
'somemusic1.wav',
'somemusic2.wav',
'somemusic3.wav',
]
player = pyglet.media.Player()
@player.event
def on_eos():
print("[event] on_eos: end of file")
@player.event
def on_player_eos():
print("[event] on_player_eos: end of queue")
musics = []
for filename in files:
item = pyglet.media.load(filename)
musics.append( item )
print('load:', filename)
player.queue(item)
print('queue:', item)
player.play()
pyglet.app.run() # need it to run `event loop`
If you want to run it with tkinter
then it can be problem because pyglet
runs event loop pyglet.app.run()
which blocks code and tkinter
has to run own event loop root.mainloop()
which also blocks code. One of this loop would have to run in separated thread - something similar to answer in Playing music with Pyglet and Tkinter in Python
I tried use thread for this code but I played only first music when I press button in tkinter
. So I resigned.
I tried also build own loop in piglet
(see and add root.update()
instead of root.mainloop()
but it would need something more to work correctly. So I resigned.
while True:
pyglet.clock.tick()
for window in pyglet.app.windows:
window.switch_to()
window.dispatch_events()
window.dispatch_event('on_draw')
window.flip()
root.update()
As for me the best solution is to use PyQt
. It is used to create GUI
and it has many wigdets and many classes for other task.
I used some example code with QMediaPlayer
and QMediaPlaylist
to run all music one by one after clicking button. It has also function to change volume
but I didn't test it.
It can load not only sound but also video which it can display in QVideoWidget
. And it can load files directly from internet (URLs).
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QPushButton
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer, QMediaPlaylist
import sys
files = [
'somemusic1.wav',
'somemusic2.wav',
'somemusic3.wav',
]
class VideoPlayer:
def __init__(self):
#self.video = QVideoWidget()
#self.video.resize(300, 300)
#self.video.move(0, 0)
self.playlist = QMediaPlaylist()
for item in files:
self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(item)))
self.playlist.setCurrentIndex(1)
self.player = QMediaPlayer()
#self.player.setVideoOutput(self.video)
self.player.setPlaylist(self.playlist)
def callback(self):
self.player.setPosition(0) # to start at the beginning of the video every time
#self.video.show()
self.player.play()
if __name__ == '__main__':
app = QApplication(sys.argv)
v = VideoPlayer()
b = QPushButton('start')
b.clicked.connect(v.callback)
b.show()
sys.exit(app.exec_())
EDIT:
I created working code with Pyglet
and tkinter
using pyglet.clock.schedule()
to runs root.update()
periodically.
import pyglet
from pyglet import clock
import tkinter as tk
files = [
'somemusic1.wav',
'somemusic2.wav',
'somemusic3.wav',
]
player = pyglet.media.Player()
@player.event
def on_eos():
print("[event] on_eos: end of file")
@player.event
def on_player_eos():
print("[event] on_player_eos: end of queue")
media = []
# load files
for filename in files:
print('load:', filename)
item = pyglet.media.load(filename)
media.append( item )
def create_queue():
# create queue
for item in media:
print('queue:', item)
player.queue(item)
# --- tkitner ---
def play():
create_queue()
player.play()
def update(event): # `schedule` sends `event` but `root.update` doesn't get any arguments
root.update()
def on_close():
clock.unschedule(update)
root.destroy()
pyglet.app.exit()
is_paused = False
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", on_close)
tk.Button(root, text="Play", command=play).pack()
tk.Button(root, text="Exit", command=on_close).pack()
clock.schedule(update)
pyglet.app.run() # need it to run `event loop`
Upvotes: 0