[py] fix reference counting of exception types (thanks @wackou)
[aubio.git] / python / ext / py-filter.c
index 90b8961..220eb13 100644 (file)
@@ -6,10 +6,62 @@ typedef struct
   aubio_filter_t * o;
   uint_t order;
   fvec_t vec;
-  fvec_t *out;
+  PyObject *out;
+  fvec_t c_out;
 } Py_filter;
 
-static char Py_filter_doc[] = "filter object";
+static char Py_filter_doc[] = ""
+"digital_filter(order=7)\n"
+"\n"
+"Create a digital filter.\n"
+"";
+
+static char Py_filter_set_c_weighting_doc[] = ""
+"set_c_weighting(samplerate)\n"
+"\n"
+"Set filter coefficients to C-weighting.\n"
+"\n"
+"`samplerate` should be one of 8000, 11025, 16000, 22050, 24000, 32000,\n"
+"44100, 48000, 88200, 96000, or 192000. `order` of the filter should be 5.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"samplerate : int\n"
+"    Sampling-rate of the input signal, in Hz.\n"
+"";
+
+static char Py_filter_set_a_weighting_doc[] = ""
+"set_a_weighting(samplerate)\n"
+"\n"
+"Set filter coefficients to A-weighting.\n"
+"\n"
+"`samplerate` should be one of 8000, 11025, 16000, 22050, 24000, 32000,\n"
+"44100, 48000, 88200, 96000, or 192000. `order` of the filter should be 7.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"samplerate : int\n"
+"    Sampling-rate of the input signal.\n"
+"";
+
+static char Py_filter_set_biquad_doc[] = ""
+"set_biquad(b0, b1, b2, a1, a2)\n"
+"\n"
+"Set biquad coefficients. `order` of the filter should be 3.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"b0 : float\n"
+"    Forward filter coefficient.\n"
+"b1 : float\n"
+"    Forward filter coefficient.\n"
+"b2 : float\n"
+"    Forward filter coefficient.\n"
+"a1 : float\n"
+"    Feedback filter coefficient.\n"
+"a2 : float\n"
+"    Feedback filter coefficient.\n"
+"";
 
 static PyObject *
 Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
@@ -49,19 +101,20 @@ Py_filter_init (Py_filter * self, PyObject * args, PyObject * kwds)
   if (self->o == NULL) {
     return -1;
   }
-  self->out = new_fvec(Py_default_vector_length);
+  self->out = NULL;
   return 0;
 }
 
 static void
 Py_filter_del (Py_filter * self)
 {
-  del_fvec(self->out);
-  del_aubio_filter (self->o);
+  Py_XDECREF(self->out);
+  if (self->o)
+    del_aubio_filter (self->o);
   Py_TYPE(self)->tp_free ((PyObject *) self);
 }
 
-static PyObject * 
+static PyObject *
 Py_filter_do(Py_filter * self, PyObject * args)
 {
   PyObject *input;
@@ -78,17 +131,21 @@ Py_filter_do(Py_filter * self, PyObject * args)
     return NULL;
   }
 
-  // reallocate the output if needed
-  if (self->vec.length != self->out->length) {
-    del_fvec(self->out);
-    self->out = new_fvec(self->vec.length);
+  // initialize output now
+  if (self->out == NULL) {
+    self->out = new_py_fvec(self->vec.length);
+  }
+
+  Py_INCREF(self->out);
+  if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out)) ) {
+    return NULL;
   }
   // compute the function
-  aubio_filter_do_outplace (self->o, &(self->vec), self->out);
-  return PyAubio_CFvecToArray(self->out);
+  aubio_filter_do_outplace (self->o, &(self->vec), &(self->c_out));
+  return self->out;
 }
 
-static PyObject * 
+static PyObject *
 Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
 {
   uint_t err = 0;
@@ -99,14 +156,24 @@ Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
 
   err = aubio_filter_set_c_weighting (self->o, samplerate);
   if (err > 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to C-weighting");
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError,
+          "error when setting filter to C-weighting");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      Py_XDECREF(type);
+      type = PyExc_ValueError;
+      Py_XINCREF(type);
+      PyErr_Restore(type, value, traceback);
+    }
     return NULL;
   }
   Py_RETURN_NONE;
 }
 
-static PyObject * 
+static PyObject *
 Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
 {
   uint_t err = 0;
@@ -117,8 +184,18 @@ Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
 
   err = aubio_filter_set_a_weighting (self->o, samplerate);
   if (err > 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to A-weighting");
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError,
+          "error when setting filter to A-weighting");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      Py_XDECREF(type);
+      type = PyExc_ValueError;
+      Py_XINCREF(type);
+      PyErr_Restore(type, value, traceback);
+    }
     return NULL;
   }
   Py_RETURN_NONE;
@@ -135,8 +212,18 @@ Py_filter_set_biquad(Py_filter * self, PyObject *args)
 
   err = aubio_filter_set_biquad (self->o, b0, b1, b2, a1, a2);
   if (err > 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "error when setting filter with biquad coefficients");
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError,
+          "error when setting filter with biquad coefficients");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      Py_XDECREF(type);
+      type = PyExc_ValueError;
+      Py_XINCREF(type);
+      PyErr_Restore(type, value, traceback);
+    }
     return NULL;
   }
   Py_RETURN_NONE;
@@ -151,11 +238,11 @@ static PyMemberDef Py_filter_members[] = {
 
 static PyMethodDef Py_filter_methods[] = {
   {"set_c_weighting", (PyCFunction) Py_filter_set_c_weighting, METH_VARARGS,
-      "set filter coefficients to C-weighting"},
+      Py_filter_set_c_weighting_doc},
   {"set_a_weighting", (PyCFunction) Py_filter_set_a_weighting, METH_VARARGS,
-      "set filter coefficients to A-weighting"},
+      Py_filter_set_a_weighting_doc},
   {"set_biquad", (PyCFunction) Py_filter_set_biquad, METH_VARARGS,
-      "set b0, b1, b2, a1, a2 biquad coefficients"},
+      Py_filter_set_biquad_doc},
   {NULL}
 };
 
@@ -198,4 +285,13 @@ PyTypeObject Py_filterType = {
   (initproc) Py_filter_init,    /* tp_init           */
   0,                            /* tp_alloc          */
   Py_filter_new,                /* tp_new            */
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
 };