如何在 python 声音设备中使用 OutputStream 播放声音文件?

How to play a sound file using an OutputStream in python sounddevice?

目标是同时播放两个声音文件,所以 sounddevice.play 功能不是一个选项。我相信我应该为每个文件制作一个 OutputStream。现在我一直在努力让一个 OutputStream 工作。请帮忙。

到目前为止我的代码:

import soundfile as sf
import sounddevice as sd

data, fs = sf.read('sound_file.wav', dtype='float32')

def callback(outdata, frames, time, status):
    outdata[:] = data

with sd.OutputStream(callback=callback):
               pass

编辑: 切换为 RawOutputStream

import soundfile as sf
import sounddevice as sd

wf = sf.SoundFile('sound_file.wav')

def callback(outdata, frames, time, status):
    data = wf.buffer_read(frames, dtype='float32')
    if len(data) <= 0:
        raise sd.CallbackAbort
    if len(outdata) > len(data):
        raise sd.CallbackAbort #wrong obviously
    outdata[:] = data

with sd.RawOutputStream(channels=wf.channels,
                        callback=callback) as stream:
    while stream.active:
        continue

如果采样率相似,您可以将两个数据数组相加:

import numpy as np
import soundfile as sf
import sounddevice as sd

data_1, fs_1 = sf.read('sound_file_1.wav', dtype='float32')
data_2, fs_2 = sf.read('sound_file_2.wav', dtype='float32')

if len(data_1) > len(data_2):
    data = data_1 + np.pad(data_2, (0, len(data_1) - len(data_2)))
else:
    data = np.pad(data_1, (0, len(data_2) - len(data_1))) + data_2

# determine fs from a combination of fs_1 and fs_2 of your choosing, like
fs = min(fs_1, fs_2)

sd.play(data, fs)
import soundfile as sf
import sounddevice as sd
import threading

def _play(sound):
    event =threading.Event()

    def callback(outdata, frames, time, status):
        data = wf.buffer_read(frames, dtype='float32')
        if len(outdata) > len(data):
            outdata[:len(data)] = data
            outdata[len(data):] = b'\x00' * (len(outdata) - len(data))
            raise sd.CallbackStop
        else:
            outdata[:] = data

    with sf.SoundFile(sound) as wf:
        stream = sd.RawOutputStream(samplerate=wf.samplerate,
                                    channels=wf.channels,
                                    callback=callback,
                                    blocksize=1024,
                                    finished_callback=event.set)
        with stream:
            event.wait()

def _playsound(sound):
    new_thread = threading.Thread(target=_play, args=(sound,))
    new_thread.start()

_playsound('sounds_file.wav')