[py] fix reference counting of exception types (thanks @wackou)
[aubio.git] / python / ext / py-filter.c
1 #include "aubio-types.h"
2
3 typedef struct
4 {
5   PyObject_HEAD
6   aubio_filter_t * o;
7   uint_t order;
8   fvec_t vec;
9   PyObject *out;
10   fvec_t c_out;
11 } Py_filter;
12
13 static char Py_filter_doc[] = ""
14 "digital_filter(order=7)\n"
15 "\n"
16 "Create a digital filter.\n"
17 "";
18
19 static char Py_filter_set_c_weighting_doc[] = ""
20 "set_c_weighting(samplerate)\n"
21 "\n"
22 "Set filter coefficients to C-weighting.\n"
23 "\n"
24 "`samplerate` should be one of 8000, 11025, 16000, 22050, 24000, 32000,\n"
25 "44100, 48000, 88200, 96000, or 192000. `order` of the filter should be 5.\n"
26 "\n"
27 "Parameters\n"
28 "----------\n"
29 "samplerate : int\n"
30 "    Sampling-rate of the input signal, in Hz.\n"
31 "";
32
33 static char Py_filter_set_a_weighting_doc[] = ""
34 "set_a_weighting(samplerate)\n"
35 "\n"
36 "Set filter coefficients to A-weighting.\n"
37 "\n"
38 "`samplerate` should be one of 8000, 11025, 16000, 22050, 24000, 32000,\n"
39 "44100, 48000, 88200, 96000, or 192000. `order` of the filter should be 7.\n"
40 "\n"
41 "Parameters\n"
42 "----------\n"
43 "samplerate : int\n"
44 "    Sampling-rate of the input signal.\n"
45 "";
46
47 static char Py_filter_set_biquad_doc[] = ""
48 "set_biquad(b0, b1, b2, a1, a2)\n"
49 "\n"
50 "Set biquad coefficients. `order` of the filter should be 3.\n"
51 "\n"
52 "Parameters\n"
53 "----------\n"
54 "b0 : float\n"
55 "    Forward filter coefficient.\n"
56 "b1 : float\n"
57 "    Forward filter coefficient.\n"
58 "b2 : float\n"
59 "    Forward filter coefficient.\n"
60 "a1 : float\n"
61 "    Feedback filter coefficient.\n"
62 "a2 : float\n"
63 "    Feedback filter coefficient.\n"
64 "";
65
66 static PyObject *
67 Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
68 {
69   int order= 0;
70   Py_filter *self;
71   static char *kwlist[] = { "order", NULL };
72
73   if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
74           &order)) {
75     return NULL;
76   }
77
78   self = (Py_filter *) type->tp_alloc (type, 0);
79
80   if (self == NULL) {
81     return NULL;
82   }
83
84   self->order = 7;
85
86   if (order > 0) {
87     self->order = order;
88   } else if (order < 0) {
89     PyErr_SetString (PyExc_ValueError,
90         "can not use negative order");
91     return NULL;
92   }
93
94   return (PyObject *) self;
95 }
96
97 static int
98 Py_filter_init (Py_filter * self, PyObject * args, PyObject * kwds)
99 {
100   self->o = new_aubio_filter (self->order);
101   if (self->o == NULL) {
102     return -1;
103   }
104   self->out = NULL;
105   return 0;
106 }
107
108 static void
109 Py_filter_del (Py_filter * self)
110 {
111   Py_XDECREF(self->out);
112   if (self->o)
113     del_aubio_filter (self->o);
114   Py_TYPE(self)->tp_free ((PyObject *) self);
115 }
116
117 static PyObject *
118 Py_filter_do(Py_filter * self, PyObject * args)
119 {
120   PyObject *input;
121
122   if (!PyArg_ParseTuple (args, "O:digital_filter.do", &input)) {
123     return NULL;
124   }
125
126   if (input == NULL) {
127     return NULL;
128   }
129
130   if (!PyAubio_ArrayToCFvec(input, &(self->vec))) {
131     return NULL;
132   }
133
134   // initialize output now
135   if (self->out == NULL) {
136     self->out = new_py_fvec(self->vec.length);
137   }
138
139   Py_INCREF(self->out);
140   if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out)) ) {
141     return NULL;
142   }
143   // compute the function
144   aubio_filter_do_outplace (self->o, &(self->vec), &(self->c_out));
145   return self->out;
146 }
147
148 static PyObject *
149 Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
150 {
151   uint_t err = 0;
152   uint_t samplerate;
153   if (!PyArg_ParseTuple (args, "I", &samplerate)) {
154     return NULL;
155   }
156
157   err = aubio_filter_set_c_weighting (self->o, samplerate);
158   if (err > 0) {
159     if (PyErr_Occurred() == NULL) {
160       PyErr_SetString (PyExc_ValueError,
161           "error when setting filter to C-weighting");
162     } else {
163       // change the RuntimeError into ValueError
164       PyObject *type, *value, *traceback;
165       PyErr_Fetch(&type, &value, &traceback);
166       Py_XDECREF(type);
167       type = PyExc_ValueError;
168       Py_XINCREF(type);
169       PyErr_Restore(type, value, traceback);
170     }
171     return NULL;
172   }
173   Py_RETURN_NONE;
174 }
175
176 static PyObject *
177 Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
178 {
179   uint_t err = 0;
180   uint_t samplerate;
181   if (!PyArg_ParseTuple (args, "I", &samplerate)) {
182     return NULL;
183   }
184
185   err = aubio_filter_set_a_weighting (self->o, samplerate);
186   if (err > 0) {
187     if (PyErr_Occurred() == NULL) {
188       PyErr_SetString (PyExc_ValueError,
189           "error when setting filter to A-weighting");
190     } else {
191       // change the RuntimeError into ValueError
192       PyObject *type, *value, *traceback;
193       PyErr_Fetch(&type, &value, &traceback);
194       Py_XDECREF(type);
195       type = PyExc_ValueError;
196       Py_XINCREF(type);
197       PyErr_Restore(type, value, traceback);
198     }
199     return NULL;
200   }
201   Py_RETURN_NONE;
202 }
203
204 static PyObject *
205 Py_filter_set_biquad(Py_filter * self, PyObject *args)
206 {
207   uint_t err = 0;
208   lsmp_t b0, b1, b2, a1, a2;
209   if (!PyArg_ParseTuple (args, "ddddd", &b0, &b1, &b2, &a1, &a2)) {
210     return NULL;
211   }
212
213   err = aubio_filter_set_biquad (self->o, b0, b1, b2, a1, a2);
214   if (err > 0) {
215     if (PyErr_Occurred() == NULL) {
216       PyErr_SetString (PyExc_ValueError,
217           "error when setting filter with biquad coefficients");
218     } else {
219       // change the RuntimeError into ValueError
220       PyObject *type, *value, *traceback;
221       PyErr_Fetch(&type, &value, &traceback);
222       Py_XDECREF(type);
223       type = PyExc_ValueError;
224       Py_XINCREF(type);
225       PyErr_Restore(type, value, traceback);
226     }
227     return NULL;
228   }
229   Py_RETURN_NONE;
230 }
231
232 static PyMemberDef Py_filter_members[] = {
233   // TODO remove READONLY flag and define getter/setter
234   {"order", T_INT, offsetof (Py_filter, order), READONLY,
235       "order of the filter"},
236   {NULL}                        /* Sentinel */
237 };
238
239 static PyMethodDef Py_filter_methods[] = {
240   {"set_c_weighting", (PyCFunction) Py_filter_set_c_weighting, METH_VARARGS,
241       Py_filter_set_c_weighting_doc},
242   {"set_a_weighting", (PyCFunction) Py_filter_set_a_weighting, METH_VARARGS,
243       Py_filter_set_a_weighting_doc},
244   {"set_biquad", (PyCFunction) Py_filter_set_biquad, METH_VARARGS,
245       Py_filter_set_biquad_doc},
246   {NULL}
247 };
248
249 PyTypeObject Py_filterType = {
250   PyVarObject_HEAD_INIT(NULL, 0)
251   "aubio.digital_filter",       /* tp_name           */
252   sizeof (Py_filter),           /* tp_basicsize      */
253   0,                            /* tp_itemsize       */
254   (destructor) Py_filter_del,   /* tp_dealloc        */
255   0,                            /* tp_print          */
256   0,                            /* tp_getattr        */
257   0,                            /* tp_setattr        */
258   0,                            /* tp_compare        */
259   0, //(reprfunc) Py_filter_repr,    /* tp_repr           */
260   0,                            /* tp_as_number      */
261   0,                            /* tp_as_sequence    */
262   0,                            /* tp_as_mapping     */
263   0,                            /* tp_hash           */
264   (ternaryfunc)Py_filter_do,    /* tp_call           */
265   0,                            /* tp_str            */
266   0,                            /* tp_getattro       */
267   0,                            /* tp_setattro       */
268   0,                            /* tp_as_buffer      */
269   Py_TPFLAGS_DEFAULT,           /* tp_flags          */
270   Py_filter_doc,                /* tp_doc            */
271   0,                            /* tp_traverse       */
272   0,                            /* tp_clear          */
273   0,                            /* tp_richcompare    */
274   0,                            /* tp_weaklistoffset */
275   0,                            /* tp_iter           */
276   0,                            /* tp_iternext       */
277   Py_filter_methods,            /* tp_methods        */
278   Py_filter_members,            /* tp_members        */
279   0,                            /* tp_getset         */
280   0,                            /* tp_base           */
281   0,                            /* tp_dict           */
282   0,                            /* tp_descr_get      */
283   0,                            /* tp_descr_set      */
284   0,                            /* tp_dictoffset     */
285   (initproc) Py_filter_init,    /* tp_init           */
286   0,                            /* tp_alloc          */
287   Py_filter_new,                /* tp_new            */
288   0,
289   0,
290   0,
291   0,
292   0,
293   0,
294   0,
295   0,
296   0,
297 };