shithub: aubio

ref: 992beaa9bea5d3cd1aae961f80f581d2003bcc79
dir: /interfaces/python/py-cvec.c/

View raw version
#include "aubio-types.h"

/* cvec type definition 

class cvec():
    def __init__(self, length = 1024, channels = 1):
        self.length = length 
        self.channels = channels 
        self.norm = array(length, channels)
        self.phas = array(length, channels)
*/


static char Py_cvec_doc[] = "cvec object";

static PyObject *
Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
{
  int length= 0, channels = 0;
  Py_cvec *self;
  static char *kwlist[] = { "length", "channels", NULL };

  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
          &length, &channels)) {
    return NULL;
  }


  self = (Py_cvec *) type->tp_alloc (type, 0);

  self->length = Py_default_vector_length;
  self->channels = Py_default_vector_channels;

  if (self == NULL) {
    return NULL;
  }

  if (length > 0) {
    self->length = length;
  } else if (length < 0) {
    PyErr_SetString (PyExc_ValueError,
        "can not use negative number of elements");
    return NULL;
  }

  if (channels > 0) {
    self->channels = channels;
  } else if (channels < 0) {
    PyErr_SetString (PyExc_ValueError,
        "can not use negative number of channels");
    return NULL;
  }

  return (PyObject *) self;
}

static int
Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
{
  self->o = new_cvec (self->length, self->channels);
  if (self->o == NULL) {
    return -1;
  }

  return 0;
}

static void
Py_cvec_del (Py_cvec * self)
{
  del_cvec (self->o);
  self->ob_type->tp_free ((PyObject *) self);
}

static PyObject *
Py_cvec_repr (Py_cvec * self, PyObject * unused)
{
  PyObject *format = NULL;
  PyObject *args = NULL;
  PyObject *result = NULL;

  format = PyString_FromString ("aubio cvec of %d elements with %d channels");
  if (format == NULL) {
    goto fail;
  }

  args = Py_BuildValue ("II", self->length, self->channels);
  if (args == NULL) {
    goto fail;
  }
  //cvec_print ( self->o );

  result = PyString_Format (format, args);

fail:
  Py_XDECREF (format);
  Py_XDECREF (args);

  return result;
}

Py_cvec *
PyAubio_ArrayToCvec (PyObject *input) {
  PyObject *array;
  Py_cvec *vec;
  uint_t i;
  // parsing input object into a Py_cvec
  if (PyObject_TypeCheck (input, &Py_cvecType)) {
    // input is an cvec, nothing else to do
    vec = (Py_cvec *) input;
  } else if (PyArray_Check(input)) {

    // we got an array, convert it to an cvec 
    if (PyArray_NDIM (input) == 0) {
      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
      goto fail;
    } else if (PyArray_NDIM (input) > 2) {
      PyErr_SetString (PyExc_ValueError,
          "input array has more than two dimensions");
      goto fail;
    }

    if (!PyArray_ISFLOAT (input)) {
      PyErr_SetString (PyExc_ValueError, "input array should be float");
      goto fail;
#if AUBIO_DO_CASTING
    } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
      // input data type is not float32, casting 
      array = PyArray_Cast ( (PyArrayObject*) input, AUBIO_NPY_SMPL);
      if (array == NULL) {
        PyErr_SetString (PyExc_IndexError, "failed converting to NPY_FLOAT");
        goto fail;
      }
#else
    } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
      PyErr_SetString (PyExc_ValueError, "input array should be float32");
      goto fail;
#endif
    } else {
      // input data type is float32, nothing else to do
      array = input;
    }

    // create a new cvec object
    vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); 
    if (PyArray_NDIM (array) == 1) {
      PyErr_SetString (PyExc_ValueError,
          "input array should be have at least two rows for norm and phas");
      goto fail;
    } else if (PyArray_NDIM (array) == 2) {
      vec->channels = 1;
      vec->length = PyArray_SIZE (array);
    } else {
      vec->channels = PyArray_DIM (array, 0) / 2;
      vec->length = PyArray_DIM (array, 1);
    }

    // no need to really allocate cvec, just its struct member 
    // vec->o = new_cvec (vec->length, vec->channels);
    vec->o = (cvec_t *)malloc(sizeof(cvec_t));
    vec->o->length = vec->length; vec->o->channels = vec->channels;
    vec->o->norm = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
    vec->o->phas = (smpl_t**)malloc(vec->o->channels * sizeof(smpl_t*));
    // hat data[i] point to array line
    for (i = 0; i < vec->channels; i+=2) {
      vec->o->norm[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
      vec->o->phas[i] = (smpl_t *) PyArray_GETPTR1 (array, i+1);
    }

  } else {
    PyErr_SetString (PyExc_ValueError, "can only accept array or cvec as input");
    return NULL;
  }

  return vec;

fail:
  return NULL;
}

