How to continue a sound in Pygame? - python

I have a sound that I wish to play.
My code;
[...]
if var_camera_flip == 1:
if var_camera != 4:
pygame.mixer.Channel(2).play(pygame.mixer.Sound(r'audio\camera\camera motor.mp3'), -1)
else:
pygame.mixer.Channel(2).stop()
else:
pygame.mixer.Channel(2).stop()
[...]
This code is in a subroutine that I call. What happens is that it restarts the sound each time it runs. What I want is that is the sound to continue playing until it is told not to.

Do not stop a sound, but pause it with pygame.mixer.Channel.pause:
pygame.mixer.Channel(2).pause()
Once a sound is paused it can be continued with pygame.mixer.unpause:
pygame.mixer.Channel(2).unpause()

Related

Trying to play music while opening a door

EDIT : replaced GPIO.PUD_UP to GPIO.PUD_DOWN and while loop looks like this now :
playing = False
while True:
if GPIO.input(26)==False:
if not playing:
pygame.mixer.music.play()
playing = True
else:
if playing:
pygame.mixer.music.stop()
playing = False
I'm trying to play music while opening a door, doing it with a raspberry pi Zero WH and an Hall effect sensor. I'm rather new to python, but its fairly simple. But im stuck because i can't find how to do exactly what I want.
So I want to play music when the door is opened (GPIO is LOW), but i also want it to stop when it is closed (when GPIO is UP then). It seems that I can't find how to do it. Here's my code :
import RPi.GPIO as GPIO
import time
import pygame
import pygame.mixer
pygame.mixer.init()
pygame.init()
scary = pygame.mixer.Sound("scary.wav")
pygame.mixer.music.set_volume(0.1)
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
if GPIO.input(26)==False:
pygame.mixer.music.play()
while GPIO.input(26)==False:
pass
else:
pygame.mixer.music.stop()
while GPIO.input(26)==True:
pass
I want music to play as soon as the door open, only once (its about a minute long), but can stop whenever the door close. How should I do it ? (time.sleep(x) just delays the whole loop, or maybe idk how to use it?) Thanks !
Addd a variable to keep track if the music is currently playing:
playing = False
while True:
if gpio is high:
if not playing:
play()
playing = True
else:
if playing:
stop()
playing = False
You can't rid of the indentation by using if/else with and/or statements.

Tkinter "intervention" in a logic loop

