Начинающий, расширяющий C с Python (в частности, Numpy) - PullRequest
6 голосов
/ 18 февраля 2010

Я работаю над динамически связанной библиотекой обработки звука в реальном времени, где у меня есть двумерный массив данных C с плавающей запятой, который представляет аудиобуфер. Одно измерение - время (отсчеты), а другое - канал. Я хотел бы передать это скрипту Python в качестве массива для обработки DSP, а затем я хотел бы передать это обратно в C, чтобы данные могли продолжить цепочку обработки в C. Функция-член в C ++, которая выполняет обработка выглядит так:

void myEffect::process (float** inputs, float** outputs, int buffersize)
{
    //Some processing stuff
}

Массивы входы и выходы имеют одинаковый размер. Целое число размер буфера - это число столбцов во входных и выходных массивах. Что касается 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 наиболее эффективным способом (избегая ненужного копирования памяти и т. Д.)? До сих пор для простых изменений параметров я использовал вызовы C-API, подобные следующим:

pValue = PyObject_CallMethod(pInstance, "setParameter", "(f)", value);

Использую ли я что-то похожее для моих массивов или есть лучший способ? Спасибо за чтение.

1 Ответ

7 голосов
/ 19 февраля 2010

Вы можете полностью отказаться от использования API NumPy C.Python может вызывать C-код с помощью модуля ctypes, а вы можете получить доступ к указателям на пустые данные с помощью атрибута массива ctypes.

Вот минимальный пример, показывающий процесс для функции 1d суммы квадратов.

ctsquare.c

#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;
}

компиляция в ctsquare.so

Эти командные строки предназначены для OS X, ваша ОС может отличаться.

$ gcc -O3 -fPIC -c ctsquare.c -o ctsquare.o
$ ld -dylib -o ctsquare.so -lc ctsquare.o

ctsquare.py

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...