play multiple sounds concurrently using playsound - python

I have a program that calls a function that is supposed to play a sound immediately after invocation. Sometimes the duration inbetween the function calls is smaller than the duration of the sound itself, in which case i would like for the sounds to overlap. Here is my current approach:
from playsound import playsound
import threading
import os
playdq = []
def run_play_sound():
for i in range(2):
thread = threading.Thread(target=play_sound, args=(), daemon = True)
thread.start()
def play_sound():
while True:
if len(playdq)!=0:
o = playdq.pop()
playsound(os.path.join(os.path.dirname(__file__),o+".mp3"))
def play():
if len(playdq)==0:
playdq.append("soundname")
run_play_sound()
Unfortunately this approach is slightly laggy and the sounds are not immediately played when the "play" function is called. Is there a more efficient solution?

using pygame mixer worked for this purpose

Related

What is a simple solution to record audio in Python with pause, resume and no duration time?

I'm looking for a simple solution for audio recording with pause, resume and no duration time.
pyaudio, sounddevice, I can do something with them, but this is a rather low level.
The difficulty is that they require duration time for recording, that is, the recording time that must be set initially. In my case, the recording should continue until the appropriate code is called to stop.
I found code to record without duration time in sounddevice, but it's still complicated and not a library to use in other parts of the code:
https://github.com/spatialaudio/python-sounddevice/blob/master/examples/rec_unlimited.py
The easiest way to record that I was able to find is using the recorder library:
https://pypi.org/project/recorder/
Here is the code for a simple voice recorder that I managed to find:
import tkinter as tk
from tkinter import *
import recorder
window = Tk()#creating window
window.geometry('700x300')#geomtry of window
window.title('TechVidvan')#title to window
Label(window,text="Click on Start To Start Recording",font=('bold',20)).pack()#label
rec = recorder.Recorder(channels=2)
running = None
def start():
global running
if running is not None:
print('already running')
else:
running = rec.open('untitled.flac', 'wb')
running.start_recording()
Label(window,text='Recording has started').pack()
def stop():
global running
if running is not None:
running.stop_recording()
running.close()
running = None
Label(window,text='Recording has stoped').pack()
else:
print('not running')
Button(window,text='Start',bg='green',command=start,font=('bold',20)).pack()#create a button
Button(window,text='Stop',bg='green',command=stop,font=('bold',20)).pack()#create a button
window.mainloop()
But the question of pause and resume is still open.
Maybe you can advise something?
Thanks in advance!
I'd recommend using either the SimpleSound package or pyaudio
import simplesound as sa
import pyaudio as pa
for recording sound pyaudio might be a better choice, but have a play around and see what works for you <3

How to play different sound consecutively and asynchronously?

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.

No sound is played in pygame

I made a program to play music at random using python-pygame.
When I tried to run, the audio did not play ...
By the way, I think that the problem is pygame because the volume is MAX and it can be heard normally even when playing .mp3
music.py
import pygame
import sys
import glob
from random import shuffle
x = glob.glob("sound/*.mp3")
shuffle(x)
print(x[1])
pygame.mixer.init()
pygame.mixer.music.load(x[1])
pygame.mixer.music.play(2)
while False:
x = 1
pygame.mixer.music.stop()
sys.exit()
Seems you want to play only one file randomly chosen. You want something like this:
import pygame
import sys
import glob
from random import choice
allmusic = glob.glob("*.mp3")
played = choice(allmusic) #select randomly one element from the list
print(played) #print the name of the chosen file
pygame.mixer.init()
pygame.mixer.music.load(played)
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pass
the last while loop checks if the music is played, and do nothing until the music ends. It's purpose is to keep the program alive, otherwise it ends immediately and the music stream is terminated.
Notice that you do not have control on the music, it will play until the end with no way to stop it before. To have some control of this kind, you need a more complex script handling events (from keyboard or a custom GUI interface you create, but this is going too far from your question I think).

How do I exit a while loop in python with an event?

I'm making this project for school that involves displaying data to a raspberry pi. The code I'm using refreshes (and needs to refresh) incredibly quickly, but I need a way for the user to stop the output, which I believe requires some kind of key event. The thing is, I'm new to Python and I can't figure out how to exit a while loop with turtle.onkey(). I found this code:
import turtle
def quit():
global more
more = False
turtle.onkey(quit, "Up")
turtle.listen()
more = True
while more:
print("something")
Which doesn't work. I've tested it. How do I make this work, or is there another way to get user input without interrupting the flow of the program?
while loop run on thread
check this code
import threading
def something():
while more:
print("something")
th = threading.Thread(something)
th.start()
Avoid infinite loops in a Python turtle graphics program:
more = True
while more:
print("something")
You can effectively block events from firing, including the one intended to stop the loop. Instead, use timer events to run your code and allow other events to fire:
from turtle import Screen
more = True
counter = 0
def stop():
global more
more = False
def start():
global more
more = True
screen.ontimer(do_something, 100)
def do_something():
global counter
print("something", counter)
counter += 1
if more:
screen.ontimer(do_something, 100)
screen = Screen()
screen.onkey(stop, "Up")
screen.onkey(start, "Down")
screen.listen()
start()
screen.mainloop()
I've added a counter to your program just so you can more easily see when the 'something' statements stop and I've added a restart on the down key so you can start them up again. Control should always reach mainloop() (or done() or exitonclick()) to give all the event handlers a chance to execute. Some infinite loops allow events to fire but they typically have calls into the turtle methods that allow it to have control some of the time but are still the wrong approach.
Chances are that you are trying to run your code in an interactive IPython shell. That does not work. The bare Python repl shell works, though.
Here I found a project that tries to bring turtle to IPython: https://github.com/Andrewkind/Turtle-Ipython. I did not test it, and I'm not exactly sure that this is a better solution than simply using the unsugared shell.
You could have you loop check a file like this:
def check_for_value_in_file():
with open('file.txt') as f:
value = f.read()
return value
while check_for_value_in_file() == 'the right value':
do_stuff()

Sound not playing fully?

The problem is when i play a sound it stops/cuts before finishing playing. (sound being under 1 second)
import pyglet
#from time import sleep
window = pyglet.window.Window()
# i use this for my code.
#pyglet.resource.path = ['/resources']
#pyglet.resource.reindex()
#bullet_sound = pyglet.resource.media("bullet.wav", streaming=False)
## streaming fix's an error message
bullet_sound = pyglet.media.load("/resources/bullet.wav", streaming=False)
#window.event
def on_key_press(symbol, modifiers):
# sound only plays for a millisecond
bullet_sound.play()
# this lets the sound complete
#sleep(1)
# also tried this with 'update()'
#player.queue(bullet_sound)
#def update(dt):
# player.play()
#pyglet.clock.schedule_interval(update, 1/120.0)
pyglet.app.run()
I can't seem to find anything about this when google searching. Sleeping makes the sound finish, so i suppose it has something to do with it dropping the sound prematurely. But how to i get it not to do so?
I even tried using the player, putting it in an update function and queuing it from the event, but that din't change anything.
Segmentation faults, sound cutting, too large exceptions, sound related issues on linux mint might be caused by Linux/PulseAudio, the fix is using OpanAL, installing(might be pre-installed on mint) then adding a line to use it after importing pyglet:
pyglet.options['audio'] = ('openal', 'silent')

Categories