Trying to queuing up multiple files in pygame.music - python

I'm trying to get a queue of music files in random order for playing on a raspberry pi using pygame. But I'm finding an issue (limitation?) of where it seems to be only able to queue up song.
I've tried to reproduce it on my desktop (so I can debug it) but the queuing doesn't seem to work at all on it. It can't even queue up 1 other file. Hence, I'm wondering why it won't even work on my desktop. I've stripped down my desktop testing/debugging code to as follows:
import pygame
import random
import time
soundType = ".ogg"
# files are in the same directory at the moment
musicLocation = ""
musicFiles = (("takepills01", 0), ("takepistol01", 0), ("takesniper01", 0), ("taunt01", 0), ("teamkillaccident02", 0), ("thanks01", 0))
queuedFilesResut = []
pygame.mixer.init()
# choose a random file to start
selectedMusicName = musicFiles[random.randint(0, len(musicFiles) - 1)][0]
pygame.mixer.music.load(musicLocation + selectedMusicName + soundType)
queuedFilesResut.append(selectedMusicName)
# choose a random file to follow
selectedMusicName = musicFiles[random.randint(0, len(musicFiles) - 1)][0]
pygame.mixer.music.play()
pygame.mixer.music.queue(musicLocation + selectedMusicName + soundType)
queuedFilesResut.append(selectedMusicName)
# not sure if it matters if the play() call is before or after the queue() call
# seen it both ways on a few examples
#pygame.mixer.music.play()
# print to see what was selected
print queuedFilesResut
# now sleep for a bit while the music plays, the testing files are very short, each only 1-2 seconds
time.sleep(5)
What happens right now for the above code is that whatever file is selected first plays, then that's it. Here is how I was attempting to queue up multiple files, before I realised I couldn't even queue up 1 file:
for counter in range(0, 10):
selectedMusicName = musicFiles[random.randint(0, len(musicFiles) - 1)][0]
pygame.mixer.music.queue(musicLocation + selectedMusicName + soundType)
queuedFilesResut.append(selectedMusicName)
I was really expecting pygame to be able to just play a song and queue up 'n' files, then I could just forget about it and leave it run its course.
Although this is just a question more on why the above script doesn't work, I should add that when I go back to the raspberry pi, I'm calling the music playing python script via lighttpd and thus need the method call to return to be responsive -I don't think I can use a loop to check for when the music is done playing/check the event queue. Lighttpd also seems to limit python to just 1 thread.
I do have an idea on how to get around this whole issue/limitation, but it involves running a loop as an entirely separate python process on startup and having a written file to communicate between lighttpd-python and python. I am hoping to find a nicer/cleaner way.

I know this was in 2014 and was with python 2.7 but this could be useful to others with this problem.
I am using python 3.4.
You could try to put your randomly chosen files in a list and play the list like a playlist. The songs will play from left to right in the list.
E.g.
for file in musicList:
#play song here
time.sleep(5)
You can add files to this list mid program by using:
#Chosen random music file
songList.append(musicFile)
Hope this helps.
Cheers

Related

How can I play looping music in the background as other functions are being performed?

I am currently using the subprocess module to play .mp3 files. It works just fine getting them to play, but once I do subprocess.call(["afplay", "../music/songname.mp3"]), that's all the code will do until the entire duration of the song has finished playing. I want to make things happen while the song is playing. I don't know how easy this is but I've struggled to find people online asking about the same thing. Is it possible to use a different command with the same subprocess module and achieve this result? Is there a completely separate way to achieve this? I'm open to anything, but keep in mind I'm very new to this.
I have created a loop track so that, after a certain time in the song has been reached, it will instead play an identical track which has set beginning and end times that, when played back-to-back, create a perfect music loop. Once that first problem is solved, how can I rig this track to repeat infinitely in the background?
I'm very new to this.
You can try mixer from pygame module for playing sounds and repeat it infinitely in the 'background'.
import contextlib
with contextlib.redirect_stdout(None): # hide pygame intro text
from pygame import mixer # import mixer from pygame module
mixer.init() # initialize the mixer module
mixer.music.load('songname.mp3') # load media file
mixer.music.set_volume(0.5) # set playing volume
mixer.music.play(-1) # play & loops media for n times in arguments, -1 always looping
# for demonstration
from random import randint, choice
def demo():
a, b = randint(0,10), randint(0,10)
while True:
if int(input(f'{a} + {b} = ')) == a + b:
print(choice(['Correct!', 'Nice!', 'Excellent!', 'Genius!', 'Wow!']))
demo() if input('More (y/n)? ') == 'y' else print('Bye!'); break
else:
print(choice(['Wrong!', 'Nope!', 'OMG!', 'WTH!', 'Try Again!', 'LOL!']))
demo()
Try the native module threading. Please refer to this answer as guideline for non-blocking audio playback with threading.
subprocess forks then execs a process, but it waits for the process to finish before returning. you will need to do this in a separate thread, use an asyncio suprocess interface or do an initial a fork yourself. it is a bit tricky. what is also complicated, is that you will likely not get a perfect gapless playback by looping subprocess commands, as python will likely take a millisecond or two to re-execute the command.

