Code gets delayed when using Pyaudio and Ursina

Viewed 18

All I’m trying to do is play a sound with Pyaudio while using the Ursina engine for the rest of my game. The game won’t start until the sound is done playing. This isn't the case when I use the case when I use the playsound module. It also isn't a lag problem since my Ursina window is always at 60 fps when the sound is playing. `from ursina import *

import random
import pyaudio
import wave
from playsound import playsound

def play(file):
    CHUNK = 1024
    sound = wave.open(file, 'rb')
    p = pyaudio.PyAudio()
    stream = p.open(format=p.get_format_from_width(sound.getsampwidth()),
        channels=sound.getnchannels(),
        rate=sound.getframerate(),
        output=True,
        input =False)

    data = sound.readframes(CHUNK)
    while len(data)>0:
        stream.write(data)
        data = sound.readframes(CHUNK)
    stream.stop_stream()
    stream.close()
    p.terminate()
app = Ursina()
quantity = Entity(color=color.clear,position=(0,0,-30))
points=Entity(color=color.clear,position=(0,0,-30))
high= Entity(color=color.clear, position=(0, 0, -30))
score_text = int(points.x)
score_text2 = str(score_text)
score = Text(text=score_text2, scale=5,position=(-0.6,0.35,-18), color=color.black)
score_top = Text(text="score:", scale=3,position=(-0.65,0.45,-18), color=color.black); highscore_text = int(high.x)
highscore_text2 = str(highscore_text)
highscore = Text(text=highscore_text2, scale=5, position=(0.6, 0.35, -18), color=color.black)
highscore_top = Text(text="high score:", scale=3,position=(0.45,0.45,-18), color=color.black)
respawn_texture = Entity(model='quad',scale=(0.3,0.1),position=(0,0,5),texture=load_texture('textures/replay'))
menu_texture = Entity(model='quad',scale=(0.3,0.1),position=(0,-0.1,5),texture=load_texture('textures/main_menu'))
while quantity.x < 0:
    quantity.x = 0

class background(Button):
    def __init__(self):
        super().__init__(
            model = 'cube',
            parent=scene,
            color=color.white,
            position=(0,0,4.5),
            scale = (30,30,2))

    def input(self, key):
        if self.hovered:
            if key == 'left mouse down':
                playsound("audio/screeching.m4a", block=False)
                camera.z = 4
                points.x = 0

class Tile(Button):
    def __init__(self):
        quantity.x +=1
        placement = random.randint(-4, 4)
        potential_color_list = (color.red,color.black,color.black,color.black,color.black,color.black)

        super().__init__(
            model = 'quad',
            parent=scene,
            color= random.choice(potential_color_list),
            position=(placement,quantity.x * 2 + 3,3),
            scale = (random.uniform(0.1,3),random.uniform(0.5,3))),


    def input(self,key):
        if self.hovered:
            if key == 'left mouse down':
                if points.x == 0:
                    play('audio/Game_music.wav')
                if self.color == color.black:
                    play("audio/scored.wav")
                    destroy(self)
                    quantity.x -=1
                    amount = random.randint(1,3)
                    multiplier_calculations = points.x / 10 + 1
                    Multiplier = int(multiplier_calculations)
                    points.x += Multiplier
                    score.Text = points.x
                    score_text = int(points.x)
                    score_text2 = str(score_text)
                    score.text = score_text2
                    if quantity.x <= 0:
                        if amount == 1:
                            Tile()
                        if amount == 2:
                            Tile()
                            Tile()
                        if amount == 3:
                            Tile()
                            Tile()
                            Tile()

                if self.color == color.red:
                    play("audio/screeching.m4a")
                    camera.z = 4
                if high.x < points.x:
                    high.x = points.x
                    highscore_text = int(high.x)
                    highscore_text2 = str(highscore_text)
                    highscore.text = highscore_text2
                    score.Text=points.x

        if camera.z == 4:
            destroy(self)
    def update(self):
        speed = points.x / 40 + 3
        if camera.z == -20 and points.x != 0:
            self.y -= speed * time.dt
        else:
            self.position=(0,4,3)
            self.color = color.black
        if self.y <= -6.5:
            if self.color == color.black:
                playsound("audio/screeching.m4a", block=False)
                camera.z = 4
                destroy(self)
            if self.color == color.red:
                destroy(self)
                quantity.x -= 1
                if quantity <= 0:
                    amount = random.randint(1,3)
                    if amount == 1:
                        Tile()
                    if amount == 2:
                        Tile()
                        Tile()
                    if amount == 3:
                        Tile()
                        Tile()
                        Tile()
        if camera.z == 4:
            score.text = '0'
            destroy(self)
            Tile()
            quantity.x = 0


class menu(Button):
    def __init__(self):
        super().__init__(
            model = 'quad',
            color=color.clear,
            parent=scene,
            position=(0,-0.05,5),
            scale = (0.09,0.03))

    def input(self, key):
        if self.hovered:
            if key == 'left mouse down':
                playsound("audio/bounce.m4a", block=False)
                points.x = 0
                quantity.x = 0
                camera.z = 8

class play_again(Button):
    def __init__(self):
        super().__init__(
            model = 'quad',
            color=color.clear,
            parent=scene,
            position=(0,0,4.8),
            scale = (0.09,0.03))

    def input(self, key):
        if self.hovered:
            if key == 'left mouse down':
                playsound("audio/bounce.m4a", block=False)
                points.x = 0
                quantity.x = 0
                camera.z = -20
                Tile()

menu()
play_again()
background()
Tile()
app.run()`
1 Answers

while loops will block the main ursina loop, and thus stop ursina fron running until the while loop has finished. To go around that you could use pyaudio in another thread. However, is there any reason why you can't use ursina's Audio class to play sound instead?

Example:

a = Audio('jump_sfx')

If you need to generate the waveform from code. It would make sense to me to do that beforehand and save it, not every time you want to play it.

Related