From 96fe713cccdf01faf343d5ac629381d9348fca68 Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Sat, 5 Dec 2009 01:44:11 +0100 Subject: [PATCH] interfaces/python: towards mono --- interfaces/python/aubio-types.h | 18 +- interfaces/python/aubiomodule.c | 3 + interfaces/python/aubiowraphell.h | 3 +- interfaces/python/gen_pyobject.py | 49 +++-- interfaces/python/py-fft.c | 29 +-- interfaces/python/py-filter.c | 24 +-- interfaces/python/py-filterbank.c | 9 +- interfaces/python/py-fmat.c | 332 ++++++++++++++++++++++++++++++ 8 files changed, 394 insertions(+), 73 deletions(-) create mode 100644 interfaces/python/py-fmat.c diff --git a/interfaces/python/aubio-types.h b/interfaces/python/aubio-types.h index 8d00191c..035f69e0 100644 --- a/interfaces/python/aubio-types.h +++ b/interfaces/python/aubio-types.h @@ -5,8 +5,8 @@ #define AUBIO_UNSTABLE 1 #include -#define Py_default_vector_length 1024 -#define Py_default_vector_channels 1 +#define Py_default_vector_length 1024 +#define Py_default_vector_height 1 #define Py_aubio_default_samplerate 44100 @@ -24,20 +24,30 @@ types different than NPY_FLOAT to and fvec, and therefore creating a copy of it. */ -#define AUBIO_DO_CASTING 0 typedef struct { PyObject_HEAD fvec_t * o; uint_t length; - uint_t channels; } Py_fvec; extern PyTypeObject Py_fvecType; extern PyObject *PyAubio_FvecToArray (Py_fvec * self); extern PyObject *PyAubio_CFvecToArray (fvec_t * self); extern Py_fvec *PyAubio_ArrayToFvec (PyObject * self); +typedef struct +{ + PyObject_HEAD + fmat_t * o; + uint_t length; + uint_t height; +} Py_fmat; +extern PyTypeObject Py_fmatType; +extern PyObject *PyAubio_FmatToArray (Py_fmat * self); +extern PyObject *PyAubio_CFmatToArray (fmat_t * self); +extern Py_fmat *PyAubio_ArrayToFmat (PyObject * self); + typedef struct { PyObject_HEAD diff --git a/interfaces/python/aubiomodule.c b/interfaces/python/aubiomodule.c index c3b568f5..b0f75985 100644 --- a/interfaces/python/aubiomodule.c +++ b/interfaces/python/aubiomodule.c @@ -121,6 +121,7 @@ init_aubio (void) int err; if ((PyType_Ready (&Py_fvecType) < 0) + || (PyType_Ready (&Py_fmatType) < 0) || (PyType_Ready (&Py_cvecType) < 0) || (PyType_Ready (&Py_filterType) < 0) || (PyType_Ready (&Py_filterbankType) < 0) @@ -147,6 +148,8 @@ init_aubio (void) Py_INCREF (&Py_fvecType); PyModule_AddObject (m, "fvec", (PyObject *) & Py_fvecType); + Py_INCREF (&Py_fmatType); + PyModule_AddObject (m, "fmat", (PyObject *) & Py_fmatType); Py_INCREF (&Py_cvecType); PyModule_AddObject (m, "cvec", (PyObject *) & Py_cvecType); Py_INCREF (&Py_filterType); diff --git a/interfaces/python/aubiowraphell.h b/interfaces/python/aubiowraphell.h index c8fc2227..7ccdc096 100644 --- a/interfaces/python/aubiowraphell.h +++ b/interfaces/python/aubiowraphell.h @@ -93,7 +93,6 @@ PyTypeObject Py_ ## NAME ## Type = { \ }; // some more helpers -#define AUBIO_NEW_VEC(name, type, lengthval, channelsval) \ +#define AUBIO_NEW_VEC(name, type, lengthval) \ name = (type *) PyObject_New (type, & type ## Type); \ - name->channels = channelsval; \ name->length = lengthval; diff --git a/interfaces/python/gen_pyobject.py b/interfaces/python/gen_pyobject.py index 20c12e93..bb6ba6ef 100644 --- a/interfaces/python/gen_pyobject.py +++ b/interfaces/python/gen_pyobject.py @@ -68,20 +68,20 @@ def get_name(proto): # the important bits: the size of the output for each objects. this data should # move into the C library at some point. defaultsizes = { - 'resampler': ('input->length * self->ratio', 'input->channels'), - 'specdesc': ('1', 'fftgrain->channels'), - 'onset': ('1', 'self->channels'), - 'pitchyin': ('1', 'in->channels'), - 'pitchyinfft': ('1', 'in->channels'), - 'pitchschmitt': ('1', 'in->channels'), - 'pitchmcomb': ('1', 'self->channels'), - 'pitchfcomb': ('1', 'self->channels'), - 'pitch': ('1', 'self->channels'), - 'tss': ('self->hop_size', 'self->channels'), - 'mfcc': ('self->n_coeffs', 'in->channels'), - 'beattracking': ('self->hop_size', 'self->channels'), - 'tempo': ('1', 'self->channels'), - 'peakpicker': ('1', 'self->channels'), + 'resampler': 'input->length * self->ratio', + 'specdesc': '1', + 'onset': '1', + 'pitchyin': '1', + 'pitchyinfft': '1', + 'pitchschmitt': '1', + 'pitchmcomb': '1', + 'pitchfcomb': '1', + 'pitch': '1', + 'tss': 'self->hop_size', + 'mfcc': 'self->n_coeffs', + 'beattracking': 'self->hop_size', + 'tempo': '1', + 'peakpicker': '1', } # default value for variables @@ -98,7 +98,6 @@ aubiodefvalue = { # and here too 'hop_size': 'Py_default_vector_length / 2', # these should be alright - 'channels': 'Py_default_vector_channels', 'samplerate': 'Py_aubio_default_samplerate', # now for the non obvious ones 'n_filters': '40', @@ -150,7 +149,10 @@ aubiovectopyobj_new = { def gen_new_init(newfunc, name): newparams = get_params_types_names(newfunc) # self->param1, self->param2, self->param3 - selfparams = ', self->'.join([p[1] for p in newparams]) + if len(newparams): + selfparams = ', self->'+', self->'.join([p[1] for p in newparams]) + else: + selfparams = '' # "param1", "param2", "param3" paramnames = ", ".join(["\""+p[1]+"\"" for p in newparams]) pyparams = "".join(map(lambda p: aubio2pytypes[p[0]], newparams)) @@ -178,6 +180,7 @@ static char Py_%(name)s_doc[] = "%(name)s object"; static PyObject * Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) { + Py_%(name)s *self; """ % locals() for ptype, pname in newparams: initval = aubioinitvalue[ptype] @@ -185,14 +188,16 @@ Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) %(ptype)s %(pname)s = %(initval)s; """ % locals() # now the actual PyArg_Parse - s += """\ - Py_%(name)s *self; + if len(paramnames): + s += """\ static char *kwlist[] = { %(paramnames)s, NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist, %(paramrefs)s)) { return NULL; } +""" % locals() + s += """\ self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0); @@ -237,7 +242,7 @@ Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) return (PyObject *) self; } -AUBIO_INIT(%(name)s, self->%(selfparams)s) +AUBIO_INIT(%(name)s %(selfparams)s) AUBIO_DEL(%(name)s) @@ -286,10 +291,10 @@ def gen_do(dofunc, name): # "too many output parameters" outputvecs = "\n ".join([aubio2pyaubio[p[0]]+" * " + p[-1] + ";" for p in outputparams]) outputcreate = "\n ".join(["""\ -AUBIO_NEW_VEC(%(name)s, %(pytype)s, %(length)s, %(channels)s) - %(name)s->o = new_%(autype)s (%(length)s, %(channels)s);""" % \ +AUBIO_NEW_VEC(%(name)s, %(pytype)s, %(length)s) + %(name)s->o = new_%(autype)s (%(length)s);""" % \ {'name': p[-1], 'pytype': aubio2pyaubio[p[0]], 'autype': p[0][:-3], - 'length': defaultsizes[name][0], 'channels': defaultsizes[name][1]} \ + 'length': defaultsizes[name]} \ for p in outputparams]) if len(outputparams) > 1: returnval = "PyObject *outputs = PyList_New(0);\n" diff --git a/interfaces/python/py-fft.c b/interfaces/python/py-fft.c index acbeb67c..20e8fe57 100644 --- a/interfaces/python/py-fft.c +++ b/interfaces/python/py-fft.c @@ -2,18 +2,18 @@ static char Py_fft_doc[] = "fft object"; -AUBIO_DECLARE(fft, uint_t win_s; uint_t channels) +AUBIO_DECLARE(fft, uint_t win_s) //AUBIO_NEW(fft) static PyObject * Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds) { - int win_s = 0, channels = 0; + int win_s = 0; Py_fft *self; - static char *kwlist[] = { "win_s", "channels", NULL }; + static char *kwlist[] = { "win_s", NULL }; - if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist, - &win_s, &channels)) { + if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist, + &win_s)) { return NULL; } @@ -24,7 +24,6 @@ Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds) } self->win_s = Py_default_vector_length; - self->channels = Py_default_vector_channels; if (self == NULL) { return NULL; @@ -38,19 +37,11 @@ Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds) return NULL; } - if (channels > 0) { - self->channels = channels; - } else if (channels < 0) { - PyErr_SetString (PyExc_ValueError, - "can not use negative number of filters"); - return NULL; - } - return (PyObject *) self; } -AUBIO_INIT(fft, self->win_s, self->channels) +AUBIO_INIT(fft, self->win_s) AUBIO_DEL(fft) @@ -72,9 +63,8 @@ Py_fft_do(PyObject * self, PyObject * args) } output = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); - output->channels = vec->channels; output->length = ((Py_fft *) self)->win_s; - output->o = new_cvec(((Py_fft *) self)->win_s, vec->channels); + output->o = new_cvec(((Py_fft *) self)->win_s); // compute the function aubio_fft_do (((Py_fft *)self)->o, vec->o, output->o); @@ -86,8 +76,6 @@ Py_fft_do(PyObject * self, PyObject * args) AUBIO_MEMBERS_START(fft) {"win_s", T_INT, offsetof (Py_fft, win_s), READONLY, "size of the window"}, - {"channels", T_INT, offsetof (Py_fft, channels), READONLY, - "number of channels"}, AUBIO_MEMBERS_STOP(fft) static PyObject * @@ -108,9 +96,8 @@ Py_fft_rdo(PyObject * self, PyObject * args) } output = (Py_fvec*) PyObject_New (Py_fvec, &Py_fvecType); - output->channels = vec->channels; output->length = ((Py_fft *) self)->win_s; - output->o = new_fvec(output->length, output->channels); + output->o = new_fvec(output->length); // compute the function aubio_fft_rdo (((Py_fft *)self)->o, vec->o, output->o); diff --git a/interfaces/python/py-filter.c b/interfaces/python/py-filter.c index 7f463411..7888b7aa 100644 --- a/interfaces/python/py-filter.c +++ b/interfaces/python/py-filter.c @@ -5,7 +5,6 @@ typedef struct PyObject_HEAD aubio_filter_t * o; uint_t order; - uint_t channels; } Py_filter; static char Py_filter_doc[] = "filter object"; @@ -13,12 +12,12 @@ static char Py_filter_doc[] = "filter object"; static PyObject * Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds) { - int order= 0, channels = 0; + int order= 0; Py_filter *self; - static char *kwlist[] = { "order", "channels", NULL }; + static char *kwlist[] = { "order", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist, - &order, &channels)) { + &order)) { return NULL; } @@ -29,7 +28,6 @@ Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds) } self->order = 7; - self->channels = Py_default_vector_channels; if (order > 0) { self->order = order; @@ -39,21 +37,13 @@ Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds) return NULL; } - if (channels > 0) { - self->channels = channels; - } else if (channels < 0) { - PyErr_SetString (PyExc_ValueError, - "can not use negative number of channels"); - return NULL; - } - return (PyObject *) self; } static int Py_filter_init (Py_filter * self, PyObject * args, PyObject * kwds) { - self->o = new_aubio_filter (self->order, self->channels); + self->o = new_aubio_filter (self->order); if (self->o == NULL) { return -1; } @@ -91,11 +81,11 @@ Py_filter_do(PyObject * self, PyObject * args) // compute the function #if 1 aubio_filter_do (((Py_filter *)self)->o, vec->o); - Py_INCREF(vec); + PyArray_INCREF((PyArrayObject*)vec); return (PyObject *)vec; #else Py_fvec *copy = (Py_fvec*) PyObject_New (Py_fvec, &Py_fvecType); - copy->o = new_fvec(vec->o->length, vec->o->channels); + copy->o = new_fvec(vec->o->length); aubio_filter_do_outplace (((Py_filter *)self)->o, vec->o, copy->o); return (PyObject *)copy; #endif @@ -141,8 +131,6 @@ static PyMemberDef Py_filter_members[] = { // TODO remove READONLY flag and define getter/setter {"order", T_INT, offsetof (Py_filter, order), READONLY, "order of the filter"}, - {"channels", T_INT, offsetof (Py_filter, channels), READONLY, - "number of channels"}, {NULL} /* Sentinel */ }; diff --git a/interfaces/python/py-filterbank.c b/interfaces/python/py-filterbank.c index f8a1307e..95c94214 100644 --- a/interfaces/python/py-filterbank.c +++ b/interfaces/python/py-filterbank.c @@ -67,9 +67,8 @@ Py_filterbank_do(Py_filterbank * self, PyObject * args) } output = (Py_fvec*) PyObject_New (Py_fvec, &Py_fvecType); - output->channels = vec->channels; output->length = self->n_filters; - output->o = new_fvec(self->n_filters, vec->channels); + output->o = new_fvec(self->n_filters); // compute the function aubio_filterbank_do (self->o, vec->o, output->o); @@ -137,11 +136,9 @@ Py_filterbank_set_mel_coeffs_slaney (Py_filterbank * self, PyObject *args) static PyObject * Py_filterbank_get_coeffs (Py_filterbank * self, PyObject *unused) { - Py_fvec *output = (Py_fvec *) PyObject_New (Py_fvec, &Py_fvecType); - output->channels = self->n_filters; - output->length = self->win_s / 2 + 1; + Py_fmat *output = (Py_fmat *) PyObject_New (Py_fmat, &Py_fvecType); output->o = aubio_filterbank_get_coeffs (self->o); - return (PyObject *)PyAubio_FvecToArray(output); + return (PyObject *)PyAubio_FmatToArray(output); } static PyMethodDef Py_filterbank_methods[] = { diff --git a/interfaces/python/py-fmat.c b/interfaces/python/py-fmat.c new file mode 100644 index 00000000..92c12c53 --- /dev/null +++ b/interfaces/python/py-fmat.c @@ -0,0 +1,332 @@ +#include "aubio-types.h" + +/* fmat type definition + +class fmat(): + def __init__(self, length = 1024, height = 1): + self.length = length + self.height = height + self.data = array(length, height) + +*/ + +static char Py_fmat_doc[] = "fmat object"; + +static PyObject * +Py_fmat_new (PyTypeObject * type, PyObject * args, PyObject * kwds) +{ + int length= 0, height = 0; + Py_fmat *self; + static char *kwlist[] = { "length", "height", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist, + &length, &height)) { + return NULL; + } + + + self = (Py_fmat *) type->tp_alloc (type, 0); + + self->length = Py_default_vector_length; + self->height = Py_default_vector_height; + + if (self == NULL) { + return NULL; + } + + if (length > 0) { + self->length = length; + } else if (length < 0) { + PyErr_SetString (PyExc_ValueError, + "can not use negative number of elements"); + return NULL; + } + + if (height > 0) { + self->height = height; + } else if (height < 0) { + PyErr_SetString (PyExc_ValueError, + "can not use negative number of height"); + return NULL; + } + + return (PyObject *) self; +} + +static int +Py_fmat_init (Py_fmat * self, PyObject * args, PyObject * kwds) +{ + self->o = new_fmat (self->length, self->height); + if (self->o == NULL) { + return -1; + } + + return 0; +} + +static void +Py_fmat_del (Py_fmat * self) +{ + del_fmat (self->o); + self->ob_type->tp_free ((PyObject *) self); +} + +static PyObject * +Py_fmat_repr (Py_fmat * self, PyObject * unused) +{ + PyObject *format = NULL; + PyObject *args = NULL; + PyObject *result = NULL; + + format = PyString_FromString ("aubio fmat of %d elements with %d height"); + if (format == NULL) { + goto fail; + } + + args = Py_BuildValue ("II", self->length, self->height); + if (args == NULL) { + goto fail; + } + fmat_print ( self->o ); + + result = PyString_Format (format, args); + +fail: + Py_XDECREF (format); + Py_XDECREF (args); + + return result; +} + +Py_fmat * +PyAubio_ArrayTofmat (PyObject *input) { + PyObject *array; + Py_fmat *vec; + uint_t i; + if (input == NULL) { + PyErr_SetString (PyExc_ValueError, "input array is not a python object"); + goto fail; + } + // parsing input object into a Py_fmat + if (PyObject_TypeCheck (input, &Py_fmatType)) { + // input is an fmat, nothing else to do + vec = (Py_fmat *) input; + } else if (PyArray_Check(input)) { + + // we got an array, convert it to an fmat + if (PyArray_NDIM (input) == 0) { + PyErr_SetString (PyExc_ValueError, "input array is a scalar"); + goto fail; + } else if (PyArray_NDIM (input) > 2) { + PyErr_SetString (PyExc_ValueError, + "input array has more than two dimensions"); + goto fail; + } + + if (!PyArray_ISFLOAT (input)) { + PyErr_SetString (PyExc_ValueError, "input array should be float"); + goto fail; + } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) { + PyErr_SetString (PyExc_ValueError, "input array should be float32"); + goto fail; + } else { + // input data type is float32, nothing else to do + array = input; + } + + // create a new fmat object + vec = (Py_fmat*) PyObject_New (Py_fmat, &Py_fmatType); + if (PyArray_NDIM (array) == 1) { + vec->height = 1; + vec->length = PyArray_SIZE (array); + } else { + vec->height = PyArray_DIM (array, 0); + vec->length = PyArray_DIM (array, 1); + } + + // no need to really allocate fmat, just its struct member + // vec->o = new_fmat (vec->length, vec->height); + vec->o = (fmat_t *)malloc(sizeof(fmat_t)); + vec->o->length = vec->length; vec->o->height = vec->height; + vec->o->data = (smpl_t**)malloc(vec->o->height * sizeof(smpl_t*)); + // hat data[i] point to array line + for (i = 0; i < vec->height; i++) { + vec->o->data[i] = (smpl_t *) PyArray_GETPTR1 (array, i); + } + + } else { + PyErr_SetString (PyExc_ValueError, "can only accept array or fmat as input"); + return NULL; + } + + return vec; + +fail: + return NULL; +} + +PyObject * +PyAubio_CfmatToArray (fmat_t * self) +{ + PyObject *array = NULL; + uint_t i; + npy_intp dims[] = { self->length, 1 }; + PyObject *concat = PyList_New (0), *tmp = NULL; + for (i = 0; i < self->height; i++) { + tmp = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data[i]); + PyList_Append (concat, tmp); + Py_DECREF (tmp); + } + array = PyArray_FromObject (concat, AUBIO_NPY_SMPL, 2, 2); + Py_DECREF (concat); + return array; +} + +PyObject * +PyAubio_FmatToArray (Py_fmat * self) +{ + PyObject *array = NULL; + if (self->height == 1) { + npy_intp dims[] = { self->length, 1 }; + array = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->data[0]); + } else { + uint_t i; + npy_intp dims[] = { self->length, 1 }; + PyObject *concat = PyList_New (0), *tmp = NULL; + for (i = 0; i < self->height; i++) { + tmp = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->data[i]); + PyList_Append (concat, tmp); + Py_DECREF (tmp); + } + array = PyArray_FromObject (concat, AUBIO_NPY_SMPL, 2, 2); + Py_DECREF (concat); + } + return array; +} + +static Py_ssize_t +Py_fmat_get_height (Py_fmat * self) +{ + return self->height; +} + +static PyObject * +Py_fmat_getitem (Py_fmat * self, Py_ssize_t index) +{ + PyObject *array; + + if (index < 0 || index >= self->height) { + PyErr_SetString (PyExc_IndexError, "no such channel"); + return NULL; + } + + npy_intp dims[] = { self->length, 1 }; + array = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->data[index]); + return array; +} + +static int +Py_fmat_setitem (Py_fmat * self, Py_ssize_t index, PyObject * o) +{ + PyObject *array; + + if (index < 0 || index >= self->height) { + PyErr_SetString (PyExc_IndexError, "no such channel"); + return -1; + } + + array = PyArray_FROM_OT (o, AUBIO_NPY_SMPL); + if (array == NULL) { + PyErr_SetString (PyExc_ValueError, "should be an array of float"); + goto fail; + } + + if (PyArray_NDIM (array) != 1) { + PyErr_SetString (PyExc_ValueError, "should be a one-dimensional array"); + goto fail; + } + + if (PyArray_SIZE (array) != self->length) { + PyErr_SetString (PyExc_ValueError, + "should be an array of same length as target fmat"); + goto fail; + } + + self->o->data[index] = (smpl_t *) PyArray_GETPTR1 (array, 0); + + return 0; + +fail: + return -1; +} + +static PyMemberDef Py_fmat_members[] = { + // TODO remove READONLY flag and define getter/setter + {"length", T_INT, offsetof (Py_fmat, length), READONLY, + "length attribute"}, + {"height", T_INT, offsetof (Py_fmat, height), READONLY, + "height attribute"}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef Py_fmat_methods[] = { + {"__array__", (PyCFunction) PyAubio_FmatToArray, METH_NOARGS, + "Returns the vector as a numpy array."}, + {NULL} +}; + +static PySequenceMethods Py_fmat_tp_as_sequence = { + (lenfunc) Py_fmat_get_height, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc) Py_fmat_getitem, /* sq_item */ + 0, /* sq_slice */ + (ssizeobjargproc) Py_fmat_setitem, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + + +PyTypeObject Py_fmatType = { + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "aubio.fmat", /* tp_name */ + sizeof (Py_fmat), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) Py_fmat_del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) Py_fmat_repr, /* tp_repr */ + 0, /* tp_as_number */ + &Py_fmat_tp_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_fmat_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Py_fmat_methods, /* tp_methods */ + Py_fmat_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) Py_fmat_init, /* tp_init */ + 0, /* tp_alloc */ + Py_fmat_new, /* tp_new */ +}; -- 2.26.2