shithub: aubio

Download patch

ref: f264b173a447448e0e124df2ac309b5e482e02c9
parent: 60fc05b3fadd7da5957eb8c531bfa882d35e6568
parent: 6769586029891c240afe04dec96f7c554e3803bd
author: Paul Brossier <piem@piem.org>
date: Wed Jun 22 09:00:10 EDT 2016

Merge branch 'master' into notes

--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,7 @@
 
 aubio-*.tar.bz2
 aubio-*.zip
+
+# test sounds
+python/tests/sounds
+aubio.egg-info
--- /dev/null
+++ b/.landscape.yml
@@ -1,0 +1,5 @@
+strictness: medium
+test-warnings: true
+python-targets:
+  - 2
+  - 3
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,64 @@
-language: c
+language: python
 
-sudo: false
+matrix:
+  include:
+    - python: 2.7
+      os: linux
+      compiler: gcc
+      env: ARCH=x86_64
+    - python: 2.7
+      os: linux
+      compiler: gcc
+      env: ARCH=i386
+    - python: 3.4
+      os: linux
+      compiler: gcc
+      env: ARCH=x86_64
+    - python: 3.4
+      os: linux
+      compiler: gcc
+      env: ARCH=i386 WAFOPTS=--enable-fftw3f
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=x86_64
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=i386
+    - python: 2.7
+      os: linux
+      compiler: gcc
+      env: ARCH=x86_64 HAVE_DOUBLE=1 WAFOPTS=--enable-fftw3
+    - python: 2.7
+      os: linux
+      compiler: gcc
+      env: ARCH=i386 HAVE_DOUBLE=1
+    - python: 3.4
+      os: linux
+      compiler: gcc
+      env: ARCH=x86_64 HAVE_DOUBLE=1
+    - python: 3.4
+      os: linux
+      compiler: gcc
+      env: ARCH=i386 HAVE_DOUBLE=1
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=x86_64 HAVE_DOUBLE=1
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=i386 HAVE_DOUBLE=1
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=x86_64 WAFOPTS=--enable-fat
+    - language: C
+      os: osx
+      compiler: clang
+      env: ARCH=i386 WAFOPTS=--enable-fat
 
-compiler:
-  - gcc
-  - clang
-
-env:
-  - ARCH=i386
-  - ARCH=x86_64
-
 addons:
   apt:
     packages:
@@ -19,12 +68,34 @@
     - libjack-dev
     - libasound2-dev
     - libfftw3-dev
-    - python-dev
-    - python-numpy
+    - sox
 
+before_install:
+   - |
+     if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+       brew update
+       brew install sox
+       export PATH="$HOME/Library/Python/2.7/bin/:$PATH"
+     fi;
+
+
+install:
+  - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then travis_retry pip install nose2; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then travis_retry pip install --user nose2; fi
+
 script:
+  - make create_test_sounds
   - make build
   - make build_python
+  - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make test_python; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make test_python_osx; fi
   - make clean_python
   - make clean
   - make distcheck
+  - make test_pure_python
+
+notifications:
+    irc:
+        channels:
+            - "irc.freenode.org#aubio"
+        use_notice: true
--- /dev/null
+++ b/MANIFEST.in
@@ -1,0 +1,25 @@
+include AUTHORS COPYING README.md VERSION ChangeLog
+include python/README
+include Makefile wscript */wscript_build
+include waf
+include aubio.pc.in
+include nose2.cfg
+include requirements.txt
+include src/*.h
+include src/*/*.h
+include examples/*.c examples/*.h
+include tests/*.h tests/*/*.c tests/*/*/*.c
+include python/ext/*.h
+include python/__init__.py
+include python/lib/__init__.py
+include python/lib/moresetuptools.py
+include python/lib/gen_external.py
+include python/lib/gen_code.py
+include python/tests/run_all_tests
+include python/tests/*.py
+include python/demos/*.py
+include python/tests/*.expected
+include doc/*.txt doc/*.rst doc/*.cfg doc/Makefile doc/make.bat doc/conf.py
+include scripts/* scripts/apple/Info.plist scripts/apple/Modules/module.modulemap
+exclude python/gen/*
+exclude python/ext/config.h
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+WAFCMD=python waf
+
+SOX=sox
+
+ENABLE_DOUBLE := $(shell [ -z $(HAVE_DOUBLE) ] || echo --enable-double )
+TESTSOUNDS := python/tests/sounds
+
 all: build
 
 checkwaf:
@@ -4,28 +11,86 @@
 	@[ -f waf ] || make getwaf
 
 getwaf:
-	curl https://waf.io/waf-1.8.12 > waf
+	curl https://waf.io/waf-1.8.20 > waf
+	@chmod +x waf
+
+expandwaf:
 	@[ -d wafilb ] || rm -fr waflib
-	@chmod +x waf && ./waf --help > /dev/null
-	@mv .waf*/waflib . && rm -fr .waf-*
+	@$(WAFCMD) --help > /dev/null
+	@mv .waf*/waflib . && rm -fr .waf*
 	@sed '/^#==>$$/,$$d' waf > waf2 && mv waf2 waf
 	@chmod +x waf
 
-build: checkwaf
-	./waf configure
-	./waf build
+configure: checkwaf
+	$(WAFCMD) configure $(WAFOPTS) $(ENABLE_DOUBLE)
 
+build: configure
+	$(WAFCMD) build $(WAFOPTS)
+
 build_python:
-	cd python && ./setup.py build
+	python ./setup.py generate $(ENABLE_DOUBLE) build
 
+test_python: export LD_LIBRARY_PATH=$(PWD)/build/src
+test_python:
+	pip install -v -r requirements.txt
+	pip install -v .
+	nose2 --verbose
+	pip uninstall -y -v aubio
+
+test_python_osx:
+	# create links from ~/lib/lib* to build/src/lib*
+	[ -f build/src/libaubio.[0-9].dylib ] && ( mkdir -p ~/lib && cp -prv build/src/libaubio.4.dylib ~/lib ) || true
+	# then run the tests
+	pip install --user -v -r requirements.txt
+	pip install --user -v .
+	nose2 --verbose
+	pip uninstall -y -v aubio
+
 clean_python:
-	cd python && ./setup.py clean
+	./setup.py clean
 
+test_pure_python:
+	-pip uninstall -v -y aubio
+	-rm -rf build/ python/gen/
+	-rm -f dist/*.egg
+	-pip install -v -r requirements.txt
+	CFLAGS=-Os python setup.py bdist_egg
+	[ "$(TRAVIS_OS_NAME)" == "osx" ] && easy_install --user dist/*.egg || \
+		easy_install dist/*.egg
+	nose2 -N 4
+	pip uninstall -v -y aubio
+
+test_pure_python_wheel:
+	-pip uninstall -v -y aubio
+	-rm -rf build/ python/gen/
+	-rm -f dist/*.whl
+	-pip install -v -r requirements.txt
+	-pip install -v wheel
+	CFLAGS=-Os python setup.py bdist_wheel --universal
+	wheel install dist/*.whl
+	nose2 -N 4
+	pip uninstall -v -y aubio
+
+build_python3:
+	python3 ./setup.py generate $(ENABLE_DOUBLE) build
+
+clean_python3:
+	python3 ./setup.py clean
+
 clean:
-	./waf clean
+	$(WAFCMD) clean
 
-distcheck: build
-	./waf distcheck
+distcheck: checkwaf
+	$(WAFCMD) distcheck $(WAFOPTS) $(ENABLE_DOUBLE)
 
 help:
-	./waf --help
+	$(WAFCMD) --help
+
+create_test_sounds:
+	-[ -z `which $(SOX)` ] && ( echo $(SOX) could not be found) || true
+	-mkdir -p $(TESTSOUNDS)
+	-$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_1f_silence.wav"      synth 1s   silence 0
+	-$(SOX) -r 22050 -b 16 -n "$(TESTSOUNDS)/22050Hz_5s_brownnoise.wav"   synth 5    brownnoise      vol 0.9
+	-$(SOX) -r 32000 -b 16 -n "$(TESTSOUNDS)/32000Hz_127f_sine440.wav"    synth 127s sine 440        vol 0.9
+	-$(SOX) -r  8000 -b 16 -n "$(TESTSOUNDS)/8000Hz_30s_silence.wav"      synth 30   silence 0       vol 0.9
+	-$(SOX) -r 48000 -b 32 -n "$(TESTSOUNDS)/48000Hz_60s_sweep.wav"       synth 60   sine 100-20000  vol 0.9
--- a/README.md
+++ b/README.md
@@ -68,20 +68,19 @@
 
 The latest version of the documentation can be found at:
 
-  http://aubio.org/documentation
+  https://aubio.org/documentation
 
-Installation and Build Instructions
------------------------------------
+Build Instructions
+------------------
 
 A number of distributions already include aubio. Check your favorite package
 management system, or have a look at the [download
-page](http://aubio.org/download).
+page](https://aubio.org/download).
 
 aubio uses [waf](https://waf.io/) to configure, compile, and test the source:
 
     ./waf configure
     ./waf build
-    sudo ./waf install
 
 If waf is not found in the directory, you can download and install it with:
 
@@ -89,6 +88,35 @@
 
 aubio compiles on Linux, Mac OS X, Cygwin, and iOS.
 
+Installation
+------------
+
+To install aubio library and headers on your system, use:
+
+    sudo ./waf install
+
+To uninstall:
+
+    sudo ./waf uninstall
+
+If you don't have root access to install libaubio on your system, you can use
+libaubio without installing libaubio either by setting `LD_LIBRARY_PATH`, or by
+copying it to `~/lib`.
+
+On Linux, you should be able to set `LD_LIBRARY_PATH` with:
+
+    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/build/src
+
+On Mac OS X, a copy or a symlink can be made in `~/lib`:
+
+    $ mkdir -p ~/lib
+    $ ln -sf $PWD/build/src/libaubio*.dylib ~/lib/
+
+Note on Mac OS X systems older than El Capitan (10.11), the `DYLD_LIBRARY_PATH`
+variable can be set as follows:
+
+    $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$PWD/build/src
+
 Credits and Publications
 ------------------------
 
@@ -107,7 +135,7 @@
 in:
 
   - Paul Brossier, _[Automatic annotation of musical audio for interactive
-    systems](http://aubio.org/phd)_, PhD thesis, Centre for Digital music,
+    systems](https://aubio.org/phd)_, PhD thesis, Centre for Digital music,
 Queen Mary University of London, London, UK, 2006.
 
 Additional results obtained with this software were discussed in the following
@@ -114,12 +142,12 @@
 papers:
 
   - P. M. Brossier and J. P. Bello and M. D. Plumbley, [Real-time temporal
-    segmentation of note objects in music signals](http://aubio.org/articles/brossier04fastnotes.pdf),
+    segmentation of note objects in music signals](https://aubio.org/articles/brossier04fastnotes.pdf),
 in _Proceedings of the International Computer Music Conference_, 2004, Miami,
 Florida, ICMA
 
   -  P. M. Brossier and J. P. Bello and M. D. Plumbley, [Fast labelling of note
-     objects in music signals] (http://aubio.org/articles/brossier04fastnotes.pdf),
+     objects in music signals] (https://aubio.org/articles/brossier04fastnotes.pdf),
 in _Proceedings of the International Symposium on Music Information Retrieval_,
 2004, Barcelona, Spain
 
@@ -127,7 +155,7 @@
 Contact Info and Mailing List
 -----------------------------
 
-The home page of this project can be found at: http://aubio.org/
+The home page of this project can be found at: https://aubio.org/
 
 Questions, comments, suggestions, and contributions are welcome. Use the
 mailing list: <aubio-user@aubio.org>.
--- /dev/null
+++ b/appveyor.yml
@@ -1,0 +1,67 @@
+# appveyor configuration. See http://www.appveyor.com/docs/appveyor-yml
+# and http://www.appveyor.com/docs/installed-software#python
+
+environment:
+
+  matrix:
+
+    # pre-installed python version, see:
+    # http://www.appveyor.com/docs/installed-software#python
+    - PYTHON: "C:\\Python27"
+      PYTHON_VERSION: "2.7.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python27-x64"
+      PYTHON_VERSION: "2.7.x"
+      PYTHON_ARCH: "64"
+
+    - PYTHON: "C:\\Python34"
+      PYTHON_VERSION: "3.4.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python34-x64"
+      PYTHON_VERSION: "3.4.x"
+      PYTHON_ARCH: "64"
+
+    - PYTHON: "C:\\Python35"
+      PYTHON_VERSION: "3.5.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python35-x64"
+      PYTHON_VERSION: "3.5.x"
+      PYTHON_ARCH: "64"
+
+install:
+
+  - ECHO "Installed SDKs:"
+  - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
+
+  # Check that we have the expected version and architecture for Python
+  - "%PYTHON%\\python.exe --version"
+  - "%PYTHON%\\python.exe -c \"import struct; print(struct.calcsize('P') * 8)\""
+
+  # We need wheel installed to build wheels
+  - "%PYTHON%\\python.exe -m pip install wheel"
+
+  - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+
+  - "pip install --disable-pip-version-check --user --upgrade pip"
+  - "pip install --upgrade setuptools"
+
+before_build:
+  - curl -fsS -o waf https://waf.io/waf-1.8.20
+  - curl -fsS -o waf.bat https://raw.githubusercontent.com/waf-project/waf/master/utils/waf.bat
+
+build_script:
+  # build python module without using libaubio
+  - "pip install -r requirements.txt"
+  - "python setup.py build"
+  - "pip install ."
+  - "python python\\demos\\demo_create_test_sounds.py"
+  - "nose2"
+  # clean up
+  - waf distclean
+  # build libaubio
+  - waf configure build --verbose
+  # build python module using libaubio dll
+  - "python setup.py build"
--- a/examples/aubiotrack.c
+++ b/examples/aubiotrack.c
@@ -20,6 +20,7 @@
 
 #include "utils.h"
 #define PROG_HAS_TEMPO 1
+#define PROG_HAS_ONSET 1
 #define PROG_HAS_OUTPUT 1
 #define PROG_HAS_JACK 1
 #include "parse_args.h"
--- a/examples/jackio.c
+++ b/examples/jackio.c
@@ -21,7 +21,7 @@
 #include <aubio.h>
 #include "config.h"
 
-#if HAVE_JACK
+#ifdef HAVE_JACK
 #include "utils.h" // for aubio_process_func_t
 #include "jackio.h"
 #include "aubio_priv.h"
--- a/examples/parse_args.h
+++ b/examples/parse_args.h
@@ -18,6 +18,12 @@
 
 */
 
+#include "config.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
 extern int verbose;
 // input / output
 extern int usejack;
@@ -63,6 +69,7 @@
 
 void usage (FILE * stream, int exit_code)
 {
+#ifdef HAVE_GETOPT_H
   fprintf (stream, "usage: %s [ options ] \n", prog_name);
   fprintf (stream,
       "       -i      --input            input file\n"
@@ -106,6 +113,10 @@
       "       -v      --verbose          be verbose\n"
       "       -h      --help             display this message\n"
       );
+#else /* HAVE_GETOPT_H */
+  fprintf (stream, "warning: compiled with getopt.h, no argument parsing\n");
+  fprintf (stream, "usage: %s <filename> \n", prog_name);
+#endif /* HAVE_GETOPT_H */
   exit (exit_code);
 }
 
@@ -112,6 +123,7 @@
 int
 parse_args (int argc, char **argv)
 {
+#ifdef HAVE_GETOPT_H
   const char *options = "hv"
     "i:r:B:H:"
 #ifdef PROG_HAS_JACK
@@ -157,11 +169,13 @@
     {"force-overwrite",       0, NULL, 'f'},
     {NULL,                    0, NULL, 0}
   };
+#endif /* HAVE_GETOPT_H */
   prog_name = argv[0];
   if (argc < 1) {
     usage (stderr, 1);
     return -1;
   }
+#ifdef HAVE_GETOPT_H
   do {
     next_option = getopt_long (argc, argv, options, long_options, NULL);
     switch (next_option) {
@@ -235,6 +249,9 @@
     }
   }
   while (next_option != -1);
+#else /* HAVE_GETOPT_H */
+  int optind = 1;
+#endif /* HAVE_GETOPT_H */
 
   // if unique, use the non option argument as the source
   if ( source_uri == NULL ) {
--- a/examples/utils.c
+++ b/examples/utils.c
@@ -72,7 +72,7 @@
 
 #if HAVE_JACK
 aubio_jack_t *jack_setup;
-#endif
+#endif /* HAVE_JACK */
 
 void examples_common_init (int argc, char **argv);
 void examples_common_del (void);
@@ -114,7 +114,7 @@
     jack_setup = new_aubio_jack (hop_size, 1, 1, 0, 1);
     samplerate = aubio_jack_get_samplerate (jack_setup);
     source_uri = "jack";
-#endif
+#endif /* HAVE_JACK */
   }
   ibuf = new_fvec (hop_size);
   obuf = new_fvec (hop_size);
@@ -137,16 +137,16 @@
   uint_t read = 0;
   if (usejack) {
 
-#if HAVE_JACK
+#ifdef HAVE_JACK
     debug ("Jack activation ...\n");
     aubio_jack_activate (jack_setup, process_func);
     debug ("Processing (Ctrl+C to quit) ...\n");
     pause ();
     aubio_jack_close (jack_setup);
-#else
+#else /* HAVE_JACK */
     usage (stderr, 1);
     outmsg ("Compiled without jack output, exiting.\n");
-#endif
+#endif /* HAVE_JACK */
 
   } else {
 
@@ -181,7 +181,7 @@
 send_noteon (int pitch, int velo)
 {
   smpl_t mpitch = floor (aubio_freqtomidi (pitch) + .5);
-#if HAVE_JACK
+#ifdef HAVE_JACK
   jack_midi_event_t ev;
   ev.size = 3;
   ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
--- a/examples/utils.h
+++ b/examples/utils.h
@@ -18,15 +18,29 @@
 
 */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <math.h>               /* for isfinite */
-#include <string.h>             /* for strcmp */
 #include <aubio.h>
+
 #include "config.h"
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>              // for fprintf
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>             // for exit
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>             // for access
+#elif defined(HAVE_WIN_HACKS)
+#include <io.h>
+#define access _access
+#define F_OK   0
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>               // for isfinite
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>             // for strcmp
+#endif
 
 #ifdef HAVE_C99_VARARGS_MACROS
 #ifdef HAVE_DEBUG
--- a/examples/wscript_build
+++ b/examples/wscript_build
@@ -1,15 +1,9 @@
 # vim:set syntax=python:
 
-uselib = []
-uselib += ['FFTW3', 'FFTW3F']
-uselib += ['SAMPLERATE']
-uselib += ['SNDFILE']
-uselib += ['AVCODEC']
-uselib += ['AVFORMAT']
-uselib += ['AVRESAMPLE']
-uselib += ['AVUTIL']
+uselib = ['aubio']
 uselib += ['JACK']
 
+includes = ['../src']
 utils_source = ['utils.c', 'jackio.c']
 programs_source = ctx.path.ant_glob('*.c', excl = utils_source)
 
@@ -16,17 +10,15 @@
 # build examples
 bld(features = 'c',
         source = utils_source,
-        includes = ['../src'],
-        uselib = uselib,
+        includes = includes,
+        use = uselib,
         target = 'utilsio')
 
 # loop over all *.c filenames in examples to build them all
 for source_file in programs_source:
     bld(features = 'c cprogram',
-            includes = '../src',
-            lib = 'm',
-            use = ['aubio', 'utilsio'],
-            uselib = uselib,
             source = source_file,
-            target = str(source_file).split('.')[0]
-            )
+            target = str(source_file).split('.')[0],
+            includes = includes,
+            use = uselib + ['utilsio'],
+       )
--- /dev/null
+++ b/nose2.cfg
@@ -1,0 +1,6 @@
+[unittest]
+start-dir = python/tests/
+plugins = nose2.plugins.mp
+
+[multiprocess]
+always-on = false
--- a/python/MANIFEST.in
+++ /dev/null
@@ -1,8 +1,0 @@
-include README COPYING VERSION
-include ext/*.h
-include lib/generator.py
-include lib/gen_pyobject.py
-include gen/aubio-generated.h
-include tests/run_all_tests
-include tests/*.py
-include demos/*.py
--- a/python/README
+++ b/python/README
@@ -45,15 +45,6 @@
 
     $ export PYTHONPATH=$PYTHONPATH:$PWD/`ls -rtd build/lib.* | head -1`:$PWD/tests
 
-Similarly, you can use the aubio module without installing libaubio by pointing
-LD_LIBRARY_PATH to the path libaubio can be found at:
-
-    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:PWD/../build/src
-
-Or on Mac OS X systems, setting DYLD_LIBRARY_PATH:
-
-    $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$PWD/../build/src
-
 Testing the Python module
 -------------------------
 
--- a/python/VERSION
+++ /dev/null
@@ -1,7 +1,0 @@
-AUBIO_MAJOR_VERSION=0
-AUBIO_MINOR_VERSION=4
-AUBIO_PATCH_VERSION=2
-AUBIO_VERSION_STATUS='~alpha'
-LIBAUBIO_LT_CUR=4
-LIBAUBIO_LT_REV=1
-LIBAUBIO_LT_AGE=1
--- a/python/demos/demo_a_weighting.py
+++ /dev/null
@@ -1,27 +1,0 @@
-#! /usr/bin/env python
-
-
-def apply_filter(path, params = {}):
-    from aubio import source, sink, digital_filter
-    from os.path import basename, splitex, splitextt
-    s = source(path)
-    f = digital_filter(7)
-    f.set_a_weighting(s.samplerate)
-    #f = digital_filter(3)
-    #f.set_biquad(...)
-    o = sink("filtered_" + splitext(basename(path))[0] + ".wav")
-    # Total number of frames read
-    total_frames = 0
-
-    while True:
-        samples, read = s()
-        filtered_samples = f(samples)
-        o(samples, read)
-        total_frames += read
-        if read < s.hop_size: break
-    print "filtered", s.uri, "to", o.uri, "using an A-weighting filter"
-
-if __name__ == '__main__':
-    import sys
-    for f in sys.argv[1:]:
-        apply_filter(f)
--- a/python/demos/demo_bpm_extract.py
+++ b/python/demos/demo_bpm_extract.py
@@ -3,16 +3,18 @@
 from aubio import source, tempo
 from numpy import median, diff
 
-def get_file_bpm(path, params = {}):
+def get_file_bpm(path, params = None):
     """ Calculate the beats per minute (bpm) of a given file.
         path: path to the file
         param: dictionary of parameters
     """
+    if params is None:
+        params = {}
     try:
         win_s = params['win_s']
         samplerate = params['samplerate']
         hop_s = params['hop_s']
-    except:
+    except KeyError:
         """
         # super fast
         samplerate, win_s, hop_s = 4000, 128, 64 
@@ -43,8 +45,14 @@
             break
 
     # Convert to periods and to bpm 
-    bpms = 60./diff(beats)
-    b = median(bpms)
+    if len(beats) > 1:
+        if len(beats) < 4:
+            print("few beats found in {:s}".format(path))
+        bpms = 60./diff(beats)
+        b = median(bpms)
+    else:
+        b = 0
+        print("not enough beats found in {:s}".format(path))
     return b
 
 if __name__ == '__main__':
@@ -51,4 +59,4 @@
     import sys
     for f in sys.argv[1:]:
         bpm = get_file_bpm(f)
-        print "%6s" % ("%.2f" % bpm), f
+        print("{:6s} {:s}".format("{:2f}".format(bpm), f))
--- /dev/null
+++ b/python/demos/demo_create_test_sounds.py
@@ -1,0 +1,50 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys, os
+import numpy as np
+from aubio import fvec, sink, float_type
+
+if __name__ == '__main__':
+    if len(sys.argv) < 1:
+        print('usage: %s' % sys.argv[0])
+        sys.exit(1)
+
+    samplerate = 44100
+    hop_size = 256
+
+    # create python/tests/sounds if needed
+    output_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    output_dir = os.path.join(output_dir, 'tests', 'sounds')
+    if not os.path.isdir(output_dir):
+        os.makedirs(output_dir)
+
+    filenames = ['44100Hz_1f_silence.wav',
+                 '22050Hz_5s_brownnoise.wav',
+                 '32000Hz_127f_sine440.wav',
+                ]
+    samplerates = [44100, 22050, 32000]
+    durations = [1, 5*22050, 127]
+
+    for fname, samplerate, duration in zip(filenames, samplerates, durations):
+        output_name = os.path.join(output_dir, fname)
+        g = sink(output_name, samplerate)
+        total_frames = 0
+        while total_frames < duration:
+            write = min(hop_size, duration - total_frames)
+            if 'brownnoise' in fname:
+                vec = np.random.rand(write).astype(float_type) * 2. - 1.
+            elif 'sine' in fname:
+                freq = 440
+                t = np.arange(write).astype(float_type) + total_frames
+                vec = np.sin(2. * np.pi * freq * t / float(samplerate))
+            else:
+                # silence
+                vec = fvec(write)
+            g(vec, write)
+            total_frames += write
+        outstr = "wrote {:2f}s".format(total_frames / float(samplerate))
+        outstr += " ({:d} frames".format(total_frames)
+        outstr += " at {:d}Hz)".format(g.samplerate)
+        outstr += " to {:s}".format(g.uri)
+        print(outstr)
--- /dev/null
+++ b/python/demos/demo_filter.py
@@ -1,0 +1,36 @@
+#! /usr/bin/env python
+
+
+def apply_filter(path):
+    from aubio import source, sink, digital_filter
+    from os.path import basename, splitext
+
+    # open input file, get its samplerate
+    s = source(path)
+    samplerate = s.samplerate
+
+    # create an A-weighting filter
+    f = digital_filter(7)
+    f.set_a_weighting(samplerate)
+    # alternatively, apply another filter
+
+    # create output file
+    o = sink("filtered_" + splitext(basename(path))[0] + ".wav", samplerate)
+
+    total_frames = 0
+    while True:
+        samples, read = s()
+        filtered_samples = f(samples)
+        o(filtered_samples, read)
+        total_frames += read
+        if read < s.hop_size: break
+
+    duration = total_frames / float(samplerate)
+    print ("read {:s}".format(s.uri))
+    print ("applied A-weighting filtered ({:d} Hz)".format(samplerate))
+    print ("wrote {:s} ({:.2f} s)".format(o.uri, duration))
+
+if __name__ == '__main__':
+    import sys
+    for f in sys.argv[1:]:
+        apply_filter(f)
--- a/python/demos/demo_filterbank.py
+++ b/python/demos/demo_filterbank.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 from aubio import filterbank, fvec
-from pylab import loglog, show, subplot, xlim, ylim, xlabel, ylabel, title
+from pylab import loglog, show, xlim, ylim, xlabel, ylabel, title
 from numpy import vstack, arange
 
 win_s = 2048
@@ -19,7 +19,7 @@
 
 f.set_coeffs(coeffs)
 
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
 title('Bank of filters built using a simple list of boundaries\nThe middle band has been amplified by 2.')
 loglog(times.T, f.get_coeffs().T, '.-')
 xlim([50, samplerate/2])
--- a/python/demos/demo_filterbank_slaney.py
+++ b/python/demos/demo_filterbank_slaney.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 from aubio import filterbank
-from numpy import array, arange, vstack
+from numpy import arange, vstack
 
 win_s = 8192
 samplerate = 16000
@@ -11,7 +11,7 @@
 
 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)
+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])
--- a/python/demos/demo_filterbank_triangle_bands.py
+++ b/python/demos/demo_filterbank_triangle_bands.py
@@ -16,7 +16,7 @@
 
 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)
+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])
@@ -37,7 +37,7 @@
 f.set_coeffs(coeffs)
 
 subplot(212)
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+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])
--- a/python/demos/demo_keyboard.py
+++ b/python/demos/demo_keyboard.py
@@ -25,7 +25,6 @@
     return xb, xw, 2/3. *scaleb, 1/2. * scalew
 
 def create_keyboard_patches(firstnote, lastnote, ax = None):
-    import numpy as np
     import matplotlib.pyplot as plt
     from matplotlib.path import Path
     import matplotlib.patches as mpatches
--- a/python/demos/demo_mel-energy.py
+++ b/python/demos/demo_mel-energy.py
@@ -1,14 +1,14 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import fvec, source, pvoc, filterbank
+from aubio import source, pvoc, filterbank
 from numpy import vstack, zeros
 
 win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
+hop_s = win_s // 4          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -34,14 +34,14 @@
     samples, read = s()
     fftgrain = pv(samples)
     new_energies = f(fftgrain)
-    print '%f' % (total_frames / float(samplerate) ),
-    print ' '.join(['%f' % b for b in new_energies])
+    timestr = '%f' % (total_frames / float(samplerate) )
+    print('{:s} {:s}'.format(timestr, ' '.join(['%f' % b for b in new_energies])))
     energies = vstack( [energies, new_energies] )
     total_frames += read
     if read < hop_s: break
 
 if 1:
-    print "done computing, now plotting"
+    print("done computing, now plotting")
     import matplotlib.pyplot as plt
     from demo_waveform_plot import get_waveform_plot
     from demo_waveform_plot import set_xlabels_sample2time
--- a/python/demos/demo_mfcc.py
+++ b/python/demos/demo_mfcc.py
@@ -2,16 +2,16 @@
 
 import sys
 from aubio import source, pvoc, mfcc
-from numpy import array, vstack, zeros
+from numpy import vstack, zeros
 
 win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
+hop_s = win_s // 4          # hop size
 n_filters = 40              # must be 40 for mfcc
 n_coeffs = 13
 samplerate = 44100
 
 if len(sys.argv) < 2:
-    print "Usage: %s <source_filename>" % sys.argv[0]
+    print("Usage: %s <source_filename>" % sys.argv[0])
     sys.exit(1)
 
 source_filename = sys.argv[1]
--- a/python/demos/demo_onset.py
+++ b/python/demos/demo_onset.py
@@ -4,10 +4,10 @@
 from aubio import source, onset
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -28,7 +28,7 @@
 while True:
     samples, read = s()
     if o(samples):
-        print "%f" % o.get_last_s()
+        print("%f" % o.get_last_s())
         onsets.append(o.get_last())
     total_frames += read
     if read < hop_s: break
--- a/python/demos/demo_onset_plot.py
+++ b/python/demos/demo_onset_plot.py
@@ -2,13 +2,13 @@
 
 import sys
 from aubio import onset, source
-from numpy import array, hstack, zeros
+from numpy import hstack, zeros
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -34,10 +34,10 @@
 while True:
     samples, read = s()
     if o(samples):
-        print "%f" % (o.get_last_s())
+        print("%f" % (o.get_last_s()))
         onsets.append(o.get_last())
     # keep some data to plot it later
-    new_maxes = (abs(samples.reshape(hop_s/downsample, downsample))).max(axis=0)
+    new_maxes = (abs(samples.reshape(hop_s//downsample, downsample))).max(axis=0)
     allsamples_max = hstack([allsamples_max, new_maxes])
     desc.append(o.get_descriptor())
     tdesc.append(o.get_thresholded_descriptor())
@@ -46,7 +46,6 @@
 
 if 1:
     # do plotting
-    from numpy import arange
     import matplotlib.pyplot as plt
     allsamples_max = (allsamples_max > 0) * allsamples_max
     allsamples_max_times = [ float(t) * hop_s / downsample / samplerate for t in range(len(allsamples_max)) ]
@@ -62,9 +61,10 @@
     plt1.xaxis.set_visible(False)
     plt1.yaxis.set_visible(False)
     desc_times = [ float(t) * hop_s / samplerate for t in range(len(desc)) ]
-    desc_plot = [d / max(desc) for d in desc]
+    desc_max = max(desc) if max(desc) != 0 else 1.
+    desc_plot = [d / desc_max for d in desc]
     plt2.plot(desc_times, desc_plot, '-g')
-    tdesc_plot = [d / max(desc) for d in tdesc]
+    tdesc_plot = [d / desc_max for d in tdesc]
     for stamp in onsets:
         stamp /= float(samplerate)
         plt2.plot([stamp, stamp], [min(tdesc_plot), max(desc_plot)], '-r')
--- a/python/demos/demo_pitch.py
+++ b/python/demos/demo_pitch.py
@@ -1,20 +1,20 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import source, pitch, freqtomidi
+from aubio import source, pitch
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
 
 downsample = 1
-samplerate = 44100 / downsample
+samplerate = 44100 // downsample
 if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
 
-win_s = 4096 / downsample # fft size
-hop_s = 512  / downsample # hop size
+win_s = 4096 // downsample # fft size
+hop_s = 512  // downsample # hop size
 
 s = source(filename, samplerate, hop_s)
 samplerate = s.samplerate
@@ -36,7 +36,7 @@
     #pitch = int(round(pitch))
     confidence = pitch_o.get_confidence()
     #if confidence < 0.8: pitch = 0.
-    #print "%f %f %f" % (total_frames / float(samplerate), pitch, confidence)
+    print("%f %f %f" % (total_frames / float(samplerate), pitch, confidence))
     pitches += [pitch]
     confidences += [confidence]
     total_frames += read
@@ -45,6 +45,7 @@
 if 0: sys.exit(0)
 
 #print pitches
+import os.path
 from numpy import array, ma
 import matplotlib.pyplot as plt
 from demo_waveform_plot import get_waveform_plot, set_xlabels_sample2time
@@ -63,14 +64,11 @@
 ax1.set_xlabel('')
 
 def array_from_text_file(filename, dtype = 'float'):
-    import os.path
-    from numpy import array
     filename = os.path.join(os.path.dirname(__file__), filename)
     return array([line.split() for line in open(filename).readlines()],
         dtype = dtype)
 
 ax2 = fig.add_subplot(312, sharex = ax1)
-import sys, os.path
 ground_truth = os.path.splitext(filename)[0] + '.f0.Corrected'
 if os.path.isfile(ground_truth):
     ground_truth = array_from_text_file(ground_truth)
--- a/python/demos/demo_pitch_sinusoid.py
+++ b/python/demos/demo_pitch_sinusoid.py
@@ -1,20 +1,17 @@
 #! /usr/bin/env python
 
-from numpy import random, sin, arange, ones, zeros
-from math import pi
-from aubio import fvec, pitch
+import numpy as np
+import aubio
 
 def build_sinusoid(length, freqs, samplerate):
-  return sin( 2. * pi * arange(length) * freqs / samplerate)
+    return np.sin( 2. * np.pi * np.arange(length) * freqs / samplerate).astype(aubio.float_type)
 
 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
+    cands = []
+    for vec_slice in input_vec.reshape((-1, p.hop_size)):
+        a = p(vec_slice)[0]
+        cands.append(a)
+    return cands
 
 methods = ['default', 'schmitt', 'fcomb', 'mcomb', 'yin', 'yinfft']
 
@@ -23,9 +20,9 @@
 hop_size = 512
 samplerate = 44100
 sin_length = (samplerate * 10) % 512 * 512
-freqs = zeros(sin_length)
+freqs = np.zeros(sin_length)
 
-partition = sin_length / 8
+partition = sin_length // 8
 pointer = 0
 
 pointer += partition
@@ -40,29 +37,35 @@
 
 pointer += partition
 pointer += partition
-freqs[ pointer : pointer + partition ] = 400 + 5 * random.random(sin_length/8)
+freqs[ pointer : pointer + partition ] = 400 + 5 * np.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)
+    p = aubio.pitch(method, buf_size, hop_size, samplerate)
+    cands[method] = run_pitch(p, a)
+    print(method)
+    print(cands[method])
 
-print "done computing"
+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],'.-')
+    import matplotlib.pyplot as plt
 
-  # plot ground truth
-  ramp = arange(0, sin_length).astype('float') / samplerate
-  plot(ramp, freqs, ':')
+    # times
+    ramp = np.arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
 
-  legend(methods+['ground truth'], 'upper right')
-  xlabel('time (s)')
-  ylabel('frequency (Hz)')
-  ylim([0,2000])
-  show()
+    # plot each result
+    for method in methods:
+        plt.plot(ramp, cands[method], '.-', label=method)
 
+    # plot ground truth
+    ramp = np.arange(0, sin_length).astype('float') / samplerate
+    plt.plot(ramp, freqs, ':', label = 'ground truth')
+
+    plt.legend(loc='upper left')
+
+    plt.xlabel('time (s)')
+    plt.ylabel('frequency (Hz)')
+    plt.ylim([0,2000])
+    plt.show()
--- a/python/demos/demo_pysoundcard_play.py
+++ b/python/demos/demo_pysoundcard_play.py
@@ -10,7 +10,7 @@
     f = source(source_path, hop_size = hop_size)
     samplerate = f.samplerate
 
-    s = Stream(sample_rate = samplerate, block_length = hop_size)
+    s = Stream(samplerate = samplerate, blocksize = hop_size)
     s.start()
     read = 0
     while 1:
--- a/python/demos/demo_pysoundcard_record.py
+++ b/python/demos/demo_pysoundcard_record.py
@@ -8,17 +8,21 @@
 
     hop_size = 256
     duration = 5 # in seconds
-    s = Stream(block_length = hop_size)
-    g = sink(sink_path, samplerate = s.sample_rate)
+    s = Stream(blocksize = hop_size, channels = 1)
+    g = sink(sink_path, samplerate = int(s.samplerate))
 
     s.start()
     total_frames = 0
-    while total_frames < duration * s.sample_rate:
-        vec = s.read(hop_size)
-        # mix down to mono
-        mono_vec = vec.sum(-1) / float(s.input_channels)
-        g(mono_vec, hop_size)
-        total_frames += hop_size
+    try:
+        while total_frames < duration * s.samplerate:
+            vec = s.read(hop_size)
+            # mix down to mono
+            mono_vec = vec.sum(-1) / float(s.channels[0])
+            g(mono_vec, hop_size)
+            total_frames += hop_size
+    except KeyboardInterrupt:
+        duration = total_frames / float(s.samplerate)
+        print("stopped after %.2f seconds" % duration)
     s.stop()
 
 if __name__ == '__main__':
--- /dev/null
+++ b/python/demos/demo_reading_speed.py
@@ -1,0 +1,139 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+
+Compare the speed of several methods for reading and loading a sound file.
+
+Optionally, this file can make use of the following packages:
+
+    - audioread     https://github.com/beetbox/audioread
+    - scipy         https://scipy.org
+    - librosa       https://github.com/bmcfee/librosa
+    - pydub         https://github.com/jiaaro/pydub
+
+Uncomment the function names below and send us your speed results!
+
+"""
+
+
+test_functions = [
+            "read_file_aubio",
+            "load_file_aubio",
+            #"load_file_scipy",
+            #"load_file_scipy_mmap",
+            #"read_file_audioread",
+            #"load_file_librosa",
+            #"read_file_pydub",
+            #"load_file_pydub",
+            ]
+
+
+import numpy as np
+
+def read_file_audioread(filename):
+    import audioread
+    # taken from librosa.util.utils
+    def convert_buffer_to_float(buf, n_bytes = 2, dtype = np.float32):
+        # Invert the scale of the data
+        scale = 1./float(1 << ((8 * n_bytes) - 1))
+        # Construct the format string
+        fmt = '<i{:d}'.format(n_bytes)
+        # Rescale and format the data buffer
+        out = scale * np.frombuffer(buf, fmt).astype(dtype)
+        return out
+
+    with audioread.audio_open(filename) as f:
+        total_frames = 0
+        for buf in f:
+            samples = convert_buffer_to_float(buf)
+            samples = samples.reshape(f.channels, -1)
+            total_frames += samples.shape[1]
+        return total_frames, f.samplerate
+
+def load_file_librosa(filename):
+    import librosa
+    y, sr = librosa.load(filename, sr = None)
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def load_file_scipy(filename):
+    import scipy.io.wavfile
+    sr, y = scipy.io.wavfile.read(filename)
+    y = y.astype('float32') / 32767
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def load_file_scipy_mmap(filename):
+    import scipy.io.wavfile
+    sr, y = scipy.io.wavfile.read(filename, mmap = True)
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def read_file_pydub(filename):
+    from pydub import AudioSegment
+    song = AudioSegment.from_file(filename)
+    song.get_array_of_samples()
+    return song.frame_count(), song.frame_rate
+
+def load_file_pydub(filename):
+    from pydub import AudioSegment
+    song = AudioSegment.from_file(filename)
+    y = np.asarray(song.get_array_of_samples(), dtype = 'float32')
+    y = y.reshape(song.channels, -1) / 32767.
+    return song.frame_count(), song.frame_rate
+
+def read_file_aubio(filename):
+    import aubio
+    f = aubio.source(filename, hop_size = 1024)
+    total_frames = 0
+    while True:
+        _, read = f()
+        total_frames += read
+        if read < f.hop_size: break
+    return total_frames, f.samplerate
+
+def load_file_aubio(filename):
+    import aubio
+    f = aubio.source(filename, hop_size = 1024)
+    y = np.zeros(f.duration, dtype = aubio.float_type)
+    total_frames = 0
+    while True:
+        samples, read = f()
+        y[total_frames:total_frames + read] = samples[:read]
+        total_frames += read
+        if read < f.hop_size: break
+    assert len(y) == total_frames
+    #print y.mean(), y.shape
+    return total_frames, f.samplerate
+
+def test_speed(function, filename):
+    times = []
+    for _ in range(10):
+        start = time.time()
+        try:
+            total_frames, samplerate = function(filename)
+        except ImportError as e:
+            print ("error: failed importing {:s}".format(e))
+            return
+        elapsed = time.time() - start
+        #print ("{:5f} ".format(elapsed)),
+        times.append(elapsed)
+
+    #print
+    times = np.array(times)
+    duration_min = int(total_frames/float(samplerate) // 60)
+    str_format = '{:25s} took {:5f} seconds avg (±{:5f}) to run on a ~ {:d} minutes long file'
+    print (str_format.format(function.__name__, times.mean(), times.std(), duration_min ))
+
+if __name__ == '__main__':
+    import sys, time
+    if len(sys.argv) < 2:
+        print ("not enough arguments")
+        sys.exit(1)
+    filename = sys.argv[1]
+
+    for f in test_functions:
+        # get actual function from globals
+        test_function = globals()[f]
+        test_speed(test_function, filename)
--- a/python/demos/demo_simple_robot_voice.py
+++ b/python/demos/demo_simple_robot_voice.py
@@ -4,27 +4,26 @@
 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
+    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
+    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.norm *= .8               # reduce amplitude a bit
-    spectrum.phas[:] = 0.             # zero phase
-    new_samples = pv.rdo(spectrum)    # compute modified samples
-    g(new_samples, read)              # write to output
-    total_frames += read
+    while read:
+        samples, read = f()
+        spectrum = pv(samples)           # compute spectrum
+        #spectrum.norm *= .8             # reduce amplitude a bit
+        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
-
-  
+    format_str = "read {:d} samples from {:s}, written to {:s}"
+    print(format_str.format(total_frames, f.uri, g.uri))
--- a/python/demos/demo_simple_spectral_weighting.py
+++ b/python/demos/demo_simple_spectral_weighting.py
@@ -13,7 +13,7 @@
 
 if __name__ == '__main__':
     if len(sys.argv) < 2:
-        print 'usage: %s <inputfile> <outputfile>' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile>' % sys.argv[0])
         sys.exit(1)
     samplerate = 0 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,7 +22,7 @@
     g = sink(sys.argv[2], samplerate)
 
     win_s = 512 # fft size
-    hop_s = win_s / 2 # hop size
+    hop_s = win_s // 2 # hop size
     pv = pvoc(win_s, hop_s) # phase vocoder
 
     # spectral weighting vector
@@ -30,7 +30,7 @@
         .8 * hanningz(80)[40:],
         zeros( 50 ),
         1.3 * hanningz(100),
-        zeros (win_s / 2 + 1 - 40 - 50 - 100),
+        zeros (win_s // 2 + 1 - 40 - 50 - 100),
         ] )
 
     if 0:
@@ -52,4 +52,5 @@
         g(new_samples, read)
         total_frames += read
 
-    print "read", total_frames / float(samplerate), "seconds from", f.uri
+    duration = total_frames / float(samplerate)
+    print("read {:.3f}s from {:s}".format(duration, f.uri))
--- a/python/demos/demo_sink.py
+++ b/python/demos/demo_sink.py
@@ -5,7 +5,7 @@
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,8 +22,10 @@
         vec, read = f()
         g(vec, read)
         total_frames += read
-    print "wrote", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri,
-    print "to", g.uri
+    outstr = "wrote %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    outstr += " to " + g.uri
+    print(outstr)
--- a/python/demos/demo_sink_create_woodblock.py
+++ b/python/demos/demo_sink_create_woodblock.py
@@ -2,11 +2,11 @@
 
 import sys
 from math import pi, e
-from aubio import sink
-from numpy import arange, resize, sin, exp, zeros
+from aubio import sink, float_type
+from numpy import arange, sin, exp, zeros
 
 if len(sys.argv) < 2:
-    print 'usage: %s <outputfile> [samplerate]' % sys.argv[0]
+    print('usage: %s <outputfile> [samplerate]' % sys.argv[0])
     sys.exit(1)
 
 samplerate = 44100 # samplerate in Hz
@@ -25,9 +25,9 @@
 period = float(samplerate) /  pitch
 # create a sine lookup table
 tablelen = 1000
-sinetable = arange(tablelen + 1, dtype = 'float32')
+sinetable = arange(tablelen + 1, dtype = float_type)
 sinetable = 0.7 * sin(twopi * sinetable/tablelen)
-sinetone = zeros((duration,), dtype = 'float32')
+sinetone = zeros((duration,), dtype = float_type)
 
 # compute sinetone at floating point period
 for i in range(duration):
@@ -39,7 +39,7 @@
     sinetone[i] = a + frac * (b -a)
 
 # apply some envelope
-float_ramp = arange(duration, dtype = 'float32')
+float_ramp = arange(duration, dtype = float_type)
 sinetone *= exp( - e * float_ramp / duration / decay)
 sinetone[:attack] *= exp( e * ( float_ramp[:attack] / attack - 1 ) )
 
--- a/python/demos/demo_sink_multi.py
+++ b/python/demos/demo_sink_multi.py
@@ -5,7 +5,7 @@
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,10 +22,11 @@
         vec, read = f.do_multi()
         g.do_multi(vec, read)
         total_frames += read
-    print "wrote", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks",
-    print "of", f.channels, "channels",
-    print "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri,
-    print "to", g.uri
+    outstr = "wrote %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " of %d channels" % f.channels
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    outstr += " to " + g.uri
+    print(outstr)
--- a/python/demos/demo_slicing.py
+++ b/python/demos/demo_slicing.py
@@ -6,7 +6,7 @@
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <duration>' % sys.argv[0]
+        print('usage: %s <inputfile> <duration>' % sys.argv[0])
         sys.exit(1)
     source_file = sys.argv[1]
     duration = float(sys.argv[2])
@@ -44,7 +44,8 @@
         total_frames_written += read
     total_duration = total_frames_written / float(samplerate)
     slice_n += 1
-    print 'created %(slice_n)s slices from %(source_base_name)s%(source_ext)s' % locals(),
-    print ' (total duration %(total_duration).2fs)' % locals()
+    outstr = 'created %(slice_n)s slices from %(source_base_name)s%(source_ext)s' % locals()
+    outstr += ' (total duration %(total_duration).2fs)' % locals()
+    print(outstr)
     # close source and sink files
     del f, g
--- a/python/demos/demo_source.py
+++ b/python/demos/demo_source.py
@@ -5,7 +5,7 @@
 
 if __name__ == '__main__':
     if len(sys.argv) < 2:
-        print 'usage: %s <inputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
     samplerate = 0
     hop_size = 256
@@ -20,7 +20,9 @@
         vec, read = f()
         total_frames += read
         if read < f.hop_size: break
-    print "read", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri
+    outstr = "read %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    print(outstr)
--- a/python/demos/demo_specdesc.py
+++ b/python/demos/demo_specdesc.py
@@ -1,14 +1,14 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import fvec, source, pvoc, specdesc
-from numpy import hstack
+import numpy as np
+from aubio import source, pvoc, specdesc
 
 win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
+hop_s = win_s // 4          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -30,7 +30,7 @@
 
 for method in methods:
     cands = []
-    all_descs[method] = fvec(0)
+    all_descs[method] = np.array([])
     o[method] = specdesc(method, win_s)
 
 total_frames = 0
@@ -39,17 +39,17 @@
 while True:
     samples, read = s()
     fftgrain = pv(samples)
-    #print "%f" % ( total_frames / float(samplerate) ),
+    #outstr = "%f" % ( total_frames / float(samplerate) )
     for method in methods:
         specdesc_val = o[method](fftgrain)[0]
-        all_descs[method] = hstack ( [all_descs[method], specdesc_val] )
-        #print "%f" % specdesc_val,
-    #print
+        all_descs[method] = np.append(all_descs[method], specdesc_val)
+        #outstr += " %f" % specdesc_val
+    #print(outstr)
     total_frames += read
     if read < hop_s: break
 
 if 1:
-    print "done computing, now plotting"
+    print("done computing, now plotting")
     import matplotlib.pyplot as plt
     from demo_waveform_plot import get_waveform_plot
     from demo_waveform_plot import set_xlabels_sample2time
--- a/python/demos/demo_spectrogram.py
+++ b/python/demos/demo_spectrogram.py
@@ -1,63 +1,77 @@
 #! /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
+import sys, os.path
+from aubio import pvoc, source, float_type
+from numpy import zeros, log10, vstack
+import matplotlib.pyplot as plt
 
 def get_spectrogram(filename, samplerate = 0):
-  win_s = 512                                        # fft window size
-  hop_s = win_s / 2                                  # hop size
-  fft_s = win_s / 2 + 1                              # spectrum bins
+    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
-  if samplerate == 0: samplerate = a.samplerate
-  pv = pvoc(win_s, hop_s)                            # phase vocoder
-  specgram = zeros([0, fft_s], dtype='float32')      # numpy array to store spectrogram
+    a = source(filename, samplerate, hop_s)            # source file
+    if samplerate == 0: samplerate = a.samplerate
+    pv = pvoc(win_s, hop_s)                            # phase vocoder
+    specgram = zeros([0, fft_s], dtype=float_type)     # 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
+    # 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
+    # plotting
+    fig = plt.imshow(log10(specgram.T + .001), origin = 'bottom', aspect = 'auto', cmap=plt.cm.gray_r)
+    ax = fig.axes
+    ax.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
+    outstr = "total time: %0.2fs" % total_time
+    print(outstr + ", 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
+    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
+    x_ticks, x_labels = get_rounded_ticks ( len(specgram), time_step, n_xticks )
+    y_ticks, y_labels = get_rounded_ticks ( len(specgram[0]), (samplerate / 1000. / 2.) / len(specgram[0]), n_yticks )
+    ax.set_xticks( x_ticks )
+    ax.set_yticks ( y_ticks )
+    ax.set_xticklabels( x_labels )
+    ax.set_yticklabels ( y_labels )
+    ax.set_ylabel('Frequency (kHz)')
+    ax.set_xlabel('Time (s)')
+    ax.set_title(os.path.basename(filename))
+    for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
+            ax.get_xticklabels() + ax.get_yticklabels()):
+        item.set_fontsize('x-small')
+    return fig
 
-  # 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()
+    if len(sys.argv) < 2:
+        print("Usage: %s <filename>" % sys.argv[0])
+    else:
+        for soundfile in sys.argv[1:]:
+            fig = get_spectrogram(soundfile)
+            # display graph
+            plt.show()
+            #outimage = os.path.basename(soundfile) + '.png'
+            #print ("writing: " + outimage)
+            #plt.savefig(outimage)
+            plt.close()
--- a/python/demos/demo_tempo.py
+++ b/python/demos/demo_tempo.py
@@ -4,10 +4,10 @@
 from aubio import tempo, source
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -33,7 +33,7 @@
     is_beat = o(samples)
     if is_beat:
         this_beat = int(total_frames - delay + is_beat[0] * hop_s)
-        print "%f" % (this_beat / float(samplerate))
+        print("%f" % (this_beat / float(samplerate)))
         beats.append(this_beat)
     total_frames += read
     if read < hop_s: break
--- a/python/demos/demo_tempo_plot.py
+++ b/python/demos/demo_tempo_plot.py
@@ -4,10 +4,10 @@
 from aubio import tempo, source
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -39,11 +39,11 @@
 
 if len(beats) > 1:
     # do plotting
-    from numpy import array, arange, mean, median, diff
+    from numpy import mean, median, diff
     import matplotlib.pyplot as plt
     bpms = 60./ diff(beats)
-    print 'mean period:', "%.2f" % mean(bpms), 'bpm', 'median', "%.2f" % median(bpms), 'bpm'
-    print 'plotting', filename
+    print('mean period: %.2fbpm, median: %.2fbpm' % (mean(bpms), median(bpms)))
+    print('plotting %s' % filename)
     plt1 = plt.axes([0.1, 0.75, 0.8, 0.19])
     plt2 = plt.axes([0.1, 0.1, 0.8, 0.65], sharex = plt1)
     plt.rc('lines',linewidth='.8')
@@ -75,5 +75,5 @@
     plt.show()
 
 else:
-    print 'mean period:', "%.2f" % 0, 'bpm', 'median', "%.2f" % 0, 'bpm',
-    print 'nothing to plot, file too short?'
+    print('mean period: %.2fbpm, median: %.2fbpm' % (0, 0))
+    print('plotting %s' % filename)
--- /dev/null
+++ b/python/demos/demo_timestretch.py
@@ -1,0 +1,110 @@
+#! /usr/bin/env python
+
+# Implementation of the timescale algorithm according to Dan Ellis, *A Phase
+# Vocoder in Matlab*.  http://www.ee.columbia.edu/~dpwe/resources/matlab/pvoc/
+
+# This file follows the original implementation, with analysis in a first pass,
+# and synthesis in a second pass.
+
+import sys
+from aubio import source, sink, pvoc, mfcc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 1024
+hop_s = win_s / 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+    print("Usage: %s <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+    print("""Examples:
+    # twice faster
+    {0} track_01.mp3 track_01_faster.wav 2.0
+    # twice slower
+    {0} track_02.flac track_02_slower.wav 0.5
+    # one and a half time faster, resampling first the input to 22050
+    {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+    sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+# allocate memory to store norms and phases
+n_blocks = source_in.duration // hop_s + 1
+# adding an empty frame at end of spectrogram
+norms  = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+phases = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+
+block_read = 0
+while True:
+    # read from source
+    samples, read = source_in()
+    # compute fftgrain
+    spec = p(samples)
+    # store current grain
+    norms[block_read] = spec.norm
+    phases[block_read] = spec.phas
+    # until end of file
+    if read < hop_s: break
+    # increment block counter
+    block_read += 1
+
+# just to make sure
+#source_in.close()
+
+sink_out = sink(output_filename, samplerate)
+
+# interpolated time steps (j = alpha * i)
+steps = np.arange(0, n_blocks, rate, dtype = float_type)
+# initial phase
+phas_acc = phases[0]
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+new_grain = cvec(win_s)
+
+for (t, step) in enumerate(steps):
+
+    frac = 1. - np.mod(step, 1.0)
+    # get pair of frames
+    t_norms = norms[int(step):int(step+2)]
+    t_phases = phases[int(step):int(step+2)]
+
+    # compute interpolated frame
+    new_grain.norm = frac * t_norms[0] + (1. - frac) * t_norms[1]
+    new_grain.phas = phas_acc
+    #print t, step, new_grain.norm
+    #print t, step, phas_acc
+
+    # psola
+    samples = p.rdo(new_grain)
+    if t > warmup: # skip the first few frames to warm up phase vocoder
+        # write to sink
+        sink_out(samples, hop_s)
+
+    # calculate phase advance
+    dphas = t_phases[1] - t_phases[0] - phi_advance
+    # unwrap angle to [-pi; pi]
+    dphas = unwrap2pi(dphas)
+    # cumulate phase, to be used for next frame
+    phas_acc += phi_advance + dphas
+
+for t in range(warmup + 1): # purge the last frames from the phase vocoder
+    new_grain.norm[:] = 0
+    new_grain.phas[:] = 0
+    samples = p.rdo(new_grain)
+    sink_out(samples, read if t == warmup else hop_s)
+
+# just to make sure
+#sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+    len(steps), output_filename))
--- /dev/null
+++ b/python/demos/demo_timestretch_online.py
@@ -1,0 +1,110 @@
+#! /usr/bin/env python
+
+# Implementation of the timescale algorithm according to Dan Ellis, *A Phase
+# Vocoder in Matlab*.  http://www.ee.columbia.edu/~dpwe/resources/matlab/pvoc/
+
+# This file performs both analysis and synthesis in a single pass. See also
+# `demo_timestretch.py` for a version following the original implementation.
+
+import sys
+from aubio import source, sink, pvoc, mfcc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 1024
+hop_s = win_s / 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+    print("Usage: %s <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+    print("""Examples:
+    # twice faster
+    {0} track_01.mp3 track_01_faster.wav 2.0
+    # twice slower
+    {0} track_02.flac track_02_slower.wav 0.5
+    # one and a half time faster, resampling first the input to 22050
+    {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+    sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+sink_out = sink(output_filename, samplerate)
+
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+old_grain = cvec(win_s)
+new_grain = cvec(win_s)
+
+block_read = 0
+interp_read = 0
+interp_block = 0
+while True:
+
+    samples, read = source_in()
+    cur_grain = p(samples)
+
+    if block_read == 1:
+        phas_acc = old_grain.phas
+
+    #print "block_read", block_read
+    while True and (block_read > 0):
+        if interp_read >= block_read:
+            break
+        #print "`--- interp_block:", interp_block,
+        #print 'at orig_block', interp_read, '<- from', block_read - 1, block_read,
+        #print 'old_grain', old_grain, 'cur_grain', cur_grain
+        # time to compute interp grain
+        frac = 1. - np.mod(interp_read, 1.0)
+
+        # compute interpolated frame
+        new_grain.norm = frac * old_grain.norm + (1. - frac) * cur_grain.norm
+        new_grain.phas = phas_acc
+
+        # psola
+        samples = p.rdo(new_grain)
+        if interp_read > warmup: # skip the first frames to warm up phase vocoder
+            # write to sink
+            sink_out(samples, hop_s)
+
+        # calculate phase advance
+        dphas = cur_grain.phas - old_grain.phas - phi_advance
+        # unwrap angle to [-pi; pi]
+        dphas = unwrap2pi(dphas)
+        # cumulate phase, to be used for next frame
+        phas_acc += phi_advance + dphas
+
+        # prepare for next interp block
+        interp_block += 1
+        interp_read = interp_block * rate
+        if interp_read >= block_read:
+            break
+
+    # copy cur_grain to old_grain
+    old_grain.norm = np.copy(cur_grain.norm)
+    old_grain.phas = np.copy(cur_grain.phas)
+
+    block_read += 1
+    if read < hop_s: break
+
+for t in range(warmup + 2): # purge the last frames from the phase vocoder
+    new_grain.norm[:] = 0
+    new_grain.phas[:] = 0
+    samples = p.rdo(new_grain)
+    sink_out(samples, read if t == warmup + 1 else hop_s)
+
+# just to make sure
+source_in.close()
+sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+    interp_block, output_filename))
--- a/python/demos/demo_tss.py
+++ b/python/demos/demo_tss.py
@@ -4,44 +4,44 @@
 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)
+    if len(sys.argv) < 2:
+        print('usage: %s <inputfile> <outputfile_transient> <outputfile_steady>' % sys.argv[0])
+        sys.exit(1)
 
-  samplerate = 44100
-  win_s = 1024      # fft size
-  hop_s = win_s / 4 # block size
-  threshold = 0.5
+    samplerate = 44100
+    win_s = 1024       # fft size
+    hop_s = win_s // 4 # block size
+    threshold = 0.5
 
-  f = source(sys.argv[1], samplerate, hop_s)
-  g = sink(sys.argv[2], samplerate)
-  h = sink(sys.argv[3], samplerate)
+    f = source(sys.argv[1], samplerate, hop_s)
+    g = sink(sys.argv[2], samplerate)
+    h = sink(sys.argv[3], samplerate)
 
-  pva = pvoc(win_s, hop_s)    # a phase vocoder
-  pvb = pvoc(win_s, hop_s)    # another phase vocoder
-  t = tss(win_s, hop_s)       # transient steady state separation
+    pva = pvoc(win_s, hop_s)    # a phase vocoder
+    pvb = pvoc(win_s, hop_s)    # another phase vocoder
+    t = tss(win_s, hop_s)       # transient steady state separation
 
-  t.set_threshold(threshold)
+    t.set_threshold(threshold)
 
-  read = hop_s
+    read = hop_s
 
-  while read:
-    samples, read = f()               # read file
-    spec = pva(samples)                # compute spectrum
-    trans_spec, stead_spec = t(spec)  # transient steady-state separation
-    transients = pva.rdo(trans_spec)   # overlap-add synthesis of transients
-    steadstate = pvb.rdo(stead_spec)   # overlap-add synthesis of steady states
-    g(transients, read)               # write transients to output
-    h(steadstate, read)               # write steady states to output
+    while read:
+        samples, read = f()               # read file
+        spec = pva(samples)               # compute spectrum
+        trans_spec, stead_spec = t(spec)  # transient steady-state separation
+        transients = pva.rdo(trans_spec)  # overlap-add synthesis of transients
+        steadstate = pvb.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
+    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()
+    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()
--- a/python/demos/demo_waveform_plot.py
+++ b/python/demos/demo_waveform_plot.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import pvoc, source
+from aubio import source
 from numpy import zeros, hstack
 
 def get_waveform_plot(filename, samplerate = 0, block_size = 4096, ax = None, downsample = 2**4):
@@ -21,7 +21,7 @@
     while True:
         samples, read = a()
         # keep some data to plot it later
-        new_maxes = (abs(samples.reshape(hop_s/downsample, downsample))).max(axis=0)
+        new_maxes = (abs(samples.reshape(hop_s//downsample, downsample))).max(axis=0)
         allsamples_max = hstack([allsamples_max, new_maxes])
         total_frames += read
         if read < hop_s: break
@@ -48,7 +48,7 @@
 if __name__ == '__main__':
     import matplotlib.pyplot as plt
     if len(sys.argv) < 2:
-        print "Usage: %s <filename>" % sys.argv[0]
+        print("Usage: %s <filename>" % sys.argv[0])
     else:
         for soundfile in sys.argv[1:]:
             get_waveform_plot(soundfile)
--- a/python/ext/aubio-types.h
+++ b/python/ext/aubio-types.h
@@ -1,6 +1,8 @@
 #include <Python.h>
 #include <structmember.h>
 
+#include "aubio-generated.h"
+
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
 
 // define numpy unique symbols for aubio
@@ -33,31 +35,38 @@
 #define Py_aubio_default_samplerate 44100
 
 #if HAVE_AUBIO_DOUBLE
-#error "Ouch! Python interface for aubio has not been much tested yet."
+// 64 bit precision with HAVE_AUBIO_DOUBLE=1
 #define AUBIO_NPY_SMPL NPY_DOUBLE
+#define AUBIO_NPY_SMPL_STR "float64"
+#define AUBIO_NPY_SMPL_CHR "d"
 #else
+// default is 32 bit precision
 #define AUBIO_NPY_SMPL NPY_FLOAT
+#define AUBIO_NPY_SMPL_STR "float32"
+#define AUBIO_NPY_SMPL_CHR "f"
 #endif
 
-// special python type for cvec
-typedef struct
-{
-  PyObject_HEAD
-  cvec_t * o;
-  uint_t length;
-  uint_t channels;
-} Py_cvec;
+// compat with Python < 2.6
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
 extern PyTypeObject Py_cvecType;
 
+PyObject * new_py_fvec(uint_t length);
+PyObject * new_py_cvec(uint_t length);
+PyObject * new_py_fmat(uint_t height, uint_t length);
+
 // defined in aubio-proxy.c
+extern int PyAubio_IsValidVector (PyObject *input);
+
 extern PyObject *PyAubio_CFvecToArray (fvec_t * self);
-extern fvec_t *PyAubio_ArrayToCFvec (PyObject * self);
+extern int PyAubio_ArrayToCFvec (PyObject * self, fvec_t *out);
 
-extern Py_cvec *PyAubio_CCvecToPyCvec (cvec_t * self);
-extern cvec_t *PyAubio_ArrayToCCvec (PyObject *input);
+extern int PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i);
 
 extern PyObject *PyAubio_CFmatToArray (fmat_t * self);
-extern fmat_t *PyAubio_ArrayToCFmat (PyObject *input);
+extern int PyAubio_ArrayToCFmat (PyObject *input, fmat_t *out);
 
 // hand written wrappers
 extern PyTypeObject Py_filterType;
--- a/python/ext/aubiomodule.c
+++ b/python/ext/aubiomodule.c
@@ -1,6 +1,5 @@
 #define PY_AUBIO_MODULE_MAIN
 #include "aubio-types.h"
-#include "aubio-generated.h"
 #include "py-musicutils.h"
 
 static char aubio_module_doc[] = "Python module for the aubio library";
@@ -83,11 +82,11 @@
 Py_alpha_norm (PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   smpl_t alpha;
   PyObject *result;
 
-  if (!PyArg_ParseTuple (args, "Of:alpha_norm", &input, &alpha)) {
+  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":alpha_norm", &input, &alpha)) {
     return NULL;
   }
 
@@ -95,14 +94,12 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  result = Py_BuildValue ("f", fvec_alpha_norm (vec, alpha));
+  result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, fvec_alpha_norm (&vec, alpha));
   if (result == NULL) {
     return NULL;
   }
@@ -116,7 +113,7 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -131,7 +128,7 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -146,7 +143,7 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -161,7 +158,7 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -174,7 +171,7 @@
 Py_zero_crossing_rate (PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *result;
 
   if (!PyArg_ParseTuple (args, "O:zero_crossing_rate", &input)) {
@@ -185,14 +182,12 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  result = Py_BuildValue ("f", aubio_zero_crossing_rate (vec));
+  result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, aubio_zero_crossing_rate (&vec));
   if (result == NULL) {
     return NULL;
   }
@@ -204,7 +199,7 @@
 Py_min_removal(PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
 
   if (!PyArg_ParseTuple (args, "O:min_removal", &input)) {
     return NULL;
@@ -214,19 +209,17 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  fvec_min_removal (vec);
+  fvec_min_removal (&vec);
 
   // since this function does not return, we could return None
   //Py_RETURN_NONE;
   // however it is convenient to return the modified vector
-  return (PyObject *) PyAubio_CFvecToArray(vec);
+  return (PyObject *) PyAubio_CFvecToArray(&vec);
   // or even without converting it back to an array
   //Py_INCREF(vec);
   //return (PyObject *)vec;
@@ -245,13 +238,28 @@
   {"silence_detection", Py_aubio_silence_detection, METH_VARARGS, Py_aubio_silence_detection_doc},
   {"level_detection", Py_aubio_level_detection, METH_VARARGS, Py_aubio_level_detection_doc},
   {"window", Py_aubio_window, METH_VARARGS, Py_aubio_window_doc},
-  {NULL, NULL} /* Sentinel */
+  {NULL, NULL, 0, NULL} /* Sentinel */
 };
 
-PyMODINIT_FUNC
-init_aubio (void)
+#if PY_MAJOR_VERSION >= 3
+// Python3 module definition
+static struct PyModuleDef moduledef = {
+   PyModuleDef_HEAD_INIT,
+   "_aubio",          /* m_name */
+   aubio_module_doc,  /* m_doc */
+   -1,                /* m_size */
+   aubio_methods,     /* m_methods */
+   NULL,              /* m_reload */
+   NULL,              /* m_traverse */
+   NULL,              /* m_clear */
+   NULL,              /* m_free */
+};
+#endif
+
+static PyObject *
+initaubio (void)
 {
-  PyObject *m;
+  PyObject *m = NULL;
   int err;
 
   // fvec is defined in __init__.py
@@ -265,13 +273,17 @@
       // generated objects
       || (generated_types_ready() < 0 )
   ) {
-    return;
+    return m;
   }
 
+#if PY_MAJOR_VERSION >= 3
+  m = PyModule_Create(&moduledef);
+#else
   m = Py_InitModule3 ("_aubio", aubio_methods, aubio_module_doc);
+#endif
 
   if (m == NULL) {
-    return;
+    return m;
   }
 
   err = _import_array ();
@@ -295,9 +307,27 @@
   Py_INCREF (&Py_sinkType);
   PyModule_AddObject (m, "sink", (PyObject *) & Py_sinkType);
 
+  PyModule_AddStringConstant(m, "float_type", AUBIO_NPY_SMPL_STR);
+
   // add generated objects
   add_generated_objects(m);
 
   // add ufunc
   add_ufuncs(m);
+
+  return m;
 }
+
+#if PY_MAJOR_VERSION >= 3
+    // Python3 init
+    PyMODINIT_FUNC PyInit__aubio(void)
+    {
+        return initaubio();
+    }
+#else
+    // Python 2 init
+    PyMODINIT_FUNC init_aubio(void)
+    {
+        initaubio();
+    }
+#endif
--- a/python/ext/aubioproxy.c
+++ b/python/ext/aubioproxy.c
@@ -1,12 +1,30 @@
 #include "aubio-types.h"
 
-fvec_t *
-PyAubio_ArrayToCFvec (PyObject *input) {
-  PyObject *array;
-  fvec_t *vec;
+PyObject *
+new_py_fvec(uint_t length) {
+    npy_intp dims[] = { length, 1 };
+    return PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+}
+
+PyObject *
+new_py_fmat(uint_t height, uint_t length) {
+    npy_intp dims[] = { height, length, 1 };
+    return PyArray_ZEROS(2, dims, AUBIO_NPY_SMPL, 0);
+}
+
+PyObject *
+PyAubio_CFvecToArray (fvec_t * self)
+{
+  npy_intp dims[] = { self->length, 1 };
+  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data);
+}
+
+int
+PyAubio_IsValidVector (PyObject * input) {
+  npy_intp length;
   if (input == NULL) {
     PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+    return 0;
   }
   // parsing input object into a Py_fvec
   if (PyArray_Check(input)) {
@@ -14,74 +32,47 @@
     // 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;
+      return 0;
     } else if (PyArray_NDIM ((PyArrayObject *)input) > 1) {
       PyErr_SetString (PyExc_ValueError,
           "input array has more than one dimensions");
-      goto fail;
+      return 0;
     }
 
     if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
       PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
+      return 0;
     } 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;
+      PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+      return 0;
     }
 
-    // vec = new_fvec (vec->length);
-    // no need to really allocate fvec, just its struct member
-    vec = (fvec_t *)malloc(sizeof(fvec_t));
-    long length = PyArray_SIZE ((PyArrayObject *)array);
-    if (length > 0) {
-      vec->length = (uint_t)length;
-    } else {
+    length = PyArray_SIZE ((PyArrayObject *)input);
+    if (length <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array size should be greater than 0");
-      goto fail;
+      return 0;
     }
-    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;
+    return 0;
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept vector of float as input");
-    return NULL;
+    return 0;
   }
-
-  return vec;
-
-fail:
-  return NULL;
+  return 1;
 }
 
-PyObject *
-PyAubio_CFvecToArray (fvec_t * self)
-{
-  npy_intp dims[] = { self->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data);
-}
+int
+PyAubio_ArrayToCFvec (PyObject *input, fvec_t *out) {
 
-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;
+  if (!PyAubio_IsValidVector(input)){
+    return 0;
   }
+
+  out->length = (uint_t) PyArray_SIZE ((PyArrayObject *)input);
+  out->data = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)input, 0);
+  return 1;
 }
 
 PyObject *
@@ -101,14 +92,13 @@
   return array;
 }
 
-fmat_t *
-PyAubio_ArrayToCFmat (PyObject *input) {
-  PyObject *array;
-  fmat_t *mat;
-  uint_t i;
+int
+PyAubio_ArrayToCFmat (PyObject *input, fmat_t *mat) {
+  uint_t i, new_height;
+  npy_intp length, height;
   if (input == NULL) {
     PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+    return 0;
   }
   // parsing input object into a Py_fvec
   if (PyArray_Check(input)) {
@@ -116,56 +106,53 @@
     // 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;
+      return 0;
     } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
       PyErr_SetString (PyExc_ValueError,
           "input array has more than two dimensions");
-      goto fail;
+      return 0;
     }
 
     if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
       PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
+      return 0;
     } 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;
+      PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+      return 0;
     }
 
     // no need to really allocate fvec, just its struct member
-    mat = (fmat_t *)malloc(sizeof(fmat_t));
-    long length = PyArray_DIM ((PyArrayObject *)array, 1);
-    if (length > 0) {
-      mat->length = (uint_t)length;
-    } else {
+    length = PyArray_DIM ((PyArrayObject *)input, 1);
+    if (length <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array dimension 1 should be greater than 0");
-      goto fail;
+      return 0;
     }
-    long height = PyArray_DIM ((PyArrayObject *)array, 0);
-    if (height > 0) {
-      mat->height = (uint_t)height;
-    } else {
+    height = PyArray_DIM ((PyArrayObject *)input, 0);
+    if (height <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array dimension 0 should be greater than 0");
-      goto fail;
+      return 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;
+    return 0;
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept matrix of float as input");
-    return NULL;
+    return 0;
   }
 
-  return mat;
+  new_height = (uint_t)PyArray_DIM ((PyArrayObject *)input, 0);
+  if (mat->height != new_height) {
+    if (mat->data) {
+      free(mat->data);
+    }
+    mat->data = (smpl_t **)malloc(sizeof(smpl_t*) * new_height);
+  }
 
-fail:
-  return NULL;
+  mat->height = new_height;
+  mat->length = (uint_t)PyArray_DIM ((PyArrayObject *)input, 1);
+  for (i=0; i< mat->height; i++) {
+    mat->data[i] = (smpl_t*)PyArray_GETPTR1 ((PyArrayObject *)input, i);
+  }
+  return 1;
 }
-
--- a/python/ext/aubiowraphell.h
+++ /dev/null
@@ -1,90 +1,0 @@
-#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;
--- a/python/ext/py-cvec.c
+++ b/python/ext/py-cvec.c
@@ -1,17 +1,51 @@
 #include "aubio-types.h"
 
-/* cvec type definition 
+/* cvec type definition
 
 class cvec():
-    def __init__(self, length = 1024):
-        self.length = length 
-        self.norm = array(length)
-        self.phas = array(length)
+    def __new__(self, length = 1024):
+        self.length = length / 2 + 1
+        self.norm = np.zeros(length / 2 + 1)
+        self.phas = np.zeros(length / 2 + 1)
 
 */
 
+// special python type for cvec
+typedef struct
+{
+  PyObject_HEAD
+  PyObject *norm;
+  PyObject *phas;
+  uint_t length;
+} Py_cvec;
+
 static char Py_cvec_doc[] = "cvec object";
 
+
+PyObject *
+new_py_cvec(uint_t length) {
+  Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
+  npy_intp dims[] = { length / 2 + 1, 1 };
+  vec->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  vec->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  vec->length = length / 2 + 1;
+  return (PyObject*)vec;
+}
+
+int
+PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) {
+  if (PyObject_TypeCheck (input, &Py_cvecType)) {
+      Py_cvec * in = (Py_cvec *)input;
+      i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0);
+      i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0);
+      i->length = ((Py_cvec*)input)->length;
+      return 1;
+  } else {
+      PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
+      return 0;
+  }
+}
+
 static PyObject *
 Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -24,7 +58,6 @@
     return NULL;
   }
 
-
   self = (Py_cvec *) type->tp_alloc (type, 0);
 
   self->length = Py_default_vector_length / 2 + 1;
@@ -47,11 +80,9 @@
 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;
-  }
-
+  npy_intp dims[] = { self->length, 1 };
+  self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
   return 0;
 }
 
@@ -58,8 +89,9 @@
 static void
 Py_cvec_del (Py_cvec * self)
 {
-  del_cvec (self->o);
-  self->ob_type->tp_free ((PyObject *) self);
+  Py_DECREF(self->norm);
+  Py_DECREF(self->phas);
+  Py_TYPE(self)->tp_free ((PyObject *) self);
 }
 
 static PyObject *
@@ -69,7 +101,7 @@
   PyObject *args = NULL;
   PyObject *result = NULL;
 
-  format = PyString_FromString ("aubio cvec of %d elements");
+  format = PyUnicode_FromString ("aubio cvec of %d elements");
   if (format == NULL) {
     goto fail;
   }
@@ -78,9 +110,9 @@
   if (args == NULL) {
     goto fail;
   }
-  cvec_print ( self->o );
+  // hide actual norm / phas content
 
-  result = PyString_Format (format, args);
+  result = PyUnicode_Format (format, args);
 
 fail:
   Py_XDECREF (format);
@@ -90,152 +122,61 @@
 }
 
 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);
+  // we want self->norm to still exist after our caller return it
+  Py_INCREF(self->norm);
+  return (PyObject*)(self->norm);
 }
 
 PyObject *
 Py_cvec_get_phas (Py_cvec * self, void *closure)
 {
-  return PyAubio_CvecPhasToArray(self);
+  // we want self->phas to still exist after our caller return it
+  Py_INCREF(self->phas);
+  return (PyObject *)(self->phas);
 }
 
 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;
+  npy_intp length;
+  if (!PyAubio_IsValidVector(input)) {
+    return 1;
   }
-  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");
+  length = PyArray_SIZE ((PyArrayObject *)input);
+  if (length != vec->length) {
+    PyErr_Format (PyExc_ValueError,
+        "input array has length %ld, but cvec has length %d", length,
+        vec->length);
     return 1;
   }
 
-  Py_INCREF(array);
+  Py_XDECREF(vec->norm);
+  vec->norm = input;
+  Py_INCREF(vec->norm);
   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;
+  npy_intp length;
+  if (!PyAubio_IsValidVector(input)) {
+    return 1;
   }
-  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");
+  length = PyArray_SIZE ((PyArrayObject *)input);
+  if (length != vec->length) {
+    PyErr_Format (PyExc_ValueError,
+        "input array has length %ld, but cvec has length %d", length,
+        vec->length);
     return 1;
   }
 
-  Py_INCREF(array);
+  Py_XDECREF(vec->phas);
+  vec->phas = input;
+  Py_INCREF(vec->phas);
   return 0;
-
-fail:
-  return 1;
 }
 
 static PyMemberDef Py_cvec_members[] = {
@@ -260,8 +201,7 @@
 };
 
 PyTypeObject Py_cvecType = {
-  PyObject_HEAD_INIT (NULL)
-  0,                            /* ob_size           */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "aubio.cvec",                 /* tp_name           */
   sizeof (Py_cvec),             /* tp_basicsize      */
   0,                            /* tp_itemsize       */
@@ -272,7 +212,7 @@
   0,                            /* tp_compare        */
   (reprfunc) Py_cvec_repr,      /* tp_repr           */
   0,                            /* tp_as_number      */
-  0, //&Py_cvec_tp_as_sequence,      /* tp_as_sequence    */
+  0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
   0,                            /* tp_as_mapping     */
   0,                            /* tp_hash           */
   0,                            /* tp_call           */
@@ -299,4 +239,13 @@
   (initproc) Py_cvec_init,      /* tp_init           */
   0,                            /* tp_alloc          */
   Py_cvec_new,                  /* tp_new            */
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
 };
--- a/python/ext/py-fft.c
+++ b/python/ext/py-fft.c
@@ -1,10 +1,20 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 static char Py_fft_doc[] = "fft object";
 
-AUBIO_DECLARE(fft, uint_t win_s)
+typedef struct
+{
+  PyObject_HEAD
+  aubio_fft_t * o;
+  uint_t win_s;
+  // do / rdo input vectors
+  fvec_t vecin;
+  cvec_t cvecin;
+  // do / rdo output results
+  PyObject *doout;
+  PyObject *rdoout;
+} Py_fft;
 
-//AUBIO_NEW(fft)
 static PyObject *
 Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -36,62 +46,100 @@
   return (PyObject *) self;
 }
 
+static int
+Py_fft_init (Py_fft * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_aubio_fft (self->win_s);
+  if (self->o == NULL) {
+    PyErr_Format(PyExc_RuntimeError,
+        "error creating fft with win_s=%d "
+        "(should be a power of 2 greater than 1; "
+        "try recompiling aubio with --enable-fftw3)",
+        self->win_s);
+    return -1;
+  }
 
-AUBIO_INIT(fft, self->win_s)
+  self->doout = new_py_cvec(self->win_s);
+  self->rdoout = new_py_fvec(self->win_s);
 
-AUBIO_DEL(fft)
+  return 0;
+}
 
-static PyObject * 
-Py_fft_do(PyObject * self, PyObject * args)
+static void
+Py_fft_del (Py_fft *self, PyObject *unused)
 {
+  Py_XDECREF(self->doout);
+  Py_XDECREF(self->rdoout);
+  if (self->o) {
+    del_aubio_fft(self->o);
+  }
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *
+Py_fft_do(Py_fft * self, PyObject * args)
+{
   PyObject *input;
-  fvec_t *vec;
-  cvec_t *output;
+  cvec_t c_out;
 
   if (!PyArg_ParseTuple (args, "O", &input)) {
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
+  if (!PyAubio_ArrayToCFvec(input, &(self->vecin))) {
+    return NULL;
+  }
 
-  if (vec == NULL) {
+  if (self->vecin.length != self->win_s) {
+    PyErr_Format(PyExc_ValueError,
+                 "input array has length %d, but fft expects length %d",
+                 self->vecin.length, self->win_s);
     return NULL;
   }
 
-  output = new_cvec(((Py_fft *) self)->win_s);
-
+  Py_INCREF(self->doout);
+  if (!PyAubio_PyCvecToCCvec(self->doout, &c_out)) {
+    return NULL;
+  }
   // compute the function
-  aubio_fft_do (((Py_fft *)self)->o, vec, output);
-  return (PyObject *)PyAubio_CCvecToPyCvec(output);
+  aubio_fft_do (self->o, &(self->vecin), &c_out);
+  return self->doout;
 }
 
-AUBIO_MEMBERS_START(fft) 
+static PyMemberDef Py_fft_members[] = {
   {"win_s", T_INT, offsetof (Py_fft, win_s), READONLY,
     "size of the window"},
-AUBIO_MEMBERS_STOP(fft)
+  {NULL}
+};
 
-static PyObject * 
+static PyObject *
 Py_fft_rdo(Py_fft * self, PyObject * args)
 {
   PyObject *input;
-  cvec_t *vec;
-  fvec_t *output;
+  fvec_t out;
 
   if (!PyArg_ParseTuple (args, "O", &input)) {
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCCvec (input);
+  if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) {
+    return NULL;
+  }
 
-  if (vec == NULL) {
+  if (self->cvecin.length != self->win_s / 2 + 1) {
+    PyErr_Format(PyExc_ValueError,
+                 "input cvec has length %d, but fft expects length %d",
+                 self->cvecin.length, self->win_s / 2 + 1);
     return NULL;
   }
 
-  output = new_fvec(self->win_s);
-
+  Py_INCREF(self->rdoout);
+  if (!PyAubio_ArrayToCFvec(self->rdoout, &out) ) {
+    return NULL;
+  }
   // compute the function
-  aubio_fft_rdo (((Py_fft *)self)->o, vec, output);
-  return (PyObject *)PyAubio_CFvecToArray(output);
+  aubio_fft_rdo (self->o, &(self->cvecin), &out);
+  return self->rdoout;
 }
 
 static PyMethodDef Py_fft_methods[] = {
@@ -100,4 +148,52 @@
   {NULL}
 };
 
-AUBIO_TYPEOBJECT(fft, "aubio.fft")
+PyTypeObject Py_fftType = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.fft",
+  sizeof (Py_fft),
+  0,
+  (destructor) Py_fft_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_fft_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_fft_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_fft_methods,
+  Py_fft_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_fft_init,
+  0,
+  Py_fft_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+};
--- a/python/ext/py-filter.c
+++ b/python/ext/py-filter.c
@@ -5,6 +5,9 @@
   PyObject_HEAD
   aubio_filter_t * o;
   uint_t order;
+  fvec_t vec;
+  PyObject *out;
+  fvec_t c_out;
 } Py_filter;
 
 static char Py_filter_doc[] = "filter object";
@@ -47,7 +50,7 @@
   if (self->o == NULL) {
     return -1;
   }
-
+  self->out = NULL;
   return 0;
 }
 
@@ -54,15 +57,15 @@
 static void
 Py_filter_del (Py_filter * self)
 {
+  Py_XDECREF(self->out);
   del_aubio_filter (self->o);
-  self->ob_type->tp_free ((PyObject *) self);
+  Py_TYPE(self)->tp_free ((PyObject *) self);
 }
 
-static PyObject * 
+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;
@@ -72,19 +75,25 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &(self->vec))) {
     return NULL;
   }
 
+  // initialize output now
+  if (self->out == NULL) {
+    self->out = new_py_fvec(self->vec.length);
+  }
+
+  Py_INCREF(self->out);
+  if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out)) ) {
+    return NULL;
+  }
   // compute the function
-  fvec_t * out = new_fvec(vec->length);
-  aubio_filter_do_outplace (self->o, vec, out);
-  return PyAubio_CFvecToArray(out);
+  aubio_filter_do_outplace (self->o, &(self->vec), &(self->c_out));
+  return self->out;
 }
 
-static PyObject * 
+static PyObject *
 Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
 {
   uint_t err = 0;
@@ -102,7 +111,7 @@
   Py_RETURN_NONE;
 }
 
-static PyObject * 
+static PyObject *
 Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
 {
   uint_t err = 0;
@@ -156,8 +165,7 @@
 };
 
 PyTypeObject Py_filterType = {
-  PyObject_HEAD_INIT (NULL)
-  0,                            /* ob_size           */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "aubio.digital_filter",       /* tp_name           */
   sizeof (Py_filter),           /* tp_basicsize      */
   0,                            /* tp_itemsize       */
@@ -195,4 +203,13 @@
   (initproc) Py_filter_init,    /* tp_init           */
   0,                            /* tp_alloc          */
   Py_filter_new,                /* tp_new            */
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
 };
--- a/python/ext/py-filterbank.c
+++ b/python/ext/py-filterbank.c
@@ -1,10 +1,20 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 static char Py_filterbank_doc[] = "filterbank object";
 
-AUBIO_DECLARE(filterbank, uint_t n_filters; uint_t win_s)
+typedef struct
+{
+  PyObject_HEAD
+  aubio_filterbank_t * o;
+  uint_t n_filters;
+  uint_t win_s;
+  cvec_t vec;
+  fvec_t freqs;
+  fmat_t coeffs;
+  PyObject *out;
+  fvec_t c_out;
+} Py_filterbank;
 
-//AUBIO_NEW(filterbank)
 static PyObject *
 Py_filterbank_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -44,41 +54,67 @@
   return (PyObject *) self;
 }
 
+static int
+Py_filterbank_init (Py_filterbank * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_aubio_filterbank (self->n_filters, self->win_s);
+  if (self->o == NULL) {
+    PyErr_Format(PyExc_RuntimeError, "error creating filterbank with"
+        " n_filters=%d, win_s=%d", self->n_filters, self->win_s);
+    return -1;
+  }
+  self->out = new_py_fvec(self->n_filters);
 
-AUBIO_INIT(filterbank, self->n_filters, self->win_s)
+  return 0;
+}
 
-AUBIO_DEL(filterbank)
+static void
+Py_filterbank_del (Py_filterbank *self, PyObject *unused)
+{
+  if (self->o) {
+    free(self->coeffs.data);
+    del_aubio_filterbank(self->o);
+  }
+  Py_XDECREF(self->out);
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
 
 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 (!PyAubio_PyCvecToCCvec(input, &(self->vec) )) {
+    return NULL;
+  }
 
-  if (vec == NULL) {
+  if (self->vec.length != self->win_s / 2 + 1) {
+    PyErr_Format(PyExc_ValueError,
+                 "input cvec has length %d, but fft expects length %d",
+                 self->vec.length, self->win_s / 2 + 1);
     return NULL;
   }
 
-  out = new_fvec (self->n_filters);
-
+  Py_INCREF(self->out);
+  if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out))) {
+    return NULL;
+  }
   // compute the function
-  aubio_filterbank_do (self->o, vec, out);
-  return (PyObject *)PyAubio_CFvecToArray(out);
+  aubio_filterbank_do (self->o, &(self->vec), &(self->c_out));
+  return self->out;
 }
 
-AUBIO_MEMBERS_START(filterbank)
+static PyMemberDef Py_filterbank_members[] = {
   {"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)
+  {NULL} /* sentinel */
+};
 
 static PyObject *
 Py_filterbank_set_triangle_bands (Py_filterbank * self, PyObject *args)
@@ -87,7 +123,6 @@
 
   PyObject *input;
   uint_t samplerate;
-  fvec_t *freqs;
   if (!PyArg_ParseTuple (args, "OI", &input, &samplerate)) {
     return NULL;
   }
@@ -96,14 +131,12 @@
     return NULL;
   }
 
-  freqs = PyAubio_ArrayToCFvec (input);
-
-  if (freqs == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &(self->freqs) )) {
     return NULL;
   }
 
   err = aubio_filterbank_set_triangle_bands (self->o,
-      freqs, samplerate);
+      &(self->freqs), samplerate);
   if (err > 0) {
     PyErr_SetString (PyExc_ValueError,
         "error when setting filter to A-weighting");
@@ -137,21 +170,15 @@
   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");
+  if (!PyAubio_ArrayToCFmat(input, &(self->coeffs))) {
     return NULL;
   }
 
-  err = aubio_filterbank_set_coeffs (self->o, coeffs);
+  err = aubio_filterbank_set_coeffs (self->o, &(self->coeffs));
 
   if (err > 0) {
     PyErr_SetString (PyExc_ValueError,
@@ -180,4 +207,52 @@
   {NULL}
 };
 
-AUBIO_TYPEOBJECT(filterbank, "aubio.filterbank")
+PyTypeObject Py_filterbankType = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.filterbank",
+  sizeof (Py_filterbank),
+  0,
+  (destructor) Py_filterbank_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_filterbank_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_filterbank_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_filterbank_methods,
+  Py_filterbank_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_filterbank_init,
+  0,
+  Py_filterbank_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+};
--- a/python/ext/py-musicutils.c
+++ b/python/ext/py-musicutils.c
@@ -8,7 +8,6 @@
   fvec_t *window = NULL;
 
   if (!PyArg_ParseTuple (args, "|sI", &wintype, &winlen)) {
-    PyErr_SetString (PyExc_ValueError, "failed parsing arguments");
     return NULL;
   }
 
@@ -25,11 +24,10 @@
 Py_aubio_level_lin(PyObject *self, PyObject *args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *level_lin;
 
   if (!PyArg_ParseTuple (args, "O:level_lin", &input)) {
-    PyErr_SetString (PyExc_ValueError, "failed parsing arguments");
     return NULL;
   }
 
@@ -37,12 +35,11 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
-  level_lin = Py_BuildValue("f", aubio_level_lin(vec));
+  level_lin = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_level_lin(&vec));
   if (level_lin == NULL) {
     PyErr_SetString (PyExc_ValueError, "failed computing level_lin");
     return NULL;
@@ -55,11 +52,10 @@
 Py_aubio_db_spl(PyObject *self, PyObject *args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *db_spl;
 
   if (!PyArg_ParseTuple (args, "O:db_spl", &input)) {
-    PyErr_SetString (PyExc_ValueError, "failed parsing arguments");
     return NULL;
   }
 
@@ -67,12 +63,11 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
-  db_spl = Py_BuildValue("f", aubio_db_spl(vec));
+  db_spl = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_db_spl(&vec));
   if (db_spl == NULL) {
     PyErr_SetString (PyExc_ValueError, "failed computing db_spl");
     return NULL;
@@ -85,12 +80,11 @@
 Py_aubio_silence_detection(PyObject *self, PyObject *args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *silence_detection;
   smpl_t threshold;
 
-  if (!PyArg_ParseTuple (args, "Of:silence_detection", &input, &threshold)) {
-    PyErr_SetString (PyExc_ValueError, "failed parsing arguments");
+  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":silence_detection", &input, &threshold)) {
     return NULL;
   }
 
@@ -98,12 +92,11 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
-  silence_detection = Py_BuildValue("I", aubio_silence_detection(vec, threshold));
+  silence_detection = Py_BuildValue("I", aubio_silence_detection(&vec, threshold));
   if (silence_detection == NULL) {
     PyErr_SetString (PyExc_ValueError, "failed computing silence_detection");
     return NULL;
@@ -116,12 +109,11 @@
 Py_aubio_level_detection(PyObject *self, PyObject *args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *level_detection;
   smpl_t threshold;
 
-  if (!PyArg_ParseTuple (args, "Of:level_detection", &input, &threshold)) {
-    PyErr_SetString (PyExc_ValueError, "failed parsing arguments");
+  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":level_detection", &input, &threshold)) {
     return NULL;
   }
 
@@ -129,12 +121,11 @@
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
-  level_detection = Py_BuildValue("f", aubio_level_detection(vec, threshold));
+  level_detection = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_level_detection(&vec, threshold));
   if (level_detection == NULL) {
     PyErr_SetString (PyExc_ValueError, "failed computing level_detection");
     return NULL;
--- a/python/ext/py-musicutils.h
+++ b/python/ext/py-musicutils.h
@@ -1,5 +1,5 @@
-#ifndef _PY_AUBIO_MUSICUTILS_H_
-#define _PY_AUBIO_MUSICUTILS_H_
+#ifndef PY_AUBIO_MUSICUTILS_H
+#define PY_AUBIO_MUSICUTILS_H
 
 static char Py_aubio_window_doc[] = ""
 "window(string, integer) -> fvec\n"
@@ -71,4 +71,4 @@
 
 PyObject * Py_aubio_level_detection(PyObject *self, PyObject *args);
 
-#endif /* _PY_AUBIO_MUSICUTILS_H_ */
+#endif /* PY_AUBIO_MUSICUTILS_H */
--- a/python/ext/py-phasevoc.c
+++ b/python/ext/py-phasevoc.c
@@ -1,10 +1,22 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 static char Py_pvoc_doc[] = "pvoc object";
 
-AUBIO_DECLARE(pvoc, uint_t win_s; uint_t hop_s)
+typedef struct
+{
+  PyObject_HEAD
+  aubio_pvoc_t * o;
+  uint_t win_s;
+  uint_t hop_s;
+  fvec_t vecin;
+  cvec_t cvecin;
+  PyObject *output;
+  cvec_t c_output;
+  PyObject *routput;
+  fvec_t c_routput;
+} Py_pvoc;
 
-//AUBIO_NEW(pvoc)
+
 static PyObject *
 Py_pvoc_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -49,64 +61,99 @@
   return (PyObject *) self;
 }
 
+static int
+Py_pvoc_init (Py_pvoc * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_aubio_pvoc ( self->win_s, self->hop_s);
+  if (self->o == NULL) {
+    PyErr_Format(PyExc_RuntimeError,
+        "failed creating pvoc with win_s=%d, hop_s=%d",
+        self->win_s, self->hop_s);
+    return -1;
+  }
 
-AUBIO_INIT(pvoc, self->win_s, self->hop_s)
+  self->output = new_py_cvec(self->win_s);
+  self->routput = new_py_fvec(self->hop_s);
 
-AUBIO_DEL(pvoc)
+  return 0;
+}
 
-static PyObject * 
+
+static void
+Py_pvoc_del (Py_pvoc *self, PyObject *unused)
+{
+  Py_XDECREF(self->output);
+  Py_XDECREF(self->routput);
+  if (self->o) {
+    del_aubio_pvoc(self->o);
+  }
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+
+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 (!PyAubio_ArrayToCFvec (input, &(self->vecin) )) {
+    return NULL;
+  }
 
-  if (vec == NULL) {
+  if (self->vecin.length != self->hop_s) {
+    PyErr_Format(PyExc_ValueError,
+                 "input fvec has length %d, but pvoc expects length %d",
+                 self->vecin.length, self->hop_s);
     return NULL;
   }
 
-  output = new_cvec(self->win_s);
-
+  Py_INCREF(self->output);
+  if (!PyAubio_PyCvecToCCvec (self->output, &(self->c_output))) {
+    return NULL;
+  }
   // compute the function
-  aubio_pvoc_do (self->o, vec, output);
-  return (PyObject *)PyAubio_CCvecToPyCvec(output);
+  aubio_pvoc_do (self->o, &(self->vecin), &(self->c_output));
+  return self->output;
 }
 
-AUBIO_MEMBERS_START(pvoc) 
+static PyMemberDef Py_pvoc_members[] = {
   {"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)
+  { NULL } // sentinel
+};
 
-static PyObject * 
+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 (!PyAubio_PyCvecToCCvec (input, &(self->cvecin) )) {
+    return NULL;
+  }
 
-  if (vec == NULL) {
+  if (self->cvecin.length != self->win_s / 2 + 1) {
+    PyErr_Format(PyExc_ValueError,
+                 "input cvec has length %d, but pvoc expects length %d",
+                 self->cvecin.length, self->win_s / 2 + 1);
     return NULL;
   }
 
-  output = new_fvec(self->hop_s);
-
+  Py_INCREF(self->routput);
+  if (!PyAubio_ArrayToCFvec(self->routput, &(self->c_routput)) ) {
+    return NULL;
+  }
   // compute the function
-  aubio_pvoc_rdo (self->o, vec, output);
-  return (PyObject *)PyAubio_CFvecToArray(output);
+  aubio_pvoc_rdo (self->o, &(self->cvecin), &(self->c_routput));
+  return self->routput;
 }
 
 static PyMethodDef Py_pvoc_methods[] = {
@@ -115,4 +162,52 @@
   {NULL}
 };
 
-AUBIO_TYPEOBJECT(pvoc, "aubio.pvoc")
+PyTypeObject Py_pvocType = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.pvoc",
+  sizeof (Py_pvoc),
+  0,
+  (destructor) Py_pvoc_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_pvoc_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_pvoc_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_pvoc_methods,
+  Py_pvoc_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_pvoc_init,
+  0,
+  Py_pvoc_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+};
--- a/python/ext/py-sink.c
+++ b/python/ext/py-sink.c
@@ -1,4 +1,4 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 typedef struct
 {
@@ -7,6 +7,8 @@
   char_t* uri;
   uint_t samplerate;
   uint_t channels;
+  fvec_t write_data;
+  fmat_t mwrite_data;
 } Py_sink;
 
 static char Py_sink_doc[] = ""
@@ -115,7 +117,7 @@
     aubio_sink_preset_samplerate ( self->o, self->samplerate );
   }
   if (self->o == NULL) {
-    PyErr_SetString (PyExc_StandardError, "error creating sink with this uri");
+    PyErr_SetString (PyExc_RuntimeError, "error creating sink with this uri");
     return -1;
   }
   self->samplerate = aubio_sink_get_samplerate ( self->o );
@@ -124,7 +126,13 @@
   return 0;
 }
 
-AUBIO_DEL(sink)
+static void
+Py_sink_del (Py_sink *self, PyObject *unused)
+{
+  del_aubio_sink(self->o);
+  free(self->mwrite_data.data);
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
 
 /* function Py_sink_do */
 static PyObject *
@@ -134,7 +142,6 @@
   PyObject * write_data_obj;
 
   /* input vectors prototypes */
-  fvec_t* write_data;
   uint_t write;
 
 
@@ -142,20 +149,14 @@
     return NULL;
   }
 
-
   /* input vectors parsing */
-  write_data = PyAubio_ArrayToCFvec (write_data_obj);
-
-  if (write_data == NULL) {
+  if (!PyAubio_ArrayToCFvec(write_data_obj, &(self->write_data))) {
     return NULL;
   }
 
 
-
-
-
   /* compute _do function */
-  aubio_sink_do (self->o, write_data, write);
+  aubio_sink_do (self->o, &(self->write_data), write);
 
   Py_RETURN_NONE;
 }
@@ -168,7 +169,6 @@
   PyObject * write_data_obj;
 
   /* input vectors prototypes */
-  fmat_t * write_data;
   uint_t write;
 
 
@@ -178,22 +178,16 @@
 
 
   /* input vectors parsing */
-  write_data = PyAubio_ArrayToCFmat (write_data_obj);
-
-  if (write_data == NULL) {
+  if (!PyAubio_ArrayToCFmat(write_data_obj, &(self->mwrite_data))) {
     return NULL;
   }
 
-
-
-
-
   /* compute _do function */
-  aubio_sink_do_multi (self->o, write_data, write);
+  aubio_sink_do_multi (self->o, &(self->mwrite_data), write);
   Py_RETURN_NONE;
 }
 
-AUBIO_MEMBERS_START(sink)
+static PyMemberDef Py_sink_members[] = {
   {"uri", T_STRING, offsetof (Py_sink, uri), READONLY,
     "path at which the sink was created"},
   {"samplerate", T_INT, offsetof (Py_sink, samplerate), READONLY,
@@ -200,7 +194,8 @@
     "samplerate at which the sink was created"},
   {"channels", T_INT, offsetof (Py_sink, channels), READONLY,
     "number of channels with which the sink was created"},
-AUBIO_MEMBERS_STOP(sink)
+  { NULL } // sentinel
+};
 
 static PyObject *
 Pyaubio_sink_close (Py_sink *self, PyObject *unused)
@@ -216,4 +211,52 @@
   {NULL} /* sentinel */
 };
 
-AUBIO_TYPEOBJECT(sink, "aubio.sink")
+PyTypeObject Py_sinkType = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.sink",
+  sizeof (Py_sink),
+  0,
+  (destructor) Py_sink_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_sink_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_sink_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_sink_methods,
+  Py_sink_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_sink_init,
+  0,
+  Py_sink_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+};
--- a/python/ext/py-source.c
+++ b/python/ext/py-source.c
@@ -1,4 +1,4 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 typedef struct
 {
@@ -8,6 +8,11 @@
   uint_t samplerate;
   uint_t channels;
   uint_t hop_size;
+  uint_t duration;
+  PyObject *read_to;
+  fvec_t c_read_to;
+  PyObject *mread_to;
+  fmat_t c_mread_to;
 } Py_source;
 
 static char Py_source_doc[] = ""
@@ -135,9 +140,8 @@
 {
   self->o = new_aubio_source ( self->uri, self->samplerate, self->hop_size );
   if (self->o == NULL) {
-    char_t errstr[30 + strlen(self->uri)];
-    sprintf(errstr, "error creating source with %s", self->uri);
-    PyErr_SetString (PyExc_StandardError, errstr);
+    PyErr_Format (PyExc_RuntimeError, "error creating source with \"%s\"",
+        self->uri);
     return -1;
   }
   self->samplerate = aubio_source_get_samplerate ( self->o );
@@ -144,39 +148,45 @@
   if (self->channels == 0) {
     self->channels = aubio_source_get_channels ( self->o );
   }
+  self->duration = aubio_source_get_duration ( self->o );
 
+  self->read_to = new_py_fvec(self->hop_size);
+  self->mread_to = new_py_fmat(self->channels, self->hop_size);
+
   return 0;
 }
 
-AUBIO_DEL(source)
+static void
+Py_source_del (Py_source *self, PyObject *unused)
+{
+  if (self->o) {
+    del_aubio_source(self->o);
+    free(self->c_mread_to.data);
+  }
+  Py_XDECREF(self->read_to);
+  Py_XDECREF(self->mread_to);
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
 
+
 /* function Py_source_do */
 static PyObject *
 Py_source_do(Py_source * self, PyObject * args)
 {
-
-
-  /* output vectors prototypes */
-  fvec_t* read_to;
+  PyObject *outputs;
   uint_t read;
-
-
-
-
-
-
-  /* creating output read_to as a new_fvec of length self->hop_size */
-  read_to = new_fvec (self->hop_size);
   read = 0;
 
-
+  Py_INCREF(self->read_to);
+  if (!PyAubio_ArrayToCFvec(self->read_to, &(self->c_read_to))) {
+    return NULL;
+  }
   /* compute _do function */
-  aubio_source_do (self->o, read_to, &read);
+  aubio_source_do (self->o, &(self->c_read_to), &read);
 
-  PyObject *outputs = PyList_New(0);
-  PyList_Append( outputs, (PyObject *)PyAubio_CFvecToArray (read_to));
-  //del_fvec (read_to);
-  PyList_Append( outputs, (PyObject *)PyInt_FromLong (read));
+  outputs = PyTuple_New(2);
+  PyTuple_SetItem( outputs, 0, self->read_to );
+  PyTuple_SetItem( outputs, 1, (PyObject *)PyLong_FromLong(read));
   return outputs;
 }
 
@@ -184,33 +194,24 @@
 static PyObject *
 Py_source_do_multi(Py_source * self, PyObject * args)
 {
-
-
-  /* output vectors prototypes */
-  fmat_t* read_to;
+  PyObject *outputs;
   uint_t read;
-
-
-
-
-
-
-  /* creating output read_to as a new_fvec of length self->hop_size */
-  read_to = new_fmat (self->channels, self->hop_size);
   read = 0;
 
-
+  Py_INCREF(self->mread_to);
+  if (!PyAubio_ArrayToCFmat(self->mread_to,  &(self->c_mread_to))) {
+    return NULL;
+  }
   /* compute _do function */
-  aubio_source_do_multi (self->o, read_to, &read);
+  aubio_source_do_multi (self->o, &(self->c_mread_to), &read);
 
-  PyObject *outputs = PyList_New(0);
-  PyList_Append( outputs, (PyObject *)PyAubio_CFmatToArray (read_to));
-  //del_fvec (read_to);
-  PyList_Append( outputs, (PyObject *)PyInt_FromLong (read));
+  outputs = PyTuple_New(2);
+  PyTuple_SetItem( outputs, 0, self->mread_to);
+  PyTuple_SetItem( outputs, 1, (PyObject *)PyLong_FromLong(read));
   return outputs;
 }
 
-AUBIO_MEMBERS_START(source)
+static PyMemberDef Py_source_members[] = {
   {"uri", T_STRING, offsetof (Py_source, uri), READONLY,
     "path at which the source was created"},
   {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY,
@@ -219,14 +220,16 @@
     "number of channels found in the source"},
   {"hop_size", T_INT, offsetof (Py_source, hop_size), READONLY,
     "number of consecutive frames that will be read at each do or do_multi call"},
-AUBIO_MEMBERS_STOP(source)
+  {"duration", T_INT, offsetof (Py_source, duration), READONLY,
+    "total number of frames in the source (estimated)"},
+  { NULL } // sentinel
+};
 
-
 static PyObject *
 Pyaubio_source_get_samplerate (Py_source *self, PyObject *unused)
 {
   uint_t tmp = aubio_source_get_samplerate (self->o);
-  return (PyObject *)PyInt_FromLong (tmp);
+  return (PyObject *)PyLong_FromLong (tmp);
 }
 
 static PyObject *
@@ -233,7 +236,7 @@
 Pyaubio_source_get_channels (Py_source *self, PyObject *unused)
 {
   uint_t tmp = aubio_source_get_channels (self->o);
-  return (PyObject *)PyInt_FromLong (tmp);
+  return (PyObject *)PyLong_FromLong (tmp);
 }
 
 static PyObject *
@@ -248,11 +251,18 @@
 {
   uint_t err = 0;
 
-  uint_t position;
+  int position;
   if (!PyArg_ParseTuple (args, "I", &position)) {
     return NULL;
   }
 
+  if (position < 0) {
+    PyErr_Format(PyExc_ValueError,
+        "error when seeking in source: can not seek to negative value %d",
+        position);
+    return NULL;
+  }
+
   err = aubio_source_seek(self->o, position);
   if (err != 0) {
     PyErr_SetString (PyExc_ValueError,
@@ -278,4 +288,52 @@
   {NULL} /* sentinel */
 };
 
-AUBIO_TYPEOBJECT(source, "aubio.source")
+PyTypeObject Py_sourceType = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.source",
+  sizeof (Py_source),
+  0,
+  (destructor) Py_source_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_source_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_source_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_source_methods,
+  Py_source_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_source_init,
+  0,
+  Py_source_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+};
--- a/python/ext/ufuncs.c
+++ b/python/ext/ufuncs.c
@@ -84,6 +84,7 @@
 void add_ufuncs ( PyObject *m )
 {
   int err = 0;
+  PyObject *dict, *f, *g, *h;
 
   err = _import_umath ();
   if (err != 0) {
@@ -91,7 +92,6 @@
         "Unable to import Numpy umath from aubio module (error %d)\n", err);
   }
 
-  PyObject *f, *dict;
   dict = PyModule_GetDict(m);
   f = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_unwrap2pi_data, Py_aubio_unary_types,
           Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
@@ -99,7 +99,6 @@
   PyDict_SetItemString(dict, "unwrap2pi", f);
   Py_DECREF(f);
 
-  PyObject *g;
   g = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_freqtomidi_data, Py_aubio_unary_types,
           Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
           PyUFunc_None, "freqtomidi", Py_freqtomidi_doc, 0);
@@ -106,7 +105,6 @@
   PyDict_SetItemString(dict, "freqtomidi", g);
   Py_DECREF(g);
 
-  PyObject *h;
   h = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_miditofreq_data, Py_aubio_unary_types,
           Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
           PyUFunc_None, "miditofreq", Py_miditofreq_doc, 0);
--- a/python/lib/aubio/__init__.py
+++ b/python/lib/aubio/__init__.py
@@ -1,14 +1,18 @@
 #! /usr/bin/env python
 
 import numpy
-from _aubio import *
-from midiconv import *
-from slicing import *
+from ._aubio import *
+from ._aubio import float_type
+from .midiconv import *
+from .slicing import *
 
 class fvec(numpy.ndarray):
-    " a simple numpy array holding a vector of float32 "
-    def __new__(self, length = 1024, **kwargs):
-        self.length = length
-        if type(length) == type([]):
-            return numpy.array(length, dtype='float32', **kwargs)
-        return numpy.zeros(length, dtype='float32', **kwargs)
+    """a numpy vector holding audio samples"""
+
+    def __new__(cls, input_arg=1024, **kwargs):
+        if isinstance(input_arg, int):
+            if input_arg == 0:
+                raise ValueError("vector length of 1 or more expected")
+            return numpy.zeros(input_arg, dtype=float_type, **kwargs)
+        else:
+            return numpy.array(input_arg, dtype=float_type, **kwargs)
--- a/python/lib/aubio/midiconv.py
+++ b/python/lib/aubio/midiconv.py
@@ -1,14 +1,28 @@
 # -*- coding: utf-8 -*-
+""" utilities to convert midi note number to and from note names """
 
+__all__ = ['note2midi', 'midi2note', 'freq2note']
+
+import sys
+py3 = sys.version_info[0] == 3
+if py3:
+    str_instances = str
+    int_instances = int
+else:
+    str_instances = (str, unicode)
+    int_instances = (int, long)
+
 def note2midi(note):
     " convert note name to midi note number, e.g. [C-1, G9] -> [0, 127] "
     _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
-    _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2, 'b': -1, u'♭': -1, u'\ufffd': -2}
+    _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2,
+                        'b': -1, u'♭': -1, u'\ufffd': -2}
     _valid_octaves = range(-1, 10)
-    if type(note) not in (str, unicode):
-        raise TypeError, "a string is required, got %s" % note
-    if not (1 < len(note) < 5):
-        raise ValueError, "string of 2 to 4 characters expected, got %d (%s)" % (len(note), note)
+    if not isinstance(note, str_instances):
+        raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
+    if len(note) not in range(2, 5):
+        raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
+                         % (len(note), note))
     notename, modifier, octave = [None]*3
 
     if len(note) == 4:
@@ -26,27 +40,27 @@
     octave = int(octave)
 
     if notename not in _valid_notenames:
-        raise ValueError, "%s is not a valid note name" % notename
+        raise ValueError("%s is not a valid note name" % notename)
     if modifier not in _valid_modifiers:
-        raise ValueError, "%s is not a valid modifier" % modifier
+        raise ValueError("%s is not a valid modifier" % modifier)
     if octave not in _valid_octaves:
-        raise ValueError, "%s is not a valid octave" % octave
+        raise ValueError("%s is not a valid octave" % octave)
 
     midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
     if midi > 127:
-        raise ValueError, "%s is outside of the range C-2 to G8" % note
+        raise ValueError("%s is outside of the range C-2 to G8" % note)
     return midi
 
 def midi2note(midi):
     " convert midi note number to note name, e.g. [0, 127] -> [C-1, G9] "
-    if type(midi) != int:
-        raise TypeError, "an integer is required, got %s" % midi
-    if not (-1 < midi < 128):
-        raise ValueError, "an integer between 0 and 127 is excepted, got %d" % midi
-    midi = int(midi)
+    if not isinstance(midi, int_instances):
+        raise TypeError("an integer is required, got %s" % midi)
+    if midi not in range(0, 128):
+        raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
     _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
-    return _valid_notenames[midi % 12] + str( midi / 12 - 1)
+    return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
 
 def freq2note(freq):
+    " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] "
     from aubio import freqtomidi
     return midi2note(int(freqtomidi(freq)))
--- a/python/lib/aubio/slicing.py
+++ b/python/lib/aubio/slicing.py
@@ -1,43 +1,45 @@
-from aubio import source, sink
+"""utility routines to slice sound files at given timestamps"""
+
 import os
+from aubio import source, sink
 
-max_timestamp = 1e120
+_max_timestamp = 1e120
 
-def slice_source_at_stamps(source_file, timestamps, timestamps_end = None,
-        output_dir = None,
-        samplerate = 0,
-        hopsize = 256):
+def slice_source_at_stamps(source_file, timestamps, timestamps_end=None,
+                           output_dir=None, samplerate=0, hopsize=256):
+    """ slice a sound file at given timestamps """
 
-    if timestamps == None or len(timestamps) == 0:
-        raise ValueError ("no timestamps given")
+    if timestamps is None or len(timestamps) == 0:
+        raise ValueError("no timestamps given")
 
     if timestamps[0] != 0:
         timestamps = [0] + timestamps
-        if timestamps_end != None:
+        if timestamps_end is not None:
             timestamps_end = [timestamps[1] - 1] + timestamps_end
 
-    if timestamps_end != None:
+    if timestamps_end is not None:
         if len(timestamps_end) != len(timestamps):
-            raise ValueError ("len(timestamps_end) != len(timestamps)")
+            raise ValueError("len(timestamps_end) != len(timestamps)")
     else:
-        timestamps_end = [t - 1 for t in timestamps[1:] ] + [ max_timestamp ]
+        timestamps_end = [t - 1 for t in timestamps[1:]] + [_max_timestamp]
 
-    regions = zip(timestamps, timestamps_end)
+    regions = list(zip(timestamps, timestamps_end))
     #print regions
 
-    source_base_name, source_ext = os.path.splitext(os.path.basename(source_file))
-    if output_dir != None:
+    source_base_name, _ = os.path.splitext(os.path.basename(source_file))
+    if output_dir is not None:
         if not os.path.isdir(output_dir):
             os.makedirs(output_dir)
         source_base_name = os.path.join(output_dir, source_base_name)
 
     def new_sink_name(source_base_name, timestamp, samplerate):
+        """ create a sink based on a timestamp in samples, converted in seconds """
         timestamp_seconds = timestamp / float(samplerate)
         return source_base_name + "_%011.6f" % timestamp_seconds + '.wav'
 
-    # reopen source file
-    s = source(source_file, samplerate, hopsize)
-    samplerate = s.get_samplerate()
+    # open source file
+    _source = source(source_file, samplerate, hopsize)
+    samplerate = _source.samplerate
 
     total_frames = 0
     slices = []
@@ -44,7 +46,7 @@
 
     while True:
         # get hopsize new samples from source
-        vec, read = s.do_multi()
+        vec, read = _source.do_multi()
         # if the total number of frames read will exceed the next region start
         if len(regions) and total_frames + read >= regions[0][0]:
             #print "getting", regions[0], "at", total_frames
@@ -53,9 +55,9 @@
             # create a name for the sink
             new_sink_path = new_sink_name(source_base_name, start_stamp, samplerate)
             # create its sink
-            g = sink(new_sink_path, samplerate, s.channels)
+            _sink = sink(new_sink_path, samplerate, _source.channels)
             # create a dictionary containing all this
-            new_slice = {'start_stamp': start_stamp, 'end_stamp': end_stamp, 'sink': g}
+            new_slice = {'start_stamp': start_stamp, 'end_stamp': end_stamp, 'sink': _sink}
             # append the dictionary to the current list of slices
             slices.append(new_slice)
 
@@ -62,7 +64,7 @@
         for current_slice in slices:
             start_stamp = current_slice['start_stamp']
             end_stamp = current_slice['end_stamp']
-            g = current_slice['sink']
+            _sink = current_slice['sink']
             # sample index to start writing from new source vector
             start = max(start_stamp - total_frames, 0)
             # number of samples yet to written be until end of region
@@ -72,12 +74,13 @@
             if remaining < read:
                 if remaining > start:
                     # write remaining samples from current region
-                    g.do_multi(vec[:,start:remaining], remaining - start)
+                    _sink.do_multi(vec[:, start:remaining], remaining - start)
                     #print "closing region", "remaining", remaining
                     # close this file
-                    g.close()
+                    _sink.close()
             elif read > start:
                 # write all the samples
-                g.do_multi(vec[:,start:read], read - start)
+                _sink.do_multi(vec[:, start:read], read - start)
         total_frames += read
-        if read < hopsize: break
+        if read < hopsize:
+            break
--- /dev/null
+++ b/python/lib/gen_code.py
@@ -1,0 +1,533 @@
+aubiodefvalue = {
+    # we have some clean up to do
+    'buf_size': 'Py_default_vector_length',
+    'win_s': 'Py_default_vector_length',
+    # and here too
+    'hop_size': 'Py_default_vector_length / 2',
+    'hop_s': '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"',
+    }
+
+member_types = {
+        'name': 'type',
+        'char_t*': 'T_STRING',
+        'uint_t': 'T_INT',
+        'smpl_t': 'AUBIO_NPY_SMPL',
+        }
+
+pyfromtype_fn = {
+        'smpl_t': 'PyFloat_FromDouble',
+        'uint_t': 'PyLong_FromLong', # was: 'PyInt_FromLong',
+        'fvec_t*': 'PyAubio_CFvecToArray',
+        'fmat_t*': 'PyAubio_CFmatToArray',
+        }
+
+pytoaubio_fn = {
+        'fvec_t*': 'PyAubio_ArrayToCFvec',
+        'cvec_t*': 'PyAubio_PyCvecToCCvec',
+        #'fmat_t*': 'PyAubio_ArrayToCFmat',
+        }
+
+newfromtype_fn = {
+        'fvec_t*': 'new_py_fvec',
+        'fmat_t*': 'new_py_fmat',
+        'cvec_t*': 'new_py_cvec',
+        }
+
+delfromtype_fn = {
+        'fvec_t*': 'Py_DECREF',
+        'fmat_t*': 'Py_DECREF',
+        'cvec_t*': 'Py_DECREF',
+        }
+
+param_init = {
+        'char_t*': 'NULL',
+        'uint_t': '0',
+        'sint_t': 0,
+        'smpl_t': 0.,
+        'lsmp_t': 0.,
+        }
+
+pyargparse_chars = {
+        'smpl_t': 'f', # if not usedouble else 'd',
+        'uint_t': 'I',
+        'sint_t': 'I',
+        'char_t*': 's',
+        'fmat_t*': 'O',
+        'fvec_t*': 'O',
+        'cvec_t*': 'O',
+        }
+
+objoutsize = {
+        'onset': '1',
+        'pitch': '1',
+        'wavetable': 'self->hop_size',
+        'sampler': 'self->hop_size',
+        'mfcc': 'self->n_coeffs',
+        'specdesc': '1',
+        'tempo': '1',
+        'filterbank': 'self->n_filters',
+        'tss': 'self->hop_size',
+        }
+
+def get_name(proto):
+    name = proto.replace(' *', '* ').split()[1].split('(')[0]
+    name = name.replace('*','')
+    if name == '': raise ValueError(proto + "gave empty name")
+    return name
+
+def get_return_type(proto):
+    import re
+    paramregex = re.compile('(\w+ ?\*?).*')
+    outputs = paramregex.findall(proto)
+    assert len(outputs) == 1
+    return outputs[0].replace(' ', '')
+
+def split_type(arg):
+    """ arg = 'foo *name' 
+        return ['foo*', 'name'] """
+    l = arg.split()
+    type_arg = {} #'type': l[0], 'name': l[1]}
+    type_arg['type'] = " ".join(l[:-1])
+    type_arg['name'] = l[-1]
+    # fix up type / name
+    if type_arg['name'].startswith('*'):
+        # ['foo', '*name'] -> ['foo*', 'name']
+        type_arg['type'] += '*'
+        type_arg['name'] = type_arg['name'][1:]
+    if type_arg['type'].endswith(' *'):
+        # ['foo *', 'name'] -> ['foo*', 'name']
+        type_arg['type'] = type_arg['type'].replace(' *','*')
+    if type_arg['type'].startswith('const '):
+        # ['foo *', 'name'] -> ['foo*', 'name']
+        type_arg['type'] = type_arg['type'].replace('const ','')
+    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('.*\((.*)\);')
+    a = paramregex.findall(proto)[0].split(', ')
+    #a = [i.replace('const ', '') for i in a]
+    return a
+
+def get_input_params(proto):
+    a = get_params(proto)
+    return [i.replace('const ', '') for i in a if (i.startswith('const ') or i.startswith('uint_t ') or i.startswith('smpl_t '))]
+
+def get_output_params(proto):
+    a = get_params(proto)
+    return [i for i in a if not i.startswith('const ')][1:]
+
+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']]
+    """
+    a = list(map(split_type, get_params(proto)))
+    #print proto, a
+    #import sys; sys.exit(1)
+    return a
+
+class MappedObject(object):
+
+    def __init__(self, prototypes, usedouble = False):
+        if usedouble:
+            pyargparse_chars['smpl_t'] = 'd'
+        self.prototypes = prototypes
+
+        self.shortname = prototypes['shortname']
+        self.longname = prototypes['longname']
+        self.new_proto = prototypes['new'][0]
+        self.del_proto = prototypes['del'][0]
+        self.do_proto = prototypes['do'][0]
+        self.input_params = get_params_types_names(self.new_proto)
+        self.input_params_list = "; ".join(get_input_params(self.new_proto))
+        self.outputs = get_params_types_names(self.do_proto)[2:]
+        self.do_inputs = [get_params_types_names(self.do_proto)[1]]
+        self.do_outputs = get_params_types_names(self.do_proto)[2:]
+        struct_output_str = ["PyObject *{0[name]}; {1} c_{0[name]}".format(i, i['type'][:-1]) for i in self.do_outputs]
+        self.struct_outputs = ";\n    ".join(struct_output_str)
+
+        #print ("input_params: ", map(split_type, get_input_params(self.do_proto)))
+        #print ("output_params", map(split_type, get_output_params(self.do_proto)))
+
+    def gen_code(self):
+        out = ""
+        out += self.gen_struct()
+        out += self.gen_doc()
+        out += self.gen_new()
+        out += self.gen_init()
+        out += self.gen_del()
+        out += self.gen_do()
+        out += self.gen_memberdef()
+        out += self.gen_set()
+        out += self.gen_get()
+        out += self.gen_methodef()
+        out += self.gen_typeobject()
+        return out
+
+    def gen_struct(self):
+        out = """
+// {shortname} structure
+typedef struct{{
+    PyObject_HEAD
+    // pointer to aubio object
+    {longname} *o;
+    // input parameters
+    {input_params_list};
+    // do input vectors
+    {do_inputs_list};
+    // output results
+    {struct_outputs};
+}} Py_{shortname};
+"""
+        # fmat_t* / fvec_t* / cvec_t* inputs -> full fvec_t /.. struct in Py_{shortname}
+        do_inputs_list = "; ".join(get_input_params(self.do_proto)).replace('fvec_t *','fvec_t').replace('fmat_t *', 'fmat_t').replace('cvec_t *', 'cvec_t')
+        return out.format(do_inputs_list = do_inputs_list, **self.__dict__)
+
+    def gen_doc(self):
+        out = """
+// TODO: add documentation
+static char Py_{shortname}_doc[] = \"undefined\";
+"""
+        return out.format(**self.__dict__)
+
+    def gen_new(self):
+        out = """
+// new {shortname}
+static PyObject *
+Py_{shortname}_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
+{{
+    Py_{shortname} *self;
+""".format(**self.__dict__)
+        params = self.input_params
+        for p in params:
+            out += """
+    {type} {name} = {defval};""".format(defval = param_init[p['type']], **p)
+        plist = ", ".join(["\"%s\"" % p['name'] for p in params])
+        out += """
+    static char *kwlist[] = {{ {plist}, NULL }};""".format(plist = plist)
+        argchars = "".join([pyargparse_chars[p['type']] for p in params])
+        arglist = ", ".join(["&%s" % p['name'] for p in params])
+        out += """
+    if (!PyArg_ParseTupleAndKeywords (args, kwds, "|{argchars}", kwlist,
+              {arglist})) {{
+        return NULL;
+    }}
+""".format(argchars = argchars, arglist = arglist)
+        out += """
+    self = (Py_{shortname} *) pytype->tp_alloc (pytype, 0);
+    if (self == NULL) {{
+        return NULL;
+    }}
+""".format(**self.__dict__)
+        params = self.input_params
+        for p in params:
+            out += self.check_valid(p)
+        out += """
+    return (PyObject *)self;
+}
+"""
+        return out
+
+    def check_valid(self, p):
+        if p['type'] == 'uint_t':
+            return self.check_valid_uint(p)
+        if p['type'] == 'char_t*':
+            return self.check_valid_char(p)
+        else:
+            print ("ERROR, no idea how to check %s for validity" % p['type'])
+
+    def check_valid_uint(self, p):
+        name = p['name']
+        return """
+    self->{name} = {defval};
+    if ((sint_t){name} > 0) {{
+        self->{name} = {name};
+    }} else if ((sint_t){name} < 0) {{
+        PyErr_SetString (PyExc_ValueError, "can not use negative value for {name}");
+        return NULL;
+    }}
+""".format(defval = aubiodefvalue[name], name = name)
+
+    def check_valid_char(self, p):
+        name = p['name']
+        return """
+    self->{name} = {defval};
+    if ({name} != NULL) {{
+        self->{name} = {name};
+    }}
+""".format(defval = aubiodefvalue[name], name = name)
+
+    def gen_init(self):
+        out = """
+// init {shortname}
+static int
+Py_{shortname}_init (Py_{shortname} * self, PyObject * args, PyObject * kwds)
+{{
+""".format(**self.__dict__)
+        new_name = get_name(self.new_proto)
+        new_params = ", ".join(["self->%s" % s['name'] for s in self.input_params])
+        out += """
+  self->o = {new_name}({new_params});
+""".format(new_name = new_name, new_params = new_params)
+        paramchars = "%s"
+        paramvals = "self->method"
+        out += """
+  // return -1 and set error string on failure
+  if (self->o == NULL) {{
+    PyErr_Format (PyExc_Exception, "failed creating {shortname}");
+    return -1;
+  }}
+""".format(paramchars = paramchars, paramvals = paramvals, **self.__dict__)
+        output_create = ""
+        for o in self.outputs:
+            output_create += """
+  self->{name} = {create_fn}({output_size});""".format(name = o['name'], create_fn = newfromtype_fn[o['type']], output_size = objoutsize[self.shortname])
+        out += """
+  // TODO get internal params after actual object creation?
+"""
+        out += """
+  // create outputs{output_create}
+""".format(output_create = output_create)
+        out += """
+  return 0;
+}
+"""
+        return out
+
+    def gen_memberdef(self):
+        out = """
+static PyMemberDef Py_{shortname}_members[] = {{
+""".format(**self.__dict__)
+        for p in get_params_types_names(self.new_proto):
+            tmp = "  {{\"{name}\", {ttype}, offsetof (Py_{shortname}, {name}), READONLY, \"TODO documentation\"}},\n"
+            pytype = member_types[p['type']]
+            out += tmp.format(name = p['name'], ttype = pytype, shortname = self.shortname)
+        out += """  {NULL}, // sentinel
+};
+"""
+        return out
+
+    def gen_del(self):
+        out = """
+// del {shortname}
+static void
+Py_{shortname}_del  (Py_{shortname} * self, PyObject * unused)
+{{""".format(**self.__dict__)
+        for input_param in self.do_inputs:
+            if input_param['type'] == 'fmat_t *':
+                out += """
+    free(self->{0[name]}.data);""".format(input_param)
+        for o in self.outputs:
+            name = o['name']
+            del_out = delfromtype_fn[o['type']]
+            out += """
+    {del_out}(self->{name});""".format(del_out = del_out, name = name)
+        del_fn = get_name(self.del_proto)
+        out += """
+    if (self->o) {{
+        {del_fn}(self->o);
+    }}
+    Py_TYPE(self)->tp_free((PyObject *) self);
+}}
+""".format(del_fn = del_fn)
+        return out
+
+    def gen_do(self):
+        out = """
+// do {shortname}
+static PyObject*
+Py_{shortname}_do  (Py_{shortname} * self, PyObject * args)
+{{""".format(**self.__dict__)
+        input_params = self.do_inputs
+        output_params = self.do_outputs
+        #print input_params
+        #print output_params
+        for input_param in input_params:
+            out += """
+    PyObject *py_{0};""".format(input_param['name'])
+        refs = ", ".join(["&py_%s" % p['name'] for p in input_params])
+        pyparamtypes = "".join([pyargparse_chars[p['type']] for p in input_params])
+        out += """
+    if (!PyArg_ParseTuple (args, "{pyparamtypes}", {refs})) {{
+        return NULL;
+    }}""".format(refs = refs, pyparamtypes = pyparamtypes, **self.__dict__)
+        for input_param in input_params:
+            out += """
+
+    if (!{pytoaubio}(py_{0[name]}, &(self->{0[name]}))) {{
+        return NULL;
+    }}""".format(input_param, pytoaubio = pytoaubio_fn[input_param['type']])
+        out += """
+
+    // TODO: check input sizes"""
+        for output_param in output_params:
+            out += """
+
+    Py_INCREF(self->{0[name]});
+    if (!{pytoaubio}(self->{0[name]}, &(self->c_{0[name]}))) {{
+        return NULL;
+    }}""".format(output_param, pytoaubio = pytoaubio_fn[output_param['type']])
+        do_fn = get_name(self.do_proto)
+        inputs = ", ".join(['&(self->'+p['name']+')' for p in input_params])
+        c_outputs = ", ".join(["&(self->c_%s)" % p['name'] for p in self.do_outputs])
+        outputs = ", ".join(["self->%s" % p['name'] for p in self.do_outputs])
+        out += """
+
+    {do_fn}(self->o, {inputs}, {c_outputs});
+
+    return {outputs};
+}}
+""".format(
+        do_fn = do_fn,
+        inputs = inputs, outputs = outputs, c_outputs = c_outputs,
+        )
+        return out
+
+    def gen_set(self):
+        out = """
+// {shortname} setters
+""".format(**self.__dict__)
+        for set_param in self.prototypes['set']:
+            params = get_params_types_names(set_param)[1]
+            paramtype = params['type']
+            method_name = get_name(set_param)
+            param = method_name.split('aubio_'+self.shortname+'_set_')[-1]
+            pyparamtype = pyargparse_chars[paramtype]
+            out += """
+static PyObject *
+Pyaubio_{shortname}_set_{param} (Py_{shortname} *self, PyObject *args)
+{{
+  uint_t err = 0;
+  {paramtype} {param};
+
+  if (!PyArg_ParseTuple (args, "{pyparamtype}", &{param})) {{
+    return NULL;
+  }}
+  err = aubio_{shortname}_set_{param} (self->o, {param});
+
+  if (err > 0) {{
+    PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
+    return NULL;
+  }}
+  Py_RETURN_NONE;
+}}
+""".format(param = param, paramtype = paramtype, pyparamtype = pyparamtype, **self.__dict__)
+        return out
+
+    def gen_get(self):
+        out = """
+// {shortname} getters
+""".format(**self.__dict__)
+        for method in self.prototypes['get']:
+            params = get_params_types_names(method)
+            method_name = get_name(method)
+            assert len(params) == 1, \
+                "get method has more than one parameter %s" % params
+            param = method_name.split('aubio_'+self.shortname+'_get_')[-1]
+            paramtype = get_return_type(method)
+            ptypeconv = pyfromtype_fn[paramtype]
+            out += """
+static PyObject *
+Pyaubio_{shortname}_get_{param} (Py_{shortname} *self, PyObject *unused)
+{{
+  {ptype} {param} = aubio_{shortname}_get_{param} (self->o);
+  return (PyObject *){ptypeconv} ({param});
+}}
+""".format(param = param, ptype = paramtype, ptypeconv = ptypeconv,
+        **self.__dict__)
+        return out
+
+    def gen_methodef(self):
+        out = """
+static PyMethodDef Py_{shortname}_methods[] = {{""".format(**self.__dict__)
+        for m in self.prototypes['set']:
+            name = get_name(m)
+            shortname = name.replace('aubio_%s_' % self.shortname, '')
+            out += """
+  {{"{shortname}", (PyCFunction) Py{name},
+    METH_VARARGS, ""}},""".format(name = name, shortname = shortname)
+        for m in self.prototypes['get']:
+            name = get_name(m)
+            shortname = name.replace('aubio_%s_' % self.shortname, '')
+            out += """
+  {{"{shortname}", (PyCFunction) Py{name},
+    METH_NOARGS, ""}},""".format(name = name, shortname = shortname)
+        out += """
+  {NULL} /* sentinel */
+};
+"""
+        return out
+
+    def gen_typeobject(self):
+        return """
+PyTypeObject Py_{shortname}Type = {{
+  //PyObject_HEAD_INIT (NULL)
+  //0,
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "aubio.{shortname}",
+  sizeof (Py_{shortname}),
+  0,
+  (destructor) Py_{shortname}_del,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (ternaryfunc)Py_{shortname}_do,
+  0,
+  0,
+  0,
+  0,
+  Py_TPFLAGS_DEFAULT,
+  Py_{shortname}_doc,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  Py_{shortname}_methods,
+  Py_{shortname}_members,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  (initproc) Py_{shortname}_init,
+  0,
+  Py_{shortname}_new,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+}};
+""".format(**self.__dict__)
--- /dev/null
+++ b/python/lib/gen_external.py
@@ -1,0 +1,249 @@
+import distutils.ccompiler
+import sys, os, subprocess, glob
+
+header = os.path.join('src', 'aubio.h')
+output_path = os.path.join('python', 'gen')
+
+source_header = """// this file is generated! do not modify
+#include "aubio-types.h"
+"""
+
+skip_objects = [
+  # already in ext/
+  'fft',
+  'pvoc',
+  'filter',
+  'filterbank',
+  #'resampler',
+  # AUBIO_UNSTABLE
+  'hist',
+  'parameter',
+  'scale',
+  'beattracking',
+  'resampler',
+  'peakpicker',
+  'pitchfcomb',
+  'pitchmcomb',
+  'pitchschmitt',
+  'pitchspecacf',
+  'pitchyin',
+  'pitchyinfft',
+  'sink',
+  'sink_apple_audio',
+  'sink_sndfile',
+  'sink_wavwrite',
+  #'mfcc',
+  'source',
+  'source_apple_audio',
+  'source_sndfile',
+  'source_avcodec',
+  'source_wavread',
+  #'sampler',
+  'audio_unit',
+
+  'tss',
+  ]
+
+def get_preprocessor():
+    # findout which compiler to use
+    from distutils.sysconfig import customize_compiler
+    compiler_name = distutils.ccompiler.get_default_compiler()
+    compiler = distutils.ccompiler.new_compiler(compiler=compiler_name)
+    try:
+        customize_compiler(compiler)
+    except AttributeError as e:
+        print("Warning: failed customizing compiler ({:s})".format(repr(e)))
+
+    if hasattr(compiler, 'initialize'):
+        try:
+            compiler.initialize()
+        except ValueError as e:
+            print("Warning: failed initializing compiler ({:s})".format(repr(e)))
+
+    cpp_cmd = None
+    if hasattr(compiler, 'preprocessor'): # for unixccompiler
+        cpp_cmd = compiler.preprocessor
+    elif hasattr(compiler, 'compiler'): # for ccompiler
+        cpp_cmd = compiler.compiler.split()
+        cpp_cmd += ['-E']
+    elif hasattr(compiler, 'cc'): # for msvccompiler
+        cpp_cmd = compiler.cc.split()
+        cpp_cmd += ['-E']
+
+    if not cpp_cmd:
+        print("Warning: could not guess preprocessor, using env's CC")
+        cpp_cmd = os.environ.get('CC', 'cc').split()
+        cpp_cmd += ['-E']
+
+    return cpp_cmd
+
+def get_cpp_objects(header=header):
+    cpp_cmd = get_preprocessor()
+
+    macros = [('AUBIO_UNSTABLE', 1)]
+
+    if not os.path.isfile(header):
+        raise Exception("could not find include file " + header)
+
+    includes = [os.path.dirname(header)]
+    cpp_cmd += distutils.ccompiler.gen_preprocess_options(macros, includes)
+    cpp_cmd += [header]
+
+    print("Running command: {:s}".format(" ".join(cpp_cmd)))
+    proc = subprocess.Popen(cpp_cmd,
+            stderr=subprocess.PIPE,
+            stdout=subprocess.PIPE)
+    assert proc, 'Proc was none'
+    cpp_output = proc.stdout.read()
+    err_output = proc.stderr.read()
+    if not cpp_output:
+        raise Exception("preprocessor output is empty:\n%s" % err_output)
+    elif err_output:
+        print ("Warning: preprocessor produced warnings:\n%s" % err_output)
+    if not isinstance(cpp_output, list):
+        cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')]
+
+    cpp_output = filter(lambda y: len(y) > 1, cpp_output)
+    cpp_output = list(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_external(header=header, output_path=output_path, usedouble=False, overwrite=True):
+    if not os.path.isdir(output_path): os.mkdir(output_path)
+    elif not overwrite: return glob.glob(os.path.join(output_path, '*.c'))
+    sources_list = []
+    cpp_output, cpp_objects = get_cpp_objects(header)
+    lib = {}
+
+    for o in cpp_objects:
+        if o[:6] != 'aubio_':
+            continue
+        shortname = o[6:-2]
+        if shortname in skip_objects:
+            continue
+        lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []}
+        lib[shortname]['longname'] = o
+        lib[shortname]['shortname'] = shortname
+        for fn in cpp_output:
+            if o[:-1] in fn:
+                #print "found", o[:-1], "in", fn
+                if 'typedef struct ' in fn:
+                    lib[shortname]['struct'].append(fn)
+                elif '_do' in fn:
+                    lib[shortname]['do'].append(fn)
+                elif 'new_' in fn:
+                    lib[shortname]['new'].append(fn)
+                elif 'del_' in fn:
+                    lib[shortname]['del'].append(fn)
+                elif '_get_' in fn:
+                    lib[shortname]['get'].append(fn)
+                elif '_set_' in fn:
+                    lib[shortname]['set'].append(fn)
+                else:
+                    #print "no idea what to do about", fn
+                    lib[shortname]['other'].append(fn)
+
+    """
+    for fn in cpp_output:
+        found = 0
+        for o in lib:
+            for family in lib[o]:
+                if fn in lib[o][family]:
+                    found = 1
+        if found == 0:
+            print "missing", fn
+
+    for o in lib:
+        for family in lib[o]:
+            if type(lib[o][family]) == str:
+                print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
+            elif len(lib[o][family]) == 1:
+                print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family][0] ) )
+            else:
+                print ( "{:15s} {:10s} {:d}".format(o, family, len(lib[o][family]) ) )
+    """
+
+    try:
+        from .gen_code import MappedObject
+    except (SystemError, ValueError):
+        from gen_code import MappedObject
+    for o in lib:
+        out = source_header
+        mapped = MappedObject(lib[o], usedouble = usedouble)
+        out += mapped.gen_code()
+        output_file = os.path.join(output_path, 'gen-%s.c' % o)
+        with open(output_file, 'w') as f:
+            f.write(out)
+            print ("wrote %s" % output_file )
+            sources_list.append(output_file)
+
+    out = source_header
+    out += "#include \"aubio-generated.h\""
+    check_types = "\n     ||  ".join(["PyType_Ready(&Py_%sType) < 0" % o for o in lib])
+    out += """
+
+int generated_types_ready (void)
+{{
+  return ({pycheck_types});
+}}
+""".format(pycheck_types = check_types)
+
+    add_types = "".join(["""
+  Py_INCREF (&Py_{name}Type);
+  PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name = o) for o in lib])
+    out += """
+
+void add_generated_objects ( PyObject *m )
+{{
+{add_types}
+}}
+""".format(add_types = add_types)
+
+    output_file = os.path.join(output_path, 'aubio-generated.c')
+    with open(output_file, 'w') as f:
+        f.write(out)
+        print ("wrote %s" % output_file )
+        sources_list.append(output_file)
+
+    objlist = "".join(["extern PyTypeObject Py_%sType;\n" % p for p in lib])
+    out = """// generated list of objects created with gen_external.py
+
+#include <Python.h>
+"""
+    if usedouble:
+        out += """
+#ifndef HAVE_AUBIO_DOUBLE
+#define HAVE_AUBIO_DOUBLE 1
+#endif
+"""
+    out += """
+{objlist}
+int generated_objects ( void );
+void add_generated_objects( PyObject *m );
+""".format(objlist = objlist)
+
+    output_file = os.path.join(output_path, 'aubio-generated.h')
+    with open(output_file, 'w') as f:
+        f.write(out)
+        print ("wrote %s" % output_file )
+        # no need to add header to list of sources
+
+    return sources_list
+
+if __name__ == '__main__':
+    if len(sys.argv) > 1: header = sys.argv[1]
+    if len(sys.argv) > 2: output_path = sys.argv[2]
+    generate_external(header, output_path)
--- a/python/lib/gen_pyobject.py
+++ /dev/null
@@ -1,529 +1,0 @@
-#! /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],
-  'sampler': [1, 1],
-}
-
-# 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'],
-    'sampler':      ['self->hop_size'],
-    'wavetable':    ['self->hop_size'],
-}
-
-# 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 ((sint_t)%(pname)s > 0) {
-    self->%(pname)s = %(pname)s;
-  } else if ((sint_t)%(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 += "  Py_RETURN_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;
-  }
-  Py_RETURN_NONE;
-}
-""" % {'funcname': method_name, 'objname': name, 
-        'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
-        shortname = method_name.split('aubio_'+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('aubio_'+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
--- a/python/lib/generator.py
+++ /dev/null
@@ -1,226 +1,0 @@
-#! /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(output_path):
-  if os.path.isdir(output_path): shutil.rmtree(output_path)
-  os.mkdir(output_path)
-
-  generated_objects = []
-  cpp_output, cpp_objects = get_cpp_objects()
-  skip_objects = [
-      # already in ext/
-      'fft',
-      'pvoc',
-      'filter',
-      'filterbank',
-      #'resampler',
-      # AUBIO_UNSTABLE
-      'hist',
-      'parameter',
-      'scale',
-      'beattracking',
-      'resampler',
-      'sndfile',
-      'peakpicker',
-      'pitchfcomb',
-      'pitchmcomb',
-      'pitchschmitt',
-      'pitchspecacf',
-      'pitchyin',
-      'pitchyinfft',
-      'sink',
-      'sink_apple_audio',
-      'sink_sndfile',
-      'sink_wavwrite',
-      'source',
-      'source_apple_audio',
-      'source_sndfile',
-      'source_avcodec',
-      'source_wavread',
-      #'sampler',
-      'audio_unit',
-      ]
-
-  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 = os.path.join(output_path,'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
-
-"""
-
-  types_ready = []
-  for each in generated_objects:
-      types_ready.append("  PyType_Ready (&Py_%sType) < 0" % \
-              each.replace('aubio_','').replace('_t','') )
-
-  s = """// generated list of objects created with generator.py
-
-#include "aubio-generated.h"
-"""
-
-  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(os.path.join(output_path,'aubio-generated.c'), 'w')
-  fd.write(s)
-
-  s = """// generated list of objects created with generator.py
-
-#include <Python.h>
-
-"""
-
-  for each in generated_objects:
-      s += "extern PyTypeObject Py_%sType;\n" % \
-              each.replace('aubio_','').replace('_t','')
-
-  s+= "int generated_objects ( void );\n"
-  s+= "void add_generated_objects( PyObject *m );\n"
-
-  fd = open(os.path.join(output_path,'aubio-generated.h'), 'w')
-  fd.write(s)
-
-  from os import listdir
-  generated_files = listdir(output_path)
-  generated_files = filter(lambda x: x.endswith('.c'), generated_files)
-  generated_files = [output_path+'/'+f for f in generated_files]
-  return generated_files
-
-if __name__ == '__main__':
-  generate_object_files('gen')
--- /dev/null
+++ b/python/lib/moresetuptools.py
@@ -1,0 +1,141 @@
+""" A collection of function used from setup.py distutils script """
+#
+import sys, os, glob, subprocess
+import distutils, distutils.command.clean, distutils.dir_util
+from .gen_external import generate_external, header, output_path
+
+# inspired from https://gist.github.com/abergmeier/9488990
+def add_packages(packages, ext=None, **kw):
+    """ use pkg-config to search which of 'packages' are installed """
+    flag_map = {
+        '-I': 'include_dirs',
+        '-L': 'library_dirs',
+        '-l': 'libraries'}
+
+    # if a setuptools extension is passed, fill it with pkg-config results
+    if ext:
+        kw = {'include_dirs': ext.include_dirs,
+              'extra_link_args': ext.extra_link_args,
+              'library_dirs': ext.library_dirs,
+              'libraries': ext.libraries,
+             }
+
+    for package in packages:
+        cmd = ['pkg-config', '--libs', '--cflags', package]
+        try:
+            tokens = subprocess.check_output(cmd)
+        except Exception as e:
+            print("Running \"{:s}\" failed: {:s}".format(' '.join(cmd), repr(e)))
+            continue
+        tokens = tokens.decode('utf8').split()
+        for token in tokens:
+            key = token[:2]
+            try:
+                arg = flag_map[key]
+                value = token[2:]
+            except KeyError:
+                arg = 'extra_link_args'
+                value = token
+            kw.setdefault(arg, []).append(value)
+    for key, value in iter(kw.items()): # remove duplicated
+        kw[key] = list(set(value))
+    return kw
+
+def add_local_aubio_header(ext):
+    """ use local "src/aubio.h", not <aubio/aubio.h>"""
+    ext.define_macros += [('USE_LOCAL_AUBIO', 1)]
+    ext.include_dirs += ['src'] # aubio.h
+
+def add_local_aubio_lib(ext):
+    """ add locally built libaubio from build/src """
+    print("Info: using locally built libaubio")
+    ext.library_dirs += [os.path.join('build', 'src')]
+    ext.libraries += ['aubio']
+
+def add_local_aubio_sources(ext):
+    """ build aubio inside python module instead of linking against libaubio """
+    print("Warning: libaubio was not built with waf, adding src/")
+    # create an empty header, macros will be passed on the command line
+    fake_config_header = os.path.join('python', 'ext', 'config.h')
+    distutils.file_util.write_file(fake_config_header, "")
+    aubio_sources = glob.glob(os.path.join('src', '**.c'))
+    aubio_sources += glob.glob(os.path.join('src', '*', '**.c'))
+    ext.sources += aubio_sources
+    # define macros (waf puts them in build/src/config.h)
+    for define_macro in ['HAVE_STDLIB_H', 'HAVE_STDIO_H',
+                         'HAVE_MATH_H', 'HAVE_STRING_H',
+                         'HAVE_C99_VARARGS_MACROS',
+                         'HAVE_LIMITS_H', 'HAVE_MEMCPY_HACKS']:
+        ext.define_macros += [(define_macro, 1)]
+
+    # loof for additional packages
+    print("Info: looking for *optional* additional packages")
+    packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample',
+                'jack',
+                'sndfile', 'samplerate',
+                #'fftw3f',
+               ]
+    add_packages(packages, ext=ext)
+    if 'avcodec' in ext.libraries \
+            and 'avformat' in ext.libraries \
+            and 'avutil' in ext.libraries \
+            and 'avresample' in ext.libraries:
+        ext.define_macros += [('HAVE_LIBAV', 1)]
+    if 'jack' in ext.libraries:
+        ext.define_macros += [('HAVE_JACK', 1)]
+    if 'sndfile' in ext.libraries:
+        ext.define_macros += [('HAVE_SNDFILE', 1)]
+    if 'samplerate' in ext.libraries:
+        ext.define_macros += [('HAVE_SAMPLERATE', 1)]
+    if 'fftw3f' in ext.libraries:
+        ext.define_macros += [('HAVE_FFTW3F', 1)]
+        ext.define_macros += [('HAVE_FFTW3', 1)]
+
+    # add accelerate on darwin
+    if sys.platform.startswith('darwin'):
+        ext.extra_link_args += ['-framework', 'Accelerate']
+        ext.define_macros += [('HAVE_ACCELERATE', 1)]
+        ext.define_macros += [('HAVE_SOURCE_APPLE_AUDIO', 1)]
+        ext.define_macros += [('HAVE_SINK_APPLE_AUDIO', 1)]
+
+    if sys.platform.startswith('win'):
+        ext.define_macros += [('HAVE_WIN_HACKS', 1)]
+
+    ext.define_macros += [('HAVE_WAVWRITE', 1)]
+    ext.define_macros += [('HAVE_WAVREAD', 1)]
+    # TODO:
+    # add cblas
+    if 0:
+        ext.libraries += ['cblas']
+        ext.define_macros += [('HAVE_ATLAS_CBLAS_H', 1)]
+
+def add_system_aubio(ext):
+    # use pkg-config to find aubio's location
+    add_packages(['aubio'], ext)
+    if 'aubio' not in ext.libraries:
+        print("Error: libaubio not found")
+
+class CleanGenerated(distutils.command.clean.clean):
+    def run(self):
+        distutils.dir_util.remove_tree(output_path)
+        distutils.command.clean.clean.run(self)
+
+class GenerateCommand(distutils.cmd.Command):
+    description = 'generate gen/gen-*.c files from ../src/aubio.h'
+    user_options = [
+            # The format is (long option, short option, description).
+            ('enable-double', None, 'use HAVE_AUBIO_DOUBLE=1 (default: 0)'),
+            ]
+
+    def initialize_options(self):
+        self.enable_double = False
+
+    def finalize_options(self):
+        if self.enable_double:
+            self.announce(
+                    'will generate code for aubio compiled with HAVE_AUBIO_DOUBLE=1',
+                    level=distutils.log.INFO)
+
+    def run(self):
+        self.announce( 'Generating code', level=distutils.log.INFO)
+        generated_object_files = generate_external(header, output_path, usedouble=self.enable_double)
--- a/python/scripts/aubiocut
+++ b/python/scripts/aubiocut
@@ -134,7 +134,7 @@
         if len(args) == 1:
             options.source_file = args[0]
         else:
-            print "no file name given\n", usage
+            print ("no file name given\n" + usage)
             sys.exit(1)
     return options, args
 
@@ -171,7 +171,7 @@
         samples, read = s()
         if o(samples):
             timestamps.append (o.get_last())
-            if options.verbose: print "%.4f" % o.get_last_s()
+            if options.verbose: print ("%.4f" % o.get_last_s())
         total_frames += read
         if read < hopsize: break
     del s
@@ -188,7 +188,7 @@
         from aubio.slicing import slice_source_at_stamps
         timestamps_end = None
         if options.cut_until_nslices and options.cut_until_nsamples:
-            print "warning: using cut_until_nslices, but cut_until_nsamples is set"
+            print ("warning: using cut_until_nslices, but cut_until_nsamples is set")
         if options.cut_until_nsamples:
             timestamps_end = [t + options.cut_until_nsamples for t in timestamps[1:]]
             timestamps_end += [ 1e120 ]
--- a/python/setup.py
+++ /dev/null
@@ -1,99 +1,0 @@
-#! /usr/bin/env python
-
-from setuptools import setup, Extension
-
-import sys
-import os.path
-import numpy
-
-# read from VERSION
-for l in open('VERSION').readlines(): exec (l.strip())
-__version__ = '.'.join \
-        ([str(x) for x in [AUBIO_MAJOR_VERSION, AUBIO_MINOR_VERSION, AUBIO_PATCH_VERSION]]) \
-        + AUBIO_VERSION_STATUS
-
-
-include_dirs = []
-library_dirs = []
-define_macros = []
-extra_link_args = []
-
-include_dirs += ['ext']
-include_dirs += [ numpy.get_include() ]
-
-if sys.platform.startswith('darwin'):
-    extra_link_args += ['-framework','CoreFoundation', '-framework','AudioToolbox']
-
-output_path = 'gen'
-generated_object_files = []
-
-if not os.path.isdir(output_path):
-    from lib.generator import generate_object_files
-    generated_object_files = generate_object_files(output_path)
-    # define include dirs
-else:
-    import glob
-    generated_object_files = glob.glob(os.path.join(output_path, '*.c'))
-include_dirs += [output_path]
-
-if os.path.isfile('../src/aubio.h'):
-    define_macros += [('USE_LOCAL_AUBIO', 1)]
-    include_dirs += ['../src'] # aubio.h
-    include_dirs += ['../build/src'] # config.h
-    library_dirs += ['../build/src']
-
-aubio_extension = Extension("aubio._aubio", [
-    "ext/aubiomodule.c",
-    "ext/aubioproxy.c",
-    "ext/ufuncs.c",
-    "ext/py-musicutils.c",
-    "ext/py-cvec.c",
-    # example without macro
-    "ext/py-filter.c",
-    # macroised
-    "ext/py-filterbank.c",
-    "ext/py-fft.c",
-    "ext/py-phasevoc.c",
-    "ext/py-source.c",
-    "ext/py-sink.c",
-    # generated files
-    ] + generated_object_files,
-    include_dirs = include_dirs,
-    library_dirs = library_dirs,
-    extra_link_args = extra_link_args,
-    define_macros = define_macros,
-    libraries=['aubio'])
-
-classifiers = [
-    'Development Status :: 4 - Beta',
-    'Environment :: Console',
-    'Intended Audience :: Science/Research',
-    'Topic :: Software Development :: Libraries',
-    'Topic :: Multimedia :: Sound/Audio :: Analysis',
-    'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis',
-    'Operating System :: POSIX',
-    'Operating System :: MacOS :: MacOS X',
-    'Operating System :: Microsoft :: Windows',
-    'Programming Language :: C',
-    'Programming Language :: Python',
-    'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
-    ]
-
-distrib = setup(name='aubio',
-    version = __version__,
-    packages = ['aubio'],
-    package_dir = {'aubio':'lib/aubio'},
-    scripts = ['scripts/aubiocut'],
-    ext_modules = [aubio_extension],
-    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/',
-    platforms = 'any',
-    classifiers = classifiers,
-    install_requires = ['numpy'],
-    )
--- a/python/tests/run_all_tests
+++ b/python/tests/run_all_tests
@@ -1,24 +1,5 @@
 #! /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)
-    modfiles = filter (lambda y: not 'beattracking' in y, modfiles)
-    modfiles = filter (lambda y: not 'hist' in y, modfiles)
-    modfiles = filter (lambda y: not 'scale' in y, modfiles)
-    modfiles = filter (lambda y: not 'peakpicker' in y, 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')
+    import nose2.main
+    nose2.discover()
--- a/python/tests/test_aubio.py
+++ b/python/tests/test_aubio.py
@@ -1,14 +1,14 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
+from unittest import main
+from numpy.testing import TestCase
 
 class aubiomodule_test_case(TestCase):
 
-  def test_import(self):
-    """ try importing aubio """
-    import aubio 
+    def test_import(self):
+        """ try importing aubio """
+        import aubio
 
 if __name__ == '__main__':
-  from unittest import main
-  main()
+    main()
 
--- a/python/tests/test_cvec.py
+++ b/python/tests/test_cvec.py
@@ -1,17 +1,19 @@
 #! /usr/bin/env python
 
-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
+from unittest import main
+import numpy as np
+from numpy.testing import TestCase, assert_equal
+from aubio import cvec, fvec, float_type
 
+wrong_type = 'float32' if float_type == 'float64' else 'float64'
+
 class aubio_cvec_test_case(TestCase):
 
     def test_vector_created_with_zeroes(self):
         a = cvec(10)
-        shape(a.norm)
-        shape(a.phas)
-        a.norm[0]
+        assert_equal(a.norm.shape[0], 10 / 2 + 1)
+        assert_equal(a.phas.shape[0], 10 / 2 + 1)
+        _ = a.norm[0]
         assert_equal(a.norm, 0.)
         assert_equal(a.phas, 0.)
 
@@ -41,11 +43,103 @@
 
     def test_assign_cvec_phas_slice(self):
         spec = cvec(1024)
-        spec.phas[39:-1] = -pi
+        spec.phas[39:-1] = -np.pi
         assert_equal(spec.phas[0:39], 0)
-        assert_equal(spec.phas[39:-1], -pi)
+        assert_equal(spec.phas[39:-1], -np.pi)
         assert_equal(spec.norm, 0)
 
+    def test_assign_cvec_with_other_cvec(self):
+        """ check dest cvec is still reachable after source was deleted """
+        spec = cvec(1024)
+        a = np.random.rand(1024//2+1).astype(float_type)
+        b = np.random.rand(1024//2+1).astype(float_type)
+        spec.norm = a
+        spec.phas = b
+        new_spec = spec
+        del spec
+        assert_equal(a, new_spec.norm)
+        assert_equal(b, new_spec.phas)
+        assert_equal(id(a), id(new_spec.norm))
+        assert_equal(id(b), id(new_spec.phas))
+
+    def test_pass_to_numpy(self):
+        spec = cvec(1024)
+        norm = spec.norm
+        phas = spec.phas
+        del spec
+        new_spec = cvec(1024)
+        new_spec.norm = norm
+        new_spec.phas = phas
+        assert_equal(norm, new_spec.norm)
+        assert_equal(phas, new_spec.phas)
+        assert_equal(id(norm), id(new_spec.norm))
+        assert_equal(id(phas), id(new_spec.phas))
+        del norm
+        del phas
+        assert_equal(new_spec.norm, 0.)
+        assert_equal(new_spec.phas, 0.)
+        del new_spec
+
+    def test_assign_norm_too_large(self):
+        a = cvec(512)
+        b = fvec(512//2+1 + 4)
+        with self.assertRaises(ValueError):
+            a.norm = b
+
+    def test_assign_norm_too_small(self):
+        a = cvec(512)
+        b = fvec(512//2+1 - 4)
+        with self.assertRaises(ValueError):
+            a.norm = b
+
+    def test_assign_phas_too_large(self):
+        a = cvec(512)
+        b = fvec(512//2+1 + 4)
+        with self.assertRaises(ValueError):
+            a.phas = b
+
+    def test_assign_phas_too_small(self):
+        a = cvec(512)
+        b = fvec(512//2+1 - 4)
+        with self.assertRaises(ValueError):
+            a.phas = b
+
+    def test_cvec_repr(self):
+        win_s = 512
+        c = cvec(win_s)
+        expected_repr = "aubio cvec of {:d} elements".format(win_s//2+1)
+        self.assertEqual(repr(c), expected_repr)
+
+class aubio_cvec_wrong_norm_input(TestCase):
+
+    def test_wrong_length(self):
+        with self.assertRaises(ValueError):
+            cvec(-1)
+
+    def test_set_norm_with_scalar(self):
+        a = cvec(512)
+        with self.assertRaises(ValueError):
+            a.norm = 1
+
+    def test_set_norm_with_scalar_array(self):
+        a = cvec(512)
+        with self.assertRaises(ValueError):
+            a.norm = np.ndarray(1, dtype = 'int')
+
+    def test_set_norm_with_int_array(self):
+        a = cvec(512)
+        with self.assertRaises(ValueError):
+            a.norm = np.zeros(512//2+1, dtype = 'int')
+
+    def test_set_norm_with_wrong_float_array(self):
+        a = cvec(512)
+        with self.assertRaises(ValueError):
+            a.norm = np.zeros(512//2+1, dtype = wrong_type)
+
+    def test_set_norm_with_wrong_2d_array(self):
+        a = cvec(512)
+        with self.assertRaises(ValueError):
+            a.norm = np.zeros((512//2+1, 2), dtype = float_type)
+
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_fft.py
+++ b/python/tests/test_fft.py
@@ -1,10 +1,12 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
+from unittest import main
+from numpy.testing import TestCase
 from numpy.testing import assert_equal, assert_almost_equal
+import numpy as np
 from aubio import fvec, fft, cvec
-from numpy import array, shape
-from math import pi
+from math import pi, floor
+from random import random
 
 class aubio_fft_test_case(TestCase):
 
@@ -20,8 +22,9 @@
         timegrain = fvec(win_s)
         f = fft (win_s)
         fftgrain = f (timegrain)
-        assert_equal (shape(fftgrain.norm), (win_s/2+1,))
-        assert_equal (shape(fftgrain.phas), (win_s/2+1,))
+        del f
+        assert_equal (fftgrain.norm.shape, (win_s/2+1,))
+        assert_equal (fftgrain.phas.shape, (win_s/2+1,))
 
     def test_zeros(self):
         """ check the transform of zeros is all zeros """
@@ -34,10 +37,8 @@
 
     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)
+        i = int(floor(random()*win_s))
         impulse = pi * random()
         f = fft(win_s)
         timegrain = fvec(win_s)
@@ -49,27 +50,26 @@
         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
+        """ check the transform of a negative impulse at a random place """
         win_s = 256
-        i = 0
-        impulse = -10.
+        i = int(floor(random()*win_s))
+        impulse = -.1
         f = fft(win_s)
         timegrain = fvec(win_s)
+        timegrain[0] = 0
         timegrain[i] = impulse
         fftgrain = f ( timegrain )
         #self.plot_this ( fftgrain.phas )
-        assert_almost_equal ( fftgrain.norm, abs(impulse), decimal = 6 )
+        assert_almost_equal ( fftgrain.norm, abs(impulse), decimal = 5 )
         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 ( 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)
+            assert_almost_equal ( np.fmod(fftgrain.phas[-1], pi), 0, 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)
+            #assert_equal ( fftgrain.phas[1:-1] == 0, True)
+            assert_equal ( fftgrain.phas[0], 0)
+            assert_almost_equal ( np.fmod(fftgrain.phas[-1], pi), 0, decimal = 6)
         # now check the resynthesis
         synthgrain = f.rdo ( fftgrain )
         #self.plot_this ( fftgrain.phas.T )
@@ -95,7 +95,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 )
@@ -106,7 +105,84 @@
         plot ( this )
         show ()
 
+    def test_local_fftgrain(self):
+        """ check aubio.fft() result can be accessed after deletion """
+        def compute_grain(impulse):
+            win_s = 1024
+            timegrain = fvec(win_s)
+            timegrain[0] = impulse
+            f = fft(win_s)
+            fftgrain = f ( timegrain )
+            return fftgrain
+        impulse = pi
+        fftgrain = compute_grain(impulse)
+        assert_equal ( fftgrain.phas[0], 0)
+        assert_almost_equal ( fftgrain.phas[1], 0)
+        assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
+
+    def test_local_reconstruct(self):
+        """ check aubio.fft.rdo() result can be accessed after deletion """
+        def compute_grain(impulse):
+            win_s = 1024
+            timegrain = fvec(win_s)
+            timegrain[0] = impulse
+            f = fft(win_s)
+            fftgrain = f ( timegrain )
+            r = f.rdo(fftgrain)
+            return r
+        impulse = pi
+        r = compute_grain(impulse)
+        assert_almost_equal ( r[0], impulse, decimal = 6)
+        assert_almost_equal ( r[1:], 0)
+
+    def test_large_input_timegrain(self):
+        win_s = 1024
+        f = fft(win_s)
+        t = fvec(win_s + 1)
+        with self.assertRaises(ValueError):
+            f(t)
+
+    def test_small_input_timegrain(self):
+        win_s = 1024
+        f = fft(win_s)
+        t = fvec(1)
+        with self.assertRaises(ValueError):
+            f(t)
+
+    def test_large_input_fftgrain(self):
+        win_s = 1024
+        f = fft(win_s)
+        s = cvec(win_s + 5)
+        with self.assertRaises(ValueError):
+            f.rdo(s)
+
+    def test_small_input_fftgrain(self):
+        win_s = 1024
+        f = fft(win_s)
+        s = cvec(16)
+        with self.assertRaises(ValueError):
+            f.rdo(s)
+
+class aubio_fft_wrong_params(TestCase):
+
+    def test_wrong_buf_size(self):
+        win_s = -1
+        with self.assertRaises(ValueError):
+            fft(win_s)
+
+    def test_buf_size_not_power_of_two(self):
+        # when compiled with fftw3, aubio supports non power of two fft sizes
+        win_s = 320
+        try:
+            with self.assertRaises(RuntimeError):
+                fft(win_s)
+        except AssertionError:
+            self.skipTest('creating aubio.fft with size %d did not fail' % win_s)
+
+    def test_buf_size_too_small(self):
+        win_s = 1
+        with self.assertRaises(RuntimeError):
+            fft(win_s)
+
 if __name__ == '__main__':
-    from unittest import main
     main()
-
--- a/python/tests/test_filter.py
+++ b/python/tests/test_filter.py
@@ -1,74 +1,87 @@
 #! /usr/bin/env python
 
+from unittest import main
 from numpy.testing import TestCase, assert_equal, assert_almost_equal
 from aubio import fvec, digital_filter
-from numpy import array
 from utils import array_from_text_file
 
 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_members(self):
+        f = digital_filter()
+        assert_equal (f.order, 7)
+        f = digital_filter(5)
+        assert_equal (f.order, 5)
+        f(fvec())
 
-  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_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_8000(self):
-    expected = array_from_text_file('c_weighting_test_simple_8000.expected')
-    f = digital_filter(5)
-    f.set_c_weighting(8000)
-    v = fvec(32)
-    v[12] = .5
-    u = f(v)
-    assert_almost_equal (expected[1], u)
+    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_c_weighting_8000(self):
+        expected = array_from_text_file('c_weighting_test_simple_8000.expected')
+        f = digital_filter(5)
+        f.set_c_weighting(8000)
+        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)
+    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)
 
-if __name__ == '__main__':
-  from unittest import main
-  main()
+    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)
 
+    def test_set_biquad(self):
+        f = digital_filter(3)
+        f.set_biquad(0., 0., 0, 0., 0.)
+
+    def test_set_biquad_wrong_order(self):
+        f = digital_filter(4)
+        with self.assertRaises(ValueError):
+            f.set_biquad(0., 0., 0, 0., 0.)
+
+class aubio_filter_wrong_params(TestCase):
+
+    def test_negative_order(self):
+        with self.assertRaises(ValueError):
+            digital_filter(-1)
+
+if __name__ == '__main__':
+    main()
--- a/python/tests/test_filterbank.py
+++ b/python/tests/test_filterbank.py
@@ -1,68 +1,84 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
+from unittest import main
+from numpy.testing import TestCase
 from numpy.testing import assert_equal, assert_almost_equal
-from numpy import random
-from math import pi
-from numpy import array
-from aubio import cvec, filterbank
+import numpy as np
+from aubio import cvec, filterbank, float_type
 from utils import array_from_text_file
 
 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_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())
+    def test_set_coeffs(self):
+        f = filterbank(40, 512)
+        r = np.random.random([40, int(512 / 2) + 1]).astype(float_type)
+        f.set_coeffs(r)
+        assert_equal (r, f.get_coeffs())
 
-  def test_phase(self):
-    f = filterbank(40, 512)
-    c = cvec(512)
-    c.phas[:] = pi
-    assert_equal( f(c), 0);
+    def test_phase(self):
+        f = filterbank(40, 512)
+        c = cvec(512)
+        c.phas[:] = np.pi
+        assert_equal( f(c), 0);
 
-  def test_norm(self):
-    f = filterbank(40, 512)
-    c = cvec(512)
-    c.norm[:] = 1
-    assert_equal( f(c), 0);
+    def test_norm(self):
+        f = filterbank(40, 512)
+        c = cvec(512)
+        c.norm[:] = 1
+        assert_equal( f(c), 0);
 
-  def test_random_norm(self):
-    f = filterbank(40, 512)
-    c = cvec(512)
-    c.norm[:] = random.random((512 / 2 + 1,)).astype('float32')
-    assert_equal( f(c), 0)
+    def test_random_norm(self):
+        f = filterbank(40, 512)
+        c = cvec(512)
+        c.norm[:] = np.random.random((int(512 / 2) + 1,)).astype(float_type)
+        assert_equal( f(c), 0)
 
-  def test_random_coeffs(self):
-    f = filterbank(40, 512)
-    c = cvec(512)
-    r = random.random([40, 512 / 2 + 1]).astype('float32')
-    r /= r.sum()
-    f.set_coeffs(r)
-    c.norm[:] = random.random((512 / 2 + 1,)).astype('float32')
-    assert_equal ( f(c) < 1., True )
-    assert_equal ( f(c) > 0., True )
+    def test_random_coeffs(self):
+        win_s = 128
+        f = filterbank(40, win_s)
+        c = cvec(win_s)
+        r = np.random.random([40, int(win_s / 2) + 1]).astype(float_type)
+        r /= r.sum()
+        f.set_coeffs(r)
+        c.norm[:] = np.random.random((int(win_s / 2) + 1,)).astype(float_type)
+        assert_equal ( f(c) < 1., True )
+        assert_equal ( f(c) > 0., True )
 
-  def test_mfcc_coeffs(self):
-    f = filterbank(40, 512)
-    c = cvec(512)
-    f.set_mel_coeffs_slaney(44100)
-    c.norm[:] = random.random((512 / 2 + 1,)).astype('float32')
-    assert_equal ( f(c) < 1., True )
-    assert_equal ( f(c) > 0., True )
+    def test_mfcc_coeffs(self):
+        f = filterbank(40, 512)
+        c = cvec(512)
+        f.set_mel_coeffs_slaney(44100)
+        c.norm[:] = np.random.random((int(512 / 2) + 1,)).astype(float_type)
+        assert_equal ( f(c) < 1., True )
+        assert_equal ( f(c) > 0., True )
 
-  def test_mfcc_coeffs_16000(self):
-    expected = array_from_text_file('filterbank_mfcc_16000_512.expected')
-    f = filterbank(40, 512)
-    f.set_mel_coeffs_slaney(16000)
-    assert_almost_equal ( expected, f.get_coeffs() )
+    def test_mfcc_coeffs_16000(self):
+        expected = array_from_text_file('filterbank_mfcc_16000_512.expected')
+        f = filterbank(40, 512)
+        f.set_mel_coeffs_slaney(16000)
+        assert_almost_equal ( expected, f.get_coeffs() )
 
-if __name__ == '__main__':
-  from unittest import main
-  main()
+class aubio_filterbank_wrong_values(TestCase):
 
+    def test_negative_window(self):
+        self.assertRaises(ValueError, filterbank, 40, -20)
+
+    def test_negative_filters(self):
+        self.assertRaises(ValueError, filterbank, -40, 1024)
+
+    def test_filterbank_long_cvec(self):
+        f = filterbank(40, 512)
+        with self.assertRaises(ValueError):
+            f(cvec(1024))
+
+    def test_filterbank_short_cvec(self):
+        f = filterbank(40, 512)
+        with self.assertRaises(ValueError):
+            f(cvec(256))
+
+if __name__ == '__main__':
+    main()
--- a/python/tests/test_filterbank_mel.py
+++ b/python/tests/test_filterbank_mel.py
@@ -1,51 +1,49 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
+from unittest import main
+from numpy.testing import TestCase
 from numpy.testing import assert_equal, assert_almost_equal
 from numpy import array, shape
-from aubio import cvec, filterbank
+from aubio import cvec, filterbank, float_type
 
 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_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_other_slaney(self):
+        f = filterbank(40, 512*2)
+        f.set_mel_coeffs_slaney(44100)
+        _ = 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(32000)
+            _ = 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_zeros(self):
+        f = filterbank(9, 1024)
+        freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
+        freqs = array(freq_list, dtype = float_type)
+        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])
+    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 = float_type)
+        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()
-
-
+    main()
--- a/python/tests/test_fvec.py
+++ b/python/tests/test_fvec.py
@@ -1,10 +1,13 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
-from numpy.testing import assert_equal, assert_almost_equal
+from unittest import main
+import numpy as np
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
 from aubio import fvec, zero_crossing_rate, alpha_norm, min_removal
-from numpy import array, shape
+from aubio import float_type
 
+wrong_type = 'float32' if float_type == 'float64' else 'float64'
+
 default_size = 512
 
 class aubio_fvec_test_case(TestCase):
@@ -11,15 +14,15 @@
 
     def test_vector_created_with_zeroes(self):
         a = fvec(10)
-        assert a.dtype == 'float32'
+        assert a.dtype == float_type
         assert a.shape == (10,)
-        assert_equal (a, 0)
+        assert_equal(a, 0)
 
     def test_vector_create_with_list(self):
-        a = fvec([0,1,2,3])
-        assert a.dtype == 'float32'
+        a = fvec([0, 1, 2, 3])
+        assert a.dtype == float_type
         assert a.shape == (4,)
-        assert_equal (range(4), a)
+        assert_equal(list(range(4)), a)
 
     def test_vector_assign_element(self):
         a = fvec(default_size)
@@ -34,104 +37,107 @@
 
     def test_vector(self):
         a = fvec()
-        a, len(a) #a.length
-        a[0]
-        array(a)
-        a = fvec(10)
+        len(a)
+        _ = a[0]
+        np.array(a)
         a = fvec(1)
-        a.T
-        array(a).T
-        a = range(len(a))
+        a = fvec(10)
+        _ = a.T
 
-    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)
+class aubio_fvec_wrong_values(TestCase):
 
-    def test_alpha_norm_of_fvec(self):
+    def test_negative_length(self):
+        """ test creating fvec with negative length fails (pure python) """
+        self.assertRaises(ValueError, fvec, -10)
+
+    def test_zero_length(self):
+        """ test creating fvec with zero length fails (pure python) """
+        self.assertRaises(ValueError, fvec, 0)
+
+    def test_out_of_bound(self):
+        """ test assiging fvec out of bounds fails (pure python) """
         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.)
+        self.assertRaises(IndexError, a.__getitem__, 3)
+        self.assertRaises(IndexError, a.__getitem__, 2)
 
-    def test_alpha_norm_of_none(self):
-        self.assertRaises (ValueError, alpha_norm, None, 1)
+class aubio_wrong_fvec_input(TestCase):
+    """ uses min_removal to test PyAubio_IsValidVector """
 
-    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_no_input(self):
+        self.assertRaises(TypeError, min_removal)
 
-    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_none(self):
+        self.assertRaises(ValueError, min_removal, None)
 
-    def test_alpha_norm_of_array_of_string (self):
-        a = "hello"
-        self.assertRaises (ValueError, alpha_norm, a, 1)
+    def test_wrong_scalar(self):
+        a = np.array(10, dtype=float_type)
+        self.assertRaises(ValueError, min_removal, a)
 
+    def test_wrong_dimensions(self):
+        a = np.array([[[1, 2], [3, 4]]], dtype=float_type)
+        self.assertRaises(ValueError, min_removal, a)
+
+    def test_wrong_array_size(self):
+        x = np.array([], dtype=float_type)
+        self.assertRaises(ValueError, min_removal, x)
+
+    def test_wrong_type(self):
+        a = np.zeros(10, dtype=wrong_type)
+        self.assertRaises(ValueError, min_removal, a)
+
+    def test_wrong_list_input(self):
+        self.assertRaises(ValueError, min_removal, [0., 1.])
+
+    def test_good_input(self):
+        a = np.zeros(10, dtype=float_type)
+        assert_equal(np.zeros(10, dtype=float_type), min_removal(a))
+
+class aubio_alpha_norm(TestCase):
+
+    def test_alpha_norm_of_random(self):
+        x = np.random.rand(1024).astype(float_type)
+        alpha = np.random.rand() * 5.
+        x_alpha_norm = (np.sum(np.abs(x)**alpha)/len(x))**(1/alpha)
+        assert_almost_equal(alpha_norm(x, alpha), x_alpha_norm, decimal = 5)
+
+class aubio_zero_crossing_rate_test(TestCase):
+
     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 )
+        a = np.array([0, 1, -1], dtype=float_type)
+        assert_almost_equal(zero_crossing_rate(a), 1./3.)
 
-    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_zero_crossing_rate_zeros(self):
+        a = np.zeros(100, dtype=float_type)
+        self.assertEqual(zero_crossing_rate(a), 0)
 
+    def test_zero_crossing_rate_minus_ones(self):
+        a = np.ones(100, dtype=float_type)
+        self.assertEqual(zero_crossing_rate(a), 0)
+
+    def test_zero_crossing_rate_plus_ones(self):
+        a = np.ones(100, dtype=float_type)
+        self.assertEqual(zero_crossing_rate(a), 0)
+
+class aubio_fvec_min_removal(TestCase):
+
     def test_fvec_min_removal_of_array(self):
-        a = array([20,1,19], dtype='float32')
+        a = np.array([20, 1, 19], dtype=float_type)
         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)
+        assert_equal(b, [19, 0, 18])
 
-    def test_fvec_min_removal_of_array_float64(self):
-        a = array([20,1,19], dtype='float64')
-        self.assertRaises (ValueError, min_removal, a)
+class aubio_fvec_test_memory(TestCase):
 
-    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)
+    def test_pass_to_numpy(self):
+        a = fvec(10)
+        a[:] = 1.
+        b = a
+        del a
+        assert_equal(b, 1.)
+        c = fvec(10)
+        c = b
+        del b
+        assert_equal(c, 1.)
+        del c
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_mathutils.py
+++ b/python/tests/test_mathutils.py
@@ -1,5 +1,6 @@
 #! /usr/bin/env python
 
+from unittest import main
 from numpy.testing import TestCase, assert_equal
 from numpy import array, arange, isnan, isinf
 from aubio import bintomidi, miditobin, freqtobin, bintofreq, freqtomidi, miditofreq
@@ -12,7 +13,7 @@
     def test_unwrap2pi(self):
         unwrap2pi(int(23))
         unwrap2pi(float(23.))
-        unwrap2pi(long(23.))
+        unwrap2pi(int(23.))
         unwrap2pi(arange(10))
         unwrap2pi(arange(10).astype("int"))
         unwrap2pi(arange(10).astype("float"))
@@ -23,13 +24,12 @@
         a[:] = 4.
         unwrap2pi(a)
         a = pi/100. * arange(-600,600).astype("float")
-        b = unwrap2pi (a)
+        unwrap2pi(a)
         #print zip(a, b)
 
-        try:
-            print unwrap2pi(["23.","24.",25.])
-        except Exception, e:
-            pass
+    def test_unwrap2pi_fails_on_list(self):
+        with self.assertRaises((TypeError, NotImplementedError)):
+            unwrap2pi(["23.","24.",25.])
 
     def test_unwrap2pi_takes_fvec(self):
         a = fvec(10)
@@ -53,7 +53,7 @@
         assert ( b <= pi ).all()
 
     def test_freqtomidi(self):
-        a = array(range(-20, 50000, 100) + [ -1e32, 1e32 ])
+        a = array(list(range(-20, 50000, 100)) + [ -1e32, 1e32 ])
         b = freqtomidi(a)
         #print zip(a, b)
         assert_equal ( isnan(array(b)), False )
@@ -61,7 +61,7 @@
         assert_equal ( array(b) < 0, False )
 
     def test_miditofreq(self):
-        a = range(-30, 200) + [-100000, 10000]
+        a = list(range(-30, 200)) + [-100000, 10000]
         b = miditofreq(a)
         #print zip(a, b)
         assert_equal ( isnan(b), False )
@@ -69,8 +69,8 @@
         assert_equal ( b < 0, False )
 
     def test_miditobin(self):
-        a = range(-30, 200) + [-100000, 10000]
-        b = [ bintomidi(x, 44100, 512) for x in a ]
+        a = list(range(-30, 200)) + [-100000, 10000]
+        b = [ miditobin(x, 44100, 512) for x in a ]
         #print zip(a, b)
         assert_equal ( isnan(array(b)), False )
         assert_equal ( isinf(array(b)), False )
@@ -77,7 +77,7 @@
         assert_equal ( array(b) < 0, False )
 
     def test_bintomidi(self):
-        a = range(-100, 512)
+        a = list(range(-100, 512))
         b = [ bintomidi(x, 44100, 512) for x in a ]
         #print zip(a, b)
         assert_equal ( isnan(array(b)), False )
@@ -85,7 +85,7 @@
         assert_equal ( array(b) < 0, False )
 
     def test_freqtobin(self):
-        a = range(-20, 50000, 100) + [ -1e32, 1e32 ]
+        a = list(range(-20, 50000, 100)) + [ -1e32, 1e32 ]
         b = [ freqtobin(x, 44100, 512) for x in a ]
         #print zip(a, b)
         assert_equal ( isnan(array(b)), False )
@@ -93,7 +93,7 @@
         assert_equal ( array(b) < 0, False )
 
     def test_bintofreq(self):
-        a = range(-20, 148)
+        a = list(range(-20, 148))
         b = [ bintofreq(x, 44100, 512) for x in a ]
         #print zip(a, b)
         assert_equal ( isnan(array(b)), False )
@@ -101,5 +101,4 @@
         assert_equal ( array(b) < 0, False )
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- /dev/null
+++ b/python/tests/test_mfcc.py
@@ -1,0 +1,109 @@
+#! /usr/bin/env python
+
+from nose2 import main
+from nose2.tools import params
+from numpy import random, count_nonzero
+from numpy.testing import TestCase
+from aubio import mfcc, cvec, float_type
+
+buf_size = 2048
+n_filters = 40
+n_coeffs = 13
+samplerate = 44100
+
+
+new_params = ['buf_size', 'n_filters', 'n_coeffs', 'samplerate']
+new_deflts = [1024, 40, 13, 44100]
+
+class aubio_mfcc(TestCase):
+
+    def setUp(self):
+        self.o = mfcc()
+
+    def test_default_creation(self):
+        pass
+
+    def test_delete(self):
+        del self.o
+
+    @params(*new_params)
+    def test_read_only_member(self, name):
+        o = self.o
+        with self.assertRaises((TypeError, AttributeError)):
+            setattr(o, name, 0)
+
+    @params(*zip(new_params, new_deflts))
+    def test_default_param(self, name, expected):
+        """ test mfcc.{:s} = {:d} """.format(name, expected)
+        o = self.o
+        self.assertEqual( getattr(o, name), expected)
+
+class aubio_mfcc_wrong_params(TestCase):
+
+    def test_wrong_buf_size(self):
+        with self.assertRaises(ValueError):
+            mfcc(buf_size = -1)
+
+    def test_wrong_n_filters(self):
+        with self.assertRaises(ValueError):
+            mfcc(n_filters = -1)
+
+    def test_wrong_n_coeffs(self):
+        with self.assertRaises(ValueError):
+            mfcc(n_coeffs = -1)
+
+    def test_wrong_samplerate(self):
+        with self.assertRaises(ValueError):
+            mfcc(samplerate = -1)
+
+class aubio_mfcc_compute(TestCase):
+
+    def test_members(self):
+
+        o = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        #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))
+        coeffs = o(spec)
+        self.assertEqual(coeffs.size, n_coeffs)
+        #print coeffs
+        spec.norm = random.random_sample((len(spec.norm),)).astype(float_type)
+        spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+        #print "%20s" % method, str(o(spec))
+        self.assertEqual(count_nonzero(o(spec) != 0.), n_coeffs)
+        #print coeffs
+
+
+class aubio_mfcc_all_parameters(TestCase):
+
+    @params(
+            (2048, 40, 13, 44100),
+            (1024, 40, 13, 44100),
+            (512, 40, 13, 44100),
+            (512, 40, 13, 16000),
+            (256, 40, 13, 16000),
+            (128, 40, 13, 16000),
+            (128, 40, 12, 16000),
+            (128, 40, 13, 15000),
+            (512, 40, 20, 44100),
+            (512, 40, 40, 44100),
+            (512, 40, 3, 44100),
+            (1024, 40, 20, 44100),
+            #(1024, 30, 20, 44100),
+            (1024, 40, 40, 44100),
+            (1024, 40, 3, 44100),
+            )
+    def test_run_with_params(self, buf_size, n_filters, n_coeffs, samplerate):
+        " check mfcc can run with reasonable parameters "
+        o = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        spec = cvec(buf_size)
+        spec.phas[0] = 0.2
+        for _ in range(10):
+            o(spec)
+        #print coeffs
+
+if __name__ == '__main__':
+    main()
--- a/python/tests/test_midi2note.py
+++ b/python/tests/test_midi2note.py
@@ -27,7 +27,7 @@
         " fails when passed a negative value "
         self.assertRaises(ValueError, midi2note, -2)
 
-    def test_midi2note_negative_value(self):
+    def test_midi2note_large(self):
         " fails when passed a value greater than 127 "
         self.assertRaises(ValueError, midi2note, 128)
 
--- a/python/tests/test_musicutils.py
+++ b/python/tests/test_musicutils.py
@@ -1,14 +1,12 @@
 #! /usr/bin/env python
 
+from unittest import main
+import numpy as np
 from numpy.testing import TestCase
 from numpy.testing.utils import assert_equal, assert_almost_equal
-from numpy import cos, arange
-from math import pi
-
 from aubio import window, level_lin, db_spl, silence_detection, level_detection
+from aubio import fvec, float_type
 
-from aubio import fvec
-
 class aubio_window(TestCase):
 
     def test_accept_name_and_size(self):
@@ -15,25 +13,17 @@
         window("default", 1024)
 
     def test_fail_name_not_string(self):
-        try:
+        with self.assertRaises(TypeError):
             window(10, 1024)
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-string window type does not raise a ValueError')
 
     def test_fail_size_not_int(self):
-        try:
+        with self.assertRaises(TypeError):
             window("default", "default")
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-integer window length does not raise a ValueError')
 
     def test_compute_hanning_1024(self):
         size = 1024
         aubio_window = window("hanning", size)
-        numpy_window = .5 - .5 * cos(2. * pi * arange(size) / size)
+        numpy_window = .5 - .5 * np.cos(2. * np.pi * np.arange(size) / size)
         assert_almost_equal(aubio_window, numpy_window)
 
 class aubio_level_lin(TestCase):
@@ -41,19 +31,14 @@
         level_lin(fvec(1024))
 
     def test_fail_not_fvec(self):
-        try:
+        with self.assertRaises(ValueError):
             level_lin("default")
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-number input phase does not raise a TypeError')
 
     def test_zeros_is_zeros(self):
         assert_equal(level_lin(fvec(1024)), 0.)
 
     def test_minus_ones_is_one(self):
-        from numpy import ones
-        assert_equal(level_lin(-ones(1024, dtype="float32")), 1.)
+        assert_equal(level_lin(-np.ones(1024, dtype = float_type)), 1.)
 
 class aubio_db_spl(TestCase):
     def test_accept_fvec(self):
@@ -60,20 +45,14 @@
         db_spl(fvec(1024))
 
     def test_fail_not_fvec(self):
-        try:
+        with self.assertRaises(ValueError):
             db_spl("default")
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-number input phase does not raise a TypeError')
 
     def test_zeros_is_inf(self):
-        from math import isinf
-        assert isinf(db_spl(fvec(1024)))
+        assert np.isinf(db_spl(fvec(1024)))
 
     def test_minus_ones_is_zero(self):
-        from numpy import ones
-        assert_equal(db_spl(-ones(1024, dtype="float32")), 0.)
+        assert_equal(db_spl(-np.ones(1024, dtype = float_type)), 0.)
 
 class aubio_silence_detection(TestCase):
     def test_accept_fvec(self):
@@ -80,20 +59,15 @@
         silence_detection(fvec(1024), -70.)
 
     def test_fail_not_fvec(self):
-        try:
+        with self.assertRaises(ValueError):
             silence_detection("default", -70)
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-number input phase does not raise a TypeError')
 
     def test_zeros_is_one(self):
-        from math import isinf
         assert silence_detection(fvec(1024), -70) == 1
 
     def test_minus_ones_is_zero(self):
         from numpy import ones
-        assert silence_detection(ones(1024, dtype="float32"), -70) == 0
+        assert silence_detection(ones(1024, dtype = float_type), -70) == 0
 
 class aubio_level_detection(TestCase):
     def test_accept_fvec(self):
@@ -100,21 +74,15 @@
         level_detection(fvec(1024), -70.)
 
     def test_fail_not_fvec(self):
-        try:
+        with self.assertRaises(ValueError):
             level_detection("default", -70)
-        except ValueError, e:
-            pass
-        else:
-            self.fail('non-number input phase does not raise a TypeError')
 
     def test_zeros_is_one(self):
-        from math import isinf
         assert level_detection(fvec(1024), -70) == 1
 
     def test_minus_ones_is_zero(self):
         from numpy import ones
-        assert level_detection(ones(1024, dtype="float32"), -70) == 0
+        assert level_detection(ones(1024, dtype = float_type), -70) == 0
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_note2midi.py
+++ b/python/tests/test_note2midi.py
@@ -1,7 +1,9 @@
 #! /usr/bin/env python
 # -*- coding: utf-8 -*-
 
-from aubio import note2midi
+from __future__ import unicode_literals
+
+from aubio import note2midi, freq2note
 import unittest
 
 list_of_known_notes = (
@@ -14,13 +16,13 @@
         ( 'A4', 69 ),
         ( 'A#4', 70 ),
         ( 'Bb4', 70 ),
-        ( u'B♭4', 70 ),
+        ( 'B♭4', 70 ),
         ( 'G8', 115 ),
-        ( u'G♯8', 116 ),
+        ( 'G♯8', 116 ),
         ( 'G9', 127 ),
-        ( u'G\udd2a2', 45 ),
-        ( u'B\ufffd2', 45 ),
-        ( u'A♮2', 45 ),
+        ( 'G\udd2a2', 45 ),
+        ( 'B\ufffd2', 45 ),
+        ( 'A♮2', 45 ),
         )
 
 class note2midi_good_values(unittest.TestCase):
@@ -49,12 +51,27 @@
         self.assertRaises(ValueError, note2midi, 'CBc')
 
     def test_note2midi_out_of_range(self):
-        " fails when passed a out of range note"
+        " fails when passed a note out of range"
         self.assertRaises(ValueError, note2midi, 'A9')
 
+    def test_note2midi_wrong_note_name(self):
+        " fails when passed a note with a wrong name"
+        self.assertRaises(ValueError, note2midi, 'W9')
+
+    def test_note2midi_low_octave(self):
+        " fails when passed a note with a too low octave"
+        self.assertRaises(ValueError, note2midi, 'C-9')
+
     def test_note2midi_wrong_data_type(self):
         " fails when passed a non-string value "
         self.assertRaises(TypeError, note2midi, 123)
+
+
+class freq2note_simple_test(unittest.TestCase):
+
+    def test_freq2note(self):
+        " make sure freq2note(441) == A4 "
+        self.assertEqual("A4", freq2note(441))
 
 if __name__ == '__main__':
     unittest.main()
--- a/python/tests/test_onset.py
+++ b/python/tests/test_onset.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
-from numpy.testing import assert_equal, assert_almost_equal
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
 from aubio import onset
 
 class aubio_onset_default(TestCase):
@@ -84,5 +84,4 @@
     samplerate = 8000
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_phasevoc.py
+++ b/python/tests/test_phasevoc.py
@@ -1,12 +1,23 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, assert_equal, assert_almost_equal
-from aubio import fvec, cvec, pvoc
-from numpy import array, shape
-from numpy.random import random
+from numpy.testing import TestCase, assert_equal, assert_array_less
+from aubio import fvec, cvec, pvoc, float_type
+from nose2 import main
+from nose2.tools import params
+import numpy as np
 
-precision = 6
+if float_type == 'float32':
+    max_sq_error = 1.e-12
+else:
+    max_sq_error = 1.e-29
 
+def create_sine(hop_s, freq, samplerate):
+    t = np.arange(hop_s).astype(float_type)
+    return np.sin( 2. * np.pi * freq * t / float(samplerate))
+
+def create_noise(hop_s):
+    return np.random.rand(hop_s).astype(float_type) * 2. - 1.
+
 class aubio_pvoc_test_case(TestCase):
     """ pvoc object test case """
 
@@ -30,53 +41,147 @@
         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 ):
+        for _ in range( int ( 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)
+            assert_equal ( t, 0.)
+            assert_equal ( s.norm, 0.)
+            assert_equal ( s.phas, 0.)
+            assert_equal ( r, 0.)
 
-    def test_resynth_two_steps(self):
-        """ check the resynthesis of steps is correct with 50% overlap """
-        hop_s = 512
-        buf_s = hop_s * 2
+    @params(
+            ( 256, 8),
+            ( 256, 4),
+            ( 256, 2),
+            ( 512, 8),
+            ( 512, 4),
+            ( 512, 2),
+            #( 129, 2),
+            #( 320, 4),
+            #(  13, 8),
+            (1024, 8),
+            (1024, 4),
+            (1024, 2),
+            (2048, 8),
+            (2048, 4),
+            (2048, 2),
+            (4096, 8),
+            (4096, 4),
+            (4096, 2),
+            (8192, 8),
+            (8192, 4),
+            (8192, 2),
+            )
+    def test_resynth_steps_noise(self, hop_s, ratio):
+        """ check the resynthesis of a random signal is correct """
+        sigin = create_noise(hop_s)
+        self.reconstruction(sigin, hop_s, ratio)
+
+    @params(
+            (44100,  256, 8,   441),
+            (44100,  256, 4,  1203),
+            (44100,  256, 2,  3045),
+            (44100,  512, 8,   445),
+            (44100,  512, 4,   445),
+            (44100,  512, 2,   445),
+            (44100, 1024, 8,   445),
+            (44100, 1024, 4,   445),
+            (44100, 1024, 2,   445),
+            ( 8000, 1024, 2,   445),
+            (22050, 1024, 2,   445),
+            (22050,  256, 8,   445),
+            (96000, 1024, 8, 47000),
+            (96000, 1024, 8,    20),
+            )
+    def test_resynth_steps_sine(self, samplerate, hop_s, ratio, freq):
+        """ check the resynthesis of a sine is correct """
+        sigin = create_sine(hop_s, freq, samplerate)
+        self.reconstruction(sigin, hop_s, ratio)
+
+    def reconstruction(self, sigin, hop_s, ratio):
+        buf_s = hop_s * ratio
         f = pvoc(buf_s, hop_s)
-        sigin = fvec(hop_s)
         zeros = fvec(hop_s)
-        # negative step
-        sigin[20:50] = -.1
-        # positive step
-        sigin[100:200] = .1
-        s1 = f(sigin)
-        r1 = f.rdo(s1)
-        s2 = f(zeros)
-        r2 = f.rdo(s2)
-        #self.plot_this ( s2.norm.T )
-        assert_almost_equal ( r2, sigin, decimal = precision )
-    
-    def test_resynth_three_steps(self):
-        """ check the resynthesis of steps is correct with 25% overlap """
-        hop_s = 16
-        buf_s = hop_s * 4
-        sigin = fvec(hop_s)
-        zeros = fvec(hop_s)
-        f = pvoc(buf_s, hop_s)
-        for i in xrange(hop_s):
-            sigin[i] = random() * 2. - 1.
-        t2 = f.rdo( f(sigin) )
-        t2 = f.rdo( f(zeros) )
-        t2 = f.rdo( f(zeros) )
-        t2 = f.rdo( f(zeros) )
-        assert_almost_equal( sigin, t2, decimal = precision )
-    
-    def plot_this( self, this ):
-        from pylab import semilogy, show
-        semilogy ( this )
-        show ()
+        r2 = f.rdo( f(sigin) )
+        for _ in range(1, ratio):
+            r2 = f.rdo( f(zeros) )
+        # compute square errors
+        sq_error = (r2 - sigin)**2
+        # make sure all square errors are less than desired precision
+        assert_array_less(sq_error, max_sq_error)
 
+class aubio_pvoc_strange_params(TestCase):
+
+    def test_win_size_short(self):
+        with self.assertRaises(RuntimeError):
+            pvoc(1, 1)
+
+    def test_hop_size_long(self):
+        with self.assertRaises(RuntimeError):
+            pvoc(1024, 1025)
+
+    def test_large_input_timegrain(self):
+        win_s = 1024
+        f = pvoc(win_s)
+        t = fvec(win_s + 1)
+        with self.assertRaises(ValueError):
+            f(t)
+
+    def test_small_input_timegrain(self):
+        win_s = 1024
+        f = pvoc(win_s)
+        t = fvec(1)
+        with self.assertRaises(ValueError):
+            f(t)
+
+    def test_large_input_fftgrain(self):
+        win_s = 1024
+        f = pvoc(win_s)
+        s = cvec(win_s + 5)
+        with self.assertRaises(ValueError):
+            f.rdo(s)
+
+    def test_small_input_fftgrain(self):
+        win_s = 1024
+        f = pvoc(win_s)
+        s = cvec(16)
+        with self.assertRaises(ValueError):
+            f.rdo(s)
+
+class aubio_pvoc_wrong_params(TestCase):
+
+    def test_wrong_buf_size(self):
+        win_s = -1
+        with self.assertRaises(ValueError):
+            pvoc(win_s)
+
+    def test_buf_size_too_small(self):
+        win_s = 1
+        with self.assertRaises(RuntimeError):
+            pvoc(win_s)
+
+    def test_hop_size_negative(self):
+        win_s = 512
+        hop_s = -2
+        with self.assertRaises(ValueError):
+            pvoc(win_s, hop_s)
+
+    def test_hop_size_too_small(self):
+        win_s = 1
+        hop_s = 1
+        with self.assertRaises(RuntimeError):
+            pvoc(win_s, hop_s)
+
+    def test_buf_size_not_power_of_two(self):
+        win_s = 320
+        hop_s = win_s // 2
+        try:
+            with self.assertRaises(RuntimeError):
+                pvoc(win_s, hop_s)
+        except AssertionError:
+            # when compiled with fftw3, aubio supports non power of two fft sizes
+            self.skipTest('creating aubio.pvoc with size %d did not fail' % win_s)
+
 if __name__ == '__main__':
-  from unittest import main
-  main()
+    main()
 
--- a/python/tests/test_pitch.py
+++ b/python/tests/test_pitch.py
@@ -1,10 +1,9 @@
 #! /usr/bin/env python
 
-from unittest import TestCase
-from numpy.testing import assert_equal, assert_almost_equal
-from numpy import random, sin, arange, mean, median, isnan
-from math import pi
-from aubio import fvec, pitch, freqtomidi
+from unittest import TestCase, main
+from numpy.testing import assert_equal
+from numpy import sin, arange, mean, median, isnan, pi
+from aubio import fvec, pitch, freqtomidi, float_type
 
 class aubio_pitch_Good_Values(TestCase):
 
@@ -24,7 +23,7 @@
         " running on silence gives 0 "
         p = pitch('default', 2048, 512, 32000)
         f = fvec (512)
-        for i in xrange(10): assert_equal (p(f), 0.)
+        for _ in range(10): assert_equal (p(f), 0.)
 
     def test_run_on_ones(self):
         " running on ones gives 0 "
@@ -31,7 +30,7 @@
         p = pitch('default', 2048, 512, 32000)
         f = fvec (512)
         f[:] = 1
-        for i in xrange(10): assert_equal (p(f), 0.)
+        for _ in range(10): assert_equal (p(f), 0.)
 
 class aubio_pitch_Sinusoid(TestCase):
 
@@ -50,10 +49,9 @@
         self.run_pitch(p, sinvec, freq)
 
     def build_sinusoid(self, length, freq, samplerate):
-        return sin( 2. * pi * arange(length).astype('float32') * freq / samplerate)
+        return sin( 2. * pi * arange(length).astype(float_type) * freq / samplerate)
 
     def run_pitch(self, p, input_vec, freq):
-        count = 0
         pitches, errors = [], []
         input_blocks = input_vec.reshape((-1, p.hop_size))
         for new_block in input_blocks:
@@ -63,7 +61,7 @@
         assert_equal ( len(input_blocks), len(pitches) )
         assert_equal ( isnan(pitches), False )
         # cut the first candidates
-        cut = ( p.buf_size - p.hop_size ) / p.hop_size
+        #cut = ( p.buf_size - p.hop_size ) / p.hop_size
         pitches = pitches[2:]
         errors = errors[2:]
         # check that the mean of all relative errors is less than 10%
@@ -124,5 +122,4 @@
         setattr (aubio_pitch_Sinusoid, test_method.__name__, test_method)
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_sink.py
+++ b/python/tests/test_sink.py
@@ -1,17 +1,31 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from nose2 import main
+from nose2.tools import params
+from numpy.testing import TestCase
 from aubio import fvec, source, sink
-from numpy import array
 from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
 
 list_of_sounds = list_all_sounds('sounds')
+samplerates = [0, 44100, 8000, 32000]
+hop_sizes = [512, 1024, 64]
+
 path = None
 
 many_files = 300 # 256 opened files is too much
 
+all_params = []
+for soundfile in list_of_sounds:
+    for hop_size in hop_sizes:
+        for samplerate in samplerates:
+            all_params.append((hop_size, samplerate, soundfile))
+
 class aubio_sink_test_case(TestCase):
 
+    def setUp(self):
+        if not len(list_of_sounds):
+            self.skipTest('add some sound files in \'python/tests/sounds\'')
+
     def test_many_sinks(self):
         from tempfile import mkdtemp
         import os.path
@@ -23,87 +37,47 @@
             g = sink(path, 0)
             sink_list.append(g)
             write = 32
-            for n in range(200):
+            for _ in range(200):
                 vec = fvec(write)
                 g(vec, write)
             g.close()
         shutil.rmtree(tmpdir)
 
-    def test_many_sinks_not_closed(self):
-        from tempfile import mkdtemp
-        import os.path
-        import shutil
-        tmpdir = mkdtemp()
-        sink_list = []
+    @params(*all_params)
+    def test_read_and_write(self, hop_size, samplerate, path):
+
         try:
-            for i in range(many_files):
-                path = os.path.join(tmpdir, 'f-' + str(i) + '.wav')
-                g = sink(path, 0)
-                sink_list.append(g)
-                write = 256
-                for n in range(200):
-                    vec = fvec(write)
-                    g(vec, write)
-        except StandardError:
-            pass
-        else:
-            self.fail("does not fail on too many files open")
-        for g in sink_list:
-            g.close()
-        shutil.rmtree(tmpdir)
+            f = source(path, samplerate, hop_size)
+        except RuntimeError as e:
+            self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+        if samplerate == 0: samplerate = f.samplerate
+        sink_path = get_tmp_sink_path()
+        g = sink(sink_path, samplerate)
+        total_frames = 0
+        while True:
+            vec, read = f()
+            g(vec, read)
+            total_frames += read
+            if read < f.hop_size: break
+        del_tmp_sink_path(sink_path)
 
-    def test_read_and_write(self):
+    @params(*all_params)
+    def test_read_and_write_multi(self, hop_size, samplerate, path):
+        try:
+            f = source(path, samplerate, hop_size)
+        except RuntimeError as e:
+            self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+        if samplerate == 0: samplerate = f.samplerate
+        sink_path = get_tmp_sink_path()
+        g = sink(sink_path, samplerate, channels = f.channels)
+        total_frames = 0
+        while True:
+            vec, read = f.do_multi()
+            g.do_multi(vec, read)
+            total_frames += read
+            if read < f.hop_size: break
+        del_tmp_sink_path(sink_path)
 
-        if not len(list_of_sounds):
-            self.skipTest('add some sound files in \'python/tests/sounds\'')
-
-        for path in list_of_sounds:
-            for samplerate, hop_size in zip([0, 44100, 8000, 32000], [512, 1024, 64, 256]):
-                f = source(path, samplerate, hop_size)
-                if samplerate == 0: samplerate = f.samplerate
-                sink_path = get_tmp_sink_path()
-                g = sink(sink_path, samplerate)
-                total_frames = 0
-                while True:
-                    vec, read = f()
-                    g(vec, read)
-                    total_frames += read
-                    if read < f.hop_size: break
-                if 0:
-                    print "read", "%.2fs" % (total_frames / float(f.samplerate) ),
-                    print "(", total_frames, "frames", "in",
-                    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-                    print "from", f.uri,
-                    print "to", g.uri
-                del_tmp_sink_path(sink_path)
-
-    def test_read_and_write_multi(self):
-
-        if not len(list_of_sounds):
-            self.skipTest('add some sound files in \'python/tests/sounds\'')
-
-        for path in list_of_sounds:
-            for samplerate, hop_size in zip([0, 44100, 8000, 32000], [512, 1024, 64, 256]):
-                f = source(path, samplerate, hop_size)
-                if samplerate == 0: samplerate = f.samplerate
-                sink_path = get_tmp_sink_path()
-                g = sink(sink_path, samplerate, channels = f.channels)
-                total_frames = 0
-                while True:
-                    vec, read = f.do_multi()
-                    g.do_multi(vec, read)
-                    total_frames += read
-                    if read < f.hop_size: break
-                if 0:
-                    print "read", "%.2fs" % (total_frames / float(f.samplerate) ),
-                    print "(", total_frames, "frames", "in",
-                    print f.channels, "channels", "in",
-                    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-                    print "from", f.uri,
-                    print "to", g.uri,
-                    print "in", g.channels, "channels"
-                del_tmp_sink_path(sink_path)
-
     def test_close_file(self):
         samplerate = 44100
         sink_path = get_tmp_sink_path()
@@ -120,5 +94,4 @@
         del_tmp_sink_path(sink_path)
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_slicing.py
+++ b/python/tests/test_slicing.py
@@ -1,10 +1,10 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, run_module_suite
-from numpy.testing import assert_equal, assert_almost_equal
-
+from unittest import main
+from numpy.testing import TestCase, assert_equal
 from aubio import slice_source_at_stamps
-from utils import *
+from utils import count_files_in_directory, get_default_test_sound
+from utils import count_samples_in_directory, count_samples_in_file
 
 import tempfile
 import shutil
@@ -146,5 +146,4 @@
         shutil.rmtree(self.output_dir)
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_source.py
+++ b/python/tests/test_source.py
@@ -1,17 +1,29 @@
 #! /usr/bin/env python
 
-from numpy.testing import TestCase, assert_equal, assert_almost_equal
-from aubio import fvec, source
-from numpy import array
+from nose2 import main
+from nose2.tools import params
+from numpy.testing import TestCase
+from aubio import source
 from utils import list_all_sounds
 
 list_of_sounds = list_all_sounds('sounds')
+samplerates = [0, 44100, 8000, 32000]
+hop_sizes = [512, 1024, 64]
+
 path = None
 
+all_params = []
+for soundfile in list_of_sounds:
+    for hop_size in hop_sizes:
+        for samplerate in samplerates:
+            all_params.append((hop_size, samplerate, soundfile))
+
+
 class aubio_source_test_case_base(TestCase):
 
     def setUp(self):
         if not len(list_of_sounds): self.skipTest('add some sound files in \'python/tests/sounds\'')
+        self.default_test_sound = list_of_sounds[0]
 
 class aubio_source_test_case(aubio_source_test_case_base):
 
@@ -35,86 +47,111 @@
     def read_from_source(self, f):
         total_frames = 0
         while True:
-            vec, read = f()
+            _ , read = f()
             total_frames += read
             if read < f.hop_size: break
-        print "read", "%.2fs" % (total_frames / float(f.samplerate) ),
-        print "(", total_frames, "frames", "in",
-        print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-        print "from", f.uri
+        #result_str = "read {:.2f}s ({:d} frames in {:d} blocks at {:d}Hz) from {:s}"
+        #result_params = total_frames / float(f.samplerate), total_frames, total_frames//f.hop_size, f.samplerate, f.uri
+        #print (result_str.format(*result_params))
         return total_frames
 
-    def test_samplerate_hopsize(self):
-        for p in list_of_sounds:
-            for samplerate, hop_size in zip([0, 44100, 8000, 32000], [ 512, 512, 64, 256]):
-                f = source(p, samplerate, hop_size)
-                assert f.samplerate != 0
-                self.read_from_source(f)
+    @params(*all_params)
+    def test_samplerate_hopsize(self, hop_size, samplerate, soundfile):
+        try:
+            f = source(soundfile, samplerate, hop_size)
+        except RuntimeError as e:
+            self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+        assert f.samplerate != 0
+        self.read_from_source(f)
 
-    def test_samplerate_none(self):
-        for p in list_of_sounds:
-            f = source(p)
-            assert f.samplerate != 0
-            self.read_from_source(f)
+    @params(*list_of_sounds)
+    def test_samplerate_none(self, p):
+        f = source(p)
+        assert f.samplerate != 0
+        self.read_from_source(f)
 
-    def test_samplerate_0(self):
-        for p in list_of_sounds:
-            f = source(p, 0)
-            assert f.samplerate != 0
-            self.read_from_source(f)
+    @params(*list_of_sounds)
+    def test_samplerate_0(self, p):
+        f = source(p, 0)
+        assert f.samplerate != 0
+        self.read_from_source(f)
 
+    @params(*list_of_sounds)
+    def test_zero_hop_size(self, p):
+        f = source(p, 0, 0)
+        assert f.samplerate != 0
+        assert f.hop_size != 0
+        self.read_from_source(f)
+
+    @params(*list_of_sounds)
+    def test_seek_to_half(self, p):
+        from random import randint
+        f = source(p, 0, 0)
+        assert f.samplerate != 0
+        assert f.hop_size != 0
+        a = self.read_from_source(f)
+        c = randint(0, a)
+        f.seek(c)
+        b = self.read_from_source(f)
+        assert a == b + c
+
+    @params(*list_of_sounds)
+    def test_duration(self, p):
+        total_frames = 0
+        f = source(p)
+        duration = f.duration
+        while True:
+            _, read = f()
+            total_frames += read
+            if read < f.hop_size: break
+        self.assertEqual(duration, total_frames)
+
+
+class aubio_source_test_wrong_params(TestCase):
+
+    def test_wrong_file(self):
+        with self.assertRaises(RuntimeError):
+            source('path_to/unexisting file.mp3')
+
+class aubio_source_test_wrong_params_with_file(aubio_source_test_case_base):
+
     def test_wrong_samplerate(self):
-        for p in list_of_sounds:
-            try:
-                f = source(p, -1)
-            except ValueError, e:
-                pass
-            else:
-                self.fail('negative samplerate does not raise ValueError')
+        with self.assertRaises(ValueError):
+            source(self.default_test_sound, -1)
 
     def test_wrong_hop_size(self):
-        for p in list_of_sounds:
-            try:
-                f = source(p, 0, -1)
-            except ValueError, e:
-                pass
-            else:
-                self.fail('negative hop_size does not raise ValueError')
+        with self.assertRaises(ValueError):
+            source(self.default_test_sound, 0, -1)
 
-    def test_zero_hop_size(self):
-        for p in list_of_sounds:
-            f = source(p, 0, 0)
-            assert f.samplerate != 0
-            assert f.hop_size != 0
-            self.read_from_source(f)
+    def test_wrong_channels(self):
+        with self.assertRaises(ValueError):
+            source(self.default_test_sound, 0, 0, -1)
 
-    def test_seek_to_half(self):
-        from random import randint
-        for p in list_of_sounds:
-            f = source(p, 0, 0)
-            assert f.samplerate != 0
-            assert f.hop_size != 0
-            a = self.read_from_source(f)
-            c = randint(0, a)
-            f.seek(c)
-            b = self.read_from_source(f)
-            assert a == b + c
+    def test_wrong_seek(self):
+        f = source(self.default_test_sound)
+        with self.assertRaises(ValueError):
+            f.seek(-1)
 
+    def test_wrong_seek_too_large(self):
+        f = source(self.default_test_sound)
+        try:
+            with self.assertRaises(ValueError):
+                f.seek(f.duration + f.samplerate * 10)
+        except AssertionError:
+            self.skipTest('seeking after end of stream failed raising ValueError')
+
 class aubio_source_readmulti_test_case(aubio_source_read_test_case):
 
     def read_from_source(self, f):
         total_frames = 0
         while True:
-            vec, read = f.do_multi()
+            _, read = f.do_multi()
             total_frames += read
             if read < f.hop_size: break
-        print "read", "%.2fs" % (total_frames / float(f.samplerate) ),
-        print "(", total_frames, "frames", "in",
-        print f.channels, "channels and",
-        print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-        print "from", f.uri
+        #result_str = "read {:.2f}s ({:d} frames in {:d} channels and {:d} blocks at {:d}Hz) from {:s}"
+        #result_params = total_frames / float(f.samplerate), total_frames, f.channels, int(total_frames/f.hop_size), f.samplerate, f.uri
+        #print (result_str.format(*result_params))
         return total_frames
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_specdesc.py
+++ b/python/tests/test_specdesc.py
@@ -1,9 +1,9 @@
 #! /usr/bin/env python
 
+from unittest import main
 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
+from aubio import specdesc, cvec, float_type
 
 methods = ["default",
      "energy",
@@ -29,38 +29,25 @@
         o = specdesc()
 
         for method in methods:
-          o = specdesc(method, buf_size)
-          assert_equal ([o.buf_size, o.method], [buf_size, method])
+            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.)
+            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(float_type)
+            spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+            #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')
+        spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
         # phase of random is not zero
         spec.norm[:] = 1
         assert (o(spec) != 0.)
@@ -70,7 +57,7 @@
         spec = cvec(buf_size)
         # specdiff of zeros is zero
         assert_equal (o(spec), 0.)
-        spec.phas = random.random_sample((len(spec.phas),)).astype('float32')
+        spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
         # phase of random is not zero
         spec.norm[:] = 1
         assert (o(spec) != 0.)
@@ -79,7 +66,7 @@
         o = specdesc("hfc")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         assert_equal (a, c.norm)
         assert_equal ( sum(a*(a+1)), o(c))
@@ -88,7 +75,7 @@
         o = specdesc("complex")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         assert_equal (a, c.norm)
         # the previous run was on zeros, so previous frames are still 0
@@ -101,7 +88,7 @@
         o = specdesc("kl")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         assert_almost_equal( sum(a * log(1.+ a/1.e-1 ) ) / o(c), 1., decimal=6)
 
@@ -109,7 +96,7 @@
         o = specdesc("mkl")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         assert_almost_equal( sum(log(1.+ a/1.e-1 ) ) / o(c), 1, decimal=6)
 
@@ -117,11 +104,11 @@
         o = specdesc("specflux")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         assert_equal( sum(a), o(c))
         assert_equal( 0, o(c))
-        c.norm = zeros(c.length, dtype='float32')
+        c.norm = zeros(c.length, dtype=float_type)
         assert_equal( 0, o(c))
 
     def test_centroid(self):
@@ -129,7 +116,7 @@
         c = cvec()
         # make sure centroid of zeros is zero
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         centroid = sum(a*a) / sum(a)
         assert_almost_equal (centroid, o(c), decimal = 2)
@@ -140,7 +127,7 @@
     def test_spread(self):
         o = specdesc("spread")
         c = cvec(2048)
-        ramp = arange(c.length, dtype='float32')
+        ramp = arange(c.length, dtype=float_type)
         assert_equal( 0., o(c))
 
         a = ramp
@@ -153,7 +140,7 @@
         o = specdesc("skewness")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         centroid = sum(a*a) / sum(a)
         spread = sum( (a - centroid)**2 *a) / sum(a)
@@ -167,7 +154,7 @@
         o = specdesc("kurtosis")
         c = cvec()
         assert_equal( 0., o(c))
-        a = arange(c.length, dtype='float32')
+        a = arange(c.length, dtype=float_type)
         c.norm = a
         centroid = sum(a*a) / sum(a)
         spread = sum( (a - centroid)**2 *a) / sum(a)
@@ -178,8 +165,8 @@
         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')
+        a = arange(c.length * 2, 0, -2, dtype=float_type)
+        k = arange(c.length, dtype=float_type)
         c.norm = a
         num = len(a) * sum(k*a) - sum(k)*sum(a)
         den = (len(a) * sum(k**2) - sum(k)**2)
@@ -186,7 +173,7 @@
         slope = num/den/sum(a)
         assert_almost_equal (slope, o(c), decimal = 5)
 
-        a = arange(0, c.length * 2, +2, dtype='float32')
+        a = arange(0, c.length * 2, +2, dtype=float_type)
         c.norm = a
         num = len(a) * sum(k*a) - sum(k)*sum(a)
         den = (len(a) * sum(k**2) - sum(k)**2)
@@ -193,7 +180,7 @@
         slope = num/den/sum(a)
         assert_almost_equal (slope, o(c), decimal = 5)
 
-        a = arange(0, c.length * 2, +2, dtype='float32')
+        a = arange(0, c.length * 2, +2, dtype=float_type)
         c.norm = a * 2
         assert_almost_equal (slope, o(c), decimal = 5)
 
@@ -201,18 +188,18 @@
         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')
+        a = arange(c.length * 2, 0, -2, dtype=float_type)
+        k = arange(c.length, dtype=float_type)
         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')
+        a = arange(0, c.length * 2, +2, dtype=float_type)
         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')
+        a = arange(0, c.length * 2, +2, dtype=float_type)
         c.norm = a * 2
         decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:]) 
         assert_almost_equal (decrease, o(c), decimal = 5)
@@ -221,18 +208,27 @@
         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')
+        a = arange(c.length * 2, 0, -2, dtype=float_type)
         c.norm = a
         cumsum = .95*sum(a*a)
         i = 0; rollsum = 0
         while rollsum < cumsum:
-          rollsum += a[i]*a[i]
-          i+=1
+            rollsum += a[i]*a[i]
+            i+=1
         rolloff = i 
         assert_equal (rolloff, o(c))
 
+class aubio_specdesc_wrong(TestCase):
 
+    def test_negative(self):
+        with self.assertRaises(ValueError):
+            specdesc("default", -10)
+
+    def test_unknown(self):
+        # FIXME should fail?
+        with self.assertRaises(ValueError):
+            specdesc("unknown", 512)
+            self.skipTest('todo: new_specdesc should fail on wrong method')
+
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/test_zero_crossing_rate.py
+++ b/python/tests/test_zero_crossing_rate.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
+from unittest import main
 from numpy.testing import TestCase
-
 from aubio import fvec, zero_crossing_rate
 
 buf_size = 2048
@@ -22,26 +22,25 @@
 
     def test_impulse(self):
         """ check zero crossing rate on a buffer with an impulse """
-        self.vector[buf_size / 2] = 1.
+        self.vector[int(buf_size / 2)] = 1.
         self.assertEqual(0., zero_crossing_rate(self.vector))
 
     def test_negative_impulse(self):
         """ check zero crossing rate on a buffer with a negative impulse """
-        self.vector[buf_size / 2] = -1.
+        self.vector[int(buf_size / 2)] = -1.
         self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
 
     def test_single(self):
         """ check zero crossing rate on single crossing """
-        self.vector[buf_size / 2 - 1] = 1.
-        self.vector[buf_size / 2] = -1.
+        self.vector[int(buf_size / 2) - 1] = 1.
+        self.vector[int(buf_size / 2)] = -1.
         self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
 
     def test_single_with_gap(self):
         """ check zero crossing rate on single crossing with a gap"""
-        self.vector[buf_size / 2 - 2] = 1.
-        self.vector[buf_size / 2] = -1.
+        self.vector[int(buf_size / 2) - 2] = 1.
+        self.vector[int(buf_size / 2)] = -1.
         self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
 
 if __name__ == '__main__':
-    from unittest import main
     main()
--- a/python/tests/utils.py
+++ b/python/tests/utils.py
@@ -1,14 +1,18 @@
 #! /usr/bin/env python
 
+import os
+import glob
+import numpy as np
+from tempfile import mkstemp
+
 def array_from_text_file(filename, dtype = 'float'):
-    import os.path
-    from numpy import array
     filename = os.path.join(os.path.dirname(__file__), filename)
-    return array([line.split() for line in open(filename).readlines()],
-        dtype = dtype)
+    with open(filename) as f:
+        lines = f.readlines()
+    return np.array([line.split() for line in lines],
+            dtype = dtype)
 
 def list_all_sounds(rel_dir):
-    import os.path, glob
     datadir = os.path.join(os.path.dirname(__file__), rel_dir)
     return glob.glob(os.path.join(datadir,'*.*'))
 
@@ -20,15 +24,21 @@
         return all_sounds[0]
 
 def get_tmp_sink_path():
-    from tempfile import mkstemp
-    import os
     fd, path = mkstemp()
     os.close(fd)
     return path
 
 def del_tmp_sink_path(path):
-    import os
-    os.unlink(path)
+    try:
+        os.unlink(path)
+    except WindowsError as e:
+        print("deleting {:s} failed ({:s}), reopening".format(path, repr(e)))
+        with open(path, 'wb') as f:
+            f.close()
+        try:
+            os.unlink(path)
+        except WindowsError as f:
+            print("deleting {:s} failed ({:s}), aborting".format(path, repr(e)))
 
 def array_from_yaml_file(filename):
     import yaml
@@ -43,13 +53,12 @@
     s = source(file_path, 0, hopsize)
     total_frames = 0
     while True:
-        samples, read = s()
+        _, read = s()
         total_frames += read
         if read < hopsize: break
     return total_frames
 
 def count_samples_in_directory(samples_dir):
-    import os
     total_frames = 0
     for f in os.walk(samples_dir):
         if len(f[2]):
@@ -60,7 +69,6 @@
     return total_frames
 
 def count_files_in_directory(samples_dir):
-    import os
     total_files = 0
     for f in os.walk(samples_dir):
         if len(f[2]):
--- /dev/null
+++ b/requirements.txt
@@ -1,0 +1,2 @@
+numpy
+nose2
--- /dev/null
+++ b/scripts/apple/Info.plist
@@ -1,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>org.aubio.$(PRODUCT_NAME:rfc1034identifier)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>$(CURRENT_PROJECT_VERSION)</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2015 Paul Brossier. All rights reserved.</string>
+	<key>NSPrincipalClass</key>
+	<string></string>
+</dict>
+</plist>
--- /dev/null
+++ b/scripts/apple/Modules/module.modulemap
@@ -1,0 +1,6 @@
+framework module aubio {
+  umbrella header "aubio.h"
+
+  export *
+  module * { export * }
+}
--- /dev/null
+++ b/scripts/build_apple_frameworks
@@ -1,0 +1,100 @@
+#! /bin/sh
+
+AUBIO_TMPDIR=`mktemp -d /var/tmp/aubio-build-XXXX`
+PACKAGE=aubio
+source VERSION
+VERSION=$AUBIO_MAJOR_VERSION.$AUBIO_MINOR_VERSION.$AUBIO_PATCH_VERSION$AUBIO_VERSION_STATUS
+LIBVERSION=$LIBAUBIO_LT_CUR.$LIBAUBIO_LT_REV.$LIBAUBIO_LT_AGE
+OUTPUTDIR=$PWD/dist
+mkdir -p "$OUTPUTDIR"
+# add git abbreviated commit hash
+#VERSION+=+$(git log --pretty=format:"%h" -1)
+
+CFLAGS="-Werror -Ofast"
+WAFCONF="--disable-sndfile --disable-avcodec --disable-samplerate --enable-fat" # --disable-memcpy --disable-accelerate"
+
+export VERSION
+
+function cleanup () {
+  rm -rf $AUBIO_TMPDIR
+}
+
+trap cleanup SIGINT SIGTERM
+
+function create_tarballs() {
+  # name version platform
+  # create tarball
+  tarfile=$OUTPUTDIR/$1-$2.$3_binary.tar.bz2
+  tar -C $AUBIO_TMPDIR/dist-$3/ -jcf "$tarfile" .
+  #rm -rf $AUBIO_TMPDIR/dist-$3
+}
+
+function create_framework() {
+  rm -rf $AUBIO_TMPDIR/framework-$3
+  mkdir -p $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework
+  cp -pr COPYING README.md $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework
+  pushd $AUBIO_TMPDIR/framework-$3
+  cp -pr "$OLDPWD/build/src/lib$1.a" $1-$2.$3_framework/$1.framework/$1 || \
+    cp -pr $AUBIO_TMPDIR/dist-$3/usr/local/lib/lib$1.$LIBVERSION.dylib \
+    $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework/$1
+  cp -pr $AUBIO_TMPDIR/dist-$3/usr/local/include/$1 $1-$2.$3_framework/$1.framework/Headers
+  cp -pr "$OLDPWD/scripts/apple/Modules" $1-$2.$3_framework/$1.framework/
+  popd
+}
+
+function create_framework_fat() {
+  rm -rf $AUBIO_TMPDIR/framework-$3
+  mkdir -p $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework
+  cp -pr COPYING README.md $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework
+  pushd $AUBIO_TMPDIR/framework-$3
+  cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Headers $1-$2.$3_framework/$1.framework
+  cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Modules $1-$2.$3_framework/$1.framework
+  lipo $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/$1 \
+       $AUBIO_TMPDIR/framework-iosimulator/$1-$2.iosimulator_framework/$1.framework/$1 \
+       -output $1-$2.$3_framework/$1.framework/$1 -create
+  popd
+}
+
+function create_framework_zip() {
+  # create zip
+  pushd $AUBIO_TMPDIR/framework-$3
+  zipfile=$1-$2.$3_framework.zip
+  zip -qr $zipfile $1-$2.$3_framework
+  popd
+  mv $AUBIO_TMPDIR/framework-$3/$zipfile "$OUTPUTDIR"
+}
+
+set -x
+set -e
+
+#./waf dist --verbose
+
+for PLATFORM in darwin ios iosimulator
+do
+  rm -rf $AUBIO_TMPDIR/dist-$PLATFORM
+  WAF_OPTIONS="--verbose --destdir $AUBIO_TMPDIR/dist-$PLATFORM --with-target-platform $PLATFORM $WAFCONF"
+  for target in distclean configure build install
+  do
+    CFLAGS="$CFLAGS" ./waf $target $WAF_OPTIONS
+  done
+
+  create_framework $PACKAGE $VERSION $PLATFORM
+  if [ $PLATFORM == 'darwin' ]
+  then
+    # on darwin, build a .tar.bz2 of /usr and a .zip of aubio.framework
+    create_tarballs $PACKAGE $VERSION $PLATFORM
+    create_framework_zip $PACKAGE $VERSION $PLATFORM
+  fi
+  ./waf uninstall $WAF_OPTIONS
+
+done
+
+# after both ios and iosimulator have been built
+PLATFORM=iosuniversal
+create_framework_fat $PACKAGE $VERSION $PLATFORM
+create_framework_zip $PACKAGE $VERSION $PLATFORM
+
+./waf clean
+./waf distclean
+
+cleanup
--- /dev/null
+++ b/scripts/build_emscripten
@@ -1,0 +1,21 @@
+#! /bin/sh
+
+function checkprog() {
+  type $1 >/dev/null 2>&1 || { echo >&2 "$1 required but not found, aborting."; exit 1; }
+}
+
+checkprog emcc
+checkprog emconfigure
+checkprog emmake
+
+# clean
+emmake ./waf distclean
+
+# configure
+emconfigure ./waf configure --prefix=$EMSCRIPTEN/system/local/ --with-target-platform emscripten
+
+# build
+emmake ./waf --testcmd="node %s"
+
+# intall
+#emmake ./waf install
--- /dev/null
+++ b/scripts/build_mingw
@@ -1,0 +1,28 @@
+#! /bin/bash
+
+# This script cross compiles aubio for windows using mingw, both for 32 and 64
+# bits. Built binaries will be placed in ./dist-win32 and ./dist-win64.
+
+# On debian or ubuntu, you will want to 'apt-get install gcc-mingw-w64'
+
+set -e
+set -x
+
+WAFOPTS="-v --disable-avcodec --disable-samplerate --disable-jack --disable-sndfile"
+
+[ -d dist-win32 ] && rm -rf dist-win32
+[ -d dist-win64 ] && rm -rf dist-win64
+
+CFLAGS="-Os" \
+  LDFLAGS="" \
+  CC=x86_64-w64-mingw32-gcc \
+  ./waf distclean configure build install --destdir=$PWD/dist-win64 \
+    --testcmd="echo %s" \
+    $WAFOPTS --with-target-platform=win64
+
+CFLAGS="-Os" \
+  LDFLAGS="" \
+  CC=i686-w64-mingw32-gcc \
+  ./waf distclean configure build install --destdir=$PWD/dist-win32 \
+    --testcmd="echo %s" \
+    $WAFOPTS --with-target-platform=win32
--- /dev/null
+++ b/scripts/setenv_local.sh
@@ -1,0 +1,32 @@
+#! /usr/bin/env bash
+
+# This script sets the environment to execute aubio binaries and python code
+# directly from build/ python/build/ without installing libaubio on the system
+
+# Usage: $ source ./scripts/setenv_local.sh
+
+# WARNING: this script will *overwrite* existing (DY)LD_LIBRARY_PATH and
+# PYTHONPATH variables.
+
+PYTHON_PLATFORM=`python -c "import pkg_resources, sys; print '%s-%s' % (pkg_resources.get_build_platform(), '.'.join(map(str, sys.version_info[0:2])))"`
+
+AUBIODIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
+AUBIOLIB=$AUBIODIR/build/src
+AUBIOPYTHON=$AUBIODIR/python/build/lib.$PYTHON_PLATFORM
+
+if [ "$(dirname $PWD)" == "scripts" ]; then
+  AUBIODIR=$(basename $PWD)
+else
+  AUBIODIR=$(basename $PWD)
+fi
+
+if [ "$(uname)" == "Darwin" ]; then
+  export DYLD_LIBRARY_PATH=$AUBIOLIB
+  echo export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH
+else
+  export LD_LIBRARY_PATH=$AUBIOLIB
+  echo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+fi
+
+export PYTHONPATH=$AUBIOPYTHON
+echo export PYTHONPATH=$PYTHONPATH
--- /dev/null
+++ b/setup.py
@@ -1,0 +1,111 @@
+#! /usr/bin/env python
+
+import sys, os.path, glob
+from setuptools import setup, Extension
+from python.lib.moresetuptools import *
+# function to generate gen/*.{c,h}
+from python.lib.gen_external import generate_external, header, output_path
+
+# read from VERSION
+for l in open('VERSION').readlines(): exec (l.strip())
+
+if AUBIO_MAJOR_VERSION is None or AUBIO_MINOR_VERSION is None \
+        or AUBIO_PATCH_VERSION is None:
+    raise SystemError("Failed parsing VERSION file.")
+
+__version__ = '.'.join(map(str, [AUBIO_MAJOR_VERSION,
+                                 AUBIO_MINOR_VERSION,
+                                 AUBIO_PATCH_VERSION]))
+if AUBIO_VERSION_STATUS is not None:
+    if AUBIO_VERSION_STATUS.startswith('~'):
+        AUBIO_VERSION_STATUS = AUBIO_VERSION_STATUS[1:]
+    __version__ += AUBIO_VERSION_STATUS
+
+include_dirs = []
+library_dirs = []
+define_macros = []
+extra_link_args = []
+
+include_dirs += [ 'python/ext' ]
+include_dirs += [ output_path ] # aubio-generated.h
+try:
+    import numpy
+    include_dirs += [ numpy.get_include() ]
+except ImportError:
+    pass
+
+if sys.platform.startswith('darwin'):
+    extra_link_args += ['-framework','CoreFoundation', '-framework','AudioToolbox']
+
+sources = glob.glob(os.path.join('python', 'ext', '*.c'))
+
+aubio_extension = Extension("aubio._aubio",
+    sources,
+    include_dirs = include_dirs,
+    library_dirs = library_dirs,
+    extra_link_args = extra_link_args,
+    define_macros = define_macros)
+
+if os.path.isfile('src/aubio.h'):
+    # if aubio headers are found in this directory
+    add_local_aubio_header(aubio_extension)
+    # was waf used to build the shared lib?
+    if os.path.isdir(os.path.join('build','src')):
+        # link against build/src/libaubio, built with waf
+        add_local_aubio_lib(aubio_extension)
+    else:
+        # add libaubio sources and look for optional deps with pkg-config
+        add_local_aubio_sources(aubio_extension)
+        __version__ += '_libaubio'
+else:
+    # look for aubio headers and lib using pkg-config
+    add_system_aubio(aubio_extension)
+
+
+classifiers = [
+    'Development Status :: 4 - Beta',
+    'Environment :: Console',
+    'Intended Audience :: Science/Research',
+    'Topic :: Software Development :: Libraries',
+    'Topic :: Multimedia :: Sound/Audio :: Analysis',
+    'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis',
+    'Operating System :: POSIX',
+    'Operating System :: MacOS :: MacOS X',
+    'Operating System :: Microsoft :: Windows',
+    'Programming Language :: C',
+    'Programming Language :: Python',
+    'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+    ]
+
+from distutils.command.build_ext import build_ext as _build_ext
+class build_ext(_build_ext):
+
+    def build_extension(self, extension):
+        # generate files python/gen/*.c, python/gen/aubio-generated.h
+        extension.sources += generate_external(header, output_path, overwrite = False)
+        return _build_ext.build_extension(self, extension)
+
+distrib = setup(name='aubio',
+    version = __version__,
+    packages = ['aubio'],
+    package_dir = {'aubio':'python/lib/aubio'},
+    scripts = ['python/scripts/aubiocut'],
+    ext_modules = [aubio_extension],
+    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/',
+    platforms = 'any',
+    classifiers = classifiers,
+    install_requires = ['numpy'],
+    cmdclass = {
+        'clean': CleanGenerated,
+        'generate': GenerateCommand,
+        'build_ext': build_ext,
+        },
+    test_suite = 'nose2.collector.collector',
+    )
--- a/src/aubio_priv.h
+++ b/src/aubio_priv.h
@@ -24,8 +24,8 @@
  * This file is for inclusion from _within_ the library only.
  */
 
-#ifndef _AUBIO__PRIV_H
-#define _AUBIO__PRIV_H
+#ifndef AUBIO_PRIV_H
+#define AUBIO_PRIV_H
 
 /*********************
  *
@@ -35,11 +35,11 @@
 
 #include "config.h"
 
-#if HAVE_STDLIB_H
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
 
-#if HAVE_STDIO_H
+#ifdef HAVE_STDIO_H
 #include <stdio.h>
 #endif
 
@@ -64,6 +64,63 @@
 #include <limits.h> // for CHAR_BIT, in C99 standard
 #endif
 
+#ifdef HAVE_ACCELERATE
+#define HAVE_ATLAS 1
+#include <Accelerate/Accelerate.h>
+#elif defined(HAVE_ATLAS_CBLAS_H)
+#define HAVE_ATLAS 1
+#include <atlas/cblas.h>
+#else
+#undef HAVE_ATLAS
+#endif
+
+#ifdef HAVE_ACCELERATE
+#include <Accelerate/Accelerate.h>
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_vDSP_mmov       vDSP_mmov
+#define aubio_vDSP_vmul       vDSP_vmul
+#define aubio_vDSP_vfill      vDSP_vfill
+#define aubio_vDSP_meanv      vDSP_meanv
+#define aubio_vDSP_sve        vDSP_sve
+#define aubio_vDSP_maxv       vDSP_maxv
+#define aubio_vDSP_maxvi      vDSP_maxvi
+#define aubio_vDSP_minv       vDSP_minv
+#define aubio_vDSP_minvi      vDSP_minvi
+#define aubio_vDSP_dotpr      vDSP_dotpr
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_vDSP_mmov       vDSP_mmovD
+#define aubio_vDSP_vmul       vDSP_vmulD
+#define aubio_vDSP_vfill      vDSP_vfillD
+#define aubio_vDSP_meanv      vDSP_meanvD
+#define aubio_vDSP_sve        vDSP_sveD
+#define aubio_vDSP_maxv       vDSP_maxvD
+#define aubio_vDSP_maxvi      vDSP_maxviD
+#define aubio_vDSP_minv       vDSP_minvD
+#define aubio_vDSP_minvi      vDSP_minviD
+#define aubio_vDSP_dotpr      vDSP_dotprD
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_ACCELERATE */
+
+#ifdef HAVE_ATLAS
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_catlas_set      catlas_sset
+#define aubio_cblas_copy      cblas_scopy
+#define aubio_cblas_swap      cblas_sswap
+#define aubio_cblas_dot       cblas_sdot
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_catlas_set      catlas_dset
+#define aubio_cblas_copy      cblas_dcopy
+#define aubio_cblas_swap      cblas_dswap
+#define aubio_cblas_dot       cblas_ddot
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_ATLAS */
+
+#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+#define HAVE_NOOPT 1
+#else
+#undef HAVE_NOOPT
+#endif
+
 #include "types.h"
 
 #define AUBIO_UNSTABLE 1
@@ -136,6 +193,10 @@
 #endif
 #define TWO_PI     (PI*2.)
 
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
 /* aliases to math.h functions */
 #if !HAVE_AUBIO_DOUBLE
 #define EXP        expf
@@ -193,6 +254,11 @@
 #define IMAG      cimagf
 #endif
 
+/* avoid unresolved symbol with msvc 9 */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define isnan _isnan
+#endif
+
 /* handy shortcuts */
 #define DB2LIN(g) (POW(10.0,(g)*0.05f))
 #define LIN2DB(v) (20.0*LOG10(v))
@@ -228,4 +294,12 @@
 #define UNUSED
 #endif
 
-#endif /* _AUBIO__PRIV_H */
+/* are we using gcc -std=c99 ? */
+#if defined(__STRICT_ANSI__)
+#define strnlen(a,b) MIN(strlen(a),b)
+#if !HAVE_AUBIO_DOUBLE
+#define floorf floor
+#endif
+#endif /* __STRICT_ANSI__ */
+
+#endif /* AUBIO_PRIV_H */
--- a/src/cvec.c
+++ b/src/cvec.c
@@ -21,7 +21,7 @@
 #include "aubio_priv.h"
 #include "cvec.h"
 
-cvec_t * new_cvec( uint_t length) {
+cvec_t * new_cvec(uint_t length) {
   cvec_t * s;
   if ((sint_t)length <= 0) {
     return NULL;
@@ -55,17 +55,17 @@
   return s->phas[position];
 }
 
-smpl_t * cvec_norm_get_data (cvec_t *s) {
+smpl_t * cvec_norm_get_data (const cvec_t *s) {
   return s->norm;
 }
 
-smpl_t * cvec_phas_get_data (cvec_t *s) {
+smpl_t * cvec_phas_get_data (const cvec_t *s) {
   return s->phas;
 }
 
 /* helper functions */
 
-void cvec_print(cvec_t *s) {
+void cvec_print(const cvec_t *s) {
   uint_t j;
   AUBIO_MSG("norm: ");
   for (j=0; j< s->length; j++) {
@@ -79,22 +79,22 @@
   AUBIO_MSG("\n");
 }
 
-void cvec_copy(cvec_t *s, cvec_t *t) {
+void cvec_copy(const cvec_t *s, cvec_t *t) {
   if (s->length != t->length) {
     AUBIO_ERR("trying to copy %d elements to %d elements \n",
         s->length, t->length);
     return;
   }
-#if HAVE_MEMCPY_HACKS
+#ifdef HAVE_MEMCPY_HACKS
   memcpy(t->norm, s->norm, t->length * sizeof(smpl_t));
   memcpy(t->phas, s->phas, t->length * sizeof(smpl_t));
-#else
+#else /* HAVE_MEMCPY_HACKS */
   uint_t j;
   for (j=0; j< t->length; j++) {
     t->norm[j] = s->norm[j];
     t->phas[j] = s->phas[j];
   }
-#endif
+#endif /* HAVE_MEMCPY_HACKS */
 }
 
 void cvec_norm_set_all (cvec_t *s, smpl_t val) {
@@ -105,11 +105,11 @@
 }
 
 void cvec_norm_zeros(cvec_t *s) {
-#if HAVE_MEMCPY_HACKS
+#ifdef HAVE_MEMCPY_HACKS
   memset(s->norm, 0, s->length * sizeof(smpl_t));
-#else
+#else /* HAVE_MEMCPY_HACKS */
   cvec_norm_set_all (s, 0.);
-#endif
+#endif /* HAVE_MEMCPY_HACKS */
 }
 
 void cvec_norm_ones(cvec_t *s) {
@@ -124,7 +124,7 @@
 }
 
 void cvec_phas_zeros(cvec_t *s) {
-#if HAVE_MEMCPY_HACKS
+#ifdef HAVE_MEMCPY_HACKS
   memset(s->phas, 0, s->length * sizeof(smpl_t));
 #else
   cvec_phas_set_all (s, 0.);
--- a/src/cvec.h
+++ b/src/cvec.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO__CVEC_H
-#define _AUBIO__CVEC_H
+#ifndef AUBIO_CVEC_H
+#define AUBIO_CVEC_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -150,7 +150,7 @@
   \param s vector to read from
 
 */
-smpl_t * cvec_norm_get_data (cvec_t *s);
+smpl_t * cvec_norm_get_data (const cvec_t *s);
 
 /** read phase data from a complex buffer
 
@@ -162,7 +162,7 @@
   \param s vector to read from
 
 */
-smpl_t * cvec_phas_get_data (cvec_t *s);
+smpl_t * cvec_phas_get_data (const cvec_t *s);
 
 /** print out cvec data
 
@@ -169,7 +169,7 @@
   \param s vector to print out
 
 */
-void cvec_print(cvec_t *s);
+void cvec_print(const cvec_t *s);
 
 /** make a copy of a vector
 
@@ -177,7 +177,7 @@
   \param t vector to copy to
 
 */
-void cvec_copy(cvec_t *s, cvec_t *t);
+void cvec_copy(const cvec_t *s, cvec_t *t);
 
 /** set all norm elements to a given value
 
@@ -234,4 +234,4 @@
 }
 #endif
 
-#endif /* _AUBIO__CVEC_H */
+#endif /* AUBIO_CVEC_H */
--- a/src/fmat.c
+++ b/src/fmat.c
@@ -53,27 +53,27 @@
   s->data[channel][position] = data;
 }
 
-smpl_t fmat_get_sample(fmat_t *s, uint_t channel, uint_t position) {
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position) {
   return s->data[channel][position];
 }
 
-void fmat_get_channel(fmat_t *s, uint_t channel, fvec_t *output) {
+void fmat_get_channel(const fmat_t *s, uint_t channel, fvec_t *output) {
   output->data = s->data[channel];
   output->length = s->length;
   return;
 }
 
-smpl_t * fmat_get_channel_data(fmat_t *s, uint_t channel) {
+smpl_t * fmat_get_channel_data(const fmat_t *s, uint_t channel) {
   return s->data[channel];
 }
 
-smpl_t ** fmat_get_data(fmat_t *s) {
+smpl_t ** fmat_get_data(const fmat_t *s) {
   return s->data;
 }
 
 /* helper functions */
 
-void fmat_print(fmat_t *s) {
+void fmat_print(const fmat_t *s) {
   uint_t i,j;
   for (i=0; i< s->height; i++) {
     for (j=0; j< s->length; j++) {
@@ -93,14 +93,14 @@
 }
 
 void fmat_zeros(fmat_t *s) {
-#if HAVE_MEMCPY_HACKS
+#ifdef HAVE_MEMCPY_HACKS
   uint_t i;
   for (i=0; i< s->height; i++) {
     memset(s->data[i], 0, s->length * sizeof(smpl_t));
   }
-#else
+#else /* HAVE_MEMCPY_HACKS */
   fmat_set(s, 0.);
-#endif
+#endif /* HAVE_MEMCPY_HACKS */
 }
 
 void fmat_ones(fmat_t *s) {
@@ -116,7 +116,7 @@
   }
 }
 
-void fmat_weight(fmat_t *s, fmat_t *weight) {
+void fmat_weight(fmat_t *s, const fmat_t *weight) {
   uint_t i,j;
   uint_t length = MIN(s->length, weight->length);
   for (i=0; i< s->height; i++) {
@@ -126,11 +126,11 @@
   }
 }
 
-void fmat_copy(fmat_t *s, fmat_t *t) {
+void fmat_copy(const fmat_t *s, fmat_t *t) {
   uint_t i;
-#if !HAVE_MEMCPY_HACKS
+#ifndef HAVE_MEMCPY_HACKS
   uint_t j;
-#endif
+#endif /* HAVE_MEMCPY_HACKS */
   if (s->height != t->height) {
     AUBIO_ERR("trying to copy %d rows to %d rows \n",
             s->height, t->height);
@@ -141,16 +141,46 @@
             s->length, t->length);
     return;
   }
-#if HAVE_MEMCPY_HACKS
+#ifdef HAVE_MEMCPY_HACKS
   for (i=0; i< s->height; i++) {
     memcpy(t->data[i], s->data[i], t->length * sizeof(smpl_t));
   }
-#else
+#else /* HAVE_MEMCPY_HACKS */
   for (i=0; i< t->height; i++) {
     for (j=0; j< t->length; j++) {
       t->data[i][j] = s->data[i][j];
     }
   }
-#endif
+#endif /* HAVE_MEMCPY_HACKS */
 }
 
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output) {
+  uint_t k;
+#if 0
+  assert(s->height == output->length);
+  assert(s->length == scale->length);
+#endif
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+  uint_t j;
+  fvec_zeros(output);
+  for (j = 0; j < s->length; j++) {
+    for (k = 0; k < s->height; k++) {
+      output->data[k] += scale->data[j]
+          * s->data[k][j];
+    }
+  }
+#elif defined(HAVE_ATLAS)
+  for (k = 0; k < s->height; k++) {
+    output->data[k] = aubio_cblas_dot( s->length, scale->data, 1, s->data[k], 1);
+  }
+#elif defined(HAVE_ACCELERATE)
+#if 0
+  // seems slower and less precise (and dangerous?)
+  vDSP_mmul (s->data[0], 1, scale->data, 1, output->data, 1, s->height, 1, s->length);
+#else
+  for (k = 0; k < s->height; k++) {
+    aubio_vDSP_dotpr( scale->data, 1, s->data[k], 1, &(output->data[k]), s->length);
+  }
+#endif
+#endif
+}
--- a/src/fmat.h
+++ b/src/fmat.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO__FMAT_H
-#define _AUBIO__FMAT_H
+#ifndef AUBIO_FMAT_H
+#define AUBIO_FMAT_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -65,7 +65,7 @@
   \param position sample position to read from
 
 */
-smpl_t fmat_get_sample(fmat_t *s, uint_t channel, uint_t position);
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position);
 
 /** write sample value in a buffer
 
@@ -84,7 +84,7 @@
   \param output ::fvec_t to output to
 
 */
-void fmat_get_channel (fmat_t *s, uint_t channel, fvec_t *output);
+void fmat_get_channel (const fmat_t *s, uint_t channel, fvec_t *output);
 
 /** get vector buffer from an fmat data
 
@@ -92,7 +92,7 @@
   \param channel channel to read from
 
 */
-smpl_t * fmat_get_channel_data (fmat_t *s, uint_t channel);
+smpl_t * fmat_get_channel_data (const fmat_t *s, uint_t channel);
 
 /** read data from a buffer
 
@@ -99,7 +99,7 @@
   \param s vector to read from
 
 */
-smpl_t ** fmat_get_data(fmat_t *s);
+smpl_t ** fmat_get_data(const fmat_t *s);
 
 /** print out fmat data
 
@@ -106,7 +106,7 @@
   \param s vector to print out
 
 */
-void fmat_print(fmat_t *s);
+void fmat_print(const fmat_t *s);
 
 /** set all elements to a given value
 
@@ -146,7 +146,7 @@
   \param weight weighting coefficients
 
 */
-void fmat_weight(fmat_t *s, fmat_t *weight);
+void fmat_weight(fmat_t *s, const fmat_t *weight);
 
 /** make a copy of a matrix
 
@@ -154,10 +154,19 @@
   \param t vector to copy to
 
 */
-void fmat_copy(fmat_t *s, fmat_t *t);
+void fmat_copy(const fmat_t *s, fmat_t *t);
 
+/* compute the product of a matrix by a vector
+
+   \param s matrix to compute product with
+   \param scale vector to compute product with
+   \param output vector to store restults in
+
+*/
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output);
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO__FMAT_H */
+#endif /* AUBIO_FMAT_H */
--- a/src/fvec.c
+++ b/src/fvec.c
@@ -21,20 +21,7 @@
 #include "aubio_priv.h"
 #include "fvec.h"
 
-#ifdef HAVE_ACCELERATE
-#include <Accelerate/Accelerate.h>
-#if !HAVE_AUBIO_DOUBLE
-#define aubio_vDSP_mmov       vDSP_mmov
-#define aubio_vDSP_vmul       vDSP_vmul
-#define aubio_vDSP_vfill      vDSP_vfill
-#else /* HAVE_AUBIO_DOUBLE */
-#define aubio_vDSP_mmov       vDSP_mmovD
-#define aubio_vDSP_vmul       vDSP_vmulD
-#define aubio_vDSP_vfill      vDSP_vfillD
-#endif /* HAVE_AUBIO_DOUBLE */
-#endif
-
-fvec_t * new_fvec( uint_t length) {
+fvec_t * new_fvec(uint_t length) {
   fvec_t * s;
   if ((sint_t)length <= 0) {
     return NULL;
@@ -54,17 +41,17 @@
   s->data[position] = data;
 }
 
-smpl_t fvec_get_sample(fvec_t *s, uint_t position) {
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position) {
   return s->data[position];
 }
 
-smpl_t * fvec_get_data(fvec_t *s) {
+smpl_t * fvec_get_data(const fvec_t *s) {
   return s->data;
 }
 
 /* helper functions */
 
-void fvec_print(fvec_t *s) {
+void fvec_print(const fvec_t *s) {
   uint_t j;
   for (j=0; j< s->length; j++) {
     AUBIO_MSG(AUBIO_SMPL_FMT " ", s->data[j]);
@@ -73,12 +60,14 @@
 }
 
 void fvec_set_all (fvec_t *s, smpl_t val) {
-#ifndef HAVE_ACCELERATE
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
   uint_t j;
   for (j=0; j< s->length; j++) {
     s->data[j] = val;
   }
-#else
+#elif defined(HAVE_ATLAS)
+  aubio_catlas_set(s->length, val, s->data, 1);
+#elif defined(HAVE_ACCELERATE)
   aubio_vDSP_vfill(&val, s->data, 1, s->length);
 #endif
 }
@@ -106,7 +95,7 @@
   }
 }
 
-void fvec_weight(fvec_t *s, fvec_t *weight) {
+void fvec_weight(fvec_t *s, const fvec_t *weight) {
 #ifndef HAVE_ACCELERATE
   uint_t j;
   uint_t length = MIN(s->length, weight->length);
@@ -118,22 +107,34 @@
 #endif /* HAVE_ACCELERATE */
 }
 
-void fvec_copy(fvec_t *s, fvec_t *t) {
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out) {
+#ifndef HAVE_ACCELERATE
+  uint_t j;
+  uint_t length = MIN(out->length, weight->length);
+  for (j=0; j< length; j++) {
+    out->data[j] = in->data[j] * weight->data[j];
+  }
+#else
+  aubio_vDSP_vmul(in->data, 1, weight->data, 1, out->data, 1, out->length);
+#endif /* HAVE_ACCELERATE */
+}
+
+void fvec_copy(const fvec_t *s, fvec_t *t) {
   if (s->length != t->length) {
     AUBIO_ERR("trying to copy %d elements to %d elements \n",
         s->length, t->length);
     return;
   }
-#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE)
+#ifdef HAVE_NOOPT
   uint_t j;
   for (j=0; j< t->length; j++) {
     t->data[j] = s->data[j];
   }
-#else
-#if defined(HAVE_MEMCPY_HACKS)
+#elif defined(HAVE_MEMCPY_HACKS)
   memcpy(t->data, s->data, t->length * sizeof(smpl_t));
-#else
+#elif defined(HAVE_ATLAS)
+  aubio_cblas_copy(s->length, s->data, 1, t->data, 1);
+#elif defined(HAVE_ACCELERATE)
   aubio_vDSP_mmov(s->data, t->data, 1, s->length, 1, 1);
-#endif
 #endif
 }
--- a/src/fvec.h
+++ b/src/fvec.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO__FVEC_H
-#define _AUBIO__FVEC_H
+#ifndef AUBIO_FVEC_H
+#define AUBIO_FVEC_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -89,7 +89,7 @@
   \param position sample position to read from
 
 */
-smpl_t fvec_get_sample(fvec_t *s, uint_t position);
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position);
 
 /** write sample value in a buffer
 
@@ -105,7 +105,7 @@
   \param s vector to read from
 
 */
-smpl_t * fvec_get_data(fvec_t *s);
+smpl_t * fvec_get_data(const fvec_t *s);
 
 /** print out fvec data
 
@@ -112,7 +112,7 @@
   \param s vector to print out
 
 */
-void fvec_print(fvec_t *s);
+void fvec_print(const fvec_t *s);
 
 /** set all elements to a given value
 
@@ -152,7 +152,7 @@
   \param weight weighting coefficients
 
 */
-void fvec_weight(fvec_t *s, fvec_t *weight);
+void fvec_weight(fvec_t *s, const fvec_t *weight);
 
 /** make a copy of a vector
 
@@ -160,10 +160,19 @@
   \param t vector to copy to
 
 */
-void fvec_copy(fvec_t *s, fvec_t *t);
+void fvec_copy(const fvec_t *s, fvec_t *t);
 
+/** make a copy of a vector, applying weights to each element
+
+  \param in input vector
+  \param weight weights vector
+  \param out output vector
+
+*/
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out);
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO__FVEC_H */
+#endif /* AUBIO_FVEC_H */
--- a/src/io/audio_unit.h
+++ b/src/io/audio_unit.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_AUDIO_UNIT_H
-#define _AUBIO_AUDIO_UNIT_H
+#ifndef AUBIO_AUDIO_UNIT_H
+#define AUBIO_AUDIO_UNIT_H
 
 /** \file
 
@@ -58,4 +58,4 @@
 }
 #endif
 
-#endif /* _AUBIO_AUDIO_UNIT_H */
+#endif /* AUBIO_AUDIO_UNIT_H */
--- a/src/io/sink.c
+++ b/src/io/sink.c
@@ -54,7 +54,7 @@
   del_aubio_sink_t s_del;
 };
 
-aubio_sink_t * new_aubio_sink(char_t * uri, uint_t samplerate) {
+aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate) {
   aubio_sink_t * s = AUBIO_NEW(aubio_sink_t);
 #ifdef HAVE_SINK_APPLE_AUDIO
   s->sink = (void *)new_aubio_sink_apple_audio(uri, samplerate);
@@ -70,7 +70,7 @@
     return s;
   }
 #endif /* HAVE_SINK_APPLE_AUDIO */
-#if HAVE_SNDFILE
+#ifdef HAVE_SNDFILE
   s->sink = (void *)new_aubio_sink_sndfile(uri, samplerate);
   if (s->sink) {
     s->s_do = (aubio_sink_do_t)(aubio_sink_sndfile_do);
@@ -84,7 +84,7 @@
     return s;
   }
 #endif /* HAVE_SNDFILE */
-#if HAVE_WAVWRITE
+#ifdef HAVE_WAVWRITE
   s->sink = (void *)new_aubio_sink_wavwrite(uri, samplerate);
   if (s->sink) {
     s->s_do = (aubio_sink_do_t)(aubio_sink_wavwrite_do);
@@ -120,11 +120,11 @@
   return s->s_preset_channels((void *)s->sink, channels);
 }
 
-uint_t aubio_sink_get_samplerate(aubio_sink_t * s) {
+uint_t aubio_sink_get_samplerate(const aubio_sink_t * s) {
   return s->s_get_samplerate((void *)s->sink);
 }
 
-uint_t aubio_sink_get_channels(aubio_sink_t * s) {
+uint_t aubio_sink_get_channels(const aubio_sink_t * s) {
   return s->s_get_channels((void *)s->sink);
 }
 
--- a/src/io/sink.h
+++ b/src/io/sink.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SINK_H
-#define _AUBIO_SINK_H
+#ifndef AUBIO_SINK_H
+#define AUBIO_SINK_H
 
 /** \file
 
@@ -76,7 +76,7 @@
   been called.
 
 */
-aubio_sink_t * new_aubio_sink(char_t * uri, uint_t samplerate);
+aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate);
 
 /**
 
@@ -120,7 +120,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_sink_get_samplerate(aubio_sink_t *s);
+uint_t aubio_sink_get_samplerate(const aubio_sink_t *s);
 
 /**
 
@@ -130,7 +130,7 @@
   \return number of channels
 
 */
-uint_t aubio_sink_get_channels(aubio_sink_t *s);
+uint_t aubio_sink_get_channels(const aubio_sink_t *s);
 
 /**
 
@@ -178,4 +178,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SINK_H */
+#endif /* AUBIO_SINK_H */
--- a/src/io/sink_apple_audio.c
+++ b/src/io/sink_apple_audio.c
@@ -36,7 +36,7 @@
 
 extern int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize);
 extern void freeAudioBufferList(AudioBufferList *bufferList);
-extern CFURLRef getURLFromPath(const char * path);
+extern CFURLRef createURLFromPath(const char * path);
 char_t *getPrintableOSStatusError(char_t *str, OSStatus error);
 
 uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s);
@@ -43,6 +43,8 @@
 
 #define MAX_SIZE 4096 // the maximum number of frames that can be written at a time
 
+void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write);
+
 struct _aubio_sink_apple_audio_t {
   uint_t samplerate;
   uint_t channels;
@@ -55,16 +57,18 @@
   bool async;
 };
 
-aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(char_t * uri, uint_t samplerate) {
+aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate) {
   aubio_sink_apple_audio_t * s = AUBIO_NEW(aubio_sink_apple_audio_t);
-  s->path = uri;
   s->max_frames = MAX_SIZE;
-  s->async = true;
+  s->async = false;
 
   if (uri == NULL) {
     AUBIO_ERROR("sink_apple_audio: Aborted opening null path\n");
     goto beach;
   }
+  if (s->path != NULL) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX) + 1);
+  strncpy(s->path, uri, strnlen(uri, PATH_MAX) + 1);
 
   s->samplerate = 0;
   s->channels = 0;
@@ -110,12 +114,12 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_sink_apple_audio_get_samplerate(aubio_sink_apple_audio_t *s)
+uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s)
 {
   return s->samplerate;
 }
 
-uint_t aubio_sink_apple_audio_get_channels(aubio_sink_apple_audio_t *s)
+uint_t aubio_sink_apple_audio_get_channels(const aubio_sink_apple_audio_t *s)
 {
   return s->channels;
 }
@@ -137,11 +141,12 @@
   clientFormat.mReserved         = 0;
 
   AudioFileTypeID fileType = kAudioFileWAVEType;
-  CFURLRef fileURL = getURLFromPath(s->path);
+  CFURLRef fileURL = createURLFromPath(s->path);
   bool overwrite = true;
   OSStatus err = noErr;
   err = ExtAudioFileCreateWithURL(fileURL, fileType, &clientFormat, NULL,
      overwrite ? kAudioFileFlags_EraseFile : 0, &s->audioFile);
+  CFRelease(fileURL);
   if (err) {
     char_t errorstr[20];
     AUBIO_ERR("sink_apple_audio: error when trying to create %s with "
@@ -161,7 +166,6 @@
 }
 
 void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data, uint_t write) {
-  OSStatus err = noErr;
   UInt32 c, v;
   short *data = (short*)s->bufferList.mBuffers[0].mData;
   if (write > s->max_frames) {
@@ -178,34 +182,10 @@
           }
       }
   }
-  if (s->async) {
-    err = ExtAudioFileWriteAsync(s->audioFile, write, &s->bufferList);
-
-    if (err) {
-      char_t errorstr[20];
-      AUBIO_ERROR("sink_apple_audio: error while writing %s "
-          "in ExtAudioFileWriteAsync (%s), switching to sync\n", s->path,
-          getPrintableOSStatusError(errorstr, err));
-      s->async = false;
-    } else {
-      return;
-    }
-
-  } else {
-    err = ExtAudioFileWrite(s->audioFile, write, &s->bufferList);
-
-    if (err) {
-      char_t errorstr[20];
-      AUBIO_ERROR("sink_apple_audio: error while writing %s "
-          "in ExtAudioFileWrite (%s)\n", s->path,
-          getPrintableOSStatusError(errorstr, err));
-    }
-  }
-  return;
+  aubio_sink_apple_audio_write(s, write);
 }
 
 void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * write_data, uint_t write) {
-  OSStatus err = noErr;
   UInt32 c, v;
   short *data = (short*)s->bufferList.mBuffers[0].mData;
   if (write > s->max_frames) {
@@ -222,22 +202,28 @@
           }
       }
   }
+  aubio_sink_apple_audio_write(s, write);
+}
+
+void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write) {
+  OSStatus err = noErr;
   if (s->async) {
     err = ExtAudioFileWriteAsync(s->audioFile, write, &s->bufferList);
-
     if (err) {
       char_t errorstr[20];
+      if (err == kExtAudioFileError_AsyncWriteBufferOverflow) {
+        sprintf(errorstr,"buffer overflow");
+      } else if (err == kExtAudioFileError_AsyncWriteTooLarge) {
+        sprintf(errorstr,"write too large");
+      } else {
+        // unknown error
+        getPrintableOSStatusError(errorstr, err);
+      }
       AUBIO_ERROR("sink_apple_audio: error while writing %s "
-          "in ExtAudioFileWriteAsync (%s), switching to sync\n", s->path,
-          getPrintableOSStatusError(errorstr, err));
-      s->async = false;
-    } else {
-      return;
+                  "in ExtAudioFileWriteAsync (%s)\n", s->path, errorstr);
     }
-
   } else {
     err = ExtAudioFileWrite(s->audioFile, write, &s->bufferList);
-
     if (err) {
       char_t errorstr[20];
       AUBIO_ERROR("sink_apple_audio: error while writing %s "
@@ -245,7 +231,6 @@
           getPrintableOSStatusError(errorstr, err));
     }
   }
-  return;
 }
 
 uint_t aubio_sink_apple_audio_close(aubio_sink_apple_audio_t * s) {
@@ -266,6 +251,7 @@
 
 void del_aubio_sink_apple_audio(aubio_sink_apple_audio_t * s) {
   if (s->audioFile) aubio_sink_apple_audio_close (s);
+  if (s->path) AUBIO_FREE(s->path);
   freeAudioBufferList(&s->bufferList);
   AUBIO_FREE(s);
   return;
--- a/src/io/sink_apple_audio.h
+++ b/src/io/sink_apple_audio.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SINK_APPLE_AUDIO_H
-#define _AUBIO_SINK_APPLE_AUDIO_H
+#ifndef AUBIO_SINK_APPLE_AUDIO_H
+#define AUBIO_SINK_APPLE_AUDIO_H
 
 /** \file
 
@@ -58,7 +58,7 @@
   been called.
 
 */
-aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(char_t * uri, uint_t samplerate);
+aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate);
 
 /**
 
@@ -102,7 +102,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_sink_apple_audio_get_samplerate(aubio_sink_apple_audio_t *s);
+uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s);
 
 /**
 
@@ -112,7 +112,7 @@
   \return number of channels
 
 */
-uint_t aubio_sink_apple_audio_get_channels(aubio_sink_apple_audio_t *s);
+uint_t aubio_sink_apple_audio_get_channels(const aubio_sink_apple_audio_t *s);
 
 /**
 
@@ -160,4 +160,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SINK_APPLE_AUDIO_H */
+#endif /* AUBIO_SINK_APPLE_AUDIO_H */
--- a/src/io/sink_sndfile.c
+++ b/src/io/sink_sndfile.c
@@ -53,10 +53,9 @@
 
 uint_t aubio_sink_sndfile_open(aubio_sink_sndfile_t *s);
 
-aubio_sink_sndfile_t * new_aubio_sink_sndfile(char_t * path, uint_t samplerate) {
+aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * path, uint_t samplerate) {
   aubio_sink_sndfile_t * s = AUBIO_NEW(aubio_sink_sndfile_t);
   s->max_size = MAX_SIZE;
-  s->path = path;
 
   if (path == NULL) {
     AUBIO_ERR("sink_sndfile: Aborted opening null path\n");
@@ -63,6 +62,10 @@
     return NULL;
   }
 
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   s->samplerate = 0;
   s->channels = 0;
 
@@ -106,12 +109,12 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_sink_sndfile_get_samplerate(aubio_sink_sndfile_t *s)
+uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s)
 {
   return s->samplerate;
 }
 
-uint_t aubio_sink_sndfile_get_channels(aubio_sink_sndfile_t *s)
+uint_t aubio_sink_sndfile_get_channels(const aubio_sink_sndfile_t *s)
 {
   return s->channels;
 }
@@ -219,6 +222,7 @@
 
 void del_aubio_sink_sndfile(aubio_sink_sndfile_t * s){
   if (!s) return;
+  if (s->path) AUBIO_FREE(s->path);
   aubio_sink_sndfile_close(s);
   AUBIO_FREE(s->scratch_data);
   AUBIO_FREE(s);
--- a/src/io/sink_sndfile.h
+++ b/src/io/sink_sndfile.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SINK_SNDFILE_H
-#define _AUBIO_SINK_SNDFILE_H
+#ifndef AUBIO_SINK_SNDFILE_H
+#define AUBIO_SINK_SNDFILE_H
 
 /** \file
 
@@ -57,7 +57,7 @@
   been called.
 
 */
-aubio_sink_sndfile_t * new_aubio_sink_sndfile(char_t * uri, uint_t samplerate);
+aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * uri, uint_t samplerate);
 
 /**
 
@@ -101,7 +101,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_sink_sndfile_get_samplerate(aubio_sink_sndfile_t *s);
+uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s);
 
 /**
 
@@ -111,7 +111,7 @@
   \return number of channels
 
 */
-uint_t aubio_sink_sndfile_get_channels(aubio_sink_sndfile_t *s);
+uint_t aubio_sink_sndfile_get_channels(const aubio_sink_sndfile_t *s);
 
 /**
 
@@ -159,4 +159,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SINK_SNDFILE_H */
+#endif /* AUBIO_SINK_SNDFILE_H */
--- a/src/io/sink_wavwrite.c
+++ b/src/io/sink_wavwrite.c
@@ -77,7 +77,7 @@
   return str;
 }
 
-aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * path, uint_t samplerate) {
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * path, uint_t samplerate) {
   aubio_sink_wavwrite_t * s = AUBIO_NEW(aubio_sink_wavwrite_t);
 
   if (path == NULL) {
@@ -89,7 +89,10 @@
     goto beach;
   }
 
-  s->path = path;
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   s->max_size = MAX_SIZE;
   s->bitspersample = 16;
   s->total_frames_written = 0;
@@ -142,12 +145,12 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_sink_wavwrite_get_samplerate(aubio_sink_wavwrite_t *s)
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s)
 {
   return s->samplerate;
 }
 
-uint_t aubio_sink_wavwrite_get_channels(aubio_sink_wavwrite_t *s)
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s)
 {
   return s->channels;
 }
@@ -287,6 +290,7 @@
 void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s){
   if (!s) return;
   aubio_sink_wavwrite_close(s);
+  if (s->path) AUBIO_FREE(s->path);
   AUBIO_FREE(s->scratch_data);
   AUBIO_FREE(s);
 }
--- a/src/io/sink_wavwrite.h
+++ b/src/io/sink_wavwrite.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SINK_WAVWRITE_H
-#define _AUBIO_SINK_WAVWRITE_H
+#ifndef AUBIO_SINK_WAVWRITE_H
+#define AUBIO_SINK_WAVWRITE_H
 
 /** \file
 
@@ -57,7 +57,7 @@
   been called.
 
 */
-aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * uri, uint_t samplerate);
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * uri, uint_t samplerate);
 
 /**
 
@@ -101,7 +101,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_sink_wavwrite_get_samplerate(aubio_sink_wavwrite_t *s);
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s);
 
 /**
 
@@ -111,7 +111,7 @@
   \return number of channels
 
 */
-uint_t aubio_sink_wavwrite_get_channels(aubio_sink_wavwrite_t *s);
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s);
 
 /**
 
@@ -159,4 +159,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SINK_WAVWRITE_H */
+#endif /* AUBIO_SINK_WAVWRITE_H */
--- a/src/io/source.c
+++ b/src/io/source.c
@@ -40,6 +40,7 @@
 typedef void (*aubio_source_do_multi_t)(aubio_source_t * s, fmat_t * data, uint_t * read);
 typedef uint_t (*aubio_source_get_samplerate_t)(aubio_source_t * s);
 typedef uint_t (*aubio_source_get_channels_t)(aubio_source_t * s);
+typedef uint_t (*aubio_source_get_duration_t)(aubio_source_t * s);
 typedef uint_t (*aubio_source_seek_t)(aubio_source_t * s, uint_t seek);
 typedef uint_t (*aubio_source_close_t)(aubio_source_t * s);
 typedef void (*del_aubio_source_t)(aubio_source_t * s);
@@ -50,14 +51,15 @@
   aubio_source_do_multi_t s_do_multi;
   aubio_source_get_samplerate_t s_get_samplerate;
   aubio_source_get_channels_t s_get_channels;
+  aubio_source_get_duration_t s_get_duration;
   aubio_source_seek_t s_seek;
   aubio_source_close_t s_close;
   del_aubio_source_t s_del;
 };
 
-aubio_source_t * new_aubio_source(char_t * uri, uint_t samplerate, uint_t hop_size) {
+aubio_source_t * new_aubio_source(const char_t * uri, uint_t samplerate, uint_t hop_size) {
   aubio_source_t * s = AUBIO_NEW(aubio_source_t);
-#if HAVE_LIBAV
+#ifdef HAVE_LIBAV
   s->source = (void *)new_aubio_source_avcodec(uri, samplerate, hop_size);
   if (s->source) {
     s->s_do = (aubio_source_do_t)(aubio_source_avcodec_do);
@@ -64,6 +66,7 @@
     s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_avcodec_do_multi);
     s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_avcodec_get_channels);
     s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_avcodec_get_samplerate);
+    s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_avcodec_get_duration);
     s->s_seek = (aubio_source_seek_t)(aubio_source_avcodec_seek);
     s->s_close = (aubio_source_close_t)(aubio_source_avcodec_close);
     s->s_del = (del_aubio_source_t)(del_aubio_source_avcodec);
@@ -77,6 +80,7 @@
     s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_apple_audio_do_multi);
     s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_apple_audio_get_channels);
     s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_apple_audio_get_samplerate);
+    s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_apple_audio_get_duration);
     s->s_seek = (aubio_source_seek_t)(aubio_source_apple_audio_seek);
     s->s_close = (aubio_source_close_t)(aubio_source_apple_audio_close);
     s->s_del = (del_aubio_source_t)(del_aubio_source_apple_audio);
@@ -83,7 +87,7 @@
     return s;
   }
 #endif /* HAVE_SOURCE_APPLE_AUDIO */
-#if HAVE_SNDFILE
+#ifdef HAVE_SNDFILE
   s->source = (void *)new_aubio_source_sndfile(uri, samplerate, hop_size);
   if (s->source) {
     s->s_do = (aubio_source_do_t)(aubio_source_sndfile_do);
@@ -90,6 +94,7 @@
     s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_sndfile_do_multi);
     s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_sndfile_get_channels);
     s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_sndfile_get_samplerate);
+    s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_sndfile_get_duration);
     s->s_seek = (aubio_source_seek_t)(aubio_source_sndfile_seek);
     s->s_close = (aubio_source_close_t)(aubio_source_sndfile_close);
     s->s_del = (del_aubio_source_t)(del_aubio_source_sndfile);
@@ -96,7 +101,7 @@
     return s;
   }
 #endif /* HAVE_SNDFILE */
-#if HAVE_WAVREAD
+#ifdef HAVE_WAVREAD
   s->source = (void *)new_aubio_source_wavread(uri, samplerate, hop_size);
   if (s->source) {
     s->s_do = (aubio_source_do_t)(aubio_source_wavread_do);
@@ -103,6 +108,7 @@
     s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_wavread_do_multi);
     s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_wavread_get_channels);
     s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_wavread_get_samplerate);
+    s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_wavread_get_duration);
     s->s_seek = (aubio_source_seek_t)(aubio_source_wavread_seek);
     s->s_close = (aubio_source_close_t)(aubio_source_wavread_close);
     s->s_del = (del_aubio_source_t)(del_aubio_source_wavread);
@@ -139,6 +145,10 @@
 
 uint_t aubio_source_get_channels(aubio_source_t * s) {
   return s->s_get_channels((void *)s->source);
+}
+
+uint_t aubio_source_get_duration(aubio_source_t *s) {
+  return s->s_get_duration((void *)s->source);
 }
 
 uint_t aubio_source_seek (aubio_source_t * s, uint_t seek ) {
--- a/src/io/source.h
+++ b/src/io/source.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SOURCE_H
-#define _AUBIO_SOURCE_H
+#ifndef AUBIO_SOURCE_H
+#define AUBIO_SOURCE_H
 
 /** \file
 
@@ -85,7 +85,7 @@
   ::aubio_source_get_samplerate.
 
 */
-aubio_source_t * new_aubio_source(char_t * uri, uint_t samplerate, uint_t hop_size);
+aubio_source_t * new_aubio_source(const char_t * uri, uint_t samplerate, uint_t hop_size);
 
 /**
 
@@ -149,6 +149,16 @@
 
 /**
 
+  get the duration of source object, in frames
+
+  \param s source object, created with ::new_aubio_source
+  \return number of frames in file
+
+*/
+uint_t aubio_source_get_duration (aubio_source_t * s);
+
+/**
+
   close source object
 
   \param s source object, created with ::new_aubio_source
@@ -171,4 +181,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SOURCE_H */
+#endif /* AUBIO_SOURCE_H */
--- a/src/io/source_apple_audio.c
+++ b/src/io/source_apple_audio.c
@@ -51,12 +51,12 @@
 
 extern int createAubioBufferList(AudioBufferList *bufferList, int channels, int max_source_samples);
 extern void freeAudioBufferList(AudioBufferList *bufferList);
-extern CFURLRef getURLFromPath(const char * path);
+extern CFURLRef createURLFromPath(const char * path);
 char_t *getPrintableOSStatusError(char_t *str, OSStatus error);
 
-uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, char_t * path);
+uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, const char_t * path);
 
-aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t samplerate, uint_t block_size)
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(const char_t * path, uint_t samplerate, uint_t block_size)
 {
   aubio_source_apple_audio_t * s = AUBIO_NEW(aubio_source_apple_audio_t);
 
@@ -79,7 +79,6 @@
 
   s->block_size = block_size;
   s->samplerate = samplerate;
-  s->path = path;
 
   if ( aubio_source_apple_audio_open ( s, path ) ) {
     goto beach;
@@ -91,15 +90,19 @@
   return NULL;
 }
 
-uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, char_t * path)
+uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, const char_t * path)
 {
   OSStatus err = noErr;
   UInt32 propSize;
-  s->path = path;
 
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   // open the resource url
-  CFURLRef fileURL = getURLFromPath(path);
+  CFURLRef fileURL = createURLFromPath(s->path);
   err = ExtAudioFileOpenURL(fileURL, &s->audioFile);
+  CFRelease(fileURL);
   if (err == -43) {
     AUBIO_ERR("source_apple_audio: Failed opening %s, "
         "file not found, or no read access\n", s->path);
@@ -292,6 +295,7 @@
 
 void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
   aubio_source_apple_audio_close (s);
+  if (s->path) AUBIO_FREE(s->path);
   freeAudioBufferList(&s->bufferList);
   AUBIO_FREE(s);
   return;
@@ -307,10 +311,7 @@
     goto beach;
   }
   // check if we are not seeking out of the file
-  SInt64 fileLengthFrames = 0;
-  UInt32 propSize = sizeof(fileLengthFrames);
-  ExtAudioFileGetProperty(s->audioFile,
-      kExtAudioFileProperty_FileLengthFrames, &propSize, &fileLengthFrames);
+  uint_t fileLengthFrames = aubio_source_apple_audio_get_duration(s);
   // compute position in the source file, before resampling
   smpl_t ratio = s->source_samplerate * 1. / s->samplerate;
   SInt64 resampled_pos = (SInt64)ROUND( pos * ratio );
@@ -351,12 +352,27 @@
   return err;
 }
 
-uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s) {
+uint_t aubio_source_apple_audio_get_samplerate(const aubio_source_apple_audio_t * s) {
   return s->samplerate;
 }
 
-uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s) {
+uint_t aubio_source_apple_audio_get_channels(const aubio_source_apple_audio_t * s) {
   return s->channels;
+}
+
+uint_t aubio_source_apple_audio_get_duration(const aubio_source_apple_audio_t * s) {
+  SInt64 fileLengthFrames = 0;
+  UInt32 propSize = sizeof(fileLengthFrames);
+  OSStatus err = ExtAudioFileGetProperty(s->audioFile,
+      kExtAudioFileProperty_FileLengthFrames, &propSize, &fileLengthFrames);
+  if (err) {
+    char_t errorstr[20];
+    AUBIO_ERROR("source_apple_audio: Failed getting %s duration, "
+        "error in ExtAudioFileGetProperty (%s)\n", s->path,
+        getPrintableOSStatusError(errorstr, err));
+    return err;
+  }
+  return (uint_t)fileLengthFrames;
 }
 
 #endif /* HAVE_SOURCE_APPLE_AUDIO */
--- a/src/io/source_apple_audio.h
+++ b/src/io/source_apple_audio.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SOURCE_APPLE_AUDIO_H
-#define _AUBIO_SOURCE_APPLE_AUDIO_H
+#ifndef AUBIO_SOURCE_APPLE_AUDIO_H
+#define AUBIO_SOURCE_APPLE_AUDIO_H
 
 /** \file
 
@@ -57,7 +57,7 @@
   ::aubio_source_apple_audio_get_samplerate.
 
 */
-aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * uri, uint_t samplerate, uint_t hop_size);
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(const char_t * uri, uint_t samplerate, uint_t hop_size);
 
 /**
 
@@ -95,7 +95,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s);
+uint_t aubio_source_apple_audio_get_samplerate(const aubio_source_apple_audio_t * s);
 
 /**
 
@@ -105,10 +105,20 @@
   \return number of channels
 
 */
-uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s);
+uint_t aubio_source_apple_audio_get_channels(const aubio_source_apple_audio_t * s);
 
 /**
 
+  get the duration of source object, in frames
+
+  \param s source object, created with ::new_aubio_source_apple_audio
+  \return number of frames in file
+
+*/
+uint_t aubio_source_apple_audio_get_duration(const aubio_source_apple_audio_t * s);
+
+/**
+
   seek source object
 
   \param s source object, created with ::new_aubio_source
@@ -143,4 +153,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SOURCE_APPLE_AUDIO_H */
+#endif /* AUBIO_SOURCE_APPLE_AUDIO_H */
--- a/src/io/source_avcodec.c
+++ b/src/io/source_avcodec.c
@@ -23,8 +23,14 @@
 
 #ifdef HAVE_LIBAV
 
-// determine whether we use libavformat from ffmpe or libav
-#define FFMPEG_LIBAVFORMAT (LIBAVFORMAT_VERSION_MICRO > 99)
+// determine whether we use libavformat from ffmpeg or from libav
+#define FFMPEG_LIBAVFORMAT (LIBAVFORMAT_VERSION_MICRO > 99 )
+// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 through 57.2.100
+#define FFMPEG_LIBAVFORMAT_MAX_DUR2 FFMPEG_LIBAVFORMAT && ( \
+      (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 43) \
+      || (LIBAVFORMAT_VERSION_MAJOR == 56) \
+      || (LIBAVFORMAT_VERSION_MAJOR == 57 && LIBAVFORMAT_VERSION_MINOR < 2) \
+      )
 
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
@@ -66,7 +72,22 @@
 void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi);
 void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples);
 
-aubio_source_avcodec_t * new_aubio_source_avcodec(char_t * path, uint_t samplerate, uint_t hop_size) {
+uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s);
+
+uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s) {
+  char proto[20], authorization[256], hostname[128], uripath[256];
+  int proto_size = 20, authorization_size = 256, hostname_size = 128,
+      *port_ptr = 0, path_size = 256;
+  av_url_split(proto, proto_size, authorization, authorization_size, hostname,
+      hostname_size, port_ptr, uripath, path_size, s->path);
+  if (strlen(proto)) {
+    return 1;
+  }
+  return 0;
+}
+
+
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path, uint_t samplerate, uint_t hop_size) {
   aubio_source_avcodec_t * s = AUBIO_NEW(aubio_source_avcodec_t);
   int err;
   if (path == NULL) {
@@ -84,13 +105,17 @@
 
   s->hop_size = hop_size;
   s->channels = 1;
-  s->path = path;
 
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   // register all formats and codecs
   av_register_all();
 
-  // if path[0] != '/'
-  //avformat_network_init();
+  if (aubio_source_avcodec_has_network_url(s)) {
+    avformat_network_init();
+  }
 
   // try opening the file and get some info about it
   AVFormatContext *avFormatCtx = s->avFormatCtx;
@@ -103,7 +128,7 @@
   }
 
   // try to make sure max_analyze_duration is big enough for most songs
-#if FFMPEG_LIBAVFORMAT
+#if FFMPEG_LIBAVFORMAT_MAX_DUR2
   avFormatCtx->max_analyze_duration2 *= 100;
 #else
   avFormatCtx->max_analyze_duration *= 100;
@@ -163,10 +188,10 @@
   //AUBIO_DBG("input_channels: %d\n", s->input_channels);
 
   if (samplerate == 0) {
-    samplerate = s->input_samplerate;
-    //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
+    s->samplerate = s->input_samplerate;
+  } else {
+    s->samplerate = samplerate;
   }
-  s->samplerate = samplerate;
 
   if (s->samplerate >  s->input_samplerate) {
     AUBIO_WRN("source_avcodec: upsampling %s from %d to %d\n", s->path,
@@ -299,7 +324,7 @@
   s->avr = avr;
   s->output = output;
 
-  av_free_packet(&avPacket);
+  av_packet_unref(&avPacket);
 }
 
 void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data, uint_t * read){
@@ -369,11 +394,11 @@
   *read = total_wrote;
 }
 
-uint_t aubio_source_avcodec_get_samplerate(aubio_source_avcodec_t * s) {
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s) {
   return s->samplerate;
 }
 
-uint_t aubio_source_avcodec_get_channels(aubio_source_avcodec_t * s) {
+uint_t aubio_source_avcodec_get_channels(const aubio_source_avcodec_t * s) {
   return s->input_channels;
 }
 
@@ -397,6 +422,14 @@
   return ret;
 }
 
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s) {
+  if (s && &(s->avFormatCtx) != NULL) {
+    int64_t duration = s->avFormatCtx->duration;
+    return s->samplerate * ((uint_t)duration / 1e6 );
+  }
+  return 0;
+}
+
 uint_t aubio_source_avcodec_close(aubio_source_avcodec_t * s) {
   if (s->avr != NULL) {
     avresample_close( s->avr );
@@ -424,6 +457,7 @@
   if (s->avFrame != NULL) {
     av_frame_free( &(s->avFrame) );
   }
+  if (s->path) AUBIO_FREE(s->path);
   s->avFrame = NULL;
   AUBIO_FREE(s);
 }
--- a/src/io/source_avcodec.h
+++ b/src/io/source_avcodec.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SOURCE_AVCODEC_H
-#define _AUBIO_SOURCE_AVCODEC_H
+#ifndef AUBIO_SOURCE_AVCODEC_H
+#define AUBIO_SOURCE_AVCODEC_H
 
 /** \file
 
@@ -56,7 +56,7 @@
   ::aubio_source_avcodec_get_samplerate.
 
 */
-aubio_source_avcodec_t * new_aubio_source_avcodec(char_t * uri, uint_t samplerate, uint_t hop_size);
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * uri, uint_t samplerate, uint_t hop_size);
 
 /**
 
@@ -94,7 +94,7 @@
   \return samplerate, in Hz
 
 */
-uint_t aubio_source_avcodec_get_samplerate(aubio_source_avcodec_t * s);
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s);
 
 /**
 
@@ -104,7 +104,7 @@
   \return number of channels
 
 */
-uint_t aubio_source_avcodec_get_channels (aubio_source_avcodec_t * s);
+uint_t aubio_source_avcodec_get_channels (const aubio_source_avcodec_t * s);
 
 /**
 
@@ -120,6 +120,16 @@
 
 /**
 
+  get the duration of source object, in frames
+
+  \param s source object, created with ::new_aubio_source_avcodec
+  \return number of frames in file
+
+*/
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s);
+
+/**
+
   close source
 
   \param s source object, created with ::new_aubio_source_avcodec
@@ -142,4 +152,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SOURCE_AVCODEC_H */
+#endif /* AUBIO_SOURCE_AVCODEC_H */
--- a/src/io/source_sndfile.c
+++ b/src/io/source_sndfile.c
@@ -36,6 +36,12 @@
 #define MAX_SIZE 4096
 #define MAX_SAMPLES MAX_CHANNELS * MAX_SIZE
 
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_sf_read_smpl sf_read_float
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_sf_read_smpl sf_read_double
+#endif /* HAVE_AUBIO_DOUBLE */
+
 struct _aubio_source_sndfile_t {
   uint_t hop_size;
   uint_t samplerate;
@@ -47,6 +53,7 @@
   int input_samplerate;
   int input_channels;
   int input_format;
+  int duration;
 
   // resampling stuff
   smpl_t ratio;
@@ -58,10 +65,10 @@
 
   // some temporary memory for sndfile to write at
   uint_t scratch_size;
-  float *scratch_data;
+  smpl_t *scratch_data;
 };
 
-aubio_source_sndfile_t * new_aubio_source_sndfile(char_t * path, uint_t samplerate, uint_t hop_size) {
+aubio_source_sndfile_t * new_aubio_source_sndfile(const char_t * path, uint_t samplerate, uint_t hop_size) {
   aubio_source_sndfile_t * s = AUBIO_NEW(aubio_source_sndfile_t);
   SF_INFO sfinfo;
 
@@ -80,8 +87,11 @@
 
   s->hop_size = hop_size;
   s->channels = 1;
-  s->path = path;
 
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   // try opening the file, getting the info in sfinfo
   AUBIO_MEMSET(&sfinfo, 0, sizeof (sfinfo));
   s->handle = sf_open (s->path, SFM_READ, &sfinfo);
@@ -96,14 +106,16 @@
   s->input_samplerate = sfinfo.samplerate;
   s->input_channels   = sfinfo.channels;
   s->input_format     = sfinfo.format;
+  s->duration         = sfinfo.frames;
 
   if (samplerate == 0) {
-    samplerate = s->input_samplerate;
+    s->samplerate = s->input_samplerate;
     //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
+  } else {
+    s->samplerate = samplerate;
   }
-  s->samplerate = samplerate;
   /* compute input block size required before resampling */
-  s->ratio = s->samplerate/(float)s->input_samplerate;
+  s->ratio = s->samplerate/(smpl_t)s->input_samplerate;
   s->input_hop_size = (uint_t)FLOOR(s->hop_size / s->ratio + .5);
 
   if (s->input_hop_size * s->input_channels > MAX_SAMPLES) {
@@ -128,6 +140,7 @@
       AUBIO_WRN("source_sndfile: upsampling %s from %d to %d\n", s->path,
           s->input_samplerate, s->samplerate);
     }
+    s->duration = (uint_t)FLOOR(s->duration * s->ratio);
   }
 #else
   if (s->ratio != 1) {
@@ -138,7 +151,7 @@
 
   /* allocate data for de/interleaving reallocated when needed. */
   s->scratch_size = s->input_hop_size * s->input_channels;
-  s->scratch_data = AUBIO_ARRAY(float,s->scratch_size);
+  s->scratch_data = AUBIO_ARRAY(smpl_t, s->scratch_size);
 
   return s;
 
@@ -152,7 +165,7 @@
 void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uint_t * read){
   uint_t i,j, input_channels = s->input_channels;
   /* read from file into scratch_data */
-  sf_count_t read_samples = sf_read_float (s->handle, s->scratch_data, s->scratch_size);
+  sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
 
   /* where to store de-interleaved data */
   smpl_t *ptr_data;
@@ -193,7 +206,7 @@
 void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_data, uint_t * read){
   uint_t i,j, input_channels = s->input_channels;
   /* do actual reading */
-  sf_count_t read_samples = sf_read_float (s->handle, s->scratch_data, s->scratch_size);
+  sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
 
   /* where to store de-interleaved data */
   smpl_t **ptr_data;
@@ -213,7 +226,7 @@
     // channels of the file, de-interleaving data
     for (j = 0; j < read_samples / input_channels; j++) {
       for (i = 0; i < read_data->height; i++) {
-        ptr_data[i][j] = (smpl_t)s->scratch_data[j * input_channels + i];
+        ptr_data[i][j] = s->scratch_data[j * input_channels + i];
       }
     }
   } else {
@@ -221,7 +234,7 @@
     // channel from the file to the destination matrix, de-interleaving data
     for (j = 0; j < read_samples / input_channels; j++) {
       for (i = 0; i < input_channels; i++) {
-        ptr_data[i][j] = (smpl_t)s->scratch_data[j * input_channels + i];
+        ptr_data[i][j] = s->scratch_data[j * input_channels + i];
       }
     }
   }
@@ -231,7 +244,7 @@
     // of the file to each additional channels, de-interleaving data
     for (j = 0; j < read_samples / input_channels; j++) {
       for (i = input_channels; i < read_data->height; i++) {
-        ptr_data[i][j] = (smpl_t)s->scratch_data[j * input_channels + (input_channels - 1)];
+        ptr_data[i][j] = s->scratch_data[j * input_channels + (input_channels - 1)];
       }
     }
   }
@@ -262,6 +275,13 @@
   return s->input_channels;
 }
 
+uint_t aubio_source_sndfile_get_duration (const aubio_source_sndfile_t * s) {
+  if (s && s->duration) {
+    return s->duration;
+  }
+  return 0;
+}
+
 uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t * s, uint_t pos) {
   uint_t resampled_pos = (uint_t)ROUND(pos / s->ratio);
   sf_count_t sf_ret = sf_seek (s->handle, resampled_pos, SEEK_SET);
@@ -299,6 +319,7 @@
     del_fvec(s->input_data);
   }
 #endif /* HAVE_SAMPLERATE */
+  if (s->path) AUBIO_FREE(s->path);
   AUBIO_FREE(s->scratch_data);
   AUBIO_FREE(s);
 }
--- a/src/io/source_sndfile.h
+++ b/src/io/source_sndfile.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SOURCE_SNDFILE_H
-#define _AUBIO_SOURCE_SNDFILE_H
+#ifndef AUBIO_SOURCE_SNDFILE_H
+#define AUBIO_SOURCE_SNDFILE_H
 
 /** \file
 
@@ -56,7 +56,7 @@
   ::aubio_source_sndfile_get_samplerate.
 
 */
-aubio_source_sndfile_t * new_aubio_source_sndfile(char_t * uri, uint_t samplerate, uint_t hop_size);
+aubio_source_sndfile_t * new_aubio_source_sndfile(const char_t * uri, uint_t samplerate, uint_t hop_size);
 
 /**
 
@@ -120,6 +120,16 @@
 
 /**
 
+  get the duration of source object, in frames
+
+  \param s source object, created with ::new_aubio_source_sndfile
+  \return number of frames in file
+
+*/
+uint_t aubio_source_sndfile_get_duration (const aubio_source_sndfile_t *s);
+
+/**
+
   close source
 
   \param s source object, created with ::new_aubio_source_sndfile
@@ -142,4 +152,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SOURCE_SNDFILE_H */
+#endif /* AUBIO_SOURCE_SNDFILE_H */
--- a/src/io/source_wavread.c
+++ b/src/io/source_wavread.c
@@ -52,6 +52,8 @@
   uint_t read_index;
   uint_t eof;
 
+  uint_t duration;
+
   size_t seek_start;
 
   unsigned char *short_output;
@@ -67,11 +69,11 @@
   return ret;
 }
 
-aubio_source_wavread_t * new_aubio_source_wavread(char_t * path, uint_t samplerate, uint_t hop_size) {
+aubio_source_wavread_t * new_aubio_source_wavread(const char_t * path, uint_t samplerate, uint_t hop_size) {
   aubio_source_wavread_t * s = AUBIO_NEW(aubio_source_wavread_t);
   size_t bytes_read = 0, bytes_expected = 44;
   unsigned char buf[5];
-  unsigned int format, channels, sr, byterate, blockalign, bitspersample;//, data_size;
+  unsigned int format, channels, sr, byterate, blockalign, duration, bitspersample;//, data_size;
 
   if (path == NULL) {
     AUBIO_ERR("source_wavread: Aborted opening null path\n");
@@ -86,7 +88,10 @@
     goto beach;
   }
 
-  s->path = path;
+  if (s->path) AUBIO_FREE(s->path);
+  s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+  strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
   s->samplerate = samplerate;
   s->hop_size = hop_size;
 
@@ -212,6 +217,8 @@
 
   // Subchunk2Size
   bytes_read += fread(buf, 1, 4, s->fid);
+  duration = read_little_endian(buf, 4) / blockalign;
+
   //data_size = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
   //AUBIO_MSG("found %d frames in %s\n", 8 * data_size / bitspersample / channels, s->path);
 
@@ -232,6 +239,8 @@
   s->blockalign= blockalign;
   s->bitspersample = bitspersample;
 
+  s->duration = duration;
+
   s->short_output = (unsigned char *)calloc(s->blockalign, AUBIO_WAVREAD_BUFSIZE);
   s->read_index = 0;
   s->read_samples = 0;
@@ -371,6 +380,13 @@
   return AUBIO_OK;
 }
 
+uint_t aubio_source_wavread_get_duration (const aubio_source_wavread_t * s) {
+  if (s && s->duration) {
+    return s->duration;
+  }
+  return 0;
+}
+
 uint_t aubio_source_wavread_close (aubio_source_wavread_t * s) {
   if (!s->fid) {
     return AUBIO_FAIL;
@@ -388,6 +404,7 @@
   aubio_source_wavread_close(s);
   if (s->short_output) AUBIO_FREE(s->short_output);
   if (s->output) del_fmat(s->output);
+  if (s->path) AUBIO_FREE(s->path);
   AUBIO_FREE(s);
 }
 
--- a/src/io/source_wavread.h
+++ b/src/io/source_wavread.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SOURCE_WAVREAD_H
-#define _AUBIO_SOURCE_WAVREAD_H
+#ifndef AUBIO_SOURCE_WAVREAD_H
+#define AUBIO_SOURCE_WAVREAD_H
 
 /** \file
 
@@ -61,7 +61,7 @@
   ::aubio_source_wavread_get_samplerate.
 
 */
-aubio_source_wavread_t * new_aubio_source_wavread(char_t * uri, uint_t samplerate, uint_t hop_size);
+aubio_source_wavread_t * new_aubio_source_wavread(const char_t * uri, uint_t samplerate, uint_t hop_size);
 
 /**
 
@@ -125,6 +125,16 @@
 
 /**
 
+  get the duration of source object, in frames
+
+  \param s source object, created with ::new_aubio_source_sndfile
+  \return number of frames in file
+
+*/
+uint_t aubio_source_wavread_get_duration (const aubio_source_wavread_t *s);
+
+/**
+
   close source
 
   \param s source object, created with ::new_aubio_source_wavread
@@ -147,4 +157,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SOURCE_WAVREAD_H */
+#endif /* AUBIO_SOURCE_WAVREAD_H */
--- a/src/io/utils_apple_audio.c
+++ b/src/io/utils_apple_audio.c
@@ -33,12 +33,14 @@
   bufferList = NULL;
 }
 
-CFURLRef getURLFromPath(const char * path) {
+CFURLRef createURLFromPath(const char * path) {
   CFStringRef cfTotalPath = CFStringCreateWithCString (kCFAllocatorDefault,
       path, kCFStringEncodingUTF8);
 
-  return CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfTotalPath,
+  CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfTotalPath,
       kCFURLPOSIXPathStyle, false);
+  CFRelease(cfTotalPath);
+  return url;
 }
 
 char_t *getPrintableOSStatusError(char_t *str, OSStatus error)
--- a/src/lvec.c
+++ b/src/lvec.c
@@ -21,7 +21,7 @@
 #include "aubio_priv.h"
 #include "lvec.h"
 
-lvec_t * new_lvec( uint_t length) {
+lvec_t * new_lvec(uint_t length) {
   lvec_t * s;
   if ((sint_t)length <= 0) {
     return NULL;
@@ -45,13 +45,13 @@
   return s->data[position];
 }
 
-lsmp_t * lvec_get_data(lvec_t *s) {
+lsmp_t * lvec_get_data(const lvec_t *s) {
   return s->data;
 }
 
 /* helper functions */
 
-void lvec_print(lvec_t *s) {
+void lvec_print(const lvec_t *s) {
   uint_t j;
   for (j=0; j< s->length; j++) {
     AUBIO_MSG(AUBIO_LSMP_FMT " ", s->data[j]);
--- a/src/lvec.h
+++ b/src/lvec.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO__LVEC_H
-#define _AUBIO__LVEC_H
+#ifndef AUBIO_LVEC_H
+#define AUBIO_LVEC_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -80,7 +80,7 @@
   \param s vector to read from
 
 */
-lsmp_t * lvec_get_data(lvec_t *s);
+lsmp_t * lvec_get_data(const lvec_t *s);
 
 /** print out lvec data
 
@@ -87,7 +87,7 @@
   \param s vector to print out
 
 */
-void lvec_print(lvec_t *s);
+void lvec_print(const lvec_t *s);
 
 /** set all elements to a given value
 
@@ -115,4 +115,4 @@
 }
 #endif
 
-#endif /* _AUBIO__LVEC_H */
+#endif /* AUBIO_LVEC_H */
--- a/src/mathutils.c
+++ b/src/mathutils.c
@@ -26,10 +26,6 @@
 #include "musicutils.h"
 #include "config.h"
 
-#ifdef HAVE_ACCELERATE
-#include <Accelerate/Accelerate.h>
-#endif
-
 /** Window types */
 typedef enum
 {
@@ -166,11 +162,7 @@
   }
   return tmp / (smpl_t) (s->length);
 #else
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_meanv(s->data, 1, &tmp, s->length);
-#else /* HAVE_AUBIO_DOUBLE */
-  vDSP_meanvD(s->data, 1, &tmp, s->length);
-#endif /* HAVE_AUBIO_DOUBLE */
+  aubio_vDSP_meanv(s->data, 1, &tmp, s->length);
   return tmp;
 #endif /* HAVE_ACCELERATE */
 }
@@ -185,11 +177,7 @@
     tmp += s->data[j];
   }
 #else
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_sve(s->data, 1, &tmp, s->length);
-#else /* HAVE_AUBIO_DOUBLE */
-  vDSP_sveD(s->data, 1, &tmp, s->length);
-#endif /* HAVE_AUBIO_DOUBLE */
+  aubio_vDSP_sve(s->data, 1, &tmp, s->length);
 #endif /* HAVE_ACCELERATE */
   return tmp;
 }
@@ -205,12 +193,8 @@
   }
 #else
   smpl_t tmp = 0.;
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_maxv(s->data, 1, &tmp, s->length);
-#else
-  vDSP_maxvD(s->data, 1, &tmp, s->length);
+  aubio_vDSP_maxv(s->data, 1, &tmp, s->length);
 #endif
-#endif
   return tmp;
 }
 
@@ -225,12 +209,8 @@
   }
 #else
   smpl_t tmp = 0.;
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_minv(s->data, 1, &tmp, s->length);
-#else
-  vDSP_minvD(s->data, 1, &tmp, s->length);
+  aubio_vDSP_minv(s->data, 1, &tmp, s->length);
 #endif
-#endif
   return tmp;
 }
 
@@ -247,12 +227,8 @@
 #else
   smpl_t tmp = 0.;
   uint_t pos = 0.;
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_minvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
-#else
-  vDSP_minviD(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+  aubio_vDSP_minvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
 #endif
-#endif
   return pos;
 }
 
@@ -269,12 +245,8 @@
 #else
   smpl_t tmp = 0.;
   uint_t pos = 0.;
-#if !HAVE_AUBIO_DOUBLE
-  vDSP_maxvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
-#else
-  vDSP_maxviD(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+  aubio_vDSP_maxvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
 #endif
-#endif
   return pos;
 }
 
@@ -281,20 +253,55 @@
 void
 fvec_shift (fvec_t * s)
 {
-  uint_t j;
-  for (j = 0; j < s->length / 2; j++) {
-    ELEM_SWAP (s->data[j], s->data[j + s->length / 2]);
+  uint_t half = s->length / 2, start = half, j;
+  // if length is odd, middle element is moved to the end
+  if (2 * half < s->length) start ++;
+#ifndef HAVE_ATLAS
+  for (j = 0; j < half; j++) {
+    ELEM_SWAP (s->data[j], s->data[j + start]);
   }
+#else
+  aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+  if (start != half) {
+    for (j = 0; j < half; j++) {
+      ELEM_SWAP (s->data[j + start - 1], s->data[j + start]);
+    }
+  }
 }
 
+void
+fvec_ishift (fvec_t * s)
+{
+  uint_t half = s->length / 2, start = half, j;
+  // if length is odd, middle element is moved to the beginning
+  if (2 * half < s->length) start ++;
+#ifndef HAVE_ATLAS
+  for (j = 0; j < half; j++) {
+    ELEM_SWAP (s->data[j], s->data[j + start]);
+  }
+#else
+  aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+  if (start != half) {
+    for (j = 0; j < half; j++) {
+      ELEM_SWAP (s->data[half], s->data[j]);
+    }
+  }
+}
+
 smpl_t
-aubio_level_lin (fvec_t * f)
+aubio_level_lin (const fvec_t * f)
 {
   smpl_t energy = 0.;
+#ifndef HAVE_ATLAS
   uint_t j;
   for (j = 0; j < f->length; j++) {
     energy += SQR (f->data[j]);
   }
+#else
+  energy = aubio_cblas_dot(f->length, f->data, 1, f->data, 1);
+#endif
   return energy / f->length;
 }
 
@@ -433,8 +440,9 @@
   }
 }
 
-smpl_t fvec_quadratic_peak_pos (fvec_t * x, uint_t pos) {
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t pos) {
   smpl_t s0, s1, s2; uint_t x0, x2;
+  smpl_t half = .5, two = 2.;
   if (pos == 0 || pos == x->length - 1) return pos;
   x0 = (pos < 1) ? pos : pos - 1;
   x2 = (pos + 1 < x->length) ? pos + 1 : pos;
@@ -443,7 +451,7 @@
   s0 = x->data[x0];
   s1 = x->data[pos];
   s2 = x->data[x2];
-  return pos + 0.5 * (s0 - s2 ) / (s0 - 2.* s1 + s2);
+  return pos + half * (s0 - s2 ) / (s0 - two * s1 + s2);
 }
 
 smpl_t fvec_quadratic_peak_mag (fvec_t *x, smpl_t pos) {
@@ -457,7 +465,7 @@
   return x1 - .25 * (x0 - x2) * (pos - index);
 }
 
-uint_t fvec_peakpick(fvec_t * onset, uint_t pos) {
+uint_t fvec_peakpick(const fvec_t * onset, uint_t pos) {
   uint_t tmp=0;
   tmp = (onset->data[pos] > onset->data[pos-1]
       &&  onset->data[pos] > onset->data[pos+1]
@@ -544,13 +552,13 @@
 }
 
 smpl_t
-aubio_db_spl (fvec_t * o)
+aubio_db_spl (const fvec_t * o)
 {
   return 10. * LOG10 (aubio_level_lin (o));
 }
 
 uint_t
-aubio_silence_detection (fvec_t * o, smpl_t threshold)
+aubio_silence_detection (const fvec_t * o, smpl_t threshold)
 {
   return (aubio_db_spl (o) < threshold);
 }
@@ -590,7 +598,7 @@
 }
 
 void
-aubio_autocorr (fvec_t * input, fvec_t * output)
+aubio_autocorr (const fvec_t * input, fvec_t * output)
 {
   uint_t i, j, length = input->length;
   smpl_t *data, *acf;
--- a/src/mathutils.h
+++ b/src/mathutils.h
@@ -27,8 +27,8 @@
 
  */
 
-#ifndef _AUBIO_MATHUTILS_H
-#define _AUBIO_MATHUTILS_H
+#ifndef AUBIO_MATHUTILS_H
+#define AUBIO_MATHUTILS_H
 
 #include "fvec.h"
 #include "musicutils.h"
@@ -99,6 +99,24 @@
 */
 void fvec_shift (fvec_t * v);
 
+/** swap the left and right halves of a vector
+
+  This function swaps the left part of the signal with the right part of the
+signal. Therefore
+
+  \f$ a[0], a[1], ..., a[\frac{N}{2}], a[\frac{N}{2}+1], ..., a[N-1], a[N] \f$
+
+  becomes
+
+  \f$ a[\frac{N}{2}+1], ..., a[N-1], a[N], a[0], a[1], ..., a[\frac{N}{2}] \f$
+
+  This operation, known as 'ifftshift' in the Matlab Signal Processing Toolbox,
+can be used after computing the inverse FFT to simplify the phase relationship
+of the resulting spectrum. See Amalia de Götzen's paper referred to above.
+
+*/
+void fvec_ishift (fvec_t * v);
+
 /** compute the sum of all elements of a vector
 
   \param v vector to compute the sum of
@@ -232,7 +250,7 @@
   \return \f$ p + p_{frac} \f$ exact peak position of interpolated maximum or minimum
 
 */
-smpl_t fvec_quadratic_peak_pos (fvec_t * x, uint_t p);
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t p);
 
 /** finds magnitude of peak by quadratic interpolation
 
@@ -275,7 +293,7 @@
   \return 1 if a peak is found, 0 otherwise
 
 */
-uint_t fvec_peakpick (fvec_t * v, uint_t p);
+uint_t fvec_peakpick (const fvec_t * v, uint_t p);
 
 /** return 1 if a is a power of 2, 0 otherwise */
 uint_t aubio_is_power_of_two(uint_t a);
@@ -289,10 +307,10 @@
   \param output vector to store autocorrelation function to
 
 */
-void aubio_autocorr (fvec_t * input, fvec_t * output);
+void aubio_autocorr (const fvec_t * input, fvec_t * output);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO_MATHUTILS_H */
+#endif /* AUBIO_MATHUTILS_H */
--- a/src/musicutils.h
+++ b/src/musicutils.h
@@ -22,8 +22,8 @@
  *  various functions useful in audio signal processing
  */
 
-#ifndef _AUBIO__MUSICUTILS_H
-#define _AUBIO__MUSICUTILS_H
+#ifndef AUBIO_MUSICUTILS_H
+#define AUBIO_MUSICUTILS_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -56,8 +56,8 @@
 implementations of a phase vocoder: the tricks of the trade. In Proceedings of
 the International Conference on Digital Audio Effects (DAFx-00), pages 37–44,
 Uni- versity of Verona, Italy, 2000.
-  (<a href="http://profs.sci.univr.it/%7Edafx/Final-Papers/ps/Bernardini.ps.gz">
-  ps.gz</a>)
+  (<a href="http://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf">
+  pdf</a>)
 
  */
 uint_t fvec_set_window (fvec_t * window, char_t * window_type);
@@ -121,7 +121,7 @@
   \return level of v
 
 */
-smpl_t aubio_level_lin (fvec_t * v);
+smpl_t aubio_level_lin (const fvec_t * v);
 
 /** compute sound pressure level (SPL) in dB
 
@@ -134,7 +134,7 @@
   \return level of v in dB SPL
 
 */
-smpl_t aubio_db_spl (fvec_t * v);
+smpl_t aubio_db_spl (const fvec_t * v);
 
 /** check if buffer level in dB SPL is under a given threshold
 
@@ -144,7 +144,7 @@
   \return 0 if level is under the given threshold, 1 otherwise
 
 */
-uint_t aubio_silence_detection (fvec_t * v, smpl_t threshold);
+uint_t aubio_silence_detection (const fvec_t * v, smpl_t threshold);
 
 /** get buffer level if level >= threshold, 1. otherwise
 
@@ -160,4 +160,4 @@
 }
 #endif
 
-#endif /* _AUBIO__MUSICUTILS_H */
+#endif /* AUBIO_MUSICUTILS_H */
--- a/src/onset/onset.c
+++ b/src/onset/onset.c
@@ -45,7 +45,7 @@
 };
 
 /* execute onset detection function on iput buffer */
-void aubio_onset_do (aubio_onset_t *o, fvec_t * input, fvec_t * onset)
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset)
 {
   smpl_t isonset = 0;
   aubio_pvoc_do (o->pv,input, o->fftgrain);
@@ -84,17 +84,17 @@
   return;
 }
 
-uint_t aubio_onset_get_last (aubio_onset_t *o)
+uint_t aubio_onset_get_last (const aubio_onset_t *o)
 {
   return o->last_onset - o->delay;
 }
 
-smpl_t aubio_onset_get_last_s (aubio_onset_t *o)
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o)
 {
   return aubio_onset_get_last (o) / (smpl_t) (o->samplerate);
 }
 
-smpl_t aubio_onset_get_last_ms (aubio_onset_t *o)
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o)
 {
   return aubio_onset_get_last_s (o) * 1000.;
 }
@@ -104,7 +104,7 @@
   return AUBIO_OK;
 }
 
-smpl_t aubio_onset_get_silence(aubio_onset_t * o) {
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o) {
   return o->silence;
 }
 
@@ -113,7 +113,7 @@
   return AUBIO_OK;
 }
 
-smpl_t aubio_onset_get_threshold(aubio_onset_t * o) {
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o) {
   return aubio_peakpicker_get_threshold(o->pp);
 }
 
@@ -122,15 +122,15 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_onset_get_minioi(aubio_onset_t * o) {
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o) {
   return o->minioi;
 }
 
 uint_t aubio_onset_set_minioi_s(aubio_onset_t * o, smpl_t minioi) {
-  return aubio_onset_set_minioi (o, minioi * o->samplerate);
+  return aubio_onset_set_minioi (o, (uint_t)ROUND(minioi * o->samplerate));
 }
 
-smpl_t aubio_onset_get_minioi_s(aubio_onset_t * o) {
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o) {
   return aubio_onset_get_minioi (o) / (smpl_t) o->samplerate;
 }
 
@@ -138,7 +138,7 @@
   return aubio_onset_set_minioi_s (o, minioi / 1000.);
 }
 
-smpl_t aubio_onset_get_minioi_ms(aubio_onset_t * o) {
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o) {
   return aubio_onset_get_minioi_s (o) * 1000.;
 }
 
@@ -147,7 +147,7 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_onset_get_delay(aubio_onset_t * o) {
+uint_t aubio_onset_get_delay(const aubio_onset_t * o) {
   return o->delay;
 }
 
@@ -155,7 +155,7 @@
   return aubio_onset_set_delay (o, delay * o->samplerate);
 }
 
-smpl_t aubio_onset_get_delay_s(aubio_onset_t * o) {
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o) {
   return aubio_onset_get_delay (o) / (smpl_t) o->samplerate;
 }
 
@@ -163,21 +163,21 @@
   return aubio_onset_set_delay_s (o, delay / 1000.);
 }
 
-smpl_t aubio_onset_get_delay_ms(aubio_onset_t * o) {
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o) {
   return aubio_onset_get_delay_s (o) * 1000.;
 }
 
-smpl_t aubio_onset_get_descriptor(aubio_onset_t * o) {
+smpl_t aubio_onset_get_descriptor(const aubio_onset_t * o) {
   return o->desc->data[0];
 }
 
-smpl_t aubio_onset_get_thresholded_descriptor(aubio_onset_t * o) {
+smpl_t aubio_onset_get_thresholded_descriptor(const aubio_onset_t * o) {
   fvec_t * thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
   return thresholded->data[0];
 }
 
 /* Allocate memory for an onset detection */
-aubio_onset_t * new_aubio_onset (char_t * onset_mode, 
+aubio_onset_t * new_aubio_onset (const char_t * onset_mode,
     uint_t buf_size, uint_t hop_size, uint_t samplerate)
 {
   aubio_onset_t * o = AUBIO_NEW(aubio_onset_t);
@@ -186,8 +186,8 @@
   if ((sint_t)hop_size < 1) {
     AUBIO_ERR("onset: got hop_size %d, but can not be < 1\n", hop_size);
     goto beach;
-  } else if ((sint_t)buf_size < 1) {
-    AUBIO_ERR("onset: got buffer_size %d, but can not be < 1\n", buf_size);
+  } else if ((sint_t)buf_size < 2) {
+    AUBIO_ERR("onset: got buffer_size %d, but can not be < 2\n", buf_size);
     goto beach;
   } else if (buf_size < hop_size) {
     AUBIO_ERR("onset: hop size (%d) is larger than win size (%d)\n", buf_size, hop_size);
--- a/src/onset/onset.h
+++ b/src/onset/onset.h
@@ -39,8 +39,8 @@
 */
 
 
-#ifndef _AUBIO_ONSET_H
-#define _AUBIO_ONSET_H
+#ifndef AUBIO_ONSET_H
+#define AUBIO_ONSET_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -59,7 +59,7 @@
   \return newly created ::aubio_onset_t
 
 */
-aubio_onset_t * new_aubio_onset (char_t * method,
+aubio_onset_t * new_aubio_onset (const char_t * method,
     uint_t buf_size, uint_t hop_size, uint_t samplerate);
 
 /** execute onset detection
@@ -88,7 +88,7 @@
   aubio_onset_get_delay().
 
 */
-void aubio_onset_do (aubio_onset_t *o, fvec_t * input, fvec_t * onset);
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset);
 
 /** get the time of the latest onset detected, in samples
 
@@ -97,7 +97,7 @@
   \return onset detection timestamps (in samples)
 
 */
-uint_t aubio_onset_get_last (aubio_onset_t *o);
+uint_t aubio_onset_get_last (const aubio_onset_t *o);
 
 /** get the time of the latest onset detected, in seconds
 
@@ -106,7 +106,7 @@
   \return onset detection timestamps (in seconds)
 
 */
-smpl_t aubio_onset_get_last_s (aubio_onset_t *o);
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o);
 
 /** get the time of the latest onset detected, in milliseconds
 
@@ -115,7 +115,7 @@
   \return onset detection timestamps (in milliseconds)
 
 */
-smpl_t aubio_onset_get_last_ms (aubio_onset_t *o);
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o);
 
 /** set onset detection silence threshold
 
@@ -132,7 +132,7 @@
   \return current silence threshold
 
 */
-smpl_t aubio_onset_get_silence(aubio_onset_t * o);
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o);
 
 /** get onset detection function
 
@@ -140,7 +140,7 @@
   \return the current value of the descriptor
 
 */
-smpl_t aubio_onset_get_descriptor ( aubio_onset_t *o);
+smpl_t aubio_onset_get_descriptor (const aubio_onset_t *o);
 
 /** get thresholded onset detection function
 
@@ -148,7 +148,7 @@
   \return the value of the thresholded descriptor
 
 */
-smpl_t aubio_onset_get_thresholded_descriptor ( aubio_onset_t *o);
+smpl_t aubio_onset_get_thresholded_descriptor (const aubio_onset_t *o);
 
 /** set onset detection peak picking threshold
 
@@ -219,7 +219,7 @@
   samples)
 
 */
-uint_t aubio_onset_get_minioi(aubio_onset_t * o);
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o);
 
 /** get minimum inter onset interval in seconds
 
@@ -228,7 +228,7 @@
   seconds)
 
 */
-smpl_t aubio_onset_get_minioi_s(aubio_onset_t * o);
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o);
 
 /** get minimum inter onset interval in milliseconds
 
@@ -237,7 +237,7 @@
   milliseconds)
 
 */
-smpl_t aubio_onset_get_minioi_ms(aubio_onset_t * o);
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o);
 
 /** get delay in samples
 
@@ -246,7 +246,7 @@
   (in samples)
 
 */
-uint_t aubio_onset_get_delay(aubio_onset_t * o);
+uint_t aubio_onset_get_delay(const aubio_onset_t * o);
 
 /** get delay in seconds
 
@@ -255,7 +255,7 @@
   (in seconds)
 
 */
-smpl_t aubio_onset_get_delay_s(aubio_onset_t * o);
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o);
 
 /** get delay in milliseconds
 
@@ -264,7 +264,7 @@
   (in milliseconds)
 
 */
-smpl_t aubio_onset_get_delay_ms(aubio_onset_t * o);
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o);
 
 /** get onset peak picking threshold
 
@@ -272,7 +272,7 @@
   \return current onset detection threshold
 
 */
-smpl_t aubio_onset_get_threshold(aubio_onset_t * o);
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o);
 
 /** delete onset detection object
 
@@ -285,4 +285,4 @@
 }
 #endif
 
-#endif /* _AUBIO_ONSET_H */
+#endif /* AUBIO_ONSET_H */
--- a/src/onset/peakpicker.h
+++ b/src/onset/peakpicker.h
@@ -26,8 +26,8 @@
 
 */
 
-#ifndef _AUBIO_PEAKPICK_H
-#define _AUBIO_PEAKPICK_H
+#ifndef AUBIO_PEAKPICK_H
+#define AUBIO_PEAKPICK_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -54,4 +54,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PEAKPICK_H */
+#endif /* AUBIO_PEAKPICK_H */
--- a/src/pitch/pitch.c
+++ b/src/pitch/pitch.c
@@ -61,7 +61,7 @@
 } aubio_pitch_mode;
 
 /** callback to get pitch candidate, defined below */
-typedef void (*aubio_pitch_detect_t) (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
+typedef void (*aubio_pitch_detect_t) (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
 
 /** callback to convert pitch from one unit to another, defined below */
 typedef smpl_t(*aubio_pitch_convert_t) (smpl_t value, uint_t samplerate, uint_t bufsize);
@@ -78,6 +78,7 @@
   uint_t bufsize;                 /**< buffer size */
   void *p_object;                 /**< pointer to pitch object */
   aubio_filter_t *filter;         /**< filter */
+  fvec_t *filtered;               /**< filtered input */
   aubio_pvoc_t *pv;               /**< phase vocoder for mcomb */
   cvec_t *fftgrain;               /**< spectral frame for mcomb */
   fvec_t *buf;                    /**< temporary buffer for yin */
@@ -88,12 +89,12 @@
 };
 
 /* callback functions for pitch detection */
-static void aubio_pitch_do_mcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
-static void aubio_pitch_do_yin (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
-static void aubio_pitch_do_schmitt (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
-static void aubio_pitch_do_fcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
-static void aubio_pitch_do_yinfft (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
-static void aubio_pitch_do_specacf (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_mcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_yin (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_schmitt (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_fcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_yinfft (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_specacf (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
 
 /* conversion functions for frequency conversions */
 smpl_t freqconvbin (smpl_t f, uint_t samplerate, uint_t bufsize);
@@ -101,11 +102,11 @@
 smpl_t freqconvpass (smpl_t f, uint_t samplerate, uint_t bufsize);
 
 /* adapter to stack ibuf new samples at the end of buf, and trim `buf` to `bufsize` */
-void aubio_pitch_slideblock (aubio_pitch_t * p, fvec_t * ibuf);
+void aubio_pitch_slideblock (aubio_pitch_t * p, const fvec_t * ibuf);
 
 
 aubio_pitch_t *
-new_aubio_pitch (char_t * pitch_mode,
+new_aubio_pitch (const char_t * pitch_mode,
     uint_t bufsize, uint_t hopsize, uint_t samplerate)
 {
   aubio_pitch_t *p = AUBIO_NEW (aubio_pitch_t);
@@ -132,16 +133,16 @@
 
   // check parameters are valid
   if ((sint_t)hopsize < 1) {
-    AUBIO_ERR("onset: got hopsize %d, but can not be < 1\n", hopsize);
+    AUBIO_ERR("pitch: got hopsize %d, but can not be < 1\n", hopsize);
     goto beach;
   } else if ((sint_t)bufsize < 1) {
-    AUBIO_ERR("onset: got buffer_size %d, but can not be < 1\n", bufsize);
+    AUBIO_ERR("pitch: got buffer_size %d, but can not be < 1\n", bufsize);
     goto beach;
   } else if (bufsize < hopsize) {
-    AUBIO_ERR("onset: hop size (%d) is larger than win size (%d)\n", bufsize, hopsize);
+    AUBIO_ERR("pitch: hop size (%d) is larger than win size (%d)\n", bufsize, hopsize);
     goto beach;
   } else if ((sint_t)samplerate < 1) {
-    AUBIO_ERR("onset: samplerate (%d) can not be < 1\n", samplerate);
+    AUBIO_ERR("pitch: samplerate (%d) can not be < 1\n", samplerate);
     goto beach;
   }
 
@@ -160,6 +161,7 @@
       aubio_pitchyin_set_tolerance (p->p_object, 0.15);
       break;
     case aubio_pitcht_mcomb:
+      p->filtered = new_fvec (hopsize);
       p->pv = new_aubio_pvoc (bufsize, hopsize);
       p->fftgrain = new_cvec (bufsize);
       p->p_object = new_aubio_pitchmcomb (bufsize, hopsize);
@@ -209,6 +211,7 @@
       del_aubio_pitchyin (p->p_object);
       break;
     case aubio_pitcht_mcomb:
+      del_fvec (p->filtered);
       del_aubio_pvoc (p->pv);
       del_cvec (p->fftgrain);
       del_aubio_filter (p->filter);
@@ -237,10 +240,11 @@
 }
 
 void
-aubio_pitch_slideblock (aubio_pitch_t * p, fvec_t * ibuf)
+aubio_pitch_slideblock (aubio_pitch_t * p, const fvec_t * ibuf)
 {
-  uint_t j = 0, overlap_size = 0;
-  overlap_size = p->buf->length - ibuf->length;
+  uint_t overlap_size = p->buf->length - ibuf->length;
+#if 1 //!HAVE_MEMCPY_HACKS
+  uint_t j;
   for (j = 0; j < overlap_size; j++) {
     p->buf->data[j] = p->buf->data[j + ibuf->length];
   }
@@ -247,10 +251,16 @@
   for (j = 0; j < ibuf->length; j++) {
     p->buf->data[j + overlap_size] = ibuf->data[j];
   }
+#else
+  smpl_t *data = p->buf->data;
+  smpl_t *newdata = ibuf->data;
+  memmove(data, data + ibuf->length, overlap_size);
+  memcpy(data + overlap_size, newdata, ibuf->length);
+#endif
 }
 
 uint_t
-aubio_pitch_set_unit (aubio_pitch_t * p, char_t * pitch_unit)
+aubio_pitch_set_unit (aubio_pitch_t * p, const char_t * pitch_unit)
 {
   uint_t err = AUBIO_OK;
   aubio_pitch_mode pitch_mode;
@@ -335,7 +345,7 @@
 
 /* do method, calling the detection callback, then the conversion callback */
 void
-aubio_pitch_do (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
+aubio_pitch_do (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
 {
   p->detect_cb (p, ibuf, obuf);
   if (aubio_silence_detection(ibuf, p->silence) == 1) {
@@ -346,9 +356,9 @@
 
 /* do method for each algorithm */
 void
-aubio_pitch_do_mcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
+aubio_pitch_do_mcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
 {
-  aubio_filter_do (p->filter, ibuf);
+  aubio_filter_do_outplace (p->filter, ibuf, p->filtered);
   aubio_pvoc_do (p->pv, ibuf, p->fftgrain);
   aubio_pitchmcomb_do (p->p_object, p->fftgrain, obuf);
   obuf->data[0] = aubio_bintofreq (obuf->data[0], p->samplerate, p->bufsize);
@@ -355,7 +365,7 @@
 }
 
 void
-aubio_pitch_do_yin (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
+aubio_pitch_do_yin (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
 {
   smpl_t pitch = 0.;
   aubio_pitch_slideblock (p, ibuf);
@@ -371,7 +381,7 @@
 
 
 void
-aubio_pitch_do_yinfft (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
+aubio_pitch_do_yinfft (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
 {
   smpl_t pitch = 0.;
   aubio_pitch_slideblock (p, ibuf);
@@ -386,7 +396,7 @@
 }
 
 void
-aubio_pitch_do_specacf (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * out)
+aubio_pitch_do_specacf (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
 {
   smpl_t pitch = 0., period;
   aubio_pitch_slideblock (p, ibuf);
@@ -402,7 +412,7 @@
 }
 
 void
-aubio_pitch_do_fcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * out)
+aubio_pitch_do_fcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
 {
   aubio_pitch_slideblock (p, ibuf);
   aubio_pitchfcomb_do (p->p_object, p->buf, out);
@@ -410,7 +420,7 @@
 }
 
 void
-aubio_pitch_do_schmitt (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * out)
+aubio_pitch_do_schmitt (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
 {
   smpl_t period, pitch = 0.;
   aubio_pitch_slideblock (p, ibuf);
--- a/src/pitch/pitch.h
+++ b/src/pitch/pitch.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_PITCH_H
-#define _AUBIO_PITCH_H
+#ifndef AUBIO_PITCH_H
+#define AUBIO_PITCH_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -107,7 +107,7 @@
   \param out output pitch candidates of size [1]
 
 */
-void aubio_pitch_do (aubio_pitch_t * o, fvec_t * in, fvec_t * out);
+void aubio_pitch_do (aubio_pitch_t * o, const fvec_t * in, fvec_t * out);
 
 /** change yin or yinfft tolerance threshold
 
@@ -134,7 +134,7 @@
   \return newly created ::aubio_pitch_t
 
 */
-aubio_pitch_t *new_aubio_pitch (char_t * method,
+aubio_pitch_t *new_aubio_pitch (const char_t * method,
     uint_t buf_size, uint_t hop_size, uint_t samplerate);
 
 /** set the output unit of the pitch detection object
@@ -145,7 +145,7 @@
   \return 0 if successfull, non-zero otherwise
 
 */
-uint_t aubio_pitch_set_unit (aubio_pitch_t * o, char_t * mode);
+uint_t aubio_pitch_set_unit (aubio_pitch_t * o, const char_t * mode);
 
 /** set the silence threshold of the pitch detection object
 
@@ -179,4 +179,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCH_H */
+#endif /* AUBIO_PITCH_H */
--- a/src/pitch/pitchfcomb.c
+++ b/src/pitch/pitchfcomb.c
@@ -63,7 +63,7 @@
 
 /* input must be stepsize long */
 void
-aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, fvec_t * input, fvec_t * output)
+aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, const fvec_t * input, fvec_t * output)
 {
   uint_t k, l, maxharm = 0;
   smpl_t phaseDifference = TWO_PI * (smpl_t) p->stepSize / (smpl_t) p->fftSize;
--- a/src/pitch/pitchfcomb.h
+++ b/src/pitch/pitchfcomb.h
@@ -34,8 +34,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHFCOMB_H
-#define _AUBIO_PITCHFCOMB_H
+#ifndef AUBIO_PITCHFCOMB_H
+#define AUBIO_PITCHFCOMB_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -51,7 +51,7 @@
   \param output pitch candidates in bins
 
 */
-void aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, fvec_t * input,
+void aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, const fvec_t * input,
     fvec_t * output);
 
 /** creation of the pitch detection object
@@ -73,4 +73,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCHFCOMB_H */
+#endif /* AUBIO_PITCHFCOMB_H */
--- a/src/pitch/pitchmcomb.c
+++ b/src/pitch/pitchmcomb.c
@@ -31,9 +31,9 @@
 uint_t aubio_pitchmcomb_get_root_peak (aubio_spectralpeak_t * peaks,
     uint_t length);
 uint_t aubio_pitchmcomb_quadpick (aubio_spectralpeak_t * spectral_peaks,
-    fvec_t * X);
-void aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, fvec_t * oldmag);
-void aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, fvec_t * newmag);
+    const fvec_t * X);
+void aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, const fvec_t * oldmag);
+void aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, const fvec_t * newmag);
 /* not used but useful : sort by amplitudes (or anything else)
  * sort_pitchpeak(peaks, length);
  */
@@ -42,7 +42,7 @@
 /** sort spectral_peak against their mag */
 void aubio_pitchmcomb_sort_peak (aubio_spectralpeak_t * peaks, uint_t nbins);
 /** select the best candidates */
-uint_t aubio_pitch_cands (aubio_pitchmcomb_t * p, cvec_t * fftgrain,
+uint_t aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain,
     smpl_t * cands);
 
 /** sort spectral_candidate against their comb ene */
@@ -101,7 +101,7 @@
 
 
 void
-aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, cvec_t * fftgrain, fvec_t * output)
+aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, const cvec_t * fftgrain, fvec_t * output)
 {
   uint_t j;
   smpl_t instfreq;
@@ -134,7 +134,7 @@
 }
 
 uint_t
-aubio_pitch_cands (aubio_pitchmcomb_t * p, cvec_t * fftgrain, smpl_t * cands)
+aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain, smpl_t * cands)
 {
   uint_t j;
   uint_t k;
@@ -165,7 +165,7 @@
 }
 
 void
-aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, fvec_t * newmag)
+aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, const fvec_t * newmag)
 {
   fvec_t *mag = (fvec_t *) p->scratch;
   fvec_t *tmp = (fvec_t *) p->scratch2;
@@ -197,7 +197,7 @@
 }
 
 void
-aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, fvec_t * newmag)
+aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, const fvec_t * newmag)
 {
   aubio_spectralpeak_t *peaks = (aubio_spectralpeak_t *) p->peaks;
   aubio_spectralcandidate_t **candidate =
@@ -285,7 +285,7 @@
  * \bug peak-picking too picky, sometimes counts too many peaks ?
  */
 uint_t
-aubio_pitchmcomb_quadpick (aubio_spectralpeak_t * spectral_peaks, fvec_t * X)
+aubio_pitchmcomb_quadpick (aubio_spectralpeak_t * spectral_peaks, const fvec_t * X)
 {
   uint_t j, ispeak, count = 0;
   for (j = 1; j < X->length - 1; j++) {
@@ -335,8 +335,7 @@
   uint_t cur = 0;
   uint_t run = 0;
   for (cur = 0; cur < nbins; cur++) {
-    run = cur + 1;
-    for (run = cur; run < nbins; run++) {
+    for (run = cur + 1; run < nbins; run++) {
       if (candidates[run]->ene > candidates[cur]->ene)
         CAND_SWAP (candidates[run], candidates[cur]);
     }
@@ -351,8 +350,7 @@
   uint_t cur = 0;
   uint_t run = 0;
   for (cur = 0; cur < nbins; cur++) {
-    run = cur + 1;
-    for (run = cur; run < nbins; run++) {
+    for (run = cur + 1; run < nbins; run++) {
       if (candidates[run]->ebin < candidates[cur]->ebin)
         CAND_SWAP (candidates[run], candidates[cur]);
     }
@@ -366,7 +364,7 @@
   /* bug: should check if size / 8 > post+pre+1 */
   uint_t i, j;
   uint_t spec_size;
-  p->spec_partition = 4;
+  p->spec_partition = 2;
   p->ncand = 5;
   p->npartials = 5;
   p->cutoff = 1.;
@@ -378,7 +376,7 @@
   p->goodcandidate = 0;
   p->phasefreq = bufsize / hopsize / TWO_PI;
   p->phasediff = TWO_PI * hopsize / bufsize;
-  spec_size = bufsize / p->spec_partition;
+  spec_size = bufsize / p->spec_partition + 1;
   //p->pickerfn = quadpick;
   //p->biquad = new_biquad(0.1600,0.3200,0.1600, -0.5949, 0.2348);
   /* allocate temp memory */
--- a/src/pitch/pitchmcomb.h
+++ b/src/pitch/pitchmcomb.h
@@ -35,8 +35,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHMCOMB_H
-#define _AUBIO_PITCHMCOMB_H
+#ifndef AUBIO_PITCHMCOMB_H
+#define AUBIO_PITCHMCOMB_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -52,7 +52,7 @@
   \param out_cands pitch candidate frequenciess, in bins
 
 */
-void aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, cvec_t * in_fftgrain,
+void aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, const cvec_t * in_fftgrain,
     fvec_t * out_cands);
 
 /** creation of the pitch detection object
@@ -74,4 +74,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCHMCOMB_H */
+#endif /* AUBIO_PITCHMCOMB_H */
--- a/src/pitch/pitchschmitt.c
+++ b/src/pitch/pitchschmitt.c
@@ -47,7 +47,7 @@
 }
 
 void
-aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, fvec_t * input,
+aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, const fvec_t * input,
     fvec_t * output)
 {
   uint_t j;
--- a/src/pitch/pitchschmitt.h
+++ b/src/pitch/pitchschmitt.h
@@ -34,8 +34,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHSCHMITT_H
-#define _AUBIO_PITCHSCHMITT_H
+#ifndef AUBIO_PITCHSCHMITT_H
+#define AUBIO_PITCHSCHMITT_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -51,7 +51,7 @@
   \param cands_out pitch period estimates, in samples
 
 */
-void aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, fvec_t * samples_in,
+void aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, const fvec_t * samples_in,
     fvec_t * cands_out);
 
 /** creation of the pitch detection object
@@ -72,5 +72,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCHSCHMITT_H */
-
+#endif /* AUBIO_PITCHSCHMITT_H */
--- a/src/pitch/pitchspecacf.c
+++ b/src/pitch/pitchspecacf.c
@@ -54,7 +54,7 @@
 }
 
 void
-aubio_pitchspecacf_do (aubio_pitchspecacf_t * p, fvec_t * input, fvec_t * output)
+aubio_pitchspecacf_do (aubio_pitchspecacf_t * p, const fvec_t * input, fvec_t * output)
 {
   uint_t l, tau;
   fvec_t *fftout = p->fftout;
@@ -91,7 +91,7 @@
 }
 
 smpl_t
-aubio_pitchspecacf_get_confidence (aubio_pitchspecacf_t * o) {
+aubio_pitchspecacf_get_confidence (const aubio_pitchspecacf_t * o) {
   // no confidence for now
   return o->confidence;
 }
@@ -104,7 +104,7 @@
 }
 
 smpl_t
-aubio_pitchspecacf_get_tolerance (aubio_pitchspecacf_t * p)
+aubio_pitchspecacf_get_tolerance (const aubio_pitchspecacf_t * p)
 {
   return p->tol;
 }
--- a/src/pitch/pitchspecacf.h
+++ b/src/pitch/pitchspecacf.h
@@ -38,8 +38,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHSPECACF_H
-#define _AUBIO_PITCHSPECACF_H
+#ifndef AUBIO_PITCHSPECACF_H
+#define AUBIO_PITCHSPECACF_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -55,7 +55,7 @@
   \param cands_out pitch period candidates, in samples
 
 */
-void aubio_pitchspecacf_do (aubio_pitchspecacf_t * o, fvec_t * samples_in, fvec_t * cands_out);
+void aubio_pitchspecacf_do (aubio_pitchspecacf_t * o, const fvec_t * samples_in, fvec_t * cands_out);
 /** creation of the pitch detection object
 
   \param buf_size size of the input buffer to analyse
@@ -76,7 +76,7 @@
   \return tolerance parameter for minima selection [default 1.]
 
 */
-smpl_t aubio_pitchspecacf_get_tolerance (aubio_pitchspecacf_t * o);
+smpl_t aubio_pitchspecacf_get_tolerance (const aubio_pitchspecacf_t * o);
 
 /** set tolerance parameter for `specacf` pitch detection object
 
@@ -94,10 +94,10 @@
   \return confidence parameter
 
 */
-smpl_t aubio_pitchspecacf_get_confidence (aubio_pitchspecacf_t * o);
+smpl_t aubio_pitchspecacf_get_confidence (const aubio_pitchspecacf_t * o);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO_PITCHSPECACF_H */
+#endif /* AUBIO_PITCHSPECACF_H */
--- a/src/pitch/pitchyin.c
+++ b/src/pitch/pitchyin.c
@@ -40,26 +40,26 @@
 };
 
 /** compute difference function
-  
-  \param input input signal 
+
+  \param input input signal
   \param yinbuf output buffer to store difference function (half shorter than input)
 
 */
 void aubio_pitchyin_diff (fvec_t * input, fvec_t * yinbuf);
 
-/** in place computation of the YIN cumulative normalised function 
-  
-  \param yinbuf input signal (a square difference function), also used to store function 
+/** in place computation of the YIN cumulative normalised function
 
+  \param yinbuf input signal (a square difference function), also used to store function
+
 */
 void aubio_pitchyin_getcum (fvec_t * yinbuf);
 
 /** detect pitch in a YIN function
-  
+
   \param yinbuf input buffer as computed by aubio_pitchyin_getcum
 
 */
-uint_t aubio_pitchyin_getpitch (fvec_t * yinbuf);
+uint_t aubio_pitchyin_getpitch (const fvec_t * yinbuf);
 
 aubio_pitchyin_t *
 new_aubio_pitchyin (uint_t bufsize)
@@ -111,7 +111,7 @@
 }
 
 uint_t
-aubio_pitchyin_getpitch (fvec_t * yin)
+aubio_pitchyin_getpitch (const fvec_t * yin)
 {
   uint_t tau = 1;
   do {
@@ -130,7 +130,7 @@
 
 /* all the above in one */
 void
-aubio_pitchyin_do (aubio_pitchyin_t * o, fvec_t * input, fvec_t * out)
+aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * input, fvec_t * out)
 {
   smpl_t tol = o->tol;
   fvec_t *yin = o->yin;
--- a/src/pitch/pitchyin.h
+++ b/src/pitch/pitchyin.h
@@ -35,8 +35,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHYIN_H
-#define _AUBIO_PITCHYIN_H
+#ifndef AUBIO_PITCHYIN_H
+#define AUBIO_PITCHYIN_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -66,7 +66,7 @@
   \param cands_out pitch period candidates, in samples
 
 */
-void aubio_pitchyin_do (aubio_pitchyin_t * o, fvec_t * samples_in, fvec_t * cands_out);
+void aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * samples_in, fvec_t * cands_out);
 
 
 /** set tolerance parameter for YIN algorithm
@@ -97,4 +97,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCHYIN_H */
+#endif /* AUBIO_PITCHYIN_H */
--- a/src/pitch/pitchyinfft.c
+++ b/src/pitch/pitchyinfft.c
@@ -98,7 +98,7 @@
 }
 
 void
-aubio_pitchyinfft_do (aubio_pitchyinfft_t * p, fvec_t * input, fvec_t * output)
+aubio_pitchyinfft_do (aubio_pitchyinfft_t * p, const fvec_t * input, fvec_t * output)
 {
   uint_t tau, l;
   uint_t length = p->fftout->length;
@@ -107,9 +107,7 @@
   fvec_t *yin = p->yinfft;
   smpl_t tmp = 0., sum = 0.;
   // window the input
-  for (l = 0; l < input->length; l++) {
-    p->winput->data[l] = p->win->data[l] * input->data[l];
-  }
+  fvec_weighted_copy(input, p->win, p->winput);
   // get the real / imag parts of its fft
   aubio_fft_do_complex (p->fft, p->winput, fftout);
   // get the squared magnitude spectrum, applying some weight
--- a/src/pitch/pitchyinfft.h
+++ b/src/pitch/pitchyinfft.h
@@ -35,8 +35,8 @@
 
 */
 
-#ifndef _AUBIO_PITCHYINFFT_H
-#define _AUBIO_PITCHYINFFT_H
+#ifndef AUBIO_PITCHYINFFT_H
+#define AUBIO_PITCHYINFFT_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -52,7 +52,7 @@
   \param cands_out pitch period candidates, in samples
 
 */
-void aubio_pitchyinfft_do (aubio_pitchyinfft_t * o, fvec_t * samples_in, fvec_t * cands_out);
+void aubio_pitchyinfft_do (aubio_pitchyinfft_t * o, const fvec_t * samples_in, fvec_t * cands_out);
 /** creation of the pitch detection object
 
   \param samplerate samplerate of the input signal
@@ -96,4 +96,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PITCHYINFFT_H */
+#endif /* AUBIO_PITCHYINFFT_H */
--- a/src/spectral/fft.c
+++ b/src/spectral/fft.c
@@ -64,12 +64,12 @@
 
 #ifdef HAVE_FFTW3F
 #if HAVE_AUBIO_DOUBLE
-#warning "Using aubio in double precision with fftw3 in single precision"
+#error "Using aubio in double precision with fftw3 in single precision"
 #endif /* HAVE_AUBIO_DOUBLE */
 #define real_t float
-#else /* HAVE_FFTW3F */
+#elif defined (HAVE_FFTW3) /* HAVE_FFTW3F */
 #if !HAVE_AUBIO_DOUBLE
-#warning "Using aubio in single precision with fftw3 in double precision"
+#error "Using aubio in single precision with fftw3 in double precision"
 #endif /* HAVE_AUBIO_DOUBLE */
 #define real_t double
 #endif /* HAVE_FFTW3F */
@@ -143,8 +143,8 @@
 
 aubio_fft_t * new_aubio_fft (uint_t winsize) {
   aubio_fft_t * s = AUBIO_NEW(aubio_fft_t);
-  if ((sint_t)winsize < 1) {
-    AUBIO_ERR("fft: got winsize %d, but can not be < 1\n", winsize);
+  if ((sint_t)winsize < 2) {
+    AUBIO_ERR("fft: got winsize %d, but can not be < 2\n", winsize);
     goto beach;
   }
 #ifdef HAVE_FFTW3
@@ -230,17 +230,17 @@
   AUBIO_FREE(s);
 }
 
-void aubio_fft_do(aubio_fft_t * s, fvec_t * input, cvec_t * spectrum) {
+void aubio_fft_do(aubio_fft_t * s, const fvec_t * input, cvec_t * spectrum) {
   aubio_fft_do_complex(s, input, s->compspec);
   aubio_fft_get_spectrum(s->compspec, spectrum);
 }
 
-void aubio_fft_rdo(aubio_fft_t * s, cvec_t * spectrum, fvec_t * output) {
+void aubio_fft_rdo(aubio_fft_t * s, const cvec_t * spectrum, fvec_t * output) {
   aubio_fft_get_realimag(spectrum, s->compspec);
   aubio_fft_rdo_complex(s, s->compspec, output);
 }
 
-void aubio_fft_do_complex(aubio_fft_t * s, fvec_t * input, fvec_t * compspec) {
+void aubio_fft_do_complex(aubio_fft_t * s, const fvec_t * input, fvec_t * compspec) {
   uint_t i;
 #ifndef HAVE_MEMCPY_HACKS
   for (i=0; i < s->winsize; i++) {
@@ -291,7 +291,7 @@
 #endif /* HAVE_FFTW3 */
 }
 
-void aubio_fft_rdo_complex(aubio_fft_t * s, fvec_t * compspec, fvec_t * output) {
+void aubio_fft_rdo_complex(aubio_fft_t * s, const fvec_t * compspec, fvec_t * output) {
   uint_t i;
 #ifdef HAVE_FFTW3
   const smpl_t renorm = 1./(smpl_t)s->winsize;
@@ -346,17 +346,17 @@
 #endif /* HAVE_FFTW3 */
 }
 
-void aubio_fft_get_spectrum(fvec_t * compspec, cvec_t * spectrum) {
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum) {
   aubio_fft_get_phas(compspec, spectrum);
   aubio_fft_get_norm(compspec, spectrum);
 }
 
-void aubio_fft_get_realimag(cvec_t * spectrum, fvec_t * compspec) {
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec) {
   aubio_fft_get_imag(spectrum, compspec);
   aubio_fft_get_real(spectrum, compspec);
 }
 
-void aubio_fft_get_phas(fvec_t * compspec, cvec_t * spectrum) {
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum) {
   uint_t i;
   if (compspec->data[0] < 0) {
     spectrum->phas[0] = PI;
@@ -374,7 +374,7 @@
   }
 }
 
-void aubio_fft_get_norm(fvec_t * compspec, cvec_t * spectrum) {
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum) {
   uint_t i = 0;
   spectrum->norm[0] = ABS(compspec->data[0]);
   for (i=1; i < spectrum->length - 1; i++) {
@@ -385,7 +385,7 @@
     ABS(compspec->data[compspec->length/2]);
 }
 
-void aubio_fft_get_imag(cvec_t * spectrum, fvec_t * compspec) {
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec) {
   uint_t i;
   for (i = 1; i < ( compspec->length + 1 ) / 2 /*- 1 + 1*/; i++) {
     compspec->data[compspec->length - i] =
@@ -393,7 +393,7 @@
   }
 }
 
-void aubio_fft_get_real(cvec_t * spectrum, fvec_t * compspec) {
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec) {
   uint_t i;
   for (i = 0; i < compspec->length / 2 + 1; i++) {
     compspec->data[i] =
--- a/src/spectral/fft.h
+++ b/src/spectral/fft.h
@@ -31,8 +31,8 @@
 
 */
 
-#ifndef _AUBIO_FFT_H
-#define _AUBIO_FFT_H
+#ifndef AUBIO_FFT_H
+#define AUBIO_FFT_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -65,7 +65,7 @@
   \param spectrum output spectrum
 
 */
-void aubio_fft_do (aubio_fft_t *s, fvec_t * input, cvec_t * spectrum);
+void aubio_fft_do (aubio_fft_t *s, const fvec_t * input, cvec_t * spectrum);
 /** compute backward (inverse) FFT
 
   \param s fft object as returned by new_aubio_fft
@@ -73,7 +73,7 @@
   \param output output signal
 
 */
-void aubio_fft_rdo (aubio_fft_t *s, cvec_t * spectrum, fvec_t * output);
+void aubio_fft_rdo (aubio_fft_t *s, const cvec_t * spectrum, fvec_t * output);
 
 /** compute forward FFT
 
@@ -82,7 +82,7 @@
   \param compspec complex output fft real/imag
 
 */
-void aubio_fft_do_complex (aubio_fft_t *s, fvec_t * input, fvec_t * compspec);
+void aubio_fft_do_complex (aubio_fft_t *s, const fvec_t * input, fvec_t * compspec);
 /** compute backward (inverse) FFT from real/imag
 
   \param s fft object as returned by new_aubio_fft
@@ -90,7 +90,7 @@
   \param output real output array
 
 */
-void aubio_fft_rdo_complex (aubio_fft_t *s, fvec_t * compspec, fvec_t * output);
+void aubio_fft_rdo_complex (aubio_fft_t *s, const fvec_t * compspec, fvec_t * output);
 
 /** convert real/imag spectrum to norm/phas spectrum
 
@@ -98,7 +98,7 @@
   \param spectrum cvec norm/phas output array
 
 */
-void aubio_fft_get_spectrum(fvec_t * compspec, cvec_t * spectrum);
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum);
 /** convert real/imag spectrum to norm/phas spectrum
 
   \param compspec real/imag input fft array
@@ -105,7 +105,7 @@
   \param spectrum cvec norm/phas output array
 
 */
-void aubio_fft_get_realimag(cvec_t * spectrum, fvec_t * compspec);
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec);
 
 /** compute phas spectrum from real/imag parts
 
@@ -113,7 +113,7 @@
   \param spectrum cvec norm/phas output array
 
 */
-void aubio_fft_get_phas(fvec_t * compspec, cvec_t * spectrum);
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum);
 /** compute imaginary part from the norm/phas cvec
 
   \param spectrum norm/phas input array
@@ -120,7 +120,7 @@
   \param compspec real/imag output fft array
 
 */
-void aubio_fft_get_imag(cvec_t * spectrum, fvec_t * compspec);
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec);
 
 /** compute norm component from real/imag parts
 
@@ -128,7 +128,7 @@
   \param spectrum cvec norm/phas output array
 
 */
-void aubio_fft_get_norm(fvec_t * compspec, cvec_t * spectrum);
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum);
 /** compute real part from norm/phas components
 
   \param spectrum norm/phas input array
@@ -135,10 +135,10 @@
   \param compspec real/imag output fft array
 
 */
-void aubio_fft_get_real(cvec_t * spectrum, fvec_t * compspec);
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO_FFT_H */
+#endif /* AUBIO_FFT_H */
--- a/src/spectral/filterbank.c
+++ b/src/spectral/filterbank.c
@@ -56,36 +56,30 @@
 }
 
 void
-aubio_filterbank_do (aubio_filterbank_t * f, cvec_t * in, fvec_t * out)
+aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out)
 {
-  uint_t j, fn;
-
   /* apply filter to all input channel, provided out has enough channels */
-  uint_t max_filters = MIN (f->n_filters, out->length);
-  uint_t max_length = MIN (in->length, f->filters->length);
+  //uint_t max_filters = MIN (f->n_filters, out->length);
+  //uint_t max_length = MIN (in->length, f->filters->length);
 
-  /* reset all values in output vector */
-  fvec_zeros (out);
+  // view cvec->norm as fvec->data
+  fvec_t tmp;
+  tmp.length = in->length;
+  tmp.data = in->norm;
 
-  /* for each filter */
-  for (fn = 0; fn < max_filters; fn++) {
-    /* for each sample */
-    for (j = 0; j < max_length; j++) {
-      out->data[fn] += in->norm[j] * f->filters->data[fn][j];
-    }
-  }
+  fmat_vecmul(f->filters, &tmp, out);
 
   return;
 }
 
 fmat_t *
-aubio_filterbank_get_coeffs (aubio_filterbank_t * f)
+aubio_filterbank_get_coeffs (const aubio_filterbank_t * f)
 {
   return f->filters;
 }
 
 uint_t
-aubio_filterbank_set_coeffs (aubio_filterbank_t * f, fmat_t * filter_coeffs)
+aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filter_coeffs)
 {
   fmat_copy(filter_coeffs, f->filters);
   return 0;
--- a/src/spectral/filterbank.h
+++ b/src/spectral/filterbank.h
@@ -29,8 +29,8 @@
 
 */
 
-#ifndef _AUBIO_FILTERBANK_H
-#define _AUBIO_FILTERBANK_H
+#ifndef AUBIO_FILTERBANK_H
+#define AUBIO_FILTERBANK_H
 
 #ifdef __cplusplus
 extern "C"
@@ -66,7 +66,7 @@
   \param out output vector containing the energy found in each band, `nfilt` output values
 
 */
-void aubio_filterbank_do (aubio_filterbank_t * f, cvec_t * in, fvec_t * out);
+void aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out);
 
 /** return a pointer to the matrix object containing all filter coefficients
 
@@ -73,7 +73,7 @@
   \param f filterbank object, as returned by new_aubio_filterbank()
 
  */
-fmat_t *aubio_filterbank_get_coeffs (aubio_filterbank_t * f);
+fmat_t *aubio_filterbank_get_coeffs (const aubio_filterbank_t * f);
 
 /** copy filter coefficients to the filterbank
 
@@ -81,10 +81,10 @@
   \param filters filter bank coefficients to copy from
 
  */
-uint_t aubio_filterbank_set_coeffs (aubio_filterbank_t * f, fmat_t * filters);
+uint_t aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filters);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO_FILTERBANK_H */
+#endif /* AUBIO_FILTERBANK_H */
--- a/src/spectral/filterbank_mel.c
+++ b/src/spectral/filterbank_mel.c
@@ -29,7 +29,7 @@
 
 uint_t
 aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
-    fvec_t * freqs, smpl_t samplerate)
+    const fvec_t * freqs, smpl_t samplerate)
 {
 
   fmat_t *filters = aubio_filterbank_get_coeffs (fb);
--- a/src/spectral/filterbank_mel.h
+++ b/src/spectral/filterbank_mel.h
@@ -31,8 +31,8 @@
 
 */
 
-#ifndef _AUBIO_FILTERBANK_MEL_H
-#define _AUBIO_FILTERBANK_MEL_H
+#ifndef AUBIO_FILTERBANK_MEL_H
+#define AUBIO_FILTERBANK_MEL_H
 
 #ifdef __cplusplus
 extern "C"
@@ -50,7 +50,7 @@
 
 */
 uint_t aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
-    fvec_t * freqs, smpl_t samplerate);
+    const fvec_t * freqs, smpl_t samplerate);
 
 /** filterbank initialization for Mel filters using Slaney's coefficients
 
@@ -69,4 +69,4 @@
 }
 #endif
 
-#endif /* _AUBIO_FILTERBANK_MEL_H */
+#endif /* AUBIO_FILTERBANK_MEL_H */
--- a/src/spectral/mfcc.c
+++ b/src/spectral/mfcc.c
@@ -67,21 +67,21 @@
   /* allocating buffers */
   mfcc->in_dct = new_fvec (n_filters);
 
-  mfcc->dct_coeffs = new_fmat (n_filters, n_coefs);
+  mfcc->dct_coeffs = new_fmat (n_coefs, n_filters);
 
-  /* compute DCT transform dct_coeffs[i][j] as
+  /* compute DCT transform dct_coeffs[j][i] as
      cos ( j * (i+.5) * PI / n_filters ) */
   scaling = 1. / SQRT (n_filters / 2.);
   for (i = 0; i < n_filters; i++) {
     for (j = 0; j < n_coefs; j++) {
-      mfcc->dct_coeffs->data[i][j] =
+      mfcc->dct_coeffs->data[j][i] =
           scaling * COS (j * (i + 0.5) * PI / n_filters);
     }
-    mfcc->dct_coeffs->data[i][0] *= SQRT (2.) / 2.;
+    mfcc->dct_coeffs->data[0][i] *= SQRT (2.) / 2.;
   }
 
   return mfcc;
-};
+}
 
 void
 del_aubio_mfcc (aubio_mfcc_t * mf)
@@ -100,10 +100,8 @@
 
 
 void
-aubio_mfcc_do (aubio_mfcc_t * mf, cvec_t * in, fvec_t * out)
+aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out)
 {
-  uint_t j, k;
-
   /* compute filterbank */
   aubio_filterbank_do (mf->fb, in, mf->in_dct);
 
@@ -113,16 +111,8 @@
   /* raise power */
   //fvec_pow (mf->in_dct, 3.);
 
-  /* zeros output */
-  fvec_zeros(out);
-
-  /* compute discrete cosine transform */
-  for (j = 0; j < mf->n_filters; j++) {
-    for (k = 0; k < mf->n_coefs; k++) {
-      out->data[k] += mf->in_dct->data[j]
-          * mf->dct_coeffs->data[j][k];
-    }
-  }
+  /* compute mfccs */
+  fmat_vecmul(mf->dct_coeffs, mf->in_dct, out);
 
   return;
 }
--- a/src/spectral/mfcc.h
+++ b/src/spectral/mfcc.h
@@ -34,8 +34,8 @@
 
 */
 
-#ifndef _AUBIO_MFCC_H
-#define _AUBIO_MFCC_H
+#ifndef AUBIO_MFCC_H
+#define AUBIO_MFCC_H
 
 #ifdef __cplusplus
 extern "C"
@@ -70,10 +70,10 @@
   \param out output mel coefficients buffer (n_coeffs long)
 
 */
-void aubio_mfcc_do (aubio_mfcc_t * mf, cvec_t * in, fvec_t * out);
+void aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _AUBIO_MFCC_H */
+#endif /* AUBIO_MFCC_H */
--- a/src/spectral/phasevoc.c
+++ b/src/spectral/phasevoc.c
@@ -44,12 +44,12 @@
 
 
 /** returns data and dataold slided by hop_s */
-static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, fvec_t *new);
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new);
 
 /** do additive synthesis from 'old' and 'cur' */
 static void aubio_pvoc_addsynth(aubio_pvoc_t *pv, fvec_t * synthnew);
 
-void aubio_pvoc_do(aubio_pvoc_t *pv, fvec_t * datanew, cvec_t *fftgrain) {
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t * datanew, cvec_t *fftgrain) {
   /* slide  */
   aubio_pvoc_swapbuffers(pv, datanew);
   /* windowing */
@@ -64,7 +64,12 @@
   /* calculate rfft */
   aubio_fft_rdo(pv->fft,fftgrain,pv->synth);
   /* unshift */
-  fvec_shift(pv->synth);
+  fvec_ishift(pv->synth);
+  /* windowing */
+  // if overlap = 50%, do not apply window (identity)
+  if (pv->hop_s * 2 < pv->win_s) {
+    fvec_weight(pv->synth, pv->w);
+  }
   /* additive synthesis */
   aubio_pvoc_addsynth(pv, synthnew);
 }
@@ -79,8 +84,8 @@
   if ((sint_t)hop_s < 1) {
     AUBIO_ERR("pvoc: got hop_size %d, but can not be < 1\n", hop_s);
     goto beach;
-  } else if ((sint_t)win_s < 1) {
-    AUBIO_ERR("pvoc: got buffer_size %d, but can not be < 1\n", win_s);
+  } else if ((sint_t)win_s < 2) {
+    AUBIO_ERR("pvoc: got buffer_size %d, but can not be < 2\n", win_s);
     goto beach;
   } else if (win_s < hop_s) {
     AUBIO_ERR("pvoc: hop size (%d) is larger than win size (%d)\n", win_s, hop_s);
@@ -88,6 +93,9 @@
   }
 
   pv->fft      = new_aubio_fft (win_s);
+  if (pv->fft == NULL) {
+    goto beach;
+  }
 
   /* remember old */
   pv->data     = new_fvec (win_s);
@@ -117,7 +125,16 @@
   pv->end_datasize = pv->end * sizeof(smpl_t);
   pv->hop_datasize = pv->hop_s * sizeof(smpl_t);
 
-  pv->scale = pv->hop_s * 2. / pv->win_s;
+  // for reconstruction with 75% overlap
+  if (win_s == hop_s * 4) {
+    pv->scale = 2./3.;
+  } else if (win_s == hop_s * 8) {
+    pv->scale = 1./3.;
+  } else if (win_s == hop_s * 2) {
+    pv->scale = 1.;
+  } else {
+    pv->scale = .5;
+  }
 
   return pv;
 
@@ -136,13 +153,13 @@
   AUBIO_FREE(pv);
 }
 
-static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, fvec_t *new)
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new)
 {
   /* some convenience pointers */
   smpl_t * data = pv->data->data;
   smpl_t * dataold = pv->dataold->data;
   smpl_t * datanew = new->data;
-#if !HAVE_MEMCPY_HACKS
+#ifndef HAVE_MEMCPY_HACKS
   uint_t i;
   for (i = 0; i < pv->end; i++)
     data[i] = dataold[i];
--- a/src/spectral/phasevoc.h
+++ b/src/spectral/phasevoc.h
@@ -31,8 +31,8 @@
 
 */
 
-#ifndef _AUBIO_PHASEVOC_H
-#define _AUBIO_PHASEVOC_H
+#ifndef AUBIO_PHASEVOC_H
+#define AUBIO_PHASEVOC_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -67,7 +67,7 @@
   \param fftgrain output spectral frame
 
 */
-void aubio_pvoc_do(aubio_pvoc_t *pv, fvec_t *in, cvec_t * fftgrain);
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t *in, cvec_t * fftgrain);
 /** compute signal from spectral frame
 
   This function takes an input spectral frame fftgrain of size
@@ -99,4 +99,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PHASEVOC_H */
+#endif /* AUBIO_PHASEVOC_H */
--- a/src/spectral/specdesc.c
+++ b/src/spectral/specdesc.c
@@ -26,28 +26,28 @@
 #include "mathutils.h"
 #include "utils/hist.h"
 
-void aubio_specdesc_energy(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_hfc(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_complex(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_phase(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_specdiff(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_kl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_mkl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
-void aubio_specdesc_specflux(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_energy(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_hfc(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_complex(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_phase(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specdiff(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
 
-extern void aubio_specdesc_centroid (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_spread (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_skewness (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_kurtosis (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_slope (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_decrease (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-extern void aubio_specdesc_rolloff (aubio_specdesc_t * o, cvec_t * spec,
+extern void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
 
 /** onsetdetection types */
@@ -75,7 +75,7 @@
   aubio_specdesc_type onset_type; /**< onset detection type */
   /** Pointer to aubio_specdesc_<type> function */
   void (*funcpointer)(aubio_specdesc_t *o,
-      cvec_t * fftgrain, fvec_t * onset);
+      const cvec_t * fftgrain, fvec_t * onset);
   smpl_t threshold;      /**< minimum norm threshold for phase and specdiff */
   fvec_t *oldmag;        /**< previous norm vector */
   fvec_t *dev1 ;         /**< current onset detection measure vector */
@@ -87,7 +87,7 @@
 
 /* Energy based onset detection function */
 void aubio_specdesc_energy  (aubio_specdesc_t *o UNUSED,
-    cvec_t * fftgrain, fvec_t * onset) {
+    const cvec_t * fftgrain, fvec_t * onset) {
   uint_t j;
   onset->data[0] = 0.;
   for (j=0;j<fftgrain->length;j++) {
@@ -97,7 +97,7 @@
 
 /* High Frequency Content onset detection function */
 void aubio_specdesc_hfc(aubio_specdesc_t *o UNUSED,
-    cvec_t * fftgrain, fvec_t * onset){
+    const cvec_t * fftgrain, fvec_t * onset){
   uint_t j;
   onset->data[0] = 0.;
   for (j=0;j<fftgrain->length;j++) {
@@ -107,7 +107,7 @@
 
 
 /* Complex Domain Method onset detection function */
-void aubio_specdesc_complex (aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset) {
+void aubio_specdesc_complex (aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset) {
   uint_t j;
   uint_t nbins = fftgrain->length;
   onset->data[0] = 0.;
@@ -131,7 +131,7 @@
 
 /* Phase Based Method onset detection function */
 void aubio_specdesc_phase(aubio_specdesc_t *o, 
-    cvec_t * fftgrain, fvec_t * onset){
+    const cvec_t * fftgrain, fvec_t * onset){
   uint_t j;
   uint_t nbins = fftgrain->length;
   onset->data[0] = 0.0;
@@ -161,7 +161,7 @@
 
 /* Spectral difference method onset detection function */
 void aubio_specdesc_specdiff(aubio_specdesc_t *o,
-    cvec_t * fftgrain, fvec_t * onset){
+    const cvec_t * fftgrain, fvec_t * onset){
   uint_t j;
   uint_t nbins = fftgrain->length;
     onset->data[0] = 0.0;
@@ -188,7 +188,7 @@
 /* Kullback Liebler onset detection function
  * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid 
  * negative (1.+) and infinite values (+1.e-10) */
-void aubio_specdesc_kl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset){
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
   uint_t j;
     onset->data[0] = 0.;
     for (j=0;j<fftgrain->length;j++) {
@@ -202,7 +202,7 @@
 /* Modified Kullback Liebler onset detection function
  * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid 
  * negative (1.+) and infinite values (+1.e-10) */
-void aubio_specdesc_mkl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset){
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
   uint_t j;
     onset->data[0] = 0.;
     for (j=0;j<fftgrain->length;j++) {
@@ -213,7 +213,7 @@
 }
 
 /* Spectral flux */
-void aubio_specdesc_specflux(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset){ 
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){ 
   uint_t j;
   onset->data[0] = 0.;
   for (j=0;j<fftgrain->length;j++) {
@@ -225,7 +225,7 @@
 
 /* Generic function pointing to the choosen one */
 void 
-aubio_specdesc_do (aubio_specdesc_t *o, cvec_t * fftgrain, 
+aubio_specdesc_do (aubio_specdesc_t *o, const cvec_t * fftgrain, 
     fvec_t * onset) {
   o->funcpointer(o,fftgrain,onset);
 }
@@ -234,7 +234,7 @@
  * depending on the choosen type, allocate memory as needed
  */
 aubio_specdesc_t * 
-new_aubio_specdesc (char_t * onset_mode, uint_t size){
+new_aubio_specdesc (const char_t * onset_mode, uint_t size){
   aubio_specdesc_t * o = AUBIO_NEW(aubio_specdesc_t);
   uint_t rsize = size/2+1;
   aubio_specdesc_type onset_type;
--- a/src/spectral/specdesc.h
+++ b/src/spectral/specdesc.h
@@ -145,8 +145,8 @@
 */
 
 
-#ifndef _AUBIO_SPECDESC_H
-#define _AUBIO_SPECDESC_H
+#ifndef AUBIO_SPECDESC_H
+#define AUBIO_SPECDESC_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -164,7 +164,7 @@
   \param desc output vector (one sample long, to send to the peak picking)
 
 */
-void aubio_specdesc_do (aubio_specdesc_t * o, cvec_t * fftgrain,
+void aubio_specdesc_do (aubio_specdesc_t * o, const cvec_t * fftgrain,
     fvec_t * desc);
 
 /** creation of a spectral description object
@@ -178,7 +178,7 @@
     - `centroid`, `spread`, `skewness`, `kurtosis`, `slope`, `decrease`, `rolloff`
 
 */
-aubio_specdesc_t *new_aubio_specdesc (char_t * method, uint_t buf_size);
+aubio_specdesc_t *new_aubio_specdesc (const char_t * method, uint_t buf_size);
 
 /** deletion of a spectral descriptor
 
@@ -191,4 +191,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SPECDESC_H */
+#endif /* AUBIO_SPECDESC_H */
--- a/src/spectral/statistics.c
+++ b/src/spectral/statistics.c
@@ -22,29 +22,29 @@
 #include "cvec.h"
 #include "spectral/specdesc.h"
 
-void aubio_specdesc_centroid (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_spread (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_skewness (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_kurtosis (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_slope (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_decrease (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
-void aubio_specdesc_rolloff (aubio_specdesc_t * o, cvec_t * spec,
+void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
     fvec_t * desc);
 
 
-smpl_t cvec_sum (cvec_t * s);
-smpl_t cvec_mean (cvec_t * s);
-smpl_t cvec_centroid (cvec_t * s);
-smpl_t cvec_moment (cvec_t * s, uint_t moment);
+smpl_t cvec_sum (const cvec_t * s);
+smpl_t cvec_mean (const cvec_t * s);
+smpl_t cvec_centroid (const cvec_t * s);
+smpl_t cvec_moment (const cvec_t * s, uint_t moment);
 
 smpl_t
-cvec_sum (cvec_t * s)
+cvec_sum (const cvec_t * s)
 {
   uint_t j;
   smpl_t tmp = 0.0;
@@ -55,13 +55,13 @@
 }
 
 smpl_t
-cvec_mean (cvec_t * s)
+cvec_mean (const cvec_t * s)
 {
   return cvec_sum (s) / (smpl_t) (s->length);
 }
 
 smpl_t
-cvec_centroid (cvec_t * spec)
+cvec_centroid (const cvec_t * spec)
 {
   smpl_t sum = 0., sc = 0.;
   uint_t j;
@@ -77,7 +77,7 @@
 }
 
 smpl_t
-cvec_moment (cvec_t * spec, uint_t order)
+cvec_moment (const cvec_t * spec, uint_t order)
 {
   smpl_t sum = 0., centroid = 0., sc = 0.;
   uint_t j;
@@ -94,7 +94,7 @@
 }
 
 void
-aubio_specdesc_centroid (aubio_specdesc_t * o UNUSED, cvec_t * spec,
+aubio_specdesc_centroid (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   desc->data[0] = cvec_centroid (spec); 
@@ -101,7 +101,7 @@
 }
 
 void
-aubio_specdesc_spread (aubio_specdesc_t * o UNUSED, cvec_t * spec,
+aubio_specdesc_spread (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   desc->data[0] = cvec_moment (spec, 2);
@@ -108,7 +108,7 @@
 }
 
 void
-aubio_specdesc_skewness (aubio_specdesc_t * o UNUSED, cvec_t * spec,
+aubio_specdesc_skewness (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   smpl_t spread;
@@ -122,7 +122,7 @@
 }
 
 void
-aubio_specdesc_kurtosis (aubio_specdesc_t * o UNUSED, cvec_t * spec,
+aubio_specdesc_kurtosis (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   smpl_t spread;
@@ -136,7 +136,7 @@
 }
 
 void
-aubio_specdesc_slope (aubio_specdesc_t * o UNUSED, cvec_t * spec,
+aubio_specdesc_slope (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   uint_t j;
@@ -164,7 +164,7 @@
 }
 
 void
-aubio_specdesc_decrease (aubio_specdesc_t *o UNUSED, cvec_t * spec,
+aubio_specdesc_decrease (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
     fvec_t * desc)
 {
   uint_t j; smpl_t sum;
@@ -182,7 +182,7 @@
 }
 
 void
-aubio_specdesc_rolloff (aubio_specdesc_t *o UNUSED, cvec_t * spec,
+aubio_specdesc_rolloff (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
     fvec_t *desc)
 {
   uint_t j; smpl_t cumsum, rollsum;
--- a/src/spectral/tss.c
+++ b/src/spectral/tss.c
@@ -40,7 +40,7 @@
   fvec_t *dev;
 };
 
-void aubio_tss_do(aubio_tss_t *o, cvec_t * input, 
+void aubio_tss_do(aubio_tss_t *o, const cvec_t * input,
     cvec_t * trans, cvec_t * stead)
 {
   uint_t j;
--- a/src/spectral/tss.h
+++ b/src/spectral/tss.h
@@ -36,8 +36,8 @@
 
 */
 
-#ifndef _AUBIO_TSS_H
-#define _AUBIO_TSS_H
+#ifndef AUBIO_TSS_H
+#define AUBIO_TSS_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -69,7 +69,7 @@
   \param stead output steady state components
 
 */
-void aubio_tss_do (aubio_tss_t * o, cvec_t * input, cvec_t * trans,
+void aubio_tss_do (aubio_tss_t * o, const cvec_t * input, cvec_t * trans,
     cvec_t * stead);
 
 /** set transient / steady state separation threshold
@@ -100,4 +100,4 @@
 }
 #endif
 
-#endif /* _AUBIO_TSS_H */
+#endif /* AUBIO_TSS_H */
--- a/src/synth/sampler.c
+++ b/src/synth/sampler.c
@@ -55,10 +55,14 @@
   return NULL;
 }
 
-uint_t aubio_sampler_load( aubio_sampler_t * o, char_t * uri )
+uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri )
 {
   if (o->source) del_aubio_source(o->source);
-  o->uri = uri;
+
+  if (o->uri) AUBIO_FREE(o->uri);
+  o->uri = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX));
+  strncpy(o->uri, uri, strnlen(uri, PATH_MAX));
+
   o->source = new_aubio_source(uri, o->samplerate, o->blocksize);
   if (o->source) return 0;
   AUBIO_ERR("sampler: failed loading %s", uri);
@@ -65,7 +69,7 @@
   return 1;
 }
 
-void aubio_sampler_do ( aubio_sampler_t * o, fvec_t * input, fvec_t * output)
+void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output)
 {
   uint_t read = 0, i;
   if (o->playing) {
@@ -82,7 +86,7 @@
   }
 }
 
-void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * input, fmat_t * output)
+void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output)
 {
   uint_t read = 0, i, j;
   if (o->playing) {
@@ -103,7 +107,7 @@
   }
 }
 
-uint_t aubio_sampler_get_playing ( aubio_sampler_t * o )
+uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o )
 {
   return o->playing;
 }
@@ -130,6 +134,7 @@
   if (o->source) {
     del_aubio_source(o->source);
   }
+  if (o->uri) AUBIO_FREE(o->uri);
   del_fvec(o->source_output);
   del_fmat(o->source_output_multi);
   AUBIO_FREE(o);
--- a/src/synth/sampler.h
+++ b/src/synth/sampler.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_SAMPLER_H
-#define _AUBIO_SAMPLER_H
+#ifndef AUBIO_SAMPLER_H
+#define AUBIO_SAMPLER_H
 
 /** \file
 
@@ -59,7 +59,7 @@
   \return 0 if successful, non-zero otherwise
 
 */
-uint_t aubio_sampler_load( aubio_sampler_t * o, char_t * uri );
+uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri );
 
 /** process sampler function
 
@@ -73,7 +73,7 @@
 are added to the output.
 
 */
-void aubio_sampler_do ( aubio_sampler_t * o, fvec_t * input, fvec_t * output);
+void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output);
 
 /** process sampler function, multiple channels
 
@@ -87,7 +87,7 @@
 are added to the output.
 
 */
-void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * input, fmat_t * output);
+void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output);
 
 /** get current playing state
 
@@ -96,7 +96,7 @@
   \return 0 if not playing, 1 if playing
 
 */
-uint_t aubio_sampler_get_playing ( aubio_sampler_t * o );
+uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o );
 
 /** set current playing state
 
@@ -137,4 +137,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SAMPLER_H */
+#endif /* AUBIO_SAMPLER_H */
--- a/src/synth/wavetable.c
+++ b/src/synth/wavetable.c
@@ -68,7 +68,7 @@
   return NULL;
 }
 
-static smpl_t interp_2(fvec_t *input, smpl_t pos) {
+static smpl_t interp_2(const fvec_t *input, smpl_t pos) {
   uint_t idx = (uint_t)FLOOR(pos);
   smpl_t frac = pos - (smpl_t)idx;
   smpl_t a = input->data[idx];
@@ -76,7 +76,7 @@
   return a + frac * ( b - a );
 }
 
-void aubio_wavetable_do ( aubio_wavetable_t * s, fvec_t * input, fvec_t * output)
+void aubio_wavetable_do ( aubio_wavetable_t * s, const fvec_t * input, fvec_t * output)
 {
   uint_t i;
   if (s->playing) {
@@ -107,7 +107,7 @@
   }
 }
 
-void aubio_wavetable_do_multi ( aubio_wavetable_t * s, fmat_t * input, fmat_t * output)
+void aubio_wavetable_do_multi ( aubio_wavetable_t * s, const fmat_t * input, fmat_t * output)
 {
   uint_t i, j;
   if (s->playing) {
@@ -142,7 +142,7 @@
   }
 }
 
-uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * s )
+uint_t aubio_wavetable_get_playing ( const aubio_wavetable_t * s )
 {
   return s->playing;
 }
@@ -172,7 +172,7 @@
   return aubio_parameter_set_target_value ( s->freq, freq );
 }
 
-smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * s) {
+smpl_t aubio_wavetable_get_freq ( const aubio_wavetable_t * s) {
   return aubio_parameter_get_current_value ( s->freq);
 }
 
@@ -181,7 +181,7 @@
   return aubio_parameter_set_target_value ( s->amp, amp );
 }
 
-smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * s) {
+smpl_t aubio_wavetable_get_amp ( const aubio_wavetable_t * s) {
   return aubio_parameter_get_current_value ( s->amp );
 }
 
--- a/src/synth/wavetable.h
+++ b/src/synth/wavetable.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_WAVETABLE_H
-#define _AUBIO_WAVETABLE_H
+#ifndef AUBIO_WAVETABLE_H
+#define AUBIO_WAVETABLE_H
 
 /** \file
 
@@ -59,7 +59,7 @@
   \return 0 if successful, non-zero otherwise
 
 */
-uint_t aubio_wavetable_load( aubio_wavetable_t * o, char_t * uri );
+uint_t aubio_wavetable_load( aubio_wavetable_t * o, const char_t * uri );
 
 /** process wavetable function
 
@@ -73,7 +73,7 @@
 are added to the output.
 
 */
-void aubio_wavetable_do ( aubio_wavetable_t * o, fvec_t * input, fvec_t * output);
+void aubio_wavetable_do ( aubio_wavetable_t * o, const fvec_t * input, fvec_t * output);
 
 /** process wavetable function, multiple channels
 
@@ -87,7 +87,7 @@
 are added to the output.
 
 */
-void aubio_wavetable_do_multi ( aubio_wavetable_t * o, fmat_t * input, fmat_t * output);
+void aubio_wavetable_do_multi ( aubio_wavetable_t * o, const fmat_t * input, fmat_t * output);
 
 /** get current playing state
 
@@ -96,7 +96,7 @@
   \return 0 if not playing, 1 if playing
 
 */
-uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * o );
+uint_t aubio_wavetable_get_playing ( const aubio_wavetable_t * o );
 
 /** set current playing state
 
@@ -143,7 +143,7 @@
   \return current frequency, in Hz
 
 */
-smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * o);
+smpl_t aubio_wavetable_get_freq ( const aubio_wavetable_t * o);
 
 /** set wavetable amplitude
 
@@ -162,7 +162,7 @@
   \return current amplitude
 
 */
-smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * o);
+smpl_t aubio_wavetable_get_amp ( const aubio_wavetable_t * o);
 
 /** destroy aubio_wavetable_t object
 
@@ -175,4 +175,4 @@
 }
 #endif
 
-#endif /* _AUBIO_WAVETABLE_H */
+#endif /* AUBIO_WAVETABLE_H */
--- a/src/tempo/beattracking.c
+++ b/src/tempo/beattracking.c
@@ -123,7 +123,7 @@
 
 
 void
-aubio_beattracking_do (aubio_beattracking_t * bt, fvec_t * dfframe,
+aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframe,
     fvec_t * output)
 {
 
@@ -409,10 +409,22 @@
 }
 
 smpl_t
-aubio_beattracking_get_bpm (aubio_beattracking_t * bt)
+aubio_beattracking_get_period (const aubio_beattracking_t * bt)
 {
+  return bt->hop_size * bt->bp;
+}
+
+smpl_t
+aubio_beattracking_get_period_s (const aubio_beattracking_t * bt)
+{
+  return aubio_beattracking_get_period(bt) / (smpl_t) bt->samplerate;
+}
+
+smpl_t
+aubio_beattracking_get_bpm (const aubio_beattracking_t * bt)
+{
   if (bt->bp != 0) {
-    return 60. * bt->samplerate/ bt->bp / bt->hop_size;
+    return 60. / aubio_beattracking_get_period_s(bt);
   } else {
     return 0.;
   }
@@ -419,7 +431,7 @@
 }
 
 smpl_t
-aubio_beattracking_get_confidence (aubio_beattracking_t * bt)
+aubio_beattracking_get_confidence (const aubio_beattracking_t * bt)
 {
   if (bt->gp) {
     smpl_t acf_sum = fvec_sum(bt->acfout);
--- a/src/tempo/beattracking.h
+++ b/src/tempo/beattracking.h
@@ -36,8 +36,8 @@
   \example tempo/test-beattracking.c
 
 */
-#ifndef _AUBIO_BEATTRACKING_H
-#define _AUBIO_BEATTRACKING_H
+#ifndef AUBIO_BEATTRACKING_H
+#define AUBIO_BEATTRACKING_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,9 +64,29 @@
   \param out stored detected beat locations
 
 */
-void aubio_beattracking_do (aubio_beattracking_t * bt, fvec_t * dfframes,
+void aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframes,
     fvec_t * out);
 
+/** get current beat period in samples
+
+  \param bt beat tracking object
+
+  Returns the currently observed period, in samples, or 0 if no consistent
+  value is found.
+
+*/
+smpl_t aubio_beattracking_get_period (const aubio_beattracking_t * bt);
+
+/** get current beat period in seconds
+
+  \param bt beat tracking object
+
+  Returns the currently observed period, in seconds, or 0 if no consistent
+  value is found.
+
+*/
+smpl_t aubio_beattracking_get_period_s (const aubio_beattracking_t * bt);
+
 /** get current tempo in bpm
 
   \param bt beat tracking object
@@ -75,7 +95,7 @@
   consistent value is found.
 
 */
-smpl_t aubio_beattracking_get_bpm(aubio_beattracking_t * bt);
+smpl_t aubio_beattracking_get_bpm(const aubio_beattracking_t * bt);
 
 /** get current tempo confidence
 
@@ -85,7 +105,7 @@
   consistent value is found.
 
 */
-smpl_t aubio_beattracking_get_confidence(aubio_beattracking_t * bt);
+smpl_t aubio_beattracking_get_confidence(const aubio_beattracking_t * bt);
 
 /** delete beat tracking object
 
@@ -98,4 +118,4 @@
 }
 #endif
 
-#endif /* _AUBIO_BEATTRACKING_H */
+#endif /* AUBIO_BEATTRACKING_H */
--- a/src/tempo/tempo.c
+++ b/src/tempo/tempo.c
@@ -28,27 +28,6 @@
 #include "mathutils.h"
 #include "tempo/tempo.h"
 
-// TODO implement get/set_delay
-
-/** set current delay
-
-  \param o beat tracking object
-
-  \return current delay, in samples
-
- */
-uint_t aubio_tempo_get_delay(aubio_tempo_t * o);
-
-/** set current delay
-
-  \param o beat tracking object
-  \param delay delay to set tempo to, in samples
-
-  \return `0` if successful, non-zero otherwise
-
- */
-uint_t aubio_tempo_set_delay(aubio_tempo_t * o, uint_t delay);
-
 /* structure to store object state */
 struct _aubio_tempo_t {
   aubio_specdesc_t * od;   /** onset detection */
@@ -64,16 +43,18 @@
   smpl_t threshold;              /** peak picking threshold */
   sint_t blockpos;               /** current position in dfframe */
   uint_t winlen;                 /** dfframe bufsize */
-  uint_t step;                   /** dfframe hopsize */ 
-  uint_t samplerate;             /** sampling rate of the signal */ 
+  uint_t step;                   /** dfframe hopsize */
+  uint_t samplerate;             /** sampling rate of the signal */
   uint_t hop_size;               /** get hop_size */
   uint_t total_frames;           /** total frames since beginning */
   uint_t last_beat;              /** time of latest detected beat, in samples */
-  uint_t delay;                  /** delay to remove to last beat, in samples */
+  sint_t delay;                  /** delay to remove to last beat, in samples */
+  uint_t last_tatum;             /** time of latest detected tatum, in samples */
+  uint_t tatum_signature;        /** number of tatum between each beats */
 };
 
 /* execute tempo detection function on iput buffer */
-void aubio_tempo_do(aubio_tempo_t *o, fvec_t * input, fvec_t * tempo)
+void aubio_tempo_do(aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo)
 {
   uint_t i;
   uint_t winlen = o->winlen;
@@ -90,20 +71,21 @@
     /* check dfframe */
     aubio_beattracking_do(o->bt,o->dfframe,o->out);
     /* rotate dfframe */
-    for (i = 0 ; i < winlen - step; i++ ) 
+    for (i = 0 ; i < winlen - step; i++ )
       o->dfframe->data[i] = o->dfframe->data[i+step];
-    for (i = winlen - step ; i < winlen; i++ ) 
+    for (i = winlen - step ; i < winlen; i++ )
       o->dfframe->data[i] = 0.;
     o->blockpos = -1;
   }
   o->blockpos++;
   aubio_peakpicker_do (o->pp, o->of, o->onset);
-  tempo->data[1] = o->onset->data[0];
+  // store onset detection function in second sample of vector
+  //tempo->data[1] = o->onset->data[0];
   thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
   o->dfframe->data[winlen - step + o->blockpos] = thresholded->data[0];
   /* end of second level loop */
   tempo->data[0] = 0; /* reset tactus */
-  i=0;
+  //i=0;
   for (i = 1; i < o->out->data[0]; i++ ) {
     /* if current frame is a predicted tactus */
     if (o->blockpos == FLOOR(o->out->data[i])) {
@@ -113,6 +95,7 @@
         tempo->data[0] = 0; // unset beat if silent
       }
       o->last_beat = o->total_frames + (uint_t)ROUND(tempo->data[0] * o->hop_size);
+      o->last_tatum = o->last_beat;
     }
   }
   o->total_frames += o->hop_size;
@@ -121,7 +104,7 @@
 
 uint_t aubio_tempo_get_last (aubio_tempo_t *o)
 {
-  return o->last_beat - o->delay;
+  return o->last_beat + o->delay;
 }
 
 smpl_t aubio_tempo_get_last_s (aubio_tempo_t *o)
@@ -134,15 +117,33 @@
   return aubio_tempo_get_last_s (o) * 1000.;
 }
 
-uint_t aubio_tempo_set_delay(aubio_tempo_t * o, uint_t delay) {
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay) {
   o->delay = delay;
   return AUBIO_OK;
 }
 
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay) {
+  o->delay = delay * o->samplerate;
+  return AUBIO_OK;
+}
+
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay) {
+  o->delay = 1000. * delay * o->samplerate;
+  return AUBIO_OK;
+}
+
 uint_t aubio_tempo_get_delay(aubio_tempo_t * o) {
   return o->delay;
 }
 
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o) {
+  return o->delay / (smpl_t)(o->samplerate);
+}
+
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o) {
+  return o->delay / (smpl_t)(o->samplerate) / 1000.;
+}
+
 uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence) {
   o->silence = silence;
   return AUBIO_OK;
@@ -163,7 +164,7 @@
 }
 
 /* Allocate memory for an tempo detection */
-aubio_tempo_t * new_aubio_tempo (char_t * tempo_mode,
+aubio_tempo_t * new_aubio_tempo (const char_t * tempo_mode,
     uint_t buf_size, uint_t hop_size, uint_t samplerate)
 {
   aubio_tempo_t * o = AUBIO_NEW(aubio_tempo_t);
@@ -173,8 +174,8 @@
   if ((sint_t)hop_size < 1) {
     AUBIO_ERR("tempo: got hop size %d, but can not be < 1\n", hop_size);
     goto beach;
-  } else if ((sint_t)buf_size < 1) {
-    AUBIO_ERR("tempo: got window size %d, but can not be < 1\n", buf_size);
+  } else if ((sint_t)buf_size < 2) {
+    AUBIO_ERR("tempo: got window size %d, but can not be < 2\n", buf_size);
     goto beach;
   } else if (buf_size < hop_size) {
     AUBIO_ERR("tempo: hop size (%d) is larger than window size (%d)\n", buf_size, hop_size);
@@ -214,6 +215,8 @@
     o2 = new_aubio_specdesc(type_onset2,buffer_size);
     onset2 = new_fvec(1);
   }*/
+  o->last_tatum = 0;
+  o->tatum_signature = 4;
   return o;
 
 beach:
@@ -225,8 +228,51 @@
   return aubio_beattracking_get_bpm(o->bt);
 }
 
+smpl_t aubio_tempo_get_period (aubio_tempo_t *o)
+{
+  return aubio_beattracking_get_period (o->bt);
+}
+
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t *o)
+{
+  return aubio_beattracking_get_period_s (o->bt);
+}
+
 smpl_t aubio_tempo_get_confidence(aubio_tempo_t *o) {
   return aubio_beattracking_get_confidence(o->bt);
+}
+
+uint_t aubio_tempo_was_tatum (aubio_tempo_t *o)
+{
+  uint_t last_tatum_distance = o->total_frames - o->last_tatum;
+  smpl_t beat_period = aubio_tempo_get_period(o);
+  smpl_t tatum_period = beat_period / o->tatum_signature;
+  if (last_tatum_distance < o->hop_size) {
+    o->last_tatum = o->last_beat;
+    return 2;
+  }
+  else if (last_tatum_distance > tatum_period) {
+    if ( last_tatum_distance + o->hop_size > beat_period ) {
+      // next beat is too close, pass
+      return 0;
+    }
+    o->last_tatum = o->total_frames;
+    return 1;
+  }
+  return 0;
+}
+
+smpl_t aubio_tempo_get_last_tatum (aubio_tempo_t *o) {
+  return (smpl_t)o->last_tatum - o->delay;
+}
+
+uint_t aubio_tempo_set_tatum_signature (aubio_tempo_t *o, uint_t signature) {
+  if (signature < 1 || signature > 64) {
+    return AUBIO_FAIL;
+  } else {
+    o->tatum_signature = signature;
+    return AUBIO_OK;
+  }
 }
 
 void del_aubio_tempo (aubio_tempo_t *o)
--- a/src/tempo/tempo.h
+++ b/src/tempo/tempo.h
@@ -30,8 +30,8 @@
 
 */
 
-#ifndef _AUBIO_TEMPO_H
-#define _AUBIO_TEMPO_H
+#ifndef AUBIO_TEMPO_H
+#define AUBIO_TEMPO_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,7 +50,7 @@
   \return newly created ::aubio_tempo_t if successful, `NULL` otherwise
 
 */
-aubio_tempo_t * new_aubio_tempo (char_t * method,
+aubio_tempo_t * new_aubio_tempo (const char_t * method,
     uint_t buf_size, uint_t hop_size, uint_t samplerate);
 
 /** execute tempo detection
@@ -60,7 +60,7 @@
   \param tempo output beats
 
 */
-void aubio_tempo_do (aubio_tempo_t *o, fvec_t * input, fvec_t * tempo);
+void aubio_tempo_do (aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo);
 
 /** get the time of the latest beat detected, in samples
 
@@ -121,6 +121,26 @@
 */
 smpl_t aubio_tempo_get_threshold(aubio_tempo_t * o);
 
+/** get current beat period in samples
+
+  \param bt beat tracking object
+
+  Returns the currently observed period, in samples, or 0 if no consistent
+  value is found.
+
+*/
+smpl_t aubio_tempo_get_period (aubio_tempo_t * bt);
+
+/** get current beat period in seconds
+
+  \param bt beat tracking object
+
+  Returns the currently observed period, in seconds, or 0 if no consistent
+  value is found.
+
+*/
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t * bt);
+
 /** get current tempo
 
   \param o beat tracking object
@@ -140,6 +160,87 @@
 */
 smpl_t aubio_tempo_get_confidence(aubio_tempo_t * o);
 
+/* set number of tatum per beat
+
+   \param o beat tracking object
+   \param signature number of tatum per beat (between 1 and 64)
+
+*/
+uint_t aubio_tempo_set_tatum_signature(aubio_tempo_t *o, uint_t signature);
+
+/* check whether a tatum was detected in the current frame
+
+   \param o beat tracking object
+
+   \return 2 if a beat was detected, 1 if a tatum was detected, 0 otherwise
+
+*/
+uint_t aubio_tempo_was_tatum(aubio_tempo_t *o);
+
+/* get position of last_tatum, in samples
+
+   \param o beat tracking object
+
+*/
+smpl_t aubio_tempo_get_last_tatum(aubio_tempo_t *o);
+
+/** get current delay
+
+  \param o beat tracking object
+
+  \return current delay, in samples
+
+ */
+uint_t aubio_tempo_get_delay(aubio_tempo_t * o);
+
+/** get current delay in seconds
+
+  \param o beat tracking object
+
+  \return current delay, in seconds
+
+ */
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o);
+
+/** get current delay in ms
+
+  \param o beat tracking object
+
+  \return current delay, in milliseconds
+
+ */
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o);
+
+/** set current delay
+
+  \param o beat tracking object
+  \param delay delay to set tempo to, in samples
+
+  \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay);
+
+/** set current delay in seconds
+
+  \param o beat tracking object
+  \param delay delay to set tempo to, in seconds
+
+  \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay);
+
+/** set current delay
+
+  \param o beat tracking object
+  \param delay delay to set tempo to, in samples
+
+  \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay);
+
 /** delete tempo detection object
 
   \param o beat tracking object
@@ -151,4 +252,4 @@
 }
 #endif
 
-#endif /* _AUBIO_TEMPO_H */
+#endif /* AUBIO_TEMPO_H */
--- a/src/temporal/a_weighting.c
+++ b/src/temporal/a_weighting.c
@@ -29,17 +29,27 @@
 aubio_filter_set_a_weighting (aubio_filter_t * f, uint_t samplerate)
 {
   uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
-  aubio_filter_set_samplerate (f, samplerate);
-  bs = aubio_filter_get_feedforward (f);
-  as = aubio_filter_get_feedback (f);
-  b = bs->data, a = as->data;
-  order = aubio_filter_get_order (f);
 
+  if ((sint_t)samplerate <= 0) {
+    AUBIO_ERROR("aubio_filter: failed setting A-weighting with samplerate %d\n", samplerate);
+    return AUBIO_FAIL;
+  }
+  if (f == NULL) {
+    AUBIO_ERROR("aubio_filter: failed setting A-weighting with filter NULL\n");
+    return AUBIO_FAIL;
+  }
+
+  order = aubio_filter_get_order (f);
   if (order != 7) {
-    AUBIO_ERROR ("order of A-weighting filter must be 7, not %d\n", order);
+    AUBIO_ERROR ("aubio_filter: order of A-weighting filter must be 7, not %d\n", order);
     return 1;
   }
 
+  aubio_filter_set_samplerate (f, samplerate);
+  bs = aubio_filter_get_feedforward (f);
+  as = aubio_filter_get_feedback (f);
+  b = bs->data, a = as->data;
+
   /* select coefficients according to sampling frequency */
   switch (samplerate) {
 
@@ -244,6 +254,9 @@
 new_aubio_filter_a_weighting (uint_t samplerate)
 {
   aubio_filter_t *f = new_aubio_filter (7);
-  aubio_filter_set_a_weighting (f, samplerate);
+  if (aubio_filter_set_a_weighting(f,samplerate) != AUBIO_OK) {
+    del_aubio_filter(f);
+    return NULL;
+  }
   return f;
 }
--- a/src/temporal/a_weighting.h
+++ b/src/temporal/a_weighting.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_FILTER_A_DESIGN_H
-#define _AUBIO_FILTER_A_DESIGN_H
+#ifndef AUBIO_FILTER_A_DESIGN_H
+#define AUBIO_FILTER_A_DESIGN_H
 
 /** \file
 
@@ -85,4 +85,4 @@
 }
 #endif
 
-#endif /* _AUBIO_FILTER_A_DESIGN_H */
+#endif /* AUBIO_FILTER_A_DESIGN_H */
--- a/src/temporal/biquad.h
+++ b/src/temporal/biquad.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_FILTER_BIQUAD_H
-#define _AUBIO_FILTER_BIQUAD_H
+#ifndef AUBIO_FILTER_BIQUAD_H
+#define AUBIO_FILTER_BIQUAD_H
 
 /** \file
 
@@ -72,4 +72,4 @@
 }
 #endif
 
-#endif /* _AUBIO_FILTER_BIQUAD_H */
+#endif /* AUBIO_FILTER_BIQUAD_H */
--- a/src/temporal/c_weighting.c
+++ b/src/temporal/c_weighting.c
@@ -29,17 +29,27 @@
 aubio_filter_set_c_weighting (aubio_filter_t * f, uint_t samplerate)
 {
   uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
-  aubio_filter_set_samplerate (f, samplerate);
-  bs = aubio_filter_get_feedforward (f);
-  as = aubio_filter_get_feedback (f);
-  b = bs->data, a = as->data;
-  order = aubio_filter_get_order (f);
 
+  if ((sint_t)samplerate <= 0) {
+    AUBIO_ERROR("aubio_filter: failed setting C-weighting with samplerate %d\n", samplerate);
+    return AUBIO_FAIL;
+  }
+  if (f == NULL) {
+    AUBIO_ERROR("aubio_filter: failed setting C-weighting with filter NULL\n");
+    return AUBIO_FAIL;
+  }
+
+  order = aubio_filter_get_order (f);
   if ( order != 5 ) {
-    AUBIO_ERROR ("order of C-weighting filter must be 5, not %d\n", order);
+    AUBIO_ERROR ("aubio_filter: order of C-weighting filter must be 5, not %d\n", order);
     return 1;
   }
 
+  aubio_filter_set_samplerate (f, samplerate);
+  bs = aubio_filter_get_feedforward (f);
+  as = aubio_filter_get_feedback (f);
+  b = bs->data, a = as->data;
+
   /* select coefficients according to sampling frequency */
   switch (samplerate) {
 
@@ -199,7 +209,9 @@
 
 aubio_filter_t * new_aubio_filter_c_weighting (uint_t samplerate) {
   aubio_filter_t * f = new_aubio_filter(5);
-  aubio_filter_set_c_weighting (f, samplerate);
+  if (aubio_filter_set_c_weighting(f,samplerate) != AUBIO_OK) {
+    del_aubio_filter(f);
+    return NULL;
+  }
   return f;
 }
-
--- a/src/temporal/c_weighting.h
+++ b/src/temporal/c_weighting.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_FILTER_C_DESIGN_H
-#define _AUBIO_FILTER_C_DESIGN_H
+#ifndef AUBIO_FILTER_C_DESIGN_H
+#define AUBIO_FILTER_C_DESIGN_H
 
 /** \file
 
@@ -85,4 +85,4 @@
 }
 #endif
 
-#endif /* _AUBIO_FILTER_C_DESIGN_H */
+#endif /* AUBIO_FILTER_C_DESIGN_H */
--- a/src/temporal/filter.c
+++ b/src/temporal/filter.c
@@ -39,7 +39,7 @@
 };
 
 void
-aubio_filter_do_outplace (aubio_filter_t * f, fvec_t * in, fvec_t * out)
+aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out)
 {
   fvec_copy (in, out);
   aubio_filter_do (f, out);
@@ -93,25 +93,25 @@
 }
 
 lvec_t *
-aubio_filter_get_feedback (aubio_filter_t * f)
+aubio_filter_get_feedback (const aubio_filter_t * f)
 {
   return f->a;
 }
 
 lvec_t *
-aubio_filter_get_feedforward (aubio_filter_t * f)
+aubio_filter_get_feedforward (const aubio_filter_t * f)
 {
   return f->b;
 }
 
 uint_t
-aubio_filter_get_order (aubio_filter_t * f)
+aubio_filter_get_order (const aubio_filter_t * f)
 {
   return f->order;
 }
 
 uint_t
-aubio_filter_get_samplerate (aubio_filter_t * f)
+aubio_filter_get_samplerate (const aubio_filter_t * f)
 {
   return f->samplerate;
 }
@@ -134,6 +134,10 @@
 new_aubio_filter (uint_t order)
 {
   aubio_filter_t *f = AUBIO_NEW (aubio_filter_t);
+  if ((sint_t)order < 1) {
+    AUBIO_FREE(f);
+    return NULL;
+  }
   f->x = new_lvec (order);
   f->y = new_lvec (order);
   f->a = new_lvec (order);
@@ -142,7 +146,8 @@
   f->samplerate = 0;
   f->order = order;
   /* set default to identity */
-  f->a->data[1] = 1.;
+  f->a->data[0] = 1.;
+  f->b->data[0] = 1.;
   return f;
 }
 
--- a/src/temporal/filter.h
+++ b/src/temporal/filter.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_FILTER_H
-#define _AUBIO_FILTER_H
+#ifndef AUBIO_FILTER_H
+#define AUBIO_FILTER_H
 
 /** \file
 
@@ -86,7 +86,7 @@
   \param out output vector to store filtered input
 
 */
-void aubio_filter_do_outplace (aubio_filter_t * f, fvec_t * in, fvec_t * out);
+void aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out);
 
 /** filter input vector forward and backward
 
@@ -104,7 +104,7 @@
   \return a pointer to the \f$ a_0 ... a_i ... a_P \f$ coefficients
 
 */
-lvec_t *aubio_filter_get_feedback (aubio_filter_t * f);
+lvec_t *aubio_filter_get_feedback (const aubio_filter_t * f);
 
 /** returns a pointer to feedforward coefficients \f$ b_i \f$
 
@@ -113,7 +113,7 @@
   \return a pointer to the \f$ b_0 ... b_i ... b_P \f$ coefficients
 
 */
-lvec_t *aubio_filter_get_feedforward (aubio_filter_t * f);
+lvec_t *aubio_filter_get_feedforward (const aubio_filter_t * f);
 
 /** get order of the filter
 
@@ -122,7 +122,7 @@
   \return the order of the filter
 
 */
-uint_t aubio_filter_get_order (aubio_filter_t * f);
+uint_t aubio_filter_get_order (const aubio_filter_t * f);
 
 /** get sampling rate of the filter
 
@@ -131,7 +131,7 @@
   \return the sampling rate of the filter, in Hz
 
 */
-uint_t aubio_filter_get_samplerate (aubio_filter_t * f);
+uint_t aubio_filter_get_samplerate (const aubio_filter_t * f);
 
 /** get sampling rate of the filter
 
@@ -173,4 +173,4 @@
 }
 #endif
 
-#endif /* _AUBIO_FILTER_H */
+#endif /* AUBIO_FILTER_H */
--- a/src/temporal/resampler.c
+++ b/src/temporal/resampler.c
@@ -24,7 +24,7 @@
 #include "fvec.h"
 #include "temporal/resampler.h"
 
-#if HAVE_SAMPLERATE
+#ifdef HAVE_SAMPLERATE
 
 #include <samplerate.h>         /* from libsamplerate */
 
@@ -61,7 +61,7 @@
 }
 
 void
-aubio_resampler_do (aubio_resampler_t * s, fvec_t * input, fvec_t * output)
+aubio_resampler_do (aubio_resampler_t * s, const fvec_t * input, fvec_t * output)
 {
   s->proc->input_frames = input->length;
   s->proc->output_frames = output->length;
@@ -92,7 +92,7 @@
 }
 
 void
-aubio_resampler_do (aubio_resampler_t * s UNUSED, fvec_t * input UNUSED, fvec_t * output UNUSED)
+aubio_resampler_do (aubio_resampler_t * s UNUSED, const fvec_t * input UNUSED, fvec_t * output UNUSED)
 {
 }
 #endif /* HAVE_SAMPLERATE */
--- a/src/temporal/resampler.h
+++ b/src/temporal/resampler.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_RESAMPLER_H
-#define _AUBIO_RESAMPLER_H
+#ifndef AUBIO_RESAMPLER_H
+#define AUBIO_RESAMPLER_H
 
 /** \file
 
@@ -55,7 +55,7 @@
   \param output output buffer of size N*ratio
 
 */
-void aubio_resampler_do (aubio_resampler_t * s, fvec_t * input,
+void aubio_resampler_do (aubio_resampler_t * s, const fvec_t * input,
     fvec_t * output);
 
 #ifdef __cplusplus
@@ -62,4 +62,4 @@
 }
 #endif
 
-#endif /* _AUBIO_RESAMPLER_H */
+#endif /* AUBIO_RESAMPLER_H */
--- a/src/types.h
+++ b/src/types.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO__TYPES_H
-#define _AUBIO__TYPES_H
+#ifndef AUBIO_TYPES_H
+#define AUBIO_TYPES_H
 
 /** \file
 
@@ -67,4 +67,4 @@
 }
 #endif
 
-#endif /* _AUBIO__TYPES_H */
+#endif /* AUBIO_TYPES_H */
--- a/src/utils/hist.c
+++ b/src/utils/hist.c
@@ -137,7 +137,7 @@
   }
 }
 
-smpl_t aubio_hist_mean (aubio_hist_t *s) {
+smpl_t aubio_hist_mean (const aubio_hist_t *s) {
   uint_t j;
   smpl_t tmp = 0.0;
   for (j=0; j < s->nelems; j++)
--- a/src/utils/hist.h
+++ b/src/utils/hist.h
@@ -25,8 +25,8 @@
  * Big hacks to implement an histogram
  */
 
-#ifndef _AUBIO_HIST_H
-#define _AUBIO_HIST_H
+#ifndef AUBIO_HIST_H
+#define AUBIO_HIST_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,7 +50,7 @@
 /** compute the histogram ignoring null elements */
 void aubio_hist_do_notnull(aubio_hist_t *s, fvec_t * input);
 /** compute the mean of the histogram */
-smpl_t aubio_hist_mean(aubio_hist_t *s);
+smpl_t aubio_hist_mean(const aubio_hist_t *s);
 /** weight the histogram */
 void aubio_hist_weight(aubio_hist_t *s);
 /** compute dynamic histogram for non-null elements */
@@ -60,4 +60,4 @@
 }
 #endif
 
-#endif /* _AUBIO_HIST_H */
+#endif /* AUBIO_HIST_H */
--- a/src/utils/parameter.c
+++ b/src/utils/parameter.c
@@ -84,7 +84,7 @@
   return err;
 }
 
-smpl_t aubio_parameter_get_current_value ( aubio_parameter_t * s )
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * s )
 {
   return s->current_value;
 }
@@ -109,7 +109,7 @@
   return AUBIO_OK;
 }
 
-uint_t aubio_parameter_get_steps ( aubio_parameter_t * param )
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param )
 {
   return param->steps;
 }
@@ -120,7 +120,7 @@
   return AUBIO_OK;
 }
 
-smpl_t aubio_parameter_get_min_value ( aubio_parameter_t * param )
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param )
 {
   return param->min_value;
 }
@@ -131,7 +131,7 @@
   return AUBIO_OK;
 }
 
-smpl_t aubio_parameter_get_max_value ( aubio_parameter_t * param )
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param )
 {
   return param->max_value;
 }
--- a/src/utils/parameter.h
+++ b/src/utils/parameter.h
@@ -18,8 +18,8 @@
 
 */
 
-#ifndef _AUBIO_PARAMETER_H
-#define _AUBIO_PARAMETER_H
+#ifndef AUBIO_PARAMETER_H
+#define AUBIO_PARAMETER_H
 
 /** \file
 
@@ -76,7 +76,7 @@
   \return current value
 
 */
-smpl_t aubio_parameter_get_current_value ( aubio_parameter_t * param );
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * param );
 
 /** set current parameter value, skipping interpolation
 
@@ -105,7 +105,7 @@
   \return number of steps
 
 */
-uint_t aubio_parameter_get_steps ( aubio_parameter_t * param);
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param);
 
 /** set minimum value of this parameter
 
@@ -124,7 +124,7 @@
   \return minimum value
 
 */
-smpl_t aubio_parameter_get_min_value ( aubio_parameter_t * param );
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param );
 
 /** set maximum value of this parameter
 
@@ -143,7 +143,7 @@
   \return maximum value
 
 */
-smpl_t aubio_parameter_get_max_value ( aubio_parameter_t * param );
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param );
 
 /** destroy ::aubio_parameter_t object
 
@@ -156,4 +156,4 @@
 }
 #endif
 
-#endif /* _AUBIO_PARAMETER_H */
+#endif /* AUBIO_PARAMETER_H */
--- a/src/utils/scale.c
+++ b/src/utils/scale.c
@@ -37,7 +37,7 @@
      */
 };
 
-aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig, 
+aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig,
     smpl_t olow, smpl_t ohig) {
   aubio_scale_t * s = AUBIO_NEW(aubio_scale_t);
   aubio_scale_set_limits (s, ilow, ihig, olow, ohig);
--- a/src/utils/scale.h
+++ b/src/utils/scale.h
@@ -28,8 +28,8 @@
  \f$ y = (x - ilow)*(ohig-olow)/(ihig-ilow) + olow \f$
 
 */
-#ifndef _AUBIO_SCALE_H
-#define _AUBIO_SCALE_H
+#ifndef AUBIO_SCALE_H
+#define AUBIO_SCALE_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -77,4 +77,4 @@
 }
 #endif
 
-#endif /* _AUBIO_SCALE_H */
+#endif /* AUBIO_SCALE_H */
--- /dev/null
+++ b/src/utils/windll.c
@@ -1,0 +1,59 @@
+/*
+  Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+  This file is part of aubio.
+
+  aubio is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  aubio is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file
+
+  Windows dll entry point.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_WIN_HACKS
+
+#ifndef __GNUC__ // do not include msvc headers when using gcc/mingw32
+
+// latest version
+#include <SDKDDKVer.h>
+// for earlier versions, include WinSDKVer.h and set _WIN32_WINNT macro
+
+#endif /* __GNUC__ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "aubio.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved )
+{
+  switch (ul_reason_for_call)
+  {
+    case DLL_PROCESS_ATTACH:
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+      break;
+  }
+  return TRUE;
+}
+
+#endif
--- a/src/vecutils.h
+++ b/src/vecutils.h
@@ -24,8 +24,8 @@
 
  */
 
-#ifndef _AUBIO__VECUTILS_H
-#define _AUBIO__VECUTILS_H
+#ifndef AUBIO_VECUTILS_H
+#define AUBIO_VECUTILS_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -113,4 +113,4 @@
 }
 #endif
 
-#endif /* _AUBIO__VECUTILS_H */
+#endif /* AUBIO_VECUTILS_H */
--- a/src/wscript_build
+++ b/src/wscript_build
@@ -1,6 +1,7 @@
 # vim:set syntax=python:
 
 uselib = []
+uselib += ['M']
 uselib += ['FFTW3', 'FFTW3F']
 uselib += ['SAMPLERATE']
 uselib += ['SNDFILE']
@@ -8,14 +9,14 @@
 uselib += ['AVFORMAT']
 uselib += ['AVRESAMPLE']
 uselib += ['AVUTIL']
+uselib += ['BLAS']
 
-# build each source files
 source = ctx.path.ant_glob('*.c **/*.c')
+
 ctx(features = 'c',
         source = source,
         includes = ['.'],
-        uselib = uselib,
-        lib = 'm',
+        use = uselib,
         target = 'lib_objects')
 
 # build libaubio.so (cshlib) and/or libaubio.a (cstlib)
@@ -22,15 +23,15 @@
 if ctx.env['DEST_OS'] in ['ios', 'iosimulator']:
     build_features = ['cstlib', 'cshlib']
 elif ctx.env['DEST_OS'] in ['win32', 'win64']:
-    build_features = ['cshlib']
+    build_features = ['cstlib', 'cshlib']
+elif ctx.env['DEST_OS'] in ['emscripten']:
+    build_features = ['cstlib']
 else: #linux, darwin, android, mingw, ...
-    build_features = ['cshlib', 'cstlib']
+    build_features = ['cstlib', 'cshlib']
 
 for target in build_features:
     ctx(features = 'c ' + target,
-            use = ['lib_objects'],
-            uselib = uselib,
-            lib = 'm',
+            use = uselib + ['lib_objects'],
             target = 'aubio',
             vnum = ctx.env['LIB_VERSION'])
 
--- a/tests/src/io/test-source.c
+++ b/tests/src/io/test-source.c
@@ -33,6 +33,8 @@
   if (!s) { err = 1; goto beach; }
   fvec_t *vec = new_fvec(hop_size);
 
+  uint_t n_frames_expected = aubio_source_get_duration(s);
+
   samplerate = aubio_source_get_samplerate(s);
 
   do {
@@ -41,8 +43,9 @@
     n_frames += read;
   } while ( read == hop_size );
 
-  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
-    n_frames / hop_size, source_path);
+  PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+            n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+            source_path);
 
   // close the file (optional)
   aubio_source_close(s);
--- a/tests/src/io/test-source_apple_audio.c
+++ b/tests/src/io/test-source_apple_audio.c
@@ -38,6 +38,8 @@
   if (!s) { err = 1; goto beach; }
   fvec_t *vec = new_fvec(hop_size);
 
+  uint_t n_frames_expected = aubio_source_apple_audio_get_duration(s);
+
   samplerate = aubio_source_apple_audio_get_samplerate(s);
 
   do {
@@ -46,8 +48,9 @@
     n_frames += read;
   } while ( read == hop_size );
 
-  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
-    n_frames / hop_size, source_path);
+  PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+            n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+            source_path);
 
   del_fvec (vec);
   del_aubio_source_apple_audio (s);
--- a/tests/src/io/test-source_avcodec.c
+++ b/tests/src/io/test-source_avcodec.c
@@ -38,6 +38,8 @@
   if (!s) { err = 1; goto beach; }
   fvec_t *vec = new_fvec(hop_size);
 
+  uint_t n_frames_expected = aubio_source_avcodec_get_duration(s);
+
   samplerate = aubio_source_avcodec_get_samplerate(s);
 
   do {
@@ -46,8 +48,9 @@
     n_frames += read;
   } while ( read == hop_size );
 
-  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
-    n_frames / hop_size, source_path);
+  PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+            n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+            source_path);
 
   del_fvec (vec);
   del_aubio_source_avcodec (s);
--- a/tests/src/io/test-source_sndfile.c
+++ b/tests/src/io/test-source_sndfile.c
@@ -38,6 +38,8 @@
   if (!s) { err = 1; goto beach; }
   fvec_t *vec = new_fvec(hop_size);
 
+  uint_t n_frames_expected = aubio_source_sndfile_get_duration(s);
+
   samplerate = aubio_source_sndfile_get_samplerate(s);
 
   do {
@@ -46,8 +48,9 @@
     n_frames += read;
   } while ( read == hop_size );
 
-  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
-    n_frames / hop_size, source_path);
+  PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+            n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+            source_path);
 
   del_fvec (vec);
   del_aubio_source_sndfile (s);
--- a/tests/src/io/test-source_wavread.c
+++ b/tests/src/io/test-source_wavread.c
@@ -35,9 +35,12 @@
 
   aubio_source_wavread_t * s =
     new_aubio_source_wavread(source_path, samplerate, hop_size);
+
   if (!s) { err = 1; goto beach; }
   fvec_t *vec = new_fvec(hop_size);
 
+  uint_t n_frames_expected = aubio_source_wavread_get_duration(s);
+
   samplerate = aubio_source_wavread_get_samplerate(s);
 
   do {
@@ -46,8 +49,9 @@
     n_frames += read;
   } while ( read == hop_size );
 
-  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate,
-    n_frames / hop_size, source_path);
+  PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+            n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+            source_path);
 
   del_fvec (vec);
   del_aubio_source_wavread (s);
--- a/tests/src/tempo/test-tempo.c
+++ b/tests/src/tempo/test-tempo.c
@@ -27,7 +27,7 @@
 
   // create some vectors
   fvec_t * in = new_fvec (hop_size); // input audio buffer
-  fvec_t * out = new_fvec (2); // output position
+  fvec_t * out = new_fvec (1); // output position
 
   // create tempo object
   aubio_tempo_t * o = new_aubio_tempo("default", win_size, hop_size, samplerate);
--- a/tests/src/temporal/test-a_weighting.c
+++ b/tests/src/temporal/test-a_weighting.c
@@ -20,16 +20,22 @@
 
   // samplerate unknown
   f = new_aubio_filter_a_weighting (4200);
-  del_aubio_filter (f);
+  if (!f) {
+    //PRINT_MSG ("failed creating A-weighting filter with samplerate=4200Hz\n");
+  }
 
   // order to small
   f = new_aubio_filter (2);
-  aubio_filter_set_a_weighting (f, samplerate);
+  if (aubio_filter_set_a_weighting (f, samplerate) != 0) {
+    //PRINT_MSG ("failed setting filter to A-weighting\n");
+  }
   del_aubio_filter (f);
 
   // order to big
   f = new_aubio_filter (12);
-  aubio_filter_set_a_weighting (f, samplerate);
+  if (aubio_filter_set_a_weighting (f, samplerate) != 0) {
+    //PRINT_MSG ("failed setting filter to A-weighting\n");
+  }
   del_aubio_filter (f);
 
   return 0;
--- a/tests/src/temporal/test-c_weighting.c
+++ b/tests/src/temporal/test-c_weighting.c
@@ -19,16 +19,22 @@
 
   // samplerate unknown
   f = new_aubio_filter_c_weighting (4200);
-  del_aubio_filter (f);
+  if (!f) {
+    //PRINT_WRN ("failed creating C-weighting filter with samplerate=4200Hz");
+  }
 
   // order to small
   f = new_aubio_filter (2);
-  aubio_filter_set_c_weighting (f, samplerate);
+  if (aubio_filter_set_c_weighting (f, samplerate) != 0) {
+    //PRINT_WRN ("failed setting filter to C-weighting");
+  }
   del_aubio_filter (f);
 
   // order to big
   f = new_aubio_filter (12);
-  aubio_filter_set_c_weighting (f, samplerate);
+  if (aubio_filter_set_c_weighting (f, samplerate) != 0) {
+    //PRINT_WRN ("failed setting filter to C-weighting");
+  }
   del_aubio_filter (f);
 
   return 0;
--- a/tests/src/test-lvec.c
+++ b/tests/src/test-lvec.c
@@ -6,7 +6,7 @@
   uint_t win_s = 32; // window size
   lvec_t * sp = new_lvec (win_s); // input buffer
   lvec_set_sample (sp, 2./3., 0);
-  PRINT_MSG("%lf\n", lvec_get_sample (sp, 0));
+  PRINT_MSG(AUBIO_LSMP_FMT "\n", lvec_get_sample (sp, 0));
   lvec_print (sp);
   lvec_ones (sp);
   lvec_print (sp);
--- a/tests/utils_tests.h
+++ b/tests/utils_tests.h
@@ -5,12 +5,28 @@
 #include <assert.h>
 #include "config.h"
 
+#ifdef HAVE_C99_VARARGS_MACROS
+#define PRINT_ERR(...)   fprintf(stderr, "AUBIO-TESTS ERROR: " __VA_ARGS__)
+#define PRINT_MSG(...)   fprintf(stdout, __VA_ARGS__)
+#define PRINT_DBG(...)   fprintf(stderr, __VA_ARGS__)
+#define PRINT_WRN(...)   fprintf(stderr, "AUBIO-TESTS WARNING: " __VA_ARGS__)
+#else
 #define PRINT_ERR(format, args...)   fprintf(stderr, "AUBIO-TESTS ERROR: " format , ##args)
 #define PRINT_MSG(format, args...)   fprintf(stdout, format , ##args)
 #define PRINT_DBG(format, args...)   fprintf(stderr, format , ##args)
 #define PRINT_WRN(format, args...)   fprintf(stderr, "AUBIO-TESTS WARNING: " format, ##args)
+#endif
 
-#ifdef HAVE_WIN_HACKS
+#ifndef M_PI
+#define M_PI         (3.14159265358979323846)
+#endif
+
+#ifndef RAND_MAX
+#define RAND_MAX 32767
+#endif
+
+// are we on windows ? or are we using -std=c99 ?
+#if defined(HAVE_WIN_HACKS) || defined(__STRICT_ANSI__)
 // http://en.wikipedia.org/wiki/Linear_congruential_generator
 // no srandom/random on win32
 
--- a/tests/wscript_build
+++ b/tests/wscript_build
@@ -1,25 +1,16 @@
 # vim:set syntax=python:
 
-for target_name in ctx.path.ant_glob('src/**/*.c'):
-    uselib = []
-    uselib += ['FFTW3', 'FFTW3F']
-    uselib += ['SAMPLERATE']
-    uselib += ['SNDFILE']
-    uselib += ['AVCODEC']
-    uselib += ['AVFORMAT']
-    uselib += ['AVRESAMPLE']
-    uselib += ['AVUTIL']
-    uselib += ['JACK']
-    includes = ['../src', '.']
-    extra_source = []
+uselib = ['aubio']
 
+includes = ['../src', '.']
+programs_sources = ctx.path.ant_glob('src/**/*.c')
+
+for source_file in programs_sources:
     bld(features = 'c cprogram test',
-            lib = 'm',
-            uselib = uselib,
-            source = [target_name] + extra_source,
-            target = str(target_name).split('.')[0],
+            source = source_file,
+            target = str(source_file).split('.')[0],
             includes = includes,
+            use = uselib,
             install_path = None,
             defines = 'AUBIO_UNSTABLE_API=1',
-            cflags = ['-g'],
-            use = 'aubio')
+       )
--- a/wscript
+++ b/wscript
@@ -81,7 +81,14 @@
     add_option_enable_disable(ctx, 'apple-audio', default = None,
             help_str = 'use CoreFoundation (darwin only) (auto)',
             help_disable_str = 'do not use CoreFoundation framework')
+    add_option_enable_disable(ctx, 'atlas', default = None,
+            help_str = 'use Atlas library (auto)',
+            help_disable_str = 'do not use Atlas library')
 
+    add_option_enable_disable(ctx, 'docs', default = None,
+            help_str = 'build documentation (auto)',
+            help_disable_str = 'do not build documentation')
+
     ctx.add_option('--with-target-platform', type='string',
             help='set target platform for cross-compilation', dest='target_platform')
 
@@ -95,16 +102,28 @@
     ctx.load('waf_unit_test')
     ctx.load('gnu_dirs')
 
+    # check for common headers
+    ctx.check(header_name='stdlib.h')
+    ctx.check(header_name='stdio.h')
+    ctx.check(header_name='math.h')
+    ctx.check(header_name='string.h')
+    ctx.check(header_name='limits.h')
+    ctx.check(header_name='getopt.h', mandatory = False)
+    ctx.check(header_name='unistd.h', mandatory = False)
+
     target_platform = Options.platform
     if ctx.options.target_platform:
         target_platform = ctx.options.target_platform
     ctx.env['DEST_OS'] = target_platform
 
-    if 'CL.exe' not in ctx.env.CC[0]:
+    if ctx.env.CC_NAME != 'msvc':
         ctx.env.CFLAGS += ['-g', '-Wall', '-Wextra']
     else:
-        ctx.env.CFLAGS += ['-Wall']
+        ctx.env.CFLAGS += ['/W4', '/MD']
+        ctx.env.CFLAGS += ['/D_CRT_SECURE_NO_WARNINGS']
 
+    ctx.check_cc(lib='m', uselib_store='M', mandatory=False)
+
     if target_platform not in ['win32', 'win64']:
         ctx.env.CFLAGS += ['-fPIC']
     else:
@@ -114,6 +133,9 @@
     if target_platform == 'darwin' and ctx.options.enable_fat:
         ctx.env.CFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
         ctx.env.LINKFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
+        MINSDKVER="10.4"
+        ctx.env.CFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
+        ctx.env.LINKFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
 
     if target_platform in [ 'darwin', 'ios', 'iosimulator']:
         if (ctx.options.enable_apple_audio != False):
@@ -127,7 +149,7 @@
     if target_platform in [ 'ios', 'iosimulator' ]:
         MINSDKVER="6.1"
         ctx.env.CFLAGS += ['-std=c99']
-        if (ctx.options.enable_audio_unit != False):
+        if (ctx.options.enable_apple_audio != False):
             ctx.define('HAVE_AUDIO_UNIT', 1)
             #ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
         if target_platform == 'ios':
@@ -134,6 +156,7 @@
             DEVROOT = "/Applications/Xcode.app/Contents"
             DEVROOT += "/Developer/Platforms/iPhoneOS.platform/Developer"
             SDKROOT = "%(DEVROOT)s/SDKs/iPhoneOS.sdk" % locals()
+            ctx.env.CFLAGS += [ '-fembed-bitcode' ]
             ctx.env.CFLAGS += [ '-arch', 'arm64' ]
             ctx.env.CFLAGS += [ '-arch', 'armv7' ]
             ctx.env.CFLAGS += [ '-arch', 'armv7s' ]
@@ -155,12 +178,13 @@
         ctx.env.CFLAGS += [ '-isysroot' , SDKROOT]
         ctx.env.LINKFLAGS += [ '-isysroot' , SDKROOT]
 
-    # check for required headers
-    ctx.check(header_name='stdlib.h')
-    ctx.check(header_name='stdio.h')
-    ctx.check(header_name='math.h')
-    ctx.check(header_name='string.h')
-    ctx.check(header_name='limits.h')
+    if target_platform == 'emscripten':
+        import os.path
+        ctx.env.CFLAGS += [ '-I' + os.path.join(os.environ['EMSCRIPTEN'], 'system', 'include') ]
+        ctx.env.CFLAGS += ['-Oz']
+        ctx.env.cprogram_PATTERN = "%s.js"
+        if (ctx.options.enable_atlas != True):
+            ctx.options.enable_atlas = False
 
     # check support for C99 __VA_ARGS__ macros
     check_c99_varargs = '''
@@ -174,15 +198,19 @@
             mandatory = False):
         ctx.define('HAVE_C99_VARARGS_MACROS', 1)
 
-    # double precision mode
+    # show a message about enable_double status
     if (ctx.options.enable_double == True):
-        ctx.define('HAVE_AUBIO_DOUBLE', 1)
+        ctx.msg('Checking for size of smpl_t', 'double')
+        ctx.msg('Checking for size of lsmp_t', 'long double')
     else:
-        ctx.define('HAVE_AUBIO_DOUBLE', 0)
+        ctx.msg('Checking for size of smpl_t', 'float')
+        ctx.msg('Checking for size of lsmp_t', 'double')
 
     # optionally use complex.h
     if (ctx.options.enable_complex == True):
         ctx.check(header_name='complex.h')
+    else:
+        ctx.msg('Checking if complex.h is enabled', 'no')
 
     # check for fftw3
     if (ctx.options.enable_fftw3 != False or ctx.options.enable_fftw3f != False):
@@ -259,31 +287,43 @@
     ctx.define('HAVE_WAVREAD', 1)
     ctx.define('HAVE_WAVWRITE', 1)
 
+    # use ATLAS
+    if (ctx.options.enable_atlas != False):
+        ctx.check(header_name = 'atlas/cblas.h', mandatory = ctx.options.enable_atlas)
+        #ctx.check(lib = 'lapack', uselib_store = 'LAPACK', mandatory = ctx.options.enable_atlas)
+        ctx.check(lib = 'cblas', uselib_store = 'BLAS', mandatory = ctx.options.enable_atlas)
+
     # use memcpy hacks
     if (ctx.options.enable_memcpy == True):
         ctx.define('HAVE_MEMCPY_HACKS', 1)
-    else:
-        ctx.define('HAVE_MEMCPY_HACKS', 0)
 
     # write configuration header
     ctx.write_config_header('src/config.h')
 
+    # the following defines will be passed as arguments to the compiler
+    # instead of being written to src/config.h
+
     # add some defines used in examples
     ctx.define('AUBIO_PREFIX', ctx.env['PREFIX'])
     ctx.define('PACKAGE', APPNAME)
 
-    # check if txt2man is installed, optional
-    try:
-      ctx.find_program('txt2man', var='TXT2MAN')
-    except ctx.errors.ConfigurationError:
-      ctx.to_log('txt2man was not found (ignoring)')
+    # double precision mode
+    if (ctx.options.enable_double == True):
+        ctx.define('HAVE_AUBIO_DOUBLE', 1)
 
-    # check if doxygen is installed, optional
-    try:
-      ctx.find_program('doxygen', var='DOXYGEN')
-    except ctx.errors.ConfigurationError:
-      ctx.to_log('doxygen was not found (ignoring)')
+    if (ctx.options.enable_docs != False):
+        # check if txt2man is installed, optional
+        try:
+          ctx.find_program('txt2man', var='TXT2MAN')
+        except ctx.errors.ConfigurationError:
+          ctx.to_log('txt2man was not found (ignoring)')
 
+        # check if doxygen is installed, optional
+        try:
+          ctx.find_program('doxygen', var='DOXYGEN')
+        except ctx.errors.ConfigurationError:
+          ctx.to_log('doxygen was not found (ignoring)')
+
 def build(bld):
     bld.env['VERSION'] = VERSION
     bld.env['LIB_VERSION'] = LIB_VERSION
@@ -290,8 +330,6 @@
 
     # add sub directories
     bld.recurse('src')
-    if bld.env['DEST_OS'] not in ['ios', 'iosimulator']:
-        pass
     if bld.env['DEST_OS'] not in ['ios', 'iosimulator', 'android']:
         bld.recurse('examples')
         bld.recurse('tests')
@@ -339,9 +377,15 @@
     ctx.excl  = ' **/.waf-1* **/*~ **/*.pyc **/*.swp **/.lock-w* **/.git*'
     ctx.excl += ' **/build/*'
     ctx.excl += ' **/python/gen **/python/build **/python/dist'
+    ctx.excl += ' **/python/ext/config.h'
     ctx.excl += ' **/**.zip **/**.tar.bz2'
     ctx.excl += ' **/doc/full/* **/doc/web/*'
     ctx.excl += ' **/python/*.db'
     ctx.excl += ' **/python.old/*'
+    ctx.excl += ' **/python/*/*.old'
     ctx.excl += ' **/python/tests/sounds'
     ctx.excl += ' **/**.asc'
+    ctx.excl += ' **/.DS_Store'
+    ctx.excl += ' **/.travis.yml'
+    ctx.excl += ' **/dist*'
+    ctx.excl += ' **/appveyor.yml'