Reputation: 55
I am making a little fantasy console in python and pygame and I have stumbled upon a problem. I was making a music editor that can make chiptune tunes, but when I play them using the pygame.mixer.Sound method, it pauses everything and plays the sound. For example, if I play a sound every time the hero picks up something, everything would freeze, it would play the sound, and then everything will resume. This is not a big deal at first, but it makes doing something like background music impossible. Is it possible to fix this?
I have tried using the playsound library, but that freezes everything as well.
def music(notes):
note_list = ["c","c2","d","d2","e","e2","f","f2","g","g2","a","a2"]
for i in note_list:
exec("{} = pygame.mixer.Sound('res/sounds/{}.wav')".format(i,i))
for i in notes:
for j in i:
exec("pygame.mixer.Sound.play({})".format(j))
time.sleep(.2)
I expect the program to be able to play sound using the pygame.mixer.Sound method and do other things at the same time, but what actually happens is that everything freezes, plays the sound, and then everything resumes.
Upvotes: 1
Views: 469
Reputation: 9766
The sound will play in a different thread and will not halt the execution. However, your loop contains time.sleep(.2)
, which will halt the execution for 0.2
seconds. And you're doing it for every note, which means that if you have a tune with 10 notes, it'll halt your program for 2 seconds.
There are many different solutions to your specific problem which all depends on how you've structured the code where you call this function. One solution might be to schedule events, and then play them when they appear in the event queue. Another is to call the individual sounds when they are supposed to be played. Both require a game loop, which I doubt you have since you're creating a console game.
I would go the easy route and combine the sounds to the joint sound you actually want to play, instead of playing many different sounds in succession. You can use some program such as Audacity to edit sound files. Then, you wouldn't even need a function. You could just call pygame.mixer.Sound.play(zelda_pickup_tune)
and everything would work without halting (assuming zelda_pickup_tune
is a variable that holds a valid Sound
object).
Also, don't use exec
. It's slow and could potentially be a security risk if you were ever to let other people use your code (not in you're exact use currently, but it can easily happen if you do some minor changes later on). It's also a bit "magic" and it's not possible to rewrite this code in other languages.
I would suggest a more standard approach to problems like this and use a dictionary.
def music(notes):
note_list = ["c","c2","d","d2","e","e2","f","f2","g","g2","a","a2"]
sounds = {} # Empty dictionary
for i in note_list:
sounds[i] = pygame.mixer.Sound('res/sounds/{}.wav'.format(i)) # Add note i as key and the sound as value.
for i in notes:
for j in i:
sounds[j].play() # Look up the sound with key i and play the sound.
time.sleep(.2)
Upvotes: 1