Thursday, June 26, 2014

37. Sound

Audio files are loaded and played, depending on button press.




The layout is based on GridLayout. To load and play audio, we need the SoundLoader class. The Clock class is needed to play sound with different delays.




In the app build(), we have a function to load sounds called load_sounds(). In that function, an empty dictionary is created and then 3 wav files are loaded: sound1.wav, sound2.wav, and sound3.wav. They are loaded into the dictionary with SoundLoader's load() function.




This is the code to play the first sound. We get the 0th element from the dictionary. If it exists, we play it at 0.5 volume. This function, as all play and stop functions, will be called from the kv file.




For sound2, this particular wav file is played 5 times. We set 5 Clock functions with different delays to play the sound. Depending on the length of wav file, the delays might be different.




The app function, play_sound3, is similar to play_sound1, except now, the loop = True, which means, the sound will go on forever, or until it is stopped.




This is the stop_sound function which ends a particular sound. Depending on how sound is started we either unschedule the Clock function, or use the stop() function on the particular sound.




The Python file is run by calling the run() method of the App class.


# ex37.py

from kivy.uix.gridlayout import GridLayout
from kivy.clock import Clock
from kivy.core.audio import SoundLoader
from kivy.app import App

class Ex37(GridLayout):
    pass
        
class Ex37App(App):
    def build(self):
        self.load_sounds()
        return Ex37()

    def load_sounds(self):
        self.sounds = {}
        for i in range(3):
            fname = 'sound' + str(i+1) + '.wav'
            self.sounds[i] = SoundLoader.load(fname)

    def play_sound1(self):
        sound = self.sounds.get(0)
        if sound is not None:
            sound.volume = 0.5
            sound.play()

    def play_sound2_once(self, *args):
        sound = self.sounds.get(1)
        if sound is not None:
            sound.volume = 0.5
            sound.play()
        
    def play_sound2(self):
        Clock.schedule_once(self.play_sound2_once,0)
        Clock.schedule_once(self.play_sound2_once,1)
        Clock.schedule_once(self.play_sound2_once,2)
        Clock.schedule_once(self.play_sound2_once,3)
        Clock.schedule_once(self.play_sound2_once,4)

    def play_sound3(self):
        sound = self.sounds.get(2)
        if sound is not None:
            sound.volume = 0.5
            sound.loop = True
            sound.play()

    def stop_sound(self,i):
        if i == 1:
            Clock.unschedule(self.play_sound2_once)
        else:
            sound = self.sounds.get(i)
            if sound is not None:
                if sound.state == "play":
                    sound.stop()
            
if __name__=='__main__':
    Ex37App().run()



In the kv file, we set columns as 3. We have a total of 6 RelativeLayouts, each with same size. The first one has a color of red.




For first RelativeLayout, the Label says 'sound1'.




For the Button in RelativeLayout1, the Button text is 'Play' and on_press points to play_sound1() of the app class.




For RelativeLayout2, the color, label, and button properties are listed here.




For RelativeLayout3, the color, label, and button properties are listed here.




For RelativeLayout 4 through 6, the Buttons have the text 'Stop'. The color, and button's on_press properties are listed here. The particular sound to be stopped is passed as a parameter.


# ex37.kv

<Ex37>:
    cols: 3
    RelativeLayout:
        canvas:
            Color:
                rgb: 1,0,0
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0,0
        Label:
            text: 'sound1'
            size_hint: None, None
            size: self.size
            pos_hint: {'center_x':.5,'top': 1}
        Button:
            text: 'Play'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.play_sound1()

    RelativeLayout:
        canvas:
            Color:
                rgb: 0,.5,1
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0,0
        Label:
            text: 'sound2'
            size_hint: None, None
            size: self.size
            pos_hint: {'center_x':.5,'top': 1}
        Button:
            text: 'Play'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.play_sound2()

    RelativeLayout:
        canvas:
            Color:
                rgb: 0,0,1
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0,0
        Label:
            text: 'sound3'
            size_hint: None, None
            size: self.size
            pos_hint: {'center_x':.5,'top': 1}
        Button:
            text: 'Play'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.play_sound3()

    RelativeLayout:
        canvas:
            Color:
                rgb: .5,0,.5
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0, 0
        Button:
            text: 'Stop'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.stop_sound(0)
            

    RelativeLayout:
        canvas:
            Color:
                rgb: .5,.75,0
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0, 0
        Button:
            text: 'Stop'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.stop_sound(1)

    RelativeLayout:
        canvas:
            Color:
                rgb: 1,1,0
            Rectangle:
                size: 1.0/3.0*root.width,1.0/2.0*root.height
                pos: 0, 0
        Button:
            text: 'Stop'
            size_hint: None, None
            size: 1.0/6.0*root.width,1.0/4.0*root.height
            pos: 1.0/12.0*root.width,1.0/8.0*root.height
            on_press: app.stop_sound(2)



This is the result. The 3 buttons in first row will play sound1, sound2, or sound3. The 3 buttons in the 2nd row will stop sound1, sound2, or sound3.




2 comments:

  1. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    Python Training in electronic city

    ReplyDelete