interfaces/python: add cvec and filter types
authorPaul Brossier <piem@piem.org>
Tue, 6 Oct 2009 00:50:49 +0000 (02:50 +0200)
committerPaul Brossier <piem@piem.org>
Tue, 6 Oct 2009 00:50:49 +0000 (02:50 +0200)
interfaces/python/py-cvec.c [new file with mode: 0644]
interfaces/python/py-filter.c [new file with mode: 0644]

diff --git a/interfaces/python/py-cvec.c b/interfaces/python/py-cvec.c
new file mode 100644 (file)
index 0000000..ec25546
--- /dev/null
@@ -0,0 +1,331 @@
+#include "aubio-types.h"
+
+/* cvec type definition 
+
+class cvec():
+    def __init__(self, length = 1024, channels = 1):
+        self.length = length 
+        self.channels = channels 
+        self.norm = array(length, channels)
+        self.phas = array(length, channels)
+
+*/
+
+typedef struct
+{
+  PyObject_HEAD
+  cvec_t * o;
+  uint_t length;
+  uint_t channels;
+} Py_cvec;
+
+static char Py_cvec_doc[] = "cvec object";
+
+static PyObject *
+Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int length= 0, channels = 0;
+  Py_cvec *self;
+  static char *kwlist[] = { "length", "channels", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
+          &length, &channels)) {
+    return NULL;
+  }
+
+
+  self = (Py_cvec *) type->tp_alloc (type, 0);
+
+  self->length = Py_default_vector_length;
+  self->channels = Py_default_vector_channels;
+
+  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 (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_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_cvec (self->length, self->channels);
+  if (self->o == NULL) {
+    return -1;
+  }
+
+  return 0;
+}
+
+static void
+Py_cvec_del (Py_cvec * self)
+{
+  del_cvec (self->o);
+  self->ob_type->tp_free ((PyObject *) self);
+}
+
+static PyObject *
+Py_cvec_repr (Py_cvec * self, PyObject * unused)
+{
+  PyObject *format = NULL;
+  PyObject *args = NULL;
+  PyObject *result = NULL;
+
+  format = PyString_FromString ("aubio cvec of %d elements with %d channels");
+  if (format == NULL) {
+    goto fail;
+  }
+
+  args = Py_BuildValue ("II", self->length, self->channels);
+  if (args == NULL) {
+    goto fail;
+  }
+  cvec_print ( self->o );
+
+  result = PyString_Format (format, args);
+
+fail:
+  Py_XDECREF (format);
+  Py_XDECREF (args);
+
+  return result;
+}
+
+Py_cvec *
+PyAubio_ArrayToCvec (PyObject *input) {
+  PyObject *array;
+  Py_cvec *vec;
+  uint_t i;
+  // parsing input object into a Py_cvec
+  if (PyObject_TypeCheck (input, &Py_cvecType)) {
+    // input is an cvec, nothing else to do
+    vec = (Py_cvec *) input;
+  } else if (PyArray_Check(input)) {
+
+    // we got an array, convert it to an cvec 
+    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;
+#if AUBIO_DO_CASTING
+    } else if (PyArray_TYPE (input) != AUBIO_FLOAT) {
+      // input data type is not float32, casting 
+      array = PyArray_Cast ( (PyArrayObject*) input, AUBIO_FLOAT);
+      if (array == NULL) {
+        PyErr_SetString (PyExc_IndexError, "failed converting to NPY_FLOAT");
+        goto fail;
+      }
+#else
+    } else if (PyArray_TYPE (input) != AUBIO_FLOAT) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      goto fail;
+#endif
+    } else {
+      // input data type is float32, nothing else to do
+      array = input;
+    }
+
+    // create a new cvec object
+    vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); 
+    if (PyArray_NDIM (array) == 1) {
+      vec->channels = 1;
+      vec->length = PyArray_SIZE (array);
+    } else {
+      vec->channels = PyArray_DIM (array, 0);
+      vec->length = PyArray_DIM (array, 1);
+    }
+
+    // no need to really allocate cvec, just its struct member 
+    // vec->o = new_cvec (vec->length, vec->channels);
+    vec->o = (cvec_t *)malloc(sizeof(cvec_t));
+    vec->o->length = vec->length; vec->o->channels = vec->channels;
+    vec->o->norm = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
+    vec->o->phas = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
+    // hat data[i] point to array line
+    for (i = 0; i < vec->channels; i++) {
+      vec->o->norm[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
+    }
+
+  } else {
+    PyErr_SetString (PyExc_ValueError, "can only accept array or cvec as input");
+    return NULL;
+  }
+
+  return vec;
+
+fail:
+  return NULL;
+}
+
+PyObject *
+PyAubio_CvecToArray (Py_cvec * self)
+{
+  PyObject *array = NULL;
+  if (self->channels == 1) {
+    npy_intp dims[] = { self->length, 1 };
+    array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[0]);
+  } else {
+    uint_t i;
+    npy_intp dims[] = { self->length, 1 };
+    PyObject *concat = PyList_New (0), *tmp = NULL;
+    for (i = 0; i < self->channels; i++) {
+      tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[i]);
+      PyList_Append (concat, tmp);
+      Py_DECREF (tmp);
+    }
+    array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
+    Py_DECREF (concat);
+  }
+  return array;
+}
+
+static Py_ssize_t
+Py_cvec_getchannels (Py_cvec * self)
+{
+  return self->channels;
+}
+
+static PyObject *
+Py_cvec_getitem (Py_cvec * self, Py_ssize_t index)
+{
+  PyObject *array;
+
+  if (index < 0 || index >= self->channels) {
+    PyErr_SetString (PyExc_IndexError, "no such channel");
+    return NULL;
+  }
+
+  npy_intp dims[] = { self->length, 1 };
+  array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[index]);
+  return array;
+}
+
+static int
+Py_cvec_setitem (Py_cvec * self, Py_ssize_t index, PyObject * o)
+{
+  PyObject *array;
+
+  if (index < 0 || index >= self->channels) {
+    PyErr_SetString (PyExc_IndexError, "no such channel");
+    return -1;
+  }
+
+  array = PyArray_FROM_OT (o, NPY_FLOAT);
+  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 cvec");
+    goto fail;
+  }
+
+  self->o->norm[index] = (smpl_t *) PyArray_GETPTR1 (array, 0);
+
+  return 0;
+
+fail:
+  return -1;
+}
+
+static PyMemberDef Py_cvec_members[] = {
+  // TODO remove READONLY flag and define getter/setter
+  {"length", T_INT, offsetof (Py_cvec, length), READONLY,
+      "length attribute"},
+  {"channels", T_INT, offsetof (Py_cvec, channels), READONLY,
+      "channels attribute"},
+  {NULL}                        /* Sentinel */
+};
+
+static PyMethodDef Py_cvec_methods[] = {
+  {"__array__", (PyCFunction) PyAubio_FvecToArray, METH_NOARGS,
+      "Returns the first channel as a numpy array."},
+  {NULL}
+};
+
+static PySequenceMethods Py_cvec_tp_as_sequence = {
+  (lenfunc) Py_cvec_getchannels,        /* sq_length         */
+  0,                                    /* sq_concat         */
+  0,                                    /* sq_repeat         */
+  (ssizeargfunc) Py_cvec_getitem,       /* sq_item           */
+  0,                                    /* sq_slice          */
+  (ssizeobjargproc) Py_cvec_setitem,    /* sq_ass_item       */
+  0,                                    /* sq_ass_slice      */
+  0,                                    /* sq_contains       */
+  0,                                    /* sq_inplace_concat */
+  0,                                    /* sq_inplace_repeat */
+};
+
+
+PyTypeObject Py_cvecType = {
+  PyObject_HEAD_INIT (NULL)
+  0,                            /* ob_size           */
+  "aubio.cvec",                 /* tp_name           */
+  sizeof (Py_cvec),             /* tp_basicsize      */
+  0,                            /* tp_itemsize       */
+  (destructor) Py_cvec_del,     /* tp_dealloc        */
+  0,                            /* tp_print          */
+  0,                            /* tp_getattr        */
+  0,                            /* tp_setattr        */
+  0,                            /* tp_compare        */
+  (reprfunc) Py_cvec_repr,      /* tp_repr           */
+  0,                            /* tp_as_number      */
+  &Py_cvec_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_cvec_doc,                  /* tp_doc            */
+  0,                            /* tp_traverse       */
+  0,                            /* tp_clear          */
+  0,                            /* tp_richcompare    */
+  0,                            /* tp_weaklistoffset */
+  0,                            /* tp_iter           */
+  0,                            /* tp_iternext       */
+  Py_cvec_methods,              /* tp_methods        */
+  Py_cvec_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_cvec_init,      /* tp_init           */
+  0,                            /* tp_alloc          */
+  Py_cvec_new,                  /* tp_new            */
+};
diff --git a/interfaces/python/py-filter.c b/interfaces/python/py-filter.c
new file mode 100644 (file)
index 0000000..b7d4e86
--- /dev/null
@@ -0,0 +1,199 @@
+#include "aubio-types.h"
+
+typedef struct
+{
+  PyObject_HEAD
+  aubio_filter_t * o;
+  uint_t samplerate;
+  uint_t order;
+  uint_t channels;
+} Py_filter;
+
+static char Py_filter_doc[] = "filter object";
+
+static PyObject *
+Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int samplerate= 0, order= 0, channels = 0;
+  Py_filter *self;
+  static char *kwlist[] = { "samplerate", "order", "channels", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|III", kwlist,
+          &samplerate, &order, &channels)) {
+    return NULL;
+  }
+
+  self = (Py_filter *) type->tp_alloc (type, 0);
+
+  self->samplerate = Py_aubio_default_samplerate;
+  self->order = 7;
+  self->channels = Py_default_vector_channels;
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  if (samplerate > 0) {
+    self->samplerate = samplerate;
+  } else if (samplerate < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative samplerate");
+    return NULL;
+  }
+
+  if (order > 0) {
+    self->order = order;
+  } else if (order < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative order");
+    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->samplerate, self->order, self->channels);
+  if (self->o == NULL) {
+    return -1;
+  }
+
+  return 0;
+}
+
+static void
+Py_filter_del (Py_filter * self)
+{
+  del_aubio_filter (self->o);
+  self->ob_type->tp_free ((PyObject *) self);
+}
+
+static PyObject * 
+Py_filter_do(PyObject * self, PyObject * args)
+{
+  PyObject *input;
+  Py_fvec *vec;
+
+  if (!PyArg_ParseTuple (args, "O:digital_filter.do", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  // compute the function
+#if 1
+  aubio_filter_do (((Py_filter *)self)->o, vec->o);
+  Py_INCREF(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);
+  aubio_filter_do_outplace (((Py_filter *)self)->o, vec->o, copy->o);
+  return (PyObject *)copy;
+#endif
+}
+
+static PyObject * 
+Py_filter_set_c_weighting (Py_filter * self, PyObject *unused)
+{
+  uint_t err = aubio_filter_set_c_weighting (((Py_filter *)self)->o);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to C-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject * 
+Py_filter_set_a_weighting (Py_filter * self, PyObject *unused)
+{
+  uint_t err = aubio_filter_set_a_weighting (((Py_filter *)self)->o);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to A-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyMemberDef Py_filter_members[] = {
+  // TODO remove READONLY flag and define getter/setter
+  {"samplerate", T_INT, offsetof (Py_filter, samplerate), READONLY,
+      "sampling rate"},
+  {"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 */
+};
+
+static PyMethodDef Py_filter_methods[] = {
+  {"do", (PyCFunction) Py_filter_do, METH_VARARGS,
+      "filter input vector"},
+  {"set_c_weighting", (PyCFunction) Py_filter_set_c_weighting, METH_NOARGS,
+      "set filter coefficients to C-weighting"},
+  {"set_a_weighting", (PyCFunction) Py_filter_set_a_weighting, METH_NOARGS,
+      "set filter coefficients to A-weighting"},
+  {NULL}
+};
+
+PyTypeObject Py_filterType = {
+  PyObject_HEAD_INIT (NULL)
+  0,                            /* ob_size           */
+  "aubio.digital_filter",       /* tp_name           */
+  sizeof (Py_filter),           /* tp_basicsize      */
+  0,                            /* tp_itemsize       */
+  (destructor) Py_filter_del,   /* tp_dealloc        */
+  0,                            /* tp_print          */
+  0,                            /* tp_getattr        */
+  0,                            /* tp_setattr        */
+  0,                            /* tp_compare        */
+  0, //(reprfunc) Py_filter_repr,    /* tp_repr           */
+  0,                            /* tp_as_number      */
+  0,                            /* tp_as_sequence    */
+  0,                            /* tp_as_mapping     */
+  0,                            /* tp_hash           */
+  (ternaryfunc)Py_filter_do,    /* tp_call           */
+  0,                            /* tp_str            */
+  0,                            /* tp_getattro       */
+  0,                            /* tp_setattro       */
+  0,                            /* tp_as_buffer      */
+  Py_TPFLAGS_DEFAULT,           /* tp_flags          */
+  Py_filter_doc,                /* tp_doc            */
+  0,                            /* tp_traverse       */
+  0,                            /* tp_clear          */
+  0,                            /* tp_richcompare    */
+  0,                            /* tp_weaklistoffset */
+  0,                            /* tp_iter           */
+  0,                            /* tp_iternext       */
+  Py_filter_methods,            /* tp_methods        */
+  Py_filter_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_filter_init,    /* tp_init           */
+  0,                            /* tp_alloc          */
+  Py_filter_new,                /* tp_new            */
+};