2013-08-29 2 views
0

Я прочитал буфер байтов из данных, записанных через микрофон моего компьютера (2 канала), используя пример pyaudio, взятый с сайта.Как преобразовать байты в np.array

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)?


UPDATE:

Я совершенно запутался. Я использовал ниже, чтобы изменить список строк 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... 

UPDATE 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 секунд ... как это возможно?

ответ

1

Самый простой ответ, как представляется, это:

import array 
f = ''.join(frames) 
nums = array.array('h', f) 
left = nums[1::2] 
right = nums[0::2] 

@ ответ Дилана тоже хорошо, но немного более громоздким, а также значения без знака, где подписываются значения WAV.

Также изменение CHUNK на значение 1225 является лучшим, поскольку 44100 является кратным 1225, и никакие кадры не теряются в результате ошибки округления.

1

на основе беглого взгляда источника Portaudio это выглядит как the channels are in fact interleaved

Вы можете использовать присоединиться выравниваться список, вычислить левые и правые значения (установить их быть длиной 16 бит), а затем zip список с собой.

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.

Update:

W.R.t нечетное количество байтов, read, возможно, попыталось прочесть слишком много байтов вперед и провалилось молча, только возвращающее то, что было на данный момент. Вы всегда должны получать несколько CHUNK-байтов от чтения в обычных условиях, поэтому, если ваша функция соединения не имеет ошибки, что-то не так с их конца. Попробуйте с моим и посмотрите, что произойдет.

+0

на 'encode()' строка: 'UnicodeDecodeError: 'ascii' кодек не может декодировать байт 0xff в позиции 608: порядковый номер не в диапазоне (128)' – lollercoaster

+0

и без этого строки 'map()' fail с: 'TypeError: неподдерживаемый тип операндов для <<: 'str' и 'int'' – lollercoaster

+0

Интересный ... Он работает в python3, я посмотрю на него –