我无法将非交错的立体声数据传递给PyAudio。
PyAudio文档中给出的示例显示了如何使用回调传递 interleaved 数据。交错立体数据的缓冲区具有(nframes, 2)
的形状,如下所示:
array([[f0l, f0r],
[f1l, f1r],
[f2l, f2r],
...], dtype=float32)
部分由于说明原因,我想在回调中使用非交错数据。阅读文档,我认为非交错立体数据的缓冲区的形状为(2, nframes)
,如下所示:
array([[f0l, f1l, f2l, ...],
[f0r, f1r, f2r, ...]], dtype=float32)
AFAICT,在非交错模式下设置流的调用应该在格式参数的非交错位中OR
,如下所示:
PA_NONINTERLEAVED = 0x80000000
stream = p.open(format=pyaudio.paFloat32 | PA_NONINTERLEAVED,
channels=DEFAULT_CHANNEL_COUNT,
rate=SRATE,
output=True,
stream_callback=callback)
但是当我试图运行它时,它会使我的耳朵发出声音或者用数字噪音冲击我的耳朵,或者不会播放任何东西 - 某个记忆的所有标志都在某处。
有没有人成功将非交错数据传递给PyAudio?
以下代码应该向左声道写入440Hz正弦波,向右声道写入442Hz正弦波。
相反,它是段错误。
我已成功使用交错的numpy数据运行类似的测试,但希望我可以将通道数据分开。关于我做错了什么的指示?
# python sketches/s05.py
"""
PyAudio / NumPy example: synthesize and play stereo sine waves
using non-interleaved buffers
"""
import pyaudio
import numpy as np
import time
p = pyaudio.PyAudio()
SRATE = 44100
DEFAULT_CHANNEL_COUNT = 2
DEFAULT_FRAME_COUNT = 1024
# from http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html
PA_NONINTERLEAVED = 0x80000000
class Sinner:
def __init__(self, freq, channel):
self._dtheta = freq * 2.0 * np.pi / SRATE
self._theta = 0.0
self._channel = channel
def render(self, buffer, frame_count):
thetas = np.arange(frame_count) * self._dtheta + self._theta
np.sin(thetas, buffer[self._channel])
self._theta += frame_count * self._dtheta
sin_l = Sinner(440.0, 0)
sin_r = Sinner(442.0, 1)
out_data = np.zeros((DEFAULT_CHANNEL_COUNT, DEFAULT_FRAME_COUNT),
dtype=np.float32)
def callback(in_data, frame_count, time_info, status):
global sin_l, sin_r, out_data
if (out_data.shape[1] != frame_count):
# resize numpy array if needed
out_data = np.zeros((DEFAULT_CHANNEL_COUNT, frame_count),
dtype=np.float32)
sin_l.render(out_data, frame_count)
sin_r.render(out_data, frame_count)
print(out_data[0])
print(out_data[1])
return (out_data * 0.4, pyaudio.paContinue)
stream = p.open(format=pyaudio.paFloat32 | PA_NONINTERLEAVED,
channels=DEFAULT_CHANNEL_COUNT,
rate=SRATE,
output=True,
stream_callback=callback)
stream.start_stream()
while stream.is_active(): time.sleep(0.1)
stream.stop_stream()
stream.close()
p.terminate()
答案 0 :(得分:0)
我非常怀疑非交错数据的教学优势,听到你原因的另一部分会很有趣。
你知道matplotlib如果你把它传递给一个二维数组那么会绘制列吗?
此外,您似乎忽略了阵列的order
设置。如果您假设order='C'
,那么您在问题中所说的内容才有意义。您应该能够通过numpy.asfortranarray()运行数组然后将缓冲区传递给PyAudio来获得所需的行为(但没有使用PA_NONINTERLEAVED
标志!)。
请注意,在许多情况下,这会产生不必要的数据副本。
鉴于您的示例代码,您似乎误解了PortAudio的“非交错”模式的工作原理。在这种模式下,PortAudio假定输入和输出数据是指向一堆其他数组的指针的C数组,每个数组都保存一个通道的数据。为了能够使用它,您需要获取指向NumPy数组的每一行的指针。我不知道这在纯Python中是否可行......
最后,一些广告:您应该考虑使用sounddevice模块而不是PyAudio。它仍然使用交错数据,并且通道存储在列中,但它直接支持NumPy数组,并且应该比PyAudio更容易安装和使用。
答案 1 :(得分:0)
不,至少还在 0.2.11 版本中。录制某些内容时,此回调代码仅允许在一个通道上进行投影,在示例中为第一个通道。诀窍是使用 NumPy 并将数据排列成一个维度为 frame x channel x data (= SAMPLE_WIDTH
) 的数组(立方体),然后投影到第一个通道 (0) 上:
# 16 bits sample width
SAMPLE_WIDTH = 2
def __audio_callback__(in_data, frame_count, time_info, status_flags):
channels = int(len(in_data) / (SAMPLE_WIDTH * frame_count))
buffer = np.frombuffer(in_data, dtype=uint8)
first_channel = buffer.reshape(frame_count, channels, SAMPLE_WIDTH)[:, 0, :].tobytes()
audio_samples.append(first_channel)
# when not recording, return here the processed data as first tuple part
return None, pyaudio.paContinue