shithub: aubio

Download patch

ref: 92a880038648589865c7bd3fac15647a7b792788
parent: 1f4d932e233b44476f39d699a19e6c023e058626
author: Paul Brossier <piem@piem.org>
date: Thu Apr 28 14:59:55 EDT 2016

python/ext/py-cvec.c: rewrite and simplify aubio.cvec, safer and better memory usage (see #49)

--- a/python/ext/aubio-types.h
+++ b/python/ext/aubio-types.h
@@ -50,13 +50,6 @@
 #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
 #endif
 
-// special python type for cvec
-typedef struct
-{
-  PyObject_HEAD
-  cvec_t * o;
-  uint_t length;
-} Py_cvec;
 extern PyTypeObject Py_cvecType;
 
 // defined in aubio-proxy.c
@@ -63,8 +56,8 @@
 extern PyObject *PyAubio_CFvecToArray (fvec_t * self);
 extern int PyAubio_ArrayToCFvec (PyObject * self, fvec_t *out);
 
-extern PyObject * PyAubio_CCvecToPyCvec (cvec_t * self, Py_cvec *out);
-extern int PyAubio_ArrayToCCvec (PyObject *input, cvec_t *i);
+extern PyObject * PyAubio_CCvecToPyCvec (cvec_t * self);
+extern int PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i);
 
 extern PyObject *PyAubio_CFmatToArray (fmat_t * self);
 extern int PyAubio_ArrayToCFmat (PyObject *input, fmat_t *out);
--- a/python/ext/aubioproxy.c
+++ b/python/ext/aubioproxy.c
@@ -56,29 +56,6 @@
 }
 
 PyObject *
-PyAubio_CCvecToPyCvec (cvec_t * input, Py_cvec *vec) {
-  vec->length = input->length;
-  vec->o = input;
-  // keep a reference to re-use after returning it
-  Py_INCREF(vec);
-  return (PyObject *)vec;
-}
-
-int
-PyAubio_ArrayToCCvec (PyObject *input, cvec_t *i) {
-  if (PyObject_TypeCheck (input, &Py_cvecType)) {
-      //*i = *(((Py_cvec*)input)->o);
-      i->norm = ((Py_cvec*)input)->o->norm;
-      i->phas = ((Py_cvec*)input)->o->phas;
-      i->length = ((Py_cvec*)input)->o->length;
-      return 1;
-  } else {
-      PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
-      return 0;
-  }
-}
-
-PyObject *
 PyAubio_CFmatToArray (fmat_t * input)
 {
   PyObject *array = NULL;
--- a/python/ext/py-cvec.c
+++ b/python/ext/py-cvec.c
@@ -1,17 +1,62 @@
 #include "aubio-types.h"
 
-/* cvec type definition 
+/* cvec type definition
 
 class cvec():
-    def __init__(self, length = 1024):
-        self.length = length 
-        self.norm = array(length)
-        self.phas = array(length)
+    def __new__(self, length = 1024):
+        self.length = length / 2 + 1
+        self.norm = np.zeros(length / 2 + 1)
+        self.phas = np.zeros(length / 2 + 1)
 
 */
 
+// special python type for cvec
+typedef struct
+{
+  PyObject_HEAD
+  PyObject *norm;
+  PyObject *phas;
+  uint_t length;
+} Py_cvec;
+
 static char Py_cvec_doc[] = "cvec object";
 
+PyObject *
+PyAubio_CCvecToPyCvec (cvec_t * input) {
+  if (input == NULL) {
+      PyErr_SetString (PyExc_ValueError, "PyAubio_CCvecToPyCvec got a null cvec!");
+      return NULL;
+  }
+  Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
+  npy_intp dims[] = { input->length, 1 };
+  vec->norm = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->norm);
+  vec->phas = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->phas);
+  vec->length = input->length;
+  return (PyObject *)vec;
+}
+
+int
+PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) {
+  if (PyObject_TypeCheck (input, &Py_cvecType)) {
+      Py_cvec * in = (Py_cvec *)input;
+      if (in->norm == NULL) {
+        npy_intp dims[] = { in->length, 1 };
+        in->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+      }
+      if (in->phas == NULL) {
+        npy_intp dims[] = { in->length, 1 };
+        in->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+      }
+      i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0);
+      i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0);
+      i->length = ((Py_cvec*)input)->length;
+      return 1;
+  } else {
+      PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
+      return 0;
+  }
+}
+
 static PyObject *
 Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -24,7 +69,6 @@
     return NULL;
   }
 
