Index: python/README.md
===================================================================
--- python/README.md	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/README.md	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,24 @@
+Python aubio module
+===================
+
+This module wraps the aubio library for python using the numpy module.
+
+See the [Python/C API Reference
+Manual] (http://docs.python.org/c-api/index.html) and the [Numpy/C API
+Reference](http://docs.scipy.org/doc/numpy/reference/c-api.html)
+
+Compiling python aubio on Mac OS X
+----------------------------------
+
+You should now be able to build the aubio python module out of the box on a
+recent version of OS X (10.8.x). Make sure the variables are correct in the
+file `build_osx` before running it:
+
+    $ ./build_osx
+
+Additionally, you can fetch tools such [matplotlib](http://matplotlib.org/) to
+use the demo scripts. One easy way to do it is to fetch the fully fledged
+[Scipy superpack](http://fonnesbeck.github.com/ScipySuperpack/)
+
+    $ curl -O https://raw.github.com/fonnesbeck/ScipySuperpack/master/install_superpack.sh
+    $ sh install_superpack.sh
Index: python/a_weighting_test_simple.expected
===================================================================
--- python/a_weighting_test_simple.expected	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/a_weighting_test_simple.expected	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,2 @@
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 5.00000000e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.27870563e-01 2.58244342e-01 1.18719361e-01 -4.02623805e-02 -5.61812129e-02 -5.24739734e-02 -4.72329276e-02 -4.23394349e-02 -3.79219586e-02 -3.39473148e-02 -3.03724479e-02 -2.71574847e-02 -2.42664433e-02 -2.16669285e-02 -1.93297810e-02 -1.72287543e-02 -1.53402241e-02 -1.36429261e-02 -1.21177207e-02 -1.07473802e-02
Index: python/aubio-types.h
===================================================================
--- python/aubio-types.h	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubio-types.h	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,49 @@
+#include <Python.h>
+#include <structmember.h>
+#define NO_IMPORT_ARRAY
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include <numpy/arrayobject.h>
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+
+#define Py_default_vector_length 1024
+#define Py_default_vector_height 1
+
+#define Py_aubio_default_samplerate 44100
+
+#if HAVE_AUBIO_DOUBLE
+#error "Ouch! Python interface for aubio has not been much tested yet."
+#define AUBIO_NPY_SMPL NPY_DOUBLE
+#else
+#define AUBIO_NPY_SMPL NPY_FLOAT
+#endif
+
+// special python type for cvec
+typedef struct
+{
+  PyObject_HEAD
+  cvec_t * o;
+  uint_t length;
+  uint_t channels;
+} Py_cvec;
+extern PyTypeObject Py_cvecType;
+
+// defined in aubio-proxy.c
+extern PyObject *PyAubio_CFvecToArray (fvec_t * self);
+extern fvec_t *PyAubio_ArrayToCFvec (PyObject * self);
+
+extern Py_cvec *PyAubio_CCvecToPyCvec (cvec_t * self);
+extern cvec_t *PyAubio_ArrayToCCvec (PyObject *input);
+
+extern PyObject *PyAubio_CFmatToArray (fmat_t * self);
+extern fmat_t *PyAubio_ArrayToCFmat (PyObject *input);
+
+// hand written wrappers
+extern PyTypeObject Py_filterType;
+
+extern PyTypeObject Py_filterbankType;
+
+extern PyTypeObject Py_fftType;
+
+extern PyTypeObject Py_pvocType;
+
Index: python/aubio/__init__.py
===================================================================
--- python/aubio/__init__.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubio/__init__.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,9 @@
+import numpy
+from _aubio import *
+
+class fvec(numpy.ndarray):
+
+    def __new__(self, length = 1024, **kwargs):
+        if type(length) == type([]):
+            return numpy.array(length, dtype='float32', **kwargs)
+        return numpy.zeros(length, dtype='float32', **kwargs)
Index: python/aubioinput.py
===================================================================
--- python/aubioinput.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubioinput.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,141 @@
+#! /usr/bin/python
+
+import pygst
+pygst.require('0.10')
+import gst
+import gobject
+gobject.threads_init ()
+
+def gst_buffer_to_numpy_array(buffer, chan):
+    import numpy
+    samples = numpy.frombuffer(buffer.data, dtype=numpy.float32) 
+    if chan == 1:
+        return samples.T
+    else:
+        samples.resize([len(samples)/chan, chan])
+        return samples.T
+
+class AubioSink(gst.BaseSink):
+    _caps = gst.caps_from_string('audio/x-raw-float, \
+                    rate=[ 1, 2147483647 ], \
+                    channels=[ 1, 2147483647 ], \
+                    endianness={ 1234, 4321 }, \
+                    width=32')
+
+    __gsttemplates__ = ( 
+            gst.PadTemplate ("sink",
+                gst.PAD_SINK,
+                gst.PAD_ALWAYS,
+                _caps),
+            )
+
+    def __init__(self, name, process):
+        self.__gobject_init__()
+        self.set_name(name)
+        self.process = process
+        self.adapter = gst.Adapter()
+        self.set_property('sync', False)
+        self.pos = 0
+
+    def set_property(self, name, value): 
+        if name == 'hopsize':
+            # blocksize is in byte, convert from hopsize 
+            from struct import calcsize
+            self.set_property('blocksize', value * calcsize('f'))
+        else:
+            super(gst.BaseSink, self).set_property(name, value)
+
+    def do_render(self, buffer):
+        blocksize = self.get_property('blocksize')
+        caps = buffer.get_caps()
+        chan = caps[0]['channels']
+        self.adapter.push(buffer)
+        while self.adapter.available() >= blocksize:
+            block = self.adapter.take_buffer(blocksize)
+            v = gst_buffer_to_numpy_array(block, chan)
+            if self.process:
+                self.process(v, self.pos)
+            self.pos += 1
+        remaining = self.adapter.available()
+        if remaining < blocksize and remaining > 0:
+            block = self.adapter.take_buffer(remaining)
+            v = gst_buffer_to_numpy_array(block, chan)
+            if self.process:
+                self.process(v, self.pos)
+            self.pos += 1
+        return gst.FLOW_OK
+
+gobject.type_register(AubioSink)
+
+class aubioinput(gst.Bin):
+
+    ret = 0
+
+    def __init__(self, uri, process = None, hopsize = 512,
+            caps = None):
+        if uri.startswith('/'):
+            from urllib import quote
+            uri = 'file://'+quote(uri)
+        src = gst.element_factory_make('uridecodebin')
+        src.set_property('uri', uri)
+        src.connect('pad-added', self.source_pad_added_cb)
+        conv = gst.element_factory_make('audioconvert')
+        self.conv = conv
+        rsmpl = gst.element_factory_make('audioresample')
+        capsfilter = gst.element_factory_make('capsfilter')
+        if caps:
+            capsfilter.set_property('caps', gst.caps_from_string(caps))
+        sink = AubioSink("AubioSink", process = process)
+        sink.set_property('hopsize', hopsize) # * calcsize('f'))
+
+        self.pipeline = gst.Pipeline()
+
+        self.bus = self.pipeline.get_bus()
+        self.bus.add_signal_watch()
+        self.bus.connect('message', self.on_eos)
+
+        self.apad = conv.get_pad('sink')
+
+        self.pipeline.add(src, conv, rsmpl, capsfilter, sink)
+
+        gst.element_link_many(conv, rsmpl, capsfilter, sink)
+
+        self.mainloop = gobject.MainLoop()
+        self.pipeline.set_state(gst.STATE_PLAYING)
+
+    def run(self):
+        self.mainloop.run()
+        return self.ret
+
+    def source_pad_added_cb(self, src, pad):
+        name = pad.get_caps()[0].get_name()
+        if name == 'audio/x-raw-float' or name == 'audio/x-raw-int':
+            pad.link(self.conv.get_pad("sink"))
+
+    def source_pad_removed_cb(self, src, pad):
+        pad.unlink(self.conv.get_pad("sink"))
+
+    def on_eos(self, bus, msg):
+        if msg.type == gst.MESSAGE_EOS:
+            self.bus.remove_signal_watch()
+            self.pipeline.set_state(gst.STATE_PAUSED)
+            self.mainloop.quit()
+        elif msg.type == gst.MESSAGE_ERROR:
+            print "ERROR", msg.parse_error()
+            self.bus.remove_signal_watch()
+            self.pipeline.set_state(gst.STATE_PAUSED)
+            self.mainloop.quit()
+            self.ret = 1 # set return value to 1 in case of error
+
+if __name__ == '__main__':
+    import sys
+    if len(sys.argv) < 2:
+        print "Usage: %s <filename>" % sys.argv[0]
+        sys.exit(1)
+    for filename in sys.argv[1:]:
+        peak = [0.] # use a mutable 
+        def process(buf, hop):
+            peak[0] = max( peak[0], abs(buf.max()) )
+        a = aubioinput(filename, process = process, hopsize = 512)
+        if a.run() == 0: # only display the results if no 
+            print "Finished reading %s, peak value is %f" % (filename, max(peak))
Index: python/aubiomodule.c
===================================================================
--- python/aubiomodule.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubiomodule.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,161 @@
+#include <Python.h>
+#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include <numpy/arrayobject.h>
+
+#include "aubio-types.h"
+#include "generated/aubio-generated.h"
+
+static char Py_alpha_norm_doc[] = "compute alpha normalisation factor";
+
+static PyObject *
+Py_alpha_norm (PyObject * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+  smpl_t alpha;
+  PyObject *result;
+
+  if (!PyArg_ParseTuple (args, "Of:alpha_norm", &input, &alpha)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  // compute the function
+  result = Py_BuildValue ("f", fvec_alpha_norm (vec, alpha));
+  if (result == NULL) {
+    return NULL;
+  }
+
+  return result;
+}
+
+static char Py_zero_crossing_rate_doc[] = "compute zero crossing rate";
+
+static PyObject *
+Py_zero_crossing_rate (PyObject * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+  PyObject *result;
+
+  if (!PyArg_ParseTuple (args, "O:zero_crossing_rate", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  // compute the function
+  result = Py_BuildValue ("f", aubio_zero_crossing_rate (vec));
+  if (result == NULL) {
+    return NULL;
+  }
+
+  return result;
+}
+
+static char Py_min_removal_doc[] = "compute zero crossing rate";
+
+static PyObject *
+Py_min_removal(PyObject * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+
+  if (!PyArg_ParseTuple (args, "O:min_removal", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  // compute the function
+  fvec_min_removal (vec);
+
+  // since this function does not return, we could return None
+  //return Py_None;
+  // however it is convenient to return the modified vector
+  return (PyObject *) PyAubio_CFvecToArray(vec);
+  // or even without converting it back to an array
+  //Py_INCREF(vec);
+  //return (PyObject *)vec;
+}
+
+static PyMethodDef aubio_methods[] = {
+  {"alpha_norm", Py_alpha_norm, METH_VARARGS, Py_alpha_norm_doc},
+  {"zero_crossing_rate", Py_zero_crossing_rate, METH_VARARGS,
+    Py_zero_crossing_rate_doc},
+  {"min_removal", Py_min_removal, METH_VARARGS, Py_min_removal_doc},
+  {NULL, NULL} /* Sentinel */
+};
+
+static char aubio_module_doc[] = "Python module for the aubio library";
+
+PyMODINIT_FUNC
+init_aubio (void)
+{
+  PyObject *m;
+  int err;
+
+  if (   (PyType_Ready (&Py_cvecType) < 0)
+      || (PyType_Ready (&Py_filterType) < 0)
+      || (PyType_Ready (&Py_filterbankType) < 0)
+      || (PyType_Ready (&Py_fftType) < 0)
+      || (PyType_Ready (&Py_pvocType) < 0)
+      // generated objects
+      || (generated_types_ready() < 0 )
+  ) {
+    return;
+  }
+
+  m = Py_InitModule3 ("_aubio", aubio_methods, aubio_module_doc);
+
+  if (m == NULL) {
+    return;
+  }
+
+  err = _import_array ();
+
+  if (err != 0) {
+    fprintf (stderr,
+        "Unable to import Numpy C API from aubio module (error %d)\n", err);
+  }
+
+  Py_INCREF (&Py_cvecType);
+  PyModule_AddObject (m, "cvec", (PyObject *) & Py_cvecType);
+  Py_INCREF (&Py_filterType);
+  PyModule_AddObject (m, "digital_filter", (PyObject *) & Py_filterType);
+  Py_INCREF (&Py_filterbankType);
+  PyModule_AddObject (m, "filterbank", (PyObject *) & Py_filterbankType);
+  Py_INCREF (&Py_fftType);
+  PyModule_AddObject (m, "fft", (PyObject *) & Py_fftType);
+  Py_INCREF (&Py_pvocType);
+  PyModule_AddObject (m, "pvoc", (PyObject *) & Py_pvocType);
+
+  // generated objects
+  add_generated_objects(m);
+}
Index: python/aubioproxy.c
===================================================================
--- python/aubioproxy.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubioproxy.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,153 @@
+#include "aubio-types.h"
+
+fvec_t *
+PyAubio_ArrayToCFvec (PyObject *input) {
+  PyObject *array;
+  fvec_t *vec;
+  if (input == NULL) {
+    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
+    goto fail;
+  }
+  // parsing input object into a Py_fvec
+  if (PyArray_Check(input)) {
+
+    // we got an array, convert it to an fvec
+    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
+      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+      goto fail;
+    } else if (PyArray_NDIM ((PyArrayObject *)input) > 1) {
+      PyErr_SetString (PyExc_ValueError,
+          "input array has more than one dimensions");
+      goto fail;
+    }
+
+    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float");
+      goto fail;
+    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      goto fail;
+    } else {
+      // input data type is float32, nothing else to do
+      array = input;
+    }
+
+    // vec = new_fvec (vec->length);
+    // no need to really allocate fvec, just its struct member
+    vec = (fvec_t *)malloc(sizeof(fvec_t));
+    vec->length = PyArray_SIZE ((PyArrayObject *)array);
+    vec->data = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)array, 0);
+
+  } else if (PyObject_TypeCheck (input, &PyList_Type)) {
+    PyErr_SetString (PyExc_ValueError, "does not convert from list yet");
+    return NULL;
+  } else {
+    PyErr_SetString (PyExc_ValueError, "can only accept vector of float as input");
+    return NULL;
+  }
+
+  return vec;
+
+fail:
+  return NULL;
+}
+
+PyObject *
+PyAubio_CFvecToArray (fvec_t * self)
+{
+  npy_intp dims[] = { self->length, 1 };
+  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data);
+}
+
+Py_cvec *
+PyAubio_CCvecToPyCvec (cvec_t * input) {
+  Py_cvec *vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
+  vec->length = input->length;
+  vec->o = input;
+  Py_INCREF(vec);
+  return vec;
+}
+
+cvec_t *
+PyAubio_ArrayToCCvec (PyObject *input) {
+  if (PyObject_TypeCheck (input, &Py_cvecType)) {
+      return ((Py_cvec*)input)->o;
+  } else {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      return NULL;
+  }
+}
+
+PyObject *
+PyAubio_CFmatToArray (fmat_t * input)
+{
+  PyObject *array = NULL;
+  uint_t i;
+  npy_intp dims[] = { input->length, 1 };
+  PyObject *concat = PyList_New (0), *tmp = NULL;
+  for (i = 0; i < input->height; i++) {
+    tmp = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->data[i]);
+    PyList_Append (concat, tmp);
+    Py_DECREF (tmp);
+  }
+  array = PyArray_FromObject (concat, AUBIO_NPY_SMPL, 2, 2);
+  Py_DECREF (concat);
+  return array;
+}
+
+fmat_t *
+PyAubio_ArrayToCFmat (PyObject *input) {
+  PyObject *array;
+  fmat_t *mat;
+  uint_t i;
+  if (input == NULL) {
+    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
+    goto fail;
+  }
+  // parsing input object into a Py_fvec
+  if (PyArray_Check(input)) {
+
+    // we got an array, convert it to an fvec
+    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
+      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+      goto fail;
+    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
+      PyErr_SetString (PyExc_ValueError,
+          "input array has more than two dimensions");
+      goto fail;
+    }
+
+    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float");
+      goto fail;
+    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      goto fail;
+    } else {
+      // input data type is float32, nothing else to do
+      array = input;
+    }
+
+    // no need to really allocate fvec, just its struct member
+    mat = (fmat_t *)malloc(sizeof(fmat_t));
+    mat->length = PyArray_DIM ((PyArrayObject *)array, 1);
+    mat->height = PyArray_DIM ((PyArrayObject *)array, 0);
+    mat->data = (smpl_t **)malloc(sizeof(smpl_t*) * mat->height);
+    for (i=0; i< mat->height; i++) {
+      mat->data[i] = (smpl_t*)PyArray_GETPTR1 ((PyArrayObject *)array, i);
+    }
+
+  } else if (PyObject_TypeCheck (input, &PyList_Type)) {
+    PyErr_SetString (PyExc_ValueError, "can not convert list to fmat");
+    return NULL;
+  } else {
+    PyErr_SetString (PyExc_ValueError, "can only accept matrix of float as input");
+    return NULL;
+  }
+
+  return mat;
+
+fail:
+  return NULL;
+}
+
Index: python/aubiowraphell.h
===================================================================
--- python/aubiowraphell.h	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/aubiowraphell.h	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,90 @@
+#include "aubio-types.h"
+
+#define AUBIO_DECLARE(NAME, PARAMS...) \
+typedef struct { \
+  PyObject_HEAD \
+  aubio_ ## NAME ## _t * o; \
+  PARAMS; \
+} Py_## NAME;
+
+#define AUBIO_INIT(NAME, PARAMS... ) \
+static int \
+Py_ ## NAME ## _init (Py_ ## NAME * self, PyObject * args, PyObject * kwds) \
+{ \
+  self->o = new_aubio_## NAME ( PARAMS ); \
+  if (self->o == NULL) { \
+    PyErr_SetString (PyExc_StandardError, "error creating object"); \
+    return -1; \
+  } \
+\
+  return 0; \
+}
+
+#define AUBIO_DEL(NAME) \
+static void \
+Py_ ## NAME ## _del ( Py_ ## NAME * self) \
+{ \
+  del_aubio_ ## NAME (self->o); \
+  self->ob_type->tp_free ((PyObject *) self); \
+}
+
+#define AUBIO_MEMBERS_START(NAME) \
+static PyMemberDef Py_ ## NAME ## _members[] = {
+
+#define AUBIO_MEMBERS_STOP(NAME) \
+  {NULL} \
+};
+
+#define AUBIO_METHODS(NAME) \
+static PyMethodDef Py_ ## NAME ## _methods[] = { \
+  {NULL} \
+};
+
+
+#define AUBIO_TYPEOBJECT(NAME, PYNAME) \
+PyTypeObject Py_ ## NAME ## Type = { \
+  PyObject_HEAD_INIT (NULL)    \
+  0,                           \
+  PYNAME,                      \
+  sizeof (Py_ ## NAME),          \
+  0,                           \
+  (destructor) Py_ ## NAME ## _del,  \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  (ternaryfunc)Py_ ## NAME ## _do,   \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  Py_TPFLAGS_DEFAULT,          \
+  Py_ ## NAME ## _doc,               \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  Py_ ## NAME ## _methods,           \
+  Py_ ## NAME ## _members,           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  0,                           \
+  (initproc) Py_ ## NAME ## _init,   \
+  0,                           \
+  Py_ ## NAME ## _new,               \
+};
+
+// some more helpers
+#define AUBIO_NEW_VEC(name, type, lengthval) \
+  name = (type *) PyObject_New (type, & type ## Type); \
+  name->length = lengthval;
Index: python/build_linux
===================================================================
--- python/build_linux	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/build_linux	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+set -e
+set -x
+
+python setup.py clean build
+export PYTHONPATH=./build/lib.linux-x86_64-2.7/
+export LD_LIBRARY_PATH=../../build/src/
+./run_all_tests --verbose
Index: python/build_osx
===================================================================
--- python/build_osx	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/build_osx	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+set -e
+set -x
+
+python setup.py clean build
+export PYTHONPATH=./build/lib.macosx-10.6-intel-2.7:$PYTHONPATH
+export DYLD_LIBRARY_PATH=../../build/src
+./run_all_tests --verbose
Index: python/c_weighting_test_simple.expected
===================================================================
--- python/c_weighting_test_simple.expected	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/c_weighting_test_simple.expected	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,2 @@
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 5.00000000e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.08504281e-01 2.31621372e-01 1.38614617e-01 1.58040475e-02 -9.84900252e-04 -2.72686896e-03 -2.87772967e-03 -2.87932142e-03 -2.86783482e-03 -2.85529016e-03 -2.84270413e-03 -2.83016008e-03 -2.81766458e-03 -2.80521796e-03 -2.79282009e-03 -2.78047079e-03 -2.76816989e-03 -2.75591721e-03 -2.74371257e-03 -2.73155579e-03
Index: python/demo_beats_and_tempo.py
===================================================================
--- python/demo_beats_and_tempo.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_beats_and_tempo.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,39 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import tempo, source
+
+win_s = 512                 # fft size
+hop_s = win_s / 2           # hop size
+samplerate = 44100
+
+if len(sys.argv) < 2:
+    print "Usage: %s <filename>" % sys.argv[0]
+    sys.exit(1)
+
+filename = sys.argv[1]
+beats = []
+
+s = source(filename, samplerate, hop_s)
+t = tempo("default", win_s, hop_s)
+
+block_read = 0
+while True:
+    samples, read = s()
+    isbeat = t(samples)
+    if isbeat:
+        thisbeat = (block_read * hop_s + isbeat[0]) / samplerate
+        print "%.4f" % thisbeat
+        beats.append (thisbeat)
+    block_read += 1
+    if read < hop_s: break
+
+periods = [60./(b - a) for a,b in zip(beats[:-1],beats[1:])]
+
+from numpy import mean, median
+print 'mean period:', mean(periods), 'bpm'
+print 'median period:', median(periods), 'bpm'
+
+from pylab import plot, show
+plot(beats[1:], periods)
+show()
Index: python/demo_filterbank_slaney.py
===================================================================
--- python/demo_filterbank_slaney.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_filterbank_slaney.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,21 @@
+#! /usr/bin/env python
+
+from aubio import filterbank
+from numpy import array, arange, vstack
+
+win_s = 8192
+samplerate = 16000
+
+f = filterbank(40, win_s)
+f.set_mel_coeffs_slaney(samplerate)
+
+from pylab import loglog, title, show, xlim, ylim, xlabel, ylabel
+xlim([0,samplerate / 2])
+times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * 40)
+loglog(times.T, f.get_coeffs().T, '.-')
+title('Mel frequency bands coefficients')
+xlim([100, 7500])
+ylim([1.0e-3, 2.0e-2])
+xlabel('Frequency (Hz)')
+ylabel('Amplitude')
+show()
Index: python/demo_filterbank_triangle_bands.py
===================================================================
--- python/demo_filterbank_triangle_bands.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_filterbank_triangle_bands.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+
+from aubio import filterbank, fvec
+from pylab import loglog, show, subplot, xlim, ylim, xlabel, ylabel, title
+from numpy import vstack, arange
+
+win_s = 2048
+samplerate = 48000
+
+freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000]
+n_filters = len(freq_list) - 2
+
+f = filterbank(n_filters, win_s)
+freqs = fvec(freq_list)
+f.set_triangle_bands(freqs, samplerate)
+
+subplot(211)
+title('Examples of filterbank built with set_triangle_bands and set_coeffs')
+times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+loglog(times.T, f.get_coeffs().T, '.-')
+xlim([50, samplerate/2])
+ylim([1.0e-6, 2.0e-2])
+ylabel('Amplitude')
+
+## build a new filterbank
+
+freq_list = [60, 80, 200, 400, 800, 1200, 1600, 3200, 6400, 10000, 15000, 24000]
+n_filters = len(freq_list) - 2
+
+f = filterbank(n_filters, win_s)
+freqs = fvec(freq_list)
+f.set_triangle_bands(freqs, samplerate)
+
+coeffs = f.get_coeffs()
+coeffs[4] *= 5.
+
+f.set_coeffs(coeffs)
+
+subplot(212)
+times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+loglog(times.T, f.get_coeffs().T, '.-')
+xlim([50, samplerate/2])
+ylim([1.0e-6, 2.0e-2])
+xlabel('Frequency (Hz)')
+ylabel('Amplitude')
+
+show()
Index: python/demo_onset_sinusoid.py
===================================================================
--- python/demo_onset_sinusoid.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_onset_sinusoid.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,84 @@
+#! /usr/bin/env python
+
+from numpy import random, sin, arange, ones, zeros
+from math import pi
+from aubio import fvec, onset
+
+def build_sinusoid(length, freqs, samplerate):
+  return sin( 2. * pi * arange(length) * freqs / samplerate)
+
+def run_onset(p, input_vec):
+  f = fvec (p.hop_size)
+  cands = []
+  count = 0
+  for vec_slice in input_vec.reshape((-1, p.hop_size)):
+    f[:] = vec_slice
+    cands.append(o(f))
+  return cands
+
+methods = ['default',
+           'energy',
+           'complex',
+           'phase',
+           'specdiff',
+           'kl',
+           'mkl',
+           'specflux',
+           'centroid',
+           'spread',
+           'skewness',
+           'kurtosis',
+           'slope',
+           'decrease',
+           'rolloff',
+          ]
+
+cands = {}
+buf_size = 2048
+hop_size = 512
+samplerate = 44100
+sin_length = (samplerate * 10) % 512 * 512
+freqs = zeros(sin_length)
+
+partition = sin_length / 8
+pointer = 0
+
+pointer += partition
+freqs[pointer: pointer + partition] = 440
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 740
+
+pointer += partition
+freqs[ pointer : pointer + partition ] = 1480
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 400 + 5 * random.random(sin_length/8)
+
+a = build_sinusoid(sin_length, freqs, samplerate)
+
+for method in methods:
+  o = onset(method, buf_size, hop_size, samplerate)
+  cands[method] = run_onset(o, a)
+
+print "done computing"
+
+if 1:
+  from pylab import plot, show, xlabel, ylabel, legend, ylim, subplot
+  subplot (211)
+  legend(methods+['ground truth'], 'upper right')
+  xlabel('time (s)')
+  ylabel('amplitude')
+  ramp = arange(0, sin_length).astype('float') / samplerate
+  plot(ramp, a, ':')
+  subplot (212)
+  ramp = arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
+  for method in methods:
+    plot(ramp, cands[method],'.-')
+    legend(methods, 'upper right')
+    xlabel('time (s)')
+  ylabel('spectral descriptor value')
+  show()
+
Index: python/demo_pitch_sinusoid.py
===================================================================
--- python/demo_pitch_sinusoid.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_pitch_sinusoid.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+
+from numpy import random, sin, arange, ones, zeros
+from math import pi
+from aubio import fvec, pitch
+
+def build_sinusoid(length, freqs, samplerate):
+  return sin( 2. * pi * arange(length) * freqs / samplerate)
+
+def run_pitch(p, input_vec):
+  f = fvec (p.hop_size)
+  cands = []
+  count = 0
+  for vec_slice in input_vec.reshape((-1, p.hop_size)):
+    f[:] = vec_slice
+    cands.append(p(f))
+  return cands
+
+methods = ['default', 'schmitt', 'fcomb', 'mcomb', 'yin', 'yinfft']
+
+cands = {}
+buf_size = 2048
+hop_size = 512
+samplerate = 44100
+sin_length = (samplerate * 10) % 512 * 512
+freqs = zeros(sin_length)
+
+partition = sin_length / 8
+pointer = 0
+
+pointer += partition
+freqs[pointer: pointer + partition] = 440
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 740
+
+pointer += partition
+freqs[ pointer : pointer + partition ] = 1480
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 400 + 5 * random.random(sin_length/8)
+
+a = build_sinusoid(sin_length, freqs, samplerate)
+
+for method in methods:
+  p = pitch(method, buf_size, hop_size, samplerate)
+  cands[method] = run_pitch(p, a)
+
+print "done computing"
+
+if 1:
+  from pylab import plot, show, xlabel, ylabel, legend, ylim
+  ramp = arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
+  for method in methods:
+    plot(ramp, cands[method],'.-')
+
+  # plot ground truth
+  ramp = arange(0, sin_length).astype('float') / samplerate
+  plot(ramp, freqs, ':')
+
+  legend(methods+['ground truth'], 'upper right')
+  xlabel('time (s)')
+  ylabel('frequency (Hz)')
+  ylim([0,2000])
+  show()
+
Index: python/demo_simple_robot_voice.py
===================================================================
--- python/demo_simple_robot_voice.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_simple_robot_voice.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink, pvoc
+
+if __name__ == '__main__':
+  if len(sys.argv) < 2:
+    print 'usage: %s <inputfile> <outputfile>' % sys.argv[0]
+    sys.exit(1)
+  samplerate = 44100
+  f = source(sys.argv[1], samplerate, 256)
+  g = sink(sys.argv[2], samplerate)
+  total_frames, read = 0, 256
+
+  win_s = 512                 # fft size
+  hop_s = win_s / 2           # hop size
+  pv = pvoc(win_s, hop_s)                            # phase vocoder
+
+  while read:
+    samples, read = f()
+    spectrum = pv(samples)            # compute spectrum
+    spectrum.phas[:] = 0.             # zero phase
+    new_samples = pv.rdo(spectrum)    # compute modified samples
+    g(new_samples, read)              # write to output
+    total_frames += read
+
+  print "wrote", total_frames, "from", f.uri, "to", g.uri
+
+  
Index: python/demo_sink.py
===================================================================
--- python/demo_sink.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_sink.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,17 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink
+
+if __name__ == '__main__':
+  if len(sys.argv) < 3:
+    print 'usage: %s <inputfile> <outputfile>' % sys.argv[0]
+    sys.exit(1)
+  f = source(sys.argv[1], 8000, 256)
+  g = sink(sys.argv[2], 8000)
+  total_frames, read = 0, 256
+  while read:
+    vec, read = f()
+    g(vec, read)
+    total_frames += read
+  print "read", total_frames / float(f.samplerate), "seconds from", f.uri
Index: python/demo_source.py
===================================================================
--- python/demo_source.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_source.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,15 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source
+
+if __name__ == '__main__':
+  if len(sys.argv) < 2:
+    print 'usage: %s <inputfile>' % sys.argv[0]
+    sys.exit(1)
+  f = source(sys.argv[1], 8000, 256)
+  total_frames, read = 0, 256
+  while read:
+    vec, read = f()
+    total_frames += read
+  print "read", total_frames / float(f.samplerate), "seconds from", f.uri
Index: python/demo_spectrogram.py
===================================================================
--- python/demo_spectrogram.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_spectrogram.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import pvoc, source
+from numpy import array, arange, zeros, shape, log10, vstack
+from pylab import imshow, show, cm, axis, ylabel, xlabel, xticks, yticks
+
+def get_spectrogram(filename):
+  samplerate = 44100
+  win_s = 512                                        # fft window size
+  hop_s = win_s / 2                                  # hop size
+  fft_s = win_s / 2 + 1                              # spectrum bins
+
+  a = source(filename, samplerate, hop_s)            # source file
+  pv = pvoc(win_s, hop_s)                            # phase vocoder
+  specgram = zeros([0, fft_s], dtype='float32')      # numpy array to store spectrogram
+
+  # analysis
+  while True:
+    samples, read = a()                              # read file
+    specgram = vstack((specgram,pv(samples).norm))   # store new norm vector
+    if read < a.hop_size: break
+
+  # plotting
+  imshow(log10(specgram.T + .001), origin = 'bottom', aspect = 'auto', cmap=cm.gray_r)
+  axis([0, len(specgram), 0, len(specgram[0])])
+  # show axes in Hz and seconds
+  time_step = hop_s / float(samplerate)
+  total_time = len(specgram) * time_step
+  print "total time: %0.2fs" % total_time,
+  print ", samplerate: %.2fkHz" % (samplerate / 1000.)
+  n_xticks = 10
+  n_yticks = 10
+
+  def get_rounded_ticks( top_pos, step, n_ticks ):
+      top_label = top_pos * step
+      # get the first label
+      ticks_first_label = top_pos * step / n_ticks
+      # round to the closest .1
+      ticks_first_label = round ( ticks_first_label * 10. ) / 10.
+      # compute all labels from the first rounded one
+      ticks_labels = [ ticks_first_label * n for n in range(n_ticks) ] + [ top_label ]
+      # get the corresponding positions
+      ticks_positions = [ ticks_labels[n] / step for n in range(n_ticks) ] + [ top_pos ]
+      # convert to string
+      ticks_labels = [  "%.1f" % x for x in ticks_labels ]
+      # return position, label tuple to use with x/yticks
+      return ticks_positions, ticks_labels
+
+  # apply to the axis
+  xticks( *get_rounded_ticks ( len(specgram), time_step, n_xticks ) )
+  yticks( *get_rounded_ticks ( len(specgram[0]), (samplerate / 2. / 1000.) / len(specgram[0]), n_yticks ) )
+  ylabel('Frequency (kHz)')
+  xlabel('Time (s)')
+
+if __name__ == '__main__':
+  if len(sys.argv) < 2:
+    print "Usage: %s <filename>" % sys.argv[0]
+  else:
+    for soundfile in sys.argv[1:]:
+      get_spectrogram(soundfile)
+      # display graph
+      show()
Index: python/demo_tss.py
===================================================================
--- python/demo_tss.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/demo_tss.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink, pvoc, tss
+
+if __name__ == '__main__':
+  if len(sys.argv) < 2:
+    print 'usage: %s <inputfile> <outputfile_transient> <outputfile_steady>' % sys.argv[0]
+    sys.exit(1)
+
+  samplerate = 44100
+  win_s = 512                 # fft size
+  hop_s = win_s / 2           # block size
+  threshold = 0.26
+
+  f = source(sys.argv[1], samplerate, hop_s)
+  g = sink(sys.argv[2], samplerate)
+  h = sink(sys.argv[3], samplerate)
+
+  pv = pvoc(win_s, hop_s)     # phase vocoder
+  pw = pvoc(win_s, hop_s)     # another phase vocoder
+  t = tss(win_s, hop_s)       # transient steady state separation
+
+  t.set_threshold(threshold)
+
+  read = hop_s
+
+  while read:
+    samples, read = f()               # read file
+    spec = pv(samples)                # compute spectrum
+    trans_spec, stead_spec = t(spec)  # transient steady-state separation
+    transients = pv.rdo(trans_spec)   # overlap-add synthesis of transients
+    steadstate = pw.rdo(stead_spec)   # overlap-add synthesis of steady states
+    g(transients, read)               # write transients to output
+    h(steadstate, read)               # write steady states to output
+
+  del f, g, h                         # finish writing the files now
+
+  from demo_spectrogram import get_spectrogram
+  from pylab import subplot, show
+  subplot(311)
+  get_spectrogram(sys.argv[1])
+  subplot(312)
+  get_spectrogram(sys.argv[2])
+  subplot(313)
+  get_spectrogram(sys.argv[3])
+  show()
Index: python/gen_pyobject.py
===================================================================
--- python/gen_pyobject.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/gen_pyobject.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,526 @@
+#! /usr/bin/python
+
+""" This madness of code is used to generate the C code of the python interface
+to aubio. Don't try this at home.
+
+The list of typedefs and functions is obtained from the command line 'cpp
+aubio.h'. This list is then used to parse all the functions about this object.
+
+I hear the ones asking "why not use swig, or cython, or something like that?"
+
+The requirements for this extension are the following:
+
+    - aubio vectors can be viewed as numpy arrays, and vice versa
+    - aubio 'object' should be python classes, not just a bunch of functions
+
+I haven't met any python interface generator that can meet both these
+requirements. If you know of one, please let me know, it will spare me
+maintaining this bizarre file.
+"""
+
+param_numbers = {
+  'source': [0, 2],
+  'sink':   [2, 0],
+}
+
+# TODO
+# do function: for now, only the following pattern is supported:
+# void aubio_<foo>_do (aubio_foo_t * o, 
+#       [input1_t * input, [output1_t * output, ..., output3_t * output]]);
+# There is no way of knowing that output1 is actually input2. In the future,
+# const could be used for the inputs in the C prototypes.
+
+def write_msg(*args):
+  pass
+  # uncomment out for debugging
+  #print args
+
+def split_type(arg):
+    """ arg = 'foo *name' 
+        return ['foo*', 'name'] """
+    l = arg.split()
+    type_arg = {'type': l[0], 'name': l[1]}
+    # ['foo', '*name'] -> ['foo*', 'name']
+    if l[-1].startswith('*'):
+        #return [l[0]+'*', l[1][1:]]
+        type_arg['type'] = l[0] + '*'
+        type_arg['name'] = l[1][1:]
+    # ['foo', '*', 'name'] -> ['foo*', 'name']
+    if len(l) == 3:
+        #return [l[0]+l[1], l[2]]
+        type_arg['type'] = l[0]+l[1]
+        type_arg['name'] = l[2]
+    else:
+        #return l
+        pass
+    return type_arg
+
+def get_params(proto):
+    """ get the list of parameters from a function prototype
+    example: proto = "int main (int argc, char ** argv)"
+    returns: ['int argc', 'char ** argv']
+    """
+    import re
+    paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]')
+    return paramregex.findall(proto)
+
+def get_params_types_names(proto):
+    """ get the list of parameters from a function prototype
+    example: proto = "int main (int argc, char ** argv)"
+    returns: [['int', 'argc'], ['char **','argv']]
+    """
+    return map(split_type, get_params(proto)) 
+
+def get_return_type(proto):
+    import re
+    paramregex = re.compile('(\w+ ?\*?).*')
+    outputs = paramregex.findall(proto)
+    assert len(outputs) == 1
+    return outputs[0].replace(' ', '')
+
+def get_name(proto):
+    name = proto.split()[1].split('(')[0]
+    return name.replace('*','')
+
+# the important bits: the size of the output for each objects. this data should
+# move into the C library at some point.
+defaultsizes = {
+    'resampler':    ['input->length * self->ratio'],
+    'specdesc':     ['1'],
+    'onset':        ['1'],
+    'pitchyin':     ['1'],
+    'pitchyinfft':  ['1'],
+    'pitchschmitt': ['1'],
+    'pitchmcomb':   ['1'],
+    'pitchfcomb':   ['1'],
+    'pitch':        ['1'],
+    'tss':          ['self->buf_size', 'self->buf_size'],
+    'mfcc':         ['self->n_coeffs'],
+    'beattracking': ['self->hop_size'],
+    'tempo':        ['1'],
+    'peakpicker':   ['1'],
+    'source':       ['self->hop_size', '1'],
+}
+
+# default value for variables
+aubioinitvalue = {
+    'uint_t': 0,
+    'smpl_t': 0,
+    'lsmp_t': 0.,
+    'char_t*': 'NULL',
+    }
+
+aubiodefvalue = {
+    # we have some clean up to do
+    'buf_size': 'Py_default_vector_length', 
+    # and here too
+    'hop_size': 'Py_default_vector_length / 2', 
+    # these should be alright
+    'samplerate': 'Py_aubio_default_samplerate', 
+    # now for the non obvious ones
+    'n_filters': '40', 
+    'n_coeffs': '13', 
+    'nelems': '10',
+    'flow': '0.', 
+    'fhig': '1.', 
+    'ilow': '0.', 
+    'ihig': '1.', 
+    'thrs': '0.5',
+    'ratio': '0.5',
+    'method': '"default"',
+    'uri': '"none"',
+    }
+
+# aubio to python
+aubio2pytypes = {
+    'uint_t': 'I',
+    'smpl_t': 'f',
+    'lsmp_t': 'd',
+    'fvec_t*': 'O',
+    'cvec_t*': 'O',
+    'char_t*': 's',
+}
+
+# python to aubio
+aubiovecfrompyobj = {
+    'fvec_t*': 'PyAubio_ArrayToCFvec',
+    'cvec_t*': 'PyAubio_ArrayToCCvec',
+    'uint_t': '(uint_t)PyInt_AsLong',
+}
+
+# aubio to python
+aubiovectopyobj = {
+    'fvec_t*': 'PyAubio_CFvecToArray',
+    'cvec_t*': 'PyAubio_CCvecToPyCvec',
+    'smpl_t': 'PyFloat_FromDouble',
+    'uint_t*': 'PyInt_FromLong',
+    'uint_t': 'PyInt_FromLong',
+}
+
+def gen_new_init(newfunc, name):
+    newparams = get_params_types_names(newfunc)
+    # self->param1, self->param2, self->param3
+    if len(newparams):
+        selfparams = ', self->'+', self->'.join([p['name'] for p in newparams])
+    else:
+        selfparams = '' 
+    # "param1", "param2", "param3"
+    paramnames = ", ".join(["\""+p['name']+"\"" for p in newparams])
+    pyparams = "".join(map(lambda p: aubio2pytypes[p['type']], newparams))
+    paramrefs = ", ".join(["&" + p['name'] for p in newparams])
+    s = """\
+// WARNING: this file is generated, DO NOT EDIT
+
+// WARNING: if you haven't read the first line yet, please do so
+#include "aubiowraphell.h"
+
+typedef struct
+{
+  PyObject_HEAD
+  aubio_%(name)s_t * o;
+""" % locals()
+    for p in newparams:
+        ptype = p['type']
+        pname = p['name']
+        s += """\
+  %(ptype)s %(pname)s;
+""" % locals()
+    s += """\
+} Py_%(name)s;
+
+static char Py_%(name)s_doc[] = "%(name)s object";
+
+static PyObject *
+Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
+{
+  Py_%(name)s *self;
+""" % locals()
+    for p in newparams:
+        ptype = p['type']
+        pname = p['name']
+        initval = aubioinitvalue[ptype]
+        s += """\
+  %(ptype)s %(pname)s = %(initval)s;
+""" % locals()
+    # now the actual PyArg_Parse
+    if len(paramnames):
+        s += """\
+  static char *kwlist[] = { %(paramnames)s, NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist,
+          %(paramrefs)s)) {
+    return NULL;
+  }
+""" % locals()
+    s += """\
+
+  self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
+
+  if (self == NULL) {
+    return NULL;
+  }
+""" % locals()
+    for p in newparams:
+        ptype = p['type']
+        pname = p['name']
+        defval = aubiodefvalue[pname]
+        if ptype == 'char_t*':
+            s += """\
+
+  self->%(pname)s = %(defval)s;
+  if (%(pname)s != NULL) {
+    self->%(pname)s = %(pname)s;
+  }
+""" % locals()
+        elif ptype == 'uint_t':
+            s += """\
+
+  self->%(pname)s = %(defval)s;
+  if (%(pname)s > 0) {
+    self->%(pname)s = %(pname)s;
+  } else if (%(pname)s < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative value for %(pname)s");
+    return NULL;
+  }
+""" % locals()
+        elif ptype == 'smpl_t':
+            s += """\
+
+  self->%(pname)s = %(defval)s;
+  if (%(pname)s != %(defval)s) {
+    self->%(pname)s = %(pname)s;
+  }
+""" % locals()
+        else:
+            write_msg ("ERROR, unknown type of parameter %s %s" % (ptype, pname) )
+    s += """\
+
+  return (PyObject *) self;
+}
+
+AUBIO_INIT(%(name)s %(selfparams)s)
+
+AUBIO_DEL(%(name)s)
+
+""" % locals()
+    return s
+
+def gen_do_input_params(inputparams):
+  inputdefs = ''
+  parseinput = ''
+  inputrefs = ''
+  inputvecs = ''
+  pytypes = ''
+
+  if len(inputparams):
+    # build the parsing string for PyArg_ParseTuple
+    pytypes = "".join([aubio2pytypes[p['type']] for p in inputparams])
+
+    inputdefs = "  /* input vectors python prototypes */\n"
+    for p in inputparams:
+      if p['type'] != 'uint_t':
+        inputdefs += "  PyObject * " + p['name'] + "_obj;\n"
+
+    inputvecs = "  /* input vectors prototypes */\n  "
+    inputvecs += "\n  ".join(map(lambda p: p['type'] + ' ' + p['name'] + ";", inputparams))
+
+    parseinput = "  /* input vectors parsing */\n  "
+    for p in inputparams:
+        inputvec = p['name']
+        if p['type'] != 'uint_t':
+          inputdef = p['name'] + "_obj"
+        else:
+          inputdef = p['name']
+        converter = aubiovecfrompyobj[p['type']]
+        if p['type'] != 'uint_t':
+          parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s);
+
+  if (%(inputvec)s == NULL) {
+    return NULL;
+  }
+
+  """ % locals()
+
+    # build the string for the input objects references
+    inputreflist = []
+    for p in inputparams:
+      if p['type'] != 'uint_t':
+        inputreflist += [ "&" + p['name'] + "_obj" ]
+      else:
+        inputreflist += [ "&" + p['name'] ]
+    inputrefs = ", ".join(inputreflist)
+    # end of inputs strings
+  return inputdefs, parseinput, inputrefs, inputvecs, pytypes
+
+def gen_do_output_params(outputparams, name):
+  outputvecs = ""
+  outputcreate = ""
+  if len(outputparams):
+    outputvecs = "  /* output vectors prototypes */\n"
+    for p in outputparams:
+      params = {
+        'name': p['name'], 'pytype': p['type'], 'autype': p['type'][:-3],
+        'length': defaultsizes[name].pop(0) }
+      if (p['type'] == 'uint_t*'):
+        outputvecs += '  uint_t' + ' ' + p['name'] + ";\n"
+        outputcreate += "  %(name)s = 0;\n" % params
+      else:
+        outputvecs += "  " + p['type'] + ' ' + p['name'] + ";\n"
+        outputcreate += "  /* creating output %(name)s as a new_%(autype)s of length %(length)s */\n" % params
+        outputcreate += "  %(name)s = new_%(autype)s (%(length)s);\n" % params
+
+  returnval = "";
+  if len(outputparams) > 1:
+    returnval += "  PyObject *outputs = PyList_New(0);\n"
+    for p in outputparams:
+      returnval += "  PyList_Append( outputs, (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")" +");\n"
+    returnval += "  return outputs;"
+  elif len(outputparams) == 1:
+    if defaultsizes[name] == '1':
+      returnval += "  return (PyObject *)PyFloat_FromDouble(" + p['name'] + "->data[0])"
+    else:
+      returnval += "  return (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")"
+  else:
+    returnval = "  return Py_None;";
+  # end of output strings
+  return outputvecs, outputcreate, returnval
+
+def gen_do(dofunc, name):
+    funcname = dofunc.split()[1].split('(')[0]
+    doparams = get_params_types_names(dofunc) 
+    # make sure the first parameter is the object
+    assert doparams[0]['type'] == "aubio_"+name+"_t*", \
+        "method is not in 'aubio_<name>_t"
+    # and remove it
+    doparams = doparams[1:]
+
+    n_param = len(doparams)
+
+    if name in param_numbers.keys():
+      n_input_param, n_output_param = param_numbers[name]
+    else:
+      n_input_param, n_output_param = 1, n_param - 1
+
+    assert n_output_param + n_input_param == n_param, "n_output_param + n_input_param != n_param for %s" % name
+
+    inputparams = doparams[:n_input_param]
+    outputparams = doparams[n_input_param:n_input_param + n_output_param]
+
+    inputdefs, parseinput, inputrefs, inputvecs, pytypes = gen_do_input_params(inputparams);
+    outputvecs, outputcreate, returnval = gen_do_output_params(outputparams, name)
+
+    # build strings for outputs
+    # build the parameters for the  _do() call
+    doparams_string = "self->o"
+    for p in doparams:
+      if p['type'] == 'uint_t*':
+        doparams_string += ", &" + p['name']
+      else:
+        doparams_string += ", " + p['name']
+
+    if n_input_param:
+      arg_parse_tuple = """\
+  if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) {
+    return NULL;
+  }
+""" % locals()
+    else:
+      arg_parse_tuple = ""
+    # put it all together
+    s = """\
+/* function Py_%(name)s_do */
+static PyObject * 
+Py_%(name)s_do(Py_%(name)s * self, PyObject * args)
+{
+%(inputdefs)s
+%(inputvecs)s
+%(outputvecs)s
+
+%(arg_parse_tuple)s
+
+%(parseinput)s
+  
+%(outputcreate)s
+
+  /* compute _do function */
+  %(funcname)s (%(doparams_string)s);
+
+%(returnval)s;
+}
+""" % locals()
+    return s
+
+def gen_members(new_method, name):
+    newparams = get_params_types_names(new_method)
+    s = """
+AUBIO_MEMBERS_START(%(name)s)""" % locals()
+    for param in newparams:
+        if param['type'] == 'char_t*':
+            s += """
+  {"%(pname)s", T_STRING, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
+        % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
+        elif param['type'] == 'uint_t':
+            s += """
+  {"%(pname)s", T_INT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
+        % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
+        elif param['type'] == 'smpl_t':
+            s += """
+  {"%(pname)s", T_FLOAT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
+        % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
+        else:
+            write_msg ("-- ERROR, unknown member type ", param )
+    s += """
+AUBIO_MEMBERS_STOP(%(name)s)
+
+""" % locals()
+    return s
+
+
+def gen_methods(get_methods, set_methods, name):
+    s = ""
+    method_defs = ""
+    for method in set_methods:
+        method_name = get_name(method)
+        params = get_params_types_names(method)
+        out_type = get_return_type(method)
+        assert params[0]['type'] == "aubio_"+name+"_t*", \
+            "get method is not in 'aubio_<name>_t"
+        write_msg (method )
+        write_msg (params[1:])
+        setter_args = "self->o, " +",".join([p['name'] for p in params[1:]])
+        parse_args = ""
+        for p in params[1:]:
+            parse_args += p['type'] + " " + p['name'] + ";\n"
+        argmap = "".join([aubio2pytypes[p['type']] for p in params[1:]])
+        arglist = ", ".join(["&"+p['name'] for p in params[1:]])
+        parse_args += """
+  if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) {
+    return NULL;
+  } """ % locals()
+        s += """
+static PyObject *
+Py%(funcname)s (Py_%(objname)s *self, PyObject *args)
+{
+  uint_t err = 0;
+
+  %(parse_args)s
+
+  err = %(funcname)s (%(setter_args)s);
+
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error running %(funcname)s");
+    return NULL;
+  }
+  return Py_None;
+}
+""" % {'funcname': method_name, 'objname': name, 
+        'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
+        shortname = method_name.split(name+'_')[-1]
+        method_defs += """\
+  {"%(shortname)s", (PyCFunction) Py%(method_name)s,
+    METH_VARARGS, ""},
+""" % locals()
+
+    for method in get_methods:
+        method_name = get_name(method)
+        params = get_params_types_names(method)
+        out_type = get_return_type(method)
+        assert params[0]['type'] == "aubio_"+name+"_t*", \
+            "get method is not in 'aubio_<name>_t %s" % params[0]['type']
+        assert len(params) == 1, \
+            "get method has more than one parameter %s" % params
+        getter_args = "self->o" 
+        returnval = "(PyObject *)" + aubiovectopyobj[out_type] + " (tmp)"
+        shortname = method_name.split(name+'_')[-1]
+        method_defs += """\
+  {"%(shortname)s", (PyCFunction) Py%(method_name)s,
+    METH_NOARGS, ""},
+""" % locals()
+        s += """
+static PyObject *
+Py%(funcname)s (Py_%(objname)s *self, PyObject *unused)
+{
+  %(out_type)s tmp = %(funcname)s (%(getter_args)s);
+  return %(returnval)s;
+}
+""" % {'funcname': method_name, 'objname': name, 
+        'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval }
+
+    s += """
+static PyMethodDef Py_%(name)s_methods[] = {
+""" % locals() 
+    s += method_defs 
+    s += """\
+  {NULL} /* sentinel */
+};
+""" % locals() 
+    return s
+
+def gen_finish(name):
+    s = """\
+
+AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s")
+""" % locals()
+    return s
Index: python/generator.py
===================================================================
--- python/generator.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/generator.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,187 @@
+#! /usr/bin/python
+
+""" This file generates a c file from a list of cpp prototypes. """
+
+import os, sys, shutil
+from gen_pyobject import write_msg, gen_new_init, gen_do, gen_members, gen_methods, gen_finish
+
+def get_cpp_objects():
+
+  cpp_output = [l.strip() for l in os.popen('cpp -DAUBIO_UNSTABLE=1 -I../build/src ../src/aubio.h').readlines()]
+
+  cpp_output = filter(lambda y: len(y) > 1, cpp_output)
+  cpp_output = filter(lambda y: not y.startswith('#'), cpp_output)
+
+  i = 1
+  while 1:
+      if i >= len(cpp_output): break
+      if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'):
+          cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i]
+          cpp_output.pop(i-1)
+      else:
+          i += 1
+
+  typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output)
+
+  cpp_objects = [a.split()[3][:-1] for a in typedefs]
+
+  return cpp_output, cpp_objects
+
+def generate_object_files():
+  if os.path.isdir('generated'): shutil.rmtree('generated')
+  os.mkdir('generated')
+
+  generated_objects = []
+  cpp_output, cpp_objects = get_cpp_objects()
+  skip_objects = ['fft',
+      'pvoc',
+      'filter',
+      'filterbank',
+      'resampler',
+      'sndfile',
+      'sink_apple_audio',
+      'sink_sndfile',
+      'source_apple_audio',
+      'source_sndfile']
+
+  write_msg("-- INFO: %d objects in total" % len(cpp_objects))
+
+  for this_object in cpp_objects:
+      lint = 0
+   
+      if this_object[-2:] == '_t':
+          object_name = this_object[:-2]
+      else:
+          object_name = this_object
+          write_msg("-- WARNING: %s does not end in _t" % this_object)
+
+      if object_name[:len('aubio_')] != 'aubio_':
+          write_msg("-- WARNING: %s does not start n aubio_" % this_object)
+
+      write_msg("-- INFO: looking at", object_name)
+      object_methods = filter(lambda x: this_object in x, cpp_output)
+      object_methods = [a.strip() for a in object_methods]
+      object_methods = filter(lambda x: not x.startswith('typedef'), object_methods)
+      #for method in object_methods:
+      #    write_msg(method)
+      new_methods = filter(lambda x: 'new_'+object_name in x, object_methods)
+      if len(new_methods) > 1:
+          write_msg("-- WARNING: more than one new method for", object_name)
+          for method in new_methods:
+              write_msg(method)
+      elif len(new_methods) < 1:
+          write_msg("-- WARNING: no new method for", object_name)
+      elif 0:
+          for method in new_methods:
+              write_msg(method)
+
+      del_methods = filter(lambda x: 'del_'+object_name in x, object_methods)
+      if len(del_methods) > 1:
+          write_msg("-- WARNING: more than one del method for", object_name)
+          for method in del_methods:
+              write_msg(method)
+      elif len(del_methods) < 1:
+          write_msg("-- WARNING: no del method for", object_name)
+
+      do_methods = filter(lambda x: object_name+'_do' in x, object_methods)
+      if len(do_methods) > 1:
+          pass
+          #write_msg("-- WARNING: more than one do method for", object_name)
+          #for method in do_methods:
+          #    write_msg(method)
+      elif len(do_methods) < 1:
+          write_msg("-- WARNING: no do method for", object_name)
+      elif 0:
+          for method in do_methods:
+              write_msg(method)
+
+      # check do methods return void
+      for method in do_methods:
+          if (method.split()[0] != 'void'):
+              write_msg("-- ERROR: _do method does not return void:", method )
+
+      get_methods = filter(lambda x: object_name+'_get_' in x, object_methods)
+
+      set_methods = filter(lambda x: object_name+'_set_' in x, object_methods)
+      for method in set_methods:
+          if (method.split()[0] != 'uint_t'):
+              write_msg("-- ERROR: _set method does not return uint_t:", method )
+
+      other_methods = filter(lambda x: x not in new_methods, object_methods)
+      other_methods = filter(lambda x: x not in del_methods, other_methods)
+      other_methods = filter(lambda x: x not in    do_methods, other_methods)
+      other_methods = filter(lambda x: x not in get_methods, other_methods)
+      other_methods = filter(lambda x: x not in set_methods, other_methods)
+
+      if len(other_methods) > 0:
+          write_msg("-- WARNING: some methods for", object_name, "were unidentified")
+          for method in other_methods:
+              write_msg(method)
+
+
+      # generate this_object
+      short_name = object_name[len('aubio_'):]
+      if short_name in skip_objects:
+              write_msg("-- INFO: skipping object", short_name )
+              continue
+      if 1: #try:
+          s = gen_new_init(new_methods[0], short_name)
+          s += gen_do(do_methods[0], short_name) 
+          s += gen_members(new_methods[0], short_name)
+          s += gen_methods(get_methods, set_methods, short_name)
+          s += gen_finish(short_name)
+          generated_filepath = 'generated/gen-'+short_name+'.c'
+          fd = open(generated_filepath, 'w')
+          fd.write(s)
+      #except Exception, e:
+      #        write_msg("-- ERROR:", type(e), str(e), "in", short_name)
+      #        continue
+      generated_objects += [this_object]
+
+  s = """// generated list of objects created with generator.py
+
+"""
+
+  for each in generated_objects:
+      s += "extern PyTypeObject Py_%sType;\n" % \
+              each.replace('aubio_','').replace('_t','')
+
+  types_ready = []
+  for each in generated_objects:
+      types_ready.append("  PyType_Ready (&Py_%sType) < 0" % \
+              each.replace('aubio_','').replace('_t','') )
+
+  s += """
+  int
+  generated_types_ready (void)
+  {
+    return (
+  """
+  s += ('\n     ||').join(types_ready)
+  s += """);
+  }
+  """
+
+  s += """
+  void
+  add_generated_objects ( PyObject *m )
+  {"""
+  for each in generated_objects:
+      s += """  Py_INCREF (&Py_%(name)sType);
+    PyModule_AddObject (m, "%(name)s", (PyObject *) & Py_%(name)sType);""" % \
+            { 'name': ( each.replace('aubio_','').replace('_t','') ) }
+
+  s += """
+  }"""
+
+  fd = open('generated/aubio-generated.h', 'w')
+  fd.write(s)
+
+  from os import listdir
+  generated_files = listdir('generated')
+  generated_files = filter(lambda x: x.endswith('.c'), generated_files)
+  generated_files = ['generated/'+f for f in generated_files]
+  return generated_files
+
+if __name__ == '__main__':
+  generate_object_files() 
Index: python/py-cvec.c
===================================================================
--- python/py-cvec.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/py-cvec.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,302 @@
+#include "aubio-types.h"
+
+/* cvec type definition 
+
+class cvec():
+    def __init__(self, length = 1024):
+        self.length = length 
+        self.norm = array(length)
+        self.phas = array(length)
+
+*/
+
+static char Py_cvec_doc[] = "cvec object";
+
+static PyObject *
+Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int length= 0;
+  Py_cvec *self;
+  static char *kwlist[] = { "length", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+          &length)) {
+    return NULL;
+  }
+
+
+  self = (Py_cvec *) type->tp_alloc (type, 0);
+
+  self->length = Py_default_vector_length / 2 + 1;
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  if (length > 0) {
+    self->length = length / 2 + 1;
+  } else if (length < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative number of elements");
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+static int
+Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_cvec ((self->length - 1) * 2);
+  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");
+  if (format == NULL) {
+    goto fail;
+  }
+
+  args = Py_BuildValue ("I", self->length);
+  if (args == NULL) {
+    goto fail;
+  }
+  cvec_print ( self->o );
+
+  result = PyString_Format (format, args);
+
+fail:
+  Py_XDECREF (format);
+  Py_XDECREF (args);
+
+  return result;
+}
+
+PyObject *
+PyAubio_CvecNormToArray (Py_cvec * self)
+{
+  npy_intp dims[] = { self->o->length, 1 };
+  return PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm);
+}
+
+
+PyObject *
+PyAubio_CvecPhasToArray (Py_cvec * self)
+{
+  npy_intp dims[] = { self->o->length, 1 };
+  return PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas);
+}
+
+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)
+{
+  PyArrayObject * 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 ((PyArrayObject *)input) == 0) {
+      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+      goto fail;
+    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
+      PyErr_SetString (PyExc_ValueError,
+          "input array has more than two dimensions");
+      goto fail;
+    }
+
+    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float");
+      goto fail;
+    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      goto fail;
+    }
+    array = (PyArrayObject *)input;
+
+    // check input array dimensions
+    if (PyArray_NDIM (array) != 1) {
+      PyErr_Format (PyExc_ValueError,
+          "input array has %d dimensions, not 1",
+          PyArray_NDIM (array));
+      goto fail;
+    } else {
+      if (vec->o->length != PyArray_SIZE (array)) {
+          PyErr_Format (PyExc_ValueError,
+                  "input array has length %d, but cvec has length %d",
+                  (int)PyArray_SIZE (array), vec->o->length);
+          goto fail;
+      }
+    }
+
+    vec->o->norm = (smpl_t *) PyArray_GETPTR1 (array, 0);
+
+  } 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)
+{
+  PyArrayObject * 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 ((PyArrayObject *)input) == 0) {
+      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+      goto fail;
+    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
+      PyErr_SetString (PyExc_ValueError,
+          "input array has more than two dimensions");
+      goto fail;
+    }
+
+    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float");
+      goto fail;
+    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+      PyErr_SetString (PyExc_ValueError, "input array should be float32");
+      goto fail;
+    }
+    array = (PyArrayObject *)input;
+
+    // check input array dimensions
+    if (PyArray_NDIM (array) != 1) {
+      PyErr_Format (PyExc_ValueError,
+          "input array has %d dimensions, not 1",
+          PyArray_NDIM (array));
+      goto fail;
+    } else {
+      if (vec->o->length != PyArray_SIZE (array)) {
+          PyErr_Format (PyExc_ValueError,
+                  "input array has length %d, but cvec has length %d",
+                  (int)PyArray_SIZE (array), vec->o->length);
+          goto fail;
+      }
+    }
+
+    vec->o->phas = (smpl_t *) PyArray_GETPTR1 (array, 0);
+
+  } else {
+    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
+    return 1;
+  }
+
+  Py_INCREF(array);
+  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"},
+  {NULL}                        /* Sentinel */
+};
+
+static PyMethodDef Py_cvec_methods[] = {
+  {NULL}
+};
+
+static PyGetSetDef Py_cvec_getseters[] = {
+  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
+      "Numpy vector of shape (length,) containing the magnitude",
+      NULL},
+  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
+      "Numpy vector of shape (length,) containing the phase",
+      NULL},
+  {NULL} /* sentinel */
+};
+
+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      */
+  0, //&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            */
+};
Index: python/py-fft.c
===================================================================
--- python/py-fft.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/py-fft.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,107 @@
+#include "aubiowraphell.h"
+
+static char Py_fft_doc[] = "fft object";
+
+AUBIO_DECLARE(fft, uint_t win_s)
+
+//AUBIO_NEW(fft)
+static PyObject *
+Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int win_s = 0;
+  Py_fft *self;
+  static char *kwlist[] = { "win_s", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+          &win_s)) {
+    return NULL;
+  }
+
+  self = (Py_fft *) type->tp_alloc (type, 0);
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->win_s = Py_default_vector_length;
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  if (win_s > 0) {
+    self->win_s = win_s;
+  } else if (win_s < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative window size");
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+
+AUBIO_INIT(fft, self->win_s)
+
+AUBIO_DEL(fft)
+
+static PyObject * 
+Py_fft_do(PyObject * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+  cvec_t *output;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  output = new_cvec(((Py_fft *) self)->win_s);
+
+  // compute the function
+  aubio_fft_do (((Py_fft *)self)->o, vec, output);
+  return (PyObject *)PyAubio_CCvecToPyCvec(output);
+}
+
+AUBIO_MEMBERS_START(fft) 
+  {"win_s", T_INT, offsetof (Py_fft, win_s), READONLY,
+    "size of the window"},
+AUBIO_MEMBERS_STOP(fft)
+
+static PyObject * 
+Py_fft_rdo(Py_fft * self, PyObject * args)
+{
+  PyObject *input;
+  cvec_t *vec;
+  fvec_t *output;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCCvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  output = new_fvec(self->win_s);
+
+  // compute the function
+  aubio_fft_rdo (((Py_fft *)self)->o, vec, output);
+  return (PyObject *)PyAubio_CFvecToArray(output);
+}
+
+static PyMethodDef Py_fft_methods[] = {
+  {"rdo", (PyCFunction) Py_fft_rdo, METH_VARARGS,
+    "synthesis of spectral grain"},
+  {NULL}
+};
+
+AUBIO_TYPEOBJECT(fft, "aubio.fft")
Index: python/py-filter.c
===================================================================
--- python/py-filter.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/py-filter.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,198 @@
+#include "aubio-types.h"
+
+typedef struct
+{
+  PyObject_HEAD
+  aubio_filter_t * o;
+  uint_t order;
+} Py_filter;
+
+static char Py_filter_doc[] = "filter object";
+
+static PyObject *
+Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int order= 0;
+  Py_filter *self;
+  static char *kwlist[] = { "order", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+          &order)) {
+    return NULL;
+  }
+
+  self = (Py_filter *) type->tp_alloc (type, 0);
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->order = 7;
+
+  if (order > 0) {
+    self->order = order;
+  } else if (order < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative order");
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+static int
+Py_filter_init (Py_filter * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_aubio_filter (self->order);
+  if (self->o == NULL) {
+    return -1;
+  }
+
+  return 0;
+}
+
+static void
+Py_filter_del (Py_filter * self)
+{
+  del_aubio_filter (self->o);
+  self->ob_type->tp_free ((PyObject *) self);
+}
+
+static PyObject * 
+Py_filter_do(Py_filter * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+
+  if (!PyArg_ParseTuple (args, "O:digital_filter.do", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  // compute the function
+  fvec_t * out = new_fvec(vec->length);
+  aubio_filter_do_outplace (self->o, vec, out);
+  return PyAubio_CFvecToArray(out);
+}
+
+static PyObject * 
+Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
+{
+  uint_t err = 0;
+  uint_t samplerate;
+  if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+    return NULL;
+  }
+
+  err = aubio_filter_set_c_weighting (self->o, samplerate);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to C-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject * 
+Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
+{
+  uint_t err = 0;
+  uint_t samplerate;
+  if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+    return NULL;
+  }
+
+  err = aubio_filter_set_a_weighting (self->o, samplerate);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to A-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject *
+Py_filter_set_biquad(Py_filter * self, PyObject *args)
+{
+  uint_t err = 0;
+  lsmp_t b0, b1, b2, a1, a2;
+  if (!PyArg_ParseTuple (args, "ddddd", &b0, &b1, &b2, &a1, &a2)) {
+    return NULL;
+  }
+
+  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");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyMemberDef Py_filter_members[] = {
+  // TODO remove READONLY flag and define getter/setter
+  {"order", T_INT, offsetof (Py_filter, order), READONLY,
+      "order of the filter"},
+  {NULL}                        /* Sentinel */
+};
+
+static PyMethodDef Py_filter_methods[] = {
+  {"set_c_weighting", (PyCFunction) Py_filter_set_c_weighting, METH_VARARGS,
+      "set filter coefficients to C-weighting"},
+  {"set_a_weighting", (PyCFunction) Py_filter_set_a_weighting, METH_VARARGS,
+      "set filter coefficients to A-weighting"},
+  {"set_biquad", (PyCFunction) Py_filter_set_biquad, METH_VARARGS,
+      "set b0, b1, b2, a1, a2 biquad coefficients"},
+  {NULL}
+};
+
+PyTypeObject Py_filterType = {
+  PyObject_HEAD_INIT (NULL)
+  0,                            /* ob_size           */
+  "aubio.digital_filter",       /* tp_name           */
+  sizeof (Py_filter),           /* tp_basicsize      */
+  0,                            /* tp_itemsize       */
+  (destructor) Py_filter_del,   /* tp_dealloc        */
+  0,                            /* tp_print          */
+  0,                            /* tp_getattr        */
+  0,                            /* tp_setattr        */
+  0,                            /* tp_compare        */
+  0, //(reprfunc) Py_filter_repr,    /* tp_repr           */
+  0,                            /* tp_as_number      */
+  0,                            /* tp_as_sequence    */
+  0,                            /* tp_as_mapping     */
+  0,                            /* tp_hash           */
+  (ternaryfunc)Py_filter_do,    /* tp_call           */
+  0,                            /* tp_str            */
+  0,                            /* tp_getattro       */
+  0,                            /* tp_setattro       */
+  0,                            /* tp_as_buffer      */
+  Py_TPFLAGS_DEFAULT,           /* tp_flags          */
+  Py_filter_doc,                /* tp_doc            */
+  0,                            /* tp_traverse       */
+  0,                            /* tp_clear          */
+  0,                            /* tp_richcompare    */
+  0,                            /* tp_weaklistoffset */
+  0,                            /* tp_iter           */
+  0,                            /* tp_iternext       */
+  Py_filter_methods,            /* tp_methods        */
+  Py_filter_members,            /* tp_members        */
+  0,                            /* tp_getset         */
+  0,                            /* tp_base           */
+  0,                            /* tp_dict           */
+  0,                            /* tp_descr_get      */
+  0,                            /* tp_descr_set      */
+  0,                            /* tp_dictoffset     */
+  (initproc) Py_filter_init,    /* tp_init           */
+  0,                            /* tp_alloc          */
+  Py_filter_new,                /* tp_new            */
+};
Index: python/py-filterbank.c
===================================================================
--- python/py-filterbank.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/py-filterbank.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,183 @@
+#include "aubiowraphell.h"
+
+static char Py_filterbank_doc[] = "filterbank object";
+
+AUBIO_DECLARE(filterbank, uint_t n_filters; uint_t win_s)
+
+//AUBIO_NEW(filterbank)
+static PyObject *
+Py_filterbank_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int win_s = 0, n_filters = 0;
+  Py_filterbank *self;
+  static char *kwlist[] = { "n_filters", "win_s", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
+          &n_filters, &win_s)) {
+    return NULL;
+  }
+
+  self = (Py_filterbank *) type->tp_alloc (type, 0);
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->win_s = Py_default_vector_length;
+  if (win_s > 0) {
+    self->win_s = win_s;
+  } else if (win_s < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative window size");
+    return NULL;
+  }
+
+  self->n_filters = 40;
+  if (n_filters > 0) {
+    self->n_filters = n_filters;
+  } else if (n_filters < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative number of filters");
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+
+AUBIO_INIT(filterbank, self->n_filters, self->win_s)
+
+AUBIO_DEL(filterbank)
+
+static PyObject *
+Py_filterbank_do(Py_filterbank * self, PyObject * args)
+{
+  PyObject *input;
+  cvec_t *vec;
+  fvec_t *out;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCCvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  out = new_fvec (self->n_filters);
+
+  // compute the function
+  aubio_filterbank_do (self->o, vec, out);
+  return (PyObject *)PyAubio_CFvecToArray(out);
+}
+
+AUBIO_MEMBERS_START(filterbank)
+  {"win_s", T_INT, offsetof (Py_filterbank, win_s), READONLY,
+    "size of the window"},
+  {"n_filters", T_INT, offsetof (Py_filterbank, n_filters), READONLY,
+    "number of filters"},
+AUBIO_MEMBERS_STOP(filterbank)
+
+static PyObject *
+Py_filterbank_set_triangle_bands (Py_filterbank * self, PyObject *args)
+{
+  uint_t err = 0;
+
+  PyObject *input;
+  uint_t samplerate;
+  fvec_t *freqs;
+  if (!PyArg_ParseTuple (args, "OI", &input, &samplerate)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  freqs = PyAubio_ArrayToCFvec (input);
+
+  if (freqs == NULL) {
+    return NULL;
+  }
+
+  err = aubio_filterbank_set_triangle_bands (self->o,
+      freqs, samplerate);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to A-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject *
+Py_filterbank_set_mel_coeffs_slaney (Py_filterbank * self, PyObject *args)
+{
+  uint_t err = 0;
+
+  uint_t samplerate;
+  if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+    return NULL;
+  }
+
+  err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter to A-weighting");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject *
+Py_filterbank_set_coeffs (Py_filterbank * self, PyObject *args)
+{
+  uint_t err = 0;
+
+  PyObject *input;
+  fmat_t *coeffs;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  coeffs = PyAubio_ArrayToCFmat (input);
+
+  if (coeffs == NULL) {
+    PyErr_SetString (PyExc_ValueError,
+        "unable to parse input array");
+    return NULL;
+  }
+
+  err = aubio_filterbank_set_coeffs (self->o, coeffs);
+
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "error when setting filter coefficients");
+    return NULL;
+  }
+  return Py_None;
+}
+
+static PyObject *
+Py_filterbank_get_coeffs (Py_filterbank * self, PyObject *unused)
+{
+  return (PyObject *)PyAubio_CFmatToArray(
+      aubio_filterbank_get_coeffs (self->o) );
+}
+
+static PyMethodDef Py_filterbank_methods[] = {
+  {"set_triangle_bands", (PyCFunction) Py_filterbank_set_triangle_bands,
+    METH_VARARGS, "set coefficients of filterbanks"},
+  {"set_mel_coeffs_slaney", (PyCFunction) Py_filterbank_set_mel_coeffs_slaney,
+    METH_VARARGS, "set coefficients of filterbank as in Auditory Toolbox"},
+  {"get_coeffs", (PyCFunction) Py_filterbank_get_coeffs,
+    METH_NOARGS, "get coefficients of filterbank"},
+  {"set_coeffs", (PyCFunction) Py_filterbank_set_coeffs,
+    METH_VARARGS, "set coefficients of filterbank"},
+  {NULL}
+};
+
+AUBIO_TYPEOBJECT(filterbank, "aubio.filterbank")
Index: python/py-phasevoc.c
===================================================================
--- python/py-phasevoc.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/py-phasevoc.c	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,118 @@
+#include "aubiowraphell.h"
+
+static char Py_pvoc_doc[] = "pvoc object";
+
+AUBIO_DECLARE(pvoc, uint_t win_s; uint_t hop_s)
+
+//AUBIO_NEW(pvoc)
+static PyObject *
+Py_pvoc_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+  int win_s = 0, hop_s = 0;
+  Py_pvoc *self;
+  static char *kwlist[] = { "win_s", "hop_s", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
+          &win_s, &hop_s)) {
+    return NULL;
+  }
+
+  self = (Py_pvoc *) type->tp_alloc (type, 0);
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->win_s = Py_default_vector_length;
+  self->hop_s = Py_default_vector_length/2;
+
+  if (self == NULL) {
+    return NULL;
+  }
+
+  if (win_s > 0) {
+    self->win_s = win_s;
+  } else if (win_s < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative window size");
+    return NULL;
+  }
+
+  if (hop_s > 0) {
+    self->hop_s = hop_s;
+  } else if (hop_s < 0) {
+    PyErr_SetString (PyExc_ValueError,
+        "can not use negative hop size");
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+
+AUBIO_INIT(pvoc, self->win_s, self->hop_s)
+
+AUBIO_DEL(pvoc)
+
+static PyObject * 
+Py_pvoc_do(Py_pvoc * self, PyObject * args)
+{
+  PyObject *input;
+  fvec_t *vec;
+  cvec_t *output;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCFvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  output = new_cvec(self->win_s);
+
+  // compute the function
+  aubio_pvoc_do (self->o, vec, output);
+  return (PyObject *)PyAubio_CCvecToPyCvec(output);
+}
+
+AUBIO_MEMBERS_START(pvoc) 
+  {"win_s", T_INT, offsetof (Py_pvoc, win_s), READONLY,
+    "size of the window"},
+  {"hop_s", T_INT, offsetof (Py_pvoc, hop_s), READONLY,
+    "size of the hop"},
+AUBIO_MEMBERS_STOP(pvoc)
+
+static PyObject * 
+Py_pvoc_rdo(Py_pvoc * self, PyObject * args)
+{
+  PyObject *input;
+  cvec_t *vec;
+  fvec_t *output;
+
+  if (!PyArg_ParseTuple (args, "O", &input)) {
+    return NULL;
+  }
+
+  vec = PyAubio_ArrayToCCvec (input);
+
+  if (vec == NULL) {
+    return NULL;
+  }
+
+  output = new_fvec(self->hop_s);
+
+  // compute the function
+  aubio_pvoc_rdo (self->o, vec, output);
+  return (PyObject *)PyAubio_CFvecToArray(output);
+}
+
+static PyMethodDef Py_pvoc_methods[] = {
+  {"rdo", (PyCFunction) Py_pvoc_rdo, METH_VARARGS,
+    "synthesis of spectral grain"},
+  {NULL}
+};
+
+AUBIO_TYPEOBJECT(pvoc, "aubio.pvoc")
Index: python/run_all_tests
===================================================================
--- python/run_all_tests	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/run_all_tests	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+
+if __name__ == '__main__':
+  import os, sys, unittest
+  def load_test():
+    # get relevant files
+    curdir = os.path.dirname(sys.argv[0])
+    if curdir == '': curdir = '.'
+    files = os.listdir(curdir)
+    modfiles = filter (lambda y: y.endswith('.py'), files) 
+    modfiles = filter (lambda f: f.startswith('test_'), modfiles)
+    # get module names
+    modnames = map (lambda x: os.path.splitext(x)[0], modfiles)
+    # import them
+    modules = map (__import__, modnames)
+    # create a test suites from the imported module
+    load_from_module = unittest.defaultTestLoader.loadTestsFromModule
+    tests = map(load_from_module, modules)
+    return unittest.TestSuite(tests)
+  unittest.main(defaultTest = 'load_test')
Index: python/setup.py
===================================================================
--- python/setup.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/setup.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,41 @@
+#! /usr/bin/python
+
+from distutils.core import setup, Extension
+from generator import generate_object_files
+import os.path
+import numpy
+
+library_dirs = ['../build/src', '../src/.libs']
+include_dirs = ['../build/src', '../src', '.' ]
+library_dirs = filter (lambda x: os.path.isdir(x), library_dirs)
+include_dirs = filter (lambda x: os.path.isdir(x), include_dirs)
+
+aubio_extension = Extension("_aubio",
+            ["aubiomodule.c",
+            "aubioproxy.c",
+            "py-cvec.c",
+            # example without macro
+            "py-filter.c",
+            # macroised
+            "py-filterbank.c",
+            "py-fft.c",
+            "py-phasevoc.c",
+            # generated files
+            ] + generate_object_files(),
+            include_dirs = include_dirs + [ numpy.get_include() ],
+            library_dirs = library_dirs,
+            libraries=['aubio'])
+
+setup(name='aubio',
+      version = '0.4.0alpha',
+      packages = ['aubio'],
+      description = 'interface to the aubio library',
+      long_description = 'interface to the aubio library',
+      license = 'GNU/GPL version 3',
+      author = 'Paul Brossier',
+      author_email = 'piem@aubio.org',
+      maintainer = 'Paul Brossier',
+      maintainer_email = 'piem@aubio.org',
+      url = 'http://aubio.org/',
+      ext_modules = [aubio_extension])
+
Index: python/test_aubio.py
===================================================================
--- python/test_aubio.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_aubio.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,14 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+
+class aubiomodule_test_case(TestCase):
+
+  def test_import(self):
+    """ try importing aubio """
+    import aubio 
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_cvec.py
===================================================================
--- python/test_cvec.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_cvec.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,50 @@
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+from aubio import cvec
+from numpy import array, shape, pi
+
+class aubio_cvec_test_case(TestCase):
+
+    def test_vector_created_with_zeroes(self):
+        a = cvec(10)
+        a
+        shape(a.norm)
+        shape(a.phas)
+        a.norm[0]
+        assert_equal(a.norm, 0.)
+        assert_equal(a.phas, 0.)
+
+    def test_vector_assign_element(self):
+        a = cvec()
+        a.norm[0] = 1
+        assert_equal(a.norm[0], 1)
+        a.phas[0] = 1
+        assert_equal(a.phas[0], 1)
+
+    def test_vector_assign_element_end(self):
+        a = cvec()
+        a.norm[-1] = 1
+        assert_equal(a.norm[-1], 1)
+        assert_equal(a.norm[len(a.norm)-1], 1)
+        a.phas[-1] = 1
+        assert_equal(a.phas[-1], 1)
+        assert_equal(a.phas[len(a.phas)-1], 1)
+
+    def test_assign_cvec_norm_slice(self):
+        spec = cvec(1024)
+        spec.norm[40:100] = 100
+        assert_equal (spec.norm[0:40], 0)
+        assert_equal (spec.norm[40:100], 100)
+        assert_equal (spec.norm[100:-1], 0)
+        assert_equal (spec.phas, 0)
+
+    def test_assign_cvec_phas_slice(self):
+        spec = cvec(1024)
+        spec.phas[39:-1] = -pi
+        assert_equal (spec.phas[0:39], 0)
+        assert_equal (spec.phas[39:-1], -pi)
+        assert_equal (spec.norm, 0)
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
Index: python/test_fft.py
===================================================================
--- python/test_fft.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_fft.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,113 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+# WARNING: numpy also has an fft object
+from aubio import fvec, fft, cvec
+from numpy import array, shape
+from math import pi
+
+class aubio_fft_test_case(TestCase):
+
+  def test_members(self):
+    f = fft()
+    assert_equal (f.win_s, 1024)
+
+  def test_output_dimensions(self):
+    """ check the dimensions of output """
+    win_s = 1024
+    timegrain = fvec(win_s)
+    f = fft(win_s)
+    fftgrain = f (timegrain)
+    assert_equal (fftgrain.norm, 0)
+    assert_equal (shape(fftgrain.norm), (win_s/2+1,))
+    assert_equal (fftgrain.phas, 0)
+    assert_equal (shape(fftgrain.phas), (win_s/2+1,))
+
+  def test_zeros(self):
+    """ check the transform of zeros """
+    win_s = 512
+    timegrain = fvec(win_s)
+    f = fft(win_s)
+    fftgrain = f(timegrain)
+    assert_equal ( fftgrain.norm == 0, True )
+    assert_equal ( fftgrain.phas == 0, True )
+
+  def test_impulse(self):
+    """ check the transform of one impulse at a random place """
+    from random import random
+    from math import floor
+    win_s = 256
+    i = floor(random()*win_s)
+    impulse = pi * random() 
+    f = fft(win_s)
+    timegrain = fvec(win_s)
+    timegrain[i] = impulse 
+    fftgrain = f ( timegrain )
+    #self.plot_this ( fftgrain.phas )
+    assert_almost_equal ( fftgrain.norm, impulse, decimal = 6 )
+    assert_equal ( fftgrain.phas <= pi, True)
+    assert_equal ( fftgrain.phas >= -pi, True)
+
+  def test_impulse_negative(self):
+    """ check the transform of one impulse at a random place """
+    from random import random
+    from math import floor
+    win_s = 256
+    i = 0 
+    impulse = -10. 
+    f = fft(win_s)
+    timegrain = fvec(win_s)
+    timegrain[i] = impulse 
+    fftgrain = f ( timegrain )
+    #self.plot_this ( fftgrain.phas )
+    assert_almost_equal ( fftgrain.norm, abs(impulse), decimal = 6 )
+    if impulse < 0:
+      # phase can be pi or -pi, as it is not unwrapped
+      assert_almost_equal ( abs(fftgrain.phas[1:-1]) , pi, decimal = 6 )
+      assert_almost_equal ( fftgrain.phas[0], pi, decimal = 6)
+      assert_almost_equal ( fftgrain.phas[-1], pi, decimal = 6)
+    else:
+      assert_equal ( fftgrain.phas[1:-1] == 0, True)
+      assert_equal ( fftgrain.phas[0] == 0, True)
+      assert_equal ( fftgrain.phas[-1] == 0, True)
+    # now check the resynthesis
+    synthgrain = f.rdo ( fftgrain )
+    #self.plot_this ( fftgrain.phas.T )
+    assert_equal ( fftgrain.phas <= pi, True)
+    assert_equal ( fftgrain.phas >= -pi, True)
+    #self.plot_this ( synthgrain - timegrain )
+    assert_almost_equal ( synthgrain, timegrain, decimal = 6 )
+
+  def test_impulse_at_zero(self):
+    """ check the transform of one impulse at a index 0 """
+    win_s = 1024
+    impulse = pi
+    f = fft(win_s)
+    timegrain = fvec(win_s)
+    timegrain[0] = impulse 
+    fftgrain = f ( timegrain )
+    #self.plot_this ( fftgrain.phas )
+    assert_equal ( fftgrain.phas[0], 0)
+    # could be 0 or -0 depending on fft implementation (0 for fftw3, -0 for ooura)
+    assert_almost_equal ( fftgrain.phas[1], 0)
+    assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
+
+  def test_rdo_before_do(self):
+    """ check running fft.rdo before fft.do works """
+    win_s = 1024
+    impulse = pi
+    f = fft(win_s)
+    fftgrain = cvec(win_s)
+    t = f.rdo( fftgrain )
+    assert_equal ( t, 0 )
+
+  def plot_this(self, this):
+    from pylab import plot, show
+    plot ( this )
+    show ()
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_filter.py
===================================================================
--- python/test_filter.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_filter.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import fvec, digital_filter
+from numpy import array
+
+def array_from_text_file(filename, dtype = 'float'):
+  return array([line.split() for line in open(filename).readlines()], 
+      dtype = dtype)
+
+class aubio_filter_test_case(TestCase):
+
+  def test_members(self):
+    f = digital_filter()
+    assert_equal (f.order, 7)
+    f = digital_filter(5)
+    assert_equal (f.order, 5)
+    f(fvec())
+  
+  def test_cweighting_error(self):
+    f = digital_filter (2)
+    self.assertRaises ( ValueError, f.set_c_weighting, 44100 )
+    f = digital_filter (8)
+    self.assertRaises ( ValueError, f.set_c_weighting, 44100 )
+    f = digital_filter (5)
+    self.assertRaises ( ValueError, f.set_c_weighting, 4000 )
+    f = digital_filter (5)
+    self.assertRaises ( ValueError, f.set_c_weighting, 193000 )
+    f = digital_filter (7)
+    self.assertRaises ( ValueError, f.set_a_weighting, 193000 )
+    f = digital_filter (5)
+    self.assertRaises ( ValueError, f.set_a_weighting, 192000 )
+
+  def test_c_weighting(self):
+    expected = array_from_text_file('c_weighting_test_simple.expected')
+    f = digital_filter(5)
+    f.set_c_weighting(44100)
+    v = fvec(32)
+    v[12] = .5
+    u = f(v)
+    assert_almost_equal (expected[1], u)
+
+  def test_a_weighting(self):
+    expected = array_from_text_file('a_weighting_test_simple.expected')
+    f = digital_filter(7)
+    f.set_a_weighting(44100)
+    v = fvec(32)
+    v[12] = .5
+    u = f(v)
+    assert_almost_equal (expected[1], u)
+
+  def test_a_weighting_parted(self):
+    expected = array_from_text_file('a_weighting_test_simple.expected')
+    f = digital_filter(7)
+    f.set_a_weighting(44100)
+    v = fvec(16)
+    v[12] = .5
+    u = f(v)
+    assert_almost_equal (expected[1][:16], u)
+    # one more time
+    v = fvec(16)
+    u = f(v)
+    assert_almost_equal (expected[1][16:], u)
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_filterbank.py
===================================================================
--- python/test_filterbank.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_filterbank.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,23 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+from numpy import random
+from aubio import cvec, filterbank
+
+class aubio_filterbank_test_case(TestCase):
+
+  def test_members(self):
+    f = filterbank(40, 512)
+    assert_equal ([f.n_filters, f.win_s], [40, 512])
+
+  def test_set_coeffs(self):
+    f = filterbank(40, 512)
+    r = random.random([40, 512 / 2 + 1]).astype('float32')
+    f.set_coeffs(r)
+    assert_equal (r, f.get_coeffs())
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_filterbank_mel.py
===================================================================
--- python/test_filterbank_mel.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_filterbank_mel.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,51 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+from numpy import array, shape
+from aubio import cvec, filterbank
+
+class aubio_filterbank_mel_test_case(TestCase):
+
+  def test_slaney(self):
+    f = filterbank(40, 512)
+    f.set_mel_coeffs_slaney(16000)
+    a = f.get_coeffs()
+    assert_equal(shape (a), (40, 512/2 + 1) )
+
+  def test_other_slaney(self):
+    f = filterbank(40, 512*2)
+    f.set_mel_coeffs_slaney(44100)
+    a = f.get_coeffs()
+    #print "sum is", sum(sum(a))
+    for win_s in [256, 512, 1024, 2048, 4096]:
+      f = filterbank(40, win_s)
+      f.set_mel_coeffs_slaney(320000)
+      a = f.get_coeffs()
+      #print "sum is", sum(sum(a))
+
+  def test_triangle_freqs_zeros(self):
+    f = filterbank(9, 1024)
+    freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
+    freqs = array(freq_list, dtype = 'float32')
+    f.set_triangle_bands(freqs, 48000)
+    f.get_coeffs().T
+    assert_equal ( f(cvec(1024)), 0)
+
+  def test_triangle_freqs_ones(self):
+    f = filterbank(9, 1024)
+    freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
+    freqs = array(freq_list, dtype = 'float32')
+    f.set_triangle_bands(freqs, 48000)
+    f.get_coeffs().T
+    spec = cvec(1024)
+    spec.norm[:] = 1
+    assert_almost_equal ( f(spec),
+            [ 0.02070313,  0.02138672,  0.02127604,  0.02135417, 
+        0.02133301, 0.02133301,  0.02133311,  0.02133334,  0.02133345])
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
+
Index: python/test_fvec.py
===================================================================
--- python/test_fvec.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_fvec.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,135 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+from aubio import fvec, zero_crossing_rate, alpha_norm, min_removal
+from numpy import array, shape
+
+class aubio_fvec_test_case(TestCase):
+
+    def test_vector_created_with_zeroes(self):
+        a = fvec(10)
+        a
+        shape(a)
+        a[0]
+        #del a
+        assert_equal(array(a), 0.)
+
+    def test_vector_create_with_list(self):
+        a = fvec([0,1,2,3])
+        assert_equal (range(4), a)
+
+    def test_vector_assign_element(self):
+        a = fvec()
+        a[0] = 1
+        assert_equal(a[0], 1)
+
+    def test_vector_assign_element_end(self):
+        a = fvec()
+        a[-1] = 1
+        assert_equal(a[-1], 1)
+        assert_equal(a[len(a)-1], 1)
+
+    def test_vector(self):
+        a = fvec()
+        a, len(a) #a.length
+        a[0]
+        array(a)
+        a = fvec(10)
+        a = fvec(1)
+        a.T
+        array(a).T
+        a = range(len(a))
+
+    def test_wrong_values(self):
+        self.assertRaises (ValueError, fvec, -10)
+  
+        a = fvec(2)
+        self.assertRaises (IndexError, a.__getitem__, 3)
+        self.assertRaises (IndexError, a.__getitem__, 2)
+
+    def test_alpha_norm_of_fvec(self):
+        a = fvec(2)
+        self.assertEquals (alpha_norm(a, 1), 0)
+        a[0] = 1
+        self.assertEquals (alpha_norm(a, 1), 0.5)
+        a[1] = 1
+        self.assertEquals (alpha_norm(a, 1), 1)
+        a = array([0, 1], dtype='float32')
+        from math import sqrt
+        assert_almost_equal (alpha_norm(a, 2), sqrt(2)/2.)
+
+    def test_alpha_norm_of_none(self):
+        self.assertRaises (ValueError, alpha_norm, None, 1)
+
+    def test_alpha_norm_of_array_of_float32(self):
+        # check scalar fails
+        a = array(1, dtype = 'float32')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        # check 2d array fails
+        a = array([[2],[4]], dtype = 'float32')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        # check 1d array
+        a = array(range(10), dtype = 'float32')
+        self.assertEquals (alpha_norm(a, 1), 4.5)
+
+    def test_alpha_norm_of_array_of_int(self):
+        a = array(1, dtype = 'int')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        a = array([[[1,2],[3,4]]], dtype = 'int')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        a = array(range(10), dtype = 'int')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+
+    def test_alpha_norm_of_array_of_string (self):
+        a = "hello"
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+
+    def test_zero_crossing_rate(self):
+        a = array([0,1,-1], dtype='float32')
+        assert_almost_equal (zero_crossing_rate(a), 1./3. )
+        a = array([0.]*100, dtype='float32')
+        self.assertEquals (zero_crossing_rate(a), 0 )
+        a = array([-1.]*100, dtype='float32')
+        self.assertEquals (zero_crossing_rate(a), 0 )
+        a = array([1.]*100, dtype='float32')
+        self.assertEquals (zero_crossing_rate(a), 0 )
+
+    def test_alpha_norm_of_array_of_float64(self):
+        # check scalar fail
+        a = array(1, dtype = 'float64')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        # check 3d array fail
+        a = array([[[1,2],[3,4]]], dtype = 'float64')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        # check float64 1d array fail
+        a = array(range(10), dtype = 'float64')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+        # check float64 2d array fail
+        a = array([range(10), range(10)], dtype = 'float64')
+        self.assertRaises (ValueError, alpha_norm, a, 1)
+
+    def test_fvec_min_removal_of_array(self):
+        a = array([20,1,19], dtype='float32')
+        b = min_removal(a)
+        assert_equal (array(b), [19, 0, 18])
+        assert_equal (b, [19, 0, 18])
+        assert_equal (a, b)
+        a[0] = 0
+        assert_equal (a, b)
+
+    def test_fvec_min_removal_of_array_float64(self):
+        a = array([20,1,19], dtype='float64')
+        self.assertRaises (ValueError, min_removal, a)
+
+    def test_fvec_min_removal_of_fvec(self):
+        a = fvec(3)
+        a = array([20, 1, 19], dtype = 'float32')
+        b = min_removal(a)
+        assert_equal (array(b), [19, 0, 18])
+        assert_equal (b, [19, 0, 18])
+        assert_equal (a, b)
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
Index: python/test_onset.py
===================================================================
--- python/test_onset.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_onset.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+# WARNING: numpy also has an fft object
+from aubio import onset, cvec
+from numpy import array, shape, arange, zeros, log
+from math import pi
+
+class aubio_onset(TestCase):
+
+    def test_members(self):
+        o = onset()
+        assert_equal ([o.buf_size, o.hop_size, o.method, o.samplerate],
+            [1024,512,'default',44100])
+    
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
Index: python/test_peakpicker.py
===================================================================
--- python/test_peakpicker.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_peakpicker.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,115 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import peakpicker, fvec
+
+class aubio_peakpicker(TestCase):
+
+    def test_members(self):
+        o = peakpicker()
+
+    def test_peakpicker_zeroes(self):
+        o = peakpicker()
+        assert_equal(o.get_thresholded_input(), 0.)
+
+    def test_peakpick_set_threshold(self):
+        o = peakpicker()
+        new_threshold = threshold 
+        o.set_threshold(new_threshold)
+        assert_almost_equal(new_threshold, o.get_threshold())
+
+    def test_peakpicker_get_threshold(self):
+        o = peakpicker()
+        new_threshold = o.get_threshold() 
+        o.set_threshold(new_threshold)
+        assert_equal(new_threshold, o.get_threshold())
+
+buf_size = 1024
+slice_size = 5
+delay = 1
+threshold = .9
+
+class aubio_peakpicker_peaks(TestCase):
+
+    def setUp(self):
+        self.o = peakpicker()
+        self.o.set_threshold (threshold)
+        self.vec = fvec(buf_size)
+
+    def test_peakpicker_impulse(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a] = 1000.
+        self.peaks = [a]
+
+    def test_peakpicker_ramp_up(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a]   = 1000. / 4. * 1.
+        vec[a+1] = 1000. / 4. * 2.
+        vec[a+2] = 1000. / 4. * 3.
+        vec[a+3] = 1000.
+        self.peaks = [a+1]
+
+    def test_peakpicker_ramp_down(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a]   = 1000.
+        vec[a+1] = 1000. / 4. * 3.
+        vec[a+2] = 1000. / 4. * 2.
+        vec[a+3] = 1000. / 4. * 1.
+        self.peaks = [a]
+
+    def test_peakpicker_plateau(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a]   = 1000. / 2
+        vec[a+1] = 1000.
+        vec[a+2] = 1000.
+        vec[a+3] = 1000.
+        vec[a+4] = 1000. / 2
+        self.peaks = [a+1]
+
+    def test_peakpicker_consecutive_peaks(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a]   = 1000. / 2
+        vec[a+1] = 1000.
+        vec[a+3] = 1000.
+        vec[a+4] = 1000. / 2
+        self.peaks = [a]
+
+    def test_peakpicker_distant_peaks(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a] = 1000.
+        vec[a+7] = 1000.
+        self.peaks = [a, a+7]
+
+    def test_peakpicker_very_distant_peaks(self):
+        vec = self.vec; o = self.o
+        a = 345
+        vec[a] = 1000.
+        vec[a+67] = 1000.
+        self.peaks = [a, a+67]
+
+    def tearDown(self):
+        fpeaks = []
+        for index in range(0,buf_size-slice_size):
+            sliced = self.vec[index:index+slice_size]
+            findex = self.o(sliced)
+            if findex:
+              # we found a peak
+              fpeak = index - findex - delay
+              #print self.peaks, index, '-', findex, '-', delay, '=', fpeak
+              if not round(index - findex - delay) in self.peaks:
+                  self.fail('missing peak ' + str(fpeak))
+              fpeaks.append(fpeak)
+        if len(fpeaks) != len(self.peaks):
+            self.fail('some peaks of ' + str(self.peaks) + 'were not found, got only ' + str(fpeaks))
+        #print
+        #print fpeaks, self.peaks
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
Index: python/test_phasevoc.py
===================================================================
--- python/test_phasevoc.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_phasevoc.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, run_module_suite
+from numpy.testing import assert_equal, assert_almost_equal
+from aubio import fvec, cvec, pvoc
+from numpy import array, shape
+
+class aubio_pvoc_test_case(TestCase):
+
+  def test_members(self):
+    f = pvoc()
+    assert_equal ([f.win_s, f.hop_s], [1024, 512])
+    f = pvoc(2048, 128)
+    assert_equal ([f.win_s, f.hop_s], [2048, 128])
+
+  def test_zeros(self):
+    win_s, hop_s = 1024, 256
+    f = pvoc (win_s, hop_s)
+    t = fvec (hop_s)
+    for time in range( 4 * win_s / hop_s ):
+      s = f(t)
+      r = f.rdo(s)
+      assert_equal ( array(t), 0)
+      assert_equal ( s.norm, 0)
+      assert_equal ( s.phas, 0)
+      assert_equal ( r, 0)
+
+  def test_steps_two_channels(self):
+    """ check the resynthesis of steps is correct """
+    f = pvoc(1024, 512)
+    t1 = fvec(512)
+    t2 = fvec(512)
+    # positive step in first channel
+    t1[100:200] = .1
+    # positive step in second channel
+    t1[20:50] = -.1
+    s1 = f(t1)
+    r1 = f.rdo(s1)
+    s2 = f(t2)
+    r2 = f.rdo(s2)
+    #self.plot_this ( s1.norm.T )
+    assert_almost_equal ( t1, r2, decimal = 6 )
+    
+  def test_steps_three_random_channels(self):
+    from random import random
+    f = pvoc(64, 16)
+    t0 = fvec(16)
+    t1 = fvec(16)
+    for i in xrange(16):
+        t1[i] = random() * 2. - 1.
+    t2 = f.rdo(f(t1))
+    t2 = f.rdo(f(t0))
+    t2 = f.rdo(f(t0))
+    t2 = f.rdo(f(t0))
+    assert_almost_equal( t1, t2, decimal = 6 )
+    
+  def plot_this( self, this ):
+    from pylab import semilogy, show
+    semilogy ( this )
+    show ()
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_pitch.py
===================================================================
--- python/test_pitch.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_pitch.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,101 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase
+from numpy.testing import assert_equal, assert_almost_equal
+from numpy import random, sin, arange, mean, median
+from math import pi
+from aubio import fvec, pitch
+
+class aubio_mathutils_test_case(TestCase):
+
+  def test_members(self):
+    p = pitch()
+    assert_equal ( [p.method, p.buf_size, p.hop_size, p.samplerate],
+      ['default', 1024, 512, 44100])
+
+  def test_members_not_default(self):
+    p = pitch('mcomb', 2048, 512, 32000)
+    assert_equal ( [p.method, p.buf_size, p.hop_size, p.samplerate],
+      ['mcomb', 2048, 512, 32000])
+
+  def test_run_on_zeros(self):
+    p = pitch('mcomb', 2048, 512, 32000)
+    f = fvec (512)
+    assert_equal ( p(f), 0. )
+
+  def test_run_on_ones(self):
+    p = pitch('mcomb', 2048, 512, 32000)
+    f = fvec (512)
+    f[:] = 1
+    assert( p(f) != 0. )
+
+  def test_run_default_on_sinusoid(self):
+    method = 'default'
+    buf_size = 2048
+    hop_size = 512
+    samplerate = 32000
+    freq = 450.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def test_run_schmitt_on_sinusoid(self):
+    method = 'schmitt'
+    buf_size = 4096
+    hop_size = 512
+    samplerate = 44100
+    freq = 800.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def test_run_mcomb_on_sinusoid(self):
+    method = 'mcomb'
+    buf_size = 2048
+    hop_size = 512
+    samplerate = 44100
+    freq = 10000.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def test_run_fcomb_on_sinusoid(self):
+    method = 'fcomb'
+    buf_size = 2048
+    hop_size = 512
+    samplerate = 32000
+    freq = 440.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def test_run_yin_on_sinusoid(self):
+    method = 'yin'
+    buf_size = 4096
+    hop_size = 512
+    samplerate = 32000
+    freq = 880.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def test_run_yinfft_on_sinusoid(self):
+    method = 'yinfft'
+    buf_size = 2048
+    hop_size = 512
+    samplerate = 32000
+    freq = 640.
+    self.run_pitch_on_sinusoid(method, buf_size, hop_size, samplerate, freq)
+
+  def run_pitch_on_sinusoid(self, method, buf_size, hop_size, samplerate, freq):
+    p = pitch(method, buf_size, hop_size, samplerate)
+    sinvec = self.build_sinusoid(hop_size * 100, freq, samplerate)
+    self.run_pitch(p, sinvec, freq)
+
+  def build_sinusoid(self, length, freq, samplerate):
+    return sin( 2. * pi * arange(length).astype('float32') * freq / samplerate)
+
+  def run_pitch(self, p, input_vec, freq):
+    count = 0
+    pitches, errors = [], []
+    for vec_slice in input_vec.reshape((-1, p.hop_size)):
+      pitch = p(vec_slice)
+      pitches.append(pitch)
+      errors.append(1. - pitch / freq)
+    # check that the mean of all relative errors is less than 10%
+    assert_almost_equal (mean(errors), 0., decimal = 2)
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_source.py
===================================================================
--- python/test_source.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_source.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,27 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import fvec, source
+from numpy import array
+
+path = "/Users/piem/archives/sounds/loops/drum_Chocolate_Milk_-_Ation_Speaks_Louder_Than_Words.wav"
+
+class aubio_filter_test_case(TestCase):
+
+  def test_members(self):
+    f = source(path)
+    print dir(f)
+
+  def test_read(self):
+    f = source(path)
+    total_frames = 0
+    while True:
+      vec, read = f()
+      total_frames += read
+      if read < f.hop_size: break
+    print "read", total_frames / float(f.samplerate), " seconds from", path
+
+if __name__ == '__main__':
+  from unittest import main
+  main()
+
Index: python/test_specdesc.py
===================================================================
--- python/test_specdesc.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
+++ python/test_specdesc.py	(revision 25c9f9ac65ef6d0c66a90795f9b1fd6835e28d2c)
@@ -0,0 +1,238 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from numpy import random, arange, log, zeros
+from aubio import specdesc, cvec
+from math import pi
+
+methods = ["default",
+     "energy",
+     "hfc",
+     "complex",
+     "phase",
+     "specdiff",
+     "kl",
+     "mkl",
+     "specflux",
+     "centroid",
+     "spread",
+     "skewness",
+     "kurtosis",
+     "slope",
+     "decrease",
+     "rolloff"]
+buf_size = 2048
+
+class aubio_specdesc(TestCase):
+
+    def test_members(self):
+        o = specdesc()
+
+        for method in methods:
+          o = specdesc(method, buf_size)
+          assert_equal ([o.buf_size, o.method], [buf_size, method])
+
+          spec = cvec(buf_size)
+          spec.norm[0] = 1
+          spec.norm[1] = 1./2.
+          #print "%20s" % method, str(o(spec))
+          o(spec)
+          spec.norm = random.random_sample((len(spec.norm),)).astype('float32')
+          spec.phas = random.random_sample((len(spec.phas),)).astype('float32')
+          #print "%20s" % method, str(o(spec))
+          assert (o(spec) != 0.)
+
+    def test_hfc(self):
+        o = specdesc("hfc", buf_size)
+        spec = cvec(buf_size)
+        # hfc of zeros is zero
+        assert_equal (o(spec), 0.)
+        # hfc of ones is sum of all bin numbers
+        spec.norm[:] = 1
+        expected = sum(range(buf_size/2 + 2))
+        assert_equal (o(spec), expected)
+        # changing phase doesn't change anything
+        spec.phas[:] = 1
+        assert_equal (o(spec), sum(range(buf_size/2 + 2)))
+
+    def test_phase(self):
+        o = specdesc("phase", buf_size)
+        spec = cvec(buf_size)
+        # phase of zeros is zero
+        assert_equal (o(spec), 0.)
+        spec.phas = random.random_sample((len(spec.phas),)).astype('float32')
+        # phase of random is not zero
+        spec.norm[:] = 1
+        assert (o(spec) != 0.)
+
+    def test_specdiff(self):
+        o = specdesc("phase", buf_size)
+        spec = cvec(buf_size)
+        # specdiff of zeros is zero
+        assert_equal (o(spec), 0.)
+        spec.phas = random.random_sample((len(spec.phas),)).astype('float32')
+        # phase of random is not zero
+        spec.norm[:] = 1
+        assert (o(spec) != 0.)
+    
+    def test_hfc(self):
+        o = specdesc("hfc")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        assert_equal (a, c.norm)
+        assert_equal ( sum(a*(a+1)), o(c))
+
+    def test_complex(self):
+        o = specdesc("complex")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        assert_equal (a, c.norm)
+        # the previous run was on zeros, so previous frames are still 0
+        # so we have sqrt ( abs ( r2 ^ 2) ) == r2
+        assert_equal ( sum(a), o(c))
+        # second time. c.norm = a, so, r1 = r2, and the euclidian distance is 0
+        assert_equal ( 0, o(c))
+
+    def test_kl(self):
+        o = specdesc("kl")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        assert_almost_equal( sum(a * log(1.+ a/1.e-10 ) ) / o(c), 1., decimal=6)
+
+    def test_mkl(self):
+        o = specdesc("mkl")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        assert_almost_equal( sum(log(1.+ a/1.e-10 ) ) / o(c), 1, decimal=6)
+
+    def test_specflux(self):
+        o = specdesc("specflux")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        assert_equal( sum(a), o(c))
+        assert_equal( 0, o(c))
+        c.norm = zeros(c.length, dtype='float32')
+        assert_equal( 0, o(c))
+
+    def test_centroid(self):
+        o = specdesc("centroid")
+        c = cvec()
+        # make sure centroid of zeros is zero
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        centroid = sum(a*a) / sum(a)
+        assert_almost_equal (centroid, o(c), decimal = 2)
+
+        c.norm = a * .5 
+        assert_almost_equal (centroid, o(c), decimal = 2)
+
+    def test_spread(self):
+        o = specdesc("spread")
+        c = cvec(2048)
+        ramp = arange(c.length, dtype='float32')
+        assert_equal( 0., o(c))
+
+        a = ramp
+        c.norm = a
+        centroid = sum(a*a) / sum(a)
+        spread = sum( a * pow(ramp - centroid, 2.) ) / sum(a)
+        assert_almost_equal (o(c), spread, decimal = 1)
+
+    def test_skewness(self):
+        o = specdesc("skewness")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        centroid = sum(a*a) / sum(a)
+        spread = sum( (a - centroid)**2 *a) / sum(a)
+        skewness = sum( (a - centroid)**3 *a) / sum(a) / spread **1.5
+        assert_almost_equal (skewness, o(c), decimal = 2)
+
+        c.norm = a * 3
+        assert_almost_equal (skewness, o(c), decimal = 2)
+
+    def test_kurtosis(self):
+        o = specdesc("kurtosis")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length, dtype='float32')
+        c.norm = a
+        centroid = sum(a*a) / sum(a)
+        spread = sum( (a - centroid)**2 *a) / sum(a)
+        kurtosis = sum( (a - centroid)**4 *a) / sum(a) / spread **2
+        assert_almost_equal (kurtosis, o(c), decimal = 2)
+
+    def test_slope(self):
+        o = specdesc("slope")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length * 2, 0, -2, dtype='float32')
+        k = arange(c.length, dtype='float32')
+        c.norm = a
+        num = len(a) * sum(k*a) - sum(k)*sum(a)
+        den = (len(a) * sum(k**2) - sum(k)**2)
+        slope = num/den/sum(a)
+        assert_almost_equal (slope, o(c), decimal = 5)
+
+        a = arange(0, c.length * 2, +2, dtype='float32')
+        c.norm = a
+        num = len(a) * sum(k*a) - sum(k)*sum(a)
+        den = (len(a) * sum(k**2) - sum(k)**2)
+        slope = num/den/sum(a)
+        assert_almost_equal (slope, o(c), decimal = 5)
+
+        a = arange(0, c.length * 2, +2, dtype='float32')
+        c.norm = a * 2
+        assert_almost_equal (slope, o(c), decimal = 5)
+
+    def test_decrease(self):
+        o = specdesc("decrease")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length * 2, 0, -2, dtype='float32')
+        k = arange(c.length, dtype='float32')
+        c.norm = a
+        decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:]) 
+        assert_almost_equal (decrease, o(c), decimal = 5)
+
+        a = arange(0, c.length * 2, +2, dtype='float32')
+        c.norm = a
+        decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:]) 
+        assert_almost_equal (decrease, o(c), decimal = 5)
+
+        a = arange(0, c.length * 2, +2, dtype='float32')
+        c.norm = a * 2
+        decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:]) 
+        assert_almost_equal (decrease, o(c), decimal = 5)
+
+    def test_rolloff(self):
+        o = specdesc("rolloff")
+        c = cvec()
+        assert_equal( 0., o(c))
+        a = arange(c.length * 2, 0, -2, dtype='float32')
+        k = arange(c.length, dtype='float32')
+        c.norm = a
+        cumsum = .95*sum(a*a)
+        i = 0; rollsum = 0
+        while rollsum < cumsum:
+          rollsum += a[i]*a[i]
+          i+=1
+        rolloff = i 
+        assert_equal (rolloff, o(c))
+
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
