shithub: aubio

Download patch

ref: 96fe713cccdf01faf343d5ac629381d9348fca68
parent: 7a7b00f3a3d6681b34287a8e94d5314cd6ae2c0e
author: Paul Brossier <piem@piem.org>
date: Fri Dec 4 20:44:11 EST 2009

interfaces/python: towards mono

--- a/interfaces/python/aubio-types.h
+++ b/interfaces/python/aubio-types.h
@@ -5,8 +5,8 @@
 #define AUBIO_UNSTABLE 1
 #include <aubio.h>
 
-#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,7 +24,6 @@
 it. 
 
 */
-#define AUBIO_DO_CASTING 0
 
 typedef struct
 {
@@ -31,12 +30,23 @@
   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
 {
--- a/interfaces/python/aubiomodule.c
+++ b/interfaces/python/aubiomodule.c
@@ -121,6 +121,7 @@
   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 @@
 
   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);
--- a/interfaces/python/aubiowraphell.h
+++ b/interfaces/python/aubiowraphell.h
@@ -93,7 +93,6 @@
 };
 
 // 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;
--- a/interfaces/python/gen_pyobject.py
+++ b/interfaces/python/gen_pyobject.py
@@ -68,20 +68,20 @@
 # 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 @@
     # 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 @@
 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 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,8 +188,8 @@
   %(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,
@@ -193,6 +196,8 @@
           %(paramrefs)s)) {
     return NULL;
   }
+""" % locals()
+    s += """\
 
   self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
 
@@ -237,7 +242,7 @@
   return (PyObject *) self;
 }
 
-AUBIO_INIT(%(name)s, self->%(selfparams)s)
+AUBIO_INIT(%(name)s %(selfparams)s)
 
 AUBIO_DEL(%(name)s)
 
@@ -286,10 +291,10 @@
         #    "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"
--- 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 @@
   }
 
   self->win_s = Py_default_vector_length;
-  self->channels = Py_default_vector_channels;
 
   if (self == NULL) {
     return NULL;
@@ -38,19 +37,11 @@
     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 @@
   }
 
   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 @@
 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 @@
   }
 
   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);
--- a/interfaces/python/py-filter.c
+++ b/interfaces/python/py-filter.c
@@ -5,7 +5,6 @@
   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 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 @@
   }
 
   self->order = 7;
-  self->channels = Py_default_vector_channels;
 
   if (order > 0) {
     self->order = order;
@@ -39,14 +37,6 @@
     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;
 }
 
@@ -53,7 +43,7 @@
 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 @@
   // 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 @@
   // 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 */
 };
 
--- a/interfaces/python/py-filterbank.c
+++ b/interfaces/python/py-filterbank.c
@@ -67,9 +67,8 @@
   }
 
   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 @@
 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[] = {
--- /dev/null
+++ b/interfaces/python/py-fmat.c
@@ -1,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            */
+};