-
   self = (Py_cvec *) type->tp_alloc (type, 0);
 
   self->length = Py_default_vector_length / 2 + 1;
@@ -47,11 +91,8 @@
 static int
 Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
 {
-  self->o = new_cvec ((self->length - 1) * 2);
-  if (self->o == NULL) {
-    return -1;
-  }
-
+  self->norm = NULL;
+  self->phas = NULL;
   return 0;
 }
 
@@ -58,7 +99,8 @@
 static void
 Py_cvec_del (Py_cvec * self)
 {
-  del_cvec (self->o);
+  Py_XDECREF(self->norm);
+  Py_XDECREF(self->phas);
   Py_TYPE(self)->tp_free ((PyObject *) self);
 }
 
@@ -78,7 +120,7 @@
   if (args == NULL) {
     goto fail;
   }
-  cvec_print ( self->o );
+  // hide actual norm / phas content
 
   result = PyUnicode_Format (format, args);
 
@@ -90,36 +132,27 @@
 }
 
 PyObject *
-PyAubio_CvecNormToArray (Py_cvec * self)
-{
-  npy_intp dims[] = { self->o->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->norm);
-}
-
-
-PyObject *
-PyAubio_CvecPhasToArray (Py_cvec * self)
-{
-  npy_intp dims[] = { self->o->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->phas);
-}
-
-PyObject *
-PyAubio_ArrayToCvecPhas (PyObject * self)
-{
-  return NULL;
-}
-
-PyObject *
 Py_cvec_get_norm (Py_cvec * self, void *closure)
 {
-  return PyAubio_CvecNormToArray(self);
+  // if it norm hasn't been created, create it now
+  if (self->norm == NULL) {
+    npy_intp dims[] = { self->length, 1 };
+    self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  }
+  Py_INCREF(self->norm);
+  return (PyObject*)(self->norm);
 }
 
 PyObject *
 Py_cvec_get_phas (Py_cvec * self, void *closure)
 {
-  return PyAubio_CvecPhasToArray(self);
+  // if it phas hasn't been created, create it now
+  if (self->phas == NULL) {
+    npy_intp dims[] = { self->length, 1 };
+    self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  }
+  Py_INCREF(self->phas);
+  return (PyObject *)(self->phas);
 }
 
 static int
@@ -131,8 +164,7 @@
     goto fail;
   }
   if (PyArray_Check(input)) {
-
-    // we got an array, convert it to a cvec.norm 
+    // we got an array, convert it to a cvec.norm
     if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
       PyErr_SetString (PyExc_ValueError, "input array is a scalar");
       goto fail;
@@ -158,15 +190,17 @@
           PyArray_NDIM (array));
       goto fail;
     } else {
-      if (vec->o->length != PyArray_SIZE (array)) {
+      if (vec->length != PyArray_SIZE (array)) {
           PyErr_Format (PyExc_ValueError,
                   "input array has length %d, but cvec has length %d",
-                  (int)PyArray_SIZE (array), vec->o->length);
+                  (int)PyArray_SIZE (array), vec->length);
           goto fail;
       }
     }
 
-    vec->o->norm = (smpl_t *) PyArray_GETPTR1 (array, 0);
+    Py_XDECREF(vec->norm);
+    vec->norm = input;
+    Py_INCREF(vec->norm);
 
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept array as input");
@@ -173,7 +207,6 @@
     return 1;
   }
 
-  Py_INCREF(array);
   return 0;
 
 fail:
@@ -216,15 +249,17 @@
           PyArray_NDIM (array));
       goto fail;
     } else {
-      if (vec->o->length != PyArray_SIZE (array)) {
+      if (vec->length != PyArray_SIZE (array)) {
           PyErr_Format (PyExc_ValueError,
                   "input array has length %d, but cvec has length %d",
-                  (int)PyArray_SIZE (array), vec->o->length);
+                  (int)PyArray_SIZE (array), vec->length);
           goto fail;
       }
     }
 
