Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Beginner extending C with Python (specifically Numpy)

Tags:

c++

python

c

numpy

api

I am working on a real time audio processing dynamically linked library where I have a 2 dimensional C array of floating point data which represents the audio buffer. One dimension is time (samples) and the other is channel. I would like to pass this to a python script as a numpy array for the DSP processing and then I would like to pass this back to C so the data can carry on down the processing chain in C. The member function in C++ which does the processing looks like this:

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

The arrays inputs and outputs are of equal size. The integer buffersize is the number of columns in the inputs and outputs arrays. On the python side I would like the processing to be carried out by a function which looks like the following:

class myPyEffect
    ...
    ...
    def process(self,inBuff):
    #inBuff and outBuff should be numpy arrays
        outBuff = inBuff * self.whatever # some DSP stuff
        return outBuff
    ...
    ...

Now, my question is, how can I go about getting the data in and out of C in the most efficient way possible (avoiding unnecessary memory copying etc.)? So far, for simple parameter changes I have been using C-API calls like the following:

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

Do I use something similar for my numpy arrays or is there a better way? Thanks for reading.

like image 960
learnvst Avatar asked Feb 18 '10 16:02

learnvst


People also ask

Can NumPy be used in C?

NumPy is written in C, and executes very quickly as a result. By comparison, Python is a dynamic language that is interpreted by the CPython interpreter, converted to bytecode, and executed. While it's no slouch, compiled C code is always going to be faster.

Is NumPy as fast as C?

From 2.8 seconds to 0.42! It is almost 7 times faster than straightforward C implementation. But still we are about 4 times slower than NumPy.

Can I use Python in C?

To write Python modules in C, you'll need to use the Python API, which defines the various functions, macros, and variables that allow the Python interpreter to call your C code. All of these tools and more are collectively bundled in the Python.

What is NumPy C API?

NumPy provides a C-API to enable users to extend the system and get access to the array object for use in other routines. The best way to truly understand the C-API is to read the source code. If you are unfamiliar with (C) source code, however, this can be a daunting experience at first.


1 Answers

You may be able to avoid dealing with the NumPy C API entirely. Python can call C code using the ctypes module, and you can access pointers into the numpy data using the array's ctypes attribute.

Here's a minimal example showing the process for a 1d sum-of-squares function.

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

compilation to ctsquare.so

These command lines are for OS X, your OS may vary.

$ 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)
like image 55
Theran Avatar answered Sep 28 '22 19:09

Theran