2014-11-07 4 views
0

Я использую pyaudio в режиме обратного вызова с форматом paFloat32, 2 каналами, 1024 кадрами на буфер, и меня интересует более эффективный обмен данными аудио-буфера ввода-вывода.PyAudio: Каков наиболее эффективный формат и пакет/метод распаковки для использования в режиме обратного вызова?

Для распаковки входных звукового буфера и получить список образцов поплавка, я использую:

fmt  = str(N_CHANNELS * BUFFER_SIZE) + 'f' 
in_floats = struct.unpack(fmt, in_data) 

Использования struct.pack() и struct.unpack() весьма неэффективен и требует значительных ресурсов центрального процессора, почти такие же, как при обработке звукового сигнала сам. Поскольку большинство звуковых карт 16 бит, я также пытался использовать формат paInt16, но результаты почти идентичны.

Каким будет наиболее эффективный формат и метод pack/unpack для использования в режиме обратного вызова (конечно, поддерживая полное разрешение)?

Редактировать: PyAudio обменивается данными, используя двоичные потоки или буферы, аналогичные структурам данных C, используемым с Portaudio. Мне нужно распаковать входной буфер in_data, чтобы получить образцы с плавающей точкой и проанализировать их. Все в порядке, за исключением того, что распаковка немного медленная.

+0

'struct' относительно быстро. Если вам нужно что-то быстрее, вы, вероятно, не хотите использовать python для задания. Вы можете попытаться написать обратный вызов на C или вообще не распаковывать – goncalopp

+0

Вы также можете попробовать 'numpy', но поскольку вы имеете дело с относительно небольшими буферами, накладные расходы могут быть достаточно большими, чтобы свести на нет выгоду – goncalopp

+0

Зачем вам нужно упаковать и распаковать данные? Во всяком случае, numpy 'frombuffer' может быть вам полезен здесь. Http://docs.scipy.org/doc/numpy/reference/generated/numpy.frombuffer.html#numpy.frombuffer. Если вы хотите следить, пожалуйста, напишите некоторый минимальный, но функциональный код, чтобы мы могли видеть, что вы пытаетесь сделать. – tom10

ответ

1

Использование либо NumPy или array модуль в STDLIB в будет намного быстрее, потому что большая часть стоимости struct.unpack не распаковка, это бокс из каждого значения с плавающей точкой в ​​Python float объекта.

Например:

In [1177]: f = [random.random() for _ in range(65536)] 

In [1178]: b = struct.pack('65536f', *f) 

In [1179]: %timeit struct.unpack('65536f', b) 
1000 loops, best of 3: 1.61 ms per loop 

In [1180]: %timeit array.array('f', b) 
100000 loops, best of 3: 17.7 µs per loop 

Это 100x так быстро. И у вас есть итерабельность поплавков в любом случае, это просто, что это array вместо tuple.

Однако, если вы планируете на самом деле делать какие-либо арифметические действия по этим значениям, вам все равно придется перебирать эти значения, а array придется распаковать каждый из них, как вы это делаете, что будет добавьте обратно в хороший кусок времени, которое вы сохранили.

В это время входит NumPy; Я сомневаюсь, что np.frombuffer(b, dtype=np.float32) будет намного быстрее, чем array.array('f', b), чтобы создать, но это позволит вам выполнять векторизованную арифметику непосредственно по незанятым значениям. Например:

In [1186]: a1 = array.array('f', b) 

In [1187]: a2 = np.frombuffer(b, dtype=np.float32) 

In [1189]: %timeit sum(f) 
1000 loops, best of 3: 586 µs per loop 

In [1189]: %timeit sum(a1) 
1000 loops, best of 3: 907 µs per loop 

In [1190]: %timeit a2.sum() 
10000 loops, best of 3: 80.3 µs per loop 

Как вы можете видеть, используя array.array делает это в два раза медленнее (я использовал sum потому что фактическая итерация и арифметика выполняются в C), но с использованием вместо np.array делает его 5x быстрее.