How can I play song repeatedly using pygame.mixer.music.play()? - python

I have tried to repeat a song(mp3) using pygame module. The code is as follows from the site https://www.studytonight.com/tkinter/music-player-application-using-tkinter
When calling this function, it comes out only one time, of course it's natural.
def playsong(self):
# Displaying Selected Song title
self.track.set(self.playlist.get(ACTIVE))
# Displaying Status
self.status.set("-Playing")
# Loading Selected Song
pygame.mixer.music.load(self.playlist.get(ACTIVE))
# Playing Selected Song
pygame.mixer.music.play()
To repeat this sound file I added loop like this, but it plays just one time.
How can I repeat many times over and over this? Should I call the function playsound(self) many times I want to repeat?
def playsong(self):
for i in range(3):
# Displaying Selected Song title
self.track.set(self.playlist.get(ACTIVE))
# Displaying Status
self.status.set("-Playing")
# Loading Selected Song
pygame.mixer.music.load(self.playlist.get(ACTIVE))
# Playing Selected Song
pygame.mixer.music.play()

The first optional argument (loops) to pygame.mixer.music.play() tells the function how often to repeate the music.
For instance pass 1 to play the music twice (repeat once):
pygame.mixer.music.play(1)
Pass -1 to play the music infinitely:
pygame.mixer.music.play(-1)
See pygame.mixer.music.play():
play(loops=0, start=0.0, fade_ms = 0) -> None
This will play the loaded music stream. If the music is already playing it will be restarted.
loops is an optional integer argument, which is 0 by default, it tells how many times to repeat the music. The music repeats indefinately if this argument is set to -1.

Related

python - play audio samples simultaneously and at different volumes [duplicate]

I'm trying to play multiple sounds simultaneously in Pygame. I have a background music and I want a rain sound to play continuously and play ocasional thunder sounds.
I have tried the following but my rain sound stops when thunder sound is playing. I have tried using channels but I don't know how to choose which channel to sound is playing from or if two channels can be played at once.
var.rain_sound.play()
if random.randint(0,80) == 10:
thunder = var.thunder_sound
thunder.play()
Thank you for your help
Pygame's find_channel function makes it very easy to play audio on an unused channel:
sound1 = pygame.mixer.Sound("sound.wav")
pygame.mixer.find_channel().play(sound1)
Note that by default, find_channel will return None if there are no free channels available. By passing it True, you can instead return the channel that's been playing audio the longest:
sound1 = pygame.mixer.Sound("sound.wav")
pygame.mixer.find_channel(True).play(sound1)
You may also be interested in the set_num_channels function, which lets you set the maximum number of audio channels:
pygame.mixer.set_num_channels(20)
You can only play one Sound at a time per channel, but you can play multiple channels at once. If you don't name the channels, pygame selects an unused channel to play a Sound; by default, pygame has 8 channels around. You can specify a channel by creating a Channel object. As for looping a sound indefinitely, you can do that by playing a sound with the argument loops = -1. You can find the documentation for these classes and methods at http://www.pygame.org/docs/ref/mixer.html
I would also suggest using the built-in module time, particularly the sleep() function that pauses execution for a specified time in seconds. This is because pygame.mixer functions that play a Sound return ASAP long before the sound finishes playing, and when you try to play a 2nd Sound on the same channel, the 1st Sound is stopped to play the 2nd. So, to guarantee that your thunder Sound is played to completion, it's best to pause execution while it's playing. I put the sleep() line outside the if-statement because inside the if-statement, the sleep() line won't pause execution if the thunder Sound isn't played, so the loop would just loop very quickly to the next thunder Sound, outputting far more frequently than "occasional."
import pygame
import random
import time
import var
# initialize pygame.mixer
pygame.mixer.init(frequency = 44100, size = -16, channels = 1, buffer = 2**12)
# init() channels refers to mono vs stereo, not playback Channel object
# create separate Channel objects for simultaneous playback
channel1 = pygame.mixer.Channel(0) # argument must be int
channel2 = pygame.mixer.Channel(1)
# plays loop of rain sound indefinitely until stopping playback on Channel,
# interruption by another Sound on same Channel, or quitting pygame
channel1.play(var.rain_sound, loops = -1)
# plays occasional thunder sounds
duration = var.thunder_sound.get_length() # duration of thunder in seconds
while True: # infinite while-loop
# play thunder sound if random condition met
if random.randint(0,80) == 10:
channel2.play(var.thunder_sound)
# pause while-loop for duration of thunder
time.sleep(duration)

How to get the position of music in pygame that is playing?

I want to play music and get its position in seconds or minutes of when the music is playing. I used the pygame.mixer.music.get_pos() but the code is not working.
def f5secforward():
print(pygame.mixer.music.get_pos())
pygame.mixer.music.play(0,pygame.mixer.music.get_pos()//1000+5)
print(pygame.mixer.music.get_pos())
the first 'get_pos' works but after I change the current position of the song with pygame.mixer.music.play(loop,time) it assigns the value of the get_pos to 0
I have searched more and I just found out that get_pos() is not taking where the music is playing it just get the time that the Python mixer is busy.
Is there any solutions?
If you store the first get_pos as an integer (say "oldsongtime") then add the time the second get_pos produces (in your function it will be close to 0) and the time you're adding on (5000) you should get about the right time.
I say about because when I tried to make my own fast forward function the track sometimes jumped much further forward than it should have. Might be something to do with my pre_init not using the default frequency (on all the PCs I've used 44,100 Hz is too slow).
def f5secforward():
oldsongtime = pygame.mixer.music.get_pos()
change = 5000
print(oldsongtime)
pygame.mixer.music.play(0, (oldsongtime+change)/5000)
addedtime = pygame.mixer.music.get_pos()
print(addedtime)
currenttime = oldsongtime+change+addedtime
return currenttime

Music Player - problem with skipping songs + pause etc

I've been making a music player program to practice using Tkinter for my NEA (Alevel computer science project) I have a shuffle function in the program but can't seem to find a way of pausing/skipping songs.
Example of code: (Obviously I have imported tkinter, random and winsound, also I have more songs)
def song1():
print('song name - song artist')
winsound.PlaySound(r"song address",winsound.SND_FILENAME)
def shuffle():
ShuffleButton.grid_remove()
playlist=list(range(1,NumberOfSongs+1))
random.shuffle(playlist)
print(playlist)
i=int(0)
while i<=NumberOfSongs:
if playlist[i]==1:
song1()
i=i+1
Btw I know there is probably a much simpler way to make a music player but I can actually understand this way.
Replace SND_FILENAME with SND_ASYNC this will allow you to change the song whilst one is playing.
When using SND_ASYNC the shuffle function needs to be amended so the song will play - this can be done by using time.sleep(LengthOfSongInSeconds) underneath winsound.PlaySound(r"SongAddress",SND_ASYNC) this will allow the song to play before the next (el)if playlist[i]==x: will play the next song in the list. I am aware that there will be a more efficient way of allowing the song to be played in full and I am working on the solution.

Pygame - When conditions are met, displaying pictures and stopping music?

Sound first - I currently have background music playing but I'd like to stop it and play a victory or defeat song when the user wins or loses. At the moment I am unable to get the background music to stop. I'm assuming I put the command to stop the music and play the other file in the condition. Am I correct in this?
I have tried things such as bgm_music = True while bgm_music == true: code and during the condition bgm_music = False but this stops my program from working.
EDIT - Okay, for the music just loading a new song works perfectly so I think I'm all-right with the sound section.
As for the picture. I'd like to do the same as the music essentially. I want to display a victory or defeat image on top of everything once the user wins or fails. Again, I have tried a similar boolean thing as above but to no avail.
EDIT 2 - I have managed to display the picture but I need to know how to get it on top (Currently the sprites are on top of it)
It think you should keep track of different states, example:
1: Gameplay
2: Song
3: Game Over screen
Then execute code according to the state in your main loop:
if state == 1:
# gameplay code
# if over start music and change to state 2
elif state == 2:
# song playing
# decrese song_counter
if song_counter == 0:
# stop music
# change to state 3
elif state == 3:
# blit game over image
# decrease game_over_counter
if game_over_counter == 0:
# reset game
# change to state 1

In pygame (or even in python in general), how would I create a loop that keeps executing while a sound is playing?

In pygame is there a way to tell if a sound has finished playing? I read the set_endevent and get_endevent documentation but I can't make sense of it or find an example.
I'm trying to specifically do the following:
play a sound
While the sound is playing keep iterating on a loop
When the sound has finished playing, move on.
I did check the other questions that were asked - didnt find anything specifically targeting python / pygame.
Thanks!
The trick is that you get an object of type pygame.mixer.Channel when you call the play() method of a sound (pygame.mixer.Sound). You can test if the sound is finished playing using the channel's get_busy() method.
A simple example:
import pygame.mixer, pygame.time
mixer = pygame.mixer
mixer.init()
tada = mixer.Sound('tada.wav')
channel = tada.play()
while channel.get_busy():
pygame.time.wait(100) # ms
print "Playing..."
print "Finished."
The examples assumes you have a sound file called 'tada.wav'.
You can use some code like this:
import pygame
pygame.mixer.music.load('your_sound_file.mid')
pygame.mixer.music.play(-1, 0.0)
while pygame.mixer.music.get_busy() == True:
continue
And, it doesn't have to be a .mid file. It can be any file type pygame understands.
To use set_endevent you have to do something like this:
# You can have several User Events, so make a separate Id for each one
END_MUSIC_EVENT = pygame.USEREVENT + 0 # ID for music Event
pygame.mixer.music.set_endevent(END_MUSIC_EVENT)
running = True
# Main loop
while running:
events = pygame.event.get()
if events:
for event in events:
...
if event.type == END_MUSIC_EVENT and event.code == 0:
print "Music ended"
...
pygame.mixer.pre_init(44100, 16, 2, 4096) # setup mixer to avoid sound lag
pygame.init()
startmusic="resources\snd\SGOpeningtheme.ogg"
pygame.mixer.set_num_channels(64) # set a large number of channels so all the game sounds will play WITHOUT stopping another
pygame.mixer.music.load(startmusic)
pygame.mixer.music.set_volume(0.3)
pygame.mixer.music.play(-1) # the music will loop endlessly
once the above code is executed the music will continue to play until you stop it or fade out as per the pygame site info.
You can loop to your heart content and the music will continue. If you need the music to play twice, instead of -1 put 1. Then the music will PLAY once and REPEAT ONCE.
You can check if the stream is playing by doing pygame.mixer.music.get_busy().
If it returns True it is. False means it has finished.

Categories