我使用从网站上获取的pyaudio
示例,通过计算机麦克风(2个频道)记录的数据读取了一个字节缓冲区。
import pyaudio
import wave
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("* done recording")
print frames
frames
看起来像这样:
['\x00\xfd\xff\xff.....\xfc\xff\xff', '\xff\xfc\xff\xff......\xfc\xff\xff', ... ]
或者如果我更改CHUNK = 1
:
['\x00\xfd\xff\xff', '\xff\xfc\xff\xff', '\x00\xfd\xcc\xcf']
虽然当然要长得多。我怀疑每个通道的字节都是交错的,所以我想我需要将它们分成两对。
我想要的是这样的数组:
np.array([
[123, 43],
[3, 433],
[43, 66]
])
其中第一列是来自第一个通道的值,第二列是来自第二个通道的值。如何解释这些编码值(将CHUNK
设置为合理的值,如1024)?
更新:
我很困惑。我使用下面的方法将format
字符串列表更改为单个字符串的空格分隔的十六进制值,但似乎有奇数个...如果有两个值,则不会发生这种情况,每个频道一个(将是偶数):
fms = ''.join(frames)
fms_string = ''.join( [ "%02X " % ord( x ) for x in fms ] ).strip()
fms_list = fms_string.split(" ")
print len(fms_list) # this prints an ODD number...
更新2:
我尝试了一条更简单的路线并尝试了这个:
import array
fstring = ''.join(frames)
wave_nums = array.array('h', fstring) # this correctly returns list of ints!
print len(wave_nums)
我尝试了不同的录制时间并获得了以下(令人困惑的结果):
RECORD_SECONDS = 2 ---> len(wave_nums) is 132300 (132300 / 44100 = 3 seconds of frames)
RECORD_SECONDS = 4 ---> len(wave_nums) is 308700 (308700 / 44100 = 7 seconds of frames)
RECORD_SECONDS = 5 ---> len(wave_nums) is 396900 (396900 / 44100 = 9 seconds of frames)
这意味着我得到的帧数与2*(number of seconds recording) - 1
秒一致......这怎么可能?
答案 0 :(得分:1)
基于对portaudio源的快速浏览,它看起来像the channels are in fact interleaved
您可以使用联接来展平列表,计算左右值(将它们设置为16位长),然后将列表自身压缩。
joined = ''.join(frames).encode('latin-1')
left = map(lambda m, l: (m << 8) + l, joined[0::4], joined[1::4])
right = map(lambda m, l: (m << 8) + l, joined[2::4], joined[3::4])
zipped = zip(left, right)
在python 2.x上,编码latin1技巧不起作用,所以你需要做
joined = ''.join(frames)
joined = map(ord, joined)
left = map(lambda m, l: (m << 8) + l, joined[0::4], joined[1::4])
right = map(lambda m, l: (m << 8) + l, joined[2::4], joined[3::4])
zipped = zip(left, right)
这与python 2.x对ascii字符串vs unicode的偏好有关。
<强>更新强>
w.r.t奇数个字节,read
可能试图读取前面太多字节而无声地失败,只返回它当前的任何内容。在正常情况下,你应该总是从读取中获得多个CHUNK字节,所以除非你的连接函数有错误,否则它们的结尾有问题。和我一起试试看看会发生什么。
答案 1 :(得分:1)
最简单的答案似乎是:
import array
f = ''.join(frames)
nums = array.array('h', f)
left = nums[1::2]
right = nums[0::2]
@Dylan的答案也很好,但有点冗长,而且值也是无符号的,wav值是签名的。
同样将CHUNK
更改为1225的值最好,因为44100是1225的倍数,并且由于舍入错误而不会丢失任何帧。