So, I'm not sure the title describes my issue in a comprehensive manner.
I have made a working "loop" code in Python (even with working recursive functions) for some sort of a card game "AI". See the following pseudo-code:
def move():
if Turn == "Computer":
if Computer cannot play:
return False
else:
Do some "AI" stuff... the computer plays
Turn = "Player"
move()
elif Turn == "Player":
if Player cannot play:
return False:
else:
in = input("Select Card: ")
****So here the loop stops and waits for the input from the player
...then the input is evaluated and "played" as a player move
Turn = "Computer"
move()
while continue:
continue = move()
So if the computer can play, it plays the card, the turn changes to Player and the move function is called again, otherwise false is returned and the PC-Player back and forth turn is over. In the Player's turn the loop stops to wait for the user input from terminal and then it continues...
So far everything works, but now I want to implement a GUI for player input. I have some basic knowledge with Tkinter and so far I created buttons on screen rapresenting the player's cards. The question is how can I "stop" the loop waiting for the user to click a button (corresponding to the card - or the PASS TURN). Maybe with some sort of threading but sounds complicated... there must be an easier solution like in the "Terminal input version" that I have already working.
Thanks
You can't use a loop in a GUI, because the GUI has it's own loop that needs to run. The mainloop() in tkinter. You need to shift your planning to "event driven" programming. It sounds like in your case the event would be the user choosing a card.
def player_chooses_card():
# graphic and logic updates for player's choice
# computer turn
if Computer cannot play:
trigger graphic for end of game
else:
Do some "AI" stuff... the computer plays
# function is done; back to idle state waiting for an event
FWIW making a loop with recursion is bad style in python.
I feel your pain on the Tkinter loops. It was a hard lesson for me to learn as well. Loops such as while and for DO NOT WORK in tkinter. The way I typically solve this problem is with "root.after." Take the code in your loop and define it as a command (adding root.after(1, name of your command) like so:
def myloop():
move()
root.after(1, myloop)
Then, call it for the first time right before 'root.mainloop', like so:
<your other code>
root.after(1, myloop)
root.mainloop()
Also keep in mind that Tkinter does not make nice nice with multiprocessing/threading within mainloops, so you have to set up each process/thread as its own canvas and root.
Finally, you could set up a series of if statements and variables to separate your loop into chunks so that it stops and starts based on player input. For example,
def myloop():
if playerhasdonething == True:
move()
else:
print("waiting on player")
root.after(1, my mainloop)
I apologize if I missed the point of your question, this is how I personally would try to solve your problem

Tkinter and waiting

I am making a mp3 player using python 3 and Tkinter, using pygame.mixer for the MP3s. When you input a directory and press play it auto finds all the MP3s in the directory (using glob) and adds them to a list. I use a for loop to load then play the music, but when it plays it starts the next song immediately and automatically repeats till the end of the list where it plays only that song. I tried using time.sleep() which works but freezes the program. How can I wait till the song is over to start the next one and not freeze the program.
My current code (just the function to play the music):
def play():
print("playing")
global playing
playing = True
direct = directorye.get()
direct = direct.lower()
if direct.endswith(".mp3"):
mixer.music.load(directorye.get())
mixer.music.play()
else:
dire = r"C:\Users\agweb\Downloads\Music" #for the time being I just hard coded the directory
mp3s = glob.glob(dire + r"\*.MP3") # adds all MP3s in directory to list
#mp3s =+ glob.glob(directorye.get() + "*.MP3")
for i in mp3s:
print(i)
mixer.music.load(i)
mixer.music.play()
audio = MP3(i)
time.sleep(audio.info.length) #works but freezes program
There are several approaches possible.
Since tkinter is thread-safeish(*) on Python 3, probably the easiest way is to start a slightly modified version of your play function as a second thread.
In the global context, create a threading.Event. I would suggest the name stop_playing.
In the play function, only sleep for a little interval at a time, checking if stop_playing is set:
for i in mp3s:
mixer.music.load(i)
mixer.music.play()
audio = MP3(i)
playtime = 0
interval = 100 # ms
while playtime < audio.info.length:
time.sleep(interval)
playtime += interval
if stop_playing.is_set():
# TODO: stop the current playback.
# Then exit the thread.
return
The new callback for the "Play" button should create a thread for play() and start() it.
The callback for the "Stop" button should simply call stop_playing.set(). That will cause the playing thread to stop.
(* Provided it uses a tcl compiled with threading enabled.)
This solution work you can test it
from threading import Thread
import pygame
from itertools import cycle
def put_next_music_inside(loop_on_musics, stop_event):
for cur_music in loop_on_musics:
while pygame.mixer.music.peek(stop_event):
pass
pygame.event.get(stop_event)
pygame.mixer.music.load(cur_music)
pygame.mixer.music.play()
pygame.mixer.init()
pygame.display.init()
END_OF_MUSIC_EVENT = -100
pygame.mixer.music.set_endevent(END_OF_MUSIC_EVENT)
list_of_music = []#fill it with musics'path
first_music = list_of_music[0]
del list_of_music[0]
list_of_music.append(first_music)
loop_on_musics = cycle(list_of_music)
t = Thread(target=put_next_music_inside, args=(loop_on_musics, END_OF_MUSIC_EVENT))
t.start()
pygame.mixer.music.load(first_music)
pygame.mixer.music.play()

How do I pause code in an if function in pygame?

How do you make the code stop for a moment before checking for something else? (I'm new to code)
if BonusTime==True and Drop==True:
if event.type == pygame.MOUSEBUTTONDOWN:
window.blit(Fired,(mouseX-12,mouseY-12))
Cankill=True
#I want it to delay here
Cankill=False
There is a cross hair that follows the mouse and when I click it, it fires. The problem is, you can just hold the mouse down and leave the cross hair in one place. Whenever an enemy walks into the cross hair, they die. I need it so even when you hold it will only fire once. I plan to make it delay the if statement, to set "Cankill" to true and then wait a second, after waiting, it should set "Cankill" to false. I've already looked through a lot of other people's questions similar to this and haven't found something I can understand. So if you could please help me find out how to delay it in the way I need.
"Pausing" is not what you want - if you do that, your game will just freeze, and nothing will move (since you are usign the OS mouse pointer, maybe it could move).
Anyway, the function to "pause" inside a game is pygame.time.wait(1000) - the number is in miliseconds.
Waht you actually need is to mark down the time the click was made, continue with the game, and when 1 second has passed, reset the variable back to the other state.
Something along:
last_trigger = 0
while True:
# game updating code goes here (getting events, and such)
...
if Cankill and pygame.time.get_ticks() - last_trigger > 1000:
Cankill = False
if event.type == pygame.MOUSEBUTTONDOWN:
window.blit(Fired,(mouseX-12,mouseY-12))
Cankill=True
last_trigger = pygame.time.get_ticks()
The "get_ticks" call returns the number of miliseconds that passed since pygame was initialized - and is usefull for this time of timers.

pygame is not working

I am trying to play a song with pygame and it is not playing the song.
My code:
import pygame,time
pygame.init()
print "Mixer settings", pygame.mixer.get_init()
print "Mixer channels", pygame.mixer.get_num_channels()
pygame.mixer.music.set_volume(1.0)
pygame.mixer.music.load('C:/1.mp3')
print "Play"
pygame.mixer.music.play(0)
while pygame.mixer.music.get_busy():
print "Playing", pygame.mixer.music.get_pos()
time.sleep(1)
print "Done"
I am getting output as
Mixer settings (22050, -16, 2)
Mixer channels 8
Play
Done
Your code works for me, on Lubuntu 11.10 running Python 2.7.2, with an MP3 I converted from a Youtube clip. Have you checked that the mp3 is not zero length? Have you tried a wav file?
Lacking other explanations, I think it is conceivable that pygame.mixer.music.get_busy() could be returning false if the play(0) call hasn't finished starting its process or thread.
This would cause your code to skip the while loop, print "Done", and terminate, deleting the music player object and terminating playback before you got to hear anything. If this is the problem, you could try something like this after play(0) and before print Done:
pygame.mixer.music.set_endevent(pygame.USEREVENT)
finishedPlaying = False
while not finishedPlaying:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
finishedPlaying = True
break # only because we don't care about any other events
print "Playing", pygame.mixer.music.get_pos() # will print -1 on the last iteration
in the comments of pygame.mixer.music.play i found this:
November 18, 2010 7:30pm - Anonymous
Work Exmpl:
pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=4096)
sound = pygame.mixer.Sound('Time_to_coffee.wav').play()
also it seems that your sending 0 as the amount of times you want to repeat it thanks Iskar Jarak , -1 is infinity.
http://www.pygame.org/docs/ref/music.html#pygame.mixer.music.play

Categories

Resources