How to play different sound consecutively and asynchronously in python?

房东的猫 提交于 2021-01-29 12:08:58

问题


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!


回答1:


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.



来源:https://stackoverflow.com/questions/61200617/how-to-play-different-sound-consecutively-and-asynchronously-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!