So I'm making a music player with the PyMedia module and the Tkinter module. I've been Googling for an answer on to to "check" if PyMedia.startPlayback is busy playing a song, but so far I've been unsuccessful. My goal is to be able to play the next song in the queue when the current song stops playing.
for example:
def Listen(songs):
global player
while True:
songs+=1
def play(number):
player.startPlayback(number)
def pause():
player.pausePlayback()
#init pymedia player
player= pymedia.Player()
player.start()
play(songs)
#wait till song is done playing...
#After finished continue on to the next one
play(songs)
This isn't the exact code but it is the gist of it.
I have python 2.7 on Windows 7. Thanks for you input.
http://pymedia.org/docs/pymedia.player.html
The docs list an isPlaying function for the player. They even use it in the example for the while loop.
Related
I'm currently building a python code to play Blackjack where I need to be able to call certain functions uppon keypress without necessarily being in the terminal. I found this keyboard module which helped but I came across this issue.
def hit_or_stand(deck,hand):
global playing
print ("\nWould you like to Hit or Stand? Enter 'h' or 's'")
if keyboard.is_pressed('h'):
hit(deck,hand)
if keyboard.is_pressed('s'):
print("Player stands. Dealer is playing.")
playing = False
Let me explain what this function does as I don't want to overload everyone with the entire code. Essentially this function is called in a loop until the player decides to hit s which declares playing as False and therefore stopping the loop. If the player hits h then the hit function is called which draws a card. The player can draw as many cards.
My problem right now is that this code doesn't wait for user keypress. It loops extremely fast repeating it. I only want it to loop after either h or s is pressed.
I tried using keyboard.wait('h') on the line above the first if but then this doesn't allow the user to press s and therefore declare playing as False.
What I'm looking for is something along the lines of keyboard.wait('h'or's') but I know this does not work.
Thank you for your help. I am using python 3.7.9
EDIT: Keyboard Module I am referring too:
https://pypi.org/project/keyboard/
Use keyboard.read_key() to wait for any input.
If it's not h or s ,read_key again.
import keyboard
def mywait():
keyboard.read_key()
def my_function():
print("Hello")
def my_exit():
quit()
keyboard.add_hotkey("p", my_function)
keyboard.add_hotkey("esc", my_exit)
while True:
mywait()
To be specific, I need to play sound in a while loop which is fast to execute. And the audio needs to be played separately. I've tried various functions/libraries: playsound, winsound, vlc. But none of them meet my demand.
Either the sounds are overlapped, or I need to wait for the sound to finish to continue the next line of code, which blocks the whole process, making the program running with unbearable lags.
Matters in playsound, winsound, vlc:
playsound: has block option but will block the process (with block=True) or overlap the sound (block=False).
winsound: with SND_ASYNC option, say I have audio A and audio B (which needs to be played after audio A), if audio B is played, audio A will stop immediately.
vlc: [000001ba245794d0] mmdevice audio output error: cannot initialize COM (error 0x80010106), which is kind of weird and nothing useful was found on Google. And this method seems not a good option to me and others. I use this simply for its is_playing() function and I can place the next sound to a queue.
So any advice?
If you're just after playing a sound and having it interrupt whatever was playing before, winsound does just that:
import winsound
from time import sleep
winsound.PlaySound("sound.wav", winsound.SND_ASYNC | winsound.SND_FILENAME)
sleep(1)
winsound.PlaySound("sound.wav", winsound.SND_ASYNC | winsound.SND_FILENAME)
sleep(3)
In this example (assuming sound.wav is longer than a second), the sound will start playing, be interrupted after 1 second and start playing again. The second sleep is there to avoid the script ending before the sound stops (stopping the script stops the sound).
If you want to queue up sounds to play one after the other, while your code keeps running:
import threading
import queue
import winsound
from time import sleep
q = queue.Queue()
def thread_function():
while True:
sound = q.get()
if sound is None:
break
winsound.PlaySound(sound, winsound.SND_FILENAME)
if __name__ == "__main__":
t = threading.Thread(target=thread_function)
t.start()
q.put("sound.wav")
print('One...')
sleep(1)
q.put("sound.wav")
print('Two...')
sleep(1)
q.put("sound.wav")
print('Three...')
q.put(None)
t.join()
This simple example queues up a sound which the thread starts playing, then while it is playing, it queues up the next one and a bit later a third. You'll noticed that the sounds play one after the other and the program only stops when the sounds complete playing (and the thread stops due to the None at the end of the queue).
If you're looking to play one sound over the other and have them mix, using winsound won't work, but you can use libraries like pyglet.
For example:
import pyglet
window = pyglet.window.Window()
effect = pyglet.resource.media('sound.wav', streaming=False)
#window.event
def on_key_press(symbol, modifiers):
effect.play()
#window.event
def on_draw():
window.clear()
if __name__ == "__main__":
pyglet.app.run()
This example opens a window and every time you press a key, it'll play the sound immediately, without interrupting previous sounds. The program ends immediately when you close the window.
This can be easily done with playsound.
playsound.playsound('alert.mp3', False)
Setting the second argument to False makes the function run asynchronously.
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.
I'm trying to shuffle a list of mp3 files and then play through them with pyglet. Once the player runs out of sources I want to re-shuffle the list, and then play through them again. This process would happen infinitely. I have been able to get pyglet to play through the sources once, but the on_player_eos event is never fired when I run out of sources. I'm not sure exactly what I am doing wrong, or if I am approaching it in the wrong way. I've tried a couple ways of doing it, but have had no luck getting it to work. Here is the code
import os, sys, random, pyglet
from random import shuffle
song1 = pyglet.media.load('beats/breathe.mp3', streaming=False)
song2 = pyglet.media.load('beats/everything.mp3', streaming=False)
song3 = pyglet.media.load('beats/jazz.mp3', streaming=False)
player = pyglet.media.Player()
# Play beatz
def beatz():
playlist = [song1, song2, song3]
shuffle(playlist)
player.queue(playlist[0])
player.queue(playlist[1])
player.queue(playlist[2])
player.play()
def on_player_eos():
print('repeating')
beatz()
player.on_player_eos = on_player_eos
pyglet.app.run()
I have also tried replacing the 'player.on_player_eos = on_player_eos' with
player.push_handlers(on_player_eos)
But it doesnt seem to do anything either. Any help appreciated.
UPDATE:
I was able to get this to work by simply adding 'streaming=False' to each song variable. Streaming sources in pyglet can only be queued once on a player object, while static sources can be queued as many times as you want.
With recognizing the event 'on_player_eos', I also wasn't aware of the pyglet event loop. In order for pyglet to pick up the events I wanted it to, the code below had to be run.
pyglet.app.run()
This fixed my problems.
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.