简体   繁体   中英

How to play different sound consecutively and asynchronously in python?

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? Thanks!

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM