Now that we have a mechanism to load drum samples and a mechanism to define beat patterns in place, let us add the ability to play these beat patterns. In many ways, this is the core of our program.
Let us first understand the functionality that we want to achieve here. Once the user has loaded one or more drum sample and has defined a beat pattern using the toggle buttons, we need to scan each column of the pattern to see if it finds a green button. If it finds one, our code should play the corresponding drum sample before moving ahead. Moreover, green buttons on the same column should play almost together, while there should be some time gap between each successive column, which would define the tempo of the music.
We will use the pymedia
module to play the sound files. The pymedia
module can play a wide variety of sound formats such as .wav
, .ogg
, .mp3
, .avi
, .divx
, .dvd
, and .cdda
on multiple operating systems.
Without getting into the details of how pymedia plays the sound files, the official documentation tells us that we can play audio files using the following code sample:
import time, wave, pymedia.audio.sound as sound f= wave.open( 'YOUR FILE NAME', 'rb' ) sampleRate= f.getframerate() channels= f.getnchannels() format= sound.AFMT_S16_LE snd= sound.Output( sampleRate, channels, format ) s= f.readframes( 300000 ) snd.play( s )
If you run this piece of code as an independent script and supply the file location of a supported audio file in place of 'YOUR FILE NAME'
, this should play the media file on your computer.
Using this code sample, we will implement the play functionality for our drum machine.
3.05.py
):import time import wave import pymedia.audio.sound as sound
play_sound
method as follows:def play_sound(self, sound_filename): try: self.s = wave.open(sound_filename, 'rb') sample_rate = self.s.getframerate() channels = self.s.getnchannels() frmt = sound.AFMT_S16_LE self.snd= sound.Output(sample_rate, channels, frmt) s = self.s.readframes(300000) self.snd.play(s) except: pass
This method simply takes the API provided by pymedia
and wraps it into a method that takes a filename and plays it.
play
method that actually plays the beat samples:def play(self): for i in range(len(self.button[0])): for item in self.button: try: if item[i].cget('bg') == 'green': if not self.widget_drum_file_name [self.button.index(item)]:continue sound_filename = self.widget_drum_file_name [self.button.index(item)] self.play_sound(sound_filename) except: continue time.sleep(3/4.0)
The description of the code is listed as follows:
widget.cget()
to check to see if its color is green.continue
.pymedia
wrapper method for playing audio to play that sample.In this iteration, we added the capability to play the loaded drum samples.
Our drum machine is now operational. You can load drum samples, define beat patterns, and when you click on the Play button, the drum machine plays that beat pattern!
In this example, we decided whether or not to play a drum sample based on the color of the button. This has been used here for demonstration purposes. However, it is not a good practice to mix logic with appearance. A better idea would be to implement a data structure for buttons that would keep track of button state as "clicked" or "not-clicked", and then play the audio based on this button's state. Implementation of this dual button states is left as an exercise for you to explore.
In our previous code, we used widget.cget()
to fetch the current value of the button's bg
option to check if it is green. You can use w.cget(key)
to return the current value of a widget option. Also, note that cget()
always returns the value as a string even if you give a nonstring value when configuring the widget option.
Similar to widget.cget()
method, Tkinter offers a wide variety of methods for all its widgets. For a list of basic widget methods, refer to the The basic widget methods section in Appendix B, Quick Reference Sheets.
If you want to know all of the options configured for a particular widget, you may use the widget.config()
method instead, as follows: (See the code in 3.06.py
)
from Tkinter import * root = Tk() widget = Button(root, text="#", bg='green') widget.pack() print widget.config() print widget.config('bg') root.mainloop()
This code will print a dictionary showing all the key-value pairs for widget options and their values listed as tuples. For example, in the preceding code the line print widget.config('bg')
prints a tuple:
('background', 'background', 'Background', <border object at 022A1AC8>, 'green')
18.117.189.228