Kivy and in-game sounds: Game update loop waits for sound to finish before continuing [FPS issues using SoundLoader in Kivy]
Question: I'm learning to program Python by making a game using Kivy, but I'm having
trouble implementing sounds for different events (eg. shield_on.play() when
shield-item is picked up.) because the game update loop appears to halt for a
short while until the sound has finished playing. I've made a short version of
the relevant code here...

    
    
    shield_on = soundLoader('shield_on.wav')
    class game(Widget):
    #...loads of other stuff...
    
        def update_loop(foo):
            self.player_one.update()
            self.player_two.update()
            self.player_item_collision_detector()
            if "game_file_says_player_one's_shields_are on":
                self.player_one.drawShield()
                shield_on.play()
    

Presently, I simply load my sounds globally. I know that's bad, but they're
also my only globals. Then there is a Widget containing the game itself which
has a lot of stuff and an update loop... it updates the player positions,
checks for collisions with items - and on collision the item, here the shield,
is registered as "on" in a game-file. Then the update-loop checks that game-
file for the status of "shields", sees they are on and should play the sound.

The sound plays just fine, however the loop appears to halt until its finished
playing the sound. Essentially, the players stop for a microsecond. How can I
make the update loop not wait for the sounds to finish...?


Answer: # Explanation and workaround with PyGame:

The cause of the problem is explained here: github.com/kivy/kivy/issues/2728
Essentially, the SoundLoader.load() function should return the class most
suited to play the soundfile you pass it. It ends up not doing exactly that,
and as I understand it the fault doesn't lie with Kivy but with GStreamer.
This causes a significant temporary framerate drop for the app - regardless of
where you call the .play() method.

Two possible solutions to this is offerend in the github-thread; 1) Either
ensure a suitable class is returned directly - using SoundSDL2 2) Use PyGame
instead

I implemented the latter, and it works fine.

    
    
    # Initialize files and PyGame mixer:
    import pygame
    pygame.init()
    pygame.mixer.pre_init(44100, 16, 2, 4096) # Frequency, size, channels and buffersize    
    shield_on = pygame.mixer.Sound("shield_on.wav")
    
    class game(Widget):
        ...
        def update_loop(self):
            ...
            if "game_file_says_shield_is_on":
                shield_on.play()
    

Hopefully this is of some help to others!

I'd like to say the above answer was useful as well because it enabled me to
identify the real problem. I'd give it a vote, but I don't have the reputation
here yet.

