Changeset ae6e15c


Ignore:
Timestamp:
Sep 30, 2009, 5:42:13 PM (10 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
feature/autosink, feature/constantq, feature/pitchshift, feature/pydocstrings, feature/timestretch, master, pitchshift, sampler, timestretch, yinfft+
Children:
7ac818f
Parents:
7de4de0
Message:

interfaces/python: improve draft wrapper alpha_norm example, add some unit tests

Location:
interfaces/python
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • interfaces/python/aubiomodule.c

    r7de4de0 rae6e15c  
    11#include <Python.h>
    2 #include <structmember.h>
     2#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
    33#include <numpy/arrayobject.h>
    4 #include <aubio.h>
    54
    6 static char aubio_module_doc[] = "Python module for the aubio library";
     5#include "aubio-types.h"
    76
    8 /* fvec type definition
    9 
    10 class fvec():
    11     def __init__(self, length = 1024, channels = 1):
    12         self.length = length
    13         self.channels = channels
    14         self.data = array(length, channels)
    15 
    16 */
    17 
    18 #define Py_fvec_default_length   1024
    19 #define Py_fvec_default_channels 1
    20 
    21 static char Py_fvec_doc[] = "fvec object";
    22 
    23 typedef struct
    24 {
    25   PyObject_HEAD fvec_t * o;
    26   uint_t length;
    27   uint_t channels;
    28 } Py_fvec;
    29 
    30 static PyObject *
    31 Py_fvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
    32 {
    33   int length = 0, channels = 0;
    34   Py_fvec *self;
    35   static char *kwlist[] = { "length", "channels", NULL };
    36 
    37   if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
    38           &length, &channels)) {
    39     return NULL;
    40   }
    41 
    42 
    43   self = (Py_fvec *) type->tp_alloc (type, 0);
    44 
    45   self->length = Py_fvec_default_length;
    46   self->channels = Py_fvec_default_channels;
    47 
    48   if (self == NULL) {
    49     return NULL;
    50   }
    51 
    52   if (length > 0) {
    53     self->length = length;
    54   } else if (length < 0) {
    55     PyErr_SetString (PyExc_ValueError,
    56         "can not use negative number of elements");
    57     return NULL;
    58   }
    59 
    60   if (channels > 0) {
    61     self->channels = channels;
    62   } else if (channels < 0) {
    63     PyErr_SetString (PyExc_ValueError,
    64         "can not use negative number of channels");
    65     return NULL;
    66   }
    67 
    68 
    69   return (PyObject *) self;
    70 }
    71 
    72 static int
    73 Py_fvec_init (Py_fvec * self, PyObject * args, PyObject * kwds)
    74 {
    75   self->o = new_fvec (self->length, self->channels);
    76   if (self->o == NULL) {
    77     return -1;
    78   }
    79 
    80   return 0;
    81 }
    82 
    83 static void
    84 Py_fvec_del (Py_fvec * self)
    85 {
    86   del_fvec (self->o);
    87   self->ob_type->tp_free ((PyObject *) self);
    88 }
    89 
    90 static PyObject *
    91 Py_fvec_repr (Py_fvec * self, PyObject * unused)
    92 {
    93   PyObject *format = NULL;
    94   PyObject *args = NULL;
    95   PyObject *result = NULL;
    96 
    97   format = PyString_FromString ("aubio fvec of %d elements with %d channels");
    98   if (format == NULL) {
    99     goto fail;
    100   }
    101 
    102   args = Py_BuildValue ("II", self->length, self->channels);
    103   if (args == NULL) {
    104     goto fail;
    105   }
    106 
    107   result = PyString_Format (format, args);
    108 
    109 fail:
    110   Py_XDECREF (format);
    111   Py_XDECREF (args);
    112 
    113   return result;
    114 }
    115 
    116 static PyObject *
    117 Py_fvec_print (Py_fvec * self, PyObject * unused)
    118 {
    119   fvec_print (self->o);
    120   return Py_None;
    121 }
    122 
    123 static PyObject *
    124 Py_fvec_array (Py_fvec * self)
    125 {
    126   PyObject *array = NULL;
    127   if (self->channels == 1) {
    128     npy_intp dims[] = { self->length, 1 };
    129     array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->data[0]);
    130   } else {
    131     uint_t i;
    132     npy_intp dims[] = { self->length, 1 };
    133     PyObject *concat = PyList_New (0), *tmp = NULL;
    134     for (i = 0; i < self->channels; i++) {
    135       tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->data[i]);
    136       PyList_Append (concat, tmp);
    137       Py_DECREF (tmp);
    138     }
    139     array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
    140     Py_DECREF (concat);
    141   }
    142   return array;
    143 }
    144 
    145 static Py_ssize_t
    146 Py_fvec_getchannels (Py_fvec * self)
    147 {
    148   return self->channels;
    149 }
    150 
    151 static PyObject *
    152 Py_fvec_getitem (Py_fvec * self, Py_ssize_t index)
    153 {
    154   PyObject *array;
    155 
    156   if (index < 0 || index >= self->channels) {
    157     PyErr_SetString (PyExc_IndexError, "no such channel");
    158     return NULL;
    159   }
    160 
    161   npy_intp dims[] = { self->length, 1 };
    162   array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->data[index]);
    163   return array;
    164 }
    165 
    166 static int
    167 Py_fvec_setitem (Py_fvec * self, Py_ssize_t index, PyObject * o)
    168 {
    169   PyObject *array;
    170 
    171   if (index < 0 || index >= self->channels) {
    172     PyErr_SetString (PyExc_IndexError, "no such channel");
    173     return -1;
    174   }
    175 
    176   array = PyArray_FROM_OT (o, NPY_FLOAT);
    177   if (array == NULL) {
    178     PyErr_SetString (PyExc_ValueError, "should be an array of float");
    179     goto fail;
    180   }
    181 
    182   if (PyArray_NDIM (array) != 1) {
    183     PyErr_SetString (PyExc_ValueError, "should be a one-dimensional array");
    184     goto fail;
    185   }
    186 
    187   if (PyArray_SIZE (array) != self->length) {
    188     PyErr_SetString (PyExc_ValueError,
    189         "should be an array of same length as target fvec");
    190     goto fail;
    191   }
    192 
    193   self->o->data[index] = (smpl_t *) PyArray_GETPTR1 (array, 0);
    194 
    195   return 0;
    196 
    197 fail:
    198   return -1;
    199 }
    200 
    201 static PyMemberDef Py_fvec_members[] = {
    202   // TODO remove READONLY flag and define getter/setter
    203   {"length", T_INT, offsetof (Py_fvec, length), READONLY,
    204       "length attribute"},
    205   {"channels", T_INT, offsetof (Py_fvec, channels), READONLY,
    206       "channels attribute"},
    207   {NULL}                        /* Sentinel */
    208 };
    209 
    210 static PyMethodDef Py_fvec_methods[] = {
    211   {"dump", (PyCFunction) Py_fvec_print, METH_NOARGS,
    212       "Dumps the contents of the vector to stdout."},
    213   {"__array__", (PyCFunction) Py_fvec_array, METH_NOARGS,
    214       "Returns the first channel as a numpy array."},
    215   {NULL}
    216 };
    217 
    218 static PySequenceMethods Py_fvec_tp_as_sequence = {
    219   (lenfunc) Py_fvec_getchannels,        /* sq_length         */
    220   0,                            /* sq_concat         */
    221   0,                            /* sq_repeat         */
    222   (ssizeargfunc) Py_fvec_getitem,       /* sq_item           */
    223   0,                            /* sq_slice          */
    224   (ssizeobjargproc) Py_fvec_setitem,    /* sq_ass_item       */
    225   0,                            /* sq_ass_slice      */
    226   0,                            /* sq_contains       */
    227   0,                            /* sq_inplace_concat */
    228   0,                            /* sq_inplace_repeat */
    229 };
    230 
    231 
    232 static PyTypeObject Py_fvecType = {
    233   PyObject_HEAD_INIT (NULL)
    234       0,                        /* ob_size           */
    235   "fvec",                       /* tp_name           */
    236   sizeof (Py_fvec),             /* tp_basicsize      */
    237   0,                            /* tp_itemsize       */
    238   (destructor) Py_fvec_del,     /* tp_dealloc        */
    239   0,                            /* tp_print          */
    240   0,                            /* tp_getattr        */
    241   0,                            /* tp_setattr        */
    242   0,                            /* tp_compare        */
    243   (reprfunc) Py_fvec_repr,      /* tp_repr           */
    244   0,                            /* tp_as_number      */
    245   &Py_fvec_tp_as_sequence,      /* tp_as_sequence    */
    246   0,                            /* tp_as_mapping     */
    247   0,                            /* tp_hash           */
    248   0,                            /* tp_call           */
    249   0,                            /* tp_str            */
    250   0,                            /* tp_getattro       */
    251   0,                            /* tp_setattro       */
    252   0,                            /* tp_as_buffer      */
    253   Py_TPFLAGS_DEFAULT,           /* tp_flags          */
    254   Py_fvec_doc,                  /* tp_doc            */
    255   0,                            /* tp_traverse       */
    256   0,                            /* tp_clear          */
    257   0,                            /* tp_richcompare    */
    258   0,                            /* tp_weaklistoffset */
    259   0,                            /* tp_iter           */
    260   0,                            /* tp_iternext       */
    261   Py_fvec_methods,              /* tp_methods        */
    262   Py_fvec_members,              /* tp_members        */
    263   0,                            /* tp_getset         */
    264   0,                            /* tp_base           */
    265   0,                            /* tp_dict           */
    266   0,                            /* tp_descr_get      */
    267   0,                            /* tp_descr_set      */
    268   0,                            /* tp_dictoffset     */
    269   (initproc) Py_fvec_init,      /* tp_init           */
    270   0,                            /* tp_alloc          */
    271   Py_fvec_new,                  /* tp_new            */
    272 };
    273 
    274 /* end of fvec type definition */
     7static char Py_alpha_norm_doc[] = "compute alpha normalisation factor";
    2758
    2769static PyObject *
    27710Py_alpha_norm (PyObject * self, PyObject * args)
    27811{
     12  PyObject *input;
    27913  Py_fvec *vec;
    28014  smpl_t alpha;
    28115  PyObject *result;
     16  PyObject *array;
     17  uint_t i;
    28218
    283   if (!PyArg_ParseTuple (args, "Of:alpha_norm", &vec, &alpha)) {
     19  if (!PyArg_ParseTuple (args, "Of:alpha_norm", &input, &alpha)) {
    28420    return NULL;
    28521  }
    28622
    287   if (vec == NULL) {
     23  if (input == NULL) {
    28824    return NULL;
    28925  }
    29026
     27  // parsing input object into a Py_fvec
     28  if (PyObject_TypeCheck (input, &Py_fvecType)) {
     29    // input is an fvec, nothing else to do
     30    vec = (Py_fvec *) input;
     31  } else if (PyArray_Check(input)) {
     32
     33    // we got an array, convert it to an fvec
     34    if (PyArray_NDIM (input) == 0) {
     35      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
     36      goto fail;
     37    } else if (PyArray_NDIM (input) > 2) {
     38      PyErr_SetString (PyExc_ValueError, "input array has more than two dimensions");
     39      goto fail;
     40    }
     41
     42    if (!PyArray_ISFLOAT (input)) {
     43      PyErr_SetString (PyExc_ValueError, "input array should be float");
     44      goto fail;
     45    } else if (PyArray_TYPE (input) != NPY_FLOAT) {
     46      // input data type is not float32, casting
     47      array = PyArray_Cast ( (PyArrayObject*) input, NPY_FLOAT);
     48      if (array == NULL) {
     49        PyErr_SetString (PyExc_IndexError, "failed converting to NPY_FLOAT");
     50        goto fail;
     51      }
     52    } else {
     53      // input data type is float32, nothing else to do
     54      array = input;
     55    }
     56
     57    // create a new fvec object
     58    vec = (Py_fvec*) PyObject_New (Py_fvec, &Py_fvecType);
     59    if (PyArray_NDIM (array) == 1) {
     60      vec->channels = 1;
     61      vec->length = PyArray_SIZE (array);
     62    } else {
     63      vec->channels = PyArray_DIM (array, 0);
     64      vec->length = PyArray_DIM (array, 1);
     65    }
     66
     67    // FIXME should not need to allocate fvec
     68    vec->o = new_fvec (vec->length, vec->channels);
     69    for (i = 0; i < vec->channels; i++) {
     70      vec->o->data[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
     71    }
     72
     73  } else {
     74    PyErr_SetString (PyExc_ValueError, "can only accept array or fvec as input");
     75    return NULL;
     76  }
     77
     78  // compute the function
    29179  result = Py_BuildValue ("f", vec_alpha_norm (vec->o, alpha));
    29280  if (result == NULL) {
     
    29684  return result;
    29785
     86fail:
     87    return NULL;
    29888}
    299 
    300 static char Py_alpha_norm_doc[] = "compute alpha normalisation factor";
    30189
    30290static PyMethodDef aubio_methods[] = {
     
    30492  {NULL, NULL}                  /* Sentinel */
    30593};
     94
     95static char aubio_module_doc[] = "Python module for the aubio library";
    30696
    30797PyMODINIT_FUNC
  • interfaces/python/setup.py

    r7de4de0 rae6e15c  
    44      ext_modules = [
    55        Extension("_aubio",
    6             ["aubiomodule.c"],
     6            ["aubiomodule.c", "py-fvec.c"],
    77            include_dirs=['../../build/default/src', '../../src' ],
    88            library_dirs=['../../build/default/src', '../../src/.libs' ],
Note: See TracChangeset for help on using the changeset viewer.