KISS FFT Wrapping
Wraps the KISS FFT library using c2py23. Demonstrates complex-number handling via interleaved float32 buffers (c2py23 has no native complex type).
Kissfft Wrap
Interface
# Python dict format equivalent of kissfft.c2py
{
"module": "kissfftmod",
"source": [
"../kissfft/kiss_fft.c",
"../kissfft/kiss_fftr.c",
"kissfft_thin.c",
],
"headers": [
"../kissfft/kiss_fft.h",
"../kissfft/kiss_fftr.h",
],
"free_threading": True,
"functions": [
{
"py_sig": "rfft_forward(data: buffer, spec: buffer) -> void",
"checks": [
"data.format == 'f'",
"spec.format == 'f'",
"data.ndim == 1",
"spec.ndim == 1",
"spec.n >= data.n + 2",
],
"c_overloads": [
{
"sig": "kissfft_rfft_forward(const float *data, float *spec, int n)",
"map": {
"data": "data.ptr",
"spec": "spec.ptr",
"n": "data.n",
},
},
],
},
{
"py_sig": "cfft_forward(fin: buffer, fout: buffer) -> void",
"checks": [
"fin.format == 'f'",
"fout.format == 'f'",
"fin.ndim == 1",
"fout.ndim == 1",
"fin.n == fout.n",
"fin.n % 2 == 0",
],
"c_overloads": [
{
"sig": "kissfft_cfft_forward(const float *fin, float *fout, int n)",
"map": {
"fin": "fin.ptr",
"fout": "fout.ptr",
"n": "fin.n / 2",
},
},
],
},
],
}
C Source
#include <stdlib.h>
#include "../kissfft/kiss_fft.h"
#include "../kissfft/kiss_fftr.h"
void kissfft_rfft_forward(const float *data, float *spec, int n) {
kiss_fftr_cfg cfg = kiss_fftr_alloc(n, 0, NULL, NULL);
if (cfg) {
kiss_fftr(cfg, data, (kiss_fft_cpx *)spec);
free(cfg);
}
}
void kissfft_cfft_forward(const float *fin, float *fout, int n) {
kiss_fft_cfg cfg = kiss_fft_alloc(n, 0, NULL, NULL);
if (cfg) {
kiss_fft(cfg, (const kiss_fft_cpx *)fin, (kiss_fft_cpx *)fout);
free(cfg);
}
}
Build
Compile:
$ cc -shared -fPIC c2py23/runtime/c2py_runtime.c kissfftmod_wrapper.c kissfft_thin.c -I c2py23/runtime -o kissfftmod.so -ldl -lm
See docs/building for cmake, meson, and setuptools options.
Run
$ python example.py
Traceback (most recent call last):
File "/home/runner/work/c2py23/c2py23/examples/kissfft_wrap/example.py", line 12, in <module>
import kissfftmod
ModuleNotFoundError: No module named 'kissfftmod'
How It Works
Complex numbers as float pairs
c2py23 has no complex type. The thin wrapper casts float* buffers to
kiss_fft_cpx* (a struct of two floats). Python callers create interleaved
float arrays -- [re0, im0, re1, im1, ...].
Buffer sizing
The real FFT takes N real floats. Its output is N/2+1 complex bins stored
as (N/2+1)*2 = N+2 floats. The check spec.n >= data.n + 2 enforces this.
The complex FFT takes N complex numbers = N*2 floats. The check
fin.n % 2 == 0 ensures an even number of floats (complete pairs).
Map expressions
The C function receives n (number of complex elements), but the buffer
has N*2 floats. The map n: "fin.n / 2" bridges this.