PyObject *
PyAubio_CvecToArray (Py_cvec * self)
{
  PyObject *array = NULL;
  uint_t i;
  npy_intp dims[] = { self->o->length, 1 };
  PyObject *concat = PyList_New (0), *tmp = NULL;
  for (i = 0; i < self->channels; i++) {
    tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[i]);
    PyList_Append (concat, tmp);
    Py_DECREF (tmp);
    tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas[i]);
    PyList_Append (concat, tmp);
    Py_DECREF (tmp);
  }
  array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
  Py_DECREF (concat);
  return array;
}

PyObject *
PyAubio_CvecNormToArray (Py_cvec * self)
{
  PyObject *array = NULL;
  uint_t i;
  npy_intp dims[] = { self->o->length, 1 };
  PyObject *concat = PyList_New (0), *tmp = NULL;
  for (i = 0; i < self->channels; i++) {
    tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[i]);
    PyList_Append (concat, tmp);
    Py_DECREF (tmp);
  }
  array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
  Py_DECREF (concat);
  return array;
}


PyObject *
PyAubio_CvecPhasToArray (Py_cvec * self)
{
  PyObject *array = NULL;
  uint_t i;
  npy_intp dims[] = { self->o->length, 1 };
  PyObject *concat = PyList_New (0), *tmp = NULL;
  for (i = 0; i < self->channels; i++) {
    tmp = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas[i]);
    PyList_Append (concat, tmp);
    Py_DECREF (tmp);
  }
  array = PyArray_FromObject (concat, NPY_FLOAT, 2, 2);
  Py_DECREF (concat);
  return array;
}

PyObject *
PyAubio_ArrayToCvecPhas (PyObject * self)
{
  return NULL;
}

PyObject *
Py_cvec_get_norm (Py_cvec * self, void *closure)
{
  return PyAubio_CvecNormToArray(self);
}

PyObject *
Py_cvec_get_phas (Py_cvec * self, void *closure)
{
  return PyAubio_CvecPhasToArray(self);
}

static int
Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
{
  uint_t i;
  PyObject * array;
  if (input == NULL) {
    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
    goto fail;
  }
  if (PyArray_Check(input)) {

    // we got an array, convert it to a cvec.norm 
    if (PyArray_NDIM (input) == 0) {
      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
      goto fail;
    } else if (PyArray_NDIM (input) > 2) {
      PyErr_SetString (PyExc_ValueError,
          "input array has more than two dimensions");
      goto fail;
    }

    if (!PyArray_ISFLOAT (input)) {
      PyErr_SetString (PyExc_ValueError, "input array should be float");
      goto fail;
    } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
      PyErr_SetString (PyExc_ValueError, "input array should be float32");
      goto fail;
    }
    array = input;

    // check input array dimensions
    if (PyArray_NDIM (array) == 1) {
      if (vec->channels != 1) {
          PyErr_SetString (PyExc_ValueError,
                  "input array should have more than one channel");
          goto fail;
      }
      if (vec->o->length != PyArray_SIZE (array)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has length %d, but cvec has length %d",
                  PyArray_SIZE (array), vec->o->length);
          goto fail;
      }
    } else {
      if (vec->channels != PyArray_DIM (array, 0)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has %d channels, but vector has %d channels",
                  PyArray_DIM (array, 0), vec->channels);
          goto fail;
      }
      if (vec->o->length != PyArray_DIM (array, 1)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has length %d, but vector has length %d",
                  PyArray_DIM (array, 1), vec->o->length);
          goto fail;
      }
    }

    for (i = 0; i < vec->channels; i++) {
      vec->o->norm[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
    }

  } else {
    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
    return 1;
  }

  Py_INCREF(array);
  return 0;

fail:
  return 1;
}

static int
Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
{
  uint_t i;
  PyObject * array;
  if (input == NULL) {
    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
    goto fail;
  }
  if (PyArray_Check(input)) {

    // we got an array, convert it to a cvec.phas
    if (PyArray_NDIM (input) == 0) {
      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
      goto fail;
    } else if (PyArray_NDIM (input) > 2) {
      PyErr_SetString (PyExc_ValueError,
          "input array has more than two dimensions");
      goto fail;
    }

    if (!PyArray_ISFLOAT (input)) {
      PyErr_SetString (PyExc_ValueError, "input array should be float");
      goto fail;
    } else if (PyArray_TYPE (input) != AUBIO_NPY_SMPL) {
      PyErr_SetString (PyExc_ValueError, "input array should be float32");
      goto fail;
    }
    array = input;

    // check input array dimensions
    if (PyArray_NDIM (array) == 1) {
      if (vec->channels != 1) {
          PyErr_SetString (PyExc_ValueError,
                  "input array should have more than one channel");
          goto fail;
      }
      if (vec->o->length != PyArray_SIZE (array)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has length %d, but cvec has length %d",
                  PyArray_SIZE (array), vec->o->length);
          goto fail;
      }
    } else {
      if (vec->channels != PyArray_DIM (array, 0)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has %d channels, but vector has %d channels",
                  PyArray_DIM (array, 0), vec->channels);
          goto fail;
      }
      if (vec->o->length != PyArray_DIM (array, 1)) {
          PyErr_Format (PyExc_ValueError,
                  "input array has length %d, but vector has length %d",
                  PyArray_DIM (array, 1), vec->o->length);
          goto fail;
      }
    }

    for (i = 0; i < vec->channels; i++) {
      vec->o->phas[i] = (smpl_t *) PyArray_GETPTR1 (array, i);
    }

  } else {
    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
    return 1;
  }

  Py_INCREF(array);
  return 0;

