Pyglet,播放完所有声音后退出
Pyglet, exit after all sounds played
AVbin 已安装。 .wav 和 .mp3 文件都可以。
import pyglet
music = pyglet.media.load('A.mp3')
music.play()
player = pyglet.media.Player()
player.queue( pyglet.media.load('B.mp3'))
player.queue( pyglet.media.load('C.wav'))
player.play()
pyglet.app.run()
pyglet.app.exit()
我想创建一个播放A的程序,然后播放队列B和C,最后三个声音都播放完就退出。
我尝试了上面的代码,但根据 this post、"this is [solely] because app.run() is a never-ending loop."
如何修改我的代码,使程序在播放完三个声音后退出?
Bonus,但是我怎样才能最少地修改我的代码,以便程序可以同时播放两个(或更多)声音文件,E.mp3 和 F.mp3?
谢谢!
因为你问的并不像你想象的那么简单。
我已经整理了一个代码示例,其中包含尽可能多的注释,而不会使示例难以阅读。
在代码下面,我会尽可能详细地解释几个关键函数。
import pyglet
from pyglet.gl import *
from collections import OrderedDict
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
super(main, self).__init__(width, height, *args, **kwargs)
self.keys = OrderedDict() # This just keeps track of which keys we're holding down. In case we want to do repeated input.
self.alive = 1 # And as long as this is True, we'll keep on rendering.
## Add more songs to the list, either here, via input() from the console or on_key_ress() function below.
self.songs = ['A.wav', 'B.wav', 'C.wav']
self.song_pool = None
self.player = pyglet.media.Player()
for song in self.songs:
media = pyglet.media.load(song)
if self.song_pool is None:
## == if the Song Pool hasn't been setup,
## we'll set one up. Because we need to know the audio_format()
## we can't really set it up in advance (consists more information than just 'mp3' or 'wav')
self.song_pool = pyglet.media.SourceGroup(media.audio_format, None)
## == Queue the media into the song pool.
self.song_pool.queue(pyglet.media.load(song))
## == And then, queue the song_pool into the player.
## We do this because SourceGroup (song_pool) as a function called
## .has_next() which we'll require later on.
self.player.queue(self.song_pool)
## == Normally, you would do self.player.eos_action = self.function()
## But for whatever windows reasons, this doesn't work for me in testing.
## So below is a manual workaround that works about as good.
self.current_track = pyglet.text.Label('', x=width/2, y=height/2+50, anchor_x='center', anchor_y='center')
self.current_time = pyglet.text.Label('', x=width/2, y=height/2-50, anchor_x='center', anchor_y='center')
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_key_release(self, symbol, modifiers):
try:
del self.keys[symbol]
except:
pass
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
elif symbol == key.SPACE:
if self.player.playing:
self.player.pause()
else:
self.player.play()
elif symbol == key.RIGHT:
self.player.seek(self.player.time + 15)
## == You could check the user input here,
## and add more songs via the keyboard here.
## For as long as self.song_pool has tracks,
## this player will continue to play.
self.keys[symbol] = True
def end_of_tracks(self, *args, **kwargs):
self.alive=0
def render(self):
## Clear the screen
self.clear()
## == You could show some video, image or text here while the music plays.
## I'll drop in a example where the current Track Name and time are playing.
## == Grab the media_info (if any, otherwise this returns None)
media_info = self.player.source.info
if not media_info:
## == if there were no meta-data, we'll show the file-name instead:
media_info = self.player.source._file.name
else:
## == But if we got meta data, we'll show "Artist - Track Title"
media_info = media_info.author + ' - ' + media_info.title
self.current_track.text = media_info
self.current_track.draw()
## == This part exists of two things,
## 1. Grab the Current Time Stamp and the Song Duration.
## Check if the song_pool() is at it's end, and if the track Cur>=Max -> We'll quit.
## * (This is the manual workaround)
cur_t, end_t = int(self.player.time), int(self.player.source._get_duration())
if self.song_pool.has_next() is False and cur_t >= end_t:
self.alive=False
## 2. Show the current time and maximum time in seconds to the user.
self.current_time.text = str(cur_t)+'/'+str(end_t) + 'seconds'
self.current_time.draw()
## This "renders" the graphics:
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
x = main()
x.run()
现在,通常你会用一堆函数来装饰你的方式。
但是我喜欢通过任何图形库进行子类化和 OOP,因为否则它会很快变得混乱。
所以我有一个自定义的 run()
函数,而不是 pyglet.app.run()
。
大多数情况下,所有这一切都是模仿 pyglet.app.run()
。至少足够了。
因为 player.eos_*
事件似乎中断了。
我添加了一个手动示例,说明如何检查歌曲是否播放完毕。
这是 self.song_pool
pyglet.media.SourceGroup, self.player.time
pyglet.media.player.time 和 self.player.source._get_duration()
的组合,其中 returns 曲目持续时间。
SourceGroup
给了我们一个 has_next()
函数,它告诉我们是否在排队歌曲的末尾。其他两个变量告诉我们是否已经到达当前轨道的末尾。这就是我们需要确定是否要退出的全部内容。
现在,我还没有在技术上添加添加更多歌曲的方法。因为同样,这也比你想象的要难。例如,除非您选择加入 if symbol == key.LCTRL: self.song_pool.queue(pyglet.media.load(input('Song: ')))
。但是同样,您需要做的就是将更多歌曲添加到 self.song_pool
队列,然后就可以了。
我希望这能回答您的问题。即使是奖金。
AVbin 已安装。 .wav 和 .mp3 文件都可以。
import pyglet
music = pyglet.media.load('A.mp3')
music.play()
player = pyglet.media.Player()
player.queue( pyglet.media.load('B.mp3'))
player.queue( pyglet.media.load('C.wav'))
player.play()
pyglet.app.run()
pyglet.app.exit()
我想创建一个播放A的程序,然后播放队列B和C,最后三个声音都播放完就退出。
我尝试了上面的代码,但根据 this post、"this is [solely] because app.run() is a never-ending loop."
如何修改我的代码,使程序在播放完三个声音后退出?
Bonus,但是我怎样才能最少地修改我的代码,以便程序可以同时播放两个(或更多)声音文件,E.mp3 和 F.mp3?
谢谢!
因为你问的并不像你想象的那么简单。
我已经整理了一个代码示例,其中包含尽可能多的注释,而不会使示例难以阅读。
在代码下面,我会尽可能详细地解释几个关键函数。
import pyglet
from pyglet.gl import *
from collections import OrderedDict
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
super(main, self).__init__(width, height, *args, **kwargs)
self.keys = OrderedDict() # This just keeps track of which keys we're holding down. In case we want to do repeated input.
self.alive = 1 # And as long as this is True, we'll keep on rendering.
## Add more songs to the list, either here, via input() from the console or on_key_ress() function below.
self.songs = ['A.wav', 'B.wav', 'C.wav']
self.song_pool = None
self.player = pyglet.media.Player()
for song in self.songs:
media = pyglet.media.load(song)
if self.song_pool is None:
## == if the Song Pool hasn't been setup,
## we'll set one up. Because we need to know the audio_format()
## we can't really set it up in advance (consists more information than just 'mp3' or 'wav')
self.song_pool = pyglet.media.SourceGroup(media.audio_format, None)
## == Queue the media into the song pool.
self.song_pool.queue(pyglet.media.load(song))
## == And then, queue the song_pool into the player.
## We do this because SourceGroup (song_pool) as a function called
## .has_next() which we'll require later on.
self.player.queue(self.song_pool)
## == Normally, you would do self.player.eos_action = self.function()
## But for whatever windows reasons, this doesn't work for me in testing.
## So below is a manual workaround that works about as good.
self.current_track = pyglet.text.Label('', x=width/2, y=height/2+50, anchor_x='center', anchor_y='center')
self.current_time = pyglet.text.Label('', x=width/2, y=height/2-50, anchor_x='center', anchor_y='center')
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_key_release(self, symbol, modifiers):
try:
del self.keys[symbol]
except:
pass
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
elif symbol == key.SPACE:
if self.player.playing:
self.player.pause()
else:
self.player.play()
elif symbol == key.RIGHT:
self.player.seek(self.player.time + 15)
## == You could check the user input here,
## and add more songs via the keyboard here.
## For as long as self.song_pool has tracks,
## this player will continue to play.
self.keys[symbol] = True
def end_of_tracks(self, *args, **kwargs):
self.alive=0
def render(self):
## Clear the screen
self.clear()
## == You could show some video, image or text here while the music plays.
## I'll drop in a example where the current Track Name and time are playing.
## == Grab the media_info (if any, otherwise this returns None)
media_info = self.player.source.info
if not media_info:
## == if there were no meta-data, we'll show the file-name instead:
media_info = self.player.source._file.name
else:
## == But if we got meta data, we'll show "Artist - Track Title"
media_info = media_info.author + ' - ' + media_info.title
self.current_track.text = media_info
self.current_track.draw()
## == This part exists of two things,
## 1. Grab the Current Time Stamp and the Song Duration.
## Check if the song_pool() is at it's end, and if the track Cur>=Max -> We'll quit.
## * (This is the manual workaround)
cur_t, end_t = int(self.player.time), int(self.player.source._get_duration())
if self.song_pool.has_next() is False and cur_t >= end_t:
self.alive=False
## 2. Show the current time and maximum time in seconds to the user.
self.current_time.text = str(cur_t)+'/'+str(end_t) + 'seconds'
self.current_time.draw()
## This "renders" the graphics:
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
x = main()
x.run()
现在,通常你会用一堆函数来装饰你的方式。 但是我喜欢通过任何图形库进行子类化和 OOP,因为否则它会很快变得混乱。
所以我有一个自定义的 run()
函数,而不是 pyglet.app.run()
。
大多数情况下,所有这一切都是模仿 pyglet.app.run()
。至少足够了。
因为 player.eos_*
事件似乎中断了。
我添加了一个手动示例,说明如何检查歌曲是否播放完毕。
这是 self.song_pool
pyglet.media.SourceGroup, self.player.time
pyglet.media.player.time 和 self.player.source._get_duration()
的组合,其中 returns 曲目持续时间。
SourceGroup
给了我们一个 has_next()
函数,它告诉我们是否在排队歌曲的末尾。其他两个变量告诉我们是否已经到达当前轨道的末尾。这就是我们需要确定是否要退出的全部内容。
现在,我还没有在技术上添加添加更多歌曲的方法。因为同样,这也比你想象的要难。例如,除非您选择加入 if symbol == key.LCTRL: self.song_pool.queue(pyglet.media.load(input('Song: ')))
。但是同样,您需要做的就是将更多歌曲添加到 self.song_pool
队列,然后就可以了。
我希望这能回答您的问题。即使是奖金。