如何在回调中优雅地停止python sounddevice

如何在回调中优雅地停止python sounddevice,python,audio,python-sounddevice,Python,Audio,Python Sounddevice,我使用和播放音频的“硬方法”,即使用非阻塞回调。注意:使用sd.play()要容易得多,但是我选择了这个patk,因为在我的最终版本中,我想在回调方法中进行额外的处理 我可以检测何时到达声音文件的末尾,但不清楚如何在播放最后一个排队的缓冲区后告诉sounddevice停止 下面是一个不起作用的回调示例:它播放整个声音文件,但在处理最后一个缓冲区后不会停止。在回调中,我提出了sd.CallbackStop(),但流状态从未变为stopped: def callback(outdata, f

我使用和播放音频的“硬方法”,即使用非阻塞回调。注意:使用sd.play()要容易得多,但是我选择了这个patk,因为在我的最终版本中,我想在回调方法中进行额外的处理

我可以检测何时到达声音文件的末尾,但不清楚如何在播放最后一个排队的缓冲区后告诉sounddevice停止

下面是一个不起作用的回调示例:它播放整个声音文件,但在处理最后一个缓冲区后不会停止。在回调中,我提出了
sd.CallbackStop()
,但流状态从未变为
stopped

    def callback(outdata, frame_count, time, status):
        view = sf.read(frame_count, dtype='float32', out=outdata)
        if (view.size != outdata.size):   # this was the last buffer.
            print('stopping')
            sd.CallbackStop()  

    with sd.OutpuStream(samplerate=sf.samplerate,
                        channels=sf.channels,
                        dtype=np.float32,
                        callback=callback) as ss:
        while (ss.active):
            time.sleep(0.1)

啊!如果您不
提出异常,异常将无法正常工作!!回调的正确代码是:

def callback(outdata, frame_count, time, status):
    view = sf.read(frame_count, dtype='float32', out=outdata)
    if (view.size != outdata.size):   # this was the last buffer.
        # zero the part of outdata not written into  by sf.read()
        outdata[view.shape[0]:,:].fill(0.0)
        print('stopping')
        raise sd.CallbackStop()

。。。它工作得非常完美,一路播放到最后,在播放完最后一个缓冲区后停止。

我很高兴听到它可以工作,但您的示例代码看起来根本无法工作!我想你不是指
sf.read()
而是指
mysoundfile.read()
,对吗?还请注意,您应该始终使用有意义的值填充
outdata
,但在上一个块中,您只填充了部分。在我的代码中未显示:
将声音文件导入为声音文件
,将声音文件(文件名)导入为sf:
,因此
sf.read()
实际上是正确的。还有一个好问题:outdata的未写入部分在最后一次调用中应该是零填充的。我将相应地测试和编辑该示例。@Matthias:您同意修复方案吗?是的,现在看起来不错!你仍然可以用
len(view)
替换
view.shape[0]
,也可以用
len()
替换
size
的东西,但我想这是个品味问题。我误解了
sf
,因为我通常使用
导入声音文件作为sf
。您应该知道,如果在某个时候(从硬盘)读取声音文件的速度由于某种原因而减慢,这可能会导致播放出现故障。这就是为什么
sf.play()
坚持在开始播放之前将整个数组存储在内存中。更正:我当然是指
sd.play()
而不是
sf.play()
!您可能应该补充一点,使用.Done有一种更简单的方法。我明确表示,我希望能够在它们经过时触摸它们。