How to replace keyboard output using python

I am not exactly sure how to word this question so I'll try to explain my problem here.
I am trying to code a program that reads text (for example an essay) from a txt file and then types each letter from that txt file as you type a letter on the keyboard (think those hacker games where you mash the keyboard and it looks like you're typing something that you are not).
Currently I am handling this by simply deleting the character right after but I noticed that I needed to add a delay for this to work with any stability whatsoever. A delay of 0.05 works okay, but any lower is unstable and 0.05 is already far too much for my liking. I also tried using keyboard.press_and_release() but this needed just as large of a delay without breaking.
I am using the keyboard module because it works on both Windows and Mac which is a must have. I am also not exactly sure that I understand why this is happening especially with the press and release function so hopefully someone might know an answer or maybe a different module to use. I have also tried pyautogui and that was even worse.
import pyautogui
import time
import keyboard
# only keyboard needs to be pip installed i think
if __name__ == '__main__':
keyboard.wait("ctrl")
time.sleep(2)
inFile = open('Essay', 'r')
while True:
line = inFile.readline();
# if line is empty meaning file is reached
if not line:
break
while len(line) > 0:
keyboard.read_key()
time.sleep(0.05)
keyboard.press("backspace")
time.sleep(0.05)
keyboard.press(line[0])
line = line[1:len(line)]
time.sleep(0.05)
keyboard.press("enter")
I am not sure but it may help you. Install the PyPI package:
pip install keyboard
or clone the repository (no installation required, source files are sufficient):
git clone https://github.com/boppreh/keyboard
or download and extract the zip into your project folder.
Then check the API docs below to see what features are available.
Example:
import keyboard
keyboard.press_and_release('shift+s, space')
keyboard.write('The quick brown fox jumps over the lazy dog.')
keyboard.add_hotkey('ctrl+shift+a', print, args=('triggered', 'hotkey'))
# Press PAGE UP then PAGE DOWN to type "foobar".
keyboard.add_hotkey('page up, page down', lambda: keyboard.write('foobar'))
# Blocks until you press esc.
keyboard.wait('esc')
# Record events until 'esc' is pressed.
recorded = keyboard.record(until='esc')
# Then replay back at three times the speed.
keyboard.play(recorded, speed_factor=3)
# Type ## then press space to replace with abbreviation.
keyboard.add_abbreviation('##', 'my.long.email#example.com')
# Block forever, like `while True`.
keyboard.wait()
Courtesy: https://softans.com/how-to-replace-keyboard-output-using-python/

Reading a file every 30 minutes in Python

As you see in the below code, it is possible to open a file in a directory and read it. now i want live_token read the file every 30 minutes and print it. Can anyone help me in this regard?
I found below code as scheduling to do a job but i don't know how to do needful modifications.
schedule.every(30).minutes.do()
Sorry if this question is so basic, I am so new with Python.
def read_key():
live_key_file_loc = r'C:\key.txt'
live_key_file = open(live_key_file_loc , 'r')
global key_token
time.sleep(6)
live_token=live_key_file.read()
print(live_token)
import time
sleep_time = 30 * 60 # Converting 30 minutes to seconds
def read_key():
live_key_file_loc = r'C:\key.txt'
live_key_file = open(live_key_file_loc, 'r')
global key_token
time.sleep(6)
live_token = live_key_file.read()
print(live_token)
while(True): # This loop runs forever! Feel free to add some conditions if you want!
# If you want to read first then wait for 30 minutes then use this-
read_key()
time.sleep(sleep_time)
# If you want to wait first then read use this-
time.sleep(sleep_time)
read_key()
#jonrsharpe is right. Refer to schedule usage. You should have a script which should keep running always to fetch the token every 30 minutes from the file. I have put below a script which should work for you. If you dont want to run this file in python always, look for implementing a scheduled job.
import schedule
import time
def read_key():
with open('C:\\key.txt' , 'r') as live_key_file_loc
live_token = live_key_file_loc.read()
print(live_token)
schedule.every(30).minutes.do(read_key)
while True:
schedule.run_pending()
time.sleep(1)
There are a few steps in this process.
Search for “Task Scheduler” and open Windows Task Scheduler GUI.
Go to Actions > Create Task…
Name your action.
Under the Actions tab, click New
Find your Python Path by entering where python in the command line. Copy the result and put it in the Program/Script input.
In the "Add arguments (optional)" box, put the name of your script. Ex. - in "C:\user\your_python_project_path\yourFile.py", put "yourFile.py".
In the "Start in (optional)" box, put the path to your script. Ex. - in "C:\user\your_python_project_path\yourFile.py", put "C:\user\your_python_project_path".
Click “OK”.
Go to “Triggers” > New and choose the repetition that you want.
For more details check this site -
https://www.jcchouinard.com/python-automation-using-task-scheduler/

Question with python, music and events, is there a more elegant way of programming this?

Goal: To create a program that will be able to turn off and on lights to music based on events that are triggered from midi notes.
Hello all, I am hoping that this isn't too broad of a question to ask. I am working on a project where I get events from a midi file and turn those events into time. I take a note from the midi file and append it to a list as the time it was placed
Example:
https://imgur.com/swZsrk9
I take all of those and place them into a list. Don't worry about how I do that as that is not my main goal to discuss. I've just substituted the list with a hard-coded one on my example code.
I now have a list of times that I want lights to either turn on or off, now I just need to set an infinite loop with a timer that starts at 0 seconds (with the start of the song) and when the timer == (the next time in the list) it will print out a line. Here is my code:
import socket
import sys
import random
import time
from pygame import mixer
from mido import MidiFile
masterList = [12.37, 14.37, 15.12, 15.62,16.36, 17.61, 18.11, 19.11, 19.61, 20.35,]
mixer.init()
song = mixer.Sound('song.wav')
startTime = time.time()
endTime = startTime + song.get_length()
print(masterList)
print('Starting song.')
song.play()
print('Playing song, timer:',startTime)
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) == masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
#print('playing...')
time.sleep(.01)
mixer.quit()
Here is a video of it runing:
https://www.youtube.com/watch?v=VW-eNoJH2Wo&feature=youtu.be
Ignore the deprecation warnings
It works but sometimes, due to the nature of programming, the time.clock() does not always == the next item in the list. I knew that this would be a problem going in as you can't rely on how long the code takes to execute. Sometimes it takes a few more milliseconds than usual to complete a while loop so then when you call the time.clock() method it != the next time in the list. Then the list does not remove it's first item and then it will never equal that first item.
I tried going by 10 milliseconds (.1) but it doesn't give me the accuracy I need.
Also, it seems clunky, sometimes the events are delayed a few milliseconds and it makes the effect not as pleasing. As you can see from my video the times of the prints aren't lined up completely where they need to be, even though they are perfectly placed on where they need to be in the midi file.
Question: Is there a more elegant way of tackling this? I seem to keep finding ways of patching it to work better and then it always goes back to the nature of programming, where the cpu always is unreliable. I've been trying to think of different ways of doing this but I can't come up with any. Your help would be much appreciated!!
Since you're deleting the notes as you play them, have you tried using >= instead of ==?
E.g.,:
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) >= masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
That way the note will play as soon as possible after the specified time, and remove it from the queue. Only way to know actual performance is to test it, but at the very least it won't skip notes.

