使用 Python sounddevice 在两个设备上进行多通道采集

Using Python sounddevice for multichannel acquisition on two devices

我正在尝试从我的 RME Fireface UCX 声卡输出多达 4 个音频通道,并在我的 miniDSP 16 通道麦克风阵列上采集 16 个通道的音频数据。目前,如果我使用 query_devices 命令中列出的设备的组合,我可以使 16-in/2-out 系统正常工作,但我似乎无法增加输出通道的数量。

来自设备列表:

0 name:Microsoft Sound Mapper - Input input ch:2 out ch:0
1 name:ADAT (7+8) (RME Fireface UCX) input ch:2 out ch:0
2 name:Line (miniDSP micArray Multi-ch input ch:2 out ch:0
...
46 name:ASIO Fireface USB input ch:18 out ch:18
47 name:ASIO4ALL v2 input ch:2 out ch:2
48 name:miniDSP ASIO Driver input ch:16 out ch:2
...
60 name:Line (miniDSP micArray Multi-channels) input ch:16 out ch:0
72 name:Line (nanoSHARC micArray16 UAC2.0) input ch:16 out ch:0
73 name:Analog (1+2) (Fireface Analog (1+2)) input ch:0 out ch:8
74 name:Analog (1+2) (Fireface Analog (1+2)) input ch:2 out ch:0
...

因此,如果我有 x(这是一个 44100*5 行乘以三列的 numpy 数组,表示以 44.1 kHz (=fs) 采样的 3 通道数据的 5 秒)我可以这样做:

sd.default.device = [46, 46]
rx_data = sd.playrec(x, samplerate=fs, channels=8)

这同时向我的扬声器播放 3 个输出通道,并在我的 RME 声卡输入上获取 8 个通道。同样,如果我这样做:

duration = 5
sd.default.device = [48, 48]
sd.rec(int(duration * fs), samplerate=fs, channels=16)

我可以让我的 miniDSP 录制 16 声道的音频 5 秒。另外,如果我这样做:

sd.default.device = [60, 73]
rx_data = sd.playrec(x, samplerate=fs, channels=16)

我可以让 miniDSP h/w 获取 16 个音频通道,而 RME 只输出 2 个通道(是的,只有 2 个通道,尽管 numpy 数组有 3 列,设备列表说设备可以输出 8 个通道?)。这没关系,但正如我所说,我可能想要 3 或 4 个音频输出通道。

我考虑过组合 ASIO 设备,即

sd.default.device = [48, 46]
rx_data = sd.playrec(x, samplerate=fs, channels=16)

但这(不足为奇)会导致 PortAudioError -9993 I/O 设备的非法组合。

所以我考虑过使用 InputStreams 和 OutputStreams,但我没有完全遵循声音设备文档中的一些示例代码。但也许这是解决这个问题的方法?

PortAudio 库(在 sounddevice 模块中使用)实际上不允许流具有不同的输入和输出(硬件)设备。它可能适用于某些主机 API 和某些设备组合,但不受官方支持。

另见 https://github.com/spatialaudio/python-sounddevice/issues/154

您可以在操作系统级别将多个设备组合成一个 "virtual device",但我不知道 if/how 是否适用于 Windows(它可能适用于Linux/ALSA 使用配置文件 .asoundrc 和在 macOS 上通过定义 "aggregate devices").

如果这不是一个选项,您可以对输入和输出使用不同的流(正如您在问题中提到的)。在这种情况下,输入和输出块的时序通常不匹配,因此您不应尝试同步处理输入和输出。 您应该使用 queue.Queue 之类的东西将音频数据从输入回调传输到输出回调。

文档中确实没有相关示例。 但你可以尝试结合 rec_unlimited.py (对于输入回调) 和 play_long_file.py (对于输出回调)。