Я работаю над оперативной динамически подключаемой библиотекой обработки аудиоданных, где у меня есть 2 размерных массива C данных с плавающей запятой, которые представляют аудио буфер. Один размер является временем (образцы), и другой канал. Я хотел бы передать это сценарию Python как массив numpy для обработки DSP, и затем я хотел бы пасовать назад это к C, таким образом, данные могут продолжить вниз цепочку обработки в C. Функция членства в C++, который делает обработку, похожа на это:
void myEffect::process (float** inputs, float** outputs, int buffersize)
{
//Some processing stuff
}
Вводы и выводы массивов имеют равный размер. Целое число buffersize является числом столбцов во входных и выходных массивах. На стороне Python я хотел бы, чтобы обработка была выполнена функцией, которая похожа на следующее:
class myPyEffect
...
...
def process(self,inBuff):
#inBuff and outBuff should be numpy arrays
outBuff = inBuff * self.whatever # some DSP stuff
return outBuff
...
...
Теперь, мой вопрос, как я могу пойти о вкладывании данных и из C самым эффективным возможным способом (предотвращение ненужной памяти, копирующей и т.д.)? До сих пор, для простого параметра изменяется, я использовал C-ВЫЗОВЫ-API как следующее:
pValue = PyObject_CallMethod(pInstance, "setParameter", "(f)", value);
Я использую что-то подобное для своих массивов numpy или есть ли лучший путь? Спасибо за чтение.
Возможно, вам удастся полностью избежать работы с NumPy C API. Python может вызывать код C, используя модуль ctypes
, и вы можете обращаться к указателям на данные numpy с помощью атрибута ctypes массива.
Вот минимальный пример, показывающий процесс для функции 1d суммы квадратов.
#include <stdlib.h>
float mysumsquares(float * array, size_t size) {
float total = 0.0f;
size_t idx;
for (idx = 0; idx < size; ++idx) {
total += array[idx]*array[idx];
}
return total;
}
Эти командные строки предназначены для OS X, ваша ОС может отличаться.
$ gcc -O3 -fPIC -c ctsquare.c -o ctsquare.o
$ ld -dylib -o ctsquare.so -lc ctsquare.o
import numpy
import ctypes
# pointer to float type, for convenience
c_float_p = ctypes.POINTER(ctypes.c_float)
# load the library
ctsquarelib = ctypes.cdll.LoadLibrary("ctsquare.so")
# define the return type and arguments of the function
ctsquarelib.mysumsquares.restype = ctypes.c_float
ctsquarelib.mysumsquares.argtypes = [c_float_p, ctypes.c_size_t]
# python front-end function, takes care of the ctypes interface
def myssq(arr):
# make sure that the array is contiguous and the right data type
arr = numpy.ascontiguousarray(arr, dtype='float32')
# grab a pointer to the array's data
dataptr = arr.ctypes.data_as(c_float_p)
# this assumes that the array is 1-dimensional. 2d is more complex.
datasize = arr.ctypes.shape[0]
# call the C function
ret = ctsquarelib.mysumsquares(dataptr, datasize)
return ret
if __name__ == '__main__':
a = numpy.array([1,2,3,4])
print 'sum of squares of [1,2,3,4] =', myssq(a)