.
[aubio.git] / interfaces / python / py-cvec.c
1 #include "aubio-types.h"
2
3 /* cvec type definition 
4
5 class cvec():
6     def __init__(self, length = 1024, channels = 1):
7         self.length = length 
8         self.channels = channels 
9         self.norm = array(length, channels)
10         self.phas = array(length, channels)
11 */
12
13
14 static char Py_cvec_doc[] = "cvec object";
15
16 static PyObject *
17 Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
18 {
19   int length= 0, channels = 0;
20   Py_cvec *self;
21   static char *kwlist[] = { "length", "channels", NULL };
22
23   if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
24           &length, &channels)) {
25     return NULL;
26   }
27
28
29   self = (Py_cvec *) type->tp_alloc (type, 0);
30
31   self->length = Py_default_vector_length;
32   self->channels = Py_default_vector_channels;
33
34   if (self == NULL) {
35     return NULL;
36   }
37
38   if (length > 0) {
39     self->length = length;
40   } else if (length < 0) {
41     PyErr_SetString (PyExc_ValueError,
42         "can not use negative number of elements");
43     return NULL;
44   }
45
46   if (channels > 0) {
47     self->channels = channels;
48   } else if (channels < 0) {
49     PyErr_SetString (PyExc_ValueError,
50         "can not use negative number of channels");
51     return NULL;
52   }
53
54   return (PyObject *) self;
55 }
56
57 static int
58 Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
59 {
60   self->o = new_cvec (self->length, self->channels);
61   if (self->o == NULL) {
62     return -1;
63   }
64
65   return 0;
66 }
67
68 static void
69 Py_cvec_del (Py_cvec * self)
70 {
71   del_cvec (self->o);
72   self->ob_type->tp_free ((PyObject *) self);
73 }
74
75 static PyObject *
76 Py_cvec_repr (Py_cvec * self, PyObject * unused)
77 {
78   PyObject *format = NULL;
79   PyObject *args = NULL;
80   PyObject *result = NULL;
81
82   format = PyString_FromString ("aubio cvec of %d elements with %d channels");
83   if (format == NULL) {
84     goto fail;
85   }
86
87   args = Py_BuildValue ("II", self->length, self->channels);
88   if (args == NULL) {
89     goto fail;
90   }
91   //cvec_print ( self->o );
92
93   result = PyString_Format (format, args);
94
95 fail:
96   Py_XDECREF (format);
97   Py_XDECREF (args);
98
99   return result;
100 }
101
102 Py_cvec *
103 PyAubio_ArrayToCvec (PyObject *input) {
104   PyObject *array;
105   Py_cvec *vec;
106   uint_t i;
107   // parsing input object into a Py_cvec
108   if (PyObject_TypeCheck (input, &Py_cvecType)) {
109     // input is an cvec, nothing else to do
110     vec = (Py_cvec *) input;
111   } else if (PyArray_Check(input)) {
112
113     // we got an array, convert it to an cvec 
114     if (PyArray_NDIM (input) == 0) {
115       PyErr_SetString (PyExc_ValueError, "input array is a scalar");
116       goto fail;
117     } else if (PyArray_NDIM (input) > 2) {
118       PyErr_SetString (PyExc_ValueError,
119           "input array has more than two dimensions");
120       goto fail;
121     }
122
123     if (!PyArray_ISFLOAT (input)) {
124       PyErr_SetString (PyExc_ValueError, "input array should be float");
125       goto fail;
126 #if AUBIO_DO_CASTING
127     } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
128       // input data type is not float32, casting 
129       array = PyArray_Cast ( (PyArrayObject*) input, AUBIO_NPY_SMPL);
130       if (array == NULL) {
131         PyErr_SetString (PyExc_IndexError, "failed converting to NPY_FLOAT");
132         goto fail;
133       }
134 #else
135     } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
136       PyErr_SetString (PyExc_ValueError, "input array should be float32");
137       goto fail;
138 #endif
139     } else {
140       // input data type is float32, nothing else to do
141       array = input;
142     }
143
144     // create a new cvec object
145     vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); 
146     if (PyArray_NDIM (array) == 1) {
147       PyErr_SetString (PyExc_ValueError,
148           "input array should be have at least two rows for norm and phas");
149       goto fail;
150     } else if (PyArray_NDIM (array) == 2) {
151       vec->channels = 1;
152       vec->length = PyArray_SIZE (array);
153     } else {
154       vec->channels = PyArray_DIM (array, 0) / 2;
155       vec->length = PyArray_DIM (array, 1);
156     }
157
158     // no need to really allocate cvec, just its struct member 
159     // vec->o = new_cvec (vec->length, vec->channels);
160     vec->o = (cvec_t *)malloc(sizeof(cvec_t));
161     vec->o->length = vec->length; vec->o->channels = vec->channels;
162     vec->o->norm = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
163     vec->o->phas = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
164     // hat data[i] point to array line
165     for (i = 0; i < vec->channels; i+=2) {
166       vec->o->norm[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
167       vec->o->phas[i] = (smpl_t *) PyArray_GETPTR1 (array, i+1);
168     }
169
170   } else {
171     PyErr_SetString (PyExc_ValueError, "can only accept array or cvec as input");
172     return NULL;
173   }
174
175   return vec;
176
177 fail:
178   return NULL;
179 }
180
181 PyObject *
182 PyAubio_CvecToArray (Py_cvec * self)
183 {
184   PyObject *array = NULL;
185   uint_t i;
186   npy_intp dims[] = { self->o->length, 1 };
187   PyObject *concat = PyList_New (0), *tmp = NULL;
188   for (i = 0; i < self->channels; i++) {
189     tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[i]);
190     PyList_Append (concat, tmp);
191     Py_DECREF (tmp);
192     tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas[i]);
193     PyList_Append (concat, tmp);
194     Py_DECREF (tmp);
195   }
196   array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
197   Py_DECREF (concat);
198   return array;
199 }
200
201 PyObject *
202 PyAubio_CvecNormToArray (Py_cvec * self)
203 {
204   PyObject *array = NULL;
205   uint_t i;
206   npy_intp dims[] = { self->o->length, 1 };
207   PyObject *concat = PyList_New (0), *tmp = NULL;
208   for (i = 0; i < self->channels; i++) {
209     tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[i]);
210     PyList_Append (concat, tmp);
211     Py_DECREF (tmp);
212   }
213   array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
214   Py_DECREF (concat);
215   return array;
216 }
217
218 PyObject *
219 PyAubio_ArrayToCvecNorm (PyObject * self)
220 {
221   return NULL;
222 }
223
224 PyObject *
225 PyAubio_CvecPhasToArray (Py_cvec * self)
226 {
227   PyObject *array = NULL;
228   uint_t i;
229   npy_intp dims[] = { self->o->length, 1 };
230   PyObject *concat = PyList_New (0), *tmp = NULL;
231   for (i = 0; i < self->channels; i++) {
232     tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas[i]);
233     PyList_Append (concat, tmp);
234     Py_DECREF (tmp);
235   }
236   array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
237   Py_DECREF (concat);
238   return array;
239 }
240
241 PyObject *
242 PyAubio_ArrayToCvecPhas (PyObject * self)
243 {
244   return NULL;
245 }
246
247 PyObject *
248 Py_cvec_get_norm (Py_cvec * self, void *closure)
249 {
250   return PyAubio_CvecNormToArray(self);
251 }
252
253 PyObject *
254 Py_cvec_get_phas (Py_cvec * self, void *closure)
255 {
256   return PyAubio_CvecPhasToArray(self);
257 }
258
259 static int
260 Py_cvec_set_norm (Py_cvec * self, PyObject *value, void * closure)
261 {
262   return 0;
263 }
264
265 static int
266 Py_cvec_set_phas (Py_cvec * self, PyObject *value, void * closure)
267 {
268   return 0;
269 }
270
271 static Py_ssize_t
272 Py_cvec_getchannels (Py_cvec * self)
273 {
274   return self->channels;
275 }
276
277 static PyObject *
278 Py_cvec_getitem (Py_cvec * self, Py_ssize_t index)
279 {
280   PyObject *array;
281
282   if (index < 0 || index >= self->channels) {
283     PyErr_SetString (PyExc_IndexError, "no such channel");
284     return NULL;
285   }
286
287   npy_intp dims[] = { self->length, 1 };
288   array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[index]);
289   return array;
290 }
291
292 static int
293 Py_cvec_setitem (Py_cvec * self, Py_ssize_t index, PyObject * o)
294 {
295   PyObject *array;
296
297   if (index < 0 || index >= self->channels) {
298     PyErr_SetString (PyExc_IndexError, "no such channel");
299     return -1;
300   }
301
302   array = PyArray_FROM_OT (o, NPY_FLOAT);
303   if (array == NULL) {
304     PyErr_SetString (PyExc_ValueError, "should be an array of float");
305     goto fail;
306   }
307
308   if (PyArray_NDIM (array) != 1) {
309     PyErr_SetString (PyExc_ValueError, "should be a one-dimensional array");
310     goto fail;
311   }
312
313   if (PyArray_SIZE (array) != self->length) {
314     PyErr_SetString (PyExc_ValueError,
315         "should be an array of same length as target cvec");
316     goto fail;
317   }
318
319   self->o->norm[index] = (smpl_t *) PyArray_GETPTR1 (array, 0);
320
321   return 0;
322
323 fail:
324   return -1;
325 }
326
327 static PyMemberDef Py_cvec_members[] = {
328   // TODO remove READONLY flag and define getter/setter
329   {"length", T_INT, offsetof (Py_cvec, length), READONLY,
330       "length attribute"},
331   {"channels", T_INT, offsetof (Py_cvec, channels), READONLY,
332       "channels attribute"},
333   {NULL}                        /* Sentinel */
334 };
335
336 static PyMethodDef Py_cvec_methods[] = {
337   {"__array__", (PyCFunction) PyAubio_CvecToArray, METH_NOARGS,
338       "Returns the content of this cvec as a numpy array"},
339 /*
340   {"norm", (PyCFunction) PyAubio_CvecNormToArray, METH_NOARGS,
341       "Returns the content of the magnitude of this cvec as a numpy array."},
342   {"phas", (PyCFunction) PyAubio_CvecPhasToArray, METH_NOARGS,
343       "Returns the content of the phase of this cvec as a numpy array."},
344 */
345   {NULL}
346 };
347
348 static PyGetSetDef Py_cvec_getseters[] = {
349   {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
350       "Content of the magnitude of this cvec",
351       NULL},
352   {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
353       "Content of the magnitude of this cvec",
354       NULL},
355   {NULL} /* sentinel */
356 };
357
358 static PySequenceMethods Py_cvec_tp_as_sequence = {
359   (lenfunc) Py_cvec_getchannels,        /* sq_length         */
360   0,                                    /* sq_concat         */
361   0,                                    /* sq_repeat         */
362   (ssizeargfunc) Py_cvec_getitem,       /* sq_item           */
363   0,                                    /* sq_slice          */
364   (ssizeobjargproc) Py_cvec_setitem,    /* sq_ass_item       */
365   0,                                    /* sq_ass_slice      */
366   0,                                    /* sq_contains       */
367   0,                                    /* sq_inplace_concat */
368   0,                                    /* sq_inplace_repeat */
369 };
370
371
372 PyTypeObject Py_cvecType = {
373   PyObject_HEAD_INIT (NULL)
374   0,                            /* ob_size           */
375   "aubio.cvec",                 /* tp_name           */
376   sizeof (Py_cvec),             /* tp_basicsize      */
377   0,                            /* tp_itemsize       */
378   (destructor) Py_cvec_del,     /* tp_dealloc        */
379   0,                            /* tp_print          */
380   0,                            /* tp_getattr        */
381   0,                            /* tp_setattr        */
382   0,                            /* tp_compare        */
383   (reprfunc) Py_cvec_repr,      /* tp_repr           */
384   0,                            /* tp_as_number      */
385   &Py_cvec_tp_as_sequence,      /* tp_as_sequence    */
386   0,                            /* tp_as_mapping     */
387   0,                            /* tp_hash           */
388   0,                            /* tp_call           */
389   0,                            /* tp_str            */
390   0,                            /* tp_getattro       */
391   0,                            /* tp_setattro       */
392   0,                            /* tp_as_buffer      */
393   Py_TPFLAGS_DEFAULT,           /* tp_flags          */
394   Py_cvec_doc,                  /* tp_doc            */
395   0,                            /* tp_traverse       */
396   0,                            /* tp_clear          */
397   0,                            /* tp_richcompare    */
398   0,                            /* tp_weaklistoffset */
399   0,                            /* tp_iter           */
400   0,                            /* tp_iternext       */
401   Py_cvec_methods,              /* tp_methods        */
402   Py_cvec_members,              /* tp_members        */
403   Py_cvec_getseters,            /* tp_getset         */
404   0,                            /* tp_base           */
405   0,                            /* tp_dict           */
406   0,                            /* tp_descr_get      */
407   0,                            /* tp_descr_set      */
408   0,                            /* tp_dictoffset     */
409   (initproc) Py_cvec_init,      /* tp_init           */
410   0,                            /* tp_alloc          */
411   Py_cvec_new,                  /* tp_new            */
412 };