0

我使用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秒数一致……这怎么可能?

4

2 回答 2

1

基于对 portaudio 源的快速浏览,看起来通道实际上是交错的

您可以使用连接来展平列表,计算左右值(您将它们设置为 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 字符串与 unicode 的偏好有关。

更新:

wrt 奇数字节,read可能试图提前读取太多字节并且默默地失败,只返回它目前拥有的任何内容。在正常情况下,您应该始终从 read 中接收多个 CHUNK 字节,因此除非您的连接函数有错误,否则它们的末端有问题。用我的试试,看看会发生什么。

于 2013-08-29T04:38:06.163 回答
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 的倍数,并且不会因舍入误差而丢失帧。

于 2013-08-29T19:48:45.053 回答