Getting the audio to play

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)

Prepare for Lift Off

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:

Prepare for Lift Off

Engage Thrusters

Step 1 – creating the GUI class

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:

  • We create a class named GUI, and run the Tkinter mainloop from within its __init__ method.
  • We will separate the actual audio manipulation logic such as play, pause, rewind, forward, and others in a separate class to be defined later. However, because we want those functionalities to be available in this GUI class, we pass an object instantiated out of that player class as an argument to our __init__ method.
  • The line self.player = player within our __init__ method ensures that the player class instance is available throughout the GUI class.
  • Just like we want to access the properties and methods of the 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().
  • With these two lines of code, we have ensured that all properties of the 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.

Step 2 – creating the Play button and Add File button

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:

  • Each of the two buttons is associated with a TkinterPhotoImage class icon. We have provided a set of icons in a separate folder named icons.

Step 3 – toggling between play and pause

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:

  • The method, 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.

Step 4 – add file dialog

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

Step 5 – creating the Player class

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.

Note

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:

  • We create a class named 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.
  • We then define our 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.
  • Although this code can play audio files, pyglet requires running its own event loop to play the audio. This means it will return control to our GUI mainloop only after it has completed playing the entire sound, while freezing the Tkinter mainloop if run directly.
  • We, therefore, need to call the play method in a separate thread. We use the threading module to define a new method named start_play_thread, which simply calls our play_media method in a separate thread, thus preventing freezing out of GUI.
  • Lastly, we define the pause method, which pauses or stops the audio file being currently played. Pyglet does not differentiate between pause and stop functions. Therefore, we are typically stopping the audio using the pause command.

Step 6 – running the application

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:

  • The last section of code creates an object from the player class that we are yet to define. The player class will take care of all audio manipulation using pyglet.
  • We first create an object out of the 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().

Objective Complete – Mini Debriefing

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.154.252