I am developing an audio algorithm using Python and Numpy. Now I want to speed up that algorithm by implementing a part of it in C. In the past, I have done this using cython. Now I want to do the same thing using the new cffi.
For testing purposes, I wrote a trivial C function:
void copy(float *in, float *out, int len) {
for (int i=0; i<len; i++) {
out[i] = in[i];
}
}
Now I want to create two numpy arrays and have those be processed by this function. I figured out a way to do that:
import numpy as np
from cffi import FFI
ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("/path/to/copy.dll")
float_in = ffi.new("float[16]")
float_out = ffi.new("float[16]")
arr_in = 42*np.ones(16, dtype=np.float32)
float_in[0:16] = arr_in[0:16]
C.copy(float_in, float_out, 16)
arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32)
However, I would like to improve this code:
ffi.buffer
is very convenient for quickly converting to contents of a C array to a Numpy array. Is there an equivalent way for quickly converting a numpy array into a C array without copying the individual elements?float_in[0:16] = arr_in[0:16]
is a convenient way of accessing data. The opposite, arr_out[0:16] = float_out[0:16]
does not work however. Why not?The ctypes
attribute of ndarray can interact with the ctypes module, for example, ndarray.ctypes.data
is the data address of the array, you can cast it to a float *
pointer,
and then pass the pointer to the C function.
import numpy as np
from cffi import FFI
ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("ccode.dll")
a = 42*np.ones(16, dtype=np.float32)
b = np.zeros_like(a)
pa = ffi.cast("float *", a.ctypes.data)
pb = ffi.cast("float *", b.ctypes.data)
C.copy(pa, pb, len(a))
print b
For your question 3:
I think ffi array doesn't provide numpy the necessary information to access it's inner buffer. So numpy try to convert it to a float number which failed.
The best solution I can thinks is convert it to list first:
float_in[0:16] = list(arr_in[0:16])