The first goal of our project is to add the ability to play the audio file. As usual, we will keep the audio related logic separate from our GUI section. Therefore, we create two separate files: main-gui.py
and player.py
. (See code 5.01)
We first code a basic GUI, which includes a Play button (which toggles between play and stop functionality) and an Add File button. At the end of this iteration, we should be able to load a file, play it, and stop it. By the end of this section, our application will look like the following screenshot:
Let's create the GUI
class. The code for main-gui.py
is as follows (see code 5.01 main-gui.py):
from Tkinter import * import tkFileDialog import player class GUI: def __init__(self, player): self.player = player player.parent = self self.root = Tk() self.create_button_frame() self.create_bottom_frame() self.root.mainloop()
The description of the code is listed as follows:
GUI
, and run the Tkinter mainloop from within its __init__ method
.GUI
class, we pass an object instantiated out of that player
class as an argument to our __init__
method.self.player = player
within our __init__
method ensures that the player
class instance is available throughout the GUI
class.player
class from this GUI
class, we also want the methods and attributes of the GUI
class to be available within our player
class. We, therefore, use the line player.parent = self
in the __init__
method. This creates a reference to self so that all its methods can be assessed inside the player
class using the syntax parent.attribute
and parent.method()
.GUI
class will be available in the player
class and vice versa; all properties of the player
class will be available in the GUI
class.For this, we add two methods: create_button_frame
and create_bottom_frame
. The create_button_frame
method holds the Play button, and the create_bottom_frame
method holds the Add File button, as follows:
def create_button_frame(self): buttonframe= Frame(self.root) self.playicon = PhotoImage(file='../icons/play.gif') self.stopicon = PhotoImage(file='../icons/stop.gif') self.playbtn=Button(buttonframe, text ='play', image=self.playicon, borderwidth=0, command=self.toggle_play_pause) self.playbtn.image = self.playicon self.playbtn.grid(row=3, column=3) buttonframe.grid(row=1, pady=4, padx=5) def create_bottom_frame(self): bottomframe = Frame(self.root) add_fileicon = PhotoImage(file='../icons/add_file.gif') add_filebtn=Button(bottomframe, image=add_fileicon, borderwidth=0, text='Add File', command=self.add_file) add_filebtn.image = add_fileicon add_filebtn.grid(row=2, column=1) bottomframe.grid(row=2, sticky='w', padx=5)
The description of the code is listed as follows:
TkinterPhotoImage
class icon. We have provided a set of icons in a separate folder named icons
.The Play button has a command callback that toggles the button between play and stop functionality. The toggle
method is defined as follows:
def toggle_play_pause(self): if self.playbtn['text'] =='play': self.playbtn.config(text='stop', image=self.stopicon) self.player.start_play_thread() elif self.playbtn['text'] =='stop': self.playbtn.config(text ='play', image=self.playicon) self.player.pause()
The description of the code is listed as follows:
toggle_play_pause
, changes the icon alternatively between a play and pause icon. It also calls the play
and pause
methods of the player
class to play and pause the songs.The Add File button opens tkFileDialog
, which associates the file opened with a class attribute named currentTrack
, as follows:
def add_file(self): tfile = tkFileDialog.askopenfilename(filetypes=[('All supported', '.mp3 .wav .ogg'), ('All files', '*.*')]) self.currentTrack = tfile
Now, let's code the basic player
class. For now, we will only add play and pause functionality to the class. The code for our player
class is built upon the pyglet library.
Pyglet provides an object-oriented interface for developing rich media applications, such as games, audio and video tools, and others. It is a popular choice with Python programmers for media manipulation, because it has no external dependencies, supports a large number of formats, and is available on all major operating systems.
Before we proceed further, you might want to look at the API documentation of the pyglet player available at:
http://www.pyglet.org/doc/api/pyglet.media.Player-class.html
The documentation tells us that we can play an audio file using the following code:
myplayer= pyglet.media.Player() source = pyglet.media.load(<<audio file to be played>>) myplayer.queue(source) myplayer.play() pyglet.app.run()
We will use this code snippet to play the audio file. Accordingly, the code for our Player
class is as follows(see code 5.01 player.py):
import pyglet from threading import Thread class Player(): parent = None def play_media(self): try: self.myplayer= pyglet.media.Player() self.source = pyglet.media.load(self.parent.currentTrack) self.myplayer.queue(self.source) self.myplayer.play() pyglet.app.run() except: pass def start_play_thread(self): player_thread = Thread(target=self.play_media) player_thread.start() def pause(self): try: self.myplayer.pause() self.paused = True except: pass
The description of the code is listed as follows:
Player
and initialize its parent class as None
. Recall that in our GUI
class, we have defined a reference player.parent = self
, so as to be able to assess our GUI
class properties from within our player
class.play_media
method, which is responsible for actually playing the sound. The method accesses the currentTrack
attribute of the GUI
class and tries to play it.start_play_thread
, which simply calls our play_media
method in a separate thread, thus preventing freezing out of GUI.We finally run the application by creating an object out of our GUI
class. Because this GUI
class requires an object from the player
class, we also instantiate a player object and pass it as an argument to our GUI
class, as follows:
if __name__ == '__main__': playerobj = player.Player() app = GUI(playerobj)
The description of the code is listed as follows:
player
class that we are yet to define. The player
class will take care of all audio manipulation using pyglet.player
class and pass it as an argument to the __init__
method of our GUI
class. This ensures that all attributes and methods of the player
class are available within the GUI
class using the syntax player.attribute
and player.method()
.This completes our first iteration.
In this section, we created a GUI
class, added a button that toggles between play and pause. We added another button to add a file using tkFileDialog
.
We also created a Player
class, which uses pyglet for playing audio files. The files are played in a separate thread to avoid freezing of the Tkinter mainloop while the audio is playing.
Finally, we ran our application by first creating a player object and passing it as an argument to another object created by our GUI
class.
We now have a functional audio player, where you can load a single file using tkFileDialog
. After loading, you can press the Play button and the audio file starts playing. You can stop the audio by clicking the Play button, which toggles alternatively between play and pause functions.
3.142.114.19