2017-06-25 4 views
1

AVbin ist installiert. Sowohl .wav als auch .mp3 Dateien funktionieren.Pyglet, Beenden, nachdem alle Sounds abgespielt wurden

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() 


Ich möchte ein Programm erstellen, das A spielt, spielt dann die Warteschlange mit B und dann C, und beendet schließlich, nachdem alle drei Töne spielen.

Ich habe versucht, den Code oben, aber nach this post, "das ist [allein], weil app.run() ist eine nie endende Schleife."


Wie kann ich meinen Code minimal ändern, so dass das Programm beendet, nachdem die drei Töne gespielt werden?

Bonus, aber wie kann ich meinen Code minimal ändern, so dass das Programm zwei (oder mehr) Sounddateien abspielen kann, E.mp3 und F.mp3, auf einmal?


Vielen Dank!

Antwort

1

Weil das, was Sie fragen, nicht so einfach ist, wie Sie vielleicht denken, dass es ist.
Ich habe ein Codebeispiel mit so vielen Kommentaren zusammengestellt, wie ich hineinpasse, ohne das Beispiel schwer lesbar zu machen.

Unter dem Code werde ich versuchen, einige wichtige Funktionen so detailliert wie möglich zu erklären.

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 fucky 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() 

Nun, normalerweise würden Sie Ihren Weg Trog dies mit einer Reihe von Funktionen dekorieren. Aber ich mag es, Unterklasse und OOP meinen Weg durch jede grafische Bibliotheken, weil es andernfalls ziemlich schnell unordentlich wird.

So anstelle von pyglet.app.run(), ich habe eine benutzerdefinierte run() Funktion.
All dies macht die pyglet.app.run() zum größten Teil nach. Genug, um wenigstens loszulegen.

Weil player.eos_* Ereignisse scheint gebrochen zu sein.
Ich habe ein manuelles Beispiel hinzugefügt, wie Sie überprüfen können, ob die Songs abgespielt werden oder nicht.

Dies ist eine Kombination von self.song_poolpyglet.media.SourceGroup, self.player.timepyglet.media.player.time und self.player.source._get_duration() die die Spurdauer zurückkehrt.

Die SourceGroup gibt uns eine has_next() Funktion, die uns sagt, wenn wir am Ende der Warteschlange Songs sind. Die anderen zwei Variablen sagen uns, ob wir das Ende des aktuellen Tracks erreicht haben. Das ist alles, was wir brauchen, um zu bestimmen, ob wir aussteigen wollen oder nicht.

Nun habe ich technisch keine Möglichkeit hinzugefügt, weitere Songs hinzuzufügen. Denn wieder wäre das auch härter als du denkst. Es sei denn, Sie entscheiden sich zum Beispiel für if symbol == key.LCTRL: self.song_pool.queue(pyglet.media.load(input('Song: '))). Aber noch einmal, alles, was Sie tun müssten, ist, weitere Songs zur self.song_pool Warteschlange hinzuzufügen, und los geht's.

Ich hoffe, dies beantwortet Ihre Frage. Sogar der Bonus.

+0

+1 Vielen Dank für das Codebeispiel! Ich hatte ein ähnliches Problem, aber dieses Mal mit Video.Mit dem Trick, die Rendering-Schleife zu stoppen, funktioniert jetzt alles (außer für MP4-Videos ... aber das scheint ein Problem mit AVbin zu sein). –

+1

Nur zu erwähnen .... pyglet 1.4.0a1 ist von AVbin nach ffmpeg umgezogen, und jetzt funktionieren mp4 und einige andere Formate gut mit pyglet Player! –

Verwandte Themen