fail:
  return 1;
}

static Py_ssize_t
Py_cvec_getchannels (Py_cvec * self)
{
  return self->channels;
}

static PyObject *
Py_cvec_getitem (Py_cvec * self, Py_ssize_t index)
{
  PyObject *array;

  if (index < 0 || index >= self->channels) {
    PyErr_SetString (PyExc_IndexError, "no such channel");
    return NULL;
  }

  npy_intp dims[] = { self->length, 1 };
  array = PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm[index]);
  return array;
}

static int
Py_cvec_setitem (Py_cvec * self, Py_ssize_t index, PyObject * o)
{
  PyObject *array;

  if (index < 0 || index >= self->channels) {
    PyErr_SetString (PyExc_IndexError, "no such channel");
    return -1;
  }

  array = PyArray_FROM_OT (o, NPY_FLOAT);
  if (array == NULL) {
    PyErr_SetString (PyExc_ValueError, "should be an array of float");
    goto fail;
  }

  if (PyArray_NDIM (array) != 1) {
    PyErr_SetString (PyExc_ValueError, "should be a one-dimensional array");
    goto fail;
  }

  if (PyArray_SIZE (array) != self->length) {
    PyErr_SetString (PyExc_ValueError,
        "should be an array of same length as target cvec");
    goto fail;
  }

  self->o->norm[index] = (smpl_t *) PyArray_GETPTR1 (array, 0);

  return 0;

fail:
  return -1;
}

static PyMemberDef Py_cvec_members[] = {
  // TODO remove READONLY flag and define getter/setter
  {"length", T_INT, offsetof (Py_cvec, length), READONLY,
      "length attribute"},
  {"channels", T_INT, offsetof (Py_cvec, channels), READONLY,
      "channels attribute"},
  {NULL}                        /* Sentinel */
};

static PyMethodDef Py_cvec_methods[] = {
  {"__array__", (PyCFunction) PyAubio_CvecToArray, METH_NOARGS,
      "Returns the content of this cvec as a numpy array"},
  {NULL}
};

static PyGetSetDef Py_cvec_getseters[] = {
  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
      "Content of the magnitude of this cvec",
      NULL},
  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
      "Content of the magnitude of this cvec",
      NULL},
  {NULL} /* sentinel */
};

static PySequenceMethods Py_cvec_tp_as_sequence = {
  (lenfunc) Py_cvec_getchannels,        /* sq_length         */
  0,                                    /* sq_concat         */
  0,                                    /* sq_repeat         */
  (ssizeargfunc) Py_cvec_getitem,       /* sq_item           */
  0,                                    /* sq_slice          */
  (ssizeobjargproc) Py_cvec_setitem,    /* sq_ass_item       */
  0,                                    /* sq_ass_slice      */
  0,                                    /* sq_contains       */
  0,                                    /* sq_inplace_concat */
  0,                                    /* sq_inplace_repeat */
};


PyTypeObject Py_cvecType = {
  PyObject_HEAD_INIT (NULL)
  0,                            /* ob_size           */
  "aubio.cvec",                 /* tp_name           */
  sizeof (Py_cvec),             /* tp_basicsize      */
  0,                            /* tp_itemsize       */
  (destructor) Py_cvec_del,     /* tp_dealloc        */
  0,                            /* tp_print          */
  0,                            /* tp_getattr        */
  0,                            /* tp_setattr        */
  0,                            /* tp_compare        */
  (reprfunc) Py_cvec_repr,      /* tp_repr           */
  0,                            /* tp_as_number      */
  &Py_cvec_tp_as_sequence,      /* tp_as_sequence    */
  0,                            /* tp_as_mapping     */
  0,                            /* tp_hash           */
  0,                            /* tp_call           */
  0,                            /* tp_str            */
  0,                            /* tp_getattro       */
  0,                            /* tp_setattro       */
  0,                            /* tp_as_buffer      */
  Py_TPFLAGS_DEFAULT,           /* tp_flags          */
  Py_cvec_doc,                  /* tp_doc            */
  0,                            /* tp_traverse       */
  0,                            /* tp_clear          */
  0,                            /* tp_richcompare    */
  0,                            /* tp_weaklistoffset */
  0,                            /* tp_iter           */
  0,                            /* tp_iternext       */
  Py_cvec_methods,              /* tp_methods        */
  Py_cvec_members,              /* tp_members        */
  Py_cvec_getseters,            /* tp_getset         */
  0,                            /* tp_base           */
  0,                            /* tp_dict           */
  0,                            /* tp_descr_get      */
  0,                            /* tp_descr_set      */
  0,                            /* tp_dictoffset     */
  (initproc) Py_cvec_init,      /* tp_init           */
  0,                            /* tp_alloc          */
  Py_cvec_new,                  /* tp_new            */
};