Python 2.X / Tkinter needs print to run

Firstly, very much Py Newby!
I have written a program to import data from a file and display it as an image using tkinter. The loop that is misbehaving runs thus:
Get data and plot
for x in xrange(WIDE):
for y in xrange(HIGH):
dataPointLo = inFile.read(1)
dataPointHi = inFile.read(1)
pixelValue = ((ord(dataPointLo) + 256*(ord(dataPointHi)))-31500)
colour = rgb[pixelValue]
#print below makes prog run!
print pixelValue
img.put(colour, to=(x,y))
As suggested by the comment, leaving out the print stops it working, but it locks one core of the processor at 100% for as long as you leave it (well at least 20 mins!). This effect occurs both in IDLE and from the command line (Ubuntu 12.04). Of course, the print to the IDLE window slows the program down, so I would like to remove it! Any thoughts?
it sounds like the process you are running takes a long time to complete, i would suggest that the reason you think it stops is because the window doesn't update while the process is busy unless you tell it to. i suggest you add a function like the following to your code and call it once before you enter your loop:
def keep_alive(self):
self.update()
self.after(100, self.keep_alive)
this way you are adding an event to update the window every 100ms(ish) to the event loop, which will keep the program responsive. you can adjust the timing to suit you, too often will slow your loop down, too far apart and the program will feel sluggish.

Categories

Resources