将多通道PyAudio转换为NumPy数组

13
我能找到的所有示例都是单声道的,CHANNELS = 1。 如何使用PyAudio中的回调方法读取立体声或多声道输入,并将其转换为2D NumPy数组或多个1D数组?对于单声道输入,以下内容可以正常工作:
def callback(in_data, frame_count, time_info, status):
    global result
    global result_waiting

    if in_data:
        result = np.fromstring(in_data, dtype=np.float32)
        result_waiting = True
    else:
        print('no input')

    return None, pyaudio.paContinue

stream = p.open(format=pyaudio.paFloat32,
                channels=1,
                rate=fs,
                output=False,
                input=True,
                frames_per_buffer=fs,
                stream_callback=callback)

但是对于立体声输入无效,result数组的长度是原来的两倍,因此我认为这些通道是交错的或其他什么情况,但是我找不到相关文档。

但是对于立体声输入无效,result数组的长度是原来的两倍,因此我认为这些通道是交错的或其他什么情况,但是我找不到相关文档。


我正在尝试编写一个数组并使用PyAudio播放它。对此有什么想法吗? - SolessChong
@SolessChong 我在下面的答案中添加了函数。 - endolith
1个回答

18

看起来是逐个样本交错的,左声道先。当左声道输入有信号而右声道静音时,我得到:

result = [0.2776, -0.0002,  0.2732, -0.0002,  0.2688, -0.0001,  0.2643, -0.0003,  0.2599, ...

因此,为了将其分离成立体声流,请将其重新塑造为二维数组:

result = np.fromstring(in_data, dtype=np.float32)
result = np.reshape(result, (frames_per_buffer, 2))

现在要访问左声道,请使用result[:, 0],右声道请使用result[:, 1]

def decode(in_data, channels):
    """
    Convert a byte stream into a 2D numpy array with 
    shape (chunk_size, channels)

    Samples are interleaved, so for a stereo stream with left channel 
    of [L0, L1, L2, ...] and right channel of [R0, R1, R2, ...], the output 
    is ordered as [L0, R0, L1, R1, ...]
    """
    # TODO: handle data type as parameter, convert between pyaudio/numpy types
    result = np.fromstring(in_data, dtype=np.float32)

    chunk_length = len(result) / channels
    assert chunk_length == int(chunk_length)

    result = np.reshape(result, (chunk_length, channels))
    return result


def encode(signal):
    """
    Convert a 2D numpy array into a byte stream for PyAudio

    Signal should be a numpy array with shape (chunk_size, channels)
    """
    interleaved = signal.flatten()

    # TODO: handle data type as parameter, convert between pyaudio/numpy types
    out_data = interleaved.astype(np.float32).tostring()
    return out_data

1
非常有帮助。部分相关于这个问题 - SolessChong
使用其他数据格式进行音频编码(例如np.int16)。 - user3002273
2
interleaved 是什么意思?我尝试了一下,发现 flatten 函数实际上是一个解决方案,但是不带参数的 flatten 将二维数组压缩为一维数组时,第一行中的所有值在第二行中的所有值之前。在 numpy 文档 中,我发现可以将 'F' 字符作为第一个参数提供,这样就会按照我们期望的方式进行压缩。这是否与 interleaved.astype(np.float32).tostring() 调用等效?如果是,则看起来是最简单的解决方案。 - pt12lol
1
正如所述,“样本是交错的,因此对于左声道为[L0、L1、L2、...]和右声道为[R0、R1、R2、...]的立体声流,输出的顺序为[L0、R0、L1、R1、...]”。 - endolith
@endolith 我刚刚测试了Numpy的flatten方法,@pt12lol是正确的,需要使用“'F'”来实际交错2D数组。你的“encode”方法会将所有左声道放在右声道之前,就像[L0,L1,...,R0,R1,...]。 - Pinyi Wang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接