首页 > 解决方案 > 如何在 sounddevice 中停止 stream.write 函数

问题描述

是否可以在缓冲区完全消耗之前停止 stream.write 函数?当我尝试这样做时,声音停止了,但 stream.write 函数永远不会返回。

这是一个工作示例,说明我想如何使用一个小类来播放纯音而不阻塞主线程。

import time
import sounddevice as sd
import numpy as np
from threading import Thread

toneduration = 10
samplerate = 44100
frequency = 440
amplitude = 0.5

sd.default.device = 1
sd.default.samplerate = samplerate
sd.default.channels = 2

class Sound(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.stream = sd.OutputStream()
        self.stream.start()

        vector1 = np.linspace(0, toneduration, toneduration * samplerate)
        vector2 = amplitude * np.sin(2 * np.pi * frequency * vector1)
        vector3 = np.array([vector2, vector2])
        self.soundVector = np.ascontiguousarray(vector3.T, dtype=np.float32)

    def run(self):
        self.stream.write(self.soundVector)
        print('end')

sound = Sound()
sound.start()
time.sleep(3)
sound.stream.close()

我可以播放给定持续时间的声音,但是如果我使用stream.close()该函数手动停止流,则不会返回(print('end')消息永远不会显示,线程也不会完成)

我必须改用回调吗?在那种情况下,我应该如何用 numpy 数组填充缓冲区?我阅读了文档中的代码示例,但我不知道该怎么做。

标签: pythonaudiopython-sounddevice

解决方案


我想最简单的方法是使用play()函数,该函数默认在后台开始播放(使用从底层 PortAudio 库创建的单独线程调用的回调函数)。然后,您可以使用stop()函数停止播放。

如果您需要比简单回放 NumPy 数组更复杂的东西,您可以实现自己的回调函数。例如,您可以查看play()函数的实现或查看示例,例如play_long_file.py

正如您所提到的,您还可以使用所谓的“阻塞”API(使用write()方法)。

无论哪种方式,您通常会将音频数据拆分为一系列块。这样,您可以安排在任何一个块之后停止播放。这也是play()函数内部所做的。


推荐阅读