-    vec->o->phas = (smpl_t *) PyArray_GETPTR1 (array, 0);
+    Py_XDECREF(vec->phas);
+    vec->phas = input;
+    Py_INCREF(vec->phas);
 
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept array as input");
@@ -231,7 +266,6 @@
     return 1;
   }
 
-  Py_INCREF(array);
   return 0;
 
 fail:
--- a/python/ext/py-fft.c
+++ b/python/ext/py-fft.c
@@ -13,8 +13,6 @@
   // do / rdo output results
   cvec_t *out;
   fvec_t *rout;
-  // bridge for cvec output
-  Py_cvec *py_out;
 } Py_fft;
 
 static PyObject *
@@ -60,8 +58,6 @@
   }
 
   self->out = new_cvec(self->win_s);
-  self->py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
-  Py_XINCREF(self->py_out);
   self->rout = new_fvec(self->win_s);
 
   return 0;
@@ -70,7 +66,6 @@
 static void
 Py_fft_del (Py_fft *self, PyObject *unused)
 {
-  Py_XDECREF((PyObject*)(self->py_out));
   del_aubio_fft(self->o);
   del_cvec(self->out);
   del_fvec(self->rout);
@@ -92,14 +87,8 @@
 
   // compute the function
   aubio_fft_do (((Py_fft *)self)->o, &(self->vecin), self->out);
-#if 0
-  Py_cvec * py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
-  PyObject* output = PyAubio_CCvecToPyCvec(self->out, py_out);
-  return output;
-#else
-  // convert cvec to py_cvec, incrementing refcount to keep a copy
-  return PyAubio_CCvecToPyCvec(self->out, self->py_out);
-#endif
+  // convert cvec to py_cvec
+  return PyAubio_CCvecToPyCvec(self->out);
 }
 
 static PyMemberDef Py_fft_members[] = {
@@ -117,7 +106,7 @@
     return NULL;
   }
 
-  if (!PyAubio_ArrayToCCvec (input, &(self->cvecin)) ) {
+  if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) {
     return NULL;
   }
 
--- a/python/ext/py-filterbank.c
+++ b/python/ext/py-filterbank.c
@@ -87,7 +87,7 @@
     return NULL;
   }
 
-  if (!PyAubio_ArrayToCCvec(input, &(self->vec) )) {
+  if (!PyAubio_PyCvecToCCvec(input, &(self->vec) )) {
     return NULL;
   }
 
--- a/python/ext/py-phasevoc.c
+++ b/python/ext/py-phasevoc.c
@@ -10,7 +10,6 @@
   uint_t hop_s;
   fvec_t vecin;
   cvec_t *output;
-  Py_cvec *py_out;
   cvec_t cvecin;
   fvec_t *routput;
 } Py_pvoc;
@@ -72,7 +71,6 @@
   }
 
   self->output = new_cvec(self->win_s);
-  self->py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
   self->routput = new_fvec(self->hop_s);
 
   return 0;
@@ -104,14 +102,8 @@
 
   // compute the function
   aubio_pvoc_do (self->o, &(self->vecin), self->output);
-#if 0
-  Py_cvec * py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
-  PyObject* output = PyAubio_CCvecToPyCvec(self->output, py_out);
-  return output;
-#else
-  // convert cvec to py_cvec, incrementing refcount to keep a copy
-  return PyAubio_CCvecToPyCvec(self->output, self->py_out);
-#endif
+  // convert cvec to py_cvec
+  return PyAubio_CCvecToPyCvec(self->output);
 }
 
 static PyMemberDef Py_pvoc_members[] = {
@@ -130,7 +122,7 @@
     return NULL;
   }
 
-  if (!PyAubio_ArrayToCCvec (input, &(self->cvecin) )) {
+  if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin) )) {
     return NULL;
   }
 
--- a/python/lib/gen_code.py
+++ b/python/lib/gen_code.py
@@ -37,7 +37,7 @@
 
 pytoaubio_fn = {
         'fvec_t*': 'PyAubio_ArrayToCFvec',
-        'cvec_t*': 'PyAubio_ArrayToCCvec',
+        'cvec_t*': 'PyAubio_PyCvecToCCvec',
         #'fmat_t*': 'PyAubio_ArrayToCFmat',
         }