shithub: aubio

Download patch

ref: 633400de7313737941a2d3d3e61ba37d8e7e02ea
parent: 5b46bc3029153f1d6ae00a12bdb63537d52650d3
parent: f19db54741e591f6f2111dd9687391967efb5983
author: Paul Brossier <piem@piem.org>
date: Wed Dec 5 17:34:39 EST 2018

Merge branch 'master' into feature/pitchshift

--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -7,63 +7,72 @@
 
     # pre-installed python version, see:
     # http://www.appveyor.com/docs/installed-software#python
-    - PYTHON: "C:\\Python27"
-      PYTHON_VERSION: "2.7.x"
-      PYTHON_ARCH: "32"
+    - PYTHONDIR: C:\Python27
+      PYTHON_VERSION: 2.7.x
+      PYTHON_ARCH: 32
 
-    - PYTHON: "C:\\Python27-x64"
-      PYTHON_VERSION: "2.7.x"
-      PYTHON_ARCH: "64"
+    - PYTHONDIR: C:\Python27-x64
+      PYTHON_VERSION: 2.7.x
+      PYTHON_ARCH: 64
 
-    - PYTHON: "C:\\Python34"
-      PYTHON_VERSION: "3.4.x"
-      PYTHON_ARCH: "32"
+    - PYTHONDIR: C:\Python35
+      PYTHON_VERSION: 3.5.x
+      PYTHON_ARCH: 32
 
-    - PYTHON: "C:\\Python34-x64"
-      PYTHON_VERSION: "3.4.x"
-      PYTHON_ARCH: "64"
+    - PYTHONDIR: C:\Python35-x64
+      PYTHON_VERSION: 3.5.x
+      PYTHON_ARCH: 64
 
-    - PYTHON: "C:\\Python35"
-      PYTHON_VERSION: "3.5.x"
-      PYTHON_ARCH: "32"
+    - PYTHONDIR: C:\Python36
+      PYTHON_VERSION: 3.6.x
+      PYTHON_ARCH: 32
 
-    - PYTHON: "C:\\Python35-x64"
-      PYTHON_VERSION: "3.5.x"
-      PYTHON_ARCH: "64"
-      # add path required to run preprocessor step
-      PATH_EXTRAS: "c:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin"
+    - PYTHONDIR: C:\Python36-x64
+      PYTHON_VERSION: 3.6.x
+      PYTHON_ARCH: 64
 
-install:
+    - PYTHONDIR: C:\Python37
+      PYTHON_VERSION: 3.7.x
+      PYTHON_ARCH: 32
 
+    - PYTHONDIR: C:\Python37-x64
+      PYTHON_VERSION: 3.7.x
+      PYTHON_ARCH: 64
+
+install:
   - ECHO "Installed SDKs:"
   - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
 
+  - "SET PATH=%PYTHONDIR%;%PYTHONDIR%\\Scripts;%PATH%"
+
   # 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)\""
+  - "python --version"
+  - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
 
+  - "python -m pip install --disable-pip-version-check --user --upgrade pip"
+  - "python -m pip install --upgrade setuptools"
+
   # We need wheel installed to build wheels
-  - "%PYTHON%\\python.exe -m pip install wheel"
+  - "python -m pip install wheel"
 
-  - "SET PATH=%PATH_EXTRAS%;%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+  - "pip install -r requirements.txt"
 
-  - "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.22
-  - curl -fsS -o waf.bat https://raw.githubusercontent.com/waf-project/waf/master/utils/waf.bat
+  - "bash scripts/get_waf.sh"
 
 build_script:
-  # build python module without using libaubio
-  - "pip install -r requirements.txt"
-  - "python setup.py build"
-  - "pip install ."
+  # also build libaubio with waf
+  - python waf configure build install --verbose --msvc_version="msvc 14.0"
+  # clean before building python package
+  - python waf distclean
+  # build, upload and install wheel (inspired by numpy's appveyor)
+  - ps: |
+      pip wheel -v -v -v --wheel-dir=dist .
+      ls dist -r | Foreach-Object {
+          Push-AppveyorArtifact $_.FullName
+          pip install $_.FullName
+      }
+
+test_script:
   - "python python\\demos\\demo_create_test_sounds.py"
   - "nose2 --verbose"
-  # clean up
-  - waf distclean
-  # build libaubio
-  - waf configure build --verbose
-  # build python module using libaubio dll
-  - "python setup.py build"
--- /dev/null
+++ b/.circleci/config.yml
@@ -1,0 +1,104 @@
+apt-run: &apt-install
+  name: Install apt packages
+  command: |
+    sudo apt-get update
+    sudo apt-get -y install make sox pkg-config libavcodec-dev libavformat-dev libavresample-dev libavutil-dev libsndfile1-dev libsamplerate-dev
+
+pip-install: &pip-install
+  name: Install pip dependencies
+  command: |
+    pip install --user -r requirements.txt
+
+build-wheel: &build-wheel
+  name: Build python wheel
+  command: |
+    pip wheel -v -v -v --wheel-dir=dist .
+
+install-wheel: &install-wheel
+  name: Install python wheel
+  command: |
+    pip install --user dist/aubio*.whl
+
+test-nose2: &test-nose2
+  name: Test python wheel
+  command: |
+    make create_test_sounds
+    PATH=/home/circleci/.local/bin:$PATH nose2 -v
+
+test-nose2-nosounds: &test-nose2-nosounds
+  name: Test python wheel
+  command: |
+    PATH=/home/circleci/.local/bin:$PATH nose2 -v
+
+uninstall-wheel: &uninstall-wheel
+  name: Uninstall python wheel
+  command: |
+    pip show -f aubio
+    pip uninstall --verbose --yes aubio
+
+version: 2
+jobs:
+  build-27:
+    docker:
+      - image: circleci/python:2.7
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-36:
+    docker:
+      - image: circleci/python:3.6
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-37:
+    docker:
+      - image: circleci/python:3.7
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-37-nodeps:
+    docker:
+      - image: circleci/python:3.7
+    steps:
+      - checkout
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2-nosounds
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+workflows:
+  version: 2
+
+  test-wheel:
+    jobs:
+      - build-27
+      - build-36
+      - build-37
+      - build-37-nodeps
--- /dev/null
+++ b/.coveragerc
@@ -1,0 +1,3 @@
+[run]
+branch = True
+source = aubio
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@
 # doxygen
 doc/web/
 doc/full/
+doc/_build/
 
 python/gen
 python/dist
@@ -37,9 +38,15 @@
 python/*.db
 python/*.wav
 
+pip-delete-this-directory.txt
+
 aubio-*.tar.bz2
 aubio-*.zip
+dist/*.tar.gz
+dist/*.whl
 
 # test sounds
 python/tests/sounds
 aubio.egg-info
+.eggs
+.cache
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,67 +2,59 @@
 
 matrix:
   include:
-    - python: 2.7
+    - python: 3.5
       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
+    - python: 3.5
       os: linux
       compiler: gcc
-      env: ARCH=i386 HAVE_DOUBLE=1
+      env: CFLAGS="-Os" WAFOPTS="--disable-samplerate --disable-sndfile"
     - python: 3.4
       os: linux
       compiler: gcc
-      env: ARCH=x86_64 HAVE_DOUBLE=1
-    - python: 3.4
+      env: HAVE_AUBIO_DOUBLE=1 CFLAGS="-O3" WAFOPTS="--enable-fftw3"
+    - python: 2.7
       os: linux
       compiler: gcc
-      env: ARCH=i386 HAVE_DOUBLE=1
+      env: CFLAGS="`dpkg-buildflags --get CFLAGS`" LDFLAGS="`dpkg-buildflags --get LDFLAGS`"
     - 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
+      env: CFLAGS="-Os" HAVE_AUBIO_DOUBLE=1 WAFOPTS="--disable-accelerate"
     - language: C
       os: osx
       compiler: clang
-      env: ARCH=x86_64 WAFOPTS="--enable-fat --disable-sndfile --disable-samplerate --disable-rubberband"
+      env: WAFOPTS="--enable-fat --disable-avcodec --disable-sndfile --disable-samplerate --disable-rubberband"
     - language: C
       os: osx
       compiler: clang
-      env: ARCH=i386 WAFOPTS="--enable-fat --disable-sndfile --disable-samplerate --disable-rubberband"
+      env: WAFOPTS="--with-target-platform=ios --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
+    - language: C
+      os: osx
+      compiler: clang
+      env: WAFOPTS="--with-target-platform=iosimulator --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
 
+# use trusty
+dist: trusty
+sudo: required
+
 addons:
   apt:
     packages:
     - bzip2
+    - libavcodec-dev
+    - libavformat-dev
+    - libavresample-dev
+    - libavutil-dev
     - libsndfile1-dev
     - libsamplerate-dev
     - libjack-dev
@@ -70,33 +62,58 @@
     - libfftw3-dev
     - librubberband-dev
     - sox
+    - lcov
+  homebrew:
+    packages:
+    - sox
+    - ffmpeg
+    - libsndfile
+    - libsamplerate
+    - rubberband
+    - lcov
+    #update: true
 
 before_install:
    - |
      if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
-       brew update
-       brew install sox libsamplerate libsndfile rubberband
        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
+  - |
+    if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+      alias pip=pip2
+    fi;
+  - travis_retry pip install --upgrade pip
+  - travis_retry make getwaf expandwaf deps_python
+  - which pip
+  - pip --version
 
 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
+  - |
+    if [[ -z "$AUBIO_NOTESTS" ]]; then
+      make test_lib_python_clean
+      make coverage
+    else
+      make test_lib_only_clean
+    fi;
 
+after_success:
+  - |
+    if [[ -z "$AUBIO_NOTESTS" ]]; then
+      # upload to codecov
+      bash <(curl -s https://codecov.io/bash)
+    fi
+
 notifications:
     irc:
         channels:
             - "irc.freenode.org#aubio"
         use_notice: true
+    webhooks:
+        urls:
+            - https://webhooks.gitter.im/e/81e7733a5b1d977854b4
+        on_success: change  # options: [always|never|change] default: always
+        on_failure: always  # options: [always|never|change] default: always
+        on_start: never     # options: [always|never|change] default: always
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,511 @@
+2018-11-21 Paul Brossier <piem@aubio.org>
+
+	[ Overview ]
+
+	* VERSION: bump to 0.4.8
+	* notes: new option release_drop (gh-203)
+	* spectral: new parameters added to filterbank and mfcc (gh-206)
+	* python: start documenting module (gh-73, debian #480018), improve build for
+	win-amd64 (gh-154, gh-199, gh-208)
+	* fixes: prevent crash when using fft sizes unsupported by vDSP (gh-207),
+	prevent saturation when down-mixing a multi-channel source (avcodec/ffmpeg)
+
+	[ Fixes ]
+
+	* avcodec: prevent saturation when down-mixing a multi-channel source, emit
+	a warning if compiling against avutil < 53 (gh-137), wrap long lines
+	* examples/: avoid hiding global and unreachable code
+	* fft: limit to r*2*n sizes, with r in [1, 3, 5, 15] (vDSP only) (gh-207)
+	* fft: fix reconstruction for odd sizes (fftw only)
+	* pvoc: add missing implementations for aubio_pvoc_get_hop/win
+	* mathutils: increase ln(2) precision of in freqtomidi/miditofreq
+	* wavetable: stop sets playing to 0, add dummy implementation for _load
+
+	[ New features ]
+
+	* src/musicutils.h: new aubio_meltohz, aubio_hztomel, with _htk versions
+	* src/spectral/filterbank.h: new set_mel_coeffs, set_mel_coeffs_htk,
+	set_power, and set_norm methods, improved set_triangle_bands
+	* src/spectral/mfcc.h: new set_scale, set_power, set_norm, set_mel_coeffs,
+	set_mel_coeffs_htk, set_mel_coeffs_slaney
+	* src/mathutils.h: new fvec_mul
+	* src/notes: new option release_drop to prevent missing note-offs (gh-203)
+
+	[ Python module ]
+
+	* fix: rounding to nearest integer in midi2note and freq2note
+	* general: supports code generation of setters with none or multiple
+	parameters
+	* documentation: add docstrings do fvec, cvec, source, sink, pvoc, frequency
+	conversion and level detection routines (gh-73, debian #480018)
+	* slicing: improve and document slice_source_at_stamps
+	* module: new note2freq function, recover error log when raising exceptions
+	on failed set_ methods, prevent cyclic import, coding style improvements
+	* demos: improve coding style, fix bpm_extract arguments
+	* MANIFEST.in: exclude *.pyc, improve patterns
+
+	[ Documentation ]
+
+	* doc/: use sphinx autodoc to load docstrings from aubio module, reorganize
+	python module documentation, add a note about double precision, use https
+	when possible
+	* src/spectral/: update Auditory Toolbox url, update copyright year
+
+	[ Tools ]
+
+	* aubionotes: add --release-drop option
+	* aubio: add --release-drop and --silence options to `aubio notes`,
+	workaround for -V to really show version (py2)
+	* aubiocut: add option --create-first to always create first slice
+
+	[ Tests ]
+
+	* tests/, python/tests: add tests for new methods, check source channel
+	down-mix, improve coverage
+
+	[ Build system ]
+
+	* Makefile: disable docs when measuring coverage, add branch coverage
+	option, add coverage_zero_counters target, improve html report
+	* waf: update to 2.0.12, improve wscript style, prevent shipping some
+	generated files
+	* python: always show compiler warnings when pre-processing headers,
+	workaround to fix code generation for win-amd64 (gh-154, gh-199, gh-208).
+	* continuous integration: add azure pipelines, update and improve
+	configurations for appveyor, circleci, and travis.
+
+2018-09-22 Paul Brossier <piem@aubio.org>
+
+	[ Overview ]
+
+	* VERSION: bump to 0.4.7
+	* src/spectral/dct.h: add dct type II object with optimised versions
+	* src/io/, src/notes/, src/pitch: prevent crashes on corrupted files
+	* examples/: fix jack midi output, improve messages when jack disabled
+	* python/: add dct support, minor bug fixes tests and demos
+	* wscript: improve support for BLAS/ATLAS
+
+	[ Library fixes ]
+
+	* src/pitch/pitchyinfft.c: fix out of bound read when samplerate > 50kHz
+	thanks to @fCorleone (closes #189, CVE-2018-14523, debian #904906)
+	* src/notes/notes.c: bail out if pitch creation failed (see #188)
+	* src/io/source_wavread.c:
+	 - also exit if samplerate is negative (closes #188, CVE-2018-14522,
+	 debian #904907)
+	 - add some input validation (closes #148 and #158, CVE-2017-17054,
+	 debian #883355)
+	* src/io/source_avcodec.c:
+	 - give up if resampling context failed opening (see #137, closes #187,
+	 CVE-2018-14521, debian #904908)
+	 - give up reading file if number of channel changes during stream (closes
+	 #137, CVE-2017-17554, debian #884237)
+	 - make sure libavutil > 52 before checking avFrame->channels (see #137)
+	 - fix build with ffmpeg 4.0, thanks to @jcowgill (closes #168, #173)
+	 - avoid deprecated call for ffmpeg >= 4.0
+	* src/onset/onset.c: add dummy default parameters for wphase (closes #150)
+
+	[ Tools ]
+
+	* examples/parse_args.h: hide jack options if not available, improve error
+	message (closes #182)
+	* examples/utils.h: process_block returns void
+	* examples/utils.c: fix examples failing to send more than one JACK midi
+	event per frame, thanks to @cyclopsian (closes #201)
+
+	[ New features ]
+
+	* src/spectral/dct.h: add dct type II object with implementation factory
+	* src/spectral/dct_plain.c: add plain dct implementation
+	* src/spectral/dct_ooura.c: add ooura implementation
+	* src/spectral/dct_fftw.c: add fftw implementation
+	* src/spectral/dct_ipp.c: add ipp version
+	* src/spectral/dct_accelerate.c: add vdsp/accelerate dct
+	* tests/src/spectral/test-dct.c: check reconstruction works
+	* src/spectral/mfcc.c: use new dct to compute mfcc
+
+	[ Library internals ]
+
+	* src/aubio_priv.h: avoid hard-coded undefs, split BLAS and ATLAS support,
+	add vdsp scalar add and multiply
+
+	[ Build system ]
+
+	* wscript:
+	 - add options to disable examples and tests
+	 - detect includes for openblas/libblas/atlas
+	* scripts/get_waf.sh: bump to 2.0.11, verify signature if gpg available
+	* python/lib/gen_external.py: pass '-x c' to emcc only
+
+	[ Python ]
+
+	* python/lib/gen_code.py: add support for rdo methods
+	* python/tests/test_dct.py: add tests for new dct
+	* python/demos/demo_pitch_sinusoid.py: use // to yield an integer, fixing
+	demo on py3, thanks to @ancorcruz (closes #176)
+	* python/ext/py-musicutils.*: add shift(fvec) and ishift(fvec)
+	* python/tests/test_fvec_shift.py: add tests for shift() and ishift()
+	* python/lib/aubio/cmd.py: fix typo in comment
+
+	[ Documentation ]
+
+	* README.md, doc/statuslinks.rst: use latest for commits-since
+	* examples/parse_args.h: add yinfast to pitch algorithms
+	* doc/requirements.rst: add some blas documentation
+	* doc/requirements.rst: split media/optimisation libraries
+	* doc/develop.rst: fixed spelling error, thanks to Jon Williams (closes #161)
+	* doc/aubio{pitch,notes}.txt: add yinfast to list of pitch methods
+
+	[ Continuous integration ]
+
+	* .travis.yml: remove xcode8.2 builds, group osx, add alias pip=pip2
+	* .appveyor.yml: upgrade pip first, always use python -m pip
+
+2017-10-02 Paul Brossier <piem@aubio.org>
+
+	[ Overview ]
+
+	* VERSION: bump to 0.4.6
+	* src/spectral/fft.c, src/*.c: add support for Intel IPP (many thanks to
+	Eduard Mueller)
+	* wscript: add support for emscripten (thanks to Martin Hermant)
+	* src/pitch/pitchyinfast.h: new fast method to compute YIN algorithm
+	* src/pitch/pitchyin*.c: improve confidence measure, making sure its value
+	corresponds to the selected period (thanks to Eduard Mueller)
+	* python/lib/aubio/cmd.py: add `quiet`, `cut`, and `help` subcommands
+
+	[ Library ]
+
+	* src/aubio_priv.h: add missing aubio_vDSP_vclr (Eduard Mueller)
+	* src/io/source_avcodec.c: improve error message, prevent un-opened bracket,
+	no declaration after statements for older compilers, avoid unused variable
+	* src/mathutils.c: prevent segfault with Accelerate.framework (closes #58,
+	closes #102)
+	* src/spectral/phasevoc.h: add aubio_pvoc_set_window to change the windowing
+	function
+	* src/mathutils.c: add window type `ones` (no windowing)
+
+	[ Python ]
+
+	* python/demos/demo_tapthebeat.py: add a real-time example to play beats
+	using pyaudio
+	* python/lib/gen_external.py: improve parsing and syntax, use results in
+	emscripten build (Martin Hermant)
+	* python/lib/aubio/cmd.py: add option `-u` to `aubio pitch`, improve error
+	messages, add `quiet` subcommand (closes #124), improve syntax, add some
+	documentation, add `cut` and `help` subcommand, add silence and time format
+	options
+	* python/lib/aubio/cut.py: upgrade to argparse, set samplerate as needed
+	* python/demos/demo_yin_compare.py: add comparison of yin implementations
+	* python/demos/demo_wav2midi.py: add an example to create a midi from a
+	sound file using mido (closes: #134)
+	* python/demos/demo_bpm_extract.py: use argparse, use beats_to_bpm function
+	* python/ext/py-cvec.c: fix support for pypy by changing setters to return a
+	negative value on error (closes #17)
+
+	[ Documentation ]
+
+	* src/tempo/beattracking.h: fix typo (thanks to Hannes Fritz)
+	* doc/requirements.rst: fix broken link (thanks to @ssj71, closes #99)
+	* doc/aubiomfcc.txt: fix typo in 'coefficients'
+
+	[ Tests ]
+
+	* python/tests/tests_aubio_{cmd,cut}.py: add basic tests
+	* python/tests/test_filterbank*.py: ignore UserWarnings, clean-up,
+	improve get_coeff tests
+
+	[ Build system ]
+
+	* wscript: add support for emscripten, see scripts/build_emscripten
+	* scripts/get_waf.sh: update waf to 2.0.1, build waf from source tarball
+	* scripts/build_emscripten: update to build aubio.js
+	* Makefile: add coverage and coverage_report targets, run tests once
+
+	[ Continuous integration ]
+
+	* .travis.yml: add coverage report on osx
+	* .appveyor.yml: use msvc 14.0 (VS 2015) and scripts/get_waf.sh
+	* .coveragerc: add minimal python coverage configuration
+
+2017-04-10 Paul Brossier <piem@aubio.org>
+
+	[Overview]
+
+	* VERSION: bump to 0.4.5
+	* src/io/source_avcodec.c: add support for libswresample
+	* aubio: new python command line tool to extract information
+	* src/onset/onset.c: add spectral whitening and compression, improve default
+	parameters
+	* this_version.py: use centralized script to get current version, adding git
+	sha when building from git repo (thanks to MartinHN)
+
+	[Interface]
+
+	* src/spectral/awhithening.h: add adaptive whitening
+	* src/{cvec,mathutils,musicutils}.h: add cvec_logmag, fvec_logmag, and fvec_push
+	* src/onset/onset.h: add aubio_onset_set_default_parameters to load optimal
+	parameters of each novelty function, _{set,get}_compression and
+	_{set,get}_awhitening to turn on/off compression and adaptive whitening
+	* src/spectral/specdesc.h: add weighted phase
+
+	[Library]
+
+	* src/onset/onset.c: improve default onset parameters (thanks to @superbock
+	for access to his evaluation database), see commit dccfad2 for more details
+	* src/pitch/pitch.c: avoid segfault when using invalid parameters
+	* src/temporal/biquad.c: fix biquad parameters initialization (thanks to
+	@jurlhardt)
+
+	[Tools]
+
+	* examples/aubio{onset,track}.c: add options --miditap-note and
+	--miditap-velo to set which midi note is triggered at onset/beat (thanks to
+	@tseaver)
+	* examples/aubioonset.c: show actual parameters in verbose mode
+	* examples/utils.c: improve memory usage to emit midi notes
+
+	[Python]
+
+	* python/ext/py-source.c: add with (PEP 343) and iter (PEP 234) interface
+	* python/ext/py-sink.c: add with interface (PEP 343)
+	* python/lib/aubio/cmd.py: new `aubio` command line tool
+	* python/lib/aubio/cut.py: moved from python/scripts/aubiocut
+
+	[Documentation]
+
+	* doc/*.rst: reorganize and improve sphinx manual
+	* doc/*.txt: update manpages, add simple manpage for aubio command line
+	* doc/full.cfg: derive from doc/web.cfg
+	* README.md: simplify and add contribute information
+
+	[Build system]
+
+	* wscript: prefer libswresample over libavsamplerate when available, use
+	current version in manpages, doxygen, and sphinx, update to newest waf
+	* setup.py: use entry_points console_scripts to generate scripts, use
+	centralized version from this_version.py, clean up
+	* python/lib/moresetuptools.py: detect if libswresample is available
+
+2017-01-08 Paul Brossier <piem@aubio.org>
+
+	[ Overview ]
+
+	* VERSION: bump to 0.4.4
+	* src/utils/log.h: new function to redirect log, error, and warnings
+	* python/: AUBIO_ERR raises python exception, AUBIO_WRN to emit py warning
+	* doc/: add some documentation, fix errors in manpages
+	* wscript: new rules to build 'manpages', 'doxygen', and 'sphinx', new
+	--build-type=<release|debug> option (thanks to Eduard Mueller)
+	* src/notes/notes.h: add minioi and silence methods
+	* examples/: add --minioi (minimum inter-onset interval) option
+	* src/pitch/pitchyin.c: improve msvc compiler optimisations (thanks to
+	Eduard Mueller)
+	* python/, src/: improve error messages, fix minor memory leaks
+	* src/io/source_avcodec.c: improve compatibility with latest ffmpeg and with
+	older libav/ffmpeg versions
+	* python/demos/: new demos to capture microphone in real time
+
+	[ Interface]
+
+	* src/aubio.h: include utils/log.h
+	* src/utils/log.h: add new aubio_log_set_function to redirect log messages
+	* src/notes/notes.h: add aubio_notes_{get,set}_minioi_ms, add
+	_{get,set}_silence methods
+
+	[ Library ]
+
+	* src/aubio_priv.h: add AUBIO_INF to print to stdout with header, use new
+	logging function, add ATAN alias, add stdarg.h, move #include "config.h"
+	* src/{fmat,fvec}.c: avoid integer division
+	* src/pitch/pitchyin.c: [msvc] help compiler to optimize aubio_pitchyin_do
+	by giving it addresses for all arrays which are referenced in inner loops,
+	thanks to Eduard Mueller.
+	* src/pitch/pitch.c: declare internal functions as static, fail on wrong
+	method, warn on wrong unit, improve error messages, fix error string
+	* src/spectral/specdesc.c: return NULL if wrong mode asked, remove trailing
+	spaces
+	* src/onset/onset.c: return null and clean-up if new_aubio_specdesc failed,
+	fix error message
+	* src/notes/notes.c: use midi note to store pitch candidate, round to
+	nearest note, add a variable to define precision, fix out-of-bound write,
+	fix unset silence_threshold, fix error message
+	* src/spectral/ooura_fft8g.c: add cast to avoid conversion warnings, prefix
+	public function with aubio_ooura_ to avoid with other apps using ooura (e.g.
+	puredata), make internal functions static,
+	* src/spectral/fft.c: add message about fftw3 being able to do non-power of
+	two sizes, make calls to fftw_destroy_plan thread-safe, use prefixed
+	aubio_ooura_rdft
+	* src/spectral/phasevoc.c: fix error string
+	* src/temporal/resampler.c: throw an error when using libsamplerate with doubles
+	* src/io/ioutils.h: add functions to check samplerate and channels, use in sink_*.c
+	* src/io/source.c: add error message when aubio was compiled with no source,
+	only show error message from last child source_
+	* src/io/source_avcodec.c: call avformat_free_context after
+	avformat_close_input, keep a reference to packet to remove it when closing
+	file, avoid deprecation warnings with ffmpeg 3.2, add backward compatibility
+	for libavcodec55, fix for old libavcodec54, use AV_SAMPLE_FMT_DBL when
+	compiling with HAVE_AUBIO_DOUBLE, fix missing samples in eof block, avoid
+	function calls before declarations, improve error messages, replace with new
+	context before closing old one, make sure s->path is set to null
+	* src/io/{source_wavread,sink_wavwrite}.c: declare internal functions as static
+	* src/io/source_wavread.c: fix bytes_read for JUNK headers, improve error
+	messages, initialize buffer, skip chunks until data is found, or abort, skip
+	junk chunk
+	* src/io/source_sndfile.c: add support for multi-channel resampling, set
+	handle to null after sucessful close, add missing floor in ratio comparison,
+	improve formatting
+	* src/io/sink.c: only show error message from last child sink_
+	* src/io/sink_apple_audio.c: avoid crash on empty file name
+	* src/io/sink_sndfile.c: improve error message
+	* src/io/sink_{sndfile,wavwrite}.c: use AUBIO_MAX_CHANNELS, fix error message
+
+	[ Documentation ]
+
+	* README.md: update copyright dates, use https
+	* src/aubio.h: add some links to examples, use https
+	* src/pitch/pitch.h: add aubio_pitch_get_tolerance, add basic description of
+	unit modes
+	* src/notes/notes.h: add doxygen header
+	* src/spectral/fft.h: strip example path
+	* doc/*.rst: improve sphinx documentation
+	* doc/android.rst: add reference to it scripts/build_android
+	* doc/debian_packages.rst: added page on debian packages
+	* doc/python_module.rst: add demo_source_simple.py, add note on pip, add
+	`print(aubio.version)`
+	* doc/cli.rst: include command line manpages
+	* doc/cli_features.rst: add matrix of command line features
+	* doc/requirements.rst: add a note about --notests (closes #77), document
+	--msvc options, improve description of options
+	* doc/download.rst: added page on download
+	* doc/installing.rst: update
+	* doc/xcode_frameworks.rst: added page on xcode frameworks
+	* doc/**: use https://aubio.org
+	* doc/conf.py: use pyramid theme, update copyright, remove hardcoded path
+	* doc/web.cfg: exclude ioutils from doc
+	* doc/aubionotes.txt: document -M option (see #18),
+	* doc/aubioonset.txt: add documentation for -M, --minioi, improve threshold
+	description (thanks to Peter Parker), fix typo (onset, not pitch)
+	* doc/aubio*.txt: document -T/--timeformat option
+
+	[ Build ]
+
+	* Makefile: add a brief intro, avoid offline operations, add html and dist
+	targets, add rules for documentation, simplify listing, avoid offline
+	operations, bump waf to 1.9.6, check for waf before clean, chmod go-w
+	waflib, improve clean, use pip to install, factorise pip options, generate
+	more test sounds, improve test_python and test_pure_python, pass build_ext
+	in test_pure_python{,_wheel}, quieten uninstall_python if already
+	uninstalled, improve test targets, use bdist_wheel in test_pure_python,
+	build_ext only for --enable-double, verbose waf rules, add cleanwaf
+	* wscript: added debug/release build type configurations release (default)
+	enables optimizations, debug symbols are enabled in both configurations,
+	thanks to Eduard Mueller.
+	* wscript: add options to disable source_wavread/sink_wavwrite, add check
+	for stdarg.h, new rules 'manpages', 'sphinx', and 'doxygen' to build
+	documentation, add version to sphinx and manpages, disable libsamplerate
+	if double precision enabled (libsamplerate only supports float), fix typos,
+	remove trailing spaces, improve tarball creation (./waf dist), remove
+	full.cfg from tarball, prepend to CFLAGS to honor user cflags
+	* wscript, src/wscript_build: improve install locations using DATAROOTDIR,
+	MANDIR, INCLUDEDIR
+	* wscript: default to no atlas for now
+	* src/wscript_build: always build static library
+	* scripts/build_android: add an example script to build aubio on android,
+
+	[ Tools ]
+
+	* examples/aubionotes.c: use new notes, set minioi, send last note off when
+	needed, add warning for missing options
+	* examples/aubioonset.c: add minioi option, in seconds
+	* examples/: only send a last note off when using jack
+	* examples/: return 1 if object creation failed
+	* examples/: use PROG_HAS_OUTPUT, add PROG_HAS_SILENCE
+
+	[ Tests ]
+
+	* tests/src/spectral/test-fft.c: fix default size
+	* tests/src/spectral/test-phasevoc.c: fix typos
+	* tests/src/utils/test-log.c: add AUBIO_INF, add example for
+	aubio_log_set_function, improve messages
+
+	[ Python ]
+
+	* python/ext/aubiomodule.c: add aubio._aubio.__version__ and import it as
+	aubio.version, use custom logging function for errors and warnings, remove
+	duplicated add_generated_objects, use <> for non local aubio
+	* python/ext/py-cvec.c: use NPY_INTP_FMT
+	* python/ext/py-fft.c: use error string set in src/spectral/fft.c
+	* python/ext/py-phasevoc.c: use error string set in src/spectral/phasevoc.c
+	* python/ext/py-sink.c: always set samplerate and channels in init
+	* python/ext/py-source.c: use error string set in src/io/source.c
+	* python/lib/aubio/midiconv.py: add unicode double sharp and double flat,
+	improve unicode handling, skip UnicodeEncodeError on python 2.x
+
+	[ Python build ]
+
+	* MANIFEST.in: add src/**.c, exclude full.cfg, include waflib, remove
+	python/ext/config.h
+	* setup.py: define AUBIO_VERSION use sorted glob.glob to improve
+	reproducibility, remove extra quotes, remove status from version string,
+	update description, use custom build_ext instead of 'generate' command,
+	define HAVE_AUBIO_DOUBLE to 1 if needed
+	* python/lib/gen_code.py: add support for multiple _do outputs, fix number
+	of output, improve del_ function, safer DECREF, fix indentation, emit RuntimeError
+	* python/lib/gen_external.py: clean-up, enable tss, remove duplicate,
+	sort generated files
+	* python/lib/moresetuptools.py: add HAVE_STDARG_H, also check for
+	HAVE_AUBIO_DOUBLE, cleaner clean, look first for system library, then for
+	local build, then local sources, mo nore fake config.h here, use
+	samplerate in single precision only
+	* python/README.md: add a note about nose2 for python tests (closes #74)
+	* scripts/setenv_local.sh: python3 compat
+
+	[ Python demos ]
+
+	* python/demos/demo_alsa.py: add example using alsaaudio (closes #72)
+	* python/demos/demo_mfcc.py: add options to plot first and second
+	derivatives, and set samplerate/win_s/hop_s, thanks to @jhoelzl (closes #68)
+	* python/demos/demo_notes.py: add simple notes demos
+	* python/demos/demo_pyaudio.py: added simple demo for pyaudio, see #6,
+	closes #78, thanks to @jhoelzl and @notalentgeek, add some comments, avoid
+	overwriting aubio.pitch
+	* python/demos/demo_source_simple.py: fix indentation, make executable
+	* python/demos/demo_timestretch{,_online}.py: fix usage string, remove
+	unused import, use // to yield an integer (closes #71)
+	* python/demos/demo_timestretch_online.py: use 512, fix block counter
+	* python/demos/demo_tss.py: improve default parameters, exit before plotting
+
+	[ Python tests ]
+
+	* python/tests/: use local import, add __init__.py
+	* python/tests/test_cvec.py: simplify
+	* python/tests/test_fft.py: skip test fft(zeros).phas == 0 if needed, expected powerpc
+	* python/tests/test_fvec.py: reduce alpha norm precision to 10.-4
+	* python/tests/test_{midi2note,note2midi}.py: use nose2.params, add unicode tests
+	* python/tests/test_notes.py: add basic tests
+	* python/tests/test_notes.py: test results are correct for 44100Hz_44100f_sine441.wav
+	* python/tests/test_sink.py: add more tests, quiet warnings
+	* python/tests/test_source.py: break long line, check the tail of the file
+	is non-zero on non silent test files, filter user warnings to avoid spamming
+	the console, only check if last frames are non silent on brownnoise (weak),
+	remove fragile brownnoise test, check duration on short files, use nose2
+	params to process one sound file per test
+	* python/tests/test_specdesc.py: RuntimeError is now raised on wrong mode
+	* python/tests/utils.py: by default, use 5 seconds brownoise
+
+	[ Only in git ]
+
+	* .travis.yml: add debian dpkg-buildflags config, switch from precise to
+	trusty, sudo required, add ffmpeg on osx, add targets ios, iosimulator,
+	and osx noopt configs, bump to xcode8, add xcode8.2 config, mimick
+	build_apple_frameworks options, alway upgrade pip, add pip --version and
+	which pip after upgrading, remove --user, use expandwaf in install, remove
+	unused ARCH, shuffle order, remove duplicate, add missing opening quote,
+	use AUBIO_NOTESTS to build only lib on ios, add gitter webhook
+	* .appveyor.yml: fix path for windows+python 3.5, fix typo in path, make
+	nose2 tests verbose
+
 2016-08-16 Paul Brossier <piem@aubio.org>
 
 	[ Interface ]
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,7 +1,10 @@
 include AUTHORS COPYING README.md VERSION ChangeLog
 include python/README.md
-include Makefile wscript */wscript_build
+include this_version.py
+include waf_gensyms.py
 include waf
+recursive-include waflib *.py
+include Makefile wscript */wscript_build
 include aubio.pc.in
 include nose2.cfg
 include requirements.txt
@@ -10,16 +13,12 @@
 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
+recursive-include python *.py
+include python/README.md
 include python/tests/run_all_tests
-include python/tests/*.py
-include python/demos/*.py
+include python/tests/eval_pitch
 include python/tests/*.expected
 include doc/*.txt doc/*.rst doc/*.cfg doc/Makefile doc/make.bat doc/conf.py
+exclude doc/full.cfg
 include scripts/* scripts/apple/Info.plist scripts/apple/Modules/module.modulemap
 exclude python/gen/*
-exclude python/ext/config.h
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,49 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+#
+# This makefile contains simple rules to prepare, compile, test, and install
+# aubio. Try one of the following rules:
+#
+# $ make configure
+# $ make build
+# $ make install
+# $ make test_python
+
 WAFCMD=python waf
-WAFURL=https://waf.io/waf-1.8.22
 
+#WAFOPTS:=
+# turn on verbose mode
+WAFOPTS += --verbose
+# build wafopts
+WAFOPTS += --destdir $(DESTDIR)
+# multiple jobs
+WAFOPTS += --jobs 4
+# if HAVE_AUBIO_DOUBLE is defined, pass --enable-double to waf
+# python/lib/moresetuptools.py also checks for HAVE_AUBIO_DOUBLE
+WAFOPTS += $(shell [ -z $(HAVE_AUBIO_DOUBLE) ] || echo --enable-double )
+
+PIPOPTS += --verbose
+
+DESTDIR:=$(PWD)/build/dist
+PYDESTDIR:=$(PWD)/build/pydist
+
+# default install locations
+PREFIX?=/usr/local
+EXEC_PREFIX?=$(PREFIX)
+LIBDIR?=$(PREFIX)/lib
+INCLUDEDIR?=$(PREFIX)/include
+DATAROOTDIR?=$(PREFIX)/share
+MANDIR?=$(DATAROOTDIR)/man
+
+# default nose2 command
+NOSE2?=nose2 -N 4 --verbose
+
 SOX=sox
 
-ENABLE_DOUBLE := $(shell [ -z $(HAVE_DOUBLE) ] || echo --enable-double )
 TESTSOUNDS := python/tests/sounds
 
+LCOVOPTS += --rc lcov_branch_coverage=1
+
 all: build
 
 checkwaf:
@@ -12,76 +50,130 @@
 	@[ -f waf ] || make getwaf
 
 getwaf:
-	@./scripts/get_waf.sh
+	./scripts/get_waf.sh
 
-expandwaf:
-	@[ -d wafilb ] || rm -fr waflib
-	@$(WAFCMD) --help > /dev/null
-	@mv .waf*/waflib . && rm -fr .waf*
-	@sed '/^#==>$$/,$$d' waf > waf2 && mv waf2 waf
-	@chmod +x waf
+expandwaf: getwaf
+	[ -d wafilb ] || rm -fr waflib
+	$(WAFCMD) --help > /dev/null
+	mv .waf*/waflib . && rm -fr .waf*
+	sed '/^#==>$$/,$$d' waf > waf2 && mv waf2 waf
+	chmod +x waf && chmod -R go-w waflib
 
+cleanwaf:
+	rm -rf waf waflib .waf*
+
 configure: checkwaf
-	$(WAFCMD) configure $(WAFOPTS) $(ENABLE_DOUBLE)
+	$(WAFCMD) configure $(WAFOPTS)
 
 build: configure
 	$(WAFCMD) build $(WAFOPTS)
 
+install:
+	# install
+	$(WAFCMD) install $(WAFOPTS)
+
+list_installed:
+	find $(DESTDIR) -ls | sed 's|$(DESTDIR)|/«destdir»|'
+
+list_installed_python:
+	pip show -f aubio
+
+list_all_installed: list_installed list_installed_python
+
+uninstall:
+	# uninstall
+	$(WAFCMD) uninstall $(WAFOPTS)
+
+delete_install:
+	rm -rf $(PWD)/dist/test
+
 build_python:
-	python ./setup.py generate $(ENABLE_DOUBLE) build
+	# build python-aubio, using locally built libaubio if found
+	python ./setup.py 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
+build_python_extlib:
+	# build python-aubio using (locally) installed libaubio
+	[ -f $(DESTDIR)/$(INCLUDEDIR)/aubio/aubio.h ]
+	[ -d $(DESTDIR)/$(LIBDIR) ]
+	[ -f $(DESTDIR)/$(LIBDIR)/pkgconfig/aubio.pc ]
+	PKG_CONFIG_PATH=$(DESTDIR)/$(LIBDIR)/pkgconfig \
+	CFLAGS="-I$(DESTDIR)/$(INCLUDEDIR)" \
+	LDFLAGS="-L$(DESTDIR)/$(LIBDIR)" \
+		make build_python
 
-test_python_osx:
+deps_python:
+	# install or upgrade python requirements
+	pip install $(PIPOPTS) --requirement requirements.txt
+
+# use pip or distutils?
+install_python: install_python_with_pip
+uninstall_python: uninstall_python_with_pip
+#install_python: install_python_with_distutils
+#uninstall_python: uninstall_python_with_distutils
+
+install_python_with_pip:
+	# install package
+	pip install $(PIPOPTS) .
+
+uninstall_python_with_pip:
+	# uninstall package
+	( pip show aubio | grep -l aubio > /dev/null ) && \
+	pip uninstall -y -v aubio || echo "info: aubio package is not installed"
+
+install_python_with_distutils:
+	./setup.py install $(PIPOPTS) $(DISTUTILSOPTS)
+
+uninstall_python_with_distutils:
+	#./setup.py uninstall
+	[ -d $(PYDESTDIR)/$(LIBDIR) ] && echo Warning: did not clean $(PYDESTDIR)/$(LIBDIR) || true
+
+force_uninstall_python:
+	# ignore failure if not installed
+	-make uninstall_python
+
+local_dylib:
+	# DYLD_LIBRARY_PATH is no more on mac os
 	# create links from ~/lib/lib* to build/src/lib*
-	[ -f build/src/libaubio.[0-9].dylib ] && ( mkdir -p ~/lib && cp -prv build/src/libaubio.[0-9].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
+	[ -f $(PWD)/build/src/libaubio.[0-9].dylib ] && ( mkdir -p ~/lib && cp -prv build/src/libaubio.[0-9].dylib ~/lib ) || true
 
+test_python: export LD_LIBRARY_PATH=$(DESTDIR)/$(LIBDIR)
+test_python: export PYTHONPATH=$(PYDESTDIR)/$(LIBDIR)
+test_python: local_dylib
+	# run test with installed package
+	# ./python/tests/run_all_tests --verbose
+	# run with nose2, multiple processes
+	$(NOSE2)
+
 clean_python:
 	./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
+check_clean_python:
+	# check cleaning a second time works
+	make clean_python
+	make clean_python
 
-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
+clean: checkwaf
+	# optionnaly clean before build
+	-$(WAFCMD) clean
+	# remove possible left overs
+	-rm -rf doc/_build
 
-build_python3:
-	python3 ./setup.py generate $(ENABLE_DOUBLE) build
+check_clean:
+	# check cleaning after build works
+	$(WAFCMD) clean
+	# check cleaning a second time works
+	$(WAFCMD) clean
 
-clean_python3:
-	python3 ./setup.py clean
+distclean:
+	$(WAFCMD) distclean
+	-rm -rf doc/_build/
+	-rm -rf doc/web/
 
-clean:
-	$(WAFCMD) clean
+check_distclean:
+	make distclean
 
 distcheck: checkwaf
-	$(WAFCMD) distcheck $(WAFOPTS) $(ENABLE_DOUBLE)
+	$(WAFCMD) distcheck $(WAFOPTS)
 
 help:
 	$(WAFCMD) --help
@@ -89,8 +181,113 @@
 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 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_1f_silence.wav"      trim 0 1s
 	-$(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  8000 -b 16 -n "$(TESTSOUNDS)/8000Hz_30s_silence.wav"      trim 0 30
 	-$(SOX) -r 48000 -b 32 -n "$(TESTSOUNDS)/48000Hz_60s_sweep.wav"       synth 60   sine 100-20000  vol 0.9
+	-$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_44100f_sine441.wav"  synth 44100s   sine 441 	vol 0.9
+	-$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_100f_sine441.wav"    synth 100s sine 441 	vol 0.9
+
+# build only libaubio, no python-aubio
+test_lib_only: clean distclean configure build install list_installed
+# additionally, clean after a fresh build
+test_lib_only_clean: test_lib_only uninstall check_clean check_distclean
+
+# build libaubio, build and test python-aubio against it
+test_lib_python: force_uninstall_python deps_python \
+	clean_python clean distclean \
+	configure build build_python \
+	install install_python \
+	test_python \
+	list_all_installed
+
+test_lib_python_clean: test_lib_python \
+	uninstall_python uninstall \
+	check_clean_python \
+	check_clean \
+	check_distclean
+
+# build libaubio, install it, build python-aubio against it
+test_lib_install_python: force_uninstall_python deps_python \
+	clean_python distclean \
+	configure build \
+	install \
+	build_python_extlib \
+	install_python \
+	test_python \
+	list_all_installed
+
+test_lib_install_python_clean: test_lib_install_python \
+	uninstall_python \
+	delete_install \
+	check_clean_python \
+	check_distclean
+
+# build a python-aubio that includes libaubio
+test_python_only: force_uninstall_python deps_python \
+	clean_python clean distclean \
+	build_python \
+	install_python \
+	test_python \
+	list_installed_python
+
+test_python_only_clean: test_python_only \
+	uninstall_python \
+	check_clean_python
+
+coverage_cycle: coverage_zero_counters coverage_report
+
+coverage_zero_counters:
+	lcov --zerocounters --directory .
+
+coverage: export CFLAGS=--coverage
+coverage: export LDFLAGS=--coverage
+coverage: export PYTHONPATH=$(PWD)/python/lib
+coverage: export LD_LIBRARY_PATH=$(PWD)/build/src
+coverage: force_uninstall_python deps_python \
+	clean_python clean distclean build local_dylib
+	# capture coverage after running c tests
+	lcov $(LCOVOPTS) --capture --no-external --directory . \
+		--output-file build/coverage_lib.info
+	# build and test python
+	pip install -v -e .
+	# run tests, with python coverage
+	coverage run `which nose2`
+	# capture coverage again
+	lcov $(LCOVOPTS) --capture --no-external --directory . \
+		--output-file build/coverage_python.info
+	# merge both coverage info files
+	lcov $(LCOVOPTS) -a build/coverage_python.info -a build/coverage_lib.info \
+		--output-file build/coverage.info
+	# remove tests
+	lcov $(LCOVOPTS) --remove build/coverage.info '*/ooura_fft8g*' \
+		--output-file build/coverage_lib.info
+
+# make sure we don't build the doc, which builds a temporary python module
+coverage_report: export WAFOPTS += --disable-docs
+coverage_report: coverage
+	# generate report with lcov's genhtml
+	genhtml build/coverage_lib.info --output-directory build/coverage_c \
+		--branch-coverage --highlight --legend
+	# generate python report with coverage python package
+	coverage report
+	coverage html -d build/coverage_python
+	# show links to generated reports
+	for i in $$(ls build/coverage_*/index.html); do echo file://$(PWD)/$$i; done
+
+sphinx: configure
+	$(WAFCMD) sphinx $(WAFOPTS)
+
+doxygen: configure
+	$(WAFCMD) doxygen $(WAFOPTS)
+
+manpages: configure
+	$(WAFCMD) manpages $(WAFOPTS)
+
+html: doxygen sphinx
+
+docs: html manpages
+
+dist: distclean expandwaf
+	$(WAFCMD) dist
--- a/README.md
+++ b/README.md
@@ -1,6 +1,14 @@
-aubio library
-=============
+aubio
+=====
 
+[![Travis build status](https://travis-ci.org/aubio/aubio.svg?branch=master)](https://travis-ci.org/aubio/aubio "Travis build status")
+[![Appveyor build status](https://img.shields.io/appveyor/ci/piem/aubio/master.svg)](https://ci.appveyor.com/project/piem/aubio "Appveyor build status")
+[![Landscape code health](https://landscape.io/github/aubio/aubio/master/landscape.svg?style=flat)](https://landscape.io/github/aubio/aubio/master "Landscape code health")
+[![Commits since last release](https://img.shields.io/github/commits-since/aubio/aubio/latest.svg)](https://github.com/aubio/aubio "Commits since last release")
+
+[![Documentation](https://readthedocs.org/projects/aubio/badge/?version=latest)](http://aubio.readthedocs.io/en/latest/?badge=latest "Latest documentation")
+[![DOI](https://zenodo.org/badge/396389.svg)](https://zenodo.org/badge/latestdoi/396389)
+
 aubio is a library to label music and sounds. It listens to audio signals and
 attempts to detect events. For instance, when a drum is hit, at which frequency
 is a note, or at what tempo is a rhythmic melody.
@@ -20,7 +28,7 @@
   - digital filters (low pass, high pass, and more)
   - spectral filtering
   - transient/steady-state separation
-  - sound file and audio devices read and write access
+  - sound file read and write access
   - various mathematics utilities for music applications
 
 The name aubio comes from _audio_ with a typo: some errors are likely to be
@@ -29,15 +37,20 @@
 Python module
 -------------
 
-A python module to access the library functions is also provided. Please see
-the file [`python/README.md`](python/README.md) for more information on how to
-use it.
+A python module for aubio is provided. For more information on how to use it,
+please see the file [`python/README.md`](python/README.md) and the
+[manual](https://aubio.org/manual/latest/) .
 
-Examples tools
---------------
+Tools
+-----
 
-A few simple command line tools are included along with the library:
+The python module comes with the following command line tools:
 
+ - `aubio` extracts informations from sound files
+ - `aubiocut` slices sound files at onset or beat timestamps
+
+Additional command line tools are included along with the library:
+
  - `aubioonset` outputs the time stamp of detected note onsets
  - `aubiopitch` attempts to identify a fundamental frequency, or pitch, for
    each frame of the input sound
@@ -46,27 +59,12 @@
  - `aubionotes` emits midi-like notes, with an onset, a pitch, and a duration
  - `aubioquiet` extracts quiet and loud regions
 
-Additionally, the python module comes with the following script:
+Documentation
+-------------
 
- - `aubiocut` slices sound files at onset or beat timestamps
+  - [manual](https://aubio.org/manual/latest/), generated with sphinx
+  - [developer documentation](https://aubio.org/doc/latest/), generated with Doxygen
 
-Implementation and Design Basics
---------------------------------
-
-The library is written in C and is optimised for speed and portability.
-
-The C API is designed in the following way:
-
-    aubio_something_t * new_aubio_something (void * args);
-    audio_something_do (aubio_something_t * t, void * args);
-    smpl_t aubio_something_get_a_parameter (aubio_something_t *t);
-    uint_t aubio_something_set_a_parameter (aubio_something_t *t, smpl_t a_parameter);
-    void del_aubio_something (aubio_something_t * t);
-
-For performance and real-time operation, no memory allocation or freeing take
-place in the `_do` methods. Instead, memory allocation should always take place
-in the `new_` methods, whereas free operations are done in the `del_` methods.
-
 The latest version of the documentation can be found at:
 
   https://aubio.org/documentation
@@ -74,105 +72,42 @@
 Build Instructions
 ------------------
 
-A number of distributions already include aubio. Check your favorite package
-management system, or have a look at the [download
-page](https://aubio.org/download).
+aubio compiles on Linux, Mac OS X, Windows, Cygwin, and iOS.
 
-aubio uses [waf](https://waf.io/) to configure, compile, and test the source:
+To compile aubio, you should be able to simply run:
 
-    ./waf configure
-    ./waf build
+    make
 
-If waf is not found in the directory, you can download and install it with:
+To compile the python module:
 
-    make getwaf
+    ./setup.py build
 
-aubio compiles on Linux, Mac OS X, Cygwin, and iOS.
+See the [manual](https://aubio.org/manual/latest/) for more information about
+[installing aubio](https://aubio.org/manual/latest/installing.html).
 
-Installation
-------------
+Citation
+--------
 
-To install aubio library and headers on your system, use:
+Please use the DOI link above to cite this release in your publications. For
+more information, see also the [about
+page](https://aubio.org/manual/latest/about.html) in [aubio
+manual](https://aubio.org/manual/latest/).
 
-    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
-------------------------
+Homepage
+--------
 
-This library gathers music signal processing algorithms designed at the Centre
-for Digital Music and elsewhere. This software project was developed along the
-research I did at the Centre for Digital Music, Queen Mary, University of
-London. Most of this C code was written by myself, starting from published
-papers and existing code. The header files of each algorithm contains brief
-descriptions and references to the corresponding papers.
-
-Special thanks go Juan Pablo Bello, Chris Duxbury, Samer Abdallah, Alain de
-Cheveigne for their help and publications. Also many thanks to Miguel Ramirez
-and Nicolas Wack for their bug fixing.
-
-Substantial informations about the algorithms and their evaluation are gathered
-in:
-
-  - Paul Brossier, _[Automatic annotation of musical audio for interactive
-    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
-papers:
-
-  - P. M. Brossier and J. P. Bello and M. D. Plumbley, [Real-time temporal
-    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] (https://aubio.org/articles/brossier04fastnotes.pdf),
-in _Proceedings of the International Symposium on Music Information Retrieval_,
-2004, Barcelona, Spain
-
-
-Contact Info and Mailing List
------------------------------
-
 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>.
+License
+-------
 
-To subscribe to the list, use the mailman form:
-http://lists.aubio.org/listinfo/aubio-user/
-
-Alternatively, feel free to contact directly the author.
-
-
-Copyright and License Information
----------------------------------
-
-Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
-
-aubio is free software: you can redistribute it and/or modify it under the
+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.
+
+Contributing
+------------
+
+Patches are welcome: please fork the latest git repository and create a feature
+branch. Submitted requests should pass all continuous integration tests.
--- a/VERSION
+++ b/VERSION
@@ -1,7 +1,7 @@
 AUBIO_MAJOR_VERSION=0
 AUBIO_MINOR_VERSION=4
-AUBIO_PATCH_VERSION=4
+AUBIO_PATCH_VERSION=9
 AUBIO_VERSION_STATUS='~alpha'
 LIBAUBIO_LT_CUR=5
-LIBAUBIO_LT_REV=0
-LIBAUBIO_LT_AGE=4
+LIBAUBIO_LT_REV=4
+LIBAUBIO_LT_AGE=8
--- a/aubio.pc.in
+++ b/aubio.pc.in
@@ -7,4 +7,4 @@
 Description: a library for audio labelling
 Version: @VERSION@
 Libs: -L${libdir} -laubio
-Cflags: -I${includedir} 
+Cflags: -I${includedir}
--- /dev/null
+++ b/azure-pipelines.yml
@@ -1,0 +1,38 @@
+#  configuration file for azure continuous integration
+jobs:
+
+- job: linux
+  pool:
+    vmImage: 'Ubuntu 16.04'
+  steps:
+  - script: |
+      make
+    displayName: 'make'
+    env:
+      CFLAGS: -Werror
+
+- job: windows
+  pool:
+    vmIMage: 'VS2017-Win2016'
+  steps:
+  - script: |
+      make
+    displayName: 'make'
+    env:
+      # fail on error
+      CFLAGS: /WX
+
+- job: macos
+  pool:
+    vmIMage: macOS-10.13
+  steps:
+  - script: |
+      brew update
+      brew install pkg-config gnupg
+      brew install sox ffmpeg libsndfile lcov
+    displayName: 'brew install'
+  - script: |
+      make
+    displayName: 'make'
+    env:
+      CFLAGS: -Werror
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -39,9 +39,11 @@
 	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
 
 clean:
+	-rm -rf _static
 	-rm -rf $(BUILDDIR)/*
 
 html:
+	mkdir -p _static
 	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
 	@echo
 	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
--- /dev/null
+++ b/doc/about.rst
@@ -1,0 +1,73 @@
+About
+=====
+
+This library gathers a collection of music signal processing algorithms written
+by several people. The documentation of each algorithms contains a brief
+description and references to the corresponding papers.
+
+Credits
+-------
+
+Many thanks to everyone who contributed to aubio, including:
+
+  - Martin Hermant (`MartinHN <https://github.com/MartinHN>`_)
+  - Eduard Müller (`emuell <https://github.com/emuell>`_)
+  - Nils Philippsen (`nphilipp <https://github.com/nphilipp>`_)
+  - Tres Seaver (`tseaver <https://github.com/tseaver>`_)
+  - Dirkjan Rijnders (`dirkjankrijnders <https://github.com/dirkjankrijnders>`_)
+  - Jeffrey Kern (`anwserman <https:/ /github.com/anwserman>`_)
+  - Sam Alexander (`sxalexander <https://github.com/sxalexander>`_)
+
+Special thanks to Juan Pablo Bello, Chris Duxbury, Samer Abdallah, Alain de
+Cheveigne for their help. Also many thanks to Miguel Ramirez and Nicolas Wack
+for their advices and help fixing bugs.
+
+Publications
+------------
+
+Substantial informations about several of the algorithms and their evaluation
+are gathered in:
+
+  - Paul Brossier, `Automatic annotation of musical audio for interactive
+    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
+papers:
+
+  - P. M. Brossier and J. P. Bello and M. D. Plumbley, `Real-time temporal
+    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
+    <https://aubio.org/articles/brossier04fastnotes.pdf>`, in *Proceedings of
+    the International Symposium on Music Information Retrieval*, 2004,
+    Barcelona, Spain
+
+Citation
+--------
+
+Please refer to the Zenodo link in the file README.md to cite this release.
+
+Copyright
+---------
+
+Copyright © 2003-2017 Paul Brossier <piem@aubio.org>
+
+License
+-------
+
+aubio is a `free <https://www.debian.org/intro/free>`_ and `open source
+<http://www.opensource.org/docs/definition.php>`_ software; **you** can
+redistribute it and/or modify it under the terms of the `GNU
+<https://www.gnu.org/>`_ `General Public License
+<https://www.gnu.org/licenses/gpl.html>`_ as published by the `Free Software
+Foundation <https://fsf.org>`_, either version 3 of the License, or (at your
+option) any later version.
+
+.. note::
+
+   aubio is not MIT or BSD licensed. Contact us if you need it in your
+   commercial product.
--- /dev/null
+++ b/doc/android.rst
@@ -1,0 +1,9 @@
+.. _android:
+
+Android build
+-------------
+
+To compile aubio for android, you will need to get the `Android Native
+Development Toolkit (NDK) <https://developer.android.com/ndk/>`_, prepare a
+standalone toolchain, and tell waf to use the NDK toolchain. An example script
+to complete these tasks is available in ``scripts/build_android``.
--- /dev/null
+++ b/doc/aubio.txt
@@ -1,0 +1,141 @@
+NAME
+  aubio - a command line tool to extract information from sound files
+
+SYNOPSIS
+
+  aubio [-h] [-V] <command> ...
+
+COMMANDS
+
+  The general syntax is "aubio <command> <soundfile> [options]". The following
+  commands are available:
+
+  onset        get onset times
+  pitch        extract fundamental frequency
+  beat         get locations of beats
+  tempo        get overall tempo in bpm
+  notes        get midi-like notes
+  mfcc         extract mel-frequency cepstrum coefficients
+  melbands     extract mel-frequency energies per band
+
+  For a list of available commands, use "aubio -h". For more info about each
+  command, use "aubio <command> --help".
+
+GENERAL OPTIONS
+
+  These options can be used before any command has been specified.
+
+  -h, --help  show help message and exit
+
+  -V, --version  show version
+
+COMMON OPTIONS
+
+  The following options can be used with all commands:
+
+  <source_uri>, -i <source_uri>, --input <source_uri>  input sound file to
+  analyse (required)
+
+  -r <freq>, --samplerate <freq>  samplerate at which the file should be
+  represented (default: 0, e.g. samplerate of the input sound)
+
+  -H <size>, --hopsize <size>  overlap size, number of samples between two
+  consecutive analysis (default: 256)
+
+  -B <size>, --bufsize <size>  buffer size, number of samples used for each
+  analysis, (e.g. FFT length, default: 512)
+
+  -h, --help  show help message and exit
+
+  -T format, --time-format format  select time values output format (samples,
+  ms, seconds) (default: seconds)
+
+  -v, --verbose  be verbose (increment verbosity by 1, default: 1)
+
+  -q, --quiet  be quiet (set verbosity to 0)
+
+ONSET
+
+  The following additional options can be used with the "onset" subcommand.
+
+  -m <method>, --method <method>  onset novelty function
+  <default|energy|hfc|complex|phase|specdiff|kl|mkl|specflux> (default:
+  default)
+
+  -t <threshold>, --threshold <threshold>  threshold (default: unset)
+
+  -s <value>, --silence <value>  silence threshold, in dB (default: -70)
+
+  -M <value>, --minioi <value>  minimum Inter-Onset Interval (default: 12ms)
+
+PITCH
+
+  The following additional options can be used with the "pitch" subcommand.
+
+  -m <method>, --method <method>  pitch detection method
+  <default|yinfft|yin|mcomb|fcomb|schmitt> (default: default, e.g. yinfft)
+
+  -t <threshold>, --threshold <threshold>  tolerance (default: unset)
+
+  -s <value>, --silence <value>  silence threshold, in dB (default: -70)
+
+  The default buffer size for the beat algorithm is 2048. The default hop size
+  is 256.
+
+BEAT
+
+  The "beat" command accepts all common options and no additional options.
+
+  The default buffer size for the beat algorithm is 1024. The default hop size
+  is 512.
+
+TEMPO
+
+  The "tempo" command accepts all common options and no additional options.
+
+  The default buffer size for the beat algorithm is 1024. The default hop size
+  is 512.
+
+NOTES
+
+  The following additional options can be used with the "notes" subcommand.
+
+  -s <value>, --silence <value>  silence threshold, in dB (default: -70)
+
+  -d <value>, --release-drop <value>  release drop level, in dB. If the level
+  drops more than this amount since the last note started, the note will be
+  turned off (default: 10).
+
+MFCC
+
+  The "mfcc" command accepts all common options and no additional options.
+
+MELBANDS
+
+  The "melbands" command accepts all common options and no additional options.
+
+EXAMPLES
+
+  Extract onsets using a minimum inter-onset interval of 30ms:
+
+    aubio onset /path/to/input_file -M 30ms
+
+  Extract pitch with method "mcomb" and a silence threshold of -90dB:
+
+    aubio pitch /path/to/input_file -m mcomb -s -90.0
+
+  Extract MFCC using the standard Slaney implementation:
+
+    aubio mfcc /path/to/input_file -r 44100
+
+
+SEE ALSO
+
+  aubiocut(1)
+
+AUTHOR
+
+  This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+  granted to copy, distribute and/or modify this document 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.
--- a/doc/aubiocut.txt
+++ b/doc/aubiocut.txt
@@ -34,9 +34,9 @@
   -b, --beat  Use beat locations instead of onset locations.
 
   -t, --onset-threshold thres  Set the threshold value for the onset peak
-  picking. Typical values are typically within 0.001 and 0.900. Defaults to
-  0.1. Lower threshold values imply more onsets detected. Try 0.5 in case of
-  over-detections. Defaults to 0.3.
+  picking. Values are typically in the range [0.001, 0.900]. Lower threshold
+  values imply more onsets detected. Increasing this threshold should reduce
+  the number of incorrect detections. Defaults to 0.3.
 
   -c, --cut  Cut input sound file at detected labels. A new sound files for
   each slice will be created in the current directory.
@@ -49,6 +49,8 @@
 
   --cut-until-nslices n  How many extra slices should be added at the end of
   each slice (default 0).
+
+  --create-first  Alway create first slice.
 
   -h, --help  Print a short help message and exit.
 
--- a/doc/aubiomfcc.txt
+++ b/doc/aubiomfcc.txt
@@ -15,7 +15,7 @@
 
   MFCCs are coefficients that make up for the mel-frequency spectrum, a
   representation of the short-term power spectrum of a sound. By default, 13
-  coefficents are computed using 40 filters.
+  coefficients are computed using 40 filters.
 
   When started with an input source (-i/--input), the coefficients are given on
   the console, prefixed by their timestamps in seconds.
@@ -51,7 +51,7 @@
   according to Malcolm Slaney's Auditory Toolbox, available at the following
   url:
 
-  http://cobweb.ecn.purdue.edu/~malcolm/interval/1998-010/ (see file mfcc.m)
+  https://engineering.purdue.edu/~malcolm/interval/1998-010/ (see file mfcc.m)
 
 SEE ALSO
 
--- a/doc/aubionotes.txt
+++ b/doc/aubionotes.txt
@@ -6,7 +6,7 @@
   aubionotes source
   aubionotes [[-i] source]
              [-r rate] [-B win] [-H hop]
-             [-O method] [-t thres]
+             [-O method] [-t thres] [-d drop]
              [-p method] [-u unit] [-l thres]
              [-T time-format]
              [-s sil]
@@ -50,6 +50,9 @@
   0.1. Lower threshold values imply more onsets detected. Try 0.5 in case of
   over-detections. Defaults to 0.3.
 
+  -M, --minioi value  Set the minimum inter-onset interval, in seconds, the
+  shortest interval between two consecutive notes. Defaults to 0.030
+
   -p, --pitch method  The pitch detection method to use. See PITCH METHODS
   below. Defaults to 'default'.
 
@@ -65,6 +68,10 @@
   will not be detected. A value of -20.0 would eliminate most onsets but the
   loudest ones. A value of -90.0 would select all onsets. Defaults to -90.0.
 
+  -d, --release-drop  Set the release drop threshold, in dB. If the level drops
+  more than this amount since the last note started, the note will be turned
+  off. Defaults to 10.
+
   -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
   seconds.
 
@@ -84,7 +91,8 @@
 
 PITCH METHODS
 
-  Available methods: default, schmitt, fcomb, mcomb, specacf, yin, yinfft.
+  Available methods: default, schmitt, fcomb, mcomb, specacf, yin, yinfft,
+  yinfast.
 
   See aubiopitch(1) for details about these methods.
 
--- a/doc/aubioonset.txt
+++ b/doc/aubioonset.txt
@@ -9,7 +9,8 @@
              [-O method] [-t thres]
              [-T time-format]
              [-s sil] [-m] [-f]
-             [-j] [-v] [-h]
+             [-j] [-N miditap-note] [-V miditap-velo]
+             [-v] [-h]
 
 DESCRIPTION
 
@@ -48,11 +49,14 @@
   below. Defaults to 'default'.
 
   -t, --onset-threshold thres  Set the threshold value for the onset peak
-  picking. Typical values are typically within 0.001 and 0.900. Defaults to
-  0.1. Lower threshold values imply more onsets detected. Try 0.5 in case of
-  over-detections. Defaults to 0.3.
+  picking. Values are typically in the range [0.001, 0.900]. Lower threshold
+  values imply more onsets detected. Increasing this threshold should reduce
+  the number of incorrect detections. Defaults to 0.3.
 
-  -s, --silence sil  Set the silence threshold, in dB, under which the pitch
+  -M, --minioi value  Set the minimum inter-onset interval, in seconds, the
+  shortest interval between two consecutive onsets. Defaults to 0.020
+
+  -s, --silence sil  Set the silence threshold, in dB, under which the onset
   will not be detected. A value of -20.0 would eliminate most onsets but the
   loudest ones. A value of -90.0 would select all onsets. Defaults to -90.0.
 
@@ -66,6 +70,10 @@
 
   -j, --jack  Use Jack input/output. You will need a Jack connection
   controller to feed aubio some signal and listen to its output.
+
+  -N, --miditap-note  Override note value for MIDI tap. Defaults to 69.
+
+  -V, --miditap-velop  Override velocity value for MIDI tap. Defaults to 65.
 
   -h, --help  Print a short help message and exit.
 
--- a/doc/aubiopitch.txt
+++ b/doc/aubiopitch.txt
@@ -120,6 +120,12 @@
   Chapter 3, Pitch Analysis, PhD thesis, Centre for Digital music, Queen Mary
   University of London, London, UK, 2006.
 
+  yinfast  YIN algorithm (accelerated)
+
+  An optimised implementation of the YIN algorithm, yielding results identical
+  to the original YIN algorithm, while reducing its computational cost from
+  O(n^2) to O(n log(n)).
+
 SEE ALSO
 
   aubioonset(1),
--- a/doc/aubiotrack.txt
+++ b/doc/aubiotrack.txt
@@ -8,7 +8,8 @@
              [-r rate] [-B win] [-H hop]
              [-T time-format]
              [-s sil] [-m]
-             [-j] [-v] [-h]
+             [-j] [-N miditap-note] [-V miditap-velo]
+             [-v] [-h]
 
 DESCRIPTION
 
@@ -54,6 +55,10 @@
   -j, --jack  Use Jack input/output. You will need a Jack connection
   controller to feed aubio some signal and listen to its output.
 
+  -N, --miditap-note  Override note value for MIDI tap. Defaults to 69.
+
+  -V, --miditap-velop  Override velocity value for MIDI tap. Defaults to 65.
+
   -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
   seconds.
 
@@ -72,7 +77,7 @@
 
   Matthew E. P. Davies, Paul Brossier, and Mark D. Plumbley. Beat tracking
   towards automatic musical accompaniment. In Proceedings of the Audio
-  Engeeniring Society 118th Convention, Barcelona, Spain, May 2005.
+  Engineering Society 118th Convention, Barcelona, Spain, May 2005.
 
 SEE ALSO
 
--- /dev/null
+++ b/doc/binaries.rst
@@ -1,0 +1,12 @@
+Pre-compiled binaries
+---------------------
+
+`Pre-compiled binaries <https://aubio.org/download>`_
+are available for
+`macOS <https://aubio.org/download#osx>`_,
+`iOS <https://aubio.org/download#ios>`_,
+and
+`windows <https://aubio.org/download#win>`_
+
+To use aubio in a macOS or iOS application, see :ref:`xcode-frameworks-label`.
+
--- a/doc/building.rst
+++ b/doc/building.rst
@@ -20,9 +20,9 @@
 
 The **latest stable release** can be downloaded from https://aubio.org/download::
 
-        $ curl -O http://aubio.org/pub/aubio-0.4.3.tar.bz2
-        $ tar xf aubio-0.4.3.tar.bz2
-        $ cd aubio-0.4.3
+        $ curl -O http://aubio.org/pub/aubio-<version>.tar.bz2
+        $ tar xf aubio-<version>.tar.bz2
+        $ cd aubio-<version>/
 
 Git repository
 --------------
@@ -30,7 +30,7 @@
 The **latest git branch** can be obtained with::
 
         $ git clone git://git.aubio.org/git/aubio
-        $ cd aubio
+        $ cd aubio/
 
 The following command will fetch the correct `waf`_ version (not included in
 aubio's git)::
@@ -73,6 +73,34 @@
 
        $ waf configure build
 
+
+Running as a user
+-----------------
+
+To use aubio without actually installing, for instance if you don't have root
+access to install libaubio on your system,
+
+On Linux or macOS, sourcing the script ``scripts/setenv_local.sh`` should help::
+
+       $ source ./scripts/setenv_local.sh
+
+This script sets ``LD_LIBRARY_PATH``, for libaubio, and ``PYTHONPATH`` for the
+python module.
+
+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
+
 Cleaning
 --------
 
@@ -94,5 +122,8 @@
 
 .. _Git Bash: https://git-for-windows.github.io/
 
-.. toctree::
-   :maxdepth: 2
+.. _xcode-frameworks-label:
+
+.. include:: xcode_frameworks.rst
+
+.. include:: android.rst
--- a/doc/cli.rst
+++ b/doc/cli.rst
@@ -3,8 +3,13 @@
 Command line tools
 ==================
 
-A few simple command line tools are included along with the library.
+The python module comes with the following tools:
 
+ - ``aubio`` estimate and extract descriptors from sound files
+ - ``aubiocut`` slices sound files at onset or beat timestamps
+
+More command line tools are included along with the library.
+
  - ``aubioonset`` outputs the time stamp of detected note onsets
  - ``aubiopitch`` attempts to identify a fundamental frequency, or pitch, for
    each frame of the input sound
@@ -13,42 +18,56 @@
  - ``aubionotes`` emits midi-like notes, with an onset, a pitch, and a duration
  - ``aubioquiet`` extracts quiet and loud regions
 
-Additionally, the python module comes with the following script:
 
- - ``aubiocut`` slices sound files at onset or beat timestamps
+``aubio``
+---------
 
+.. literalinclude:: aubio.txt
+   :language: text
 
+
+``aubiocut``
+--------------
+
+.. literalinclude:: aubiocut.txt
+   :language: text
+
+
 ``aubioonset``
 --------------
 
 .. literalinclude:: aubioonset.txt
+   :language: text
 
 ``aubiopitch``
 --------------
 
 .. literalinclude:: aubiopitch.txt
+   :language: text
 
 ``aubiomfcc``
 --------------
 
 .. literalinclude:: aubiomfcc.txt
+   :language: text
 
 ``aubiotrack``
 --------------
 
 .. literalinclude:: aubiotrack.txt
+   :language: text
 
 ``aubionotes``
 --------------
 
 .. literalinclude:: aubionotes.txt
+   :language: text
 
 ``aubioquiet``
 --------------
 
 .. literalinclude:: aubioquiet.txt
+   :language: text
 
-``aubiocut``
---------------
 
-.. literalinclude:: aubiocut.txt
+.. include:: cli_features.rst
--- /dev/null
+++ b/doc/cli_features.rst
@@ -1,0 +1,42 @@
+Command line features
+---------------------
+
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| feat vs. prg | onset | pitch | mfcc | track | notes | quiet | cut1 | short options    |
++==============+=======+=======+======+=======+=======+=======+======+==================+
+| input        |   Y   |   Y   |  Y   |   Y   |   Y   |   Y   |  Y   | -i               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| output       |   Y   |   Y   |  N   |   Y   |   Y   |   N   | Y!1  | -o,-m,-f         |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| Hz/buf/hop   |   Y   |   Y   |  Y   |   Y   |   Y   |  Y!2  |  Y   | -r,-B-,H         |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| jack         |   Y   |   Y   |  N   |   Y   |   Y   |  N!3  |  N   | -j               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| onset        |   Y   |   N   |  N   |  Y!8  |  Y!6  |   N   |  Y   | -O,-t,-M         |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| pitch        |   N   |   Y   |  N   |   N   |  Y!6  |   N   | N!5  | -p,-u,-l         |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| silence      |   Y   |   Y   |  N   |   Y   |  Y!7  |   Y   | N!4  | -s               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| timefmt      |   Y   |   Y   |  Y   |   Y   |   Y   |   Y   |  !   | -T               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| help         |   Y   |   Y   |  Y   |   Y   |   Y   |   Y   |  Y   | -h               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+| verbose      |   Y   |   Y   |  Y   |   Y   |   Y   |   Y   |  Y   | -v               |
++--------------+-------+-------+------+-------+-------+-------+------+------------------+
+
+1. ``aubiocut --output`` is used to specify a directory, not a file.
+
+2. Option ``--bufsize`` is useless for ``aubioquiet``
+
+3. ``aubioquiet`` could have a jack output
+
+4. Regression, re-add slicing at silences to ``aubiocut``
+
+5. ``aubiocut`` could cut on notes
+
+6. ``aubionotes`` needs onset/pitch setters.
+
+7. Silence was different for pitch and onset, test.
+
+8. Some ``aubiotrack`` options should be disabled (minioi, threshold).
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -13,10 +13,14 @@
 
 import sys, os
 
+# get version using this_version.py
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+from this_version import get_aubio_version
+
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../../python/build/lib.macosx-10.6-intel-2.7'))
+#sys.path.insert(0, os.path.abspath('../../python/build/...'))
 
 # -- General configuration -----------------------------------------------------
 
@@ -25,8 +29,15 @@
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.viewcode', 'sphinx.ext.autodoc']
+extensions = ['sphinx.ext.viewcode', 'sphinx.ext.autodoc',
+        'sphinx.ext.napoleon', 'sphinx.ext.intersphinx']
 
+autodoc_member_order = 'groupwise'
+
+intersphinx_mapping = {
+        'numpy': ('https://docs.scipy.org/doc/numpy/', None),
+        }
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -41,7 +52,7 @@
 
 # General information about the project.
 project = u'aubio'
-copyright = u'2016, Paul Brossier'
+copyright = u'2018, Paul Brossier'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -48,9 +59,10 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.4'
+
+version = get_aubio_version()[:3]
 # The full version, including alpha/beta/rc tags.
-release = 'latest'
+release = get_aubio_version()
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -64,7 +76,17 @@
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
-exclude_patterns = ['_build']
+exclude_patterns = ['_build',
+        'statuslinks.rst',
+        'download.rst',
+        'binaries.rst',
+        'debian_packages.rst',
+        'building.rst',
+        'android.rst',
+        'xcode_frameworks.rst',
+        'requirements.rst',
+        'cli_features.rst',
+        ]
 
 # The reST default role (used for this markup: `text`) to use for all documents.
 #default_role = None
@@ -91,7 +113,10 @@
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+#html_theme = 'agogo'
+#html_theme = 'default'
+#html_theme = 'haiku'
+html_theme = 'pyramid'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -120,7 +145,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = [] #['_static']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
@@ -150,7 +175,7 @@
 #html_show_sourcelink = True
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+html_show_sphinx = False
 
 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
 #html_show_copyright = True
@@ -240,3 +265,6 @@
 
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
 #texinfo_show_urls = 'footnote'
+
+def setup(app):
+    if release.endswith('~alpha'): app.tags.add('devel')
--- a/doc/debian_packages.rst
+++ b/doc/debian_packages.rst
@@ -9,7 +9,7 @@
 https://anonscm.debian.org/cgit/collab-maint/aubio.git/. Use
 ``git-buildpackage`` to build from the git repository. For instance:
 
-.. code-block:: bash
+.. code-block:: console
 
     $ git clone git://anonscm.debian.org/collab-maint/aubio.git
     $ cd aubio
--- a/doc/develop.rst
+++ b/doc/develop.rst
@@ -1,47 +1,95 @@
-Developping with aubio
-======================
+.. _develop:
 
-Read `Contribute`_ to report issues and request new features.
+Developing with aubio
+=====================
 
-See `Doxygen documentation`_ for the complete documentation of the C library,
-built using `Doxygen <http://www.doxygen.org/>`_.
+Here is a brief overview of the C library.
 
-Below is a brief `Library overview`_.
+For a more detailed list of available functions, see the `API documentation
+<https://aubio.org/doc/latest/>`_.
 
-Library overview
-----------------
+To report issues, ask questions, and request new features, use `Github Issues
+<https://github.com/aubio/aubio/issues>`_
+
+Design Basics
+-------------
 
-Here is a brief overview of the C library. See also the `Doxygen
-documentation`_ for a more detailed list of available functions.
+The library is written in C and is optimised for speed and portability.
 
-Vectors and matrix
-``````````````````
+All memory allocations take place in the `new_` methods. Each successful call
+to `new_` should have a matching call to `del_` to deallocate the object.
 
-``fvec_t`` are used to hold vectors of float (``smpl_t``).
+.. code-block:: C
 
-.. literalinclude:: ../tests/src/test-fvec.c
-   :language: C
-   :lines: 7
+   // new_ to create an object foobar
+   aubio_foobar_t * new_aubio_foobar(void * args);
+   // del_ to delete foobar
+   void del_aubio_foobar (aubio_foobar_t * foobar);
 
+The main computations are done in the `_do` methods.
 
 .. code-block:: C
 
-        // set some elements
-        vec->data[511] = 2.;
-        vec->data[vec->length-2] = 1.;
+   // _do to process output = foobar(input)
+   audio_foobar_do (aubio_foobar_t * foobar, fvec_t * input, cvec_t * output);
 
-Similarly, ``fmat_t`` are used to hold matrix of floats.
+Most parameters can be read and written at any time:
 
-.. literalinclude:: ../tests/src/test-fmat.c
-   :language: C
-   :lines: 9-19
+.. code-block:: C
 
+   // _get_param to get foobar.param
+   smpl_t aubio_foobar_get_a_parameter (aubio_foobar_t * foobar);
+   // _set_param to set foobar.param
+   uint_t aubio_foobar_set_a_parameter (aubio_foobar_t * foobar, smpl_t a_parameter);
+
+In some case, more functions are available:
+
+.. code-block:: C
+
+   // non-real time functions
+   uint_t aubio_foobar_reset(aubio_foobar_t * t);
+
+Basic Types
+-----------
+
+.. code-block:: C
+
+    // integers
+    uint_t n = 10;                 // unsigned
+    sint_t delay = -90;            // signed
+
+    // float
+    smpl_t a = -90.;               // simple precision
+    lsmp_t f = 0.024;              // double precision
+
+    // vector of floats (simple precision)
+    fvec_t * vec = new_fvec(n);
+    vec->data[0] = 1;
+    vec->data[vec->length-1] = 1.; // vec->data has n elements
+    fvec_print(vec);
+    del_fvec(vec);
+
+    // complex data
+    cvec_t * fftgrain = new_cvec(n);
+    vec->norm[0] = 1.;             // vec->norm has n/2+1 elements
+    vec->phas[n/2] = 3.1415;       // vec->phas as well
+    del_cvec(fftgrain);
+
+    // matrix
+    fmat_t * mat = new_fmat (height, length);
+    mat->data[height-1][0] = 1;    // mat->data has height rows
+    mat->data[0][length-1] = 10;   // mat->data[0] has length columns
+    del_fmat(mat);
+
+
 Reading a sound file
-````````````````````
-In this example, ``aubio_source`` is used to read a media file.
+--------------------
 
-First, create the objects we need.
+In this example, `aubio_source <https://aubio.org/doc/latest/source_8h.html>`_
+is used to read a media file.
 
+First, define a few variables and allocate some memory.
+
 .. literalinclude:: ../tests/src/io/test-source.c
    :language: C
    :lines: 22-24, 30-32, 34
@@ -56,17 +104,17 @@
    :language: C
    :lines: 40-44
 
-At the end of the processing loop, clean-up and de-allocate memory:
+At the end of the processing loop, memory is deallocated:
 
 .. literalinclude:: ../tests/src/io/test-source.c
    :language: C
-   :lines: 50-56
+   :lines: 55-56
 
 See the complete example: :download:`test-source.c
 <../tests/src/io/test-source.c>`.
 
-Computing the spectrum
-``````````````````````
+Computing a spectrum
+--------------------
 
 Now let's create a phase vocoder:
 
@@ -74,12 +122,18 @@
    :language: C
    :lines: 6-11
 
-The processing loop could know look like:
+The processing loop could now look like:
 
 .. literalinclude:: ../tests/src/spectral/test-phasevoc.c
    :language: C
-   :lines: 21-35
+   :lines: 20-37
 
+Time to clean up the previously allocated memory:
+
+.. literalinclude:: ../tests/src/spectral/test-phasevoc.c
+   :language: C
+   :lines: 39-44
+
 See the complete example: :download:`test-phasevoc.c
 <../tests/src/spectral/test-phasevoc.c>`.
 
@@ -88,9 +142,10 @@
 Doxygen documentation
 ---------------------
 
-The latest version of the doxygen documentation is available at:
+The latest version of the API documentation is built using `Doxygen
+<http://www.doxygen.org/>`_ and is available at:
 
-    https://aubio.org/doc/latest
+    https://aubio.org/doc/latest/
 
 Contribute
 ----------
@@ -97,4 +152,3 @@
 
 Please report any issue and feature request at the `Github issue tracker
 <https://github.com/aubio/aubio/issues>`_. Patches and pull-requests welcome!
-
--- a/doc/download.rst
+++ b/doc/download.rst
@@ -5,16 +5,12 @@
 
 A number of distributions already include aubio. Check your favorite package
 management system, or have a look at the `aubio download page
-<http://aubio.org/download>`_ for more options.
+<https://aubio.org/download>`_ for more options.
 
-To use aubio in a macOS or iOS application, see :ref:`xcode-frameworks-label`.
-
 To use aubio in an android project, see :ref:`android`.
 
-.. toctree::
+To compile aubio from source, read :ref:`building`.
 
-  debian_packages
-  xcode_frameworks
-  android
+.. include:: binaries.rst
 
-To compile aubio from source, read :ref:`building`.
+.. include:: debian_packages.rst
--- a/doc/full.cfg
+++ b/doc/full.cfg
@@ -1,2354 +1,11 @@
-# Doxyfile 1.8.8
+@INCLUDE_PATH = ./doc
+@INCLUDE = web.cfg
 
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = aubio
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         = "0.4.2~alpha full"
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
-
-PROJECT_LOGO           =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
 OUTPUT_DIRECTORY       = full
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES    = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        = ../src
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
 EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
 EXTRACT_PRIVATE        = YES
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
 EXTRACT_STATIC         = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES         =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  = ../src
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS          = *.h \
-                         *.c
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
+FILE_PATTERNS          = *.h *.c
 EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           = ../examples \
-                         ../tests/src
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = YES
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
-# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
-# cost of reduced performance. This can be particularly helpful with template
-# rich C++ code for which doxygen's built-in parser lacks the necessary type
-# information.
-# Note: The availability of this option depends on whether or not doxygen was
-# compiled with the --with-libclang option.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = NO
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS          =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = NO
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.aubio.aubio
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.aubio.aubio.Maintainer
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          =
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.aubio.aubio
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = YES
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR             =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
 INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       =
-
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               =
-
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
 HIDE_UNDOC_RELATIONS   = NO
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: YES.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           =
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
-# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
-# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           =
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-PLANTUML_JAR_PATH      =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -10,6 +10,38 @@
 performing pitch detection, tapping the beat and producing midi streams from
 live audio.
 
+Quick links
+===========
+
+* :ref:`python`
+* :ref:`manpages`
+* :ref:`develop`
+* :ref:`building`
+
+.. only:: devel
+
+    .. include:: statuslinks.rst
+
+Project pages
+=============
+
+* `Project homepage`_: https://aubio.org
+* `aubio on github`_: https://github.com/aubio/aubio
+* `aubio on pypi`_: https://pypi.python.org/pypi/aubio
+* `Doxygen documentation`_: https://aubio.org/doc/latest/
+* `Mailing lists`_: https://lists.aubio.org
+
+.. _Project homepage: https://aubio.org
+.. _aubio on github: https://github.com/aubio/aubio
+.. _aubio on pypi: https://pypi.python.org/pypi/aubio
+.. _Doxygen documentation: https://aubio.org/doc/latest/
+.. _Mailing lists: https://lists.aubio.org/
+
+* `Travis Continuous integration page <https://travis-ci.org/aubio/aubio>`_
+* `Appveyor Continuous integration page <https://ci.appveyor.com/project/piem/aubio>`_
+* `Landscape python code validation <https://landscape.io/github/aubio/aubio/master>`_
+* `ReadTheDocs documentation <https://aubio.readthedocs.io/en/latest/>`_
+
 Features
 ========
 
@@ -37,65 +69,8 @@
    :maxdepth: 2
 
    installing
-   cli
    python_module
+   python
+   cli
    develop
-
-Project pages
-=============
-
-* `Project homepage`_: https://aubio.org
-* `aubio on github`_: https://github.com/aubio/aubio
-* `aubio on pypi`_: https://pypi.python.org/pypi/aubio
-* `Doxygen documentation`_: https://aubio.org/doc/latest/
-* `Mailing lists`_: https://lists.aubio.org
-
-.. _Project homepage: https://aubio.org
-.. _aubio on github: https://github.com/aubio/aubio
-.. _aubio on pypi: https://pypi.python.org/pypi/aubio
-.. _Doxygen documentation: https://aubio.org/doc/latest/
-.. _Mailing lists: https://lists.aubio.org/
-
-Current status
-==============
-
-.. image:: https://travis-ci.org/aubio/aubio.svg?branch=master
-   :target: https://travis-ci.org/aubio/aubio
-   :alt: Travis build status
-
-.. image:: https://ci.appveyor.com/api/projects/status/f3lhy3a57rkgn5yi?svg=true
-   :target: https://ci.appveyor.com/project/piem/aubio/
-   :alt: Appveyor build status
-
-.. image:: https://landscape.io/github/aubio/aubio/master/landscape.svg?style=flat
-   :target: https://landscape.io/github/aubio/aubio/master
-   :alt: Landscape code health
-
-.. image:: https://readthedocs.org/projects/aubio/badge/?version=latest
-   :target: http://aubio.readthedocs.io/en/latest/?badge=latest
-   :alt: Documentation status
-
-.. image:: https://img.shields.io/github/commits-since/aubio/aubio/0.4.3.svg?maxAge=2592000
-   :target: https://github.com/aubio/aubio
-   :alt: Commits since last release
-
-* `Travis Continuous integration page <https://travis-ci.org/aubio/aubio>`_
-* `Appveyor Continuous integration page <https://ci.appveyor.com/project/piem/aubio>`_
-* `Landscape python code validation <https://landscape.io/github/aubio/aubio/master>`_
-* `ReadTheDocs documentation <http://aubio.readthedocs.io/en/latest/>`_
-
-Copyright and License
-=====================
-
-Copyright © 2003-2016 Paul Brossier <piem@aubio.org>
-
-aubio is a `free <http://www.debian.org/intro/free>`_ and `open source
-<http://www.opensource.org/docs/definition.php>`_ software; **you** can
-redistribute it and/or modify it under the terms of the `GNU
-<http://www.gnu.org/>`_ `General Public License
-<https://www.gnu.org/licenses/gpl.html>`_ as published by the `Free Software
-Foundation <https://fsf.org>`_, either version 3 of the License, or (at your
-option) any later version.
-
-.. Note:: aubio is not MIT or BSD licensed. Contact the author if you need it
-  in your commercial product.
+   about
--- a/doc/installing.rst
+++ b/doc/installing.rst
@@ -4,16 +4,76 @@
 aubio runs on Linux, Windows, macOS, iOS, Android, and probably a few others
 operating systems.
 
-To download a pre-compiled version of the library, head to :ref:`download`.
+Aubio is available as a C library and as a python module.
 
-To install the python extension, head to :ref:`python`.
+Cheat sheet
+-----------
 
-To compile aubio form source, first check the :ref:`requirements`, then read
-:ref:`building`.
+- :ref:`get aubio latest source code <building>`::
 
-.. toctree::
-   :maxdepth: 2
+    # official repo
+    git clone https://git.aubio.org/aubio/aubio
+    # mirror
+    git clone https://github.com/aubio/aubio
+    # latest release
+    wget https://aubio.org/pub/aubio-<version>.tar.gz
 
-   download
-   requirements
-   building
+
+- :ref:`build aubio from source <building>`::
+
+    # 1. simple
+    cd aubio
+    make
+
+    # 2. step by step
+    ./scripts/get_waf.sh
+    ./waf configure
+    ./waf build
+    sudo ./waf install
+
+- :ref:`install python-aubio from source <python-install>`::
+
+    # from git
+    pip install git+https://git.aubio.org/aubio/aubio/
+    # mirror
+    pip install git+https://github.com/aubio/aubio/
+    # from latest release
+    pip install https://aubio.org/pub/aubio-latest.tar.bz2
+    # from pypi
+    pip install aubio
+    # from source directory
+    cd aubio
+    pip install -v .
+
+- :ref:`install python-aubio from a pre-compiled binary <python-install>`::
+
+      # conda [osx, linux, win]
+      conda install -c conda-forge aubio
+      # .deb (debian, ubuntu) [linux]
+      sudo apt-get install python3-aubio python-aubio aubio-tools
+      # brew [osx]
+      brew install aubio --with-python
+
+- :ref:`get a pre-compiled version of libaubio <download>`::
+
+    # .deb (linux) WARNING: old version
+    sudo apt-get install aubio-tools
+
+    # python module
+    ./setup.py install
+    # using pip
+    pip install .
+
+- :ref:`check the list of optional dependencies <requirements>`::
+
+    # debian / ubuntu
+    dpkg -l libavcodec-dev libavutil-dev libavformat-dev \
+            libswresample-dev libavresample-dev \
+            libsamplerate-dev libsndfile-dev \
+            txt2man doxygen
+
+.. include:: download.rst
+
+.. include:: building.rst
+
+.. include:: requirements.rst
--- /dev/null
+++ b/doc/py_datatypes.rst
@@ -1,0 +1,43 @@
+.. default-domain:: py
+.. currentmodule:: aubio
+
+Data-types
+----------
+
+This section contains the documentation for :data:`float_type`,
+:class:`fvec`, and :class:`cvec`.
+
+.. defined in rst only
+
+.. data:: float_type
+
+    A string constant describing the floating-point representation used in
+    :class:`fvec`, :class:`cvec`, and elsewhere in this module.
+
+    Defaults to `"float32"`.
+
+    If `aubio` was built specifically with the option `--enable-double`, this
+    string will be defined to `"float64"`. See :ref:`py-doubleprecision` in
+    :ref:`python-install` for more details on building aubio in double
+    precision mode.
+
+    .. rubric:: Examples
+
+    >>> aubio.float_type
+    'float32'
+    >>> numpy.zeros(10).dtype
+    'float64'
+    >>> aubio.fvec(10).dtype
+    'float32'
+    >>> np.arange(10, dtype=aubio.float_type).dtype
+    'float32'
+
+.. defined in `python/lib/aubio/__init__.py`
+
+.. autoclass:: fvec
+  :members:
+
+.. defined in `python/ext/py-cvec.h`
+
+.. autoclass:: cvec
+  :members:
--- /dev/null
+++ b/doc/py_examples.rst
@@ -1,0 +1,42 @@
+.. default-domain:: py
+.. currentmodule:: aubio
+
+Examples
+--------
+
+Below is a short selection of examples using the aubio module.
+
+Read a sound file
+.................
+
+Here is a simple script, :download:`demo_source_simple.py
+<../python/demos/demo_source_simple.py>` that reads all the samples from a
+media file using :class:`source`:
+
+.. literalinclude:: ../python/demos/demo_source_simple.py
+   :language: python
+
+Filter a sound file
+...................
+
+Here is another example, :download:`demo_filter.py
+<../python/demos/demo_filter.py>`, which applies a filter to a sound file
+and writes the filtered signal in another file:
+
+* read audio samples from a file with :class:`source`
+
+* filter them using an `A-weighting <https://en.wikipedia.org/wiki/A-weighting>`_
+  filter using :class:`digital_filter`
+
+* write the filtered samples to a new file with :class:`sink`.
+
+.. literalinclude:: ../python/demos/demo_filter.py
+   :language: python
+
+More examples
+.............
+
+For more examples showing how to use other components of the module, see
+the `python demos folder`_.
+
+.. _python demos folder: https://github.com/aubio/aubio/blob/master/python/demos
--- /dev/null
+++ b/doc/py_io.rst
@@ -1,0 +1,118 @@
+.. currentmodule:: aubio
+.. default-domain:: py
+
+Input/Output
+------------
+
+This section contains the documentation for two classes:
+:class:`source`, to read audio samples from files, and :class:`sink`,
+to write audio samples to disk.
+
+.. defined in `python/ext`
+
+..
+   Note: __call__ docstrings of objects defined in C must be written
+   specifically in RST, since there is no known way to add them to
+   their C implementation.
+
+..
+   TODO: remove special-members documentation
+
+.. defined in py-source.c
+
+.. autoclass:: source
+  :members:
+  :special-members: __enter__
+  :no-special-members:
+
+  .. function:: __call__()
+
+    Read at most `hop_size` new samples from self, return them in
+    a tuple with the number of samples actually read.
+
+    The returned tuple contains:
+
+    - a vector of shape `(hop_size,)`, filled with the `read` next
+      samples available, zero-padded if `read < hop_size`
+    - `read`, an integer indicating the number of samples read
+
+    If opened with more than one channel, the frames will be
+    down-mixed to produce the new samples.
+
+    :returns: A tuple of one array of samples and one integer.
+    :rtype: (array, int)
+
+    .. seealso:: :meth:`__next__`
+
+    .. rubric:: Example
+
+    >>> src = aubio.source('stereo.wav')
+    >>> while True:
+    ...     samples, read = src()
+    ...     if read < src.hop_size:
+    ...         break
+
+  .. function:: __next__()
+
+    Read at most `hop_size` new frames from self, return them in
+    an array.
+
+    If source was opened with one channel, next(self) returns
+    an array of shape `(read,)`, where `read` is the actual
+    number of frames read (`0 <= read <= hop_size`).
+
+    If `source` was opened with more then one channel, the
+    returned arrays will be of shape `(channels, read)`, where
+    `read` is the actual number of frames read (`0 <= read <=
+    hop_size`).
+
+    :return: A tuple of one array of frames and one integer.
+    :rtype: (array, int)
+
+    .. seealso:: :meth:`__call__`
+
+    .. rubric:: Example
+
+    >>> for frames in aubio.source('song.flac')
+    ...     print(samples.shape)
+
+  .. function:: __iter__()
+
+    Implement iter(self).
+
+    .. seealso:: :meth:`__next__`
+
+  .. function:: __enter__()
+
+    Implement context manager interface. The file will be opened
+    upon entering the context. See `with` statement.
+
+    .. rubric:: Example
+
+    >>> with aubio.source('loop.ogg') as src:
+    ...     src.uri, src.samplerate, src.channels
+
+  .. function:: __exit__()
+
+    Implement context manager interface. The file will be closed
+    before exiting the context. See `with` statement.
+
+    .. seealso:: :meth:`__enter__`
+
+.. py-sink.c
+   TODO: remove special-members documentation
+
+.. autoclass:: aubio.sink
+  :members:
+
+  .. function:: __call__(vec, length)
+
+    Write `length` samples from `vec`.
+
+    :param array vec: input vector to write from
+    :param int length: number of samples to write
+    :example:
+
+    >>> with aubio.sink('foo.wav') as snk:
+    ...     snk(aubio.fvec(1025), 1025)
+
--- /dev/null
+++ b/doc/py_utils.rst
@@ -1,0 +1,84 @@
+.. default-domain:: py
+.. currentmodule:: aubio
+
+Utilities
+---------
+
+This section documents various helper functions included in the aubio library.
+
+Note name conversion
+....................
+
+.. midiconv.py
+
+.. autofunction:: note2midi
+
+.. autofunction:: midi2note
+
+.. autofunction:: freq2note
+
+.. autofunction:: note2freq
+
+Frequency conversion
+....................
+
+.. python/ext/ufuncs.c
+
+.. autofunction:: freqtomidi
+
+.. autofunction:: miditofreq
+
+.. python/ext/py-musicutils.h
+
+.. autofunction:: meltohz
+
+.. autofunction:: hztomel
+
+.. python/ext/aubiomodule.c
+
+.. autofunction:: bintomidi
+.. autofunction:: miditobin
+.. autofunction:: bintofreq
+.. autofunction:: freqtobin
+
+Audio file slicing
+..................
+
+.. slicing.py
+
+.. autofunction:: slice_source_at_stamps
+
+Windowing
+.........
+
+.. python/ext/py-musicutils.h
+
+.. autofunction:: window
+
+Audio level detection
+.....................
+
+.. python/ext/py-musicutils.h
+
+.. autofunction:: level_lin
+.. autofunction:: db_spl
+.. autofunction:: silence_detection
+.. autofunction:: level_detection
+
+Vector utilities
+................
+
+.. python/ext/aubiomodule.c
+
+.. autofunction:: alpha_norm
+.. autofunction:: zero_crossing_rate
+.. autofunction:: min_removal
+
+.. python/ext/py-musicutils.h
+
+.. autofunction:: shift
+.. autofunction:: ishift
+
+.. python/ext/ufuncs.c
+
+.. autofunction:: unwrap2pi
--- /dev/null
+++ b/doc/python.rst
@@ -1,0 +1,55 @@
+.. make sure our default-domain is python here
+.. default-domain:: py
+
+.. set current module
+.. currentmodule:: aubio
+
+..
+   we follow numpy type docstrings, see:
+   https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
+..
+   note: we do not import aubio's docstring, which will be displayed from an
+   interpreter.
+
+.. .. automodule:: aubio
+
+
+.. _python:
+
+Python documentation
+====================
+
+This module provides a number of classes and functions for the analysis of
+music and audio signals.
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 1
+
+   py_datatypes
+   py_io
+   py_utils
+   py_examples
+
+Introduction
+------------
+
+This document provides a reference guide. For documentation on how to
+install aubio, see :ref:`python-install`.
+
+Examples included in this guide and within the code are written assuming
+both `aubio` and `numpy`_ have been imported:
+
+.. code-block:: python
+
+    >>> import aubio
+    >>> import numpy as np
+
+`Changed in 0.4.8` :  Prior to this version, almost no documentation was
+provided with the python module. This version adds documentation for some
+classes, including :class:`fvec`, :class:`cvec`, :class:`source`, and
+:class:`sink`.
+
+.. _numpy: https://www.numpy.org
--- a/doc/python_module.rst
+++ b/doc/python_module.rst
@@ -1,73 +1,102 @@
-.. _python:
+.. _python-install:
 
-Python module
-=============
+Installing aubio for Python
+===========================
 
-The aubio extension for Python is available for Python 2.7 and Python 3.
+aubio is available as a package for Python 2.7 and Python 3. The aubio
+extension is written C using the `Python/C`_ and the `Numpy/C`_ APIs.
 
+.. _Python/C: https://docs.python.org/c-api/index.html
+.. _Numpy/C: https://docs.scipy.org/doc/numpy/reference/c-api.html
+
+For general documentation on how to install Python packages, see `Installing
+Packages`_.
+
 Installing aubio with pip
 -------------------------
 
-aubio can now be installed using ``pip``:
+aubio can be installed from `PyPI`_ using ``pip``:
 
-.. code-block:: bash
+.. code-block:: console
 
     $ pip install aubio
 
-Building the module
--------------------
+See also `Installing from PyPI`_ for general documentation.
 
-From ``aubio`` source directory, run the following:
+.. note::
 
-.. code-block:: bash
+  aubio is currently a `source only`_ package, so you will need a compiler to
+  install it from `PyPI`_. See also `Installing aubio with conda`_ for
+  pre-compiled binaries.
 
-    $ ./setup.py clean
-    $ ./setup.py build
-    $ sudo ./setup.py install
+.. _PyPI: https://pypi.python.org/pypi/aubio
+.. _Installing Packages: https://packaging.python.org/tutorials/installing-packages/
+.. _Installing from PyPI: https://packaging.python.org/tutorials/installing-packages/#installing-from-pypi
+.. _source only: https://packaging.python.org/tutorials/installing-packages/#source-distributions-vs-wheels
 
-Using aubio in python
----------------------
+Installing aubio with conda
+---------------------------
 
-Once you have python-aubio installed, you should be able to run ``python -c
-"import aubio"``.
+`Conda packages`_ are available through the `conda-forge`_ channel for Linux,
+macOS, and Windows:
 
-A simple example
-................
+.. code-block:: console
+
+    $ conda config --add channels conda-forge
+    $ conda install -c conda-forge aubio
 
-Here is a :download:`simple script <../python/demos/demo_source_simple.py>`
-that reads all the samples from a media file:
+.. _Conda packages: https://anaconda.org/conda-forge/aubio
+.. _conda-forge: https://conda-forge.org/
 
-.. literalinclude:: ../python/demos/demo_source_simple.py
-   :language: python
+.. _py-doubleprecision:
 
-Filtering an input sound file
-.............................
-
-Here is a more complete example, :download:`demo_filter.py
-<../python/demos/demo_filter.py>`. This files executes the following:
+Double precision
+----------------
 
-* read an input media file (``aubio.source``)
+This module can be compiled in double-precision mode, in which case the
+default type for floating-point samples will be 64-bit. The default is
+single precision mode (32-bit, recommended).
 
-* filter it using an `A-weighting <https://en.wikipedia.org/wiki/A-weighting>`_
-  filter (``aubio.digital_filter``)
+To build the aubio module with double precision, use the option
+`--enable-double` of the `build_ext` subcommand:
 
-* write result to a new file (``aubio.sink``)
+.. code:: bash
 
-.. literalinclude:: ../python/demos/demo_filter.py
-   :language: python
+    $ ./setup.py clean
+    $ ./setup.py build_ext --enable-double
+    $ pip install -v .
 
-More demos
-..........
+**Note**: If linking against `libaubio`, make sure the library was also
+compiled in :ref:`doubleprecision` mode.
 
-Check out the `python demos folder`_ for more examples.
 
+Checking your installation
+--------------------------
+
+Once the python module is installed, its version can be checked with:
+
+.. code-block:: console
+
+    $ python -c "import aubio; print(aubio.version, aubio.float_type)"
+
+The command line `aubio` is also installed:
+
+.. code-block:: console
+
+    $ aubio -h
+
+
 Python tests
 ------------
 
-A number of `python tests`_ are provided. To run them, use
-``python/tests/run_all_tests``.
+A number of Python tests are provided in the `python tests`_. To run them,
+install `nose2`_ and run the script ``python/tests/run_all_tests``:
 
-.. _python demos folder: https://github.com/aubio/aubio/blob/master/python/demos
+.. code-block:: console
+
+    $ pip install nose2
+    $ ./python/tests/run_all_tests
+
 .. _demo_filter.py: https://github.com/aubio/aubio/blob/master/python/demos/demo_filter.py
 .. _python tests: https://github.com/aubio/aubio/blob/master/python/tests
-
+.. _nose2: https://github.com/nose-devs/nose2
--- a/doc/requirements.rst
+++ b/doc/requirements.rst
@@ -1,11 +1,197 @@
 .. _requirements:
 
-Requirements
-============
+Build options
+=============
 
-While aubio can be built without any external dependencies, we **recommend** to
-use at least some of the following libraries.
+If built without any external dependencies aubio can be somewhat useful, for
+instance to read, process, and write simple wav files.
 
+To support more media input formats and add more features to aubio, you can use
+one or all of the following `external libraries`_.
+
+You may also want to know more about the `other options`_ and the `platform
+notes`_
+
+The configure script will automatically for these extra libraries. To make sure
+the library or feature is used, pass the `--enable-flag` to waf. To disable
+this feature, use `--disable-feature`.
+
+To find out more about the build commands, use the `--verbose` option.
+
+External libraries
+------------------
+
+External libraries are checked for using ``pkg-config``. Set the
+``PKG_CONFIG_PATH`` environment variable if you have them installed in an
+unusual location.
+
+
+.. note::
+
+    If ``pkg-config`` is not found in ``PATH``, the configure step will
+    succeed, but none of the external libraries will be used.
+
+Media libraries
+---------------
+
+libav
+.....
+
+  `libav.org <https://libav.org/>`_, open source audio and video processing
+  tools.
+
+If all of the following libraries are found, they will be used to compile
+``aubio_source_avcodec``. so that ``aubio_source`` will be able to decode audio
+from all formats supported by `libav
+<https://libav.org/documentation/general.html#Audio-Codecs>`_.
+
+* libavcodec
+* libavformat
+* libavutil
+* libavresample
+
+To enable this option, configure with ``--enable-avcodec``. The build will then
+failed if the required libraries are not found. To disable this option,
+configure with ``--disable-avcodec``
+
+
+libsndfile
+..........
+
+  `libsndfile <http://www.mega-nerd.com/libsndfile/>`_, a C library for reading
+  and writing sampled sound files.
+
+With libsndfile built in, ``aubio_source_sndfile`` will be built in and used by
+``aubio_source``.
+
+To enable this option, configure with ``--enable-sndfile``. The build will then
+fail if the required library is not found. To disable this option, configure
+with ``--disable-sndfile``
+
+libsamplerate
+.............
+
+  `libsamplerate <http://www.mega-nerd.com/SRC/>`_, a sample rate converter for
+  audio.
+
+With libsamplerate built in, ``aubio_source_sndfile`` will support resampling,
+and ``aubio_resample`` will be fully functional.
+
+To enable this option, configure with ``--enable-samplerate``. The build will
+then fail if the required library is not found. To disable this option,
+configure with ``--disable-samplerate``
+
+Optimisation libraries
+----------------------
+
+libfftw3
+........
+
+  `FFTW <http://fftw.org/>`_, a C subroutine for computing the discrete Fourier
+  transform
+
+With libfftw3 built in, ``aubio_fft`` will use `FFTW`_ to
+compute Fast Fourier Transform (FFT), allowing aubio to compute FFT on length
+that are not a power of 2.
+
+To enable this option, configure with ``--enable-fftw3``. The build will
+then fail if the required library is not found. To disable this option,
+configure with ``--disable-fftw3``
+
+blas
+....
+
+On macOs/iOS, `blas
+<https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms>`_ are made
+available through the Accelerate framework.
+
+On Linux, they can be enabled with ``--enable-blas``.  On Debian (etch),
+`atlas`_, `openblas`_, and `libblas`_ have been successfully tested.
+
+When enabled, ``waf`` will check for the current blas configuration by running
+``pkg-config --libs blas``. Depending of the library path returned by
+``pkg-config``, different headers will be searched for.
+
+.. note::
+
+    On Debian systems, `multiple versions of BLAS and LAPACK
+    <https://wiki.debian.org/DebianScience/LinearAlgebraLibraries>`_ can be
+    installed. To configure which libblas is being used:
+
+    .. code-block:: console
+
+      $ sudo update-alternatives --config libblas.so
+
+..
+  Expected pkg-config output for each alternative:
+    /usr/lib/atlas-base/atlas/libblas.so
+    -L/usr/lib/atlas-base/atlas -lblas
+    /usr/lib/openblas-base/libblas.so
+    -L/usr/lib/openblas-base -lblas
+    /usr/lib/libblas/libblas.so
+    -lblas
+
+atlas
+.....
+
+`ATLAS BLAS APIs <http://math-atlas.sourceforge.net/>`_ will be used the path
+returned by ``pkg-config --libs blas`` contains ``atlas``.
+
+..
+  ``<atlas/cblas.h>`` will be included.
+
+Example:
+
+.. code-block:: console
+
+  $ pkg-config --libs blas
+  -L/usr/lib/atlas-base/atlas -lblas
+  $ ./waf configure --enable-atlas
+  [...]
+  Checking for 'blas'                      : yes
+  Checking for header atlas/cblas.h        : yes
+
+openblas
+........
+
+`OpenBlas libraries <https://www.openblas.net/>`_ will be used when the output
+of ``pkg-config --libs blas`` contains 'openblas',
+
+..
+  ``<openblas/cblas.h>`` will be included.
+
+Example:
+
+.. code-block:: console
+
+  $ pkg-config --libs blas
+  -L/usr/lib/openblas-base -lblas
+  $ ./waf configure --enable-atlas
+  [...]
+  Checking for 'blas'                      : yes
+  Checking for header openblas/cblas.h     : yes
+
+libblas
+.......
+
+`Netlib's libblas (LAPACK) <https://www.netlib.org/lapack/>`_ will be used if
+no specific library path is specified by ``pkg-config``
+
+..
+  ``<cblas.h>`` will be included.
+
+Example:
+
+.. code-block:: console
+
+  $ pkg-config --libs blas
+  -lblas
+  $ ./waf configure --enable-atlas
+  [...]
+  Checking for 'blas'                      : yes
+  Checking for header cblas.h              : yes
+
+
 Platform notes
 --------------
 
@@ -41,6 +227,9 @@
 The following `External libraries`_ will also be checked: `libav`_,
 `libsamplerate`_, `libsndfile`_, `libfftw3`_.
 
+To build a fat binary on a darwin like system (macOS, tvOS, appleOS, ...)
+platforms, configure with ``--enable-fat``.
+
 Windows
 .......
 
@@ -86,7 +275,7 @@
 Set ``CFLAGS`` and ``LINKFLAGS`` to change these default values, or edit
 ``wscript`` directly.
 
-Build options
+Other options
 -------------
 
 Some additional options can be passed to the configure step. For the complete
@@ -94,101 +283,88 @@
 
 .. code:: bash
 
-    $ ./waf configure --help
+    $ ./waf --help
 
-Double precision
-................
+Here is an example of a custom command:
+
+.. code:: bash
 
-To compile aubio in double precision mode, configure with ``--enable-double``.
+    $ ./waf --verbose configure build install \
+                --enable-avcodec --enable-wavread --disable-wavwrite \
+                --enable-sndfile --enable-samplerate --enable-docs \
+                --destdir $PWD/build/destdir --testcmd="echo %s" \
+                --prefix=/opt --libdir=/opt/lib/multiarch \
+                --manpagesdir=/opt/share/man  \
+                uninstall clean distclean dist distcheck
 
-To compile aubio in single precision mode, use ``--disable-double`` (default).
+.. _doubleprecision:
 
-Fat binary
-..........
-
-To build a fat binary on Mac OS platforms, configure with ``--enable-fat``.
+Double precision
+................
 
-External libraries
-------------------
+The datatype used to store real numbers in aubio is named `smpl_t`. By default,
+`smpl_t` is defined as `float`, a `single-precision format
+<https://en.wikipedia.org/wiki/Single-precision_floating-point_format>`_
+(32-bit).  Some algorithms require a floating point representation with a
+higher precision, for instance to prevent arithmetic underflow in recursive
+filters.  In aubio, these special samples are named `lsmp_t` and defined as
+`double` by default (64-bit).
 
-External libraries are checked for using ``pkg-config``. Set the
-``PKG_CONFIG_PATH`` environment variable if you have them installed in an
-unusual location.
+Sometimes it may be useful to compile aubio in `double-precision`, for instance
+to reproduce numerical results obtained with 64-bit routines. In this case,
+`smpl_t` will be defined as `double`.
 
+The following table shows how `smpl_t` and `lsmp_t` are defined in single- and
+double-precision modes:
 
-.. note::
+.. list-table:: Single and double-precision modes
+   :align: center
 
-    If ``pkg-config`` is not found in ``PATH``, the configure step will
-    succeed, but none of the external libraries will be used.
+   * -
+     - single
+     - double
+   * - `smpl_t`
+     - ``float``
+     - ``double``
+   * - `lsmp_t`
+     - ``double``
+     - ``long double``
 
-libav
-.....
+To compile aubio in double precision mode, configure with ``--enable-double``.
 
-  `libav.org <https://libav.org/>`_, open source audio and video processing
-  tools.
+To compile in single-precision mode (default), use ``--disable-double`` (or
+simply none of these two options).
 
-If all of the following libraries are found, they will be used to compile
-``aubio_source_avcodec``. so that ``aubio_source`` will be able to decode audio
-from all formats supported by `libav
-<https://libav.org/documentation/general.html#Audio-Codecs>`_.
+Disabling the tests
+...................
 
-* libavcodec
-* libavformat
-* libavutil
-* libavresample
+In some case, for instance when cross-compiling, unit tests should not be run.
+Option ``--notests`` can be used for this purpose. The tests will not be
+executed, but the binaries will be compiled, ensuring that linking against
+libaubio works as expected.
 
-To enable this option, configure with ``--enable-avcodec``. The build will then
-failed if the required libraries are not found. To disable this option,
-configure with ``--disable-avcodec``
+.. note::
 
+  The ``--notests`` option should be passed to both ``build`` and ``install``
+  targets, otherwise waf will try to run them.
 
-libsndfile
-..........
+Edit wscript
+............
 
-  `libsndfile <http://www.mega-nerd.com/libsndfile/>`_, a C library for reading
-  and writing sampled sound files.
+Many of the options are gathered in the file `wscript`. a good starting point
+when looking for additional options.
 
-With libsndfile built in, ``aubio_source_sndfile`` will be built in and used by
-``aubio_source``.
+.. _build_docs:
 
-To enable this option, configure with ``--enable-sndfile``. The build will then
-fail if the required library is not found. To disable this option, configure
-with ``--disable-sndfile``
+Building the docs
+-----------------
 
-libsamplerate
-.............
+If the following command line tools are found, the documentation will be built
+built:
 
-  `libsamplerate <http://www.mega-nerd.com/SRC/>`_, a sample rate converter for
-  audio.
-
-With libsamplerate built in, ``aubio_source_sndfile`` will support resampling,
-and ``aubio_resample`` will be fully functional.
-
-To enable this option, configure with ``--enable-samplerate``. The build will
-then fail if the required library is not found. To disable this option,
-configure with ``--disable-samplerate``
-
-libfftw3
-........
-
-  `FFTW <http://fftw.org/>`_, a C subroutine for computing the discrete Fourier
-  transform
-
-With libfftw3 built in, ``aubio_fft`` will use `FFTW`_ to
-compute Fast Fourier Transform (FFT), allowing aubio to compute FFT on length
-that are not a power of 2.
-
-To enable this option, configure with ``--enable-fftw3``. The build will
-then fail if the required library is not found. To disable this option,
-configure with ``--disable-fftw3``
-
-External tools
---------------
-
-If the following tools are found, additional documentations are built:
-
  - `doxygen <http://doxygen.org>`_ to build the :ref:`doxygen-documentation`.
  - `txt2man <https://github.com/mvertes/txt2man>`_ to build the :ref:`manpages`
+ - `sphinx <http://sphinx-doc.org>`_ to build this document
 
 These tools are searched for in the current ``PATH`` environment variable.
 By default, the documentation is built only if the tools are found.
@@ -195,4 +371,3 @@
 
 To disable the documentation, configure with ``--disable-docs``. To build with
 the documentation, configure with ``--enable-docs``.
-
--- /dev/null
+++ b/doc/statuslinks.rst
@@ -1,0 +1,24 @@
+Current status
+==============
+
+.. image:: https://travis-ci.org/aubio/aubio.svg?branch=master
+   :target: https://travis-ci.org/aubio/aubio
+   :alt: Travis build status
+
+.. image:: https://ci.appveyor.com/api/projects/status/f3lhy3a57rkgn5yi?svg=true
+   :target: https://ci.appveyor.com/project/piem/aubio/
+   :alt: Appveyor build status
+
+.. image:: https://landscape.io/github/aubio/aubio/master/landscape.svg?style=flat
+   :target: https://landscape.io/github/aubio/aubio/master
+   :alt: Landscape code health
+
+.. image:: https://readthedocs.org/projects/aubio/badge/?version=latest
+   :target: https://aubio.readthedocs.io/en/latest/?badge=latest
+   :alt: Documentation status
+
+.. image:: https://img.shields.io/github/commits-since/aubio/aubio/latest.svg
+   :target: https://github.com/aubio/aubio
+   :alt: Commits since last release
+
+
--- a/doc/web.cfg
+++ b/doc/web.cfg
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.8
+# Doxyfile 1.8.13
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -38,7 +38,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = "0.4.2~alpha"
+PROJECT_NUMBER         = "latest"
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -46,10 +46,10 @@
 
 PROJECT_BRIEF          =
 
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
 
 PROJECT_LOGO           =
 
@@ -60,7 +60,7 @@
 
 OUTPUT_DIRECTORY       = web
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
 # directories (in 2 levels) under the output directory of each output format and
 # will distribute the generated files over these directories. Enabling this
 # option can be useful when feeding doxygen a huge amount of source files, where
@@ -93,7 +93,7 @@
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
 # descriptions after the members that are listed in the file and class
 # documentation (similar to Javadoc). Set to NO to disable this.
 # The default value is: YES.
@@ -100,7 +100,7 @@
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
 # description of a member or function before the detailed description
 #
 # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -135,7 +135,7 @@
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
 # before files name in the file list and in the header files. If set to NO the
 # shortest path that makes the file name unique will be used
 # The default value is: YES.
@@ -205,9 +205,9 @@
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
 # The default value is: NO.
 
 SEPARATE_MEMBER_PAGES  = NO
@@ -276,7 +276,7 @@
 # instance to make doxygen treat .inc files as Fortran files (default is PHP),
 # and .f files as C (default is Fortran), use: inc=Fortran f=C.
 #
-# Note For files without extension you can use no_extension as a placeholder.
+# Note: For files without extension you can use no_extension as a placeholder.
 #
 # Note that for custom extensions you also need to set FILE_PATTERNS otherwise
 # the files are not read by doxygen.
@@ -293,10 +293,19 @@
 
 MARKDOWN_SUPPORT       = YES
 
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
 # When enabled doxygen tries to link words that correspond to documented
 # classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
 # The default value is: YES.
 
 AUTOLINK_SUPPORT       = YES
@@ -336,7 +345,7 @@
 IDL_PROPERTY_SUPPORT   = YES
 
 # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
 # member in the group (if any) for the other members of the group. By default
 # all members of a group must be documented explicitly.
 # The default value is: NO.
@@ -343,6 +352,13 @@
 
 DISTRIBUTE_GROUP_DOC   = NO
 
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
 # Set the SUBGROUPING tag to YES to allow class member groups of the same type
 # (for instance a group of public functions) to be put as a subgroup of that
 # type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -401,7 +417,7 @@
 # Build related configuration options
 #---------------------------------------------------------------------------
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
 # documentation are documented, even if no documentation was available. Private
 # class members and static file members will be hidden unless the
 # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -411,26 +427,26 @@
 
 EXTRACT_ALL            = NO
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
 # be included in the documentation.
 # The default value is: NO.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
 # scope will be included in the documentation.
 # The default value is: NO.
 
 EXTRACT_PACKAGE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
 # included in the documentation.
 # The default value is: NO.
 
 EXTRACT_STATIC         = NO
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
 # only classes defined in header files are included. Does not have any effect
 # for Java sources.
 # The default value is: YES.
@@ -437,9 +453,9 @@
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local methods,
+# This flag is only useful for Objective-C code. If set to YES, local methods,
 # which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
 # included.
 # The default value is: NO.
 
@@ -464,14 +480,14 @@
 
 # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
 # undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
 # The default value is: NO.
 
 HIDE_UNDOC_CLASSES     = NO
 
 # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
+# (class|struct|union) declarations. If set to NO, these declarations will be
 # included in the documentation.
 # The default value is: NO.
 
@@ -478,7 +494,7 @@
 HIDE_FRIEND_COMPOUNDS  = NO
 
 # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
+# documentation blocks found inside the body of a function. If set to NO, these
 # blocks will be appended to the function's detailed documentation block.
 # The default value is: NO.
 
@@ -492,7 +508,7 @@
 INTERNAL_DOCS          = NO
 
 # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
+# names in lower-case letters. If set to YES, upper-case letters are also
 # allowed. This is useful if you have classes or files whose names only differ
 # in case and if your file system supports case sensitive file names. Windows
 # and Mac users are advised to set this option to NO.
@@ -501,12 +517,19 @@
 CASE_SENSE_NAMES       = NO
 
 # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
+# their full class and namespace scopes in the documentation. If set to YES, the
 # scope will be hidden.
 # The default value is: NO.
 
 HIDE_SCOPE_NAMES       = NO
 
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
 # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
 # the files that are included by a file in the documentation of that file.
 # The default value is: YES.
@@ -534,7 +557,7 @@
 
 # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
 # (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
+# name. If set to NO, the members will appear in declaration order.
 # The default value is: YES.
 
 SORT_MEMBER_DOCS       = YES
@@ -541,7 +564,7 @@
 
 # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
 # descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
+# name. If set to NO, the members will appear in declaration order. Note that
 # this will also influence the order of the classes in the class list.
 # The default value is: NO.
 
@@ -586,27 +609,25 @@
 
 STRICT_PROTO_MATCHING  = NO
 
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
 # The default value is: YES.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
 # The default value is: YES.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
 # list. This list is created by putting \bug commands in the documentation.
 # The default value is: YES.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
 # the deprecated list. This list is created by putting \deprecated commands in
 # the documentation.
 # The default value is: YES.
@@ -631,8 +652,8 @@
 MAX_INITIALIZER_LINES  = 30
 
 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
 # The default value is: YES.
 
 SHOW_USED_FILES        = YES
@@ -696,7 +717,7 @@
 QUIET                  = NO
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
 # this implies that the warnings are on.
 #
 # Tip: Turn warnings on while writing the documentation.
@@ -704,7 +725,7 @@
 
 WARNINGS               = YES
 
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
 # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
 # will automatically be disabled.
 # The default value is: YES.
@@ -721,12 +742,18 @@
 
 # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
 # are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
 # The default value is: NO.
 
 WARN_NO_PARAMDOC       = NO
 
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
 # The WARN_FORMAT tag determines the format of the warning messages that doxygen
 # can produce. The string should contain the $file, $line, and $text tags, which
 # will be replaced by the file and line number from which the warning originated
@@ -750,7 +777,7 @@
 # The INPUT tag is used to specify the files and/or directories that contain
 # documented source files. You may enter file names like myfile.cpp or
 # directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = ../src
@@ -766,12 +793,17 @@
 
 # If the value of the INPUT tag contains directories, you can use the
 # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
 
 FILE_PATTERNS          = *.h
 
@@ -790,6 +822,7 @@
 
 EXCLUDE                = ../src/aubio_priv.h \
                          ../src/mathutils.h \
+                         ../src/io/ioutils.h \
                          ../src/io/audio_unit.h \
                          ../src/io/source_sndfile.h \
                          ../src/io/source_apple_audio.h \
@@ -802,6 +835,7 @@
                          ../src/pitch/pitchmcomb.h \
                          ../src/pitch/pitchyin.h \
                          ../src/pitch/pitchyinfft.h \
+                         ../src/pitch/pitchyinfast.h \
                          ../src/pitch/pitchschmitt.h \
                          ../src/pitch/pitchfcomb.h \
                          ../src/pitch/pitchspecacf.h \
@@ -878,6 +912,10 @@
 # Note that the filter must not add or remove lines; it is applied before the
 # code is scanned, but not when the output code is generated. If lines are added
 # or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 INPUT_FILTER           =
 
@@ -887,11 +925,15 @@
 # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
 # filters are used. If the FILTER_PATTERNS tag is empty or if none of the
 # patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 FILTER_PATTERNS        =
 
 # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
+# INPUT_FILTER) will also be used to filter the input files that are used for
 # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
 # The default value is: NO.
 
@@ -951,7 +993,7 @@
 REFERENCES_RELATION    = YES
 
 # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
 # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
 # link to the documentation.
 # The default value is: YES.
@@ -998,13 +1040,13 @@
 
 VERBATIM_HEADERS       = YES
 
-# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
 # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
 # cost of reduced performance. This can be particularly helpful with template
 # rich C++ code for which doxygen's built-in parser lacks the necessary type
 # information.
 # Note: The availability of this option depends on whether or not doxygen was
-# compiled with the --with-libclang option.
+# generated with the -Duse-libclang=ON option for CMake.
 # The default value is: NO.
 
 CLANG_ASSISTED_PARSING = NO
@@ -1047,7 +1089,7 @@
 # Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
 # The default value is: YES.
 
 GENERATE_HTML          = YES
@@ -1113,10 +1155,10 @@
 # cascading style sheets that are included after the standard style sheets
 # created by doxygen. Using this option one can overrule certain style aspects.
 # This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
 # Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
 # list). For an example see the documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
@@ -1133,7 +1175,7 @@
 HTML_EXTRA_FILES       =
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
+# will adjust the colors in the style sheet and background images according to
 # this color. Hue is specified as an angle on a colorwheel, see
 # http://en.wikipedia.org/wiki/Hue for more information. For instance the value
 # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
@@ -1164,8 +1206,9 @@
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
 # page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_TIMESTAMP         = NO
@@ -1261,7 +1304,7 @@
 CHM_FILE               =
 
 # The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
 # doxygen will try to run the HTML help compiler on the generated index.hhp.
 # The file has to be specified with full path.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1268,21 +1311,21 @@
 
 HHC_LOCATION           =
 
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 GENERATE_CHI           = NO
 
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
 # and project file content.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_INDEX_ENCODING     =
 
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
 # enables the Previous and Next buttons.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1396,7 +1439,7 @@
 # index structure (just like the one that is generated for HTML Help). For this
 # to work a browser that supports JavaScript, DHTML, CSS and frames is required
 # (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
 # further fine-tune the look of the index. As an example, the default style
 # sheet generated by doxygen has an example that shows how to put an image at
 # the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1424,7 +1467,7 @@
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
 # external symbols imported via tag files in a separate window.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1453,7 +1496,7 @@
 
 # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
 # http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
 # installed or if you want to formulas look prettier in the HTML output. When
 # enabled you may also need to install MathJax separately and configure the path
 # to it using the MATHJAX_RELPATH option.
@@ -1483,7 +1526,7 @@
 # The default value is: http://cdn.mathjax.org/mathjax/latest.
 # This tag requires that the tag USE_MATHJAX is set to YES.
 
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_RELPATH        = https://cdn.mathjax.org/mathjax/latest
 
 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
 # extension names that should be enabled during MathJax rendering. For example
@@ -1539,7 +1582,7 @@
 # external search engine pointed to by the SEARCHENGINE_URL option to obtain the
 # search results.
 #
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
 # (doxysearch.cgi) which are based on the open source search engine library
 # Xapian (see: http://xapian.org/).
 #
@@ -1552,7 +1595,7 @@
 # The SEARCHENGINE_URL should point to a search engine hosted by a web server
 # which will return the search results when EXTERNAL_SEARCH is enabled.
 #
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
 # (doxysearch.cgi) which are based on the open source search engine library
 # Xapian (see: http://xapian.org/). See the section "External Indexing and
 # Searching" for details.
@@ -1590,7 +1633,7 @@
 # Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
 # The default value is: YES.
 
 GENERATE_LATEX         = NO
@@ -1621,7 +1664,7 @@
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
 # documents. This may be useful for small projects and may help to save some
 # trees in general.
 # The default value is: NO.
@@ -1639,9 +1682,12 @@
 PAPER_TYPE             = a4
 
 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
 # If left blank no extra packages will be included.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
 
@@ -1656,9 +1702,9 @@
 # Note: Only use a user-defined header if you know what you are doing! The
 # following commands have a special meaning inside the header: $title,
 # $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HEADER           =
@@ -1674,6 +1720,17 @@
 
 LATEX_FOOTER           =
 
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
 # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
 # other source files which should be copied to the LATEX_OUTPUT output
 # directory. Note that the files will be copied as-is; there are no commands or
@@ -1692,7 +1749,7 @@
 PDF_HYPERLINKS         = YES
 
 # If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
 # higher quality PDF documentation.
 # The default value is: YES.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1733,11 +1790,19 @@
 
 LATEX_BIB_STYLE        = plain
 
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
 #---------------------------------------------------------------------------
 # Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
 # RTF output is optimized for Word 97 and may not look too pretty with other RTF
 # readers/editors.
 # The default value is: NO.
@@ -1752,7 +1817,7 @@
 
 RTF_OUTPUT             = rtf
 
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
 # documents. This may be useful for small projects and may help to save some
 # trees in general.
 # The default value is: NO.
@@ -1789,11 +1854,21 @@
 
 RTF_EXTENSIONS_FILE    =
 
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
 #---------------------------------------------------------------------------
 # Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
 # classes and files.
 # The default value is: NO.
 
@@ -1837,7 +1912,7 @@
 # Configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
 # captures the structure of the code including all documentation.
 # The default value is: NO.
 
@@ -1851,7 +1926,7 @@
 
 XML_OUTPUT             = xml
 
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
 # listings (including syntax highlighting and cross-referencing information) to
 # the XML output. Note that enabling this will significantly increase the size
 # of the XML output.
@@ -1864,7 +1939,7 @@
 # Configuration options related to the DOCBOOK output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
 # that can be used to generate PDF.
 # The default value is: NO.
 
@@ -1878,7 +1953,7 @@
 
 DOCBOOK_OUTPUT         = docbook
 
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
 # program listings (including syntax highlighting and cross-referencing
 # information) to the DOCBOOK output. Note that enabling this will significantly
 # increase the size of the DOCBOOK output.
@@ -1891,10 +1966,10 @@
 # Configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
 # The default value is: NO.
 
 GENERATE_AUTOGEN_DEF   = NO
@@ -1903,7 +1978,7 @@
 # Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
 # file that captures the structure of the code including all documentation.
 #
 # Note that this feature is still experimental and incomplete at the moment.
@@ -1911,7 +1986,7 @@
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
 # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
 # output from the Perl module output.
 # The default value is: NO.
@@ -1919,9 +1994,9 @@
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
 # formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
+# understand what is going on. On the other hand, if this tag is set to NO, the
 # size of the Perl module output will be much smaller and Perl will parse it
 # just the same.
 # The default value is: YES.
@@ -1941,14 +2016,14 @@
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
 # C-preprocessor directives found in the sources and include files.
 # The default value is: YES.
 
 ENABLE_PREPROCESSING   = YES
 
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
 # performed. Macro expansion can be done in a controlled way by setting
 # EXPAND_ONLY_PREDEF to YES.
 # The default value is: NO.
@@ -1964,7 +2039,7 @@
 
 EXPAND_ONLY_PREDEF     = NO
 
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
 # INCLUDE_PATH will be searched if a #include is found.
 # The default value is: YES.
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -2040,20 +2115,21 @@
 
 GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
 # The default value is: NO.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
 # listed.
 # The default value is: YES.
 
 EXTERNAL_GROUPS        = YES
 
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
 # the related pages index. If set to NO, only the current project's pages will
 # be listed.
 # The default value is: YES.
@@ -2070,7 +2146,7 @@
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
 # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
 # NO turns the diagrams off. Note that this option also works with HAVE_DOT
 # disabled, but it is recommended to install and use dot, since it yields more
@@ -2095,7 +2171,7 @@
 
 DIA_PATH               =
 
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# If set to YES the inheritance and collaboration graphs will hide inheritance
 # and usage relations if the target is undocumented or is not a class.
 # The default value is: YES.
 
@@ -2168,7 +2244,7 @@
 
 GROUP_GRAPHS           = YES
 
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
 # collaboration diagrams in a style similar to the OMG's Unified Modeling
 # Language.
 # The default value is: NO.
@@ -2220,7 +2296,8 @@
 #
 # Note that enabling this option will significantly increase the time of a run.
 # So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
 # The default value is: NO.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2231,7 +2308,8 @@
 #
 # Note that enabling this option will significantly increase the time of a run.
 # So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
 # The default value is: NO.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2254,13 +2332,17 @@
 DIRECTORY_GRAPH        = YES
 
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
 # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
 # to make the SVG files visible in IE 9+ (other browsers do not have this
 # requirement).
 # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
 # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
-# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
 # The default value is: png.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2308,10 +2390,19 @@
 # PlantUML is not used or called during a preprocessing step. Doxygen will
 # generate a warning when it encounters a \startuml command in this case and
 # will not generate output for the diagram.
-# This tag requires that the tag HAVE_DOT is set to YES.
 
 PLANTUML_JAR_PATH      =
 
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
 # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
 # that will be shown in the graph. If the number of nodes in a graph becomes
 # larger than this value, doxygen will truncate the graph, which is visualized
@@ -2348,7 +2439,7 @@
 
 DOT_TRANSPARENT        = NO
 
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
 # files in one run (i.e. multiple -o and -T options on the command line). This
 # makes dot run faster, but since only newer versions of dot (>1.8.10) support
 # this, this feature is disabled by default.
@@ -2365,7 +2456,7 @@
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
 # files that are used to generate the various graphs.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
--- a/doc/xcode_frameworks.rst
+++ b/doc/xcode_frameworks.rst
@@ -1,8 +1,6 @@
-.. _xcode-frameworks-label:
+Frameworks for Xcode
+--------------------
 
-Using aubio frameworks in Xcode
--------------------------------
-
 `Binary frameworks`_ are available and ready to use in your XCode project, for
 `iOS`_ and `macOS`_.
 
@@ -34,7 +32,41 @@
 
     import aubio
 
+Using aubio from swift
+----------------------
+
+Once you have downloaded and installed :ref:`aubio.framework
+<xcode-frameworks-label>`, you sould be able to use aubio from C, Obj-C, and
+Swift source files.
+
+
+Here is a short example showing how to read a sound file in swift:
+
+
+  .. code-block:: swift
+
+    import aubio
+
+    let path = Bundle.main.path(forResource: "example", ofType: "mp4")
+    if (path != nil) {
+        let hop_size : uint_t = 512
+        let a = new_fvec(hop_size)
+        let b = new_aubio_source(path, 0, hop_size)
+        var read: uint_t = 0
+        var total_frames : uint_t = 0
+        while (true) {
+            aubio_source_do(b, a, &read)
+            total_frames += read
+            if (read < hop_size) { break }
+        }
+        print("read", total_frames, "frames at", aubio_source_get_samplerate(b), "Hz")
+        del_aubio_source(b)
+        del_fvec(a)
+    } else {
+        print("could not find file")
+    }
+
+
 .. _Binary frameworks: https://aubio.org/download
 .. _iOS: https://aubio.org/download#ios
 .. _macOS: https://aubio.org/download#osx
-.. _Download: https://aubio.org/download
--- a/examples/aubiomfcc.c
+++ b/examples/aubiomfcc.c
@@ -48,6 +48,7 @@
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   // change some default params
   buffer_size  = 512;
   hop_size = 256;
@@ -62,6 +63,10 @@
   fftgrain = new_cvec (buffer_size);
   mfcc = new_aubio_mfcc(buffer_size, n_filters, n_coefs, samplerate);
   mfcc_out = new_fvec(n_coefs);
+  if (pv == NULL || fftgrain == NULL || mfcc == NULL || mfcc_out == NULL) {
+    ret = 1;
+    goto beach;
+  }
 
   examples_common_process((aubio_process_func_t)process_block, process_print);
 
@@ -70,7 +75,7 @@
   del_aubio_mfcc(mfcc);
   del_fvec(mfcc_out);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
--- a/examples/aubionotes.c
+++ b/examples/aubionotes.c
@@ -21,6 +21,8 @@
 #include "utils.h"
 #define PROG_HAS_PITCH 1
 #define PROG_HAS_ONSET 1
+#define PROG_HAS_NOTES 1
+#define PROG_HAS_SILENCE 1
 #define PROG_HAS_JACK 1
 // TODO add PROG_HAS_OUTPUT
 #include "parse_args.h"
@@ -33,12 +35,12 @@
   aubio_notes_do (notes, ibuf, obuf);
   // did we get a note off?
   if (obuf->data[2] != 0) {
-    lastmidi = aubio_freqtomidi (obuf->data[2]) + .5;
+    lastmidi = obuf->data[2];
     send_noteon(lastmidi, 0);
   }
   // did we get a note on?
   if (obuf->data[0] != 0) {
-    lastmidi = aubio_freqtomidi (obuf->data[0]) + .5;
+    lastmidi = obuf->data[0];
     send_noteon(lastmidi, obuf->data[1]);
   }
 }
@@ -49,6 +51,8 @@
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
+
   examples_common_init(argc,argv);
 
   verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
@@ -64,15 +68,38 @@
   verbmsg ("tolerance: %f\n", pitch_tolerance);
 
   notes = new_aubio_notes ("default", buffer_size, hop_size, samplerate);
+  if (notes == NULL) { ret = 1; goto beach; }
 
+  if (onset_minioi != 0.) {
+    aubio_notes_set_minioi_ms(notes, onset_minioi);
+  }
+  if (onset_threshold != 0.) {
+    errmsg ("warning: onset threshold not supported yet\n");
+    //aubio_onset_set_threshold(aubio_notes_get_aubio_onset(o), onset_threshold);
+  }
+  if (silence_threshold != -90.) {
+    if (aubio_notes_set_silence (notes, silence_threshold) != 0) {
+      errmsg ("failed setting notes silence threshold to %.2f\n",
+          silence_threshold);
+    }
+  }
+  if (release_drop != 10.) {
+    if (aubio_notes_set_release_drop (notes, release_drop) != 0) {
+      errmsg ("failed setting notes release drop to %.2f\n",
+          release_drop);
+    }
+  }
+
   examples_common_process((aubio_process_func_t)process_block, process_print);
 
-  // send a last note off
-  send_noteon (lastmidi, 0);
+  // send a last note off if required
+  if (lastmidi) {
+    send_noteon (lastmidi, 0);
+  }
 
   del_aubio_notes (notes);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
--- a/examples/aubioonset.c
+++ b/examples/aubioonset.c
@@ -21,6 +21,7 @@
 #include "utils.h"
 #define PROG_HAS_ONSET 1
 #define PROG_HAS_OUTPUT 1
+#define PROG_HAS_SILENCE 1
 #define PROG_HAS_JACK 1
 #include "parse_args.h"
 
@@ -42,10 +43,11 @@
   } else {
     aubio_wavetable_stop ( wavetable );
   }
-  if (mix_input)
+  if (mix_input) {
     aubio_wavetable_do (wavetable, ibuf, obuf);
-  else
+  } else {
     aubio_wavetable_do (wavetable, obuf, obuf);
+  }
 }
 
 void process_print (void)
@@ -57,21 +59,27 @@
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   examples_common_init(argc,argv);
 
-  verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
-  verbmsg ("onset method: %s, ", onset_method);
-  verbmsg ("buffer_size: %d, ", buffer_size);
-  verbmsg ("hop_size: %d, ", hop_size);
-  verbmsg ("silence: %f, ", silence_threshold);
-  verbmsg ("threshold: %f\n", onset_threshold);
-
   o = new_aubio_onset (onset_method, buffer_size, hop_size, samplerate);
+  if (o == NULL) { ret = 1; goto beach; }
   if (onset_threshold != 0.)
     aubio_onset_set_threshold (o, onset_threshold);
   if (silence_threshold != -90.)
     aubio_onset_set_silence (o, silence_threshold);
+  if (onset_minioi != 0.)
+    aubio_onset_set_minioi_s (o, onset_minioi);
 
+  verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+  verbmsg ("onset method: %s, ", onset_method);
+  verbmsg ("buffer_size: %d, ", buffer_size);
+  verbmsg ("hop_size: %d, ", hop_size);
+  verbmsg ("silence: %f, ", aubio_onset_get_silence(o));
+  verbmsg ("threshold: %f, ", aubio_onset_get_threshold(o));
+  verbmsg ("awhitening: %f, ", aubio_onset_get_awhitening(o));
+  verbmsg ("compression: %f\n", aubio_onset_get_compression(o));
+
   onset = new_fvec (1);
 
   wavetable = new_aubio_wavetable (samplerate, hop_size);
@@ -81,12 +89,15 @@
   examples_common_process((aubio_process_func_t)process_block, process_print);
 
   // send a last note off
-  send_noteon (miditap_note, 0);
+  if (usejack) {
+    send_noteon (miditap_note, 0);
+  }
 
   del_aubio_onset (o);
   del_aubio_wavetable (wavetable);
   del_fvec (onset);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
--- a/examples/aubiopitch.c
+++ b/examples/aubiopitch.c
@@ -21,6 +21,7 @@
 #include "utils.h"
 #define PROG_HAS_PITCH 1
 #define PROG_HAS_OUTPUT 1
+#define PROG_HAS_SILENCE 1
 #define PROG_HAS_JACK 1
 #include "parse_args.h"
 
@@ -51,6 +52,7 @@
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
 
   buffer_size = 2048;
 
@@ -64,6 +66,7 @@
   verbmsg ("tolerance: %f\n", pitch_tolerance);
 
   o = new_aubio_pitch (pitch_method, buffer_size, hop_size, samplerate);
+  if (o == NULL) { ret = 1; goto beach; }
   if (pitch_tolerance != 0.)
     aubio_pitch_set_tolerance (o, pitch_tolerance);
   if (silence_threshold != -90.)
@@ -82,7 +85,7 @@
   del_aubio_wavetable (wavetable);
   del_fvec (pitch);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
--- a/examples/aubioquiet.c
+++ b/examples/aubioquiet.c
@@ -19,6 +19,7 @@
 */
 
 #include "utils.h"
+#define PROG_HAS_SILENCE 1
 #include "parse_args.h"
 
 sint_t wassilence = 1, issilence;
--- a/examples/aubiotrack.c
+++ b/examples/aubiotrack.c
@@ -21,6 +21,7 @@
 #include "utils.h"
 #define PROG_HAS_TEMPO 1
 #define PROG_HAS_ONSET 1
+#define PROG_HAS_SILENCE 1
 #define PROG_HAS_OUTPUT 1
 #define PROG_HAS_JACK 1
 #include "parse_args.h"
@@ -45,10 +46,11 @@
   } else {
     aubio_wavetable_stop ( wavetable );
   }
-  if (mix_input)
+  if (mix_input) {
     aubio_wavetable_do (wavetable, ibuf, obuf);
-  else
+  } else {
     aubio_wavetable_do (wavetable, obuf, obuf);
+  }
 }
 
 void process_print (void) {
@@ -59,6 +61,7 @@
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   // override general settings from utils.c
   buffer_size = 1024;
   hop_size = 512;
@@ -74,9 +77,11 @@
 
   tempo_out = new_fvec(2);
   tempo = new_aubio_tempo(tempo_method, buffer_size, hop_size, samplerate);
+  if (tempo == NULL) { ret = 1; goto beach; }
   // set silence threshold very low to output beats even during silence
   // aubio_tempo_set_silence(tempo, -1000.);
   if (onset_threshold != 0.) aubio_tempo_set_threshold (tempo, onset_threshold);
+  if (onset_minioi != 0.) errmsg ("warning: minioio not supported yet\n");
 
   wavetable = new_aubio_wavetable (samplerate, hop_size);
   aubio_wavetable_set_freq ( wavetable, 2450.);
@@ -85,13 +90,15 @@
   examples_common_process((aubio_process_func_t)process_block,process_print);
 
   // send a last note off
-  send_noteon (miditap_note, 0);
+  if (usejack) {
+    send_noteon (miditap_note, 0);
+  }
 
   del_aubio_tempo(tempo);
   del_aubio_wavetable (wavetable);
   del_fvec(tempo_out);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
--- a/examples/parse_args.h
+++ b/examples/parse_args.h
@@ -36,6 +36,7 @@
 // onset stuff
 extern char_t * onset_method;
 extern smpl_t onset_threshold;
+extern smpl_t onset_minioi;
 // pitch stuff
 extern char_t * pitch_method;
 extern char_t * pitch_unit;
@@ -46,6 +47,7 @@
 extern char_t * tempo_method;
 // more general stuff
 extern smpl_t silence_threshold;
+extern smpl_t release_drop;
 extern uint_t mix_input;
 // midi tap
 extern smpl_t miditap_note;
@@ -63,8 +65,8 @@
 // internal stuff
 extern int blocks;
 
-extern fvec_t *ibuf;
-extern fvec_t *obuf;
+extern fvec_t *input_buffer;
+extern fvec_t *output_buffer;
 
 const char *prog_name;
 
@@ -91,17 +93,25 @@
       "                 default=hfc\n"
       "       -t      --onset-threshold  set onset detection threshold\n"
       "                 a value between 0.1 (more detections) and 1 (less); default=0.3\n"
+      "       -M      --minioi           set minimum inter-onset interval\n"
+      "                 a value in second; default=0.012\n"
 #endif /* PROG_HAS_ONSET */
 #ifdef PROG_HAS_PITCH
       "       -p      --pitch            select pitch detection algorithm\n"
-      "                 <default|yinfft|yin|mcomb|fcomb|schmitt>; default=yinfft\n"
+      "                 <default|yinfft|yinfast|yin|mcomb|fcomb|schmitt>; default=yinfft\n"
       "       -u      --pitch-unit       select pitch output unit\n"
       "                 <default|freq|hertz|Hz|midi|cent|bin>; default=freq\n"
       "       -l      --pitch-tolerance  select pitch tolerance\n"
       "                 (yin, yinfft only) a value between 0.1 and 0.7; default=0.3\n"
 #endif /* PROG_HAS_PITCH */
+#ifdef PROG_HAS_SILENCE
       "       -s      --silence          select silence threshold\n"
       "                 a value in dB, for instance -70, or -100; default=-90\n"
+#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+      "       -d      --release-drop     select release drop threshold\n"
+      "                 a positive value in dB; default=10\n"
+#endif
       "       -T      --time-format      select time values output format\n"
       "                 (samples, ms, seconds) default=seconds\n"
 #ifdef PROG_HAS_OUTPUT
@@ -109,10 +119,14 @@
       "                 input signal will be added to output synthesis\n"
       "       -f      --force-overwrite  overwrite output file if needed\n"
       "                 do not fail if output file already exists\n"
-#endif
-#ifdef PROG_HAS_JACK
+#endif /* PROG_HAS_OUTPUT */
+#if defined(PROG_HAS_JACK) && defined(HAVE_JACK)
       "       -j      --jack             use Jack\n"
-#endif
+#if defined(PROG_HAS_ONSET) && !defined(PROG_HAS_PITCH)
+      "       -N      --miditap-note     MIDI note; default=69.\n"
+      "       -V      --miditap-velo     MIDI velocity; default=65.\n"
+#endif /* defined(PROG_HAS_ONSET) && !defined(PROG_HAS_PITCH) */
+#endif /* defined(PROG_HAS_JACK) && defined(HAVE_JACK) */
       "       -v      --verbose          be verbose\n"
       "       -h      --help             display this message\n"
       );
@@ -131,18 +145,30 @@
     "i:r:B:H:"
 #ifdef PROG_HAS_JACK
     "j"
+#if defined(PROG_HAS_ONSET) && !defined(PROG_HAS_PITCH)
+    "N:V:"
+#endif /* defined(PROG_HAS_ONSET) && !defined(PROG_HAS_PITCH) */
 #endif /* PROG_HAS_JACK */
 #ifdef PROG_HAS_OUTPUT
     "o:"
 #endif /* PROG_HAS_OUTPUT */
 #ifdef PROG_HAS_ONSET
-    "O:t:"
+    "O:t:M:"
 #endif /* PROG_HAS_ONSET */
 #ifdef PROG_HAS_PITCH
     "p:u:l:"
 #endif /* PROG_HAS_PITCH */
     "T:"
-    "s:mf";
+#ifdef PROG_HAS_SILENCE
+    "s:"
+#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+    "d:"
+#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_OUTPUT
+    "mf"
+#endif /* PROG_HAS_OUTPUT */
+    ;
   int next_option;
   struct option long_options[] = {
     {"help",                  0, NULL, 'h'},
@@ -153,6 +179,10 @@
     {"hopsize",               1, NULL, 'H'},
 #ifdef PROG_HAS_JACK
     {"jack",                  0, NULL, 'j'},
+#if defined(PROG_HAS_ONSET) && !defined(PROG_HAS_PITCH)
+    {"miditap-note",          1, NULL, 'N'},
+    {"miditap-velo",          1, NULL, 'V'},
+#endif /* PROG_HAS_ONSET !PROG_HAS_PITCH */
 #endif /* PROG_HAS_JACK */
 #ifdef PROG_HAS_OUTPUT
     {"output",                1, NULL, 'o'},
@@ -160,6 +190,7 @@
 #ifdef PROG_HAS_ONSET
     {"onset",                 1, NULL, 'O'},
     {"onset-threshold",       1, NULL, 't'},
+    {"onset-minioi",          1, NULL, 'M'},
 #endif /* PROG_HAS_ONSET */
 #ifdef PROG_HAS_PITCH
     {"pitch",                 1, NULL, 'p'},
@@ -166,18 +197,25 @@
     {"pitch-unit",            1, NULL, 'u'},
     {"pitch-tolerance",       1, NULL, 'l'},
 #endif /* PROG_HAS_PITCH */
+#ifdef PROG_HAS_SILENCE
     {"silence",               1, NULL, 's'},
+#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+    {"release-drop",          1, NULL, 'd'},
+#endif /* PROG_HAS_NOTES */
     {"time-format",           1, NULL, 'T'},
+#ifdef PROG_HAS_OUTPUT
     {"mix-input",             0, NULL, 'm'},
     {"force-overwrite",       0, NULL, 'f'},
+#endif /* PROG_HAS_OUTPUT */
     {NULL,                    0, NULL, 0}
   };
 #endif /* HAVE_GETOPT_H */
-  prog_name = argv[0];
+  // better safe than sorry
   if (argc < 1) {
     usage (stderr, 1);
-    return -1;
   }
+  prog_name = argv[0];
 #ifdef HAVE_GETOPT_H
   do {
     next_option = getopt_long (argc, argv, options, long_options, NULL);
@@ -191,6 +229,12 @@
       case 'j':
         usejack = 1;
         break;
+      case 'N':
+        miditap_note = (smpl_t) atoi (optarg);
+        break;
+      case 'V':
+        miditap_velo = (smpl_t) atoi (optarg);
+        break;
       case 'i':
         source_uri = optarg;
         break;
@@ -215,6 +259,9 @@
       case 't':                /* threshold value for onset */
         onset_threshold = (smpl_t) atof (optarg);
         break;
+      case 'M':                /* minimum inter-onset-interval */
+        onset_minioi = (smpl_t) atof (optarg);
+        break;
       case 'p':
         pitch_method = optarg;
         break;
@@ -238,6 +285,9 @@
       case 's':                /* silence threshold */
         silence_threshold = (smpl_t) atof (optarg);
         break;
+      case 'd':                /* release-drop threshold */
+        release_drop = (smpl_t) atof (optarg);
+        break;
       case 'm':                /* mix_input flag */
         mix_input = 1;
         break;
@@ -277,7 +327,8 @@
     usejack = 1;
 #else
     errmsg("Error: no arguments given (and no available audio input)\n");
-    usage ( stderr, 1 );
+    errmsg("       consider recompiling with jack support (--enable-jack)\n");
+    exit ( 1 );
 #endif /* HAVE_JACK */
 #else
     errmsg("Error: no arguments given\n");
--- a/examples/utils.c
+++ b/examples/utils.c
@@ -43,6 +43,7 @@
 // onset stuff
 char_t * onset_method = "default";
 smpl_t onset_threshold = 0.0; // will be set if != 0.
+smpl_t onset_minioi = 0.0; // will be set if != 0.
 // pitch stuff
 char_t * pitch_unit = "default";
 char_t * pitch_method = "default";
@@ -53,6 +54,7 @@
 char_t * tempo_method = "default";
 // more general stuff
 smpl_t silence_threshold = -90.;
+smpl_t release_drop = 10.;
 uint_t mix_input = 0;
 
 uint_t force_overwrite = 0;
@@ -61,8 +63,8 @@
 // internal memory stuff
 aubio_source_t *this_source = NULL;
 aubio_sink_t *this_sink = NULL;
-fvec_t *ibuf;
-fvec_t *obuf;
+fvec_t *input_buffer;
+fvec_t *output_buffer;
 
 smpl_t miditap_note = 69.;
 smpl_t miditap_velo = 65.;
@@ -74,7 +76,12 @@
 extern int parse_args (int argc, char **argv);
 
 #if HAVE_JACK
+#define MAX_MIDI_EVENTS 128
+#define MAX_MIDI_EVENT_SIZE 3
 aubio_jack_t *jack_setup;
+jack_midi_event_t ev;
+jack_midi_data_t midi_data[MAX_MIDI_EVENTS * MAX_MIDI_EVENT_SIZE];
+size_t midi_event_count = 0;
 #endif /* HAVE_JACK */
 
 void examples_common_init (int argc, char **argv);
@@ -119,15 +126,15 @@
     source_uri = "jack";
 #endif /* HAVE_JACK */
   }
-  ibuf = new_fvec (hop_size);
-  obuf = new_fvec (hop_size);
+  input_buffer = new_fvec (hop_size);
+  output_buffer = new_fvec (hop_size);
 
 }
 
 void examples_common_del (void)
 {
-  del_fvec (ibuf);
-  del_fvec (obuf);
+  del_fvec (input_buffer);
+  del_fvec (output_buffer);
   aubio_cleanup ();
   fflush(stderr);
   fflush(stdout);
@@ -141,6 +148,8 @@
   if (usejack) {
 
 #ifdef HAVE_JACK
+    ev.size = MAX_MIDI_EVENT_SIZE;
+    ev.time = 0; // send it now
     debug ("Jack activation ...\n");
     aubio_jack_activate (jack_setup, process_func);
     debug ("Processing (Ctrl+C to quit) ...\n");
@@ -157,14 +166,14 @@
     blocks = 0;
 
     do {
-      aubio_source_do (this_source, ibuf, &read);
-      process_func (ibuf, obuf);
+      aubio_source_do (this_source, input_buffer, &read);
+      process_func (input_buffer, output_buffer);
       // print to console if verbose or no output given
       if (verbose || sink_uri == NULL) {
         print();
       }
       if (this_sink) {
-        aubio_sink_do (this_sink, obuf, hop_size);
+        aubio_sink_do (this_sink, output_buffer, hop_size);
       }
       blocks++;
       total_read += read;
@@ -184,11 +193,11 @@
 send_noteon (smpl_t pitch, smpl_t velo)
 {
 #ifdef HAVE_JACK
-  jack_midi_event_t ev;
-  ev.size = 3;
-  ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
-  ev.time = 0;
   if (usejack) {
+    ev.buffer = midi_data + midi_event_count++ * MAX_MIDI_EVENT_SIZE;
+    if (midi_event_count >= MAX_MIDI_EVENTS) {
+      midi_event_count = 0;
+    }
     ev.buffer[2] = velo;
     ev.buffer[1] = pitch;
     if (velo == 0) {
--- a/examples/utils.h
+++ b/examples/utils.h
@@ -66,7 +66,7 @@
 void send_noteon (smpl_t pitch, smpl_t velo);
 
 /** common process function */
-typedef int (*aubio_process_func_t) (fvec_t * input, fvec_t * output);
+typedef void (*aubio_process_func_t) (fvec_t * input, fvec_t * output);
 
 void process_block (fvec_t *ibuf, fvec_t *obuf);
 void process_print (void);
--- a/python/README.md
+++ b/python/README.md
@@ -1,100 +1,109 @@
-Python aubio module
-===================
+aubio
+=====
 
-This module wraps the aubio library for Python using the numpy module.
+aubio is a collection of tools for music and audio analysis.
 
-Using the Python aubio module
------------------------------
+This package integrates the aubio library with [NumPy] to provide a set of
+efficient tools to process and analyse audio signals, including:
 
-After installing python-aubio, you will be able to import the aubio module:
+- read audio from any media file, including videos and remote streams
+- high quality phase vocoder, spectral filterbanks, and linear filters
+- Mel-Frequency Cepstrum Coefficients and standard spectral descriptors
+- detection of note attacks (onset)
+- pitch tracking (fundamental frequency estimation)
+- beat detection and tempo tracking
 
-    $ python
-    [...]
-    >>> import aubio
-    >>> help(aubio.miditofreq)
+aubio works with both Python 2 and Python 3.
 
-Finding some inspiration
-------------------------
+Links
+-----
 
-Some examples are available in the `python/demos` directory. These scripts are
-small programs written in python and using python-aubio.
+- [module documentation][doc_python]
+- [installation instructions][doc_python_install]
+- [aubio manual][manual]
+- [aubio homepage][homepage]
+- [issue tracker][bugtracker]
 
-For instance, `demo_source.py` reads a media file.
+Demos
+-----
 
-    $ ./python/demos/demo_source.py /path/to/sound/sample.wav
+Some examples are available in the [`python/demos`][demos_dir] folder. Each
+script is a command line program which accepts one ore more argument.
 
-and `demo_timestretch_online.py` stretches the original file into a new one:
+**Notes**: installing additional modules is required to run some of the demos.
 
-    $ ./python/demo/demo_timestretch_online.py loop.wav stretched_loop.wav 0.92`
+### Analysis
 
-Note: you might need to install additional modules to run some of the demos.
-Some demos use [matplotlib](http://matplotlib.org/) to draw plots, others use
-[PySoundCard](https://github.com/bastibe/PySoundCard) to play and record
-sounds.
+- `demo_source.py` uses aubio to read audio samples from media files
+- `demo_onset_plot.py` detects attacks in a sound file and plots the results
+  using [matplotlib]
+- `demo_pitch.py` looks for fundamental frequency in a sound file and plots the
+  results using [matplotlib]
+- `demo_spectrogram.py`, `demo_specdesc.py`, `demo_mfcc.py` for spectral
+  analysis.
 
-Testing the Python module
--------------------------
+### Real-time
 
-To run the all the python tests, use the script:
+- `demo_pyaudio.py` and `demo_tapthebeat.py` use [pyaudio]
+- `demo_pysoundcard_play.py`, `demo_pysoundcard.py` use [PySoundCard]
+- `demo_alsa.py` uses [pyalsaaudio]
 
-    $ ./python/tests/run_all_tests
+### Others
 
-Each test script can also be called one at a time. For instance:
+- `demo_timestretch.py` can change the duration of an input file and write the
+  new sound to disk,
+- `demo_wav2midi.py` detects the notes in a file and uses [mido] to write the
+  results into a MIDI file
 
-    $ ./python/tests/test_note2midi.py -v
+### Example
 
-Install in a virtualenv
------------------------
+Use `demo_timestretch_online.py` to slow down `loop.wav`, write the results in
+`stretched_loop.wav`:
 
-You should be able to install python-aubio directly from the top source
-directory of aubio.
+    $ python demo_timestretch_online.py loop.wav stretched_loop.wav 0.92
 
-First, create a virtualenv to hold the required python module:
+Built with
+----------
 
-    $ virtualenv pyaubio
-    $ source pyaubio/bin/activate
+The core of aubio is written in C for portability and speed. In addition to
+[NumPy], aubio can be optionally built to use one or more of the following
+libraries:
 
-Now install and build the python extension using:
+- media file reading:
 
-    $ pip install .
+    - [ffmpeg] / [avcodec] to decode and read audio from almost any format,
+    - [libsndfile] to read audio from uncompressed sound files,
+    - [libsamplerate] to re-sample audio signals,
+    - [CoreAudio] to read all media formats supported by macOS, iOS, and tvOS.
 
-Install requirements
---------------------
+- hardware acceleration:
 
-Before compiling this module, you must have compiled libaubio.
+    - [Atlas] and [Blas], for accelerated vector and matrix computations,
+    - [fftw3], to compute fast Fourier Transforms of any size,
+    - [Accelerate] for accelerated FFT and matrix computations (macOS/iOS),
+    - [Intel IPP], accelerated vector computation and FFT implementation.
 
-A simple way to do this is with pip:
+[ffmpeg]: https://ffmpeg.org
+[avcodec]: https://libav.org
+[libsndfile]: http://www.mega-nerd.com/libsndfile/
+[libsamplerate]: http://www.mega-nerd.com/SRC/
+[CoreAudio]: https://developer.apple.com/reference/coreaudio
+[Atlas]: http://math-atlas.sourceforge.net/
+[Blas]: https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms
+[fftw3]: http://fftw.org
+[Accelerate]: https://developer.apple.com/reference/accelerate
+[Intel IPP]: https://software.intel.com/en-us/intel-ipp
 
-    $ pip install -r requirements.txt
+[demos_dir]:https://github.com/aubio/aubio/tree/master/python/demos
+[pyaudio]:https://people.csail.mit.edu/hubert/pyaudio/
+[PySoundCard]:https://github.com/bastibe/PySoundCard
+[pyalsaaudio]:https://larsimmisch.github.io/pyalsaaudio/
+[mido]:https://mido.readthedocs.io
 
-For more information about how this module works, please refer to the [Python/C
-API Reference Manual] (http://docs.python.org/c-api/index.html) and the
-[Numpy/C API Reference](http://docs.scipy.org/doc/numpy/reference/c-api.html).
-
-Compiling python aubio
-----------------------
-
-To build the aubio Python module, run the following command from the top source
-directory of aubio:
-
-    $ ./setup.py build
-
-Note: if libaubio was previously built using waf, the script will use it.
-Otherwise, the entire library will be built inside the python extension.
-
-To find out more about `setup.py` options:
-
-    $ ./setup.py --help
-
-Installing
-----------
-
-To install the Python module:
-
-    $ ./setup.py install
-
-Alternatively, you may want to use the Python module without installing it by
-setting your PYTHONPATH, for instance as follows:
-
-    $ export PYTHONPATH=$PYTHONPATH:$PWD/`ls -rtd build/lib.* | head -1`:$PWD/tests
-
+[manual]: https://aubio.org/manual/latest/
+[doc_python]: https://aubio.org/manual/latest/python.html
+[doc_python_install]: https://aubio.org/manual/latest/python_module.html
+[homepage]: https://aubio.org
+[NumPy]: https://www.numpy.org
+[bugtracker]: https://github.com/aubio/aubio/issues
+[matplotlib]:https://matplotlib.org/
--- /dev/null
+++ b/python/demos/demo_alsa.py
@@ -1,0 +1,45 @@
+#! /usr/bin/env python
+
+import alsaaudio
+import numpy as np
+import aubio
+
+# constants
+samplerate = 44100
+win_s = 2048
+hop_s = win_s // 2
+framesize = hop_s
+
+# set up audio input
+recorder = alsaaudio.PCM(type=alsaaudio.PCM_CAPTURE)
+recorder.setperiodsize(framesize)
+recorder.setrate(samplerate)
+recorder.setformat(alsaaudio.PCM_FORMAT_FLOAT_LE)
+recorder.setchannels(1)
+
+# create aubio pitch detection (first argument is method, "default" is
+# "yinfft", can also be "yin", "mcomb", fcomb", "schmitt").
+pitcher = aubio.pitch("default", win_s, hop_s, samplerate)
+# set output unit (can be 'midi', 'cent', 'Hz', ...)
+pitcher.set_unit("Hz")
+# ignore frames under this level (dB)
+pitcher.set_silence(-40)
+
+print("Starting to listen, press Ctrl+C to stop")
+
+# main loop
+while True:
+    try:
+        # read data from audio input
+        _, data = recorder.read()
+        # convert data to aubio float samples
+        samples = np.fromstring(data, dtype=aubio.float_type)
+        # pitch of current frame
+        freq = pitcher(samples)[0]
+        # compute energy of current block
+        energy = np.sum(samples**2)/len(samples)
+        # do something with the results
+        print("{:10.4f} {:10.4f}".format(freq,energy))
+    except KeyboardInterrupt:
+        print("Ctrl+C pressed, exiting")
+        break
--- /dev/null
+++ b/python/demos/demo_bench_yin.py
@@ -1,0 +1,50 @@
+#! /usr/bin/env python
+
+import numpy as np
+from aubio import pitch
+import pylab as plt
+
+buf_size = 2048 * 1
+hop_size = buf_size // 4
+
+samplerate = 44100
+minfreq = 40
+maxfreq = 6000
+
+def sinewave(freq, duration, samplerate = samplerate):
+    """ generate a sinewave """
+    length = hop_size
+    while length < duration * samplerate:
+        length += hop_size
+    return np.sin( 2. * np.pi * np.arange(length) * freq / samplerate ).astype("float32")
+
+def get_stats_for_pitch_method(method, freqs, samplerate = samplerate):
+    """ for a given pitch method and a list of frequency, generate a sinewave
+    and get mean deviation """
+    means = np.zeros(len(freqs))
+    medians = np.zeros(len(freqs))
+    for freq, fn in zip(freqs, range(len(freqs))):
+        s = sinewave(freq, .50).reshape(-1, hop_size)
+        #s = (sinewave(freq, .50) + .0*sinewave(freq/2., .50)).reshape(-1, hop_size)
+        p = pitch(method, buf_size, hop_size, samplerate = samplerate)
+        candidates = np.zeros(len(s))
+        #samples = np.zeros(buf_size)
+        for frame, i in zip(s, range(len(s))):
+            candidates[i] = p(frame)[0]
+        # skip first few candidates
+        candidates = candidates[4:]
+        means[fn] = np.mean(candidates[candidates != 0] - freq)
+        medians[fn] = np.median(candidates[candidates != 0] - freq)
+        print (freq, means[fn], medians[fn])
+    return means, medians
+
+if __name__ == '__main__':
+    freqs = np.arange(minfreq, maxfreq, 1.)
+    modes = ["yin", "yinfft"]
+    for mode in modes:
+        means, medians = get_stats_for_pitch_method(mode, freqs)
+        plt.figure()
+        plt.plot(freqs, means, 'g-')
+        plt.plot(freqs, medians, 'r--')
+        #plt.savefig(mode + '_deviations_test.png', dpi=300)
+        plt.show()
--- a/python/demos/demo_bpm_extract.py
+++ b/python/demos/demo_bpm_extract.py
@@ -3,7 +3,7 @@
 from aubio import source, tempo
 from numpy import median, diff
 
-def get_file_bpm(path, params = None):
+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
@@ -10,19 +10,26 @@
     """
     if params is None:
         params = {}
-    try:
-        win_s = params['win_s']
-        samplerate = params['samplerate']
-        hop_s = params['hop_s']
-    except KeyError:
-        """
-        # super fast
-        samplerate, win_s, hop_s = 4000, 128, 64 
-        # fast
-        samplerate, win_s, hop_s = 8000, 512, 128
-        """
-        # default:
-        samplerate, win_s, hop_s = 44100, 1024, 512
+    # default:
+    samplerate, win_s, hop_s = 44100, 1024, 512
+    if 'mode' in params:
+        if params.mode in ['super-fast']:
+            # super fast
+            samplerate, win_s, hop_s = 4000, 128, 64
+        elif params.mode in ['fast']:
+            # fast
+            samplerate, win_s, hop_s = 8000, 512, 128
+        elif params.mode in ['default']:
+            pass
+        else:
+            raise ValueError("unknown mode {:s}".format(params.mode))
+    # manual settings
+    if 'samplerate' in params:
+        samplerate = params.samplerate
+    if 'win_s' in params:
+        win_s = params.win_s
+    if 'hop_s' in params:
+        hop_s = params.hop_s
 
     s = source(path, samplerate, hop_s)
     samplerate = s.samplerate
@@ -44,19 +51,29 @@
         if read < hop_s:
             break
 
-    # Convert to periods and to bpm 
-    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
+    def beats_to_bpm(beats, path):
+        # if enough beats are found, convert to periods then to bpm
+        if len(beats) > 1:
+            if len(beats) < 4:
+                print("few beats found in {:s}".format(path))
+            bpms = 60./diff(beats)
+            return median(bpms)
+        else:
+            print("not enough beats found in {:s}".format(path))
+            return 0
 
+    return beats_to_bpm(beats, path)
+
 if __name__ == '__main__':
-    import sys
-    for f in sys.argv[1:]:
-        bpm = get_file_bpm(f)
+    import argparse
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-m', '--mode',
+            help="mode [default|fast|super-fast]",
+            dest="mode", default='default')
+    parser.add_argument('sources',
+            nargs='+',
+            help="input_files")
+    args = parser.parse_args()
+    for f in args.sources:
+        bpm = get_file_bpm(f, params = args)
         print("{:6s} {:s}".format("{:2f}".format(bpm), f))
--- a/python/demos/demo_filter.py
+++ b/python/demos/demo_filter.py
@@ -1,36 +1,53 @@
 #! /usr/bin/env python
 
+import sys
+import os.path
+import aubio
 
-def apply_filter(path):
-    from aubio import source, sink, digital_filter
-    from os.path import basename, splitext
 
+def apply_filter(path, target):
     # open input file, get its samplerate
-    s = source(path)
+    s = aubio.source(path)
     samplerate = s.samplerate
 
     # create an A-weighting filter
-    f = digital_filter(7)
+    f = aubio.digital_filter(7)
     f.set_a_weighting(samplerate)
-    # alternatively, apply another filter
 
     # create output file
-    o = sink("filtered_" + splitext(basename(path))[0] + ".wav", samplerate)
+    o = aubio.sink(target, samplerate)
 
     total_frames = 0
     while True:
+        # read from source
         samples, read = s()
+        # filter samples
         filtered_samples = f(samples)
+        # write to sink
         o(filtered_samples, read)
+        # count frames read
         total_frames += read
-        if read < s.hop_size: break
+        # end of file reached
+        if read < s.hop_size:
+            break
 
+    # print some info
     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))
+    input_str = "input: {:s} ({:.2f} s, {:d} Hz)"
+    output_str = "output: {:s}, A-weighting filtered ({:d} frames total)"
+    print(input_str.format(s.uri, duration, samplerate))
+    print(output_str.format(o.uri, total_frames))
 
 if __name__ == '__main__':
-    import sys
-    for f in sys.argv[1:]:
-        apply_filter(f)
+    usage = "{:s} <input_file> [output_file]".format(sys.argv[0])
+    if not 1 < len(sys.argv) < 4:
+        print(usage)
+        sys.exit(1)
+    if len(sys.argv) < 3:
+        input_path = sys.argv[1]
+        basename = os.path.splitext(os.path.basename(input_path))[0] + ".wav"
+        output_path = "filtered_" + basename
+    else:
+        input_path, output_path = sys.argv[1:]
+    # run function
+    apply_filter(input_path, output_path)
--- a/python/demos/demo_filterbank.py
+++ b/python/demos/demo_filterbank.py
@@ -1,30 +1,44 @@
 #! /usr/bin/env python
 
-from aubio import filterbank, fvec
-from pylab import loglog, show, xlim, ylim, xlabel, ylabel, title
-from numpy import vstack, arange
+"""Create a filterbank from a list of frequencies.
 
-win_s = 2048
+This demo uses `aubio.filterbank.set_triangle_bands` to build a set of
+triangular filters from a list of frequencies.
+
+The filterbank coefficients are then modified before being displayed."""
+
+import aubio
+import numpy as np
+import matplotlib.pyplot as plt
+
+# sampling rate and size of the fft
 samplerate = 48000
+win_s = 2048
 
+# define a list of custom frequency
 freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000]
+# number of filters to create
 n_filters = len(freq_list) - 2
 
-f = filterbank(n_filters, win_s)
-freqs = fvec(freq_list)
+# create a new filterbank
+f = aubio.filterbank(n_filters, win_s)
+freqs = aubio.fvec(freq_list)
 f.set_triangle_bands(freqs, samplerate)
 
+# get the coefficients from the filterbank
 coeffs = f.get_coeffs()
-coeffs[4] *= 5.
-
+# apply a gain to fifth band
+coeffs[4] *= 6.
+# load the modified coeffs into the filterbank
 f.set_coeffs(coeffs)
 
-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])
-ylim([1.0e-6, 2.0e-2])
-xlabel('log frequency (Hz)')
-ylabel('log amplitude')
-
-show()
+# display the band gains in a loglog plot
+freqs = np.vstack([np.arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
+plt.title('filterbank built from a list of frequencies\n'
+          'The 5th band has been amplified by a factor 6.')
+plt.loglog(freqs.T, f.get_coeffs().T, '.-')
+plt.xlim([50, samplerate/2])
+plt.ylim([1.0e-6, 2.0e-2])
+plt.xlabel('log frequency (Hz)')
+plt.ylabel('log amplitude')
+plt.show()
--- /dev/null
+++ b/python/demos/demo_notes.py
@@ -1,0 +1,37 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, notes
+
+if len(sys.argv) < 2:
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+    sys.exit(1)
+
+filename = sys.argv[1]
+
+downsample = 1
+samplerate = 44100 // downsample
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+win_s = 512 // downsample # fft size
+hop_s = 256 // downsample # hop size
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+tolerance = 0.8
+
+notes_o = notes("default", win_s, hop_s, samplerate)
+
+print("%8s" % "time","[ start","vel","last ]")
+
+# total number of frames read
+total_frames = 0
+while True:
+    samples, read = s()
+    new_note = notes_o(samples)
+    if (new_note[0] != 0):
+        note_str = ' '.join(["%.2f" % i for i in new_note])
+        print("%.6f" % (total_frames/float(samplerate)), new_note)
+    total_frames += read
+    if read < hop_s: break
--- a/python/demos/demo_pitch_sinusoid.py
+++ b/python/demos/demo_pitch_sinusoid.py
@@ -37,7 +37,7 @@
 
 pointer += partition
 pointer += partition
-freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length/8)
+freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length//8)
 
 a = build_sinusoid(sin_length, freqs, samplerate)
 
--- /dev/null
+++ b/python/demos/demo_pyaudio.py
@@ -1,0 +1,75 @@
+#! /usr/bin/env python
+
+# Use pyaudio to open the microphone and run aubio.pitch on the stream of
+# incoming samples. If a filename is given as the first argument, it will
+# record 5 seconds of audio to this location. Otherwise, the script will
+# run until Ctrl+C is pressed.
+
+# Examples:
+#    $ ./python/demos/demo_pyaudio.py
+#    $ ./python/demos/demo_pyaudio.py /tmp/recording.wav
+
+import pyaudio
+import sys
+import numpy as np
+import aubio
+
+# initialise pyaudio
+p = pyaudio.PyAudio()
+
+# open stream
+buffer_size = 1024
+pyaudio_format = pyaudio.paFloat32
+n_channels = 1
+samplerate = 44100
+stream = p.open(format=pyaudio_format,
+                channels=n_channels,
+                rate=samplerate,
+                input=True,
+                frames_per_buffer=buffer_size)
+
+if len(sys.argv) > 1:
+    # record 5 seconds
+    output_filename = sys.argv[1]
+    record_duration = 5 # exit 1
+    outputsink = aubio.sink(sys.argv[1], samplerate)
+    total_frames = 0
+else:
+    # run forever
+    outputsink = None
+    record_duration = None
+
+# setup pitch
+tolerance = 0.8
+win_s = 4096 # fft size
+hop_s = buffer_size # hop size
+pitch_o = aubio.pitch("default", win_s, hop_s, samplerate)
+pitch_o.set_unit("midi")
+pitch_o.set_tolerance(tolerance)
+
+print("*** starting recording")
+while True:
+    try:
+        audiobuffer = stream.read(buffer_size)
+        signal = np.fromstring(audiobuffer, dtype=np.float32)
+
+        pitch = pitch_o(signal)[0]
+        confidence = pitch_o.get_confidence()
+
+        print("{} / {}".format(pitch,confidence))
+
+        if outputsink:
+            outputsink(signal, len(signal))
+
+        if record_duration:
+            total_frames += len(signal)
+            if record_duration * samplerate < total_frames:
+                break
+    except KeyboardInterrupt:
+        print("*** Ctrl+C pressed, exiting")
+        break
+
+print("*** done recording")
+stream.stop_stream()
+stream.close()
+p.terminate()
--- a/python/demos/demo_source_simple.py
+++ b/python/demos/demo_source_simple.py
@@ -1,16 +1,20 @@
 #! /usr/bin/env python
-import sys, aubio
 
+"""A simple example using aubio.source."""
+
+import sys
+import aubio
+
 samplerate = 0  # use original source samplerate
-hop_size = 256 # number of frames to read in one block
-s = aubio.source(sys.argv[1], samplerate, hop_size)
+hop_size = 256  # number of frames to read in one block
+src = aubio.source(sys.argv[1], samplerate, hop_size)
 total_frames = 0
 
-while True: # reading loop
-    samples, read = s()
-    total_frames += read
-    if read < hop_size: break # end of file reached
+while True:
+    samples, read = src()  # read hop_size new samples from source
+    total_frames += read   # increment total number of frames
+    if read < hop_size:    # end of file reached
+        break
 
 fmt_string = "read {:d} frames at {:d}Hz from {:s}"
-print (fmt_string.format(total_frames, s.samplerate, sys.argv[1]))
-
+print(fmt_string.format(total_frames, src.samplerate, src.uri))
--- /dev/null
+++ b/python/demos/demo_tapthebeat.py
@@ -1,0 +1,78 @@
+#! /usr/bin/env python
+
+""" A simple demo using aubio and pyaudio to play beats in real time
+
+Note you will need to have pyaudio installed: `pip install pyaudio`.
+
+Examples:
+    ./demo_tapthebeat.py ~/Music/track1.ogg
+
+When compiled with ffmpeg/libav, you should be able to open remote streams. For
+instance using youtube-dl (`pip install youtube-dl`):
+
+    ./demo_tapthebeat.py `youtube-dl -xg https://youtu.be/zZbM9n9j3_g`
+
+"""
+
+import sys
+import time
+import pyaudio
+import aubio
+import numpy as np
+
+win_s = 1024                # fft size
+hop_s = win_s // 2          # hop size
+
+# parse command line arguments
+if len(sys.argv) < 2:
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+    sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+# create aubio source
+a_source = aubio.source(filename, samplerate, hop_s)
+samplerate = a_source.samplerate
+
+# create aubio tempo detection
+a_tempo = aubio.tempo("default", win_s, hop_s, samplerate)
+
+# create a simple click sound
+click = 0.7 * np.sin(2. * np.pi * np.arange(hop_s) / hop_s * samplerate / 3000.)
+
+# pyaudio callback
+def pyaudio_callback(_in_data, _frame_count, _time_info, _status):
+    samples, read = a_source()
+    is_beat = a_tempo(samples)
+    if is_beat:
+        samples += click
+        #print ('tick') # avoid print in audio callback
+    audiobuf = samples.tobytes()
+    if read < hop_s:
+        return (audiobuf, pyaudio.paComplete)
+    return (audiobuf, pyaudio.paContinue)
+
+# create pyaudio stream with frames_per_buffer=hop_s and format=paFloat32
+p = pyaudio.PyAudio()
+pyaudio_format = pyaudio.paFloat32
+frames_per_buffer = hop_s
+n_channels = 1
+stream = p.open(format=pyaudio_format, channels=n_channels, rate=samplerate,
+        output=True, frames_per_buffer=frames_per_buffer,
+        stream_callback=pyaudio_callback)
+
+# start pyaudio stream
+stream.start_stream()
+
+# wait for stream to finish
+while stream.is_active():
+    time.sleep(0.1)
+
+# stop pyaudio stream
+stream.stop_stream()
+stream.close()
+# close pyaudio
+p.terminate()
--- a/python/demos/demo_timestretch.py
+++ b/python/demos/demo_timestretch.py
@@ -12,7 +12,7 @@
 import numpy as np
 
 win_s = 1024
-hop_s = win_s / 8 # 87.5 % overlap
+hop_s = win_s // 8 # 87.5 % overlap
 
 warmup = win_s // hop_s - 1
 
--- a/python/demos/demo_timestretch_online.py
+++ b/python/demos/demo_timestretch_online.py
@@ -11,8 +11,8 @@
 from aubio import unwrap2pi, float_type
 import numpy as np
 
-win_s = 1024
-hop_s = win_s / 8 # 87.5 % overlap
+win_s = 512
+hop_s = win_s // 8 # 87.5 % overlap
 
 warmup = win_s // hop_s - 1
 
@@ -92,8 +92,10 @@
     old_grain.norm = np.copy(cur_grain.norm)
     old_grain.phas = np.copy(cur_grain.phas)
 
-    block_read += 1
+    # until end of file
     if read < hop_s: break
+    # increment block counter
+    block_read += 1
 
 for t in range(warmup + 2): # purge the last frames from the phase vocoder
     new_grain.norm[:] = 0
--- /dev/null
+++ b/python/demos/demo_wav2midi.py
@@ -1,0 +1,77 @@
+#! /usr/bin/env python
+
+# Simple demo to extract notes from a sound file, and store them in a midi file
+# using mido.
+#
+# Install mido: `pip instal mido`
+#
+# Documentation: https://mido.readthedocs.io/
+
+import sys
+from aubio import source, notes
+from mido import Message, MetaMessage, MidiFile, MidiTrack, second2tick, bpm2tempo
+
+if len(sys.argv) < 3:
+    print("Usage: %s <filename> <output> [samplerate]" % sys.argv[0])
+    sys.exit(1)
+
+filename = sys.argv[1]
+midioutput = sys.argv[2]
+
+downsample = 1
+samplerate = 44100 // downsample
+if len( sys.argv ) > 3: samplerate = int(sys.argv[3])
+
+win_s = 512 // downsample # fft size
+hop_s = 256 // downsample # hop size
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+tolerance = 0.8
+
+notes_o = notes("default", win_s, hop_s, samplerate)
+
+print("%8s" % "time","[ start","vel","last ]")
+
+# create a midi file
+mid = MidiFile()
+track = MidiTrack()
+mid.tracks.append(track)
+
+ticks_per_beat = mid.ticks_per_beat # default: 480
+bpm = 120 # default midi tempo
+
+tempo = bpm2tempo(bpm)
+track.append(MetaMessage('set_tempo', tempo=tempo))
+track.append(MetaMessage('time_signature', numerator=4, denominator=4))
+
+def frames2tick(frames, samplerate=samplerate):
+    sec = frames / float(samplerate)
+    return int(second2tick(sec, ticks_per_beat, tempo))
+
+last_time = 0
+
+# total number of frames read
+total_frames = 0
+while True:
+    samples, read = s()
+    new_note = notes_o(samples)
+    if (new_note[0] != 0):
+        note_str = ' '.join(["%.2f" % i for i in new_note])
+        print("%.6f" % (total_frames/float(samplerate)), new_note)
+        delta = frames2tick(total_frames) - last_time
+        if new_note[2] > 0:
+            track.append(Message('note_off', note=int(new_note[2]),
+                velocity=127, time=0)
+                )
+        track.append(Message('note_on',
+            note=int(new_note[0]),
+            velocity=int(new_note[1]),
+            time=delta)
+            )
+        last_time = frames2tick(total_frames)
+    total_frames += read
+    if read < hop_s: break
+
+mid.save(midioutput)
--- /dev/null
+++ b/python/demos/demo_yin_compare.py
@@ -1,0 +1,175 @@
+#! /usr/bin/env python
+# -*- coding: utf8 -*-
+
+""" Pure python implementation of the sum of squared difference
+
+    sqd_yin: original sum of squared difference [0]
+        d_t(tau) = x ⊗ kernel
+    sqd_yinfast: sum of squared diff using complex domain [0]
+    sqd_yinfftslow: tappered squared diff [1]
+    sqd_yinfft: modified squared diff using complex domain [1]
+
+[0]:http://audition.ens.fr/adc/pdf/2002_JASA_YIN.pdf
+[1]:https://aubio.org/phd/
+"""
+
+import sys
+import numpy as np
+import matplotlib.pyplot as plt
+
+def sqd_yin(samples):
+    """ compute original sum of squared difference
+
+    Brute-force computation (cost o(N**2), slow)."""
+    B = len(samples)
+    W = B//2
+    yin = np.zeros(W)
+    for j in range(W):
+        for tau in range(1, W):
+            yin[tau] += (samples[j] - samples[j+tau])**2
+    return yin
+
+def sqd_yinfast(samples):
+    """ compute approximate sum of squared difference
+
+    Using complex convolution (fast, cost o(n*log(n)) )"""
+    # yin_t(tau) = (r_t(0) + r_(t+tau)(0)) - 2r_t(tau)
+    B = len(samples)
+    W = B//2
+    yin = np.zeros(W)
+    sqdiff = np.zeros(W)
+    kernel = np.zeros(B)
+    # compute r_(t+tau)(0)
+    squares = samples**2
+    for tau in range(W):
+        sqdiff[tau] = squares[tau:tau+W].sum()
+    # add r_t(0)
+    sqdiff += sqdiff[0]
+    # compute r_t(tau) using kernel convolution in complex domain
+    samples_fft = np.fft.fft(samples)
+    kernel[1:W+1] = samples[W-1::-1] # first half, reversed
+    kernel_fft = np.fft.fft(kernel)
+    r_t_tau = np.fft.ifft(samples_fft * kernel_fft).real[W:]
+    # compute yin_t(tau)
+    yin = sqdiff - 2 * r_t_tau
+    return yin
+
+def sqd_yintapered(samples):
+    """ compute tappered sum of squared difference
+
+    Brute-force computation (cost o(N**2), slow)."""
+    B = len(samples)
+    W = B//2
+    yin = np.zeros(W)
+    for tau in range(1, W):
+        for j in range(W - tau):
+            yin[tau] += (samples[j] - samples[j+tau])**2
+    return yin
+
+def sqd_yinfft(samples):
+    """ compute yinfft modified sum of squared differences
+
+    Very fast, improved performance in transients.
+
+    FIXME: biased."""
+    B = len(samples)
+    W = B//2
+    yin = np.zeros(W)
+    def hanningz(W):
+        return .5 * (1. - np.cos(2. * np.pi * np.arange(W) / W))
+    #win = np.ones(B)
+    win = hanningz(B)
+    sqrmag = np.zeros(B)
+    fftout = np.fft.fft(win*samples)
+    sqrmag[0] = fftout[0].real**2
+    for l in range(1, W):
+        sqrmag[l] = fftout[l].real**2 + fftout[l].imag**2
+        sqrmag[B-l] = sqrmag[l]
+    sqrmag[W] = fftout[W].real**2
+    fftout = np.fft.fft(sqrmag)
+    sqrsum = 2.*sqrmag[:W + 1].sum()
+    yin[0] = 0
+    yin[1:] = sqrsum - fftout.real[1:W]
+    return yin / B
+
+def cumdiff(yin):
+    """ compute the cumulative mean normalized difference """
+    W = len(yin)
+    yin[0] = 1.
+    cumsum = 0.
+    for tau in range(1, W):
+        cumsum += yin[tau]
+        if cumsum != 0:
+            yin[tau] *= tau/cumsum
+        else:
+            yin[tau] = 1
+    return yin
+
+def compute_all(x):
+    import time
+    now = time.time()
+
+    yin     = sqd_yin(x)
+    t1 = time.time()
+    print ("yin took %.2fms" % ((t1-now) * 1000.))
+
+    yinfast = sqd_yinfast(x)
+    t2 = time.time()
+    print ("yinfast took: %.2fms" % ((t2-t1) * 1000.))
+
+    yintapered = sqd_yintapered(x)
+    t3 = time.time()
+    print ("yintapered took: %.2fms" % ((t3-t2) * 1000.))
+
+    yinfft  = sqd_yinfft(x)
+    t4 = time.time()
+    print ("yinfft took: %.2fms" % ((t4-t3) * 1000.))
+
+    return yin, yinfast, yintapered, yinfft
+
+def plot_all(yin, yinfast, yintapered, yinfft):
+    fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey='col')
+
+    axes[0, 0].plot(yin, label='yin')
+    axes[0, 0].plot(yintapered, label='yintapered')
+    axes[0, 0].set_ylim(bottom=0)
+    axes[0, 0].legend()
+    axes[1, 0].plot(yinfast, '-', label='yinfast')
+    axes[1, 0].plot(yinfft, label='yinfft')
+    axes[1, 0].legend()
+
+    axes[0, 1].plot(cumdiff(yin), label='yin')
+    axes[0, 1].plot(cumdiff(yintapered), label='yin tapered')
+    axes[0, 1].set_ylim(bottom=0)
+    axes[0, 1].legend()
+    axes[1, 1].plot(cumdiff(yinfast), '-', label='yinfast')
+    axes[1, 1].plot(cumdiff(yinfft), label='yinfft')
+    axes[1, 1].legend()
+
+    fig.tight_layout()
+
+testfreqs = [441., 800., 10000., 40.]
+
+if len(sys.argv) > 1:
+    testfreqs = map(float,sys.argv[1:])
+
+for f in testfreqs:
+    print ("Comparing yin implementations for sine wave at %.fHz" % f)
+    samplerate = 44100.
+    win_s = 4096
+
+    x = np.cos(2.*np.pi * np.arange(win_s) * f / samplerate)
+
+    n_times = 1#00
+    for n in range(n_times):
+        yin, yinfast, yinfftslow, yinfft = compute_all(x)
+    if 0: # plot difference
+        plt.plot(yin-yinfast)
+        plt.tight_layout()
+        plt.show()
+    if 1:
+        plt.plot(yinfftslow-yinfft)
+        plt.tight_layout()
+        plt.show()
+    plot_all(yin, yinfast, yinfftslow, yinfft)
+plt.show()
--- a/python/ext/aubio-types.h
+++ b/python/ext/aubio-types.h
@@ -27,7 +27,7 @@
 #ifdef USE_LOCAL_AUBIO
 #include "aubio.h"
 #else
-#include "aubio/aubio.h"
+#include <aubio/aubio.h>
 #endif
 
 #define Py_default_vector_length 1024
@@ -44,6 +44,14 @@
 #define AUBIO_NPY_SMPL NPY_FLOAT
 #define AUBIO_NPY_SMPL_STR "float32"
 #define AUBIO_NPY_SMPL_CHR "f"
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAX_PATH
+#define PATH_MAX MAX_PATH
+#else
+#define PATH_MAX 1024
+#endif
 #endif
 
 // compat with Python < 2.6
--- a/python/ext/aubiomodule.c
+++ b/python/ext/aubiomodule.c
@@ -2,77 +2,202 @@
 #include "aubio-types.h"
 #include "py-musicutils.h"
 
+// this dummy macro is used to convince windows that a string passed as -D flag
+// is just that, a string, and not a double.
+#define REDEFINESTRING(x) #x
+#define DEFINEDSTRING(x) REDEFINESTRING(x)
+
 static char aubio_module_doc[] = "Python module for the aubio library";
 
 static char Py_alpha_norm_doc[] = ""
-"alpha_norm(fvec, integer) -> float\n"
+"alpha_norm(vec, alpha)\n"
 "\n"
-"Compute alpha normalisation factor on vector, given alpha\n"
+"Compute `alpha` normalisation factor of vector `vec`.\n"
 "\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector\n"
+"alpha : float\n"
+"   norm factor\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   p-norm of the input vector, where `p=alpha`\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> b = alpha_norm(a, 9)";
+">>> a = aubio.fvec(np.arange(10)); alpha = 2\n"
+">>> aubio.alpha_norm(a, alpha), (sum(a**alpha)/len(a))**(1./alpha)\n"
+"(5.338539123535156, 5.338539126015656)\n"
+"\n"
+"Note\n"
+"----\n"
+"Computed as:\n"
+"\n"
+".. math::\n"
+"  l_{\\alpha} = \n"
+"       \\|\\frac{\\sum_{n=0}^{N-1}{{x_n}^{\\alpha}}}{N}\\|^{1/\\alpha}\n"
+"";
 
 static char Py_bintomidi_doc[] = ""
-"bintomidi(float, samplerate = integer, fftsize = integer) -> float\n"
+"bintomidi(fftbin, samplerate, fftsize)\n"
 "\n"
-"Convert bin (float) to midi (float), given the sampling rate and the FFT size\n"
+"Convert FFT bin to frequency in midi note, given the sampling rate\n"
+"and the size of the FFT.\n"
 "\n"
+"Parameters\n"
+"----------\n"
+"fftbin : float\n"
+"   input frequency bin\n"
+"samplerate : float\n"
+"   sampling rate of the signal\n"
+"fftsize : float\n"
+"   size of the FFT\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   Frequency converted to midi note.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> midi = bintomidi(float, samplerate = 44100, fftsize = 1024)";
+">>> aubio.bintomidi(10, 44100, 1024)\n"
+"68.62871551513672\n"
+"";
 
 static char Py_miditobin_doc[] = ""
-"miditobin(float, samplerate = integer, fftsize = integer) -> float\n"
+"miditobin(midi, samplerate, fftsize)\n"
 "\n"
-"Convert midi (float) to bin (float), given the sampling rate and the FFT size\n"
+"Convert frequency in midi note to FFT bin, given the sampling rate\n"
+"and the size of the FFT.\n"
 "\n"
-"Example\n"
+"Parameters\n"
+"----------\n"
+"midi : float\n"
+"   input frequency, in midi note\n"
+"samplerate : float\n"
+"   sampling rate of the signal\n"
+"fftsize : float\n"
+"   size of the FFT\n"
+"\n"
+"Returns\n"
 "-------\n"
+"float\n"
+"   Frequency converted to FFT bin.\n"
 "\n"
-">>> bin = miditobin(midi, samplerate = 44100, fftsize = 1024)";
+"Examples\n"
+"--------\n"
+"\n"
+">>> aubio.miditobin(69, 44100, 1024)\n"
+"10.216779708862305\n"
+">>> aubio.miditobin(75.08, 32000, 512)\n"
+"10.002175331115723\n"
+"";
 
 static char Py_bintofreq_doc[] = ""
-"bintofreq(float, samplerate = integer, fftsize = integer) -> float\n"
+"bintofreq(fftbin, samplerate, fftsize)\n"
 "\n"
-"Convert bin number (float) in frequency (Hz), given the sampling rate and the FFT size\n"
+"Convert FFT bin to frequency in Hz, given the sampling rate\n"
+"and the size of the FFT.\n"
 "\n"
+"Parameters\n"
+"----------\n"
+"fftbin : float\n"
+"   input frequency bin\n"
+"samplerate : float\n"
+"   sampling rate of the signal\n"
+"fftsize : float\n"
+"   size of the FFT\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   Frequency converted to Hz.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> freq = bintofreq(bin, samplerate = 44100, fftsize = 1024)";
+">>> aubio.bintofreq(10, 44100, 1024)\n"
+"430.6640625\n"
+"";
 
 static char Py_freqtobin_doc[] = ""
-"freqtobin(float, samplerate = integer, fftsize = integer) -> float\n"
+"freqtobin(freq, samplerate, fftsize)\n"
 "\n"
-"Convert frequency (Hz) in bin number (float), given the sampling rate and the FFT size\n"
+"Convert frequency in Hz to FFT bin, given the sampling rate\n"
+"and the size of the FFT.\n"
 "\n"
-"Example\n"
+"Parameters\n"
+"----------\n"
+"midi : float\n"
+"   input frequency, in midi note\n"
+"samplerate : float\n"
+"   sampling rate of the signal\n"
+"fftsize : float\n"
+"   size of the FFT\n"
+"\n"
+"Returns\n"
 "-------\n"
+"float\n"
+"   Frequency converted to FFT bin.\n"
 "\n"
-">>> bin = freqtobin(freq, samplerate = 44100, fftsize = 1024)";
+"Examples\n"
+"--------\n"
+"\n"
+">>> aubio.freqtobin(440, 44100, 1024)\n"
+"10.216779708862305\n"
+"";
 
 static char Py_zero_crossing_rate_doc[] = ""
-"zero_crossing_rate(fvec) -> float\n"
+"zero_crossing_rate(vec)\n"
 "\n"
-"Compute Zero crossing rate of a vector\n"
+"Compute zero-crossing rate of `vec`.\n"
 "\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   Zero-crossing rate.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> z = zero_crossing_rate(a)";
+">>> a = np.linspace(-1., 1., 1000, dtype=aubio.float_type)\n"
+">>> aubio.zero_crossing_rate(a), 1/1000\n"
+"(0.0010000000474974513, 0.001)\n"
+"";
 
 static char Py_min_removal_doc[] = ""
-"min_removal(fvec) -> float\n"
+"min_removal(vec)\n"
 "\n"
-"Remove the minimum value of a vector, in-place modification\n"
+"Remove the minimum value of a vector to each of its element.\n"
 "\n"
+"Modifies the input vector in-place and returns a reference to it.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector\n"
+"\n"
+"Returns\n"
+"-------\n"
+"fvec\n"
+"   modified input vector\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> min_removal(a)";
+">>> aubio.min_removal(aubio.fvec(np.arange(1,4)))\n"
+"array([0., 1., 2.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
+"";
 
 extern void add_ufuncs ( PyObject *m );
 extern int generated_types_ready(void);
@@ -112,7 +237,9 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args,
+        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+        &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -127,7 +254,9 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args,
+        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+        &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -142,7 +271,9 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args,
+        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+        &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -157,7 +288,9 @@
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args,
+        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+        &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -237,6 +370,12 @@
   {"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},
+  {"shift", Py_aubio_shift, METH_VARARGS, Py_aubio_shift_doc},
+  {"ishift", Py_aubio_ishift, METH_VARARGS, Py_aubio_ishift_doc},
+  {"hztomel", Py_aubio_hztomel, METH_VARARGS|METH_KEYWORDS, Py_aubio_hztomel_doc},
+  {"meltohz", Py_aubio_meltohz, METH_VARARGS|METH_KEYWORDS, Py_aubio_meltohz_doc},
+  {"hztomel_htk", Py_aubio_hztomel_htk, METH_VARARGS, Py_aubio_hztomel_htk_doc},
+  {"meltohz_htk", Py_aubio_meltohz_htk, METH_VARARGS, Py_aubio_meltohz_htk_doc},
   {NULL, NULL, 0, NULL} /* Sentinel */
 };
 
@@ -323,6 +462,7 @@
   PyModule_AddObject (m, "sink", (PyObject *) & Py_sinkType);
 
   PyModule_AddStringConstant(m, "float_type", AUBIO_NPY_SMPL_STR);
+  PyModule_AddStringConstant(m, "__version__", DEFINEDSTRING(AUBIO_VERSION));
 
   // add generated objects
   add_generated_objects(m);
--- a/python/ext/py-cvec.c
+++ b/python/ext/py-cvec.c
@@ -19,7 +19,37 @@
   uint_t length;
 } Py_cvec;
 
-static char Py_cvec_doc[] = "cvec object";
+static char Py_cvec_doc[] = ""
+"cvec(size)\n"
+"\n"
+"A container holding spectral data.\n"
+"\n"
+"Create one `cvec` to store the spectral information of a window\n"
+"of `size` points. The data will be stored  in two vectors,\n"
+":attr:`phas` and :attr:`norm`, each of shape (:attr:`length`,),\n"
+"with `length = size // 2 + 1`.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"size: int\n"
+"   Size of spectrum to create.\n"
+"\n"
+"Examples\n"
+"--------\n"
+">>> c = aubio.cvec(1024)\n"
+">>> c\n"
+"aubio cvec of 513 elements\n"
+">>> c.length\n"
+"513\n"
+">>> c.norm.dtype, c.phas.dtype\n"
+"(dtype('float32'), dtype('float32'))\n"
+">>> c.norm.shape, c.phas.shape\n"
+"((513,), (513,))\n"
+"\n"
+"See Also\n"
+"--------\n"
+"fvec, fft, pvoc\n"
+"";
 
 
 PyObject *
@@ -142,14 +172,14 @@
 {
   npy_intp length;
   if (!PyAubio_IsValidVector(input)) {
-    return 1;
+    return -1;
   }
   length = PyArray_SIZE ((PyArrayObject *)input);
   if (length != vec->length) {
     PyErr_Format (PyExc_ValueError,
-        "input array has length %ld, but cvec has length %d", length,
+        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
         vec->length);
-    return 1;
+    return -1;
   }
 
   Py_XDECREF(vec->norm);
@@ -163,14 +193,14 @@
 {
   npy_intp length;
   if (!PyAubio_IsValidVector(input)) {
-    return 1;
+    return -1;
   }
   length = PyArray_SIZE ((PyArrayObject *)input);
   if (length != vec->length) {
     PyErr_Format (PyExc_ValueError,
-        "input array has length %ld, but cvec has length %d", length,
+        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
         vec->length);
-    return 1;
+    return -1;
   }
 
   Py_XDECREF(vec->phas);
@@ -182,7 +212,7 @@
 static PyMemberDef Py_cvec_members[] = {
   // TODO remove READONLY flag and define getter/setter
   {"length", T_INT, offsetof (Py_cvec, length), READONLY,
-      "length attribute"},
+      "int: Length of `norm` and `phas` vectors."},
   {NULL}                        /* Sentinel */
 };
 
@@ -191,11 +221,11 @@
 };
 
 static PyGetSetDef Py_cvec_getseters[] = {
-  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
-      "Numpy vector of shape (length,) containing the magnitude",
+  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm,
+      "numpy.ndarray: Vector of shape `(length,)` containing the magnitude.",
       NULL},
-  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
-      "Numpy vector of shape (length,) containing the phase",
+  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas,
+      "numpy.ndarray: Vector of shape `(length,)` containing the phase.",
       NULL},
   {NULL} /* sentinel */
 };
--- a/python/ext/py-filterbank.c
+++ b/python/ext/py-filterbank.c
@@ -94,7 +94,7 @@
 
   if (self->vec.length != self->win_s / 2 + 1) {
     PyErr_Format(PyExc_ValueError,
-                 "input cvec has length %d, but fft expects length %d",
+                 "input cvec has length %d, but filterbank expects length %d",
                  self->vec.length, self->win_s / 2 + 1);
     return NULL;
   }
@@ -122,8 +122,8 @@
   uint_t err = 0;
 
   PyObject *input;
-  uint_t samplerate;
-  if (!PyArg_ParseTuple (args, "OI", &input, &samplerate)) {
+  smpl_t samplerate;
+  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR, &input, &samplerate)) {
     return NULL;
   }
 
@@ -138,8 +138,14 @@
   err = aubio_filterbank_set_triangle_bands (self->o,
       &(self->freqs), samplerate);
   if (err > 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to A-weighting");
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError, "error running set_triangle_bands");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
     return NULL;
   }
   Py_RETURN_NONE;
@@ -150,15 +156,21 @@
 {
   uint_t err = 0;
 
-  uint_t samplerate;
-  if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+  smpl_t samplerate;
+  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &samplerate)) {
     return NULL;
   }
 
   err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
   if (err > 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to A-weighting");
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs_slaney");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
     return NULL;
   }
   Py_RETURN_NONE;
@@ -165,6 +177,64 @@
 }
 
 static PyObject *
+Py_filterbank_set_mel_coeffs (Py_filterbank * self, PyObject *args)
+{
+  uint_t err = 0;
+
+  smpl_t samplerate;
+  smpl_t freq_min;
+  smpl_t freq_max;
+  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR
+        AUBIO_NPY_SMPL_CHR, &samplerate, &freq_min, &freq_max)) {
+    return NULL;
+  }
+
+  err = aubio_filterbank_set_mel_coeffs (self->o, samplerate,
+      freq_min, freq_max);
+  if (err > 0) {
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filterbank_set_mel_coeffs_htk (Py_filterbank * self, PyObject *args)
+{
+  uint_t err = 0;
+
+  smpl_t samplerate;
+  smpl_t freq_min;
+  smpl_t freq_max;
+  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR
+        AUBIO_NPY_SMPL_CHR, &samplerate, &freq_min, &freq_max)) {
+    return NULL;
+  }
+
+  err = aubio_filterbank_set_mel_coeffs_htk (self->o, samplerate,
+      freq_min, freq_max);
+  if (err > 0) {
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs_htk");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject *
 Py_filterbank_set_coeffs (Py_filterbank * self, PyObject *args)
 {
   uint_t err = 0;
@@ -195,15 +265,69 @@
       aubio_filterbank_get_coeffs (self->o) );
 }
 
+static PyObject *
+Py_filterbank_set_power(Py_filterbank *self, PyObject *args)
+{
+  smpl_t power;
+
+  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &power)) {
+    return NULL;
+  }
+  if(aubio_filterbank_set_power (self->o, power)) {
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError,
+          "error running filterbank.set_power");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filterbank_set_norm(Py_filterbank *self, PyObject *args)
+{
+  smpl_t norm;
+
+  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &norm)) {
+    return NULL;
+  }
+  if(aubio_filterbank_set_norm (self->o, norm)) {
+    if (PyErr_Occurred() == NULL) {
+      PyErr_SetString (PyExc_ValueError,
+          "error running filterbank.set_power");
+    } else {
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
 static PyMethodDef Py_filterbank_methods[] = {
   {"set_triangle_bands", (PyCFunction) Py_filterbank_set_triangle_bands,
     METH_VARARGS, "set coefficients of filterbanks"},
   {"set_mel_coeffs_slaney", (PyCFunction) Py_filterbank_set_mel_coeffs_slaney,
     METH_VARARGS, "set coefficients of filterbank as in Auditory Toolbox"},
+  {"set_mel_coeffs", (PyCFunction) Py_filterbank_set_mel_coeffs,
+    METH_VARARGS, "set coefficients of filterbank to linearly spaced mel scale"},
+  {"set_mel_coeffs_htk", (PyCFunction) Py_filterbank_set_mel_coeffs_htk,
+    METH_VARARGS, "set coefficients of filterbank to linearly spaced mel scale"},
   {"get_coeffs", (PyCFunction) Py_filterbank_get_coeffs,
     METH_NOARGS, "get coefficients of filterbank"},
   {"set_coeffs", (PyCFunction) Py_filterbank_set_coeffs,
     METH_VARARGS, "set coefficients of filterbank"},
+  {"set_power", (PyCFunction) Py_filterbank_set_power,
+    METH_VARARGS, "set power applied to filterbank input spectrum"},
+  {"set_norm", (PyCFunction) Py_filterbank_set_norm,
+    METH_VARARGS, "set norm applied to filterbank input spectrum"},
   {NULL}
 };
 
--- a/python/ext/py-musicutils.c
+++ b/python/ext/py-musicutils.c
@@ -133,3 +133,105 @@
 
   return level_detection;
 }
+
+PyObject *
+Py_aubio_shift(PyObject *self, PyObject *args)
+{
+  PyObject *input;
+  fvec_t vec;
+
+  if (!PyArg_ParseTuple (args, "O:shift", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
+    return NULL;
+  }
+
+  fvec_shift(&vec);
+
+  //Py_RETURN_NONE;
+  return (PyObject *) PyAubio_CFvecToArray(&vec);
+}
+
+PyObject *
+Py_aubio_ishift(PyObject *self, PyObject *args)
+{
+  PyObject *input;
+  fvec_t vec;
+
+  if (!PyArg_ParseTuple (args, "O:shift", &input)) {
+    return NULL;
+  }
+
+  if (input == NULL) {
+    return NULL;
+  }
+
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
+    return NULL;
+  }
+
+  fvec_ishift(&vec);
+
+  //Py_RETURN_NONE;
+  return (PyObject *) PyAubio_CFvecToArray(&vec);
+}
+
+PyObject*
+Py_aubio_hztomel(PyObject *self, PyObject *args, PyObject *kwds)
+{
+  smpl_t v;
+  PyObject *htk = NULL;
+  static char *kwlist[] = {"f", "htk", NULL};
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, AUBIO_NPY_SMPL_CHR "|O",
+        kwlist, &v, &htk))
+  {
+    return NULL;
+  }
+  if (htk != NULL && PyObject_IsTrue(htk) == 1)
+    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel_htk(v));
+  else
+    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel(v));
+}
+
+PyObject*
+Py_aubio_meltohz(PyObject *self, PyObject *args, PyObject *kwds)
+{
+  smpl_t v;
+  PyObject *htk = NULL;
+  static char *kwlist[] = {"m", "htk", NULL};
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, AUBIO_NPY_SMPL_CHR "|O",
+        kwlist, &v, &htk))
+  {
+    return NULL;
+  }
+  if (htk != NULL && PyObject_IsTrue(htk) == 1)
+    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz_htk(v));
+  else
+    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz(v));
+}
+
+PyObject*
+Py_aubio_hztomel_htk(PyObject *self, PyObject *args)
+{
+  smpl_t v;
+  if (!PyArg_ParseTuple(args, AUBIO_NPY_SMPL_CHR, &v)) {
+    return NULL;
+  }
+  return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel_htk(v));
+}
+
+PyObject*
+Py_aubio_meltohz_htk(PyObject *self, PyObject *args)
+{
+  smpl_t v;
+  if (!PyArg_ParseTuple(args, AUBIO_NPY_SMPL_CHR, &v)) {
+    return NULL;
+  }
+  return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz_htk(v));
+}
--- a/python/ext/py-musicutils.h
+++ b/python/ext/py-musicutils.h
@@ -2,73 +2,370 @@
 #define PY_AUBIO_MUSICUTILS_H
 
 static char Py_aubio_window_doc[] = ""
-"window(string, integer) -> fvec\n"
+"window(window_type, size)\n"
 "\n"
-"Create a window\n"
+"Create a window of length `size`. `window_type` should be one\n"
+"of the following:\n"
 "\n"
-"Example\n"
+"- `default` (same as `hanningz`).\n"
+"- `ones`\n"
+"- `rectangle`\n"
+"- `hamming`\n"
+"- `hanning`\n"
+"- `hanningz` [1]_\n"
+"- `blackman`\n"
+"- `blackman_harris`\n"
+"- `gaussian`\n"
+"- `welch`\n"
+"- `parzen`\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"window_type : str\n"
+"   Type of window.\n"
+"size : int\n"
+"   Length of window.\n"
+"\n"
+"Returns\n"
 "-------\n"
+"fvec\n"
+"   Array of shape `(length,)` containing the new window.\n"
 "\n"
-">>> window('hanningz', 1024)\n"
+"See Also\n"
+"--------\n"
+"pvoc, fft\n"
+"\n"
+"Examples\n"
+"--------\n"
+"Compute a zero-phase Hann window on `1024` points:\n"
+"\n"
+">>> aubio.window('hanningz', 1024)\n"
 "array([  0.00000000e+00,   9.41753387e-06,   3.76403332e-05, ...,\n"
-"         8.46982002e-05,   3.76403332e-05,   9.41753387e-06], dtype=float32)";
+"         8.46982002e-05,   3.76403332e-05,   9.41753387e-06], dtype=float32)\n"
+"\n"
+"Plot different window types with `matplotlib <https://matplotlib.org/>`_:\n"
+"\n"
+">>> import matplotlib.pyplot as plt\n"
+">>> modes = ['default', 'ones', 'rectangle', 'hamming', 'hanning',\n"
+"...          'hanningz', 'blackman', 'blackman_harris', 'gaussian',\n"
+"...          'welch', 'parzen']; n = 2048\n"
+">>> for m in modes: plt.plot(aubio.window(m, n), label=m)\n"
+"...\n"
+">>> plt.legend(); plt.show()\n"
+"\n"
+"Note\n"
+"----\n"
+"The following examples contain the equivalent source code to compute\n"
+"each type of window with `NumPy <https://numpy.org>`_:\n"
+"\n"
+">>> n = 1024; x = np.arange(n, dtype=aubio.float_type)\n"
+">>> ones = np.ones(n).astype(aubio.float_type)\n"
+">>> rectangle = 0.5 * ones\n"
+">>> hanning = 0.5 - 0.5 * np.cos(2 * np.pi * x / n)\n"
+">>> hanningz = 0.5 * (1 - np.cos(2 * np.pi * x / n))\n"
+">>> hamming = 0.54 - 0.46 * np.cos(2.*np.pi * x / (n - 1))\n"
+">>> blackman = 0.42 \\\n"
+"...          - 0.50 * np.cos(2 * np.pi * x / (n - 1)) \\\n"
+"...          + 0.08 * np.cos(4 * np.pi * x / (n - 1))\n"
+">>> blackman_harris = 0.35875 \\\n"
+"...       - 0.48829 * np.cos(2 * np.pi * x / (n - 1)) \\\n"
+"...       + 0.14128 * np.cos(4 * np.pi * x / (n - 1)) \\\n"
+"...       + 0.01168 * np.cos(6 * np.pi * x / (n - 1))\n"
+">>> gaussian = np.exp( - 0.5 * ((x - 0.5 * (n - 1)) \\\n"
+"...                            / (0.25 * (n - 1)) )**2 )\n"
+">>> welch = 1 - ((2 * x - n) / (n + 1))**2\n"
+">>> parzen = 1 - np.abs((2 * x - n) / (n + 1))\n"
+">>> default = hanningz\n"
+"References\n"
+"----------\n"
+#if 0
+"`Window function <https://en.wikipedia.org/wiki/Window_function>`_ on\n"
+"Wikipedia.\n"
+"\n"
+#endif
+".. [1] Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional\n"
+"   (?) implementations of a phase vocoder: the tricks of the trade.\n"
+"   In *Proceedings of the International Conference on Digital Audio\n"
+"   Effects* (DAFx-00), pages 37–44, University of Verona, Italy, 2000.\n"
+"   (`online version <"
+"https://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf"
+">`_).\n"
+"";
 
 PyObject * Py_aubio_window(PyObject *self, PyObject *args);
 
 static char Py_aubio_level_lin_doc[] = ""
-"level_lin(fvec) -> fvec\n"
+"level_lin(x)\n"
 "\n"
-"Compute sound level on a linear scale.\n"
+"Compute sound pressure level of `x`, on a linear scale.\n"
 "\n"
-"This gives the average of the square amplitudes.\n"
+"Parameters\n"
+"----------\n"
+"x : fvec\n"
+"   input vector\n"
 "\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   Linear level of `x`.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> level_Lin(numpy.ones(1024))\n"
-"1.0";
+">>> aubio.level_lin(aubio.fvec(numpy.ones(1024)))\n"
+"1.0\n"
+"\n"
+"Note\n"
+"----\n"
+"Computed as the average of the squared amplitudes:\n"
+"\n"
+".. math:: L = \\frac {\\sum_{n=0}^{N-1} {x_n}^2} {N}\n"
+"\n"
+"See Also\n"
+"--------\n"
+"db_spl, silence_detection, level_detection\n"
+"";
 
 PyObject * Py_aubio_level_lin(PyObject *self, PyObject *args);
 
 static char Py_aubio_db_spl_doc[] = ""
-"Compute sound pressure level (SPL) in dB\n"
+"db_spl(x)\n"
 "\n"
-"This quantity is often wrongly called 'loudness'.\n"
+"Compute Sound Pressure Level (SPL) of `x`, in dB.\n"
 "\n"
-"This gives ten times the log10 of the average of the square amplitudes.\n"
+"Parameters\n"
+"----------\n"
+"x : fvec\n"
+"   input vector\n"
 "\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   Level of `x`, in dB SPL.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> db_spl(numpy.ones(1024))\n"
-"1.0";
+">>> aubio.db_spl(aubio.fvec(np.ones(1024)))\n"
+"1.0\n"
+">>> aubio.db_spl(0.7*aubio.fvec(np.ones(32)))\n"
+"-3.098040819168091\n"
+"\n"
+"Note\n"
+"----\n"
+"Computed as `log10` of :py:func:`level_lin`:\n"
+"\n"
+".. math::\n"
+"\n"
+"   {SPL}_{dB} = log10{\\frac {\\sum_{n=0}^{N-1}{x_n}^2} {N}}\n"
+"\n"
+"This quantity is often incorrectly called 'loudness'.\n"
+"\n"
+"See Also\n"
+"--------\n"
+"level_lin, silence_detection, level_detection\n"
+"";
 
 PyObject * Py_aubio_db_spl(PyObject *self, PyObject *args);
 
 static char Py_aubio_silence_detection_doc[] = ""
-"Check if buffer level in dB SPL is under a given threshold\n"
+"silence_detection(vec, level)\n"
 "\n"
-"Return 0 if level is under the given threshold, 1 otherwise.\n"
+"Check if level of `vec`, in dB SPL, is under a given threshold.\n"
 "\n"
-"Example\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector\n"
+"level : float\n"
+"   level threshold, in dB SPL\n"
+"\n"
+"Returns\n"
 "-------\n"
+"int\n"
+"   `1` if level of `vec`, in dB SPL, is under `level`,\n"
+"   `0` otherwise.\n"
 "\n"
-">>> import numpy\n"""
-">>> silence_detection(numpy.ones(1024, dtype=\"float32\"), -80)\n"
-"0";
+"Examples\n"
+"--------\n"
+"\n"
+">>> aubio.silence_detection(aubio.fvec(32), -100.)\n"
+"1\n"
+">>> aubio.silence_detection(aubio.fvec(np.ones(32)), 0.)\n"
+"0\n"
+"\n"
+"See Also\n"
+"--------\n"
+"level_detection, db_spl, level_lin\n"
+"";
 
 PyObject * Py_aubio_silence_detection(PyObject *self, PyObject *args);
 
 static char Py_aubio_level_detection_doc[] = ""
-"Get buffer level in dB SPL if over a given threshold, 1. otherwise.\n"
+"level_detection(vec, level)\n"
 "\n"
+"Check if `vec` is above threshold `level`, in dB SPL.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector\n"
+"level : float\n"
+"   level threshold, in dB SPL\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   `1.0` if level of `vec` in dB SPL is under `level`,\n"
+"   `db_spl(vec)` otherwise.\n"
+"\n"
 "Example\n"
 "-------\n"
 "\n"
-">>> import numpy\n"""
-">>> level_detection(0.7*numpy.ones(1024, dtype=\"float32\"), -80)\n"
-"0";
+">>> aubio.level_detection(0.7*aubio.fvec(np.ones(1024)), -3.)\n"
+"1.0\n"
+">>> aubio.level_detection(0.7*aubio.fvec(np.ones(1024)), -4.)\n"
+"-3.0980708599090576\n"
+"\n"
+"See Also\n"
+"--------\n"
+"silence_detection, db_spl, level_lin\n"
+"";
 
 PyObject * Py_aubio_level_detection(PyObject *self, PyObject *args);
+
+static char Py_aubio_shift_doc[] = ""
+"shift(vec)\n"
+"\n"
+"Swap left and right partitions of a vector, in-place.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector to shift\n"
+"\n"
+"Returns\n"
+"-------\n"
+"fvec\n"
+"   The swapped vector.\n"
+"\n"
+"Notes\n"
+"-----\n"
+"The input vector is also modified.\n"
+"\n"
+"For a vector of length N, the partition is split at index N - N//2.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> aubio.shift(aubio.fvec(np.arange(3)))\n"
+"array([2., 0., 1.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
+"\n"
+"See Also\n"
+"--------\n"
+"ishift\n"
+"";
+PyObject * Py_aubio_shift(PyObject *self, PyObject *args);
+
+static char Py_aubio_ishift_doc[] = ""
+"ishift(vec)\n"
+"\n"
+"Swap right and left partitions of a vector, in-place.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector to shift\n"
+"\n"
+"Returns\n"
+"-------\n"
+"fvec\n"
+"   The swapped vector.\n"
+"\n"
+"Notes\n"
+"-----\n"
+"The input vector is also modified.\n"
+"\n"
+"Unlike with :py:func:`shift`, the partition is split at index N//2.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> aubio.ishift(aubio.fvec(np.arange(3)))\n"
+"array([1., 2., 0.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
+"\n"
+"See Also\n"
+"--------\n"
+"shift\n"
+"";
+PyObject * Py_aubio_ishift(PyObject *self, PyObject *args);
+
+static char Py_aubio_hztomel_doc[] = ""
+"hztomel(f, htk=False)\n"
+"\n"
+"Convert a scalar from frequency to mel scale.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"m : float\n"
+"   input frequency, in Hz\n"
+"htk : bool\n"
+"   if `True`, use Htk mel scale instead of Slaney.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   output mel\n"
+"\n"
+"See Also\n"
+"--------\n"
+"meltohz\n"
+"";
+PyObject * Py_aubio_hztomel(PyObject *self, PyObject *args);
+
+static char Py_aubio_meltohz_doc[] = ""
+"meltohz(m, htk=False)\n"
+"\n"
+"Convert a scalar from mel scale to frequency.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"m : float\n"
+"   input mel\n"
+"htk : bool\n"
+"   if `True`, use Htk mel scale instead of Slaney.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"float\n"
+"   output frequency, in Hz\n"
+"\n"
+"See Also\n"
+"--------\n"
+"hztomel\n"
+"";
+PyObject * Py_aubio_meltohz(PyObject *self, PyObject *args);
+
+static char Py_aubio_hztomel_htk_doc[] = ""
+"hztomel_htk(m)\n"
+"\n"
+"Same as `hztomel(m, htk=True)`\n"
+"\n"
+"See Also\n"
+"--------\n"
+"hztomel\n"
+"";
+PyObject * Py_aubio_hztomel_htk(PyObject *self, PyObject *args);
+
+static char Py_aubio_meltohz_htk_doc[] = ""
+"meltohz_htk(m)\n"
+"\n"
+"Same as `meltohz(m, htk=True)`\n"
+"\n"
+"See Also\n"
+"--------\n"
+"meltohz\n"
+"";
+PyObject * Py_aubio_meltohz_htk(PyObject *self, PyObject *args);
 
 #endif /* PY_AUBIO_MUSICUTILS_H */
--- a/python/ext/py-phasevoc.c
+++ b/python/ext/py-phasevoc.c
@@ -1,7 +1,59 @@
 #include "aubio-types.h"
 
-static char Py_pvoc_doc[] = "pvoc object";
+static char Py_pvoc_doc[] = ""
+"pvoc(win_s=512, hop_s=256)\n"
+"\n"
+"Phase vocoder.\n"
+"\n"
+"`pvoc` creates callable object implements a phase vocoder [1]_,\n"
+"using the tricks detailed in [2]_.\n"
+"\n"
+"The call function takes one input of type `fvec` and of size\n"
+"`hop_s`, and returns a `cvec` of length `win_s//2+1`.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"win_s : int\n"
+"  number of channels in the phase-vocoder.\n"
+"hop_s : int\n"
+"  number of samples expected between each call\n"
+"\n"
+"Examples\n"
+"--------\n"
+">>> x = aubio.fvec(256)\n"
+">>> pv = aubio.pvoc(512, 256)\n"
+">>> pv(x)\n"
+"aubio cvec of 257 elements\n"
+"\n"
+"Default values for hop_s and win_s are provided:\n"
+"\n"
+">>> pv = aubio.pvoc()\n"
+">>> pv.win_s, pv.hop_s\n"
+"512, 256\n"
+"\n"
+"A `cvec` can be resynthesised using `rdo()`:\n"
+"\n"
+">>> pv = aubio.pvoc(512, 256)\n"
+">>> y = aubio.cvec(512)\n"
+">>> x_reconstructed = pv.rdo(y)\n"
+">>> x_reconstructed.shape\n"
+"(256,)\n"
+"\n"
+"References\n"
+"----------\n"
+".. [1] James A. Moorer. The use of the phase vocoder in computer music\n"
+"   applications. `Journal of the Audio Engineering Society`,\n"
+"   26(1/2):42–45, 1978.\n"
+".. [2] Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional\n"
+"   (?) implementations of a phase vocoder: the tricks of the trade.\n"
+"   In `Proceedings of the International Conference on Digital Audio\n"
+"   Effects` (DAFx-00), pages 37–44, University of Verona, Italy, 2000.\n"
+"   (`online version <"
+"https://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf"
+">`_).\n"
+"";
 
+
 typedef struct
 {
   PyObject_HEAD
@@ -38,10 +90,6 @@
   self->win_s = Py_default_vector_length;
   self->hop_s = Py_default_vector_length/2;
 
-  if (self == NULL) {
-    return NULL;
-  }
-
   if (win_s > 0) {
     self->win_s = win_s;
   } else if (win_s < 0) {
@@ -121,9 +169,11 @@
 
 static PyMemberDef Py_pvoc_members[] = {
   {"win_s", T_INT, offsetof (Py_pvoc, win_s), READONLY,
-    "size of the window"},
+    "int: Size of phase vocoder analysis windows, in samples.\n"
+    ""},
   {"hop_s", T_INT, offsetof (Py_pvoc, hop_s), READONLY,
-    "size of the hop"},
+    "int: Interval between two analysis, in samples.\n"
+    ""},
   { NULL } // sentinel
 };
 
@@ -155,9 +205,67 @@
   return self->routput;
 }
 
+static PyObject *
+Pyaubio_pvoc_set_window (Py_pvoc *self, PyObject *args)
+{
+  uint_t err = 0;
+  char_t *window = NULL;
+
+  if (!PyArg_ParseTuple (args, "s", &window)) {
+    return NULL;
+  }
+  err = aubio_pvoc_set_window (self->o, window);
+
+  if (err > 0) {
+    PyErr_SetString (PyExc_ValueError, "error running aubio_pvoc_set_window");
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
 static PyMethodDef Py_pvoc_methods[] = {
   {"rdo", (PyCFunction) Py_pvoc_rdo, METH_VARARGS,
-    "synthesis of spectral grain"},
+    "rdo(fftgrain)\n"
+    "\n"
+    "Read a new spectral grain and resynthesise the next `hop_s`\n"
+    "output samples.\n"
+    "\n"
+    "Parameters\n"
+    "----------\n"
+    "fftgrain : cvec\n"
+    "    new input `cvec` to synthesize from, should be of size `win_s/2+1`\n"
+    "\n"
+    "Returns\n"
+    "-------\n"
+    "fvec\n"
+    "    re-synthesised output of shape `(hop_s,)`\n"
+    "\n"
+    "Example\n"
+    "-------\n"
+    ">>> pv = aubio.pvoc(2048, 512)\n"
+    ">>> out = pv.rdo(aubio.cvec(2048))\n"
+    ">>> out.shape\n"
+    "(512,)\n"
+    ""},
+  {"set_window", (PyCFunction) Pyaubio_pvoc_set_window, METH_VARARGS,
+    "set_window(window_type)\n"
+    "\n"
+    "Set window function\n"
+    "\n"
+    "Parameters\n"
+    "----------\n"
+    "window_type : str\n"
+    "    the window type to use for this phase vocoder\n"
+    "\n"
+    "Raises\n"
+    "------\n"
+    "ValueError\n"
+    "    If an unknown window type was given.\n"
+    "\n"
+    "See Also\n"
+    "--------\n"
+    "window : create a window.\n"
+    ""},
   {NULL}
 };
 
--- a/python/ext/py-sink.c
+++ b/python/ext/py-sink.c
@@ -12,53 +12,78 @@
 } Py_sink;
 
 static char Py_sink_doc[] = ""
-"  __new__(path, samplerate = 44100, channels = 1)\n"
+"sink(path, samplerate=44100, channels=1)\n"
 "\n"
-"      Create a new sink, opening the given path for writing.\n"
+"Write audio samples to file.\n"
 "\n"
-"      Examples\n"
-"      --------\n"
+"Parameters\n"
+"----------\n"
+"path : str\n"
+"   Pathname of the file to be opened for writing.\n"
+"samplerate : int\n"
+"   Sampling rate of the file, in Hz.\n"
+"channels : int\n"
+"   Number of channels to create the file with.\n"
 "\n"
-"      Create a new sink at 44100Hz, mono:\n"
+"Examples\n"
+"--------\n"
 "\n"
-"      >>> sink('/tmp/t.wav')\n"
+"Create a new sink at 44100Hz, mono:\n"
 "\n"
-"      Create a new sink at 8000Hz, mono:\n"
+">>> snk = aubio.sink('out.wav')\n"
 "\n"
-"      >>> sink('/tmp/t.wav', samplerate = 8000)\n"
+"Create a new sink at 32000Hz, stereo, write 100 samples into it:\n"
 "\n"
-"      Create a new sink at 32000Hz, stereo:\n"
+">>> snk = aubio.sink('out.wav', samplerate=16000, channels=3)\n"
+">>> snk(aubio.fvec(100), 100)\n"
 "\n"
-"      >>> sink('/tmp/t.wav', samplerate = 32000, channels = 2)\n"
+"Open a new sink at 48000Hz, stereo, write `1234` samples into it:\n"
 "\n"
-"      Create a new sink at 32000Hz, 5 channels:\n"
+">>> with aubio.sink('out.wav', samplerate=48000, channels=2) as src:\n"
+"...     snk(aubio.fvec(1024), 1024)\n"
+"...     snk(aubio.fvec(210), 210)\n"
+"...\n"
 "\n"
-"      >>> sink('/tmp/t.wav', channels = 5, samplerate = 32000)\n"
-"\n"
-"  __call__(vec, write)\n"
-"      x(vec,write) <==> x.do(vec, write)\n"
-"\n"
-"      Write vector to sink.\n"
-"\n"
-"      See also\n"
-"      --------\n"
-"      aubio.sink.do\n"
+"See also\n"
+"--------\n"
+"source: read audio samples from a file.\n"
 "\n";
 
 static char Py_sink_do_doc[] = ""
-"x.do(vec, write) <==> x(vec, write)\n"
+"do(vec, write)\n"
 "\n"
-"write monophonic vector to sink";
+"Write a single channel vector to sink.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"vec : fvec\n"
+"   input vector `(n,)` where `n >= 0`.\n"
+"write : int\n"
+"   Number of samples to write.\n"
+"";
 
 static char Py_sink_do_multi_doc[] = ""
-"x.do_multi(mat, write)\n"
+"do_multi(mat, write)\n"
 "\n"
-"write polyphonic vector to sink";
+"Write a matrix containing vectors from multiple channels to sink.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"mat : numpy.ndarray\n"
+"   input matrix of shape `(channels, n)`, where `n >= 0`.\n"
+"write : int\n"
+"   Number of frames to write.\n"
+"";
 
 static char Py_sink_close_doc[] = ""
-"x.close()\n"
+"close()\n"
 "\n"
-"close this sink now";
+"Close this sink now.\n"
+"\n"
+"By default, the sink will be closed before being deleted.\n"
+"Explicitely closing a sink can be useful to control the number\n"
+"of files simultaneously opened.\n"
+"";
 
 static PyObject *
 Py_sink_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
@@ -80,27 +105,20 @@
     return NULL;
   }
 
-  self->uri = "none";
+  self->uri = NULL;
   if (uri != NULL) {
-    self->uri = uri;
+    self->uri = (char_t *)malloc(sizeof(char_t) * (strnlen(uri, PATH_MAX) + 1));
+    strncpy(self->uri, uri, strnlen(uri, PATH_MAX) + 1);
   }
 
   self->samplerate = Py_aubio_default_samplerate;
-  if ((sint_t)samplerate > 0) {
+  if (samplerate != 0) {
     self->samplerate = samplerate;
-  } else if ((sint_t)samplerate < 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "can not use negative value for samplerate");
-    return NULL;
   }
 
   self->channels = 1;
-  if ((sint_t)channels > 0) {
+  if (channels != 0) {
     self->channels = channels;
-  } else if ((sint_t)channels < 0) {
-    PyErr_SetString (PyExc_ValueError,
-        "can not use negative or null value for channels");
-    return NULL;
   }
 
   return (PyObject *) self;
@@ -109,17 +127,20 @@
 static int
 Py_sink_init (Py_sink * self, PyObject * args, PyObject * kwds)
 {
-  if (self->channels == 1) {
-    self->o = new_aubio_sink ( self->uri, self->samplerate );
-  } else {
-    self->o = new_aubio_sink ( self->uri, 0 );
-    aubio_sink_preset_channels ( self->o, self->channels );
-    aubio_sink_preset_samplerate ( self->o, self->samplerate );
-  }
+  self->o = new_aubio_sink ( self->uri, 0 );
   if (self->o == NULL) {
-    PyErr_SetString (PyExc_RuntimeError, "error creating sink with this uri");
+    // error string was set in new_aubio_sink
     return -1;
   }
+  if (aubio_sink_preset_channels(self->o, self->channels) != 0) {
+    // error string was set in aubio_sink_preset_channels
+    return -1;
+  }
+  if (aubio_sink_preset_samplerate(self->o, self->samplerate) != 0) {
+    // error string was set in aubio_sink_preset_samplerate
+    return -1;
+  }
+
   self->samplerate = aubio_sink_get_samplerate ( self->o );
   self->channels = aubio_sink_get_channels ( self->o );
 
@@ -131,6 +152,9 @@
 {
   del_aubio_sink(self->o);
   free(self->mwrite_data.data);
+  if (self->uri) {
+    free(self->uri);
+  }
   Py_TYPE(self)->tp_free((PyObject *) self);
 }
 
@@ -189,11 +213,11 @@
 
 static PyMemberDef Py_sink_members[] = {
   {"uri", T_STRING, offsetof (Py_sink, uri), READONLY,
-    "path at which the sink was created"},
+    "str (read-only): Path at which the sink was created."},
   {"samplerate", T_INT, offsetof (Py_sink, samplerate), READONLY,
-    "samplerate at which the sink was created"},
+    "int (read-only): Samplerate at which the sink was created."},
   {"channels", T_INT, offsetof (Py_sink, channels), READONLY,
-    "number of channels with which the sink was created"},
+    "int (read-only): Number of channels with which the sink was created."},
   { NULL } // sentinel
 };
 
@@ -204,10 +228,25 @@
   Py_RETURN_NONE;
 }
 
+static char Pyaubio_sink_enter_doc[] = "";
+static PyObject* Pyaubio_sink_enter(Py_sink *self, PyObject *unused) {
+  Py_INCREF(self);
+  return (PyObject*)self;
+}
+
+static char Pyaubio_sink_exit_doc[] = "";
+static PyObject* Pyaubio_sink_exit(Py_sink *self, PyObject *unused) {
+  return Pyaubio_sink_close(self, unused);
+}
+
 static PyMethodDef Py_sink_methods[] = {
   {"do", (PyCFunction) Py_sink_do, METH_VARARGS, Py_sink_do_doc},
   {"do_multi", (PyCFunction) Py_sink_do_multi, METH_VARARGS, Py_sink_do_multi_doc},
   {"close", (PyCFunction) Pyaubio_sink_close, METH_NOARGS, Py_sink_close_doc},
+  {"__enter__", (PyCFunction)Pyaubio_sink_enter, METH_NOARGS,
+    Pyaubio_sink_enter_doc},
+  {"__exit__",  (PyCFunction)Pyaubio_sink_exit, METH_VARARGS,
+    Pyaubio_sink_exit_doc},
   {NULL} /* sentinel */
 };
 
--- a/python/ext/py-source.c
+++ b/python/ext/py-source.c
@@ -16,68 +16,316 @@
 } Py_source;
 
 static char Py_source_doc[] = ""
-"   __new__(path, samplerate = 0, hop_size = 512, channels = 1)\n"
+"source(path, samplerate=0, hop_size=512, channels=0)\n"
 "\n"
-"       Create a new source, opening the given path for reading.\n"
+"Read audio samples from a media file.\n"
 "\n"
-"       Examples\n"
-"       --------\n"
+"`source` open the file specified in `path` and creates a callable\n"
+"returning `hop_size` new audio samples at each invocation.\n"
 "\n"
-"       Create a new source, using the original samplerate, with hop_size = 512:\n"
+"If `samplerate=0` (default), the original sampling rate of `path`\n"
+"will be used. Otherwise, the output audio samples will be\n"
+"resampled at the desired sampling-rate.\n"
 "\n"
-"       >>> source('/tmp/t.wav')\n"
+"If `channels=0` (default), the original number of channels\n"
+"in `path` will be used. Otherwise, the output audio samples\n"
+"will be down-mixed or up-mixed to the desired number of\n"
+"channels.\n"
 "\n"
-"       Create a new source, resampling the original to 8000Hz:\n"
+"If `path` is a URL, a remote connection will be attempted to\n"
+"open the resource and stream data from it.\n"
 "\n"
-"       >>> source('/tmp/t.wav', samplerate = 8000)\n"
+"The parameter `hop_size` determines how many samples should be\n"
+"read at each consecutive calls.\n"
 "\n"
-"       Create a new source, resampling it at 32000Hz, hop_size = 32:\n"
+"Parameters\n"
+"----------\n"
+"path : str\n"
+"   pathname (or URL) of the file to be opened for reading\n"
+"samplerate : int, optional\n"
+"   sampling rate of the file\n"
+"hop_size : int, optional\n"
+"   number of samples to be read per iteration\n"
+"channels : int, optional\n"
+"   number of channels of the file\n"
 "\n"
-"       >>> source('/tmp/t.wav', samplerate = 32000, hop_size = 32)\n"
+"Examples\n"
+"--------\n"
+"By default, when only `path` is given, the file will be opened\n"
+"with its original sampling rate and channel:\n"
 "\n"
-"       Create a new source, using its original samplerate:\n"
+">>> src = aubio.source('stereo.wav')\n"
+">>> src.uri, src.samplerate, src.channels, src.duration\n"
+"('stereo.wav', 48000, 2, 86833)\n"
 "\n"
-"       >>> source('/tmp/t.wav', samplerate = 0)\n"
+"A typical loop to read all samples from a local file could\n"
+"look like this:\n"
 "\n"
-"   __call__()\n"
-"       vec, read = x() <==> vec, read = x.do()\n"
+">>> src = aubio.source('stereo.wav')\n"
+">>> total_read = 0\n"
+">>> while True:\n"
+"...     samples, read = src()\n"
+"...     # do something with samples\n"
+"...     total_read += read\n"
+"...     if read < src.hop_size:\n"
+"...         break\n"
+"...\n"
 "\n"
-"       Read vector from source.\n"
+"In a more Pythonic way, it can also look like this:\n"
 "\n"
-"       See also\n"
-"       --------\n"
-"       aubio.source.do\n"
-"\n";
+">>> total_read = 0\n"
+">>> with aubio.source('stereo.wav') as src:\n"
+"...     for frames in src:\n"
+"...         total_read += samples.shape[-1]\n"
+"...\n"
+"\n"
+".. rubric:: Basic interface\n"
+"\n"
+"`source` is a **callable**; its :meth:`__call__` method\n"
+"returns a tuple containing:\n"
+"\n"
+"- a vector of shape `(hop_size,)`, filled with the `read` next\n"
+"  samples available, zero-padded if `read < hop_size`\n"
+"- `read`, an integer indicating the number of samples read\n"
+"\n"
+"To read the first `hop_size` samples from the source, simply call\n"
+"the instance itself, with no argument:\n"
+"\n"
+">>> src = aubio.source('song.ogg')\n"
+">>> samples, read = src()\n"
+">>> samples.shape, read, src.hop_size\n"
+"((512,), 512, 512)\n"
+"\n"
+"The first call returned the slice of samples `[0 : hop_size]`.\n"
+"The next call will return samples `[hop_size: 2*hop_size]`.\n"
+"\n"
+"After several invocations of :meth:`__call__`, when reaching the end\n"
+"of the opened stream, `read` might become less than `hop_size`:\n"
+"\n"
+">>> samples, read = src()\n"
+">>> samples.shape, read\n"
+"((512,), 354)\n"
+"\n"
+"The end of the vector `samples` is filled with zeros.\n"
+"\n"
+"After the end of the stream, `read` will be `0` since no more\n"
+"samples are available:\n"
+"\n"
+">>> samples, read = src()\n"
+">>> samples.shape, read\n"
+"((512,), 0)\n"
+"\n"
+"**Note**: when the source has more than one channels, they\n"
+"are be down-mixed to mono when invoking :meth:`__call__`.\n"
+"To read from each individual channel, see :meth:`__next__`.\n"
+"\n"
+".. rubric:: ``for`` statements\n"
+"\n"
+"The `source` objects are **iterables**. This allows using them\n"
+"directly in a ``for`` loop, which calls :meth:`__next__` until\n"
+"the end of the stream is reached:\n"
+"\n"
+">>> src = aubio.source('stereo.wav')\n"
+">>> for frames in src:\n"
+">>>     print (frames.shape)\n"
+"...\n"
+"(2, 512)\n"
+"(2, 512)\n"
+"(2, 230)\n"
+"\n"
+"**Note**: When `next(self)` is called on a source with multiple\n"
+"channels, an array of shape `(channels, read)` is returned,\n"
+"unlike with :meth:`__call__` which always returns the down-mixed\n"
+"channels.\n"
+"\n"
+"If the file is opened with a single channel, `next(self)` returns\n"
+"an array of shape `(read,)`:\n"
+"\n"
+">>> src = aubio.source('stereo.wav', channels=1)\n"
+">>> next(src).shape\n"
+"(512,)\n"
+"\n"
+".. rubric:: ``with`` statements\n"
+"\n"
+"The `source` objects are **context managers**, which allows using\n"
+"them in ``with`` statements:\n"
+"\n"
+">>> with aubio.source('audiotrack.wav') as source:\n"
+"...     n_frames=0\n"
+"...     for samples in source:\n"
+"...         n_frames += len(samples)\n"
+"...     print('read', n_frames, 'samples in', samples.shape[0], 'channels',\n"
+"...         'from file \"%%s\"' %% source.uri)\n"
+"...\n"
+"read 239334 samples in 2 channels from file \"audiotrack.wav\"\n"
+"\n"
+"The file will be closed before exiting the statement.\n"
+"\n"
+"See also the methods implementing the context manager,\n"
+":meth:`__enter__` and :meth:`__exit__`.\n"
+"\n"
+".. rubric:: Seeking and closing\n"
+"\n"
+"At any time, :meth:`seek` can be used to move to any position in\n"
+"the file. For instance, to rewind to the start of the stream:\n"
+"\n"
+">>> src.seek(0)\n"
+"\n"
+"The opened file will be automatically closed when the object falls\n"
+"out of scope and is scheduled for garbage collection.\n"
+"\n"
+"In some cases, it is useful to manually :meth:`close` a given source,\n"
+"for instance to limit the number of simultaneously opened files:\n"
+"\n"
+">>> src.close()\n"
+"\n"
+".. rubric:: Input formats\n"
+"\n"
+"Depending on how aubio was compiled, :class:`source` may or may not\n"
+"open certain **files format**. Below are some examples that assume\n"
+"support for compressed files and remote urls was compiled in:\n"
+"\n"
+"- open a local file using its original sampling rate and channels,\n"
+"  and with the default hop size:\n"
+"\n"
+">>> s = aubio.source('sample.wav')\n"
+">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
+"('sample.wav', 44100, 2, 512)\n"
+"\n"
+"- open a local compressed audio file, resampling to 32000Hz if needed:\n"
+"\n"
+">>> s = aubio.source('song.mp3', samplerate=32000)\n"
+">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
+"('song.mp3', 32000, 2, 512)\n"
+"\n"
+"- open a local video file, down-mixing and resampling it to 16kHz:\n"
+"\n"
+">>> s = aubio.source('movie.mp4', samplerate=16000, channels=1)\n"
+">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
+"('movie.mp4', 16000, 1, 512)\n"
+"\n"
+"- open a remote resource, with hop_size = 1024:\n"
+"\n"
+">>> s = aubio.source('https://aubio.org/drum.ogg', hop_size=1024)\n"
+">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
+"('https://aubio.org/drum.ogg', 48000, 2, 1024)\n"
+"\n"
+"See Also\n"
+"--------\n"
+"sink: write audio samples to a file.\n"
+"";
 
 static char Py_source_get_samplerate_doc[] = ""
-"x.get_samplerate() -> source samplerate\n"
+"get_samplerate()\n"
 "\n"
-"Get samplerate of source.";
+"Get sampling rate of source.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"int\n"
+"    Sampling rate, in Hz.\n"
+"";
 
 static char Py_source_get_channels_doc[] = ""
-"x.get_channels() -> number of channels\n"
+"get_channels()\n"
 "\n"
-"Get number of channels in source.";
+"Get number of channels in source.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"int\n"
+"    Number of channels.\n"
+"";
 
 static char Py_source_do_doc[] = ""
-"vec, read = x.do() <==> vec, read = x()\n"
+"source.do()\n"
 "\n"
-"Read monophonic vector from source.";
+"Read vector of audio samples.\n"
+"\n"
+"If the audio stream in the source has more than one channel,\n"
+"the channels will be down-mixed.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"samples : numpy.ndarray\n"
+"    `fvec` of size `hop_size` containing the new samples.\n"
+"read : int\n"
+"    Number of samples read from the source, equals to `hop_size`\n"
+"    before the end-of-file is reached, less when it is reached,\n"
+"    and `0` after.\n"
+"\n"
+"See Also\n"
+"--------\n"
+"do_multi\n"
+"\n"
+"Examples\n"
+"--------\n"
+">>> src = aubio.source('sample.wav', hop_size=1024)\n"
+">>> src.do()\n"
+"(array([-0.00123001, -0.00036685,  0.00097106, ..., -0.2031033 ,\n"
+"       -0.2025854 , -0.20221856], dtype=" AUBIO_NPY_SMPL_STR "), 1024)\n"
+"";
 
 static char Py_source_do_multi_doc[] = ""
-"mat, read = x.do_multi()\n"
+"do_multi()\n"
 "\n"
-"Read polyphonic vector from source.";
+"Read multiple channels of audio samples.\n"
+"\n"
+"If the source was opened with the same number of channels\n"
+"found in the stream, each channel will be read individually.\n"
+"\n"
+"If the source was opened with less channels than the number\n"
+"of channels in the stream, only the first channels will be read.\n"
+"\n"
+"If the source was opened with more channels than the number\n"
+"of channel in the original stream, the first channels will\n"
+"be duplicated on the additional output channel.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"samples : numpy.ndarray\n"
+"    NumPy array of shape `(hop_size, channels)` containing the new\n"
+"    audio samples.\n"
+"read : int\n"
+"    Number of samples read from the source, equals to `hop_size`\n"
+"    before the end-of-file is reached, less when it is reached,\n"
+"    and `0` after.\n"
+"\n"
+"See Also\n"
+"--------\n"
+"do\n"
+"\n"
+"Examples\n"
+"--------\n"
+">>> src = aubio.source('sample.wav')\n"
+">>> src.do_multi()\n"
+"(array([[ 0.00668335,  0.0067749 ,  0.00714111, ..., -0.05737305,\n"
+"        -0.05856323, -0.06018066],\n"
+"       [-0.00842285, -0.0072937 , -0.00576782, ..., -0.09405518,\n"
+"        -0.09558105, -0.09725952]], dtype=" AUBIO_NPY_SMPL_STR "), 512)\n"
+"";
 
 static char Py_source_close_doc[] = ""
-"x.close()\n"
+"close()\n"
 "\n"
-"Close this source now.";
+"Close this source now.\n"
+"\n"
+".. note:: Closing twice a source will **not** raise any exception.\n"
+"";
 
 static char Py_source_seek_doc[] = ""
-"x.seek(position)\n"
+"seek(position)\n"
 "\n"
-"Seek to resampled frame position.";
+"Seek to position in file.\n"
+"\n"
+"If the source was not opened with its original sampling-rate,\n"
+"`position` corresponds to the position in the re-sampled file.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"position : str\n"
+"   position to seek to, in samples\n"
+"";
 
 static PyObject *
 Py_source_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
@@ -100,9 +348,10 @@
     return NULL;
   }
 
-  self->uri = "none";
+  self->uri = NULL;
   if (uri != NULL) {
-    self->uri = uri;
+    self->uri = (char_t *)malloc(sizeof(char_t) * (strnlen(uri, PATH_MAX) + 1));
+    strncpy(self->uri, uri, strnlen(uri, PATH_MAX) + 1);
   }
 
   self->samplerate = 0;
@@ -163,6 +412,9 @@
     del_aubio_source(self->o);
     free(self->c_mread_to.data);
   }
+  if (self->uri) {
+    free(self->uri);
+  }
   Py_XDECREF(self->read_to);
   Py_XDECREF(self->mread_to);
   Py_TYPE(self)->tp_free((PyObject *) self);
@@ -213,15 +465,29 @@
 
 static PyMemberDef Py_source_members[] = {
   {"uri", T_STRING, offsetof (Py_source, uri), READONLY,
-    "path at which the source was created"},
+    "str (read-only): pathname or URL"},
   {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY,
-    "samplerate at which the source is viewed"},
+    "int (read-only): sampling rate"},
   {"channels", T_INT, offsetof (Py_source, channels), READONLY,
-    "number of channels found in the source"},
+    "int (read-only): number of channels"},
   {"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"},
+    "int (read-only): number of samples read per iteration"},
   {"duration", T_INT, offsetof (Py_source, duration), READONLY,
-    "total number of frames in the source (estimated)"},
+    "int (read-only): total number of frames in the source\n"
+    "\n"
+    "Can be estimated, for instance if the opened stream is\n"
+    "a compressed media or a remote resource.\n"
+    "\n"
+    "Example\n"
+    "-------\n"
+    ">>> n = 0\n"
+    ">>> src = aubio.source('track1.mp3')\n"
+    ">>> for samples in src:\n"
+    "...     n += samples.shape[-1]\n"
+    "...\n"
+    ">>> n, src.duration\n"
+    "(9638784, 9616561)\n"
+    ""},
   { NULL } // sentinel
 };
 
@@ -242,7 +508,7 @@
 static PyObject *
 Pyaubio_source_close (Py_source *self, PyObject *unused)
 {
-  aubio_source_close (self->o);
+  if (aubio_source_close(self->o) != 0) return NULL;
   Py_RETURN_NONE;
 }
 
@@ -272,6 +538,65 @@
   Py_RETURN_NONE;
 }
 
+static char Pyaubio_source_enter_doc[] = "";
+static PyObject* Pyaubio_source_enter(Py_source *self, PyObject *unused) {
+  Py_INCREF(self);
+  return (PyObject*)self;
+}
+
+static char Pyaubio_source_exit_doc[] = "";
+static PyObject* Pyaubio_source_exit(Py_source *self, PyObject *unused) {
+  return Pyaubio_source_close(self, unused);
+}
+
+static PyObject* Pyaubio_source_iter(PyObject *self) {
+  Py_INCREF(self);
+  return (PyObject*)self;
+}
+
+static PyObject* Pyaubio_source_iter_next(Py_source *self) {
+  PyObject *done, *size;
+  if (self->channels == 1) {
+    done = Py_source_do(self, NULL);
+  } else {
+    done = Py_source_do_multi(self, NULL);
+  }
+  if (!PyTuple_Check(done)) {
+    PyErr_Format(PyExc_ValueError,
+        "error when reading source: not opened?");
+    return NULL;
+  }
+  size = PyTuple_GetItem(done, 1);
+  if (size != NULL && PyLong_Check(size)) {
+    if (PyLong_AsLong(size) == (long)self->hop_size) {
+      PyObject *vec = PyTuple_GetItem(done, 0);
+      return vec;
+    } else if (PyLong_AsLong(size) > 0) {
+      // short read, return a shorter array
+      PyArrayObject *shortread = (PyArrayObject*)PyTuple_GetItem(done, 0);
+      PyArray_Dims newdims;
+      PyObject *reshaped;
+      newdims.len = PyArray_NDIM(shortread);
+      newdims.ptr = PyArray_DIMS(shortread);
+      // mono or multiple channels?
+      if (newdims.len == 1) {
+        newdims.ptr[0] = PyLong_AsLong(size);
+      } else {
+        newdims.ptr[1] = PyLong_AsLong(size);
+      }
+      reshaped = PyArray_Newshape(shortread, &newdims, NPY_CORDER);
+      Py_DECREF(shortread);
+      return reshaped;
+    } else {
+      PyErr_SetNone(PyExc_StopIteration);
+      return NULL;
+    }
+  } else {
+    PyErr_SetNone(PyExc_StopIteration);
+    return NULL;
+  }
+}
+
 static PyMethodDef Py_source_methods[] = {
   {"get_samplerate", (PyCFunction) Pyaubio_source_get_samplerate,
     METH_NOARGS, Py_source_get_samplerate_doc},
@@ -285,6 +610,10 @@
     METH_NOARGS, Py_source_close_doc},
   {"seek", (PyCFunction) Pyaubio_source_seek,
     METH_VARARGS, Py_source_seek_doc},
+  {"__enter__", (PyCFunction)Pyaubio_source_enter, METH_NOARGS,
+    Pyaubio_source_enter_doc},
+  {"__exit__",  (PyCFunction)Pyaubio_source_exit, METH_VARARGS,
+    Pyaubio_source_exit_doc},
   {NULL} /* sentinel */
 };
 
@@ -314,8 +643,8 @@
   0,
   0,
   0,
-  0,
-  0,
+  Pyaubio_source_iter,
+  (unaryfunc)Pyaubio_source_iter_next,
   Py_source_methods,
   Py_source_members,
   0,
--- a/python/ext/ufuncs.c
+++ b/python/ext/ufuncs.c
@@ -58,8 +58,23 @@
   //NPY_OBJECT, NPY_OBJECT,
 };
 
-static char Py_unwrap2pi_doc[] = "map angle to unit circle [-pi, pi[";
+// Note: these docstrings should *not* include the function signatures
 
+static char Py_unwrap2pi_doc[] = ""
+"\n"
+"Map angle to unit circle :math:`[-\\pi, \\pi[`.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"x : numpy.ndarray\n"
+"   input array\n"
+"\n"
+"Returns\n"
+"-------\n"
+"numpy.ndarray\n"
+"   values clamped to the unit circle :math:`[-\\pi, \\pi[`\n"
+"";
+
 static void* Py_unwrap2pi_data[] = {
   (void *)aubio_unwrap2pi,
   (void *)aubio_unwrap2pi,
@@ -67,7 +82,20 @@
   //(void *)unwrap2pio,
 };
 
-static char Py_freqtomidi_doc[] = "convert frequency to midi";
+static char Py_freqtomidi_doc[] = ""
+"\n"
+"Convert frequency `[0; 23000[` to midi `[0; 128[`.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"x : numpy.ndarray\n"
+"    Array of frequencies, in Hz.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"numpy.ndarray\n"
+"    Converted frequencies, in midi note.\n"
+"";
 
 static void* Py_freqtomidi_data[] = {
   (void *)aubio_freqtomidi,
@@ -74,7 +102,20 @@
   (void *)aubio_freqtomidi,
 };
 
-static char Py_miditofreq_doc[] = "convert midi to frequency";
+static char Py_miditofreq_doc[] = ""
+"\n"
+"Convert midi `[0; 128[` to frequency `[0, 23000]`.\n"
+"\n"
+"Parameters\n"
+"----------\n"
+"x : numpy.ndarray\n"
+"    Array of frequencies, in midi note.\n"
+"\n"
+"Returns\n"
+"-------\n"
+"numpy.ndarray\n"
+"    Converted frequencies, in Hz\n"
+"";
 
 static void* Py_miditofreq_data[] = {
   (void *)aubio_miditofreq,
--- a/python/lib/aubio/__init__.py
+++ b/python/lib/aubio/__init__.py
@@ -1,18 +1,85 @@
 #! /usr/bin/env python
+# -*- coding: utf8 -*-
 
+"""
+aubio
+=====
+
+Provides a number of classes and functions for music and audio signal
+analysis.
+
+How to use the documentation
+----------------------------
+
+Documentation of the python module is available as docstrings provided
+within the code, and a reference guide available online from `the
+aubio homepage <https://aubio.org/documentation>`_.
+
+The docstrings examples are written assuming `aubio` and `numpy` have been
+imported with:
+
+>>> import aubio
+>>> import numpy as np
+"""
+
 import numpy
-from ._aubio import *
+from ._aubio import __version__ as version
 from ._aubio import float_type
+from ._aubio import *
 from .midiconv import *
 from .slicing import *
 
+
 class fvec(numpy.ndarray):
-    """a numpy vector holding audio samples"""
+    """fvec(input_arg=1024)
+    A vector holding float samples.
 
-    def __new__(cls, input_arg=1024, **kwargs):
+    If `input_arg` is an `int`, a 1-dimensional vector of length `input_arg`
+    will be created and filled with zeros. Otherwise, if `input_arg` is an
+    `array_like` object, it will be converted to a 1-dimensional vector of
+    type :data:`float_type`.
+
+    Parameters
+    ----------
+    input_arg : `int` or `array_like`
+        Can be a positive integer, or any object that can be converted to
+        a numpy array with :func:`numpy.array`.
+
+    Examples
+    --------
+    >>> aubio.fvec(10)
+    array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
+    >>> aubio.fvec([0,1,2])
+    array([0., 1., 2.], dtype=float32)
+    >>> a = np.arange(10); type(a), type(aubio.fvec(a))
+    (<class 'numpy.ndarray'>, <class 'numpy.ndarray'>)
+    >>> a.dtype, aubio.fvec(a).dtype
+    (dtype('int64'), dtype('float32'))
+
+    Notes
+    -----
+
+    In the Python world, `fvec` is simply a subclass of
+    :class:`numpy.ndarray`. In practice, any 1-dimensional `numpy.ndarray` of
+    `dtype` :data:`float_type` may be passed to methods accepting
+    `fvec` as parameter. For instance, `sink()` or `pvoc()`.
+
+    See Also
+    --------
+    cvec : a container holding spectral data
+    numpy.ndarray : parent class of :class:`fvec`
+    numpy.zeros : create a numpy array filled with zeros
+    numpy.array : create a numpy array from an existing object
+    """
+    def __new__(cls, input_arg=1024):
         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)
+            return numpy.zeros(input_arg, dtype=float_type, order='C')
         else:
-            return numpy.array(input_arg, dtype=float_type, **kwargs)
+            np_input = numpy.array(input_arg, dtype=float_type, order='C')
+            if len(np_input.shape) != 1:
+                raise ValueError("input_arg should have shape (n,)")
+            if np_input.shape[0] == 0:
+                raise ValueError("vector length of 1 or more expected")
+            return np_input
--- /dev/null
+++ b/python/lib/aubio/cmd.py
@@ -1,0 +1,623 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""aubio command line tool
+
+This file was written by Paul Brossier <piem@aubio.org> and is released under
+the GNU/GPL v3.
+
+Note: this script is mostly about parsing command line arguments. For more
+readable code examples, check out the `python/demos` folder."""
+
+import sys
+import argparse
+import warnings
+import aubio
+
+def aubio_parser():
+    epilog = 'use "%(prog)s <command> --help" for more info about each command'
+    parser = argparse.ArgumentParser(epilog=epilog)
+    parser.add_argument('-V', '--version', help="show version",
+            action="store_true", dest="show_version")
+
+    subparsers = parser.add_subparsers(title='commands', dest='command',
+            parser_class= AubioArgumentParser,
+            metavar="")
+
+    parser_add_subcommand_help(subparsers)
+
+    parser_add_subcommand_onset(subparsers)
+    parser_add_subcommand_pitch(subparsers)
+    parser_add_subcommand_beat(subparsers)
+    parser_add_subcommand_tempo(subparsers)
+    parser_add_subcommand_notes(subparsers)
+    parser_add_subcommand_mfcc(subparsers)
+    parser_add_subcommand_melbands(subparsers)
+    parser_add_subcommand_quiet(subparsers)
+    parser_add_subcommand_cut(subparsers)
+
+    return parser
+
+def parser_add_subcommand_help(subparsers):
+    # global help subcommand
+    subparsers.add_parser('help',
+            help='show help message',
+            formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+
+def parser_add_subcommand_onset(subparsers):
+    # onset subcommand
+    subparser = subparsers.add_parser('onset',
+            help='estimate time of onsets (beginning of sound event)',
+            formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+    subparser.add_input()
+    subparser.add_buf_hop_size()
+    helpstr = "onset novelty function"
+    helpstr += " <default|energy|hfc|complex|phase|specdiff|kl|mkl|specflux>"
+    subparser.add_method(helpstr=helpstr)
+    subparser.add_threshold()
+    subparser.add_silence()
+    subparser.add_minioi()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_onset)
+
+def parser_add_subcommand_pitch(subparsers):
+    # pitch subcommand
+    subparser = subparsers.add_parser('pitch',
+            help='estimate fundamental frequency (monophonic)')
+    subparser.add_input()
+    subparser.add_buf_hop_size(buf_size=2048)
+    helpstr = "pitch detection method <default|yinfft|yin|mcomb|fcomb|schmitt>"
+    subparser.add_method(helpstr=helpstr)
+    subparser.add_threshold()
+    subparser.add_pitch_unit()
+    subparser.add_silence()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_pitch)
+
+def parser_add_subcommand_beat(subparsers):
+    # beat subcommand
+    subparser = subparsers.add_parser('beat',
+            help='estimate location of beats')
+    subparser.add_input()
+    subparser.add_buf_hop_size(buf_size=1024, hop_size=512)
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_beat)
+
+def parser_add_subcommand_tempo(subparsers):
+    # tempo subcommand
+    subparser = subparsers.add_parser('tempo',
+            help='estimate overall tempo in bpm')
+    subparser.add_input()
+    subparser.add_buf_hop_size(buf_size=1024, hop_size=512)
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_tempo)
+
+def parser_add_subcommand_notes(subparsers):
+    # notes subcommand
+    subparser = subparsers.add_parser('notes',
+            help='estimate midi-like notes (monophonic)')
+    subparser.add_input()
+    subparser.add_buf_hop_size()
+    subparser.add_silence()
+    subparser.add_release_drop()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_notes)
+
+def parser_add_subcommand_mfcc(subparsers):
+    # mfcc subcommand
+    subparser = subparsers.add_parser('mfcc',
+            help='extract Mel-Frequency Cepstrum Coefficients')
+    subparser.add_input()
+    subparser.add_buf_hop_size()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_mfcc)
+
+def parser_add_subcommand_melbands(subparsers):
+    # melbands subcommand
+    subparser = subparsers.add_parser('melbands',
+            help='extract energies in Mel-frequency bands')
+    subparser.add_input()
+    subparser.add_buf_hop_size()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_melbands)
+
+def parser_add_subcommand_quiet(subparsers):
+    # quiet subcommand
+    subparser = subparsers.add_parser('quiet',
+            help='extract timestamps of quiet and loud regions')
+    subparser.add_input()
+    subparser.add_hop_size()
+    subparser.add_silence()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_quiet)
+
+def parser_add_subcommand_cut(subparsers):
+    # cut subcommand
+    subparser = subparsers.add_parser('cut',
+            help='slice at timestamps')
+    subparser.add_input()
+    helpstr = "onset novelty function"
+    helpstr += " <default|energy|hfc|complex|phase|specdiff|kl|mkl|specflux>"
+    subparser.add_method(helpstr=helpstr)
+    subparser.add_buf_hop_size()
+    subparser.add_silence()
+    subparser.add_threshold(default=0.3)
+    subparser.add_minioi()
+    subparser.add_slicer_options()
+    subparser.add_time_format()
+    subparser.add_verbose_help()
+    subparser.set_defaults(process=process_cut)
+
+class AubioArgumentParser(argparse.ArgumentParser):
+
+    def add_input(self):
+        self.add_argument("source_uri", default=None, nargs='?',
+                help="input sound file to analyse", metavar = "<source_uri>")
+        self.add_argument("-i", "--input", dest = "source_uri2",
+                help="input sound file to analyse", metavar = "<source_uri>")
+        self.add_argument("-r", "--samplerate",
+                metavar = "<freq>", type=int,
+                action="store", dest="samplerate", default=0,
+                help="samplerate at which the file should be represented")
+
+    def add_verbose_help(self):
+        self.add_argument("-v", "--verbose",
+                action="count", dest="verbose", default=1,
+                help="make lots of noise [default]")
+        self.add_argument("-q", "--quiet",
+                action="store_const", dest="verbose", const=0,
+                help="be quiet")
+
+    def add_buf_hop_size(self, buf_size=512, hop_size=256):
+        self.add_buf_size(buf_size=buf_size)
+        self.add_hop_size(hop_size=hop_size)
+
+    def add_buf_size(self, buf_size=512):
+        self.add_argument("-B", "--bufsize",
+                action="store", dest="buf_size", default=buf_size,
+                metavar = "<size>", type=int,
+                help="buffer size [default=%d]" % buf_size)
+
+    def add_hop_size(self, hop_size=256):
+        self.add_argument("-H", "--hopsize",
+                metavar = "<size>", type=int,
+                action="store", dest="hop_size", default=hop_size,
+                help="overlap size [default=%d]" % hop_size)
+
+    def add_method(self, method='default', helpstr='method'):
+        self.add_argument("-m", "--method",
+                metavar = "<method>", type=str,
+                action="store", dest="method", default=method,
+                help="%s [default=%s]" % (helpstr, method))
+
+    def add_threshold(self, default=None):
+        self.add_argument("-t", "--threshold",
+                metavar = "<threshold>", type=float,
+                action="store", dest="threshold", default=default,
+                help="threshold [default=%s]" % default)
+
+    def add_silence(self):
+        self.add_argument("-s", "--silence",
+                metavar = "<value>", type=float,
+                action="store", dest="silence", default=-70,
+                help="silence threshold")
+
+    def add_release_drop(self):
+        self.add_argument("-d", "--release-drop",
+                metavar = "<value>", type=float,
+                action="store", dest="release_drop", default=10,
+                help="release drop threshold")
+
+    def add_minioi(self, default="12ms"):
+        self.add_argument("-M", "--minioi",
+                metavar = "<value>", type=str,
+                action="store", dest="minioi", default=default,
+                help="minimum Inter-Onset Interval [default=%s]" % default)
+
+    def add_pitch_unit(self, default="Hz"):
+        help_str = "frequency unit, should be one of Hz, midi, bin, cent"
+        help_str += " [default=%s]" % default
+        self.add_argument("-u", "--pitch-unit",
+                metavar = "<value>", type=str,
+                action="store", dest="pitch_unit", default=default,
+                help=help_str)
+
+    def add_time_format(self):
+        helpstr = "select time values output format (samples, ms, seconds)"
+        helpstr += " [default=seconds]"
+        self.add_argument("-T", "--time-format",
+                 metavar='format',
+                 dest="time_format",
+                 default=None,
+                 help=helpstr)
+
+    def add_slicer_options(self):
+        self.add_argument("-o", "--output", type = str,
+                metavar = "<outputdir>",
+                action="store", dest="output_directory", default=None,
+                help="specify path where slices of the original file should"
+                " be created")
+        self.add_argument("--cut-until-nsamples", type = int,
+                metavar = "<samples>",
+                action = "store", dest = "cut_until_nsamples", default = None,
+                help="how many extra samples should be added at the end of"
+                " each slice")
+        self.add_argument("--cut-every-nslices", type = int,
+                metavar = "<samples>",
+                action = "store", dest = "cut_every_nslices", default = None,
+                help="how many slices should be groupped together at each cut")
+        self.add_argument("--cut-until-nslices", type = int,
+                metavar = "<slices>",
+                action = "store", dest = "cut_until_nslices", default = None,
+                help="how many extra slices should be added at the end of"
+                " each slice")
+        self.add_argument("--create-first",
+                action = "store_true", dest = "create_first", default = False,
+                help="always include first slice")
+
+# some utilities
+
+def samples2seconds(n_frames, samplerate):
+    return "%f\t" % (n_frames / float(samplerate))
+
+def samples2milliseconds(n_frames, samplerate):
+    return "%f\t" % (1000. * n_frames / float(samplerate))
+
+def samples2samples(n_frames, _samplerate):
+    return "%d\t" % n_frames
+
+def timefunc(mode):
+    if mode is None or mode == 'seconds' or mode == 's':
+        return samples2seconds
+    elif mode == 'ms' or mode == 'milliseconds':
+        return samples2milliseconds
+    elif mode == 'samples':
+        return samples2samples
+    else:
+        raise ValueError("invalid time format '%s'" % mode)
+
+# definition of processing classes
+
+class default_process(object):
+    def __init__(self, args):
+        if 'time_format' in args:
+            self.time2string = timefunc(args.time_format)
+        if args.verbose > 2 and hasattr(self, 'options'):
+            name = type(self).__name__.split('_')[1]
+            optstr = ' '.join(['running', name, 'with options',
+                repr(self.options), '\n'])
+            sys.stderr.write(optstr)
+    def flush(self, frames_read, samplerate):
+        # optionally called at the end of process
+        pass
+
+    def parse_options(self, args, valid_opts):
+        # get any valid options found in a dictionnary of arguments
+        options = {k: v for k, v in vars(args).items() if k in valid_opts}
+        self.options = options
+
+    def remap_pvoc_options(self, options):
+        # FIXME: we need to remap buf_size to win_s, hop_size to hop_s
+        # adjust python/ext/py-phasevoc.c to understand buf_size/hop_size
+        if 'buf_size' in options:
+            options['win_s'] = options['buf_size']
+            del options['buf_size']
+        if 'hop_size' in options:
+            options['hop_s'] = options['hop_size']
+            del options['hop_size']
+        self.options = options
+
+class process_onset(default_process):
+    valid_opts = ['method', 'hop_size', 'buf_size', 'samplerate']
+    def __init__(self, args):
+        self.parse_options(args, self.valid_opts)
+        self.onset = aubio.onset(**self.options)
+        if args.threshold is not None:
+            self.onset.set_threshold(args.threshold)
+        if args.minioi:
+            if args.minioi.endswith('ms'):
+                self.onset.set_minioi_ms(float(args.minioi[:-2]))
+            elif args.minioi.endswith('s'):
+                self.onset.set_minioi_s(float(args.minioi[:-1]))
+            else:
+                self.onset.set_minioi(int(args.minioi))
+        if args.silence:
+            self.onset.set_silence(args.silence)
+        super(process_onset, self).__init__(args)
+    def __call__(self, block):
+        return self.onset(block)
+    def repr_res(self, res, _frames_read, samplerate):
+        if res[0] != 0:
+            outstr = self.time2string(self.onset.get_last(), samplerate)
+            sys.stdout.write(outstr + '\n')
+
+class process_pitch(default_process):
+    valid_opts = ['method', 'hop_size', 'buf_size', 'samplerate']
+    def __init__(self, args):
+        self.parse_options(args, self.valid_opts)
+        self.pitch = aubio.pitch(**self.options)
+        if args.pitch_unit is not None:
+            self.pitch.set_unit(args.pitch_unit)
+        if args.threshold is not None:
+            self.pitch.set_tolerance(args.threshold)
+        if args.silence is not None:
+            self.pitch.set_silence(args.silence)
+        super(process_pitch, self).__init__(args)
+    def __call__(self, block):
+        return self.pitch(block)
+    def repr_res(self, res, frames_read, samplerate):
+        fmt_out = self.time2string(frames_read, samplerate)
+        sys.stdout.write(fmt_out + "%.6f\n" % res[0])
+
+class process_beat(default_process):
+    valid_opts = ['method', 'hop_size', 'buf_size', 'samplerate']
+    def __init__(self, args):
+        self.parse_options(args, self.valid_opts)
+        self.tempo = aubio.tempo(**self.options)
+        super(process_beat, self).__init__(args)
+    def __call__(self, block):
+        return self.tempo(block)
+    def repr_res(self, res, _frames_read, samplerate):
+        if res[0] != 0:
+            outstr = self.time2string(self.tempo.get_last(), samplerate)
+            sys.stdout.write(outstr + '\n')
+
+class process_tempo(process_beat):
+    def __init__(self, args):
+        super(process_tempo, self).__init__(args)
+        self.beat_locations = []
+    def repr_res(self, res, _frames_read, samplerate):
+        if res[0] != 0:
+            self.beat_locations.append(self.tempo.get_last_s())
+    def flush(self, frames_read, samplerate):
+        import numpy as np
+        if len(self.beat_locations) < 2:
+            outstr = "unknown bpm"
+        else:
+            bpms = 60. / np.diff(self.beat_locations)
+            median_bpm = np.mean(bpms)
+            if len(self.beat_locations) < 10:
+                outstr = "%.2f bpm (uncertain)" % median_bpm
+            else:
+                outstr = "%.2f bpm" % median_bpm
+        sys.stdout.write(outstr + '\n')
+
+class process_notes(default_process):
+    valid_opts = ['method', 'hop_size', 'buf_size', 'samplerate']
+    def __init__(self, args):
+        self.parse_options(args, self.valid_opts)
+        self.notes = aubio.notes(**self.options)
+        if args.silence is not None:
+            self.notes.set_silence(args.silence)
+        if args.release_drop is not None:
+            self.notes.set_release_drop(args.release_drop)
+        super(process_notes, self).__init__(args)
+    def __call__(self, block):
+        return self.notes(block)
+    def repr_res(self, res, frames_read, samplerate):
+        if res[2] != 0:  # note off
+            fmt_out = self.time2string(frames_read, samplerate)
+            sys.stdout.write(fmt_out + '\n')
+        if res[0] != 0:  # note on
+            lastmidi = res[0]
+            fmt_out = "%f\t" % lastmidi
+            fmt_out += self.time2string(frames_read, samplerate)
+            sys.stdout.write(fmt_out)  # + '\t')
+    def flush(self, frames_read, samplerate):
+        eof = self.time2string(frames_read, samplerate)
+        sys.stdout.write(eof + '\n')
+
+class process_mfcc(default_process):
+    def __init__(self, args):
+        valid_opts1 = ['hop_size', 'buf_size']
+        self.parse_options(args, valid_opts1)
+        self.remap_pvoc_options(self.options)
+        self.pv = aubio.pvoc(**self.options)
+
+        valid_opts2 = ['buf_size', 'n_filters', 'n_coeffs', 'samplerate']
+        self.parse_options(args, valid_opts2)
+        self.mfcc = aubio.mfcc(**self.options)
+
+        # remember all options
+        self.parse_options(args, list(set(valid_opts1 + valid_opts2)))
+
+        super(process_mfcc, self).__init__(args)
+
+    def __call__(self, block):
+        fftgrain = self.pv(block)
+        return self.mfcc(fftgrain)
+    def repr_res(self, res, frames_read, samplerate):
+        fmt_out = self.time2string(frames_read, samplerate)
+        fmt_out += ' '.join(["% 9.7f" % f for f in res.tolist()])
+        sys.stdout.write(fmt_out + '\n')
+
+class process_melbands(default_process):
+    def __init__(self, args):
+        self.args = args
+        valid_opts = ['hop_size', 'buf_size']
+        self.parse_options(args, valid_opts)
+        self.remap_pvoc_options(self.options)
+        self.pv = aubio.pvoc(**self.options)
+
+        valid_opts = ['buf_size', 'n_filters']
+        self.parse_options(args, valid_opts)
+        self.remap_pvoc_options(self.options)
+        self.filterbank = aubio.filterbank(**self.options)
+        self.filterbank.set_mel_coeffs_slaney(args.samplerate)
+
+        super(process_melbands, self).__init__(args)
+    def __call__(self, block):
+        fftgrain = self.pv(block)
+        return self.filterbank(fftgrain)
+    def repr_res(self, res, frames_read, samplerate):
+        fmt_out = self.time2string(frames_read, samplerate)
+        fmt_out += ' '.join(["% 9.7f" % f for f in res.tolist()])
+        sys.stdout.write(fmt_out + '\n')
+
+class process_quiet(default_process):
+    def __init__(self, args):
+        self.args = args
+        valid_opts = ['hop_size', 'silence']
+        self.parse_options(args, valid_opts)
+        self.wassilence = 1
+
+        if args.silence is not None:
+            self.silence = args.silence
+        super(process_quiet, self).__init__(args)
+
+    def __call__(self, block):
+        if aubio.silence_detection(block, self.silence) == 1:
+            if self.wassilence != 1:
+                self.wassilence = 1
+                return 2   # newly found silence
+            return 1       # silence again
+        else:
+            if self.wassilence != 0:
+                self.wassilence = 0
+                return -1  # newly found noise
+            return 0       # noise again
+
+    def repr_res(self, res, frames_read, samplerate):
+        fmt_out = None
+        if res == -1:
+            fmt_out = "NOISY: "
+        if res == 2:
+            fmt_out = "QUIET: "
+        if fmt_out is not None:
+            fmt_out += self.time2string(frames_read, samplerate)
+            sys.stdout.write(fmt_out + '\n')
+
+class process_cut(process_onset):
+    def __init__(self, args):
+        super(process_cut, self).__init__(args)
+        self.slices = []
+        self.options = args
+
+    def __call__(self, block):
+        ret = super(process_cut, self).__call__(block)
+        if ret:
+            self.slices.append(self.onset.get_last())
+        return ret
+
+    def flush(self, frames_read, samplerate):
+        _cut_slice(self.options, self.slices)
+        duration = float(frames_read) / float(samplerate)
+        base_info = '%(source_file)s' % \
+                    {'source_file': self.options.source_uri}
+        base_info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % \
+                     {'duration': duration, 'samplerate': samplerate}
+        info = "created %d slices from " % len(self.slices)
+        info += base_info
+        sys.stderr.write(info)
+
+def _cut_slice(options, timestamps):
+    # cutting pass
+    nstamps = len(timestamps)
+    if nstamps > 0:
+        # generate output files
+        timestamps_end = None
+        if options.cut_every_nslices:
+            timestamps = timestamps[::options.cut_every_nslices]
+            nstamps = len(timestamps)
+        if options.cut_until_nslices and options.cut_until_nsamples:
+            msg = "using cut_until_nslices, but cut_until_nsamples is set"
+            warnings.warn(msg)
+        if options.cut_until_nsamples:
+            lag = options.cut_until_nsamples
+            timestamps_end = [t + lag for t in timestamps[1:]]
+            timestamps_end += [1e120]
+        if options.cut_until_nslices:
+            slice_lag = options.cut_until_nslices
+            timestamps_end = [t for t in timestamps[1 + slice_lag:]]
+            timestamps_end += [1e120] * (options.cut_until_nslices + 1)
+        aubio.slice_source_at_stamps(options.source_uri,
+                timestamps, timestamps_end = timestamps_end,
+                output_dir = options.output_directory,
+                samplerate = options.samplerate,
+                create_first = options.create_first)
+
+def main():
+    parser = aubio_parser()
+    if sys.version_info[0] != 3:
+        # on py2, create a dummy ArgumentParser to workaround the
+        # optional subcommand issue. See https://bugs.python.org/issue9253
+        # This ensures that:
+        #  - version string is shown when only '-V' is passed
+        #  - help is printed if  '-V' is passed with any other argument
+        #  - any other argument get forwarded to the real parser
+        parser_root = argparse.ArgumentParser(add_help=False)
+        parser_root.add_argument('-V', '--version', help="show version",
+                action="store_true", dest="show_version")
+        args, extras = parser_root.parse_known_args()
+        if not args.show_version:  # no -V, forward to parser
+            args = parser.parse_args(extras, namespace=args)
+        elif len(extras) != 0:     # -V with other arguments, print help
+            parser.print_help()
+            sys.exit(1)
+    else:  # in py3, we can simply use parser directly
+        args = parser.parse_args()
+    if 'show_version' in args and args.show_version:
+        sys.stdout.write('aubio version ' + aubio.version + '\n')
+        sys.exit(0)
+    elif 'verbose' in args and args.verbose > 3:
+        sys.stderr.write('aubio version ' + aubio.version + '\n')
+    if 'command' not in args or args.command is None \
+            or args.command in ['help']:
+        # no command given, print help and return 1
+        parser.print_help()
+        if args.command and args.command in ['help']:
+            sys.exit(0)
+        else:
+            sys.exit(1)
+    elif not args.source_uri and not args.source_uri2:
+        sys.stderr.write("Error: a source is required\n")
+        parser.print_help()
+        sys.exit(1)
+    elif args.source_uri2 is not None:
+        args.source_uri = args.source_uri2
+    try:
+        # open source_uri
+        with aubio.source(args.source_uri, hop_size=args.hop_size,
+                samplerate=args.samplerate) as a_source:
+            # always update args.samplerate to native samplerate, in case
+            # source was opened with args.samplerate=0
+            args.samplerate = a_source.samplerate
+            # create the processor for this subcommand
+            processor = args.process(args)
+            frames_read = 0
+            while True:
+                # read new block from source
+                block, read = a_source()
+                # execute processor on this block
+                res = processor(block)
+                # print results for this block
+                if args.verbose > 0:
+                    processor.repr_res(res, frames_read, a_source.samplerate)
+                # increment total number of frames read
+                frames_read += read
+                # exit loop at end of file
+                if read < a_source.hop_size:
+                    break
+            # flush the processor if needed
+            processor.flush(frames_read, a_source.samplerate)
+            if args.verbose > 1:
+                fmt_string = "read {:.2f}s"
+                fmt_string += " ({:d} samples in {:d} blocks of {:d})"
+                fmt_string += " from {:s} at {:d}Hz\n"
+                sys.stderr.write(fmt_string.format(
+                        frames_read / float(a_source.samplerate),
+                        frames_read,
+                        frames_read // a_source.hop_size + 1,
+                        a_source.hop_size,
+                        a_source.uri,
+                        a_source.samplerate))
+    except KeyboardInterrupt:
+        sys.exit(1)
--- /dev/null
+++ b/python/lib/aubio/cut.py
@@ -1,0 +1,163 @@
+#! /usr/bin/env python
+
+""" this file was written by Paul Brossier
+  it is released under the GNU/GPL license.
+"""
+
+import sys
+from aubio.cmd import AubioArgumentParser, _cut_slice
+
+def aubio_cut_parser():
+    parser = AubioArgumentParser()
+    parser.add_input()
+    parser.add_argument("-O", "--onset-method",
+            action="store", dest="onset_method", default='default',
+            metavar = "<onset_method>",
+            help="onset detection method [default=default] \
+                    complexdomain|hfc|phase|specdiff|energy|kl|mkl")
+    # cutting methods
+    parser.add_argument("-b", "--beat",
+            action="store_true", dest="beat", default=False,
+            help="slice at beat locations")
+    """
+    parser.add_argument("-S", "--silencecut",
+            action="store_true", dest="silencecut", default=False,
+            help="use silence locations")
+    parser.add_argument("-s", "--silence",
+            metavar = "<value>",
+            action="store", dest="silence", default=-70,
+            help="silence threshold [default=-70]")
+            """
+    # algorithm parameters
+    parser.add_buf_hop_size()
+    parser.add_argument("-t", "--threshold", "--onset-threshold",
+            metavar = "<threshold>", type=float,
+            action="store", dest="threshold", default=0.3,
+            help="onset peak picking threshold [default=0.3]")
+    parser.add_argument("-c", "--cut",
+            action="store_true", dest="cut", default=False,
+            help="cut input sound file at detected labels")
+    parser.add_minioi()
+
+    """
+    parser.add_argument("-D", "--delay",
+            action = "store", dest = "delay", type = float,
+            metavar = "<seconds>", default=0,
+            help="number of seconds to take back [default=system]\
+                    default system delay is 3*hopsize/samplerate")
+    parser.add_argument("-C", "--dcthreshold",
+            metavar = "<value>",
+            action="store", dest="dcthreshold", default=1.,
+            help="onset peak picking DC component [default=1.]")
+    parser.add_argument("-L", "--localmin",
+            action="store_true", dest="localmin", default=False,
+            help="use local minima after peak detection")
+    parser.add_argument("-d", "--derivate",
+            action="store_true", dest="derivate", default=False,
+            help="derivate onset detection function")
+    parser.add_argument("-z", "--zerocross",
+            metavar = "<value>",
+            action="store", dest="zerothres", default=0.008,
+            help="zero-crossing threshold for slicing [default=0.00008]")
+    # plotting functions
+    parser.add_argument("-p", "--plot",
+            action="store_true", dest="plot", default=False,
+            help="draw plot")
+    parser.add_argument("-x", "--xsize",
+            metavar = "<size>",
+            action="store", dest="xsize", default=1.,
+            type=float, help="define xsize for plot")
+    parser.add_argument("-y", "--ysize",
+            metavar = "<size>",
+            action="store", dest="ysize", default=1.,
+            type=float, help="define ysize for plot")
+    parser.add_argument("-f", "--function",
+            action="store_true", dest="func", default=False,
+            help="print detection function")
+    parser.add_argument("-n", "--no-onsets",
+            action="store_true", dest="nplot", default=False,
+            help="do not plot detected onsets")
+    parser.add_argument("-O", "--outplot",
+            metavar = "<output_image>",
+            action="store", dest="outplot", default=None,
+            help="save plot to output.{ps,png}")
+    parser.add_argument("-F", "--spectrogram",
+            action="store_true", dest="spectro", default=False,
+            help="add spectrogram to the plot")
+    """
+    parser.add_slicer_options()
+    parser.add_verbose_help()
+    return parser
+
+
+def _cut_analyze(options):
+    hopsize = options.hop_size
+    bufsize = options.buf_size
+    samplerate = options.samplerate
+    source_uri = options.source_uri
+
+    # analyze pass
+    from aubio import onset, tempo, source
+
+    s = source(source_uri, samplerate, hopsize)
+    if samplerate == 0:
+        samplerate = s.samplerate
+        options.samplerate = samplerate
+
+    if options.beat:
+        o = tempo(options.onset_method, bufsize, hopsize,
+                samplerate=samplerate)
+    else:
+        o = onset(options.onset_method, bufsize, hopsize,
+                samplerate=samplerate)
+        if options.minioi:
+            if options.minioi.endswith('ms'):
+                o.set_minioi_ms(int(options.minioi[:-2]))
+            elif options.minioi.endswith('s'):
+                o.set_minioi_s(int(options.minioi[:-1]))
+            else:
+                o.set_minioi(int(options.minioi))
+    o.set_threshold(options.threshold)
+
+    timestamps = []
+    total_frames = 0
+    while True:
+        samples, read = s()
+        if o(samples):
+            timestamps.append(o.get_last())
+            if options.verbose:
+                print("%.4f" % o.get_last_s())
+        total_frames += read
+        if read < hopsize:
+            break
+    del s
+    return timestamps, total_frames
+
+def main():
+    parser = aubio_cut_parser()
+    options = parser.parse_args()
+    if not options.source_uri and not options.source_uri2:
+        sys.stderr.write("Error: no file name given\n")
+        parser.print_help()
+        sys.exit(1)
+    elif options.source_uri2 is not None:
+        options.source_uri = options.source_uri2
+
+    # analysis
+    timestamps, total_frames = _cut_analyze(options)
+
+    # print some info
+    duration = float(total_frames) / float(options.samplerate)
+    base_info = '%(source_uri)s' % {'source_uri': options.source_uri}
+    base_info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % \
+            {'duration': duration, 'samplerate': options.samplerate}
+
+    info = "found %d timestamps in " % len(timestamps)
+    info += base_info
+    sys.stderr.write(info)
+
+    if options.cut:
+        _cut_slice(options, timestamps)
+        info = "created %d slices from " % len(timestamps)
+        info += base_info
+        sys.stderr.write(info)
--- a/python/lib/aubio/midiconv.py
+++ b/python/lib/aubio/midiconv.py
@@ -1,9 +1,11 @@
 # -*- coding: utf-8 -*-
 """ utilities to convert midi note number to and from note names """
 
-__all__ = ['note2midi', 'midi2note', 'freq2note']
-
 import sys
+from ._aubio import freqtomidi, miditofreq
+
+__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
+
 py3 = sys.version_info[0] == 3
 if py3:
     str_instances = str
@@ -12,18 +14,65 @@
     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}
+    """Convert note name to midi note number.
+
+    Input string `note` should be composed of one note root
+    and one octave, with optionally one modifier in between.
+
+    List of valid components:
+
+    - note roots: `C`, `D`, `E`, `F`, `G`, `A`, `B`,
+    - modifiers: `b`, `#`, as well as unicode characters
+      `𝄫`, `♭`, `♮`, `♯` and `𝄪`,
+    - octave numbers: `-1` -> `11`.
+
+    Parameters
+    ----------
+    note : str
+        note name
+
+    Returns
+    -------
+    int
+        corresponding midi note number
+
+    Examples
+    --------
+    >>> aubio.note2midi('C#4')
+    61
+    >>> aubio.note2midi('B♭5')
+    82
+
+    Raises
+    ------
+    TypeError
+        If `note` was not a string.
+    ValueError
+        If an error was found while converting `note`.
+
+    See Also
+    --------
+    midi2note, freqtomidi, miditofreq
+    """
+    _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7,
+                        'A': 9, 'B': 11}
+    _valid_modifiers = {
+            u'𝄫': -2,                         # double flat
+            u'♭': -1, 'b': -1, '\u266d': -1,  # simple flat
+            u'♮': 0, '\u266e': 0, None: 0,    # natural
+            '#': +1, u'♯': +1, '\u266f': +1,  # sharp
+            u'𝄪': +2,                         # double sharp
+            }
     _valid_octaves = range(-1, 10)
     if not isinstance(note, str_instances):
-        raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
+        msg = "a string is required, got {:s} ({:s})"
+        raise TypeError(msg.format(str(type(note)), repr(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
+        msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
+        raise ValueError(msg.format(len(note), note))
+    notename, modifier, octave = [None] * 3
 
     if len(note) == 4:
         notename, modifier, octave_sign, octave = note
@@ -46,21 +95,97 @@
     if octave not in _valid_octaves:
         raise ValueError("%s is not a valid octave" % octave)
 
-    midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
+    midi = (octave + 1) * 12 + _valid_notenames[notename] \
+                             + _valid_modifiers[modifier]
     if midi > 127:
         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] "
+    """Convert midi note number to note name.
+
+    Parameters
+    ----------
+    midi : int [0, 128]
+        input midi note number
+
+    Returns
+    -------
+    str
+        note name
+
+    Examples
+    --------
+    >>> aubio.midi2note(70)
+    'A#4'
+    >>> aubio.midi2note(59)
+    'B3'
+
+    Raises
+    ------
+    TypeError
+        If `midi` was not an integer.
+    ValueError
+        If `midi` is out of the range `[0, 128]`.
+
+    See Also
+    --------
+    note2midi, miditofreq, freqtomidi
+    """
     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']
+        msg = "an integer between 0 and 127 is excepted, got {:d}"
+        raise ValueError(msg.format(midi))
+    _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
+                        'A', 'A#', 'B']
     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)))
+    """Convert frequency in Hz to nearest note name.
+
+    Parameters
+    ----------
+    freq : float [0, 23000[
+        input frequency, in Hz
+
+    Returns
+    -------
+    str
+        name of the nearest note
+
+    Example
+    -------
+    >>> aubio.freq2note(440)
+    'A4'
+    >>> aubio.freq2note(220.1)
+    'A3'
+    """
+    nearest_note = int(freqtomidi(freq) + .5)
+    return midi2note(nearest_note)
+
+
+def note2freq(note):
+    """Convert note name to corresponding frequency, in Hz.
+
+    Parameters
+    ----------
+    note : str
+        input note name
+
+    Returns
+    -------
+    freq : float [0, 23000[
+        frequency, in Hz
+
+    Example
+    -------
+    >>> aubio.note2freq('A4')
+    440
+    >>> aubio.note2freq('A3')
+    220.1
+    """
+    midi = note2midi(note)
+    return miditofreq(midi)
--- a/python/lib/aubio/slicing.py
+++ b/python/lib/aubio/slicing.py
@@ -5,26 +5,91 @@
 
 _max_timestamp = 1e120
 
+
 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 """
+                           output_dir=None, samplerate=0, hopsize=256,
+                           create_first=False):
+    """Slice a sound file at given timestamps.
 
-    if timestamps is None or len(timestamps) == 0:
+    This function reads `source_file` and creates slices, new smaller
+    files each starting at `t` in `timestamps`, a list of integer
+    corresponding to time locations in `source_file`, in samples.
+
+    If `timestamps_end` is unspecified, the slices will end at
+    `timestamps_end[n] = timestamps[n+1]-1`, or the end of file.
+    Otherwise, `timestamps_end` should be a list with the same length
+    as `timestamps` containing the locations of the end of each slice.
+
+    If `output_dir` is unspecified, the new slices will be written in
+    the current directory. If `output_dir` is a string, new slices
+    will be written in `output_dir`, after creating the directory if
+    required.
+
+    The default `samplerate` is 0, meaning the original sampling rate
+    of `source_file` will be used. When using a sampling rate
+    different to the one of the original files, `timestamps` and
+    `timestamps_end` should be expressed in the re-sampled signal.
+
+    The `hopsize` parameter simply tells :class:`source` to use this
+    hopsize and does not change the output slices.
+
+    If `create_first` is True and `timestamps` does not start with `0`, the
+    first slice from `0` to `timestamps[0] - 1` will be automatically added.
+
+    Parameters
+    ----------
+    source_file : str
+        path of the resource to slice
+    timestamps : :obj:`list` of :obj:`int`
+        time stamps at which to slice, in samples
+    timestamps_end : :obj:`list` of :obj:`int` (optional)
+        time stamps at which to end the slices
+    output_dir : str (optional)
+        output directory to write the slices to
+    samplerate : int (optional)
+        samplerate to read the file at
+    hopsize : int (optional)
+        number of samples read from source per iteration
+    create_first : bool (optional)
+        always create the slice at the start of the file
+
+    Examples
+    --------
+    Create two slices: the first slice starts at the beginning of the
+    input file `loop.wav` and lasts exactly one second, starting at
+    sample `0` and ending at sample `44099`; the second slice starts
+    at sample `44100` and lasts until the end of the input file:
+
+    >>> aubio.slice_source_at_stamps('loop.wav', [0, 44100])
+
+    Create one slice, from 1 second to 2 seconds:
+
+    >>> aubio.slice_source_at_stamps('loop.wav', [44100], [44100 * 2 - 1])
+
+    Notes
+    -----
+    Slices may be overlapping. If `timestamps_end` is `1` element
+    shorter than `timestamps`, the last slice will end at the end of
+    the file.
+    """
+
+    if not timestamps:
         raise ValueError("no timestamps given")
 
-    if timestamps[0] != 0:
+    if timestamps[0] != 0 and create_first:
         timestamps = [0] + timestamps
         if timestamps_end is not None:
             timestamps_end = [timestamps[1] - 1] + timestamps_end
 
     if timestamps_end is not None:
-        if len(timestamps_end) != len(timestamps):
+        if len(timestamps_end) == len(timestamps) - 1:
+            timestamps_end = timestamps_end + [_max_timestamp]
+        elif len(timestamps_end) != len(timestamps):
             raise ValueError("len(timestamps_end) != len(timestamps)")
     else:
         timestamps_end = [t - 1 for t in timestamps[1:]] + [_max_timestamp]
 
     regions = list(zip(timestamps, timestamps_end))
-    #print regions
 
     source_base_name, _ = os.path.splitext(os.path.basename(source_file))
     if output_dir is not None:
@@ -32,8 +97,8 @@
             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 """
+    def _new_sink_name(source_base_name, timestamp, samplerate):
+        # create name based on a timestamp in samples, converted in seconds
         timestamp_seconds = timestamp / float(samplerate)
         return source_base_name + "_%011.6f" % timestamp_seconds + '.wav'
 
@@ -48,16 +113,17 @@
         # get hopsize new samples from source
         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
+        while regions and total_frames + read >= regions[0][0]:
             # get next region
             start_stamp, end_stamp = regions.pop(0)
             # create a name for the sink
-            new_sink_path = new_sink_name(source_base_name, start_stamp, samplerate)
+            new_sink_path = _new_sink_name(source_base_name, start_stamp,
+                                           samplerate)
             # create its sink
             _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': _sink}
+            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)
 
@@ -69,13 +135,11 @@
             start = max(start_stamp - total_frames, 0)
             # number of samples yet to written be until end of region
             remaining = end_stamp - total_frames + 1
-            #print current_slice, remaining, start
             # not enough frames remaining, time to split
             if remaining < read:
                 if remaining > start:
                     # write remaining samples from current region
                     _sink.do_multi(vec[:, start:remaining], remaining - start)
-                    #print "closing region", "remaining", remaining
                     # close this file
                     _sink.close()
             elif read > start:
@@ -82,5 +146,8 @@
                 # write all the samples
                 _sink.do_multi(vec[:, start:read], read - start)
         total_frames += read
+        # remove old slices
+        slices = list(filter(lambda s: s['end_stamp'] > total_frames,
+                             slices))
         if read < hopsize:
             break
--- a/python/lib/gen_code.py
+++ b/python/lib/gen_code.py
@@ -2,6 +2,7 @@
     # we have some clean up to do
     'buf_size': 'Py_default_vector_length',
     'win_s': 'Py_default_vector_length',
+    'size': 'Py_default_vector_length',
     # and here too
     'hop_size': 'Py_default_vector_length / 2',
     'hop_s': 'Py_default_vector_length / 2',
@@ -84,6 +85,7 @@
         'filterbank': 'self->n_filters',
         'tss': 'self->buf_size',
         'pitchshift': 'self->hop_size',
+        'dct': 'self->size',
         }
 
 objinputsize = {
@@ -179,6 +181,10 @@
         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]
+        if len(self.prototypes['rdo']):
+            rdo_outputs = get_params_types_names(prototypes['rdo'][0])[2:]
+            struct_output_str += ["PyObject *{0[name]}; {1} c_{0[name]}".format(i, i['type'][:-1]) for i in rdo_outputs]
+            self.outputs += rdo_outputs
         self.struct_outputs = ";\n    ".join(struct_output_str)
 
         #print ("input_params: ", map(split_type, get_input_params(self.do_proto)))
@@ -186,17 +192,26 @@
 
     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()
+        try:
+            out += self.gen_struct()
+            out += self.gen_doc()
+            out += self.gen_new()
+            out += self.gen_init()
+            out += self.gen_del()
+            out += self.gen_do()
+            if len(self.prototypes['rdo']):
+                self.do_proto = self.prototypes['rdo'][0]
+                self.do_inputs = [get_params_types_names(self.do_proto)[1]]
+                self.do_outputs = get_params_types_names(self.do_proto)[2:]
+                out += self.gen_do(method='rdo')
+            out += self.gen_memberdef()
+            out += self.gen_set()
+            out += self.gen_get()
+            out += self.gen_methodef()
+            out += self.gen_typeobject()
+        except Exception as e:
+            print ("Failed generating code for", self.shortname)
+            raise
         return out
 
     def gen_struct(self):
@@ -380,12 +395,12 @@
 """.format(del_fn = del_fn)
         return out
 
-    def gen_do(self):
+    def gen_do(self, method = 'do'):
         out = """
 // do {shortname}
 static PyObject*
-Py_{shortname}_do  (Py_{shortname} * self, PyObject * args)
-{{""".format(**self.__dict__)
+Pyaubio_{shortname}_{method}  (Py_{shortname} * self, PyObject * args)
+{{""".format(method = method, **self.__dict__)
         input_params = self.do_inputs
         output_params = self.do_outputs
         #print input_params
@@ -461,30 +476,51 @@
 // {shortname} setters
 """.format(**self.__dict__)
         for set_param in self.prototypes['set']:
-            params = get_params_types_names(set_param)[1]
-            paramtype = params['type']
+            params = get_params_types_names(set_param)[1:]
+            param = self.shortname.split('_set_')[-1]
+            paramdecls = "".join(["""
+   {0} {1};""".format(p['type'], p['name']) for p in params])
             method_name = get_name(set_param)
             param = method_name.split('aubio_'+self.shortname+'_set_')[-1]
-            pyparamtype = pyargparse_chars[paramtype]
+            refs = ", ".join(["&%s" % p['name'] for p in params])
+            paramlist = ", ".join(["%s" % p['name'] for p in params])
+            if len(params):
+                paramlist = "," + paramlist
+            pyparamtypes = ''.join([pyargparse_chars[p['type']] for p in params])
             out += """
 static PyObject *
 Pyaubio_{shortname}_set_{param} (Py_{shortname} *self, PyObject *args)
 {{
   uint_t err = 0;
-  {paramtype} {param};
+  {paramdecls}
+""".format(param = param, paramdecls = paramdecls, **self.__dict__)
 
-  if (!PyArg_ParseTuple (args, "{pyparamtype}", &{param})) {{
+            if len(refs) and len(pyparamtypes):
+                out += """
+
+  if (!PyArg_ParseTuple (args, "{pyparamtypes}", {refs})) {{
     return NULL;
   }}
-  err = aubio_{shortname}_set_{param} (self->o, {param});
+""".format(pyparamtypes = pyparamtypes, refs = refs)
 
+            out += """
+  err = aubio_{shortname}_set_{param} (self->o {paramlist});
+
   if (err > 0) {{
-    PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
+    if (PyErr_Occurred() == NULL) {{
+      PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
+    }} else {{
+      // change the RuntimeError into ValueError
+      PyObject *type, *value, *traceback;
+      PyErr_Fetch(&type, &value, &traceback);
+      PyErr_Restore(PyExc_ValueError, value, traceback);
+    }}
     return NULL;
   }}
   Py_RETURN_NONE;
 }}
-""".format(param = param, paramtype = paramtype, pyparamtype = pyparamtype, **self.__dict__)
+""".format(param = param, refs = refs, paramdecls = paramdecls,
+        pyparamtypes = pyparamtypes, paramlist = paramlist, **self.__dict__)
         return out
 
     def gen_get(self):
@@ -525,6 +561,12 @@
             out += """
   {{"{shortname}", (PyCFunction) Py{name},
     METH_NOARGS, ""}},""".format(name = name, shortname = shortname)
+        for m in self.prototypes['rdo']:
+            name = get_name(m)
+            shortname = name.replace('aubio_%s_' % self.shortname, '')
+            out += """
+  {{"{shortname}", (PyCFunction) Py{name},
+    METH_VARARGS, ""}},""".format(name = name, shortname = shortname)
         out += """
   {NULL} /* sentinel */
 };
@@ -550,7 +592,7 @@
   0,
   0,
   0,
-  (ternaryfunc)Py_{shortname}_do,
+  (ternaryfunc)Pyaubio_{shortname}_do,
   0,
   0,
   0,
--- a/python/lib/gen_external.py
+++ b/python/lib/gen_external.py
@@ -1,5 +1,10 @@
 import distutils.ccompiler
-import sys, os, subprocess, glob
+import sys
+import os
+import subprocess
+import glob
+from distutils.sysconfig import customize_compiler
+from gen_code import MappedObject
 
 header = os.path.join('src', 'aubio.h')
 output_path = os.path.join('python', 'gen')
@@ -8,43 +13,44 @@
 #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',
-  ]
+default_skip_objects = [
+    # already in ext/
+    'fft',
+    'pvoc',
+    'filter',
+    'filterbank',
+    # AUBIO_UNSTABLE
+    'hist',
+    'parameter',
+    'scale',
+    'beattracking',
+    'resampler',
+    'peakpicker',
+    'pitchfcomb',
+    'pitchmcomb',
+    'pitchschmitt',
+    'pitchspecacf',
+    'pitchyin',
+    'pitchyinfft',
+    'pitchyinfast',
+    'sink',
+    'sink_apple_audio',
+    'sink_sndfile',
+    'sink_wavwrite',
+    #'mfcc',
+    'source',
+    'source_apple_audio',
+    'source_sndfile',
+    'source_avcodec',
+    'source_wavread',
+    #'sampler',
+    'audio_unit',
+    'spectral_whitening',
+]
 
+
 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:
@@ -59,26 +65,50 @@
             print("Warning: failed initializing compiler ({:s})".format(repr(e)))
 
     cpp_cmd = None
-    if hasattr(compiler, 'preprocessor'): # for unixccompiler
+    if hasattr(compiler, 'preprocessor'):  # for unixccompiler
         cpp_cmd = compiler.preprocessor
-    elif hasattr(compiler, 'compiler'): # for ccompiler
+    elif hasattr(compiler, 'compiler'):  # for ccompiler
         cpp_cmd = compiler.compiler.split()
         cpp_cmd += ['-E']
-    elif hasattr(compiler, 'cc'): # for msvccompiler
+    elif hasattr(compiler, 'cc'):  # for msvccompiler
         cpp_cmd = compiler.cc.split()
         cpp_cmd += ['-E']
 
+    # On win-amd64 (py3.x), the default compiler is cross-compiling, from x86
+    # to amd64 with %WIN_SDK_ROOT%\x86_amd64\cl.exe, but using this binary as a
+    # pre-processor generates no output, so we use %WIN_SDK_ROOT%\cl.exe
+    # instead.
+    if len(cpp_cmd) > 1 and 'cl.exe' in cpp_cmd[-2]:
+        plat = os.path.basename(os.path.dirname(cpp_cmd[-2]))
+        if plat == 'x86_amd64':
+            print('workaround on win64 to avoid empty pre-processor output')
+            cpp_cmd[-2] = cpp_cmd[-2].replace('x86_amd64', '')
+        elif True in ['amd64' in f for f in cpp_cmd]:
+            print('warning: not using workaround for', cpp_cmd[0], plat)
+
     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']
-
+    if 'emcc' in cpp_cmd:
+        cpp_cmd += ['-x', 'c'] # emcc defaults to c++, force C language
     return cpp_cmd
 
-def get_cpp_objects(header=header):
+
+def get_c_declarations(header=header, usedouble=False):
+    ''' return a dense and preprocessed  string of all c declarations implied by aubio.h
+    '''
+    cpp_output = get_cpp_output(header=header, usedouble=usedouble)
+    return filter_cpp_output (cpp_output)
+
+
+def get_cpp_output(header=header, usedouble=False):
+    ''' find and run a C pre-processor on aubio.h '''
     cpp_cmd = get_preprocessor()
 
     macros = [('AUBIO_UNSTABLE', 1)]
+    if usedouble:
+        macros += [('HAVE_AUBIO_DOUBLE', 1)]
 
     if not os.path.isfile(header):
         raise Exception("could not find include file " + header)
@@ -89,56 +119,115 @@
 
     print("Running command: {:s}".format(" ".join(cpp_cmd)))
     proc = subprocess.Popen(cpp_cmd,
-            stderr=subprocess.PIPE,
-            stdout=subprocess.PIPE)
+                            stderr=subprocess.PIPE,
+                            stdout=subprocess.PIPE)
     assert proc, 'Proc was none'
     cpp_output = proc.stdout.read()
     err_output = proc.stderr.read()
+    if err_output:
+        print("Warning: preprocessor produced errors or warnings:\n%s" \
+                % err_output.decode('utf8'))
     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)
+        raise_msg = "preprocessor output is empty! Running command " \
+                + "\"%s\" failed" % " ".join(cpp_cmd)
+        if err_output:
+            raise_msg += " with stderr: \"%s\"" % err_output.decode('utf8')
+        else:
+            raise_msg += " with no stdout or stderr"
+        raise Exception(raise_msg)
     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)
+    return cpp_output
+
+def filter_cpp_output(cpp_raw_output):
+    ''' prepare cpp-output for parsing '''
+    cpp_output = filter(lambda y: len(y) > 1, cpp_raw_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)
+        if i >= len(cpp_output):
+            break
+        if ('{' in cpp_output[i - 1]) and ('}' not in cpp_output[i - 1]) or (';' not in cpp_output[i - 1]):
+            cpp_output[i] = cpp_output[i - 1] + ' ' + cpp_output[i]
+            cpp_output.pop(i - 1)
+        elif ('}' in cpp_output[i]):
+            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)
+    # clean pointer notations
+    tmp = []
+    for l in cpp_output:
+        tmp += [l.replace(' *', ' * ')]
+    cpp_output = tmp
 
+    return cpp_output
+
+
+def get_cpp_objects_from_c_declarations(c_declarations, skip_objects=None):
+    if skip_objects is None:
+        skip_objects = default_skip_objects
+    typedefs = filter(lambda y: y.startswith('typedef struct _aubio'), c_declarations)
     cpp_objects = [a.split()[3][:-1] for a in typedefs]
+    cpp_objects_filtered = filter(lambda y: not y[6:-2] in skip_objects, cpp_objects)
+    return cpp_objects_filtered
 
-    return cpp_output, cpp_objects
 
+def get_all_func_names_from_lib(lib):
+    ''' return flat string of all function used in lib
+    '''
+    res = []
+    for _, v in lib.items():
+        if isinstance(v, dict):
+            res += get_all_func_names_from_lib(v)
+        elif isinstance(v, list):
+            for elem in v:
+                e = elem.split('(')
+                if len(e) < 2:
+                    continue  # not a function
+                fname_part = e[0].strip().split(' ')
+                fname = fname_part[-1]
+                if fname:
+                    res += [fname]
+                else:
+                    raise NameError('gen_lib : weird function: ' + str(e))
 
-def analyze_cpp_output(cpp_objects, cpp_output):
+    return res
+
+
+def generate_lib_from_c_declarations(cpp_objects, c_declarations):
+    ''' returns a lib from given cpp_object names
+
+    a lib is a dict grouping functions by family (onset,pitch...)
+        each eement is itself a dict of functions grouped by puposes as : 
+        struct, new, del, do, get, set and other
+    '''
     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': []}
+        shortname = o
+        if o[:6] == 'aubio_':
+            shortname = o[6:-2]  # without aubio_ prefix and _t suffix
+
+        lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'rdo': [], '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
+
+        fullshortname = o[:-2]  # name without _t suffix
+
+        for fn in c_declarations:
+            func_name = fn.split('(')[0].strip().split(' ')[-1]
+            if func_name.startswith(fullshortname + '_') or func_name.endswith(fullshortname):
+                # print "found", shortname, "in", fn
                 if 'typedef struct ' in fn:
                     lib[shortname]['struct'].append(fn)
                 elif '_do' in fn:
                     lib[shortname]['do'].append(fn)
+                elif '_rdo' in fn:
+                    lib[shortname]['rdo'].append(fn)
                 elif 'new_' in fn:
                     lib[shortname]['new'].append(fn)
                 elif 'del_' in fn:
@@ -148,12 +237,13 @@
                 elif '_set_' in fn:
                     lib[shortname]['set'].append(fn)
                 else:
-                    #print "no idea what to do about", fn
+                    # print "no idea what to do about", fn
                     lib[shortname]['other'].append(fn)
     return lib
 
-def print_cpp_output_results(lib, cpp_output):
-    for fn in cpp_output:
+
+def print_c_declarations_results(lib, c_declarations):
+    for fn in c_declarations:
         found = 0
         for o in lib:
             for family in lib[o]:
@@ -160,40 +250,39 @@
                 if fn in lib[o][family]:
                     found = 1
         if found == 0:
-            print ("missing", fn)
+            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] ) )
+                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] ) )
+                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family][0]))
             else:
-                print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
+                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family]))
 
 
 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'))
+    if not os.path.isdir(output_path):
+        os.mkdir(output_path)
+    elif not overwrite:
+        return sorted(glob.glob(os.path.join(output_path, '*.c')))
 
-    cpp_output, cpp_objects = get_cpp_objects(header)
+    c_declarations = get_c_declarations(header, usedouble=usedouble)
+    cpp_objects = get_cpp_objects_from_c_declarations(c_declarations)
 
-    lib = analyze_cpp_output(cpp_objects, cpp_output)
-    # print_cpp_output_results(lib, cpp_output)
+    lib = generate_lib_from_c_declarations(cpp_objects, c_declarations)
+    # print_c_declarations_results(lib, c_declarations)
 
     sources_list = []
-    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)
+        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 )
+            print("wrote %s" % output_file)
             sources_list.append(output_file)
 
     out = source_header
@@ -205,11 +294,11 @@
 {{
   return ({pycheck_types});
 }}
-""".format(pycheck_types = check_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])
+  PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name=o) for o in lib])
     out += """
 
 void add_generated_objects ( PyObject *m )
@@ -216,12 +305,12 @@
 {{
 {add_types}
 }}
-""".format(add_types = 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 )
+        print("wrote %s" % output_file)
         sources_list.append(output_file)
 
     objlist = "".join(["extern PyTypeObject Py_%sType;\n" % p for p in lib])
@@ -239,17 +328,19 @@
 {objlist}
 int generated_objects ( void );
 void add_generated_objects( PyObject *m );
-""".format(objlist = objlist)
+""".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 )
+        print("wrote %s" % output_file)
         # no need to add header to list of sources
 
-    return sources_list
+    return sorted(sources_list)
 
 if __name__ == '__main__':
-    if len(sys.argv) > 1: header = sys.argv[1]
-    if len(sys.argv) > 2: output_path = sys.argv[2]
+    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/moresetuptools.py
+++ b/python/lib/moresetuptools.py
@@ -2,8 +2,10 @@
 #
 import sys, os, glob, subprocess
 import distutils, distutils.command.clean, distutils.dir_util
-from .gen_external import generate_external, header, output_path
+from gen_external import generate_external, header, output_path
 
+from this_version import get_aubio_version
+
 # 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 """
@@ -21,6 +23,7 @@
              }
 
     for package in packages:
+        print("checking for {:s}".format(package))
         cmd = ['pkg-config', '--libs', '--cflags', package]
         try:
             tokens = subprocess.check_output(cmd)
@@ -54,13 +57,14 @@
 
 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'))
+    print("Info: libaubio was not installed or built locally with waf, adding src/")
+    aubio_sources = sorted(glob.glob(os.path.join('src', '**.c')))
+    aubio_sources += sorted(glob.glob(os.path.join('src', '*', '**.c')))
     ext.sources += aubio_sources
+
+def add_local_macros(ext, usedouble = False):
+    if usedouble:
+        ext.define_macros += [('HAVE_AUBIO_DOUBLE', 1)]
     # 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',
@@ -69,22 +73,31 @@
                          'HAVE_MEMCPY_HACKS']:
         ext.define_macros += [(define_macro, 1)]
 
+def add_external_deps(ext, usedouble = False):
     # loof for additional packages
     print("Info: looking for *optional* additional packages")
-    packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample',
+    packages = ['libavcodec', 'libavformat', 'libavutil',
+                'libswresample', 'libavresample',
                 'jack',
-                'sndfile', 'samplerate',
+                'sndfile',
                 'rubberband',
                 #'fftw3f',
                ]
+    # samplerate only works with float
+    if usedouble is False:
+        packages += ['samplerate']
+    else:
+        print("Info: not adding libsamplerate in double precision mode")
     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)]
+            and 'avutil' in ext.libraries:
+        if 'swresample' in ext.libraries:
+            ext.define_macros += [('HAVE_SWRESAMPLE', 1)]
+        elif 'avresample' in ext.libraries:
+            ext.define_macros += [('HAVE_AVRESAMPLE', 1)]
+        if 'swresample' in ext.libraries or 'avresample' in ext.libraries:
+            ext.define_macros += [('HAVE_LIBAV', 1)]
     if 'sndfile' in ext.libraries:
         ext.define_macros += [('HAVE_SNDFILE', 1)]
     if 'samplerate' in ext.libraries:
@@ -107,8 +120,8 @@
 
     ext.define_macros += [('HAVE_WAVWRITE', 1)]
     ext.define_macros += [('HAVE_WAVREAD', 1)]
-    # TODO:
-    # add cblas
+
+    # TODO: add cblas
     if 0:
         ext.libraries += ['cblas']
         ext.define_macros += [('HAVE_ATLAS_CBLAS_H', 1)]
@@ -115,31 +128,70 @@
 
 def add_system_aubio(ext):
     # use pkg-config to find aubio's location
-    add_packages(['aubio'], ext)
+    aubio_version = get_aubio_version()
+    add_packages(['aubio = ' + aubio_version], ext)
     if 'aubio' not in ext.libraries:
-        print("Error: libaubio not found")
+        print("Info: aubio " + aubio_version + " was not found by pkg-config")
+    else:
+        print("Info: using system aubio " + aubio_version + " found in " + ' '.join(ext.library_dirs))
 
+def add_libav_on_win(ext):
+    """ no pkg-config on windows, simply assume these libs are available """
+    ext.libraries += ['avformat', 'avutil', 'avcodec', 'swresample']
+    for define_macro in ['HAVE_LIBAV', 'HAVE_SWRESAMPLE']:
+        ext.define_macros += [(define_macro, 1)]
+
 class CleanGenerated(distutils.command.clean.clean):
     def run(self):
-        distutils.dir_util.remove_tree(output_path)
-        distutils.command.clean.clean.run(self)
+        if os.path.isdir(output_path):
+            distutils.dir_util.remove_tree(output_path)
 
-class GenerateCommand(distutils.cmd.Command):
-    description = 'generate gen/gen-*.c files from ../src/aubio.h'
-    user_options = [
+from distutils.command.build_ext import build_ext as _build_ext
+class build_ext(_build_ext):
+
+    user_options = _build_ext.user_options + [
             # The format is (long option, short option, description).
             ('enable-double', None, 'use HAVE_AUBIO_DOUBLE=1 (default: 0)'),
             ]
 
     def initialize_options(self):
+        _build_ext.initialize_options(self)
         self.enable_double = False
 
     def finalize_options(self):
+        _build_ext.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)
+    def build_extension(self, extension):
+        if self.enable_double or 'HAVE_AUBIO_DOUBLE' in os.environ:
+            enable_double = True
+        else:
+            enable_double = False
+        # seack for aubio headers and lib in PKG_CONFIG_PATH
+        add_system_aubio(extension)
+        # the lib was not installed on this system
+        if 'aubio' not in extension.libraries:
+            # use local src/aubio.h
+            if os.path.isfile(os.path.join('src', 'aubio.h')):
+                add_local_aubio_header(extension)
+            add_local_macros(extension, usedouble=enable_double)
+            # look for a local waf build
+            if os.path.isfile(os.path.join('build','src', 'fvec.c.1.o')):
+                add_local_aubio_lib(extension)
+            else:
+                # check for external dependencies
+                add_external_deps(extension, usedouble=enable_double)
+                # force adding libav on windows
+                if os.name == 'nt' and ('WITH_LIBAV' in os.environ \
+                        or 'CONDA_PREFIX' in os.environ):
+                    add_libav_on_win(extension)
+                # add libaubio sources and look for optional deps with pkg-config
+                add_local_aubio_sources(extension)
+        # generate files python/gen/*.c, python/gen/aubio-generated.h
+        extension.include_dirs += [ output_path ]
+        extension.sources += generate_external(header, output_path, overwrite = False,
+                usedouble=enable_double)
+        return _build_ext.build_extension(self, extension)
--- a/python/scripts/aubiocut
+++ /dev/null
@@ -1,206 +1,0 @@
-#! /usr/bin/env python
-
-""" this file was written by Paul Brossier
-  it is released under the GNU/GPL license.
-"""
-
-import sys
-#from aubio.task import *
-
-usage = "usage: %s [options] -i soundfile" % sys.argv[0]
-usage += "\n help: %s -h" % sys.argv[0]
-
-def parse_args():
-    from optparse import OptionParser
-    parser = OptionParser(usage=usage)
-    parser.add_option("-i", "--input", action = "store", dest = "source_file",
-            help="input sound file to analyse", metavar = "<source_file>")
-    parser.add_option("-O","--onset-method",
-            action="store", dest="onset_method", default='default',
-            metavar = "<onset_method>",
-            help="onset detection method [default=default] \
-                    complexdomain|hfc|phase|specdiff|energy|kl|mkl")
-    # cutting methods
-    parser.add_option("-b","--beat",
-            action="store_true", dest="beat", default=False,
-            help="use beat locations")
-    """
-    parser.add_option("-S","--silencecut",
-            action="store_true", dest="silencecut", default=False,
-            help="use silence locations")
-    parser.add_option("-s","--silence",
-            metavar = "<value>",
-            action="store", dest="silence", default=-70,
-            help="silence threshold [default=-70]")
-            """
-    # algorithm parameters
-    parser.add_option("-r", "--samplerate",
-            metavar = "<freq>", type='int',
-            action="store", dest="samplerate", default=0,
-            help="samplerate at which the file should be represented")
-    parser.add_option("-B","--bufsize",
-            action="store", dest="bufsize", default=512,
-            metavar = "<size>", type='int',
-            help="buffer size [default=512]")
-    parser.add_option("-H","--hopsize",
-            metavar = "<size>", type='int',
-            action="store", dest="hopsize", default=256,
-            help="overlap size [default=256]")
-    parser.add_option("-t","--onset-threshold",
-            metavar = "<value>", type="float",
-            action="store", dest="threshold", default=0.3,
-            help="onset peak picking threshold [default=0.3]")
-    parser.add_option("-c","--cut",
-            action="store_true", dest="cut", default=False,
-            help="cut input sound file at detected labels \
-                    best used with option -L")
-
-    # minioi
-    parser.add_option("-M","--minioi",
-            metavar = "<value>", type='string',
-            action="store", dest="minioi", default="12ms",
-            help="minimum inter onset interval [default=12ms]")
-
-    """
-    parser.add_option("-D","--delay",
-            action = "store", dest = "delay", type = "float",
-            metavar = "<seconds>", default=0,
-            help="number of seconds to take back [default=system]\
-                    default system delay is 3*hopsize/samplerate")
-    parser.add_option("-C","--dcthreshold",
-            metavar = "<value>",
-            action="store", dest="dcthreshold", default=1.,
-            help="onset peak picking DC component [default=1.]")
-    parser.add_option("-L","--localmin",
-            action="store_true", dest="localmin", default=False,
-            help="use local minima after peak detection")
-    parser.add_option("-d","--derivate",
-            action="store_true", dest="derivate", default=False,
-            help="derivate onset detection function")
-    parser.add_option("-z","--zerocross",
-            metavar = "<value>",
-            action="store", dest="zerothres", default=0.008,
-            help="zero-crossing threshold for slicing [default=0.00008]")
-            """
-    # plotting functions
-    """
-    parser.add_option("-p","--plot",
-            action="store_true", dest="plot", default=False,
-            help="draw plot")
-    parser.add_option("-x","--xsize",
-            metavar = "<size>",
-            action="store", dest="xsize", default=1.,
-            type='float', help="define xsize for plot")
-    parser.add_option("-y","--ysize",
-            metavar = "<size>",
-            action="store", dest="ysize", default=1.,
-            type='float', help="define ysize for plot")
-    parser.add_option("-f","--function",
-            action="store_true", dest="func", default=False,
-            help="print detection function")
-    parser.add_option("-n","--no-onsets",
-            action="store_true", dest="nplot", default=False,
-            help="do not plot detected onsets")
-    parser.add_option("-O","--outplot",
-            metavar = "<output_image>",
-            action="store", dest="outplot", default=None,
-            help="save plot to output.{ps,png}")
-    parser.add_option("-F","--spectrogram",
-            action="store_true", dest="spectro", default=False,
-            help="add spectrogram to the plot")
-    """
-    parser.add_option("-o","--output", type = str,
-            metavar = "<outputdir>",
-            action="store", dest="output_directory", default=None,
-            help="specify path where slices of the original file should be created")
-    parser.add_option("--cut-until-nsamples", type = int,
-            metavar = "<samples>",
-            action = "store", dest = "cut_until_nsamples", default = None,
-            help="how many extra samples should be added at the end of each slice")
-    parser.add_option("--cut-until-nslices", type = int,
-            metavar = "<slices>",
-            action = "store", dest = "cut_until_nslices", default = None,
-            help="how many extra slices should be added at the end of each slice")
-
-    parser.add_option("-v","--verbose",
-            action="store_true", dest="verbose", default=True,
-            help="make lots of noise [default]")
-    parser.add_option("-q","--quiet",
-            action="store_false", dest="verbose", default=True,
-            help="be quiet")
-    (options, args) = parser.parse_args()
-    if not options.source_file:
-        import os.path
-        if len(args) == 1:
-            options.source_file = args[0]
-        else:
-            print ("no file name given\n" + usage)
-            sys.exit(1)
-    return options, args
-
-if __name__ == '__main__':
-    options, args = parse_args()
-
-    hopsize = options.hopsize
-    bufsize = options.bufsize
-    samplerate = options.samplerate
-    source_file = options.source_file
-
-    from aubio import onset, tempo, source, sink
-
-    s = source(source_file, samplerate, hopsize)
-    if samplerate == 0: samplerate = s.get_samplerate()
-
-    if options.beat:
-        o = tempo(options.onset_method, bufsize, hopsize)
-    else:
-        o = onset(options.onset_method, bufsize, hopsize)
-        if options.minioi:
-            if options.minioi.endswith('ms'):
-                o.set_minioi_ms(int(options.minioi[:-2]))
-            elif options.minioi.endswith('s'):
-                o.set_minioi_s(int(options.minioi[:-1]))
-            else:
-                o.set_minioi(int(options.minioi))
-    o.set_threshold(options.threshold)
-
-    timestamps = []
-    total_frames = 0
-    # analyze pass
-    while True:
-        samples, read = s()
-        if o(samples):
-            timestamps.append (o.get_last())
-            if options.verbose: print ("%.4f" % o.get_last_s())
-        total_frames += read
-        if read < hopsize: break
-    del s
-    # print some info
-    nstamps = len(timestamps)
-    duration = float (total_frames) / float(samplerate)
-    info = 'found %(nstamps)d timestamps in %(source_file)s' % locals()
-    info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
-    sys.stderr.write(info)
-
-    # cutting pass
-    if options.cut and nstamps > 0:
-        # generate output files
-        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")
-        if options.cut_until_nsamples:
-            timestamps_end = [t + options.cut_until_nsamples for t in timestamps[1:]]
-            timestamps_end += [ 1e120 ]
-        if options.cut_until_nslices:
-            timestamps_end = [t for t in timestamps[1 + options.cut_until_nslices:]]
-            timestamps_end += [ 1e120 ] * (options.cut_until_nslices + 1)
-        slice_source_at_stamps(source_file, timestamps, timestamps_end = timestamps_end,
-                output_dir = options.output_directory,
-                samplerate = samplerate)
-
-        # print some info
-        duration = float (total_frames) / float(samplerate)
-        info = 'created %(nstamps)d slices from %(source_file)s' % locals()
-        info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
-        sys.stderr.write(info)
--- /dev/null
+++ b/python/tests/__init__.py
@@ -1,0 +1,1 @@
+
--- a/python/tests/eval_pitch
+++ b/python/tests/eval_pitch
@@ -24,7 +24,7 @@
 import time
 import os.path
 import numpy
-from utils import array_from_text_file, array_from_yaml_file
+from .utils import array_from_text_file, array_from_yaml_file
 from aubio import source, pitch, freqtomidi
 
 start = time.time()
--- a/python/tests/test_aubio.py
+++ b/python/tests/test_aubio.py
@@ -9,6 +9,11 @@
         """ try importing aubio """
         import aubio
 
+    def test_version(self):
+        """ test aubio.version """
+        import aubio
+        self.assertEqual('0', aubio.version[0])
+
 if __name__ == '__main__':
     main()
 
--- /dev/null
+++ b/python/tests/test_aubio_cmd.py
@@ -1,0 +1,34 @@
+#! /usr/bin/env python
+
+import aubio.cmd
+from nose2 import main
+from numpy.testing import TestCase
+
+class aubio_cmd(TestCase):
+
+    def setUp(self):
+        self.a_parser = aubio.cmd.aubio_parser()
+
+    def test_default_creation(self):
+        try:
+            assert self.a_parser.parse_args(['-V']).show_version
+        except SystemExit:
+            url = 'https://bugs.python.org/issue9253'
+            self.skipTest('subcommand became optional in py3, see %s' % url)
+
+class aubio_cmd_utils(TestCase):
+
+    def test_samples2seconds(self):
+        self.assertEqual(aubio.cmd.samples2seconds(3200, 32000),
+                "0.100000\t")
+
+    def test_samples2milliseconds(self):
+        self.assertEqual(aubio.cmd.samples2milliseconds(3200, 32000),
+                "100.000000\t")
+
+    def test_samples2samples(self):
+        self.assertEqual(aubio.cmd.samples2samples(3200, 32000),
+                "3200\t")
+
+if __name__ == '__main__':
+    main()
--- /dev/null
+++ b/python/tests/test_aubio_cut.py
@@ -1,0 +1,16 @@
+#! /usr/bin/env python
+
+import aubio.cut
+from nose2 import main
+from numpy.testing import TestCase
+
+class aubio_cut(TestCase):
+
+    def setUp(self):
+        self.a_parser = aubio.cut.aubio_cut_parser()
+
+    def test_default_creation(self):
+        assert self.a_parser.parse_args(['-v']).verbose
+
+if __name__ == '__main__':
+    main()
--- /dev/null
+++ b/python/tests/test_dct.py
@@ -1,0 +1,68 @@
+#! /usr/bin/env python
+
+
+import numpy as np
+from numpy.testing import TestCase, assert_almost_equal
+import aubio
+
+precomputed_arange = [ 9.89949512, -6.44232273,  0., -0.67345482, 0.,
+        -0.20090288, 0., -0.05070186]
+
+precomputed_some_ones = [ 4.28539848,  0.2469689,  -0.14625292, -0.58121818,
+        -0.83483052, -0.75921834, -0.35168475,  0.24087936,
+        0.78539824, 1.06532764,  0.97632152,  0.57164496, 0.03688532,
+        -0.39446154, -0.54619485, -0.37771079]
+
+class aubio_dct(TestCase):
+
+    def test_init(self):
+        """ test that aubio.dct() is created with expected size """
+        a_dct = aubio.dct()
+        self.assertEqual(a_dct.size, 1024)
+
+    def test_arange(self):
+        """ test that dct(arange(8)) is computed correctly
+
+        >>> from scipy.fftpack import dct
+        >>> a_in = np.arange(8).astype(aubio.float_type)
+        >>> precomputed = dct(a_in, norm='ortho')
+        """
+        N = len(precomputed_arange)
+        a_dct = aubio.dct(8)
+        a_in = np.arange(8).astype(aubio.float_type)
+        a_expected = aubio.fvec(precomputed_arange)
+        assert_almost_equal(a_dct(a_in), a_expected, decimal=5)
+
+    def test_some_ones(self):
+        """ test that dct(somevector) is computed correctly """
+        a_dct = aubio.dct(16)
+        a_in = np.ones(16).astype(aubio.float_type)
+        a_in[1] = 0
+        a_in[3] = np.pi
+        a_expected = aubio.fvec(precomputed_some_ones)
+        assert_almost_equal(a_dct(a_in), a_expected, decimal=6)
+
+    def test_reconstruction(self):
+        """ test that some_ones vector can be recontructed """
+        a_dct = aubio.dct(16)
+        a_in = np.ones(16).astype(aubio.float_type)
+        a_in[1] = 0
+        a_in[3] = np.pi
+        a_dct_in = a_dct(a_in)
+        a_dct_reconstructed = a_dct.rdo(a_dct_in)
+        assert_almost_equal(a_dct_reconstructed, a_in, decimal=6)
+
+    def test_negative_size(self):
+        """ test that creation fails with a negative size """
+        with self.assertRaises(ValueError):
+            aubio.dct(-1)
+
+    def test_wrong_size(self):
+        """ test that creation fails with a non power-of-two size """
+        # supports for non 2** fft sizes only when compiled with fftw3
+        size = 13
+        try:
+            with self.assertRaises(RuntimeError):
+                aubio.dct(size)
+        except AssertionError:
+            self.skipTest('creating aubio.dct with size %d did not fail' % size)
--- a/python/tests/test_fft.py
+++ b/python/tests/test_fft.py
@@ -33,7 +33,14 @@
         f = fft (win_s)
         fftgrain = f (timegrain)
         assert_equal ( fftgrain.norm, 0 )
-        assert_equal ( fftgrain.phas, 0 )
+        try:
+            assert_equal ( fftgrain.phas, 0 )
+        except AssertionError:
+            assert_equal (fftgrain.phas[fftgrain.phas > 0], +pi)
+            assert_equal (fftgrain.phas[fftgrain.phas < 0], -pi)
+            assert_equal (np.abs(fftgrain.phas[np.abs(fftgrain.phas) != pi]), 0)
+            self.skipTest('fft(fvec(%d)).phas != +0, ' % win_s \
+                    + 'This is expected when using fftw3 on powerpc.')
 
     def test_impulse(self):
         """ check the transform of one impulse at a random place """
@@ -135,6 +142,37 @@
         assert_almost_equal ( r[0], impulse, decimal = 6)
         assert_almost_equal ( r[1:], 0)
 
+class aubio_fft_odd_sizes(TestCase):
+
+    def test_reconstruct_with_odd_size(self):
+        win_s = 29
+        self.recontruct(win_s, 'odd sizes not supported')
+
+    def test_reconstruct_with_radix15(self):
+        win_s = 2 ** 4 * 15
+        self.recontruct(win_s, 'radix 15 supported')
+
+    def test_reconstruct_with_radix5(self):
+        win_s = 2 ** 4 * 5
+        self.recontruct(win_s, 'radix 5 supported')
+
+    def test_reconstruct_with_radix3(self):
+        win_s = 2 ** 4 * 3
+        self.recontruct(win_s, 'radix 3 supported')
+
+    def recontruct(self, win_s, skipMessage):
+        try:
+            f = fft(win_s)
+        except RuntimeError:
+            self.skipTest(skipMessage)
+        input_signal = fvec(win_s)
+        input_signal[win_s//2] = 1
+        c = f(input_signal)
+        output_signal = f.rdo(c)
+        assert_almost_equal(input_signal, output_signal)
+
+class aubio_fft_wrong_params(TestCase):
+
     def test_large_input_timegrain(self):
         win_s = 1024
         f = fft(win_s)
@@ -163,21 +201,10 @@
         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
--- a/python/tests/test_filter.py
+++ b/python/tests/test_filter.py
@@ -3,7 +3,7 @@
 from unittest import main
 from numpy.testing import TestCase, assert_equal, assert_almost_equal
 from aubio import fvec, digital_filter
-from utils import array_from_text_file
+from .utils import array_from_text_file
 
 class aubio_filter_test_case(TestCase):
 
@@ -76,6 +76,16 @@
         f = digital_filter(4)
         with self.assertRaises(ValueError):
             f.set_biquad(0., 0., 0, 0., 0.)
+
+    def test_all_available_presets(self):
+        f = digital_filter(7)
+        for sr in [8000, 11025, 16000, 22050, 24000, 32000,
+                44100, 48000, 88200, 96000, 192000]:
+            f.set_a_weighting(sr)
+        f = digital_filter(5)
+        for sr in [8000, 11025, 16000, 22050, 24000, 32000,
+                44100, 48000, 88200, 96000, 192000]:
+            f.set_c_weighting(sr)
 
 class aubio_filter_wrong_params(TestCase):
 
--- a/python/tests/test_filterbank.py
+++ b/python/tests/test_filterbank.py
@@ -1,11 +1,10 @@
 #! /usr/bin/env python
 
-from unittest import main
-from numpy.testing import TestCase
-from numpy.testing import assert_equal, assert_almost_equal
 import numpy as np
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+
 from aubio import cvec, filterbank, float_type
-from utils import array_from_text_file
+from .utils import array_from_text_file
 
 class aubio_filterbank_test_case(TestCase):
 
@@ -62,6 +61,13 @@
         f.set_mel_coeffs_slaney(16000)
         assert_almost_equal ( expected, f.get_coeffs() )
 
+    def test_mfcc_coeffs_get_coeffs(self):
+        f = filterbank(40, 512)
+        coeffs = f.get_coeffs()
+        self.assertIsInstance(coeffs, np.ndarray)
+        assert_equal (coeffs, 0)
+        assert_equal (np.shape(coeffs), (40, 512 / 2 + 1))
+
 class aubio_filterbank_wrong_values(TestCase):
 
     def test_negative_window(self):
@@ -81,4 +87,5 @@
             f(cvec(256))
 
 if __name__ == '__main__':
-    main()
+    import nose2
+    nose2.main()
--- a/python/tests/test_filterbank_mel.py
+++ b/python/tests/test_filterbank_mel.py
@@ -1,11 +1,13 @@
 #! /usr/bin/env python
 
-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, float_type
+import numpy as np
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
 
+from aubio import fvec, cvec, filterbank, float_type
+
+import warnings
+warnings.filterwarnings('ignore', category=UserWarning, append=True)
+
 class aubio_filterbank_mel_test_case(TestCase):
 
     def test_slaney(self):
@@ -12,33 +14,33 @@
         f = filterbank(40, 512)
         f.set_mel_coeffs_slaney(16000)
         a = f.get_coeffs()
-        assert_equal(shape (a), (40, 512/2 + 1) )
+        assert_equal(np.shape (a), (40, 512/2 + 1) )
 
     def test_other_slaney(self):
         f = filterbank(40, 512*2)
         f.set_mel_coeffs_slaney(44100)
-        _ = f.get_coeffs()
+        self.assertIsInstance(f.get_coeffs(), np.ndarray)
         #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))
+            self.assertIsInstance(f.get_coeffs(), np.ndarray)
 
     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)
+        freqs = np.array(freq_list, dtype = float_type)
         f.set_triangle_bands(freqs, 48000)
-        _ = f.get_coeffs().T
         assert_equal ( f(cvec(1024)), 0)
+        self.assertIsInstance(f.get_coeffs(), np.ndarray)
 
     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)
+        freqs = np.array(freq_list, dtype = float_type)
         f.set_triangle_bands(freqs, 48000)
-        _ = f.get_coeffs().T
+        self.assertIsInstance(f.get_coeffs(), np.ndarray)
         spec = cvec(1024)
         spec.norm[:] = 1
         assert_almost_equal ( f(spec),
@@ -45,5 +47,126 @@
                 [ 0.02070313, 0.02138672, 0.02127604, 0.02135417,
                     0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345])
 
+    def test_triangle_freqs_with_zeros(self):
+        """make sure set_triangle_bands works when list starts with 0"""
+        freq_list = [0, 40, 80]
+        freqs = np.array(freq_list, dtype = float_type)
+        f = filterbank(len(freqs)-2, 1024)
+        f.set_triangle_bands(freqs, 48000)
+        assert_equal ( f(cvec(1024)), 0)
+        self.assertIsInstance(f.get_coeffs(), np.ndarray)
+
+    def test_triangle_freqs_with_wrong_negative(self):
+        """make sure set_triangle_bands fails when list contains a negative"""
+        freq_list = [-10, 0, 80]
+        f = filterbank(len(freq_list)-2, 1024)
+        with self.assertRaises(ValueError):
+            f.set_triangle_bands(fvec(freq_list), 48000)
+
+    def test_triangle_freqs_with_wrong_ordering(self):
+        """make sure set_triangle_bands fails when list not ordered"""
+        freq_list = [0, 80, 40]
+        f = filterbank(len(freq_list)-2, 1024)
+        with self.assertRaises(ValueError):
+            f.set_triangle_bands(fvec(freq_list), 48000)
+
+    def test_triangle_freqs_with_large_freq(self):
+        """make sure set_triangle_bands warns when freq > nyquist"""
+        samplerate = 22050
+        freq_list = [0, samplerate//4, samplerate // 2 + 1]
+        f = filterbank(len(freq_list)-2, 1024)
+        # TODO add assert_warns
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+
+    def test_triangle_freqs_with_not_enough_filters(self):
+        """make sure set_triangle_bands warns when not enough filters"""
+        samplerate = 22050
+        freq_list = [0, 100, 1000, 4000, 8000, 10000]
+        f = filterbank(len(freq_list)-3, 1024)
+        # TODO add assert_warns
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+
+    def test_triangle_freqs_with_too_many_filters(self):
+        """make sure set_triangle_bands warns when too many filters"""
+        samplerate = 22050
+        freq_list = [0, 100, 1000, 4000, 8000, 10000]
+        f = filterbank(len(freq_list)-1, 1024)
+        # TODO add assert_warns
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+
+    def test_triangle_freqs_with_double_value(self):
+        """make sure set_triangle_bands works with 2 duplicate freqs"""
+        samplerate = 22050
+        freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000]
+        f = filterbank(len(freq_list)-2, 1024)
+        # TODO add assert_warns
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+
+    def test_triangle_freqs_with_triple(self):
+        """make sure set_triangle_bands works with 3 duplicate freqs"""
+        samplerate = 22050
+        freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000]
+        f = filterbank(len(freq_list)-2, 1024)
+        # TODO add assert_warns
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+
+    def test_triangle_freqs_without_norm(self):
+        """make sure set_triangle_bands works without """
+        samplerate = 22050
+        freq_list = fvec([0, 100, 1000, 10000])
+        f = filterbank(len(freq_list) - 2, 1024)
+        f.set_norm(0)
+        f.set_triangle_bands(freq_list, samplerate)
+        expected = f.get_coeffs()
+        f.set_norm(1)
+        f.set_triangle_bands(fvec(freq_list), samplerate)
+        assert_almost_equal(f.get_coeffs().T,
+                expected.T * 2. / (freq_list[2:] - freq_list[:-2]))
+
+    def test_triangle_freqs_wrong_norm(self):
+        f = filterbank(10, 1024)
+        with self.assertRaises(ValueError):
+            f.set_norm(-1)
+
+    def test_triangle_freqs_with_power(self):
+        f = filterbank(9, 1024)
+        freqs = fvec([40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000,
+            24000])
+        f.set_power(2)
+        f.set_triangle_bands(freqs, 48000)
+        spec = cvec(1024)
+        spec.norm[:] = .1
+        expected = fvec([0.02070313, 0.02138672, 0.02127604, 0.02135417,
+            0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345])
+        expected /= 100.
+        assert_almost_equal(f(spec), expected)
+
+    def test_mel_coeffs(self):
+        f = filterbank(40, 1024)
+        f.set_mel_coeffs(44100, 0, 44100 / 2)
+
+    def test_zero_fmax(self):
+        f = filterbank(40, 1024)
+        f.set_mel_coeffs(44100, 0, 0)
+
+    def test_wrong_mel_coeffs(self):
+        f = filterbank(40, 1024)
+        with self.assertRaises(ValueError):
+            f.set_mel_coeffs_slaney(0)
+        with self.assertRaises(ValueError):
+            f.set_mel_coeffs(44100, 0, -44100 / 2)
+        with self.assertRaises(ValueError):
+            f.set_mel_coeffs(44100, -0.1, 44100 / 2)
+        with self.assertRaises(ValueError):
+            f.set_mel_coeffs(-44100, 0.1, 44100 / 2)
+        with self.assertRaises(ValueError):
+            f.set_mel_coeffs_htk(-1, 0, 0)
+
+    def test_mel_coeffs_htk(self):
+        f = filterbank(40, 1024)
+        f.set_mel_coeffs_htk(44100, 0, 44100 / 2)
+
+
 if __name__ == '__main__':
-    main()
+    import nose2
+    nose2.main()
--- a/python/tests/test_fvec.py
+++ b/python/tests/test_fvec.py
@@ -60,6 +60,14 @@
         self.assertRaises(IndexError, a.__getitem__, 3)
         self.assertRaises(IndexError, a.__getitem__, 2)
 
+    def test_wrong_dimensions(self):
+        a = np.array([[[1, 2], [3, 4]]], dtype=float_type)
+        self.assertRaises(ValueError, fvec, a)
+
+    def test_wrong_size(self):
+        a = np.ndarray([0,], dtype=float_type)
+        self.assertRaises(ValueError, fvec, a)
+
 class aubio_wrong_fvec_input(TestCase):
     """ uses min_removal to test PyAubio_IsValidVector """
 
--- /dev/null
+++ b/python/tests/test_fvec_shift.py
@@ -1,0 +1,35 @@
+#! /usr/bin/env python
+
+import numpy as np
+from numpy.testing import TestCase, assert_equal
+import aubio
+
+class aubio_shift_test_case(TestCase):
+
+    def run_shift_ishift(self, n):
+        ramp = np.arange(n, dtype=aubio.float_type)
+        # construct expected output
+        # even length: [5. 6. 7. 8. 9. 0. 1. 2. 3. 4.]
+        # odd length: [4. 5. 6. 0. 1. 2. 3.]
+        half = n - n//2
+        expected = np.concatenate([np.arange(half, n), np.arange(half)])
+        # shift in place, returns modified copy
+        assert_equal(aubio.shift(ramp), expected)
+        # check input was changed as expected
+        assert_equal(ramp, expected)
+        # construct expected output
+        expected = np.arange(n)
+        # revert shift in place, returns modifed copy
+        assert_equal(aubio.ishift(ramp), expected)
+        # check input was shifted back
+        assert_equal(ramp, expected)
+
+    def test_can_shift_fvec(self):
+        self.run_shift_ishift(10)
+
+    def test_can_shift_fvec_odd(self):
+        self.run_shift_ishift(7)
+
+from unittest import main
+if __name__ == '__main__':
+    main()
--- /dev/null
+++ b/python/tests/test_hztomel.py
@@ -1,0 +1,109 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+from numpy.testing import assert_equal, assert_almost_equal
+import numpy as np
+import aubio
+
+from aubio import hztomel, meltohz
+from aubio import hztomel_htk, meltohz_htk
+
+
+class aubio_hztomel_test_case(TestCase):
+
+    def test_hztomel(self):
+        assert_equal(hztomel(0.), 0.)
+        assert_almost_equal(hztomel(400. / 3.), 2., decimal=5)
+        assert_almost_equal(hztomel(1000. / 3), 5.)
+        assert_equal(hztomel(200.), 3.)
+        assert_almost_equal(hztomel(1000.), 15)
+        assert_almost_equal(hztomel(6400), 42)
+        assert_almost_equal(hztomel(40960), 69)
+
+        for m in np.linspace(0, 1000, 100):
+            assert_almost_equal(hztomel(meltohz(m)) - m, 0, decimal=3)
+
+    def test_meltohz(self):
+        assert_equal(meltohz(0.), 0.)
+        assert_almost_equal(meltohz(2), 400. / 3., decimal=4)
+        assert_equal(meltohz(3.), 200.)
+        assert_almost_equal(meltohz(5), 1000. / 3., decimal=4)
+        assert_almost_equal(meltohz(15), 1000., decimal=4)
+        assert_almost_equal(meltohz(42), 6400., decimal=2)
+        assert_almost_equal(meltohz(69), 40960., decimal=1)
+
+        for f in np.linspace(0, 20000, 1000):
+            assert_almost_equal(meltohz(hztomel(f)) - f, 0, decimal=1)
+
+    def test_meltohz_negative(self):
+        # TODO add assert_warns
+        assert_equal(meltohz(-1), 0)
+
+    def test_hztomel_negative(self):
+        # TODO add assert_warns
+        assert_equal(hztomel(-1), 0)
+
+
+class aubio_hztomel_htk_test_case(TestCase):
+
+    def test_meltohz(self):
+        assert_equal(meltohz(0, htk=True), 0)
+        assert_almost_equal(meltohz(2595, htk=True), 6300., decimal=1)
+
+    def test_hztomel(self):
+        assert_equal(hztomel(0, htk=True), 0)
+        assert_almost_equal(hztomel(3428.7, htk=True), 2000., decimal=1)
+        assert_almost_equal(hztomel(6300, htk=True), 2595., decimal=1)
+
+    def test_meltohz_negative(self):
+        # TODO add assert_warns
+        assert_equal(meltohz(-1, htk=True), 0)
+        assert_almost_equal(meltohz(2000, htk=True), 3428.7, decimal=1)
+        assert_almost_equal(meltohz(1000, htk=True), 1000., decimal=1)
+
+    def test_hztomel_negative(self):
+        # TODO add assert_warns
+        assert_equal(hztomel(-1, htk=True), 0)
+        assert_almost_equal(hztomel(1000, htk=True), 1000., decimal=1)
+
+    def test_hztomel_htk(self):
+        for f in np.linspace(0, 20000, 1000):
+            assert_almost_equal(meltohz_htk(hztomel_htk(f)) - f, 0, decimal=1)
+        for f in np.linspace(0, 20000, 1000):
+            assert_almost_equal(hztomel_htk(meltohz_htk(f)) - f, 0, decimal=1)
+
+
+class aubio_hztomel_wrong_values(TestCase):
+    """ more tests to cover all branches """
+
+    def test_hztomel_wrong_values(self):
+        with self.assertRaises(TypeError):
+            hztomel('s')
+
+    def test_meltohz_wrong_values(self):
+        with self.assertRaises(TypeError):
+            meltohz(bytes('ad'))
+
+    def test_meltohz_no_arg(self):
+        with self.assertRaises(TypeError):
+            meltohz()
+
+    def test_meltohz_htk_no_arg(self):
+        with self.assertRaises(TypeError):
+            meltohz_htk()
+
+    def test_hztomel_htk_wrong_values(self):
+        with self.assertRaises(TypeError):
+            hztomel_htk('0')
+
+    def test_hztomel_htk_false(self):
+        assert hztomel(120, htk=False) == hztomel(120)
+
+    def test_meltohz_htk_false(self):
+        assert meltohz(12, htk=False) == meltohz(12)
+
+
+if __name__ == '__main__':
+    from unittest import main
+    main()
--- a/python/tests/test_mfcc.py
+++ b/python/tests/test_mfcc.py
@@ -110,5 +110,42 @@
             o(spec)
         #print coeffs
 
+
+class aubio_mfcc_fb_params(TestCase):
+
+    def test_set_scale(self):
+        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
+        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        m.set_scale(10.5)
+        assert m.get_scale() == 10.5
+        m(cvec(buf_size))
+
+    def test_set_power(self):
+        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
+        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        m.set_power(2.5)
+        assert m.get_power() == 2.5
+        m(cvec(buf_size))
+
+    def test_set_mel_coeffs(self):
+        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
+        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        m.set_mel_coeffs(0., samplerate/2.)
+        m(cvec(buf_size))
+
+    def test_set_mel_coeffs_htk(self):
+        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
+        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        m.set_mel_coeffs_htk(0., samplerate/2.)
+        m(cvec(buf_size))
+
+    def test_set_mel_coeffs_slaney(self):
+        buf_size, n_filters, n_coeffs, samplerate = 512, 40, 10, 16000
+        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+        m.set_mel_coeffs_slaney()
+        m(cvec(buf_size))
+        assert m.get_power() == 1
+        assert m.get_scale() == 1
+
 if __name__ == '__main__':
     main()
--- a/python/tests/test_midi2note.py
+++ b/python/tests/test_midi2note.py
@@ -2,6 +2,7 @@
 # -*- coding: utf-8 -*-
 
 from aubio import midi2note
+from nose2.tools import params
 import unittest
 
 list_of_known_midis = (
@@ -16,10 +17,10 @@
 
 class midi2note_good_values(unittest.TestCase):
 
-    def test_midi2note_known_values(self):
+    @params(*list_of_known_midis)
+    def test_midi2note_known_values(self, midi, note):
         " known values are correctly converted "
-        for midi, note in list_of_known_midis:
-            self.assertEqual ( midi2note(midi), note )
+        self.assertEqual ( midi2note(midi), note )
 
 class midi2note_wrong_values(unittest.TestCase):
 
@@ -40,4 +41,5 @@
         self.assertRaises(TypeError, midi2note, "a")
 
 if __name__ == '__main__':
-    unittest.main()
+    import nose2
+    nose2.main()
--- a/python/tests/test_note2midi.py
+++ b/python/tests/test_note2midi.py
@@ -3,7 +3,8 @@
 
 from __future__ import unicode_literals
 
-from aubio import note2midi, freq2note
+from aubio import note2midi, freq2note, note2freq, float_type
+from nose2.tools import params
 import unittest
 
 list_of_known_notes = (
@@ -13,24 +14,57 @@
         ( 'C3', 48 ),
         ( 'B3', 59 ),
         ( 'B#3', 60 ),
+        ( 'C♯4', 61 ),
         ( 'A4', 69 ),
         ( 'A#4', 70 ),
+        ( 'A♯4', 70 ),
+        ( 'A\u266f4', 70 ),
         ( 'Bb4', 70 ),
         ( 'B♭4', 70 ),
+        ( 'B\u266d4', 70 ),
         ( 'G8', 115 ),
         ( 'G♯8', 116 ),
         ( 'G9', 127 ),
-        ( 'G\udd2a2', 45 ),
-        ( 'B\ufffd2', 45 ),
         ( 'A♮2', 45 ),
         )
 
+list_of_known_notes_with_unicode_issues = (
+        ('C𝄪4', 62 ),
+        ('E𝄫4', 62 ),
+        )
+
+list_of_unknown_notes = (
+        ( 'G\udd2a2' ),
+        ( 'B\ufffd2' ),
+        ( 'B\u266e\u266e2' ),
+        ( 'B\u266f\u266d3' ),
+        ( 'B33' ),
+        ( 'C.3' ),
+        ( 'A' ),
+        ( '2' ),
+        )
+
 class note2midi_good_values(unittest.TestCase):
 
-    def test_note2midi_known_values(self):
+    @params(*list_of_known_notes)
+    def test_note2midi_known_values(self, note, midi):
         " known values are correctly converted "
-        for note, midi in list_of_known_notes:
+        self.assertEqual ( note2midi(note), midi )
+
+    @params(*list_of_known_notes_with_unicode_issues)
+    def test_note2midi_known_values_with_unicode_issues(self, note, midi):
+        " known values are correctly converted, unless decoding is expected to fail"
+        try:
             self.assertEqual ( note2midi(note), midi )
+        except UnicodeEncodeError as e:
+            import sys
+            strfmt = "len(u'\\U0001D12A') != 1, excpected decoding failure | {:s} | {:s} {:s}"
+            strres = strfmt.format(e, sys.platform, sys.version)
+            # happens with: darwin 2.7.10, windows 2.7.12
+            if len('\U0001D12A') != 1 and sys.version[0] == '2':
+                self.skipTest(strres + " | upgrade to Python 3 to fix")
+            else:
+                raise
 
 class note2midi_wrong_values(unittest.TestCase):
 
@@ -66,12 +100,38 @@
         " fails when passed a non-string value "
         self.assertRaises(TypeError, note2midi, 123)
 
+    def test_note2midi_wrong_data_too_long(self):
+        " fails when passed a note with a note name longer than expected"
+        self.assertRaises(ValueError, note2midi, 'CB+-3')
 
+    @params(*list_of_unknown_notes)
+    def test_note2midi_unknown_values(self, note):
+        " unknown values throw out an error "
+        self.assertRaises(ValueError, note2midi, note)
+
 class freq2note_simple_test(unittest.TestCase):
 
-    def test_freq2note(self):
+    def test_freq2note_above(self):
         " make sure freq2note(441) == A4 "
         self.assertEqual("A4", freq2note(441))
 
+    def test_freq2note_under(self):
+        " make sure freq2note(439) == A4 "
+        self.assertEqual("A4", freq2note(439))
+
+class note2freq_simple_test(unittest.TestCase):
+
+    def test_note2freq(self):
+        " make sure note2freq('A3') == 220"
+        self.assertEqual(220, note2freq("A3"))
+
+    def test_note2freq_under(self):
+        " make sure note2freq(A4) == 440"
+        if float_type == 'float32':
+            self.assertEqual(440, note2freq("A4"))
+        else:
+            self.assertLess(abs(note2freq("A4")-440), 1.e-12)
+
 if __name__ == '__main__':
-    unittest.main()
+    import nose2
+    nose2.main()
--- /dev/null
+++ b/python/tests/test_notes.py
@@ -1,0 +1,95 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import notes
+
+AUBIO_DEFAULT_NOTES_SILENCE = -70.
+AUBIO_DEFAULT_NOTES_RELEASE_DROP = 10.
+AUBIO_DEFAULT_NOTES_MINIOI_MS = 30.
+
+class aubio_notes_default(TestCase):
+
+    def test_members(self):
+        o = notes()
+        assert_equal ([o.buf_size, o.hop_size, o.method, o.samplerate],
+            [1024,512,'default',44100])
+
+
+class aubio_notes_params(TestCase):
+
+    samplerate = 44100
+
+    def setUp(self):
+        self.o = notes(samplerate = self.samplerate)
+
+    def test_get_minioi_ms(self):
+        assert_equal (self.o.get_minioi_ms(), AUBIO_DEFAULT_NOTES_MINIOI_MS)
+
+    def test_set_minioi_ms(self):
+        val = 40.
+        self.o.set_minioi_ms(val)
+        assert_almost_equal (self.o.get_minioi_ms(), val)
+
+    def test_get_silence(self):
+        assert_equal (self.o.get_silence(), AUBIO_DEFAULT_NOTES_SILENCE)
+
+    def test_set_silence(self):
+        val = -50
+        self.o.set_silence(val)
+        assert_equal (self.o.get_silence(), val)
+
+    def test_get_release_drop(self):
+        assert_equal (self.o.get_release_drop(), AUBIO_DEFAULT_NOTES_RELEASE_DROP)
+
+    def test_set_release_drop(self):
+        val = 50
+        self.o.set_release_drop(val)
+        assert_equal (self.o.get_release_drop(), val)
+
+    def test_set_release_drop_wrong(self):
+        val = -10
+        with self.assertRaises(ValueError):
+            self.o.set_release_drop(val)
+
+from .utils import list_all_sounds
+list_of_sounds = list_all_sounds('sounds')
+
+class aubio_notes_sinewave(TestCase):
+
+    def analyze_file(self, filepath, samplerate=0):
+        from aubio import source
+        import numpy as np
+        win_s = 512 # fft size
+        hop_s = 256 # hop size
+
+        s = source(filepath, samplerate, hop_s)
+        samplerate = s.samplerate
+
+        tolerance = 0.8
+
+        notes_o = notes("default", win_s, hop_s, samplerate)
+        total_frames = 0
+
+        results = []
+        while True:
+            samples, read = s()
+            new_note = notes_o(samples)
+            if (new_note[0] != 0):
+                note_str = ' '.join(["%.2f" % i for i in new_note])
+                results.append( [total_frames, np.copy(new_note)] )
+            total_frames += read
+            if read < hop_s: break
+        return results
+
+    def test_sinewave(self):
+        for filepath in list_of_sounds:
+            if '44100Hz_44100f_sine441.wav' in filepath:
+                results = self.analyze_file(filepath)
+                assert_equal (len(results), 1)
+                assert_equal (len(results[0]), 2)
+                assert_equal (results[0][0], 1280)
+                assert_equal (results[0][1], [69, 123, -1])
+
+if __name__ == '__main__':
+    main()
--- a/python/tests/test_onset.py
+++ b/python/tests/test_onset.py
@@ -2,7 +2,7 @@
 
 from unittest import main
 from numpy.testing import TestCase, assert_equal, assert_almost_equal
-from aubio import onset
+from aubio import onset, fvec
 
 class aubio_onset_default(TestCase):
 
@@ -19,25 +19,25 @@
         self.o = onset(samplerate = self.samplerate)
 
     def test_get_delay(self):
-        assert_equal (self.o.get_delay(), int(4.3 * self.o.hop_size))
+        self.assertGreater(self.o.get_delay(), 0)
 
     def test_get_delay_s(self):
-        assert_almost_equal (self.o.get_delay_s(), self.o.get_delay() / float(self.samplerate))
+        self.assertGreater(self.o.get_delay_s(), 0.)
 
     def test_get_delay_ms(self):
-        assert_almost_equal (self.o.get_delay_ms(), self.o.get_delay() * 1000. / self.samplerate, 5)
+        self.assertGreater(self.o.get_delay_ms(), 0.)
 
     def test_get_minioi(self):
-        assert_almost_equal (self.o.get_minioi(), 0.02 * self.samplerate)
+        self.assertGreater(self.o.get_minioi(), 0)
 
     def test_get_minioi_s(self):
-        assert_almost_equal (self.o.get_minioi_s(), 0.02)
+        self.assertGreater(self.o.get_minioi_s(), 0.)
 
     def test_get_minioi_ms(self):
-        assert_equal (self.o.get_minioi_ms(), 20.)
+        self.assertGreater(self.o.get_minioi_ms(), 0.)
 
     def test_get_threshold(self):
-        assert_almost_equal (self.o.get_threshold(), 0.3)
+        self.assertGreater(self.o.get_threshold(), 0.)
 
     def test_set_delay(self):
         val = 256
@@ -82,6 +82,38 @@
 
 class aubio_onset_8000(aubio_onset_params):
     samplerate = 8000
+
+class aubio_onset_coverate(TestCase):
+    # extra tests to execute the C routines and improve coverage
+
+    def test_all_methods(self):
+        for method in ['default', 'energy', 'hfc', 'complexdomain', 'complex',
+                'phase', 'wphase', 'mkl', 'kl', 'specflux', 'specdiff',
+                'old_default']:
+            o = onset(method=method, buf_size=512, hop_size=256)
+            o(fvec(256))
+
+    def test_get_methods(self):
+        o = onset(method='default', buf_size=512, hop_size=256)
+
+        assert o.get_silence() == -70
+        o.set_silence(-20)
+        assert_almost_equal(o.get_silence(), -20)
+
+        assert o.get_compression() == 1
+        o.set_compression(.99)
+        assert_almost_equal(o.get_compression(), .99)
+
+        assert o.get_awhitening() == 0
+        o.set_awhitening(1)
+        assert o.get_awhitening() == 1
+
+        o.get_last()
+        o.get_last_ms()
+        o.get_last_s()
+        o.get_descriptor()
+        o.get_thresholded_descriptor()
+
 
 if __name__ == '__main__':
     main()
--- a/python/tests/test_phasevoc.py
+++ b/python/tests/test_phasevoc.py
@@ -46,8 +46,24 @@
             r = f.rdo(s)
             assert_equal ( t, 0.)
             assert_equal ( s.norm, 0.)
-            assert_equal ( s.phas, 0.)
+            try:
+                assert_equal ( s.phas, 0 )
+            except AssertionError:
+                assert_equal (s.phas[s.phas > 0], +np.pi)
+                assert_equal (s.phas[s.phas < 0], -np.pi)
+                assert_equal (np.abs(s.phas[np.abs(s.phas) != np.pi]), 0)
+                self.skipTest('pvoc(fvec(%d)).phas != +0, ' % win_s \
+                        + 'This is expected when using fftw3 on powerpc.')
             assert_equal ( r, 0.)
+
+    def test_no_overlap(self):
+        win_s, hop_s = 1024, 1024
+        f = pvoc (win_s, hop_s)
+        t = fvec (hop_s)
+        for _ in range(4):
+            s = f(t)
+            r = f.rdo(s)
+            assert_equal ( t, 0.)
 
     @params(
             ( 256, 8),
--- a/python/tests/test_pitch.py
+++ b/python/tests/test_pitch.py
@@ -70,8 +70,8 @@
         #print 'len(pitches), cut:', len(pitches), cut
         #print 'median errors: ', median(errors), 'median pitches: ', median(pitches)
 
-pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" , "specacf" ]
-pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" ]
+pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" , "specacf" ]
+pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" ]
 
 #freqs = [ 27.5, 55., 110., 220., 440., 880., 1760., 3520. ]
 freqs = [             110., 220., 440., 880., 1760., 3520. ]
--- a/python/tests/test_sink.py
+++ b/python/tests/test_sink.py
@@ -4,8 +4,11 @@
 from nose2.tools import params
 from numpy.testing import TestCase
 from aubio import fvec, source, sink
-from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
+from .utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
 
+import warnings
+warnings.filterwarnings('ignore', category=UserWarning, append=True)
+
 list_of_sounds = list_all_sounds('sounds')
 samplerates = [0, 44100, 8000, 32000]
 hop_sizes = [512, 1024, 64]
@@ -26,6 +29,26 @@
         if not len(list_of_sounds):
             self.skipTest('add some sound files in \'python/tests/sounds\'')
 
+    def test_wrong_filename(self):
+        with self.assertRaises(RuntimeError):
+            sink('')
+
+    def test_wrong_samplerate(self):
+        with self.assertRaises(RuntimeError):
+            sink(get_tmp_sink_path(), -1)
+
+    def test_wrong_samplerate_too_large(self):
+        with self.assertRaises(RuntimeError):
+            sink(get_tmp_sink_path(), 1536001, 2)
+
+    def test_wrong_channels(self):
+        with self.assertRaises(RuntimeError):
+            sink(get_tmp_sink_path(), 44100, -1)
+
+    def test_wrong_channels_too_large(self):
+        with self.assertRaises(RuntimeError):
+            sink(get_tmp_sink_path(), 44100, 202020)
+
     def test_many_sinks(self):
         from tempfile import mkdtemp
         import os.path
@@ -92,6 +115,14 @@
         g.close()
         g.close()
         del_tmp_sink_path(sink_path)
+
+    def test_read_with(self):
+        samplerate = 44100
+        sink_path = get_tmp_sink_path()
+        vec = fvec(128)
+        with sink(sink_path, samplerate) as g:
+            for _ in range(10):
+                g(vec, 128)
 
 if __name__ == '__main__':
     main()
--- a/python/tests/test_slicing.py
+++ b/python/tests/test_slicing.py
@@ -3,8 +3,8 @@
 from unittest import main
 from numpy.testing import TestCase, assert_equal
 from aubio import slice_source_at_stamps
-from utils import count_files_in_directory, get_default_test_sound
-from utils import count_samples_in_directory, count_samples_in_file
+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
@@ -23,19 +23,27 @@
 
     def test_slice_start_only_no_zero(self):
         regions_start = [i*1000 for i in range(1, n_slices)]
-        slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, create_first=True)
 
     def test_slice_start_beyond_end(self):
         regions_start = [i*1000 for i in range(1, n_slices)]
         regions_start += [count_samples_in_file(self.source_file) + 1000]
-        slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, create_first=True)
 
     def test_slice_start_every_blocksize(self):
         hopsize = 200
-        regions_start = [i*hopsize for i in range(1, n_slices)]
+        regions_start = [i*hopsize for i in range(0, n_slices)]
         slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
                 hopsize = 200)
 
+    def test_slice_start_every_half_blocksize(self):
+        hopsize = 200
+        regions_start = [i*hopsize//2 for i in range(0, n_slices)]
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, hopsize = 200)
+
     def tearDown(self):
         original_samples = count_samples_in_file(self.source_file)
         written_samples = count_samples_in_directory(self.output_dir)
@@ -91,6 +99,19 @@
         assert_equal(written_samples, expected_samples,
             "number of samples written different from number of original samples")
 
+    def test_slice_start_and_ends_with_missing_end(self):
+        regions_start = [i*1000 for i in range(n_slices)]
+        regions_ends = [r-1 for r in regions_start[1:]]
+        slice_source_at_stamps(self.source_file, regions_start, regions_ends,
+                output_dir = self.output_dir)
+        written_samples = count_samples_in_directory(self.output_dir)
+        original_samples = count_samples_in_file(self.source_file)
+        total_files = count_files_in_directory(self.output_dir)
+        assert_equal(n_slices, total_files,
+            "number of slices created different from expected")
+        assert_equal(written_samples, original_samples,
+            "number of samples written different from number of original samples")
+
     def tearDown(self):
         shutil.rmtree(self.output_dir)
 
@@ -133,7 +154,7 @@
         regions_start = [i*1000 for i in range(1, n_slices)]
         regions_end = None
         slice_source_at_stamps (self.source_file, regions_start, regions_end,
-                output_dir = self.output_dir)
+                output_dir = self.output_dir, create_first=True)
         total_files = count_files_in_directory(self.output_dir)
         assert_equal(n_slices, total_files,
             "number of slices created different from expected")
--- a/python/tests/test_source.py
+++ b/python/tests/test_source.py
@@ -2,9 +2,9 @@
 
 from nose2 import main
 from nose2.tools import params
-from numpy.testing import TestCase
+from numpy.testing import TestCase, assert_equal
 from aubio import source
-from utils import list_all_sounds
+from .utils import list_all_sounds
 
 import warnings
 warnings.filterwarnings('ignore', category=UserWarning, append=True)
@@ -51,9 +51,11 @@
     def read_from_source(self, f):
         total_frames = 0
         while True:
-            _ , read = f()
+            samples , read = f()
             total_frames += read
-            if read < f.hop_size: break
+            if read < f.hop_size:
+                assert_equal(samples[read:], 0)
+                break
         #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))
@@ -66,7 +68,14 @@
         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)
+        read_frames = self.read_from_source(f)
+        if 'f_' in soundfile and samplerate == 0:
+            import re
+            f = re.compile('.*_\([0:9]*f\)_.*')
+            match_f = re.findall('([0-9]*)f_', soundfile)
+            if len(match_f) == 1:
+                expected_frames = int(match_f[0])
+                self.assertEqual(expected_frames, read_frames)
 
     @params(*list_of_sounds)
     def test_samplerate_none(self, p):
@@ -149,13 +158,31 @@
     def read_from_source(self, f):
         total_frames = 0
         while True:
-            _, read = f.do_multi()
+            samples, read = f.do_multi()
             total_frames += read
-            if read < f.hop_size: break
+            if read < f.hop_size:
+                assert_equal(samples[:,read:], 0)
+                break
         #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
+
+class aubio_source_with(aubio_source_test_case_base):
+
+    #@params(*list_of_sounds)
+    @params(*list_of_sounds)
+    def test_read_from_mono(self, filename):
+        total_frames = 0
+        hop_size = 2048
+        with source(filename, 0, hop_size) as input_source:
+            assert_equal(input_source.hop_size, hop_size)
+            #assert_equal(input_source.samplerate, samplerate)
+            total_frames = 0
+            for frames in input_source:
+                total_frames += frames.shape[-1]
+            # check we read as many samples as we expected
+            assert_equal(total_frames, input_source.duration)
 
 if __name__ == '__main__':
     main()
--- /dev/null
+++ b/python/tests/test_source_channels.py
@@ -1,0 +1,93 @@
+#! /usr/bin/env python
+
+"""A brute force test using `sink` to create and write samples to a stereo
+file, then `source` to check the correct content is read from the files."""
+
+import os.path
+import unittest
+import aubio
+import numpy as np
+from numpy.testing import assert_equal
+from .utils import get_tmp_sink_path
+
+class aubio_source_test_case(unittest.TestCase):
+
+    def test_read_from_mono(self):
+        out = get_tmp_sink_path()
+        samplerate = 44100
+        hop_size = 256
+        blocks = 10
+        channels = 1
+        write_samples = np.ones([channels, hop_size], dtype=aubio.float_type)
+        write_samples *= .5
+        self.check_write_and_read(samplerate, channels, hop_size, blocks,
+                write_samples)
+
+    def test_read_from_stereo(self):
+        out = get_tmp_sink_path()
+        samplerate = 44100
+        hop_size = 256
+        blocks = 10
+        channels = 1
+        write_samples = np.ones([channels, hop_size], dtype=aubio.float_type)
+        write_samples *= .5
+        self.check_write_and_read(samplerate, channels, hop_size, blocks,
+                write_samples)
+
+    def test_read_from_half_stereo(self):
+        samplerate = 16000
+        channels = 2
+        hop_size = 512
+        blocks = 10
+        write_samples = np.ones([channels, hop_size], dtype=aubio.float_type)
+        write_samples *= .5
+        write_samples[1, :] = 0
+        self.check_write_and_read(samplerate, channels, hop_size, blocks,
+                write_samples)
+
+    def test_read_from_cancelling_channels(self):
+        samplerate = 16000
+        channels = 2
+        hop_size = 512
+        blocks = 10
+        write_samples = np.ones([channels, hop_size], dtype=aubio.float_type)
+        write_samples *= .5
+        write_samples[1] *= -1
+        self.check_write_and_read(samplerate, channels, hop_size, blocks,
+                write_samples)
+
+    def test_read_from_strange_three_channels(self):
+        samplerate = 8000
+        channels = 3
+        hop_size = 123
+        blocks = 10
+        write_samples = np.ones([channels, hop_size], dtype=aubio.float_type)
+        write_samples *= .5
+        write_samples[1, :] = 0
+        self.check_write_and_read(samplerate, channels, hop_size, blocks,
+                write_samples)
+
+    def check_write_and_read(self, samplerate, channels,
+            hop_size, blocks, write_samples):
+        expected_mono = np.sum(write_samples, axis=0)/write_samples.shape[0]
+        out = get_tmp_sink_path()
+        snk = aubio.sink(out, samplerate, channels=channels)
+        for i in range(blocks):
+            snk.do_multi(write_samples, hop_size)
+        # close the sink before reading from it
+        snk.close()
+
+        src = aubio.source(out, samplerate, hop_size)
+        for i in range(blocks):
+            read_samples, read = src.do_multi()
+            assert_equal (read_samples, write_samples)
+            assert_equal (read, hop_size)
+
+        src.seek(0)
+        for i in range(blocks):
+            read_samples, read = src()
+            assert_equal (read, hop_size)
+            assert_equal (read_samples, expected_mono)
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null
+++ b/python/tests/test_tempo.py
@@ -1,0 +1,91 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+import aubio
+
+class aubio_tempo_default(TestCase):
+
+    def test_members(self):
+        o = aubio.tempo()
+        assert_equal ([o.buf_size, o.hop_size, o.method, o.samplerate],
+            [1024,512,'default',44100])
+
+class aubio_tempo_params(TestCase):
+
+    samplerate = 44100
+
+    def setUp(self):
+        self.o = aubio.tempo(samplerate = self.samplerate)
+
+    def test_get_delay(self):
+        self.assertEqual(self.o.get_delay(), 0)
+
+    def test_set_delay(self):
+        val = 256
+        self.o.set_delay(val)
+        assert_equal (self.o.get_delay(), val)
+
+    def test_get_delay_s(self):
+        self.assertEqual(self.o.get_delay_s(), 0.)
+
+    def test_set_delay_s(self):
+        val = .05
+        self.o.set_delay_s(val)
+        assert_almost_equal (self.o.get_delay_s(), val)
+
+    def test_get_delay_ms(self):
+        self.assertEqual(self.o.get_delay_ms(), 0.)
+
+    def test_set_delay_ms(self):
+        val = 50.
+        self.o.set_delay_ms(val)
+        assert_almost_equal (self.o.get_delay_ms(), val)
+
+    def test_get_threshold(self):
+        assert_almost_equal(self.o.get_threshold(), 0.3)
+
+    def test_set_threshold(self):
+        val = .1
+        self.o.set_threshold(val)
+        assert_almost_equal (self.o.get_threshold(), val)
+
+    def test_get_silence(self):
+        self.assertEqual(self.o.get_silence(), -90.)
+
+    def test_set_silence(self):
+        val = -50.
+        self.o.set_silence(val)
+        assert_almost_equal (self.o.get_silence(), val)
+
+    def test_get_last(self):
+        self.assertEqual(self.o.get_last(), 0.)
+
+    def test_get_last_s(self):
+        self.assertEqual(self.o.get_last_s(), 0.)
+
+    def test_get_last_ms(self):
+        self.assertEqual(self.o.get_last_ms(), 0.)
+
+    def test_get_period(self):
+        self.assertEqual(self.o.get_period(), 0.)
+
+    def test_get_period_s(self):
+        self.assertEqual(self.o.get_period_s(), 0.)
+
+    def test_get_last_tatum(self):
+        self.assertEqual(self.o.get_last_tatum(), 0.)
+
+    def test_set_tatum_signature(self):
+        self.o.set_tatum_signature(8)
+        self.o.set_tatum_signature(64)
+        self.o.set_tatum_signature(1)
+
+    def test_set_wrong_tatum_signature(self):
+        with self.assertRaises(ValueError):
+            self.o.set_tatum_signature(101)
+        with self.assertRaises(ValueError):
+            self.o.set_tatum_signature(0)
+
+if __name__ == '__main__':
+    main()
--- /dev/null
+++ b/scripts/build_android
@@ -1,0 +1,41 @@
+#! /bin/bash
+
+set -e
+set -x
+
+# location of android NDK
+NDK_PATH=$PWD/../contrib/android-ndk-r12
+
+WAFOPTS="--disable-avcodec --disable-samplerate --disable-jack --disable-sndfile"
+
+# set these variables to change the default values
+[ -z $PLATFORM ] && PLATFORM=android-19
+[ -z $ARCH ] && ARCH=arm
+
+# location nof the standalone toolchains, created with
+# $NDK_PATH/build/tools/make-standalone-toolchains.sh
+NDK_TOOLCHAINS=$PWD/contrib
+
+# location of the current toolchain
+CURRENT_TOOLCHAIN=$NDK_TOOLCHAINS/toolchain-$PLATFORM-$ARCH
+
+# if it does not exist, create the toolchain
+[ -d $CURRENT_TOOLCHAIN ] || \
+  $NDK_PATH/build/tools/make-standalone-toolchain.sh \
+    --platform=$PLATFORM --arch=$ARCH \
+    --install-dir=$CURRENT_TOOLCHAIN
+
+# aubio install destination directory
+DESTDIR=$PWD/dist-$PLATFORM-$ARCH
+
+# wipe it out if it exists
+[ -d $DESTDIR ] && rm -rf $DESTDIR
+
+# get the link to gcc
+CC=`ls $CURRENT_TOOLCHAIN/*-linux-android*/bin/gcc`
+
+CFLAGS="-Os" \
+  CC=$CC \
+  ./waf distclean configure build install --destdir=$DESTDIR \
+   --verbose \
+   --with-target-platform=android $WAFOPTS
--- a/scripts/build_apple_frameworks
+++ b/scripts/build_apple_frameworks
@@ -1,5 +1,8 @@
 #! /bin/sh
 
+# cd to aubio directory for consistency
+cd `dirname $0`/..
+
 AUBIO_TMPDIR=`mktemp -d /var/tmp/aubio-build-XXXX`
 PACKAGE=aubio
 source VERSION
--- a/scripts/build_emscripten
+++ b/scripts/build_emscripten
@@ -1,4 +1,4 @@
-#! /bin/sh
+#! /bin/bash
 
 function checkprog() {
   type $1 >/dev/null 2>&1 || { echo >&2 "$1 required but not found, aborting."; exit 1; }
@@ -9,13 +9,10 @@
 checkprog emmake
 
 # clean
-emmake ./waf distclean
+./waf distclean
 
 # configure
-emconfigure ./waf configure --prefix=$EMSCRIPTEN/system/local/ --with-target-platform emscripten
+emconfigure ./waf configure --with-target-platform emscripten $*
 
 # build
-emmake ./waf --testcmd="node %s"
-
-# intall
-#emmake ./waf install
+emmake ./waf build
--- a/scripts/build_mingw
+++ b/scripts/build_mingw
@@ -1,28 +1,119 @@
 #! /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.
-
+# This script cross compiles aubio for windows using mingw, four times:
+#
+#  - 32 and 64 bits with no external dependencies
+#  - 32 and 64 bits against ffmpeg
+#
 # 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"
+python this_version.py -v
+VERSION=`python $PWD/this_version.py -v`
 
-[ -d dist-win32 ] && rm -rf dist-win32
-[ -d dist-win64 ] && rm -rf dist-win64
+FFMPEG_BUILDS_URL="https://ffmpeg.zeranoe.com/builds"
+FFMPEG_DEFAULT="3.3.3"
 
-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
+# define some default CFLAGS
+DEF_CFLAGS="-Os -I/usr/share/mingw-w64"
+DEF_LDFLAGS=""
 
-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
+WAFOPTS=""
+# disable external deps to make sure we don't try to use the host package
+WAFOPTS+=" --disable-samplerate --disable-jack --disable-sndfile"
+# enable ffmpeg build
+WAFOPTS+=" --disable-avcodec"
+# install without a prefix
+WAFOPTS+=" --prefix=/"
+# compile the tests, but fake running them
+# passing this option WAFOPTS fails (escaping?), added in actual waf call below
+#WAFOPTS+=" --testcmd='echo %s'"
+
+# debugging
+#WAFOPTS+=" -v"
+#WAFOPTS+=" -j1"
+#WAFOPTS+=" --notests"
+
+function fetch_ffpmeg() {
+  ## manually add ffmpeg (no pkg-config .pc files in bins)
+  [ -n "$FFMPEG_VERSION" ] || FFMPEG_VERSION=$FFMPEG_DEFAULT
+  FFMPEG_TARBALL="$PWD/ffmpeg-$FFMPEG_VERSION-$TARGET-dev.zip"
+  FFMPEG_BINARIES="${FFMPEG_TARBALL%%.zip}"
+  if [ ! -d "$FFMPEG_BINARIES" ]
+  then
+    if [ ! -f "$FFMPEG_TARBALL" ]
+    then
+      curl -O $FFMPEG_BUILDS_URL/$TARGET/dev/ffmpeg-$FFMPEG_VERSION-$TARGET-dev.zip
+    else
+      echo "using $FFMPEG_TARBALL"
+    fi
+    unzip -x $FFMPEG_TARBALL
+  else
+    echo "using $FFMPEG_BINARIES"
+  fi
+}
+
+function get_cflags() {
+  CFLAGS="$DEF_CFLAGS"
+  LDFLAGS="$DEF_LDFLAGS"
+  if [ -n "$WITH_FFMEG" ]
+  then
+    fetch_ffpmeg
+    CFLAGS+=" -DHAVE_LIBAV=1 -DHAVE_SWRESAMPLE=1"
+    CFLAGS+=" -I$FFMPEG_BINARIES/include"
+    LDFLAGS+=" -lavcodec -lavformat -lavutil -lswresample"
+    LDFLAGS+=" -L$FFMPEG_BINARIES/lib"
+  fi
+}
+
+function build_mingw() {
+  DESTDIR="$PWD/aubio-$VERSION-$TARGET"
+  [ -n "$WITH_FFMEG" ] && DESTDIR+="-ffmpeg"
+  [ -f $DESTDIR.zip ] && echo "Remove existing $DESTDIR.zip first" && exit 1
+  [ -d $DESTDIR ] && rm -rf $DESTDIR
+  WAFOPTS_TGT="$WAFOPTS --destdir=$DESTDIR"
+  WAFOPTS_TGT+=" --with-target-platform=$TARGET"
+  get_cflags
+  CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \
+    ./waf distclean configure build install $WAFOPTS_TGT --testcmd='echo %s'
+  # fix dll location (see https://github.com/waf-project/waf/issues/1860)
+  mv $DESTDIR/lib/libaubio-5.dll $DESTDIR/bin
+  mv $DESTDIR/lib/libaubio-5.def $DESTDIR/bin
+  zip -r $DESTDIR.zip `basename $DESTDIR`
+  rm -rf $DESTDIR
+  sha256sum $DESTDIR.zip > $DESTDIR.zip.sha256
+}
+
+function build_mingw32() {
+  TARGET=win32
+  export CC=i686-w64-mingw32-gcc
+  export NM=i686-w64-mingw32-nm
+  build_mingw
+}
+
+function build_mingw64() {
+  TARGET=win64
+  export CC=x86_64-w64-mingw32-gcc
+  export NM=x86_64-w64-mingw32-nm
+  build_mingw
+}
+
+# fetch waf if needed
+[ -f "waf" ] || make getwaf
+
+# first build without ffmpeg
+build_mingw32
+build_mingw64
+
+# then build against ffmpeg
+WITH_FFMEG=1
+build_mingw32
+build_mingw64
+
+set +x
+echo ""
+echo "All done! The following files were generated:"
+echo ""
+ls -lart aubio*.zip*
--- a/scripts/get_waf.sh
+++ b/scripts/get_waf.sh
@@ -1,10 +1,54 @@
-#! /bin/sh
+#! /bin/bash
 
 set -e
-set -x
+#set -x
 
-WAFURL=https://waf.io/waf-1.8.22
+WAFVERSION=2.0.12
+WAFTARBALL=waf-$WAFVERSION.tar.bz2
+WAFURL=https://waf.io/$WAFTARBALL
+WAFUPSTREAMKEY=https://gitlab.com/ita1024/waf/raw/master/utils/pubkey.asc
 
-( which wget > /dev/null && wget -qO waf $WAFURL ) || ( which curl > /dev/null && curl $WAFURL > waf )
+WAFBUILDDIR=`mktemp -d`
 
+function cleanup () {
+  rm -rf $WAFBUILDDIR
+}
+
+trap cleanup SIGINT SIGTERM
+
+function download () {
+  ( [[ -n `which wget` ]] && wget -qO $1 $2 ) || ( [[ -n `which curl` ]] && curl -so $1 $2 )
+}
+
+function checkwaf () {
+  download $WAFTARBALL.asc $WAFURL.asc
+  if [[ -z `which gpg` ]]
+  then
+    echo "Warning: gpg not found, not verifying signature for $WAFTARBALL"
+  else
+    download - $WAFUPSTREAMKEY | gpg --import
+    gpg --verify $WAFTARBALL.asc || exit 1
+  fi
+}
+
+function fetchwaf () {
+  download $WAFTARBALL $WAFURL
+  checkwaf
+}
+
+function buildwaf () {
+  tar xf $WAFTARBALL
+  pushd waf-$WAFVERSION
+  NOCLIMB=1 python waf-light --tools=c_emscripten $*
+  popd
+}
+
+pushd $WAFBUILDDIR
+fetchwaf
+buildwaf
+popd
+
+cp -prv $WAFBUILDDIR/waf-$WAFVERSION/waf $PWD
 chmod +x waf
+
+cleanup
--- a/scripts/setenv_local.sh
+++ b/scripts/setenv_local.sh
@@ -1,25 +1,16 @@
 #! /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
+# This script sets the LD_LIBRARY_PATH environment variable to ./build/src to
+# execute aubio binaries without installing libaubio.
+#
+# Usage: $ source scripts/setenv_local.sh
+#
+# Note: on macOs, the variable is DYLD_LIBRARY_PATH
 
-# 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/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
@@ -27,6 +18,3 @@
   export LD_LIBRARY_PATH=$AUBIOLIB
   echo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
 fi
-
-export PYTHONPATH=$AUBIOPYTHON
-echo export PYTHONPATH=$PYTHONPATH
--- a/setup.py
+++ b/setup.py
@@ -1,43 +1,37 @@
 #! /usr/bin/env python
 
-import sys, os.path, glob
+import sys
+import os.path
+import 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())
+# add ./python/lib to current path
+sys.path.append(os.path.join('python', 'lib'))  # noqa
+from moresetuptools import build_ext, CleanGenerated
 
-if AUBIO_MAJOR_VERSION is None or AUBIO_MINOR_VERSION is None \
-        or AUBIO_PATCH_VERSION is None:
-    raise SystemError("Failed parsing VERSION file.")
+# function to generate gen/*.{c,h}
+from this_version import get_aubio_version, get_aubio_pyversion
 
-__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
+__version__ = get_aubio_pyversion()
+__aubio_version__ = get_aubio_version()
 
 include_dirs = []
 library_dirs = []
-define_macros = []
+define_macros = [('AUBIO_VERSION', '%s' % __aubio_version__)]
 extra_link_args = []
 
-include_dirs += [ 'python/ext' ]
-include_dirs += [ output_path ] # aubio-generated.h
+include_dirs += ['python/ext']
 try:
     import numpy
-    include_dirs += [ numpy.get_include() ]
+    include_dirs += [numpy.get_include()]
 except ImportError:
     pass
 
 if sys.platform.startswith('darwin'):
-    extra_link_args += ['-framework','CoreFoundation', '-framework','AudioToolbox']
+    extra_link_args += ['-framework', 'CoreFoundation',
+            '-framework', 'AudioToolbox']
 
-sources = glob.glob(os.path.join('python', 'ext', '*.c'))
+sources = sorted(glob.glob(os.path.join('python', 'ext', '*.c')))
 
 aubio_extension = Extension("aubio._aubio",
     sources,
@@ -46,22 +40,12 @@
     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__ += 'a2' # pypi version
-else:
-    # look for aubio headers and lib using pkg-config
-    add_system_aubio(aubio_extension)
+# TODO: find a way to track if package is built against libaubio
+# if os.path.isfile('src/aubio.h'):
+#     if not os.path.isdir(os.path.join('build','src')):
+#         pass
+#         #__version__ += 'a2' # python only version
 
-
 classifiers = [
     'Development Status :: 4 - Beta',
     'Environment :: Console',
@@ -74,38 +58,45 @@
     'Operating System :: Microsoft :: Windows',
     'Programming Language :: C',
     'Programming Language :: Python',
-    'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+    '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):
+thisdir = os.path.abspath(os.path.dirname(__file__))
+py_readme_file = os.path.join(thisdir, 'python', 'README.md')
+with open(py_readme_file, 'r') as fp:
+    long_description = ''.join(fp.readlines()[3:])
 
-    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'],
+    package_dir = {'aubio': 'python/lib/aubio'},
     ext_modules = [aubio_extension],
     description = 'a collection of tools for music analysis',
-    long_description = 'a collection of tools for music analysis',
+    long_description = long_description,
+    long_description_content_type = 'text/markdown',
     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/',
+    url = 'https://aubio.org/',
     platforms = 'any',
     classifiers = classifiers,
     install_requires = ['numpy'],
+    setup_requires = ['numpy'],
     cmdclass = {
         'clean': CleanGenerated,
-        'generate': GenerateCommand,
         'build_ext': build_ext,
         },
+    entry_points = {
+        'console_scripts': [
+            'aubio = aubio.cmd:main',
+            'aubiocut = aubio.cut:main',
+        ],
+    },
     test_suite = 'nose2.collector.collector',
+    extras_require = {
+        'tests': ['numpy'],
+        },
     )
--- a/src/aubio.h
+++ b/src/aubio.h
@@ -109,15 +109,17 @@
   \endcode
 
   Several examples of C programs are available in the \p examples/ and \p tests/src
-  directories of the source tree. See more examples:
-  @ref spectral/test-fft.c
-  @ref spectral/test-phasevoc.c
-  @ref onset/test-onset.c
-  @ref pitch/test-pitch.c
-  @ref tempo/test-tempo.c
-  @ref test-fvec.c
-  @ref test-cvec.c
+  directories of the source tree.
 
+  Some examples:
+  - @ref spectral/test-fft.c
+  - @ref spectral/test-phasevoc.c
+  - @ref onset/test-onset.c
+  - @ref pitch/test-pitch.c
+  - @ref tempo/test-tempo.c
+  - @ref test-fvec.c
+  - @ref test-cvec.c
+
   \subsection unstable_api Unstable API
 
   Several more functions are available and used within aubio, but not
@@ -137,7 +139,7 @@
   \section download Download
 
   Latest versions, further documentation, examples, wiki, and mailing lists can
-  be found at http://aubio.org .
+  be found at https://aubio.org .
 
  */
 
@@ -180,11 +182,13 @@
 #include "temporal/a_weighting.h"
 #include "temporal/c_weighting.h"
 #include "spectral/fft.h"
+#include "spectral/dct.h"
 #include "spectral/phasevoc.h"
 #include "spectral/filterbank.h"
 #include "spectral/filterbank_mel.h"
 #include "spectral/mfcc.h"
 #include "spectral/specdesc.h"
+#include "spectral/awhitening.h"
 #include "spectral/tss.h"
 #include "pitch/pitch.h"
 #include "onset/onset.h"
@@ -211,6 +215,7 @@
 #include "pitch/pitchmcomb.h"
 #include "pitch/pitchyin.h"
 #include "pitch/pitchyinfft.h"
+#include "pitch/pitchyinfast.h"
 #include "pitch/pitchschmitt.h"
 #include "pitch/pitchfcomb.h"
 #include "pitch/pitchspecacf.h"
--- a/src/aubio_priv.h
+++ b/src/aubio_priv.h
@@ -33,7 +33,9 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
 #include "config.h"
+#endif
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -68,15 +70,21 @@
 #include <stdarg.h>
 #endif
 
-#ifdef HAVE_ACCELERATE
+#if defined(HAVE_ACCELERATE)
 #define HAVE_ATLAS 1
+#define HAVE_BLAS 1
 #include <Accelerate/Accelerate.h>
 #elif defined(HAVE_ATLAS_CBLAS_H)
+#elif defined(HAVE_BLAS)
+#if defined(HAVE_ATLAS_CBLAS_H)
 #define HAVE_ATLAS 1
 #include <atlas/cblas.h>
-#else
-#undef HAVE_ATLAS
+#elif defined(HAVE_OPENBLAS_CBLAS_H)
+#include <openblas/cblas.h>
+#elif defined(HAVE_CBLAS_H)
+#include <cblas.h>
 #endif
+#endif
 
 #ifdef HAVE_ACCELERATE
 #include <Accelerate/Accelerate.h>
@@ -83,6 +91,8 @@
 #ifndef HAVE_AUBIO_DOUBLE
 #define aubio_vDSP_mmov       vDSP_mmov
 #define aubio_vDSP_vmul       vDSP_vmul
+#define aubio_vDSP_vsmul      vDSP_vsmul
+#define aubio_vDSP_vsadd      vDSP_vsadd
 #define aubio_vDSP_vfill      vDSP_vfill
 #define aubio_vDSP_meanv      vDSP_meanv
 #define aubio_vDSP_sve        vDSP_sve
@@ -91,9 +101,12 @@
 #define aubio_vDSP_minv       vDSP_minv
 #define aubio_vDSP_minvi      vDSP_minvi
 #define aubio_vDSP_dotpr      vDSP_dotpr
+#define aubio_vDSP_vclr       vDSP_vclr
 #else /* HAVE_AUBIO_DOUBLE */
 #define aubio_vDSP_mmov       vDSP_mmovD
 #define aubio_vDSP_vmul       vDSP_vmulD
+#define aubio_vDSP_vsmul      vDSP_vsmulD
+#define aubio_vDSP_vsadd      vDSP_vsaddD
 #define aubio_vDSP_vfill      vDSP_vfillD
 #define aubio_vDSP_meanv      vDSP_meanvD
 #define aubio_vDSP_sve        vDSP_sveD
@@ -102,27 +115,61 @@
 #define aubio_vDSP_minv       vDSP_minvD
 #define aubio_vDSP_minvi      vDSP_minviD
 #define aubio_vDSP_dotpr      vDSP_dotprD
+#define aubio_vDSP_vclr       vDSP_vclrD
 #endif /* HAVE_AUBIO_DOUBLE */
 #endif /* HAVE_ACCELERATE */
 
-#ifdef HAVE_ATLAS
+#if defined(HAVE_BLAS)
 #ifndef HAVE_AUBIO_DOUBLE
+#ifdef HAVE_ATLAS
 #define aubio_catlas_set      catlas_sset
+#endif /* HAVE_ATLAS */
 #define aubio_cblas_copy      cblas_scopy
 #define aubio_cblas_swap      cblas_sswap
 #define aubio_cblas_dot       cblas_sdot
 #else /* HAVE_AUBIO_DOUBLE */
+#ifdef HAVE_ATLAS
 #define aubio_catlas_set      catlas_dset
+#endif /* HAVE_ATLAS */
 #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 */
+#endif /* HAVE_BLAS */
 
-#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+#if defined HAVE_INTEL_IPP
+#include <ippcore.h>
+#include <ippvm.h>
+#include <ipps.h>
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_ippsSet         ippsSet_32f
+#define aubio_ippsZero        ippsZero_32f
+#define aubio_ippsCopy        ippsCopy_32f
+#define aubio_ippsMul         ippsMul_32f
+#define aubio_ippsMulC        ippsMulC_32f
+#define aubio_ippsAddC        ippsAddC_32f
+#define aubio_ippsLn          ippsLn_32f_A21
+#define aubio_ippsMean(a,b,c) ippsMean_32f(a, b, c, ippAlgHintFast)
+#define aubio_ippsSum(a,b,c)  ippsSum_32f(a, b, c, ippAlgHintFast)
+#define aubio_ippsMax         ippsMax_32f
+#define aubio_ippsMin         ippsMin_32f
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_ippsSet         ippsSet_64f
+#define aubio_ippsZero        ippsZero_64f
+#define aubio_ippsCopy        ippsCopy_64f
+#define aubio_ippsMul         ippsMul_64f
+#define aubio_ippsMulC        ippsMulC_64f
+#define aubio_ippsAddC        ippsAddC_64f
+#define aubio_ippsLn          ippsLn_64f_A26
+#define aubio_ippsMean        ippsMean_64f
+#define aubio_ippsSum         ippsSum_64f
+#define aubio_ippsMax         ippsMax_64f
+#define aubio_ippsMin         ippsMin_64f
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif
+
+#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS) && !defined(HAVE_INTEL_IPP)
 #define HAVE_NOOPT 1
-#else
-#undef HAVE_NOOPT
 #endif
 
 #include "types.h"
@@ -181,14 +228,16 @@
 
 #ifdef HAVE_C99_VARARGS_MACROS
 #define AUBIO_ERR(...)               aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " __VA_ARGS__)
+#define AUBIO_INF(...)               aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " __VA_ARGS__)
 #define AUBIO_MSG(...)               aubio_log(AUBIO_LOG_MSG, __VA_ARGS__)
 #define AUBIO_DBG(...)               aubio_log(AUBIO_LOG_DBG, __VA_ARGS__)
 #define AUBIO_WRN(...)               aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " __VA_ARGS__)
 #else
-#define AUBIO_ERR(format, args...)   aubio_log(stderr, "AUBIO ERROR: " format , ##args)
-#define AUBIO_MSG(format, args...)   aubio_log(stdout, format , ##args)
-#define AUBIO_DBG(format, args...)   aubio_log(stderr, format , ##args)
-#define AUBIO_WRN(format, args...)   aubio_log(stderr, "AUBIO WARNING: " format, ##args)
+#define AUBIO_ERR(format, args...)   aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " format , ##args)
+#define AUBIO_INF(format, args...)   aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " format , ##args)
+#define AUBIO_MSG(format, args...)   aubio_log(AUBIO_LOG_MSG, format , ##args)
+#define AUBIO_DBG(format, args...)   aubio_log(AUBIO_LOG_DBG, format , ##args)
+#define AUBIO_WRN(format, args...)   aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " format, ##args)
 #endif
 
 #define AUBIO_ERROR   AUBIO_ERR
@@ -196,6 +245,9 @@
 #define AUBIO_QUIT(_s)               exit(_s)
 #define AUBIO_SPRINTF                sprintf
 
+#define AUBIO_MAX_SAMPLERATE (192000*8)
+#define AUBIO_MAX_CHANNELS 1024
+
 /* pi and 2*pi */
 #ifndef M_PI
 #define PI         (3.14159265358979323846)
@@ -220,6 +272,7 @@
 #define LOG        logf
 #define FLOOR      floorf
 #define CEIL       ceilf
+#define ATAN       atanf
 #define ATAN2      atan2f
 #else
 #define EXP        exp
@@ -232,6 +285,7 @@
 #define LOG        log
 #define FLOOR      floor
 #define CEIL       ceil
+#define ATAN       atan
 #define ATAN2      atan2
 #endif
 #define ROUND(x)   FLOOR(x+.5)
--- a/src/cvec.c
+++ b/src/cvec.c
@@ -85,31 +85,40 @@
         s->length, t->length);
     return;
   }
-#ifdef HAVE_MEMCPY_HACKS
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsCopy(s->phas, t->phas, (int)s->length);
+  aubio_ippsCopy(s->norm, t->norm, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
   memcpy(t->norm, s->norm, t->length * sizeof(smpl_t));
   memcpy(t->phas, s->phas, t->length * sizeof(smpl_t));
-#else /* HAVE_MEMCPY_HACKS */
+#else
   uint_t j;
   for (j=0; j< t->length; j++) {
     t->norm[j] = s->norm[j];
     t->phas[j] = s->phas[j];
   }
-#endif /* HAVE_MEMCPY_HACKS */
+#endif
 }
 
-void cvec_norm_set_all (cvec_t *s, smpl_t val) {
+void cvec_norm_set_all(cvec_t *s, smpl_t val) {
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsSet(val, s->norm, (int)s->length);
+#else
   uint_t j;
   for (j=0; j< s->length; j++) {
     s->norm[j] = val;
   }
+#endif
 }
 
 void cvec_norm_zeros(cvec_t *s) {
-#ifdef HAVE_MEMCPY_HACKS
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsZero(s->norm, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
   memset(s->norm, 0, s->length * sizeof(smpl_t));
-#else /* HAVE_MEMCPY_HACKS */
+#else
   cvec_norm_set_all (s, 0.);
-#endif /* HAVE_MEMCPY_HACKS */
+#endif
 }
 
 void cvec_norm_ones(cvec_t *s) {
@@ -117,14 +126,20 @@
 }
 
 void cvec_phas_set_all (cvec_t *s, smpl_t val) {
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsSet(val, s->phas, (int)s->length);
+#else
   uint_t j;
   for (j=0; j< s->length; j++) {
     s->phas[j] = val;
   }
+#endif
 }
 
 void cvec_phas_zeros(cvec_t *s) {
-#ifdef HAVE_MEMCPY_HACKS
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsZero(s->phas, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
   memset(s->phas, 0, s->length * sizeof(smpl_t));
 #else
   cvec_phas_set_all (s, 0.);
@@ -138,4 +153,17 @@
 void cvec_zeros(cvec_t *s) {
   cvec_norm_zeros(s);
   cvec_phas_zeros(s);
+}
+
+void cvec_logmag(cvec_t *s, smpl_t lambda) {
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsMulC(s->norm, lambda, s->norm, (int)s->length);
+  aubio_ippsAddC(s->norm, 1.0, s->norm, (int)s->length);
+  aubio_ippsLn(s->norm, s->norm, (int)s->length);
+#else
+  uint_t j;
+  for (j=0; j< s->length; j++) {
+    s->norm[j] = LOG(lambda * s->norm[j] + 1);
+  }
+#endif
 }
--- a/src/cvec.h
+++ b/src/cvec.h
@@ -230,6 +230,16 @@
 */
 void cvec_zeros(cvec_t *s);
 
+/** take logarithmic magnitude
+
+  \param s input cvec to compress
+  \param lambda value to use for normalisation
+
+  \f$ S_k = log( \lambda * S_k + 1 ) \f$
+
+*/
+void cvec_logmag(cvec_t *s, smpl_t lambda);
+
 #ifdef __cplusplus
 }
 #endif
--- a/src/fmat.c
+++ b/src/fmat.c
@@ -110,7 +110,7 @@
 void fmat_rev(fmat_t *s) {
   uint_t i,j;
   for (i=0; i< s->height; i++) {
-    for (j=0; j< FLOOR(s->length/2); j++) {
+    for (j=0; j< FLOOR((smpl_t)s->length/2); j++) {
       ELEM_SWAP(s->data[i][j], s->data[i][s->length-1-j]);
     }
   }
@@ -160,7 +160,7 @@
   assert(s->height == output->length);
   assert(s->length == scale->length);
 #endif
-#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_BLAS)
   uint_t j;
   fvec_zeros(output);
   for (j = 0; j < s->length; j++) {
@@ -169,7 +169,7 @@
           * s->data[k][j];
     }
   }
-#elif defined(HAVE_ATLAS)
+#elif defined(HAVE_BLAS)
   for (k = 0; k < s->height; k++) {
     output->data[k] = aubio_cblas_dot( s->length, scale->data, 1, s->data[k], 1);
   }
--- a/src/fvec.c
+++ b/src/fvec.c
@@ -60,28 +60,31 @@
 }
 
 void fvec_set_all (fvec_t *s, smpl_t val) {
-#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
-  uint_t j;
-  for (j=0; j< s->length; j++) {
-    s->data[j] = val;
-  }
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsSet(val, s->data, (int)s->length);
 #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);
+#else
+  uint_t j;
+  for ( j = 0; j< s->length; j++ )
+  {
+    s->data[j] = val;
+  }
 #endif
 }
 
 void fvec_zeros(fvec_t *s) {
-#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE)
-  fvec_set_all (s, 0.);
-#else
-#if defined(HAVE_MEMCPY_HACKS)
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsZero(s->data, (int)s->length);
+#elif defined(HAVE_ACCELERATE)
+  aubio_vDSP_vclr(s->data, 1, s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
   memset(s->data, 0, s->length * sizeof(smpl_t));
 #else
-  aubio_vDSP_vclr(s->data, 1, s->length);
+  fvec_set_all(s, 0.);
 #endif
-#endif
 }
 
 void fvec_ones(fvec_t *s) {
@@ -90,33 +93,37 @@
 
 void fvec_rev(fvec_t *s) {
   uint_t j;
-  for (j=0; j< FLOOR(s->length/2); j++) {
+  for (j=0; j< FLOOR((smpl_t)s->length/2); j++) {
     ELEM_SWAP(s->data[j], s->data[s->length-1-j]);
   }
 }
 
 void fvec_weight(fvec_t *s, const fvec_t *weight) {
-#ifndef HAVE_ACCELERATE
-  uint_t j;
   uint_t length = MIN(s->length, weight->length);
-  for (j=0; j< length; j++) {
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsMul(s->data, weight->data, s->data, (int)length);
+#elif defined(HAVE_ACCELERATE)
+  aubio_vDSP_vmul( s->data, 1, weight->data, 1, s->data, 1, length );
+#else
+  uint_t j;
+  for (j = 0; j < length; j++) {
     s->data[j] *= weight->data[j];
   }
-#else
-  aubio_vDSP_vmul(s->data, 1, weight->data, 1, s->data, 1, s->length);
 #endif /* HAVE_ACCELERATE */
 }
 
 void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out) {
-#ifndef HAVE_ACCELERATE
+  uint_t length = MIN(in->length, MIN(out->length, weight->length));
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsMul(in->data, weight->data, out->data, (int)length);
+#elif defined(HAVE_ACCELERATE)
+  aubio_vDSP_vmul(in->data, 1, weight->data, 1, out->data, 1, length);
+#else
   uint_t j;
-  uint_t length = MIN(out->length, weight->length);
-  for (j=0; j< length; j++) {
+  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 */
+#endif
 }
 
 void fvec_copy(const fvec_t *s, fvec_t *t) {
@@ -125,16 +132,18 @@
         s->length, t->length);
     return;
   }
-#ifdef HAVE_NOOPT
-  uint_t j;
-  for (j=0; j< t->length; j++) {
-    t->data[j] = s->data[j];
-  }
-#elif defined(HAVE_MEMCPY_HACKS)
-  memcpy(t->data, s->data, t->length * sizeof(smpl_t));
-#elif defined(HAVE_ATLAS)
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsCopy(s->data, t->data, (int)s->length);
+#elif defined(HAVE_BLAS)
   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);
+#elif defined(HAVE_MEMCPY_HACKS)
+  memcpy(t->data, s->data, t->length * sizeof(smpl_t));
+#else
+  uint_t j;
+  for (j = 0; j < t->length; j++) {
+    t->data[j] = s->data[j];
+  }
 #endif
 }
--- a/src/io/audio_unit.c
+++ b/src/io/audio_unit.c
@@ -18,9 +18,8 @@
 
 */
 
-#include "config.h"
-#ifdef HAVE_AUDIO_UNIT
 #include "aubio_priv.h"
+#ifdef HAVE_AUDIO_UNIT
 
 #include "fvec.h"
 #include "fmat.h"
--- /dev/null
+++ b/src/io/ioutils.c
@@ -1,0 +1,53 @@
+/*
+  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/>.
+
+*/
+
+#include "aubio_priv.h"
+
+uint_t
+aubio_io_validate_samplerate(const char_t *kind, const char_t *path, uint_t samplerate)
+{
+  if ((sint_t)(samplerate) <= 0) {
+    AUBIO_ERR("%s: failed creating %s, samplerate should be positive, not %d\n",
+        kind, path, samplerate);
+    return AUBIO_FAIL;
+  }
+  if ((sint_t)samplerate > AUBIO_MAX_SAMPLERATE) {
+    AUBIO_ERR("%s: failed creating %s, samplerate %dHz is too large\n",
+        kind, path, samplerate);
+    return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
+
+uint_t
+aubio_io_validate_channels(const char_t *kind, const char_t *path, uint_t channels)
+{
+  if ((sint_t)(channels) <= 0) {
+    AUBIO_ERR("sink_%s: failed creating %s, channels should be positive, not %d\n",
+        kind, path, channels);
+    return AUBIO_FAIL;
+  }
+  if (channels > AUBIO_MAX_CHANNELS) {
+    AUBIO_ERR("sink_%s: failed creating %s, too many channels (%d but %d available)\n",
+        kind, path, channels, AUBIO_MAX_CHANNELS);
+    return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
--- /dev/null
+++ b/src/io/ioutils.h
@@ -1,0 +1,60 @@
+/*
+  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/>.
+
+*/
+
+#ifndef AUBIO_IOUTILS_H
+#define AUBIO_IOUTILS_H
+
+/** \file
+
+  Simple utility functions to validate input parameters.
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** validate samplerate
+
+  \param kind       the object kind to report on
+  \param path       the object properties to report on
+  \param samplerate the object properties to report on
+  \return  0 if ok, non-zero if validation failed
+
+ */
+uint_t aubio_io_validate_samplerate(const char_t *kind, const char_t *path,
+    uint_t samplerate);
+
+/** validate number of channels
+
+  \param kind       the object kind to report on
+  \param path       the object properties to report on
+  \param channels   the object properties to report on
+  \return  0 if ok, non-zero if validation failed
+
+ */
+uint_t aubio_io_validate_channels(const char_t *kind, const char_t *path,
+    uint_t channels);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_IOUTILS_H */
--- a/src/io/sink.c
+++ b/src/io/sink.c
@@ -18,7 +18,6 @@
 
 */
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
@@ -98,8 +97,11 @@
     return s;
   }
 #endif /* HAVE_WAVWRITE */
-  AUBIO_ERROR("sink: failed creating %s with samplerate %dHz\n",
-      uri, samplerate);
+#if !defined(HAVE_WAVWRITE) && \
+  !defined(HAVE_SNDFILE) && \
+  !defined(HAVE_SINK_APPLE_AUDIO)
+  AUBIO_ERROR("sink: failed creating '%s' at %dHz (no sink built-in)\n", uri, samplerate);
+#endif
   AUBIO_FREE(s);
   return NULL;
 }
--- a/src/io/sink_apple_audio.c
+++ b/src/io/sink_apple_audio.c
@@ -18,14 +18,13 @@
 
 */
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_SINK_APPLE_AUDIO
-
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "io/sink_apple_audio.h"
+#include "io/ioutils.h"
 
 // CFURLRef, CFURLCreateWithFileSystemPath, ...
 #include <CoreFoundation/CoreFoundation.h>
@@ -62,7 +61,7 @@
   s->max_frames = MAX_SIZE;
   s->async = false;
 
-  if (uri == NULL) {
+  if ( (uri == NULL) || (strlen(uri) < 1) ) {
     AUBIO_ERROR("sink_apple_audio: Aborted opening null path\n");
     goto beach;
   }
@@ -73,10 +72,14 @@
   s->samplerate = 0;
   s->channels = 0;
 
-  // negative samplerate given, abort
-  if ((sint_t)samplerate < 0) goto beach;
   // zero samplerate given. do not open yet
-  if ((sint_t)samplerate == 0) return s;
+  if ((sint_t)samplerate == 0) {
+    return s;
+  }
+  // invalid samplerate given, abort
+  if (aubio_io_validate_samplerate("sink_apple_audio", s->path, samplerate)) {
+    goto beach;
+  }
 
   s->samplerate = samplerate;
   s->channels = 1;
@@ -94,7 +97,9 @@
 
 uint_t aubio_sink_apple_audio_preset_samplerate(aubio_sink_apple_audio_t *s, uint_t samplerate)
 {
-  if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_samplerate("sink_apple_audio", s->path, samplerate)) {
+    return AUBIO_FAIL;
+  }
   s->samplerate = samplerate;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
@@ -105,7 +110,9 @@
 
 uint_t aubio_sink_apple_audio_preset_channels(aubio_sink_apple_audio_t *s, uint_t channels)
 {
-  if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_channels("sink_apple_audio", s->path, channels)) {
+    return AUBIO_FAIL;
+  }
   s->channels = channels;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
--- a/src/io/sink_sndfile.c
+++ b/src/io/sink_sndfile.c
@@ -19,18 +19,17 @@
 */
 
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_SNDFILE
 
 #include <sndfile.h>
 
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "io/sink_sndfile.h"
+#include "io/ioutils.h"
 
-#define MAX_CHANNELS 6
 #define MAX_SIZE 4096
 
 #if !HAVE_AUBIO_DOUBLE
@@ -69,10 +68,14 @@
   s->samplerate = 0;
   s->channels = 0;
 
-  // negative samplerate given, abort
-  if ((sint_t)samplerate < 0) goto beach;
   // zero samplerate given. do not open yet
-  if ((sint_t)samplerate == 0) return s;
+  if ((sint_t)samplerate == 0) {
+    return s;
+  }
+  // invalid samplerate given, abort
+  if (aubio_io_validate_samplerate("sink_sndfile", s->path, samplerate)) {
+    goto beach;
+  }
 
   s->samplerate = samplerate;
   s->channels = 1;
@@ -89,7 +92,9 @@
 
 uint_t aubio_sink_sndfile_preset_samplerate(aubio_sink_sndfile_t *s, uint_t samplerate)
 {
-  if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_samplerate("sink_sndfile", s->path, samplerate)) {
+    return AUBIO_FAIL;
+  }
   s->samplerate = samplerate;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
@@ -100,7 +105,9 @@
 
 uint_t aubio_sink_sndfile_preset_channels(aubio_sink_sndfile_t *s, uint_t channels)
 {
-  if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_channels("sink_sndfile", s->path, channels)) {
+    return AUBIO_FAIL;
+  }
   s->channels = channels;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
@@ -132,15 +139,17 @@
 
   if (s->handle == NULL) {
     /* show libsndfile err msg */
-    AUBIO_ERR("sink_sndfile: Failed opening %s. %s\n", s->path, sf_strerror (NULL));
+    AUBIO_ERR("sink_sndfile: Failed opening \"%s\" with %d channels, %dHz: %s\n",
+        s->path, s->channels, s->samplerate, sf_strerror (NULL));
     return AUBIO_FAIL;
   }
 
   s->scratch_size = s->max_size*s->channels;
   /* allocate data for de/interleaving reallocated when needed. */
-  if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
+  if (s->scratch_size >= MAX_SIZE * AUBIO_MAX_CHANNELS) {
+    abort();
     AUBIO_ERR("sink_sndfile: %d x %d exceeds maximum aubio_sink_sndfile buffer size %d\n",
-        s->max_size, s->channels, MAX_CHANNELS * MAX_CHANNELS);
+        s->max_size, s->channels, MAX_SIZE * AUBIO_MAX_CHANNELS);
     return AUBIO_FAIL;
   }
   s->scratch_data = AUBIO_ARRAY(smpl_t,s->scratch_size);
--- a/src/io/sink_wavwrite.c
+++ b/src/io/sink_wavwrite.c
@@ -19,18 +19,17 @@
 */
 
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_WAVWRITE
 
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "io/sink_wavwrite.h"
+#include "io/ioutils.h"
 
 #include <errno.h>
 
-#define MAX_CHANNELS 6
 #define MAX_SIZE 4096
 
 #define FLOAT_TO_SHORT(x) (short)(x * 32768)
@@ -104,12 +103,14 @@
   s->samplerate = 0;
   s->channels = 0;
 
-  // negative samplerate given, abort
-  if ((sint_t)samplerate < 0) goto beach;
   // zero samplerate given. do not open yet
-  if ((sint_t)samplerate == 0) return s;
-  // samplerate way too large, fail
-  if ((sint_t)samplerate > 192000 * 4) goto beach;
+  if ((sint_t)samplerate == 0) {
+    return s;
+  }
+  // invalid samplerate given, abort
+  if (aubio_io_validate_samplerate("sink_wavwrite", s->path, samplerate)) {
+    goto beach;
+  }
 
   s->samplerate = samplerate;
   s->channels = 1;
@@ -129,7 +130,9 @@
 
 uint_t aubio_sink_wavwrite_preset_samplerate(aubio_sink_wavwrite_t *s, uint_t samplerate)
 {
-  if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_samplerate("sink_wavwrite", s->path, samplerate)) {
+    return AUBIO_FAIL;
+  }
   s->samplerate = samplerate;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
@@ -140,7 +143,9 @@
 
 uint_t aubio_sink_wavwrite_preset_channels(aubio_sink_wavwrite_t *s, uint_t channels)
 {
-  if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+  if (aubio_io_validate_channels("sink_wavwrite", s->path, channels)) {
+    return AUBIO_FAIL;
+  }
   s->channels = channels;
   // automatically open when both samplerate and channels have been set
   if (s->samplerate != 0 && s->channels != 0) {
@@ -213,9 +218,9 @@
 
   s->scratch_size = s->max_size * s->channels;
   /* allocate data for de/interleaving reallocated when needed. */
-  if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
+  if (s->scratch_size >= MAX_SIZE * AUBIO_MAX_CHANNELS) {
     AUBIO_ERR("sink_wavwrite: %d x %d exceeds SIZE maximum buffer size %d\n",
-        s->max_size, s->channels, MAX_SIZE * MAX_CHANNELS);
+        s->max_size, s->channels, MAX_SIZE * AUBIO_MAX_CHANNELS);
     goto beach;
   }
   s->scratch_data = AUBIO_ARRAY(unsigned short,s->scratch_size);
--- a/src/io/source.c
+++ b/src/io/source.c
@@ -18,7 +18,6 @@
 
 */
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
@@ -115,8 +114,13 @@
     return s;
   }
 #endif /* HAVE_WAVREAD */
-  AUBIO_ERROR("source: failed creating aubio source with %s"
-     " at samplerate %d with hop_size %d\n", uri, samplerate, hop_size);
+#if !defined(HAVE_WAVREAD) && \
+  !defined(HAVE_LIBAV) && \
+  !defined(HAVE_SOURCE_APPLE_AUDIO) && \
+  !defined(HAVE_SNDFILE)
+  AUBIO_ERROR("source: failed creating with %s at %dHz with hop size %d"
+     " (no source built-in)\n", uri, samplerate, hop_size);
+#endif
   AUBIO_FREE(s);
   return NULL;
 }
--- a/src/io/source_apple_audio.c
+++ b/src/io/source_apple_audio.c
@@ -18,11 +18,10 @@
 
 */
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_SOURCE_APPLE_AUDIO
 
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "io/source_apple_audio.h"
@@ -280,7 +279,7 @@
 uint_t aubio_source_apple_audio_close (aubio_source_apple_audio_t *s)
 {
   OSStatus err = noErr;
-  if (!s->audioFile) { return AUBIO_FAIL; }
+  if (!s->audioFile) { return AUBIO_OK; }
   err = ExtAudioFileDispose(s->audioFile);
   s->audioFile = NULL;
   if (err) {
--- a/src/io/source_avcodec.c
+++ b/src/io/source_avcodec.c
@@ -18,14 +18,23 @@
 
 */
 
+#include "aubio_priv.h"
 
-#include "config.h"
-
 #ifdef HAVE_LIBAV
 
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#if defined(HAVE_SWRESAMPLE)
+#include <libswresample/swresample.h>
+#elif defined(HAVE_AVRESAMPLE)
+#include <libavresample/avresample.h>
+#endif
+#include <libavutil/opt.h>
+#include <stdlib.h>
+
 // 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
+// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 -> 57.2.100
 #define FFMPEG_LIBAVFORMAT_MAX_DUR2 FFMPEG_LIBAVFORMAT && ( \
       (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 43) \
       || (LIBAVFORMAT_VERSION_MAJOR == 56) \
@@ -32,18 +41,28 @@
       || (LIBAVFORMAT_VERSION_MAJOR == 57 && LIBAVFORMAT_VERSION_MINOR < 2) \
       )
 
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavresample/avresample.h>
-#include <libavutil/opt.h>
-#include <stdlib.h>
+// backward compatibility with libavcodec55
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,0,0)
+#define HAVE_AUBIO_LIBAVCODEC_DEPRECATED 1
+#endif
 
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
+#warning "libavcodec < 56 is deprecated"
+#define av_frame_alloc  avcodec_alloc_frame
+#define av_frame_free avcodec_free_frame
+#define av_packet_unref av_free_packet
+#endif
+
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "source_avcodec.h"
 
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 56, 0)
 #define AUBIO_AVCODEC_MAX_BUFFER_SIZE FF_MIN_BUFFER_SIZE
+#else
+#define AUBIO_AVCODEC_MAX_BUFFER_SIZE AV_INPUT_BUFFER_MIN_SIZE
+#endif
 
 struct _aubio_source_avcodec_t {
   uint_t hop_size;
@@ -59,18 +78,24 @@
   AVFormatContext *avFormatCtx;
   AVCodecContext *avCodecCtx;
   AVFrame *avFrame;
+  AVPacket avPacket;
+#ifdef HAVE_AVRESAMPLE
   AVAudioResampleContext *avr;
-  float *output;
+#elif defined(HAVE_SWRESAMPLE)
+  SwrContext *avr;
+#endif
+  smpl_t *output;
   uint_t read_samples;
   uint_t read_index;
   sint_t selected_stream;
   uint_t eof;
-  uint_t multi;
 };
 
-// hack to create or re-create the context the first time _do or _do_multi is called
-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);
+// create or re-create the context when _do or _do_multi is called
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s);
+// actually read a frame
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s,
+    uint_t * read_samples);
 
 uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s);
 
@@ -87,8 +112,18 @@
 }
 
 
-aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path, uint_t samplerate, uint_t hop_size) {
+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);
+  AVFormatContext *avFormatCtx = s->avFormatCtx;
+  AVCodecContext *avCodecCtx = s->avCodecCtx;
+  AVFrame *avFrame = s->avFrame;
+  sint_t selected_stream = -1;
+#if FF_API_LAVF_AVCTX
+  AVCodecParameters *codecpar;
+#endif
+  AVCodec *codec;
+  uint_t i;
   int err;
   if (path == NULL) {
     AUBIO_ERR("source_avcodec: Aborted opening null path\n");
@@ -95,11 +130,13 @@
     goto beach;
   }
   if ((sint_t)samplerate < 0) {
-    AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n", path, samplerate);
+    AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n",
+        path, samplerate);
     goto beach;
   }
   if ((sint_t)hop_size <= 0) {
-    AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n", path, hop_size);
+    AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n",
+        path, hop_size);
     goto beach;
   }
 
@@ -110,8 +147,10 @@
   s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
   strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
 
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,0,0)
   // register all formats and codecs
   av_register_all();
+#endif
 
   if (aubio_source_avcodec_has_network_url(s)) {
     avformat_network_init();
@@ -118,7 +157,6 @@
   }
 
   // try opening the file and get some info about it
-  AVFormatContext *avFormatCtx = s->avFormatCtx;
   avFormatCtx = NULL;
   if ( (err = avformat_open_input(&avFormatCtx, s->path, NULL, NULL) ) < 0 ) {
     char errorstr[256];
@@ -138,8 +176,8 @@
   if ( (err = avformat_find_stream_info(avFormatCtx, NULL)) < 0 ) {
     char errorstr[256];
     av_strerror (err, errorstr, sizeof(errorstr));
-    AUBIO_ERR("source_avcodec: Could not find stream information " "for %s (%s)\n", s->path,
-        errorstr);
+    AUBIO_ERR("source_avcodec: Could not find stream information "
+        "for %s (%s)\n", s->path, errorstr);
     goto beach;
   }
 
@@ -147,10 +185,12 @@
   //av_dump_format(avFormatCtx, 0, s->path, 0);
 
   // look for the first audio stream
-  uint_t i;
-  sint_t selected_stream = -1;
   for (i = 0; i < avFormatCtx->nb_streams; i++) {
+#if FF_API_LAVF_AVCTX
+    if (avFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+#else
     if (avFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+#endif
       if (selected_stream == -1) {
         selected_stream = i;
       } else {
@@ -166,18 +206,46 @@
   //AUBIO_DBG("Taking stream %d in file %s\n", selected_stream, s->path);
   s->selected_stream = selected_stream;
 
-  AVCodecContext *avCodecCtx = s->avCodecCtx;
+#if FF_API_LAVF_AVCTX
+  codecpar = avFormatCtx->streams[selected_stream]->codecpar;
+  if (codecpar == NULL) {
+    AUBIO_ERR("source_avcodec: Could not find decoder for %s", s->path);
+    goto beach;
+  }
+  codec = avcodec_find_decoder(codecpar->codec_id);
+
+  /* Allocate a codec context for the decoder */
+  avCodecCtx = avcodec_alloc_context3(codec);
+  if (!avCodecCtx) {
+    AUBIO_ERR("source_avcodec: Failed to allocate the %s codec context "
+        "for path %s\n", av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
+        s->path);
+    goto beach;
+  }
+#else
   avCodecCtx = avFormatCtx->streams[selected_stream]->codec;
-  AVCodec *codec = avcodec_find_decoder(avCodecCtx->codec_id);
+  codec = avcodec_find_decoder(avCodecCtx->codec_id);
+#endif
   if (codec == NULL) {
     AUBIO_ERR("source_avcodec: Could not find decoder for %s", s->path);
     goto beach;
   }
 
+#if FF_API_LAVF_AVCTX
+  /* Copy codec parameters from input stream to output codec context */
+  if ((err = avcodec_parameters_to_context(avCodecCtx, codecpar)) < 0) {
+    AUBIO_ERR("source_avcodec: Failed to copy %s codec parameters to "
+        "decoder context for %s\n",
+        av_get_media_type_string(AVMEDIA_TYPE_AUDIO), s->path);
+    goto beach;
+  }
+#endif
+
   if ( ( err = avcodec_open2(avCodecCtx, codec, NULL) ) < 0) {
     char errorstr[256];
     av_strerror (err, errorstr, sizeof(errorstr));
-    AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path, errorstr);
+    AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path,
+        errorstr);
     goto beach;
   }
 
@@ -198,7 +266,6 @@
         s->input_samplerate, s->samplerate);
   }
 
-  AVFrame *avFrame = s->avFrame;
   avFrame = av_frame_alloc();
   if (!avFrame) {
     AUBIO_ERR("source_avcodec: Could not allocate frame for (%s)\n", s->path);
@@ -205,7 +272,8 @@
   }
 
   /* allocate output for avr */
-  s->output = (float *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE * sizeof(float));
+  s->output = (smpl_t *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE
+      * sizeof(smpl_t));
 
   s->read_samples = 0;
   s->read_index = 0;
@@ -214,11 +282,11 @@
   s->avCodecCtx = avCodecCtx;
   s->avFrame = avFrame;
 
-  // default to mono output
-  aubio_source_avcodec_reset_resampler(s, 0);
+  aubio_source_avcodec_reset_resampler(s);
 
+  if (s->avr == NULL) goto beach;
+
   s->eof = 0;
-  s->multi = 0;
 
   //av_log_set_level(AV_LOG_QUIET);
 
@@ -231,47 +299,78 @@
   return NULL;
 }
 
-void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi) {
-  if ( (multi != s->multi) || (s->avr == NULL) ) {
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s)
+{
+  // create or reset resampler to/from mono/multi-channel
+  if ( s->avr == NULL ) {
+    int err;
     int64_t input_layout = av_get_default_channel_layout(s->input_channels);
-    uint_t output_channels = multi ? s->input_channels : 1;
-    int64_t output_layout = av_get_default_channel_layout(output_channels);
-    if (s->avr != NULL) {
-      avresample_close( s->avr );
-      av_free ( s->avr );
-      s->avr = NULL;
-    }
-    AVAudioResampleContext *avr = s->avr;
-    avr = avresample_alloc_context();
+    int64_t output_layout = av_get_default_channel_layout(s->input_channels);
+#ifdef HAVE_AVRESAMPLE
+    AVAudioResampleContext *avr = avresample_alloc_context();
+#elif defined(HAVE_SWRESAMPLE)
+    SwrContext *avr = swr_alloc();
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
 
-    av_opt_set_int(avr, "in_channel_layout",  input_layout,           0);
-    av_opt_set_int(avr, "out_channel_layout", output_layout,          0);
-    av_opt_set_int(avr, "in_sample_rate",     s->input_samplerate,    0);
-    av_opt_set_int(avr, "out_sample_rate",    s->samplerate,          0);
+    av_opt_set_int(avr, "in_channel_layout",  input_layout,              0);
+    av_opt_set_int(avr, "out_channel_layout", output_layout,             0);
+    av_opt_set_int(avr, "in_sample_rate",     s->input_samplerate,       0);
+    av_opt_set_int(avr, "out_sample_rate",    s->samplerate,             0);
     av_opt_set_int(avr, "in_sample_fmt",      s->avCodecCtx->sample_fmt, 0);
-    av_opt_set_int(avr, "out_sample_fmt",     AV_SAMPLE_FMT_FLT,      0);
-    int err;
-    if ( ( err = avresample_open(avr) ) < 0) {
+#if HAVE_AUBIO_DOUBLE
+    av_opt_set_int(avr, "out_sample_fmt",     AV_SAMPLE_FMT_DBL,         0);
+#else
+    av_opt_set_int(avr, "out_sample_fmt",     AV_SAMPLE_FMT_FLT,         0);
+#endif
+    // TODO: use planar?
+    //av_opt_set_int(avr, "out_sample_fmt",     AV_SAMPLE_FMT_FLTP,      0);
+#ifdef HAVE_AVRESAMPLE
+    if ( ( err = avresample_open(avr) ) < 0)
+#elif defined(HAVE_SWRESAMPLE)
+    if ( ( err = swr_init(avr) ) < 0)
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
+    {
       char errorstr[256];
       av_strerror (err, errorstr, sizeof(errorstr));
-      AUBIO_ERR("source_avcodec: Could not open AVAudioResampleContext for %s (%s)\n",
-          s->path, errorstr);
-      //goto beach;
+      AUBIO_ERR("source_avcodec: Could not open resampling context"
+         " for %s (%s)\n", s->path, errorstr);
       return;
     }
     s->avr = avr;
-    s->multi = multi;
   }
 }
 
-void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples) {
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s,
+    uint_t * read_samples)
+{
   AVFormatContext *avFormatCtx = s->avFormatCtx;
   AVCodecContext *avCodecCtx = s->avCodecCtx;
   AVFrame *avFrame = s->avFrame;
-  AVPacket avPacket;
-  av_init_packet (&avPacket);
+  AVPacket avPacket = s->avPacket;
+#ifdef HAVE_AVRESAMPLE
   AVAudioResampleContext *avr = s->avr;
-  float *output = s->output;
+#elif defined(HAVE_SWRESAMPLE)
+  SwrContext *avr = s->avr;
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
+  int got_frame = 0;
+#ifdef HAVE_AVRESAMPLE
+  int in_linesize = 0;
+  int in_samples = avFrame->nb_samples;
+  int out_linesize = 0;
+  int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
+  int out_samples = 0;
+#elif defined(HAVE_SWRESAMPLE)
+  int in_samples = avFrame->nb_samples;
+  int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE / avCodecCtx->channels;
+  int out_samples = 0;
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
+  smpl_t *output = s->output;
+#ifndef FF_API_LAVF_AVCTX
+  int len = 0;
+#else
+  int ret = 0;
+#endif
+  av_init_packet (&avPacket);
   *read_samples = 0;
 
   do
@@ -284,34 +383,81 @@
     if (err != 0) {
       char errorstr[256];
       av_strerror (err, errorstr, sizeof(errorstr));
-      AUBIO_ERR("Could not read frame in %s (%s)\n", s->path, errorstr);
+      AUBIO_ERR("source_avcodec: could not read frame in %s (%s)\n",
+          s->path, errorstr);
+      s->eof = 1;
       goto beach;
     }
   } while (avPacket.stream_index != s->selected_stream);
 
-  int got_frame = 0;
-  int len = avcodec_decode_audio4(avCodecCtx, avFrame, &got_frame, &avPacket);
+#if FF_API_LAVF_AVCTX
+  ret = avcodec_send_packet(avCodecCtx, &avPacket);
+  if (ret < 0 && ret != AVERROR_EOF) {
+    AUBIO_ERR("source_avcodec: error when sending packet for %s\n", s->path);
+    goto beach;
+  }
+  ret = avcodec_receive_frame(avCodecCtx, avFrame);
+  if (ret >= 0) {
+    got_frame = 1;
+  }
+  if (ret < 0) {
+    if (ret == AVERROR(EAGAIN)) {
+      //AUBIO_WRN("source_avcodec: output is not available right now - "
+      //    "user must try to send new input\n");
+      goto beach;
+    } else if (ret == AVERROR_EOF) {
+      AUBIO_WRN("source_avcodec: the decoder has been fully flushed, "
+          "and there will be no more output frames\n");
+    } else {
+      AUBIO_ERR("source_avcodec: decoding errors on %s\n", s->path);
+      goto beach;
+    }
+  }
+#else
+  len = avcodec_decode_audio4(avCodecCtx, avFrame, &got_frame, &avPacket);
 
   if (len < 0) {
-    AUBIO_ERR("Error while decoding %s\n", s->path);
+    AUBIO_ERR("source_avcodec: error while decoding %s\n", s->path);
     goto beach;
   }
+#endif
   if (got_frame == 0) {
-    //AUBIO_ERR("Could not get frame for (%s)\n", s->path);
+    AUBIO_WRN("source_avcodec: did not get a frame when reading %s\n",
+        s->path);
     goto beach;
   }
 
-  int in_linesize = 0;
+#if LIBAVUTIL_VERSION_MAJOR > 52
+  if (avFrame->channels != (sint_t)s->input_channels) {
+    AUBIO_WRN ("source_avcodec: trying to read from %d channel(s),"
+        "but configured for %d; is '%s' corrupt?\n",
+        avFrame->channels, s->input_channels, s->path);
+    goto beach;
+  }
+#else
+#warning "avutil < 53 is deprecated, crashes might occur on corrupt files"
+#endif
+
+#ifdef HAVE_AVRESAMPLE
+  in_linesize = 0;
   av_samples_get_buffer_size(&in_linesize, avCodecCtx->channels,
       avFrame->nb_samples, avCodecCtx->sample_fmt, 1);
-  int in_samples = avFrame->nb_samples;
-  int out_linesize = 0;
-  int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
-  int out_samples = avresample_convert ( avr,
+  in_samples = avFrame->nb_samples;
+  out_linesize = 0;
+  max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
+  out_samples = avresample_convert ( avr,
         (uint8_t **)&output, out_linesize, max_out_samples,
         (uint8_t **)avFrame->data, in_linesize, in_samples);
+#elif defined(HAVE_SWRESAMPLE)
+  in_samples = avFrame->nb_samples;
+  max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE / avCodecCtx->channels;
+  out_samples = swr_convert( avr,
+      (uint8_t **)&output, max_out_samples,
+      (const uint8_t **)avFrame->data, in_samples);
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
   if (out_samples <= 0) {
-    //AUBIO_ERR("No sample found while converting frame (%s)\n", s->path);
+    AUBIO_WRN("source_avcodec: no sample found while converting frame (%s)\n",
+        s->path);
     goto beach;
   }
 
@@ -321,21 +467,28 @@
   s->avFormatCtx = avFormatCtx;
   s->avCodecCtx = avCodecCtx;
   s->avFrame = avFrame;
+#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
   s->avr = avr;
+#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
   s->output = output;
 
   av_packet_unref(&avPacket);
 }
 
-void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data, uint_t * read){
-  if (s->multi == 1) aubio_source_avcodec_reset_resampler(s, 0);
-  uint_t i;
+void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data,
+    uint_t * read) {
+  uint_t i, j;
   uint_t end = 0;
   uint_t total_wrote = 0;
   while (total_wrote < s->hop_size) {
     end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
     for (i = 0; i < end; i++) {
-      read_data->data[i + total_wrote] = s->output[i + s->read_index];
+      read_data->data[i + total_wrote] = 0.;
+      for (j = 0; j < s->input_channels; j++) {
+        read_data->data[i + total_wrote] +=
+          s->output[(i + s->read_index) * s->input_channels + j];
+      }
+      read_data->data[i + total_wrote] *= 1./s->input_channels;
     }
     total_wrote += end;
     if (total_wrote < s->hop_size) {
@@ -351,7 +504,7 @@
     }
   }
   if (total_wrote < s->hop_size) {
-    for (i = end; i < s->hop_size; i++) {
+    for (i = total_wrote; i < s->hop_size; i++) {
       read_data->data[i] = 0.;
     }
   }
@@ -358,8 +511,8 @@
   *read = total_wrote;
 }
 
-void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s, fmat_t * read_data, uint_t * read){
-  if (s->multi == 0) aubio_source_avcodec_reset_resampler(s, 1);
+void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s,
+    fmat_t * read_data, uint_t * read) {
   uint_t i,j;
   uint_t end = 0;
   uint_t total_wrote = 0;
@@ -386,7 +539,7 @@
   }
   if (total_wrote < s->hop_size) {
     for (j = 0; j < read_data->height; j++) {
-      for (i = end; i < s->hop_size; i++) {
+      for (i = total_wrote; i < s->hop_size; i++) {
         read_data->data[j][i] = 0.;
       }
     }
@@ -403,22 +556,42 @@
 }
 
 uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t * s, uint_t pos) {
-  int64_t resampled_pos = (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
+  int64_t resampled_pos =
+    (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
   int64_t min_ts = MAX(resampled_pos - 2000, 0);
   int64_t max_ts = MIN(resampled_pos + 2000, INT64_MAX);
   int seek_flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY;
-  int ret = avformat_seek_file(s->avFormatCtx, s->selected_stream,
+  int ret = AUBIO_FAIL;
+  if (s->avFormatCtx != NULL && s->avr != NULL) {
+    ret = AUBIO_OK;
+  } else {
+    AUBIO_ERR("source_avcodec: failed seeking in %s (file not opened?)",
+        s->path);
+    return ret;
+  }
+  if ((sint_t)pos < 0) {
+    AUBIO_ERR("source_avcodec: could not seek %s at %d (seeking position"
+       " should be >= 0)\n", s->path, pos);
+    return AUBIO_FAIL;
+  }
+  ret = avformat_seek_file(s->avFormatCtx, s->selected_stream,
       min_ts, resampled_pos, max_ts, seek_flags);
   if (ret < 0) {
-    AUBIO_ERR("Failed seeking to %d in file %s", pos, s->path);
+    AUBIO_ERR("source_avcodec: failed seeking to %d in file %s",
+        pos, s->path);
   }
   // reset read status
   s->eof = 0;
   s->read_index = 0;
   s->read_samples = 0;
+#ifdef HAVE_AVRESAMPLE
   // reset the AVAudioResampleContext
   avresample_close(s->avr);
   avresample_open(s->avr);
+#elif defined(HAVE_SWRESAMPLE)
+  swr_close(s->avr);
+  swr_init(s->avr);
+#endif
   return ret;
 }
 
@@ -432,18 +605,27 @@
 
 uint_t aubio_source_avcodec_close(aubio_source_avcodec_t * s) {
   if (s->avr != NULL) {
+#ifdef HAVE_AVRESAMPLE
     avresample_close( s->avr );
+#elif defined(HAVE_SWRESAMPLE)
+    swr_close ( s->avr );
+#endif
     av_free ( s->avr );
   }
   s->avr = NULL;
   if (s->avCodecCtx != NULL) {
+#ifndef HAVE_AUBIO_LIBAVCODEC_DEPRECATED
+    avcodec_free_context( &s->avCodecCtx );
+#else
     avcodec_close ( s->avCodecCtx );
+#endif
   }
   s->avCodecCtx = NULL;
   if (s->avFormatCtx != NULL) {
-    avformat_close_input ( &(s->avFormatCtx) );
+    avformat_close_input(&s->avFormatCtx);
+    s->avFormatCtx = NULL;
   }
-  s->avFormatCtx = NULL;
+  av_packet_unref(&s->avPacket);
   return AUBIO_OK;
 }
 
@@ -457,8 +639,11 @@
   if (s->avFrame != NULL) {
     av_frame_free( &(s->avFrame) );
   }
-  if (s->path) AUBIO_FREE(s->path);
   s->avFrame = NULL;
+  if (s->path) {
+    AUBIO_FREE(s->path);
+  }
+  s->path = NULL;
   AUBIO_FREE(s);
 }
 
--- a/src/io/source_sndfile.c
+++ b/src/io/source_sndfile.c
@@ -18,14 +18,12 @@
 
 */
 
+#include "aubio_priv.h"
 
-#include "config.h"
-
 #ifdef HAVE_SNDFILE
 
 #include <sndfile.h>
 
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "source_sndfile.h"
@@ -32,9 +30,8 @@
 
 #include "temporal/resampler.h"
 
-#define MAX_CHANNELS 6
 #define MAX_SIZE 4096
-#define MAX_SAMPLES MAX_CHANNELS * MAX_SIZE
+#define MAX_SAMPLES AUBIO_MAX_CHANNELS * MAX_SIZE
 
 #if !HAVE_AUBIO_DOUBLE
 #define aubio_sf_read_smpl sf_read_float
@@ -140,7 +137,7 @@
     }
     if (s->ratio > 1) {
       // we would need to add a ring buffer for these
-      if ( (uint_t)(s->input_hop_size * s->ratio + .5)  != s->hop_size ) {
+      if ( (uint_t)FLOOR(s->input_hop_size * s->ratio + .5)  != s->hop_size ) {
         AUBIO_ERR("source_sndfile: can not upsample %s from %d to %d\n", s->path,
             s->input_samplerate, s->samplerate);
         goto beach;
@@ -297,7 +294,18 @@
 
 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);
+  sf_count_t sf_ret;
+  if (s->handle == NULL) {
+    AUBIO_ERR("source_sndfile: failed seeking in %s (file not opened?)\n",
+        s->path);
+    return AUBIO_FAIL;
+  }
+  if ((sint_t)pos < 0) {
+    AUBIO_ERR("source_sndfile: could not seek %s at %d (seeking position"
+       " should be >= 0)\n", s->path, pos);
+    return AUBIO_FAIL;
+  }
+  sf_ret = sf_seek (s->handle, resampled_pos, SEEK_SET);
   if (sf_ret == -1) {
     AUBIO_ERR("source_sndfile: Failed seeking %s at %d: %s\n", s->path, pos, sf_strerror (NULL));
     return AUBIO_FAIL;
@@ -312,12 +320,13 @@
 
 uint_t aubio_source_sndfile_close (aubio_source_sndfile_t *s) {
   if (!s->handle) {
-    return AUBIO_FAIL;
+    return AUBIO_OK;
   }
   if(sf_close(s->handle)) {
     AUBIO_ERR("source_sndfile: Error closing file %s: %s\n", s->path, sf_strerror (NULL));
     return AUBIO_FAIL;
   }
+  s->handle = NULL;
   return AUBIO_OK;
 }
 
--- a/src/io/source_wavread.c
+++ b/src/io/source_wavread.c
@@ -18,11 +18,10 @@
 
 */
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_WAVREAD
 
-#include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
 #include "source_wavread.h"
@@ -76,7 +75,7 @@
 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_junk = 0, bytes_expected = 44;
-  unsigned char buf[5];
+  unsigned char buf[5] = "\0";
   unsigned int format, channels, sr, byterate, blockalign, duration, bitspersample;//, data_size;
 
   if (path == NULL) {
@@ -109,7 +108,7 @@
   bytes_read += fread(buf, 1, 4, s->fid);
   buf[4] = '\0';
   if ( strcmp((const char *)buf, "RIFF") != 0 ) {
-    AUBIO_ERR("source_wavread: could not find RIFF header in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (could not find RIFF header)\n", s->path);
     goto beach;
   }
 
@@ -120,7 +119,7 @@
   bytes_read += fread(buf, 1, 4, s->fid);
   buf[4] = '\0';
   if ( strcmp((const char *)buf, "WAVE") != 0 ) {
-    AUBIO_ERR("source_wavread: wrong format in RIFF header in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (wrong format in RIFF header)\n", s->path);
     goto beach;
   }
 
@@ -134,7 +133,7 @@
     buf[4] = '\0';
     bytes_junk += read_little_endian(buf, 4);
     if (fseek(s->fid, bytes_read + bytes_junk, SEEK_SET) != 0) {
-      AUBIO_ERR("source_wavread: could not seek past JUNK Chunk in %s (%s)\n",
+      AUBIO_ERR("source_wavread: Failed opening %s (could not seek past JUNK Chunk: %s)\n",
           s->path, strerror(errno));
       goto beach;
     }
@@ -147,7 +146,7 @@
 
   // get the fmt chunk
   if ( strcmp((const char *)buf, "fmt ") != 0 ) {
-    AUBIO_ERR("source_wavread: failed finding fmt RIFF header in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (could not find 'fmt ' in RIFF header)\n", s->path);
     goto beach;
   }
 
@@ -156,11 +155,11 @@
   format = read_little_endian(buf, 4);
   if ( format != 16 ) {
     // TODO accept format 18
-    AUBIO_ERR("source_wavread: file %s is not encoded with PCM\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (not encoded with PCM)\n", s->path);
     goto beach;
   }
   if ( buf[1] || buf[2] | buf[3] ) {
-    AUBIO_ERR("source_wavread: Subchunk1Size should be 0, in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (Subchunk1Size should be 0)\n", s->path);
     goto beach;
   }
 
@@ -167,7 +166,7 @@
   // AudioFormat
   bytes_read += fread(buf, 1, 2, s->fid);
   if ( buf[0] != 1 || buf[1] != 0) {
-    AUBIO_ERR("source_wavread: AudioFormat should be PCM, in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (AudioFormat should be PCM)\n", s->path);
     goto beach;
   }
 
@@ -190,6 +189,26 @@
   // BitsPerSample
   bytes_read += fread(buf, 1, 2, s->fid);
   bitspersample = read_little_endian(buf, 2);
+
+  if ( channels == 0 ) {
+    AUBIO_ERR("source_wavread: Failed opening %s (number of channels can not be 0)\n", s->path);
+    goto beach;
+  }
+
+  if ( (sint_t)sr <= 0 ) {
+    AUBIO_ERR("source_wavread: Failed opening %s (samplerate can not be <= 0)\n", s->path);
+    goto beach;
+  }
+
+  if ( byterate == 0 ) {
+    AUBIO_ERR("source_wavread: Failed opening %s (byterate can not be 0)\n", s->path);
+    goto beach;
+  }
+
+  if ( bitspersample == 0 ) {
+    AUBIO_ERR("source_wavread: Failed opening %s (bitspersample can not be 0)\n", s->path);
+    goto beach;
+  }
 #if 0
   if ( bitspersample != 16 ) {
     AUBIO_ERR("source_wavread: can not process %dbit file %s\n",
@@ -199,12 +218,12 @@
 #endif
 
   if ( byterate * 8 != sr * channels * bitspersample ) {
-    AUBIO_ERR("source_wavread: wrong byterate in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (wrong byterate)\n", s->path);
     goto beach;
   }
 
   if ( blockalign * 8 != channels * bitspersample ) {
-    AUBIO_ERR("source_wavread: wrong blockalign in %s\n", s->path);
+    AUBIO_ERR("source_wavread: Failed opening %s (wrong blockalign)\n", s->path);
     goto beach;
   }
 
@@ -329,6 +348,11 @@
   uint_t i, j;
   uint_t end = 0;
   uint_t total_wrote = 0;
+  if (s->fid == NULL) {
+    AUBIO_ERR("source_wavread: could not read from %s (file not opened)\n",
+        s->path);
+    return;
+  }
   while (total_wrote < s->hop_size) {
     end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
     for (i = 0; i < end; i++) {
@@ -363,6 +387,11 @@
   uint_t i,j;
   uint_t end = 0;
   uint_t total_wrote = 0;
+  if (s->fid == NULL) {
+    AUBIO_ERR("source_wavread: could not read from %s (file not opened)\n",
+        s->path);
+    return;
+  }
   while (total_wrote < s->hop_size) {
     end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
     for (j = 0; j < read_data->height; j++) {
@@ -403,7 +432,12 @@
 
 uint_t aubio_source_wavread_seek (aubio_source_wavread_t * s, uint_t pos) {
   uint_t ret = 0;
+  if (s->fid == NULL) {
+    AUBIO_ERR("source_wavread: could not seek %s (file not opened?)\n", s->path, pos);
+    return AUBIO_FAIL;
+  }
   if ((sint_t)pos < 0) {
+    AUBIO_ERR("source_wavread: could not seek %s at %d (seeking position should be >= 0)\n", s->path, pos);
     return AUBIO_FAIL;
   }
   ret = fseek(s->fid, s->seek_start + pos * s->blockalign, SEEK_SET);
@@ -425,8 +459,8 @@
 }
 
 uint_t aubio_source_wavread_close (aubio_source_wavread_t * s) {
-  if (!s->fid) {
-    return AUBIO_FAIL;
+  if (s->fid == NULL) {
+    return AUBIO_OK;
   }
   if (fclose(s->fid)) {
     AUBIO_ERR("source_wavread: could not close %s (%s)\n", s->path, strerror(errno));
--- a/src/io/utils_apple_audio.c
+++ b/src/io/utils_apple_audio.c
@@ -1,4 +1,4 @@
-#include "config.h"
+#include "aubio_priv.h"
 
 #if defined(HAVE_SOURCE_APPLE_AUDIO) || defined(HAVE_SINK_APPLE_AUDIO)
 
@@ -6,7 +6,6 @@
 #include <CoreFoundation/CoreFoundation.h>
 // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
 #include <AudioToolbox/AudioToolbox.h>
-#include "aubio_priv.h"
 
 int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize);
 void freeAudioBufferList(AudioBufferList *bufferList);
--- a/src/mathutils.c
+++ b/src/mathutils.c
@@ -24,11 +24,11 @@
 #include "fvec.h"
 #include "mathutils.h"
 #include "musicutils.h"
-#include "config.h"
 
 /** Window types */
 typedef enum
 {
+  aubio_win_ones,
   aubio_win_rectangle,
   aubio_win_hamming,
   aubio_win_hanning,
@@ -64,7 +64,9 @@
   if (window_type == NULL) {
       AUBIO_ERR ("window type can not be null.\n");
       return 1;
-  } else if (strcmp (window_type, "rectangle") == 0)
+  } else if (strcmp (window_type, "ones") == 0)
+      wintype = aubio_win_ones;
+  else if (strcmp (window_type, "rectangle") == 0)
       wintype = aubio_win_rectangle;
   else if (strcmp (window_type, "hamming") == 0)
       wintype = aubio_win_hamming;
@@ -89,9 +91,11 @@
       return 1;
   }
   switch(wintype) {
+    case aubio_win_ones:
+      fvec_ones(win);
+      break;
     case aubio_win_rectangle:
-      for (i=0;i<size;i++)
-        w[i] = 0.5;
+      fvec_set_all(win, .5);
       break;
     case aubio_win_hamming:
       for (i=0;i<size;i++)
@@ -155,16 +159,19 @@
 fvec_mean (fvec_t * s)
 {
   smpl_t tmp = 0.0;
-#ifndef HAVE_ACCELERATE
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsMean(s->data, (int)s->length, &tmp);
+  return tmp;
+#elif defined(HAVE_ACCELERATE)
+  aubio_vDSP_meanv(s->data, 1, &tmp, s->length);
+  return tmp;
+#else
   uint_t j;
   for (j = 0; j < s->length; j++) {
     tmp += s->data[j];
   }
-  return tmp / (smpl_t) (s->length);
-#else
-  aubio_vDSP_meanv(s->data, 1, &tmp, s->length);
-  return tmp;
-#endif /* HAVE_ACCELERATE */
+  return tmp / (smpl_t)(s->length);
+#endif
 }
 
 smpl_t
@@ -171,14 +178,16 @@
 fvec_sum (fvec_t * s)
 {
   smpl_t tmp = 0.0;
-#ifndef HAVE_ACCELERATE
+#if defined(HAVE_INTEL_IPP)
+  aubio_ippsSum(s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+  aubio_vDSP_sve(s->data, 1, &tmp, s->length);
+#else
   uint_t j;
   for (j = 0; j < s->length; j++) {
     tmp += s->data[j];
   }
-#else
-  aubio_vDSP_sve(s->data, 1, &tmp, s->length);
-#endif /* HAVE_ACCELERATE */
+#endif
   return tmp;
 }
 
@@ -185,15 +194,18 @@
 smpl_t
 fvec_max (fvec_t * s)
 {
-#ifndef HAVE_ACCELERATE
+#if defined(HAVE_INTEL_IPP)
+  smpl_t tmp = 0.;
+  aubio_ippsMax( s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+  smpl_t tmp = 0.;
+  aubio_vDSP_maxv( s->data, 1, &tmp, s->length );
+#else
   uint_t j;
-  smpl_t tmp = 0.0;
-  for (j = 0; j < s->length; j++) {
+  smpl_t tmp = s->data[0];
+  for (j = 1; j < s->length; j++) {
     tmp = (tmp > s->data[j]) ? tmp : s->data[j];
   }
-#else
-  smpl_t tmp = 0.;
-  aubio_vDSP_maxv(s->data, 1, &tmp, s->length);
 #endif
   return tmp;
 }
@@ -201,15 +213,18 @@
 smpl_t
 fvec_min (fvec_t * s)
 {
-#ifndef HAVE_ACCELERATE
+#if defined(HAVE_INTEL_IPP)
+  smpl_t tmp = 0.;
+  aubio_ippsMin(s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+  smpl_t tmp = 0.;
+  aubio_vDSP_minv(s->data, 1, &tmp, s->length);
+#else
   uint_t j;
   smpl_t tmp = s->data[0];
-  for (j = 0; j < s->length; j++) {
+  for (j = 1; j < s->length; j++) {
     tmp = (tmp < s->data[j]) ? tmp : s->data[j];
   }
-#else
-  smpl_t tmp = 0.;
-  aubio_vDSP_minv(s->data, 1, &tmp, s->length);
 #endif
   return tmp;
 }
@@ -226,10 +241,10 @@
   }
 #else
   smpl_t tmp = 0.;
-  uint_t pos = 0.;
-  aubio_vDSP_minvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+  vDSP_Length pos = 0;
+  aubio_vDSP_minvi(s->data, 1, &tmp, &pos, s->length);
 #endif
-  return pos;
+  return (uint_t)pos;
 }
 
 uint_t
@@ -244,10 +259,10 @@
   }
 #else
   smpl_t tmp = 0.;
-  uint_t pos = 0.;
-  aubio_vDSP_maxvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+  vDSP_Length pos = 0;
+  aubio_vDSP_maxvi(s->data, 1, &tmp, &pos, s->length);
 #endif
-  return pos;
+  return (uint_t)pos;
 }
 
 void
@@ -256,7 +271,7 @@
   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
+#ifndef HAVE_BLAS
   for (j = 0; j < half; j++) {
     ELEM_SWAP (s->data[j], s->data[j + start]);
   }
@@ -276,7 +291,7 @@
   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
+#ifndef HAVE_BLAS
   for (j = 0; j < half; j++) {
     ELEM_SWAP (s->data[j], s->data[j + start]);
   }
@@ -290,11 +305,30 @@
   }
 }
 
+void fvec_push(fvec_t *in, smpl_t new_elem) {
+  uint_t i;
+  for (i = 0; i < in->length - 1; i++) {
+    in->data[i] = in->data[i + 1];
+  }
+  in->data[in->length - 1] = new_elem;
+}
+
+void fvec_clamp(fvec_t *in, smpl_t absmax) {
+  uint_t i;
+  for (i = 0; i < in->length; i++) {
+    if (in->data[i] > 0 && in->data[i] > ABS(absmax)) {
+      in->data[i] = absmax;
+    } else if (in->data[i] < 0 && in->data[i] < -ABS(absmax)) {
+      in->data[i] = -absmax;
+    }
+  }
+}
+
 smpl_t
 aubio_level_lin (const fvec_t * f)
 {
   smpl_t energy = 0.;
-#ifndef HAVE_ATLAS
+#ifndef HAVE_BLAS
   uint_t j;
   for (j = 0; j < f->length; j++) {
     energy += SQR (f->data[j]);
@@ -353,6 +387,15 @@
   }
 }
 
+void
+fvec_mul (fvec_t *o, smpl_t val)
+{
+  uint_t j;
+  for (j = 0; j < o->length; j++) {
+    o->data[j] *= val;
+  }
+}
+
 void fvec_adapt_thres(fvec_t * vec, fvec_t * tmp,
     uint_t post, uint_t pre) {
   uint_t length = vec->length, j;
@@ -488,7 +531,7 @@
   if (freq < 2. || freq > 100000.) return 0.; // avoid nans and infs
   /* log(freq/A-2)/log(2) */
   midi = freq / 6.875;
-  midi = LOG (midi) / 0.69314718055995;
+  midi = LOG (midi) / 0.6931471805599453;
   midi *= 12;
   midi -= 3;
   return midi;
@@ -500,7 +543,7 @@
   smpl_t freq;
   if (midi > 140.) return 0.; // avoid infs
   freq = (midi + 3.) / 12.;
-  freq = EXP (freq * 0.69314718055995);
+  freq = EXP (freq * 0.6931471805599453);
   freq *= 6.875;
   return freq;
 }
@@ -549,6 +592,17 @@
   uint_t i = 1;
   while (i < a) i <<= 1;
   return i;
+}
+
+uint_t
+aubio_power_of_two_order (uint_t a)
+{
+  int order = 0;
+  int temp = aubio_next_power_of_two(a);
+  while (temp >>= 1) {
+    ++order;
+  }
+  return order;
 }
 
 smpl_t
--- a/src/mathutils.h
+++ b/src/mathutils.h
@@ -117,6 +117,17 @@
 */
 void fvec_ishift (fvec_t * v);
 
+/** push a new element to the end of a vector, erasing the first element and
+ * sliding all others
+
+  \param in vector to push to
+  \param new_elem new_element to add at the end of the vector
+
+  In numpy words, this is equivalent to: in = np.concatenate([in, [new_elem]])[1:]
+
+*/
+void fvec_push(fvec_t *in, smpl_t new_elem);
+
 /** compute the sum of all elements of a vector
 
   \param v vector to compute the sum of
@@ -182,6 +193,14 @@
 */
 void fvec_add (fvec_t * v, smpl_t c);
 
+/** multiply each elements of a vector by a scalar
+
+  \param v vector to add constant to
+  \param s constant to scale v with
+
+*/
+void fvec_mul (fvec_t * v, smpl_t s);
+
 /** remove the minimum value of the vector to each elements
 
   \param v vector to remove minimum from
@@ -300,6 +319,9 @@
 
 /** return the next power of power of 2 greater than a */
 uint_t aubio_next_power_of_two(uint_t a);
+
+/** return the log2 factor of the given power of 2 value a */
+uint_t aubio_power_of_two_order(uint_t a);
 
 /** compute normalised autocorrelation function
 
--- /dev/null
+++ b/src/musicutils.c
@@ -1,0 +1,85 @@
+/*
+  Copyright (C) 2018 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "musicutils.h"
+
+smpl_t
+aubio_hztomel (smpl_t freq)
+{
+  const smpl_t lin_space = 3./200.;
+  const smpl_t split_hz = 1000.;
+  const smpl_t split_mel = split_hz * lin_space;
+  const smpl_t log_space = 27./LOG(6400/1000.);
+  if (freq < 0) {
+    AUBIO_WRN("hztomel: input frequency should be >= 0\n");
+    return 0;
+  }
+  if (freq < split_hz)
+  {
+    return freq * lin_space;
+  } else {
+    return split_mel + log_space * LOG (freq / split_hz);
+  }
+
+}
+
+smpl_t
+aubio_meltohz (smpl_t mel)
+{
+  const smpl_t lin_space = 200./3.;
+  const smpl_t split_hz = 1000.;
+  const smpl_t split_mel = split_hz / lin_space;
+  const smpl_t logSpacing = POW(6400/1000., 1/27.);
+  if (mel < 0) {
+    AUBIO_WRN("meltohz: input mel should be >= 0\n");
+    return 0;
+  }
+  if (mel < split_mel) {
+    return lin_space * mel;
+  } else {
+    return split_hz * POW(logSpacing, mel - split_mel);
+  }
+}
+
+smpl_t
+aubio_hztomel_htk (smpl_t freq)
+{
+  const smpl_t split_hz = 700.;
+  const smpl_t log_space = 1127.;
+  if (freq < 0) {
+    AUBIO_WRN("hztomel_htk: input frequency should be >= 0\n");
+    return 0;
+  }
+  return log_space * LOG (1 + freq / split_hz);
+}
+
+smpl_t
+aubio_meltohz_htk (smpl_t mel)
+{
+  const smpl_t split_hz = 700.;
+  const smpl_t log_space = 1./1127.;
+  if (mel < 0) {
+    AUBIO_WRN("meltohz_htk: input frequency should be >= 0\n");
+    return 0;
+  }
+  return split_hz * ( EXP ( mel * log_space) - 1.);
+}
+
--- a/src/musicutils.h
+++ b/src/musicutils.h
@@ -86,6 +86,105 @@
 /** convert frequency (Hz) to frequency bin */
 smpl_t aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize);
 
+/** convert frequency (Hz) to mel
+
+  \param freq input frequency, in Hz
+
+  \return output mel
+
+  Converts a scalar from the frequency domain to the mel scale using Slaney
+  Auditory Toolbox's implementation:
+
+  If \f$ f < 1000 \f$, \f$ m = 3 f / 200 \f$.
+
+  If \f$ f >= 1000 \f$, \f$ m = 1000 + 27 \frac{{ln}(f) - ln(1000))}
+  {{ln}(6400) - ln(1000)}
+  \f$
+
+  See also
+  --------
+
+  aubio_meltohz(), aubio_hztomel_htk().
+
+*/
+smpl_t aubio_hztomel (smpl_t freq);
+
+/** convert mel to frequency (Hz)
+
+  \param mel input mel
+
+  \return output frequency, in Hz
+
+  Converts a scalar from the mel scale to the frequency domain using Slaney
+  Auditory Toolbox's implementation:
+
+  If \f$ f < 1000 \f$, \f$ f = 200 m/3 \f$.
+
+  If \f$ f \geq 1000 \f$, \f$ f = 1000 + \left(\frac{6400}{1000}\right)
+  ^{\frac{m - 1000}{27}} \f$
+
+  See also
+  --------
+
+  aubio_hztomel(), aubio_meltohz_htk().
+
+  References
+  ----------
+
+  Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+  https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+*/
+smpl_t aubio_meltohz (smpl_t mel);
+
+/** convert frequency (Hz) to mel
+
+  \param freq input frequency, in Hz
+
+  \return output mel
+
+  Converts a scalar from the frequency domain to the mel scale, using the
+  equation defined by O'Shaughnessy, as implemented in the HTK speech
+  recognition toolkit:
+
+  \f$ m = 1127 + ln(1 + \frac{f}{700}) \f$
+
+  See also
+  --------
+
+  aubio_meltohz_htk(), aubio_hztomel().
+
+  References
+  ----------
+
+  Douglas O'Shaughnessy (1987). *Speech communication: human and machine*.
+  Addison-Wesley. p. 150. ISBN 978-0-201-16520-3.
+
+  HTK Speech Recognition Toolkit: http://htk.eng.cam.ac.uk/
+
+ */
+smpl_t aubio_hztomel_htk (smpl_t freq);
+
+/** convert mel to frequency (Hz)
+
+  \param mel input mel
+
+  \return output frequency, in Hz
+
+  Converts a scalar from the mel scale to the frequency domain, using the
+  equation defined by O'Shaughnessy, as implemented in the HTK speech
+  recognition toolkit:
+
+  \f$ f = 700 * {e}^\left(\frac{f}{1127} - 1\right) \f$
+
+  See also
+  --------
+
+  aubio_hztomel_htk(), aubio_meltohz().
+
+*/
+smpl_t aubio_meltohz_htk (smpl_t mel);
+
 /** convert frequency (Hz) to midi value (0-128) */
 smpl_t aubio_freqtomidi (smpl_t freq);
 
@@ -155,6 +254,14 @@
 
 */
 smpl_t aubio_level_detection (const fvec_t * v, smpl_t threshold);
+
+/** clamp the values of a vector within the range [-abs(max), abs(max)]
+
+  \param in vector to clamp
+  \param absmax maximum value over which input vector elements should be clamped
+
+*/
+void fvec_clamp(fvec_t *in, smpl_t absmax);
 
 #ifdef __cplusplus
 }
--- a/src/notes/notes.c
+++ b/src/notes/notes.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+  Copyright (C) 2014-2018 Paul Brossier <piem@aubio.org>
 
   This file is part of aubio.
 
@@ -24,6 +24,13 @@
 #include "onset/onset.h"
 #include "notes/notes.h"
 
+#define AUBIO_DEFAULT_NOTES_SILENCE -70.
+#define AUBIO_DEFAULT_NOTES_RELEASE_DROP 10.
+// increase to 10. for .1  cent precision
+//      or to 100. for .01 cent precision
+#define AUBIO_DEFAULT_CENT_PRECISION 1.
+#define AUBIO_DEFAULT_NOTES_MINIOI_MS 30.
+
 struct _aubio_notes_t {
 
   uint_t onset_buf_size;
@@ -50,6 +57,9 @@
   smpl_t silence_threshold;
 
   uint_t isready;
+
+  smpl_t last_onset_level;
+  smpl_t release_drop_level;
 };
 
 aubio_notes_t * new_aubio_notes (const char_t * method,
@@ -73,11 +83,14 @@
   o->isready = 0;
 
   o->onset = new_aubio_onset (onset_method, o->onset_buf_size, o->hop_size, o->samplerate);
+  if (o->onset == NULL) goto fail;
   if (o->onset_threshold != 0.) aubio_onset_set_threshold (o->onset, o->onset_threshold);
   o->onset_output = new_fvec (1);
 
   o->pitch = new_aubio_pitch (pitch_method, o->pitch_buf_size, o->hop_size, o->samplerate);
+  if (o->pitch == NULL) goto fail;
   if (o->pitch_tolerance != 0.) aubio_pitch_set_tolerance (o->pitch, o->pitch_tolerance);
+  aubio_pitch_set_unit (o->pitch, "midi");
   o->pitch_output = new_fvec (1);
 
   if (strcmp(method, "default") != 0) {
@@ -87,11 +100,18 @@
   o->note_buffer = new_fvec(o->median);
   o->note_buffer2 = new_fvec(o->median);
 
+  if (!o->onset_output || !o->pitch_output ||
+      !o->note_buffer || !o->note_buffer2) goto fail;
+
   o->curnote = -1.;
   o->newnote = 0.;
 
-  o->silence_threshold = -90.;
+  aubio_notes_set_silence(o, AUBIO_DEFAULT_NOTES_SILENCE);
+  aubio_notes_set_minioi_ms (o, AUBIO_DEFAULT_NOTES_MINIOI_MS);
 
+  o->last_onset_level = AUBIO_DEFAULT_NOTES_SILENCE;
+  o->release_drop_level = AUBIO_DEFAULT_NOTES_RELEASE_DROP;
+
   return o;
 
 fail:
@@ -99,6 +119,55 @@
   return NULL;
 }
 
+uint_t aubio_notes_set_silence(aubio_notes_t *o, smpl_t silence)
+{
+  uint_t err = AUBIO_OK;
+  if (aubio_pitch_set_silence(o->pitch, silence) != AUBIO_OK) {
+    err = AUBIO_FAIL;
+  }
+  if (aubio_onset_set_silence(o->onset, silence) != AUBIO_OK) {
+    err = AUBIO_FAIL;
+  }
+  o->silence_threshold = silence;
+  return err;
+}
+
+smpl_t aubio_notes_get_silence(const aubio_notes_t *o)
+{
+  return aubio_pitch_get_silence(o->pitch);
+}
+
+uint_t aubio_notes_set_minioi_ms (aubio_notes_t *o, smpl_t minioi_ms)
+{
+  uint_t err = AUBIO_OK;
+  if (!o->onset || (aubio_onset_set_minioi_ms(o->onset, minioi_ms) != 0)) {
+    err = AUBIO_FAIL;
+  }
+  return err;
+}
+
+smpl_t aubio_notes_get_minioi_ms(const aubio_notes_t *o)
+{
+  return aubio_onset_get_minioi_ms(o->onset);
+}
+
+uint_t aubio_notes_set_release_drop(aubio_notes_t *o, smpl_t release_drop_level)
+{
+  uint_t err = AUBIO_OK;
+  if (release_drop_level <= 0.) {
+    AUBIO_ERR("notes: release_drop should be >= 0, got %f\n", release_drop_level);
+    err = AUBIO_FAIL;
+  } else {
+    o->release_drop_level = release_drop_level;
+  }
+  return err;
+}
+
+smpl_t aubio_notes_get_release_drop(const aubio_notes_t *o)
+{
+  return o->release_drop_level;
+}
+
 /** append new note candidate to the note_buffer and return filtered value. we
  * need to copy the input array as fvec_median destroy its input data.*/
 static void
@@ -108,18 +177,16 @@
   for (i = 0; i < note_buffer->length - 1; i++) {
     note_buffer->data[i] = note_buffer->data[i + 1];
   }
-  note_buffer->data[note_buffer->length - 1] = curnote;
+  //note_buffer->data[note_buffer->length - 1] = ROUND(10.*curnote)/10.;
+  note_buffer->data[note_buffer->length - 1] = ROUND(AUBIO_DEFAULT_CENT_PRECISION*curnote);
   return;
 }
 
-static uint_t
+static smpl_t
 aubio_notes_get_latest_note (aubio_notes_t *o)
 {
-  uint_t i;
-  for (i = 0; i < o->note_buffer->length; i++) {
-    o->note_buffer2->data[i] = o->note_buffer->data[i];
-  }
-  return fvec_median (o->note_buffer2);
+  fvec_copy(o->note_buffer, o->note_buffer2);
+  return fvec_median (o->note_buffer2) / AUBIO_DEFAULT_CENT_PRECISION;
 }
 
 
@@ -145,6 +212,7 @@
       //send_noteon(o->curnote,0);
       //notes->data[0] = o->curnote;
       //notes->data[1] = 0.;
+      //AUBIO_WRN("notes: sending note-off at onset, not enough level\n");
       notes->data[2] = o->curnote;
     } else {
       if (o->median) {
@@ -152,6 +220,7 @@
       } else {
         /* kill old note */
         //send_noteon(o->curnote,0, o->samplerate);
+        //AUBIO_WRN("notes: sending note-off at onset, new onset detected\n");
         notes->data[2] = o->curnote;
         /* get and send new one */
         //send_noteon(new_pitch,127+(int)floor(curlevel), o->samplerate);
@@ -159,9 +228,22 @@
         notes->data[1] = 127 + (int)floor(curlevel);
         o->curnote = new_pitch;
       }
+      o->last_onset_level = curlevel;
     }
   } else {
-    if (o->median) {
+    if (curlevel < o->last_onset_level - o->release_drop_level)
+    {
+      // send note off
+      //AUBIO_WRN("notes: sending note-off, release detected\n");
+      notes->data[0] = 0;
+      notes->data[1] = 0;
+      notes->data[2] = o->curnote;
+      // reset last_onset_level to silence_threshold
+      o->last_onset_level = o->silence_threshold;
+      o->curnote = 0;
+    }
+    else if (o->median)
+    {
       if (o->isready > 0)
         o->isready++;
       if (o->isready == o->median)
@@ -168,7 +250,11 @@
       {
         /* kill old note */
         //send_noteon(curnote,0);
-        notes->data[2] = o->curnote;
+        if (o->curnote != 0)
+        {
+          //AUBIO_WRN("notes: sending note-off, new note detected\n");
+          notes->data[2] = o->curnote;
+        }
         o->newnote = aubio_notes_get_latest_note(o);
         o->curnote = o->newnote;
         /* get and send new one */
--- a/src/notes/notes.h
+++ b/src/notes/notes.h
@@ -18,6 +18,12 @@
 
 */
 
+/** \file
+
+  Note detection object
+
+*/
+
 #ifndef _AUBIO_NOTES_H
 #define _AUBIO_NOTES_H
 
@@ -51,11 +57,84 @@
 /** execute note detection on an input signal frame
 
   \param o note detection object as returned by new_aubio_notes()
-  \param in input signal of size [hop_size]
-  \param out output notes of size [3] ? FIXME
+  \param input input signal of size [hop_size]
+  \param output output notes, fvec of length 3
 
+  The notes output is a vector of length 3 containing:
+   - 0. the midi note value, or 0 if no note was found
+   - 1. the note velocity
+   - 2. the midi note to turn off
+
 */
 void aubio_notes_do (aubio_notes_t *o, const fvec_t * input, fvec_t * output);
+
+/** set notes detection silence threshold
+
+  \param o notes detection object as returned by new_aubio_notes()
+  \param silence new silence detection threshold
+
+  \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_silence(aubio_notes_t * o, smpl_t silence);
+
+/** get notes detection silence threshold
+
+  \param o notes detection object as returned by new_aubio_notes()
+
+  \return current silence threshold
+
+*/
+smpl_t aubio_notes_get_silence(const aubio_notes_t * o);
+
+/** get notes detection minimum inter-onset interval, in millisecond
+
+  \param o notes detection object as returned by new_aubio_notes()
+
+  \return current minimum inter onset interval
+
+ */
+smpl_t aubio_notes_get_minioi_ms(const aubio_notes_t *o);
+
+/** set notes detection minimum inter-onset interval, in millisecond
+
+  \param o notes detection object as returned by new_aubio_notes()
+  \param minioi_ms new inter-onset interval
+
+  \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_minioi_ms (aubio_notes_t *o, smpl_t minioi_ms);
+
+/** get notes object release drop level, in dB
+
+  \param o notes detection object as returned by new_aubio_notes()
+
+  \return current release drop level, in dB
+
+ */
+smpl_t aubio_notes_get_release_drop (const aubio_notes_t *o);
+
+/** set note release drop level, in dB
+
+  This function sets the release_drop_level parameter, in dB. When a new note
+  is found, the current level in dB is measured. If the measured level drops
+  under that initial level - release_drop_level, then a note-off will be
+  emitted.
+
+  Defaults to `10`, in dB.
+
+  \note This parameter was added in version `0.4.8`. Results obtained with
+  earlier versions can be reproduced by setting this value to `100`, so that
+  note-off will not be played until the next note.
+
+  \param o notes detection object as returned by new_aubio_notes()
+  \param release_drop new release drop level, in dB
+
+  \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_release_drop (aubio_notes_t *o, smpl_t release_drop);
 
 #ifdef __cplusplus
 }
--- a/src/onset/onset.c
+++ b/src/onset/onset.c
@@ -23,10 +23,13 @@
 #include "cvec.h"
 #include "spectral/specdesc.h"
 #include "spectral/phasevoc.h"
+#include "spectral/awhitening.h"
 #include "onset/peakpicker.h"
 #include "mathutils.h"
 #include "onset/onset.h"
 
+void aubio_onset_default_parameters (aubio_onset_t *o, const char_t * method);
+
 /** structure to store object state */
 struct _aubio_onset_t {
   aubio_pvoc_t * pv;            /**< phase vocoder */
@@ -42,6 +45,11 @@
 
   uint_t total_frames;          /**< total number of frames processed since the beginning */
   uint_t last_onset;            /**< last detected onset location, in frames */
+
+  uint_t apply_compression;
+  smpl_t lambda_compression;
+  uint_t apply_awhitening;      /**< apply adaptive spectral whitening */
+  aubio_spectral_whitening_t *spectral_whitening;
 };
 
 /* execute onset detection function on iput buffer */
@@ -49,6 +57,16 @@
 {
   smpl_t isonset = 0;
   aubio_pvoc_do (o->pv,input, o->fftgrain);
+  /*
+  if (apply_filtering) {
+  }
+  */
+  if (o->apply_awhitening) {
+    aubio_spectral_whitening_do(o->spectral_whitening, o->fftgrain);
+  }
+  if (o->apply_compression) {
+    cvec_logmag(o->fftgrain, o->lambda_compression);
+  }
   aubio_specdesc_do (o->od, o->fftgrain, o->desc);
   aubio_peakpicker_do(o->pp, o->desc, onset);
   isonset = onset->data[0];
@@ -57,10 +75,17 @@
       //AUBIO_DBG ("silent onset, not marking as onset\n");
       isonset  = 0;
     } else {
+      // we have an onset
       uint_t new_onset = o->total_frames + (uint_t)ROUND(isonset * o->hop_size);
+      // check if last onset time was more than minioi ago
       if (o->last_onset + o->minioi < new_onset) {
-        //AUBIO_DBG ("accepted detection, marking as onset\n");
-        o->last_onset = new_onset;
+        // start of file: make sure (new_onset - delay) >= 0
+        if (o->last_onset > 0 && o->delay > new_onset) {
+          isonset = 0;
+        } else {
+          //AUBIO_DBG ("accepted detection, marking as onset\n");
+          o->last_onset = MAX(o->delay, new_onset);
+        }
       } else {
         //AUBIO_DBG ("doubled onset, not marking as onset\n");
         isonset  = 0;
@@ -99,6 +124,32 @@
   return aubio_onset_get_last_s (o) * 1000.;
 }
 
+uint_t aubio_onset_set_awhitening (aubio_onset_t *o, uint_t enable)
+{
+  o->apply_awhitening = enable == 1 ? 1 : 0;
+  return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_awhitening (aubio_onset_t *o)
+{
+  return o->apply_awhitening;
+}
+
+uint_t aubio_onset_set_compression (aubio_onset_t *o, smpl_t lambda)
+{
+  if (lambda < 0.) {
+    return AUBIO_FAIL;
+  }
+  o->lambda_compression = lambda;
+  o->apply_compression = (o->lambda_compression > 0.) ? 1 : 0;
+  return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_compression (aubio_onset_t *o)
+{
+  return o->apply_compression ? o->lambda_compression : 0;
+}
+
 uint_t aubio_onset_set_silence(aubio_onset_t * o, smpl_t silence) {
   o->silence = silence;
   return AUBIO_OK;
@@ -205,35 +256,100 @@
   o->pv = new_aubio_pvoc(buf_size, o->hop_size);
   o->pp = new_aubio_peakpicker();
   o->od = new_aubio_specdesc(onset_mode,buf_size);
-  if (o->od == NULL) goto beach_specdesc;
   o->fftgrain = new_cvec(buf_size);
   o->desc = new_fvec(1);
+  o->spectral_whitening = new_aubio_spectral_whitening(buf_size, hop_size, samplerate);
 
-  /* set some default parameter */
-  aubio_onset_set_threshold (o, 0.3);
-  aubio_onset_set_delay(o, 4.3 * hop_size);
-  aubio_onset_set_minioi_ms(o, 20.);
-  aubio_onset_set_silence(o, -70.);
+  if (!o->pv || !o->pp || !o->od || !o->fftgrain
+      || !o->desc || !o->spectral_whitening)
+    goto beach;
 
   /* initialize internal variables */
-  o->last_onset = 0;
-  o->total_frames = 0;
+  aubio_onset_set_default_parameters (o, onset_mode);
+
+  aubio_onset_reset(o);
   return o;
 
-beach_specdesc:
-  del_aubio_peakpicker(o->pp);
-  del_aubio_pvoc(o->pv);
 beach:
-  AUBIO_FREE(o);
+  del_aubio_onset(o);
   return NULL;
 }
 
+void aubio_onset_reset (aubio_onset_t *o) {
+  o->last_onset = 0;
+  o->total_frames = 0;
+}
+
+uint_t aubio_onset_set_default_parameters (aubio_onset_t * o, const char_t * onset_mode)
+{
+  uint_t ret = AUBIO_OK;
+  /* set some default parameter */
+  aubio_onset_set_threshold (o, 0.3);
+  aubio_onset_set_delay (o, 4.3 * o->hop_size);
+  aubio_onset_set_minioi_ms (o, 50.);
+  aubio_onset_set_silence (o, -70.);
+  // disable spectral whitening
+  aubio_onset_set_awhitening (o, 0);
+  // disable logarithmic magnitude
+  aubio_onset_set_compression (o, 0.);
+
+  /* method specific optimisations */
+  if (strcmp (onset_mode, "energy") == 0) {
+  } else if (strcmp (onset_mode, "hfc") == 0 || strcmp (onset_mode, "default") == 0) {
+    aubio_onset_set_threshold (o, 0.058);
+    aubio_onset_set_compression (o, 1.);
+  } else if (strcmp (onset_mode, "complexdomain") == 0
+             || strcmp (onset_mode, "complex") == 0) {
+    aubio_onset_set_delay (o, 4.6 * o->hop_size);
+    aubio_onset_set_threshold (o, 0.15);
+    aubio_onset_set_awhitening(o, 1);
+    aubio_onset_set_compression (o, 1.);
+  } else if (strcmp (onset_mode, "phase") == 0) {
+    o->apply_compression = 0;
+    aubio_onset_set_awhitening (o, 0);
+  } else if (strcmp (onset_mode, "wphase") == 0) {
+    // use defaults for now
+  } else if (strcmp (onset_mode, "mkl") == 0) {
+    aubio_onset_set_threshold (o, 0.05);
+    aubio_onset_set_awhitening(o, 1);
+    aubio_onset_set_compression (o, 0.02);
+  } else if (strcmp (onset_mode, "kl") == 0) {
+    aubio_onset_set_threshold (o, 0.35);
+    aubio_onset_set_awhitening(o, 1);
+    aubio_onset_set_compression (o, 0.02);
+  } else if (strcmp (onset_mode, "specflux") == 0) {
+    aubio_onset_set_threshold (o, 0.18);
+    aubio_onset_set_awhitening(o, 1);
+    aubio_spectral_whitening_set_relax_time(o->spectral_whitening, 100);
+    aubio_spectral_whitening_set_floor(o->spectral_whitening, 1.);
+    aubio_onset_set_compression (o, 10.);
+  } else if (strcmp (onset_mode, "specdiff") == 0) {
+  } else if (strcmp (onset_mode, "old_default") == 0) {
+    // used to reproduce results obtained with the previous version
+    aubio_onset_set_threshold (o, 0.3);
+    aubio_onset_set_minioi_ms (o, 20.);
+    aubio_onset_set_compression (o, 0.);
+  } else {
+    AUBIO_WRN("onset: unknown spectral descriptor type %s, "
+               "using default parameters.\n", onset_mode);
+    ret = AUBIO_FAIL;
+  }
+  return ret;
+}
+
 void del_aubio_onset (aubio_onset_t *o)
 {
-  del_aubio_specdesc(o->od);
-  del_aubio_peakpicker(o->pp);
-  del_aubio_pvoc(o->pv);
-  del_fvec(o->desc);
-  del_cvec(o->fftgrain);
+  if (o->spectral_whitening)
+    del_aubio_spectral_whitening(o->spectral_whitening);
+  if (o->od)
+    del_aubio_specdesc(o->od);
+  if (o->pp)
+    del_aubio_peakpicker(o->pp);
+  if (o->pv)
+    del_aubio_pvoc(o->pv);
+  if (o->desc)
+    del_fvec(o->desc);
+  if (o->fftgrain)
+    del_cvec(o->fftgrain);
   AUBIO_FREE(o);
 }
--- a/src/onset/onset.h
+++ b/src/onset/onset.h
@@ -117,6 +117,44 @@
 */
 smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o);
 
+/** set onset detection adaptive whitening
+
+  \param o onset detection object as returned by new_aubio_onset()
+  \param enable 1 to enable, 0 to disable
+
+  \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_onset_set_awhitening(aubio_onset_t * o, uint_t enable);
+
+/** get onset detection adaptive whitening
+
+  \param o onset detection object as returned by new_aubio_onset()
+
+  \return 1 if enabled, 0 otherwise
+
+*/
+smpl_t aubio_onset_get_awhitening(aubio_onset_t * o);
+
+/** set or disable log compression
+
+  \param o onset detection object as returned by new_aubio_onset()
+  \param lambda logarithmic compression factor, 0 to disable
+
+  \return 0 if successful, 1 otherwise
+
+ */
+uint_t aubio_onset_set_compression(aubio_onset_t *o, smpl_t lambda);
+
+/** get onset detection log compression
+
+  \param o onset detection object as returned by new_aubio_onset()
+
+  \returns 0 if disabled, compression factor otherwise
+
+ */
+smpl_t aubio_onset_get_compression(aubio_onset_t *o);
+
 /** set onset detection silence threshold
 
   \param o onset detection object as returned by new_aubio_onset()
@@ -273,6 +311,27 @@
 
 */
 smpl_t aubio_onset_get_threshold(const aubio_onset_t * o);
+
+/** set default parameters
+
+  \param o onset detection object as returned by new_aubio_onset()
+  \param onset_mode detection mode to adjust
+
+  This function is called at the end of new_aubio_onset().
+
+ */
+uint_t aubio_onset_set_default_parameters (aubio_onset_t * o, const char_t * onset_mode);
+
+/** reset onset detection
+
+  \param o onset detection object as returned by new_aubio_onset()
+
+  Reset current time and last onset to 0.
+
+  This function is called at the end of new_aubio_onset().
+
+ */
+void aubio_onset_reset(aubio_onset_t * o);
 
 /** delete onset detection object
 
--- a/src/onset/peakpicker.c
+++ b/src/onset/peakpicker.c
@@ -92,27 +92,21 @@
   fvec_t *thresholded = p->thresholded;
   fvec_t *scratch = p->scratch;
   smpl_t mean = 0., median = 0.;
-  uint_t length = p->win_post + p->win_pre + 1;
   uint_t j = 0;
 
-  /* store onset in onset_keep */
-  /* shift all elements but last, then write last */
-  for (j = 0; j < length - 1; j++) {
-    onset_keep->data[j] = onset_keep->data[j + 1];
-    onset_proc->data[j] = onset_keep->data[j];
-  }
-  onset_keep->data[length - 1] = onset->data[0];
-  onset_proc->data[length - 1] = onset->data[0];
+  /* push new novelty to the end */
+  fvec_push(onset_keep, onset->data[0]);
+  /* store a copy */
+  fvec_copy(onset_keep, onset_proc);
 
-  /* filter onset_proc */
-  /** \bug filtfilt calculated post+pre times, should be only once !? */
+  /* filter this copy */
   aubio_filter_do_filtfilt (p->biquad, onset_proc, scratch);
 
   /* calculate mean and median for onset_proc */
   mean = fvec_mean (onset_proc);
-  /* copy to scratch */
-  for (j = 0; j < length; j++)
-    scratch->data[j] = onset_proc->data[j];
+
+  /* copy to scratch and compute its median */
+  fvec_copy(onset_proc, scratch);
   median = p->thresholdfn (scratch);
 
   /* shift peek array */
@@ -185,7 +179,9 @@
      generated with octave butter function: [b,a] = butter(2, 0.34);
    */
   t->biquad = new_aubio_filter_biquad (0.15998789, 0.31997577, 0.15998789,
-      -0.59488894, 0.23484048);
+      // FIXME: broken since c9e20ca, revert for now
+      //-0.59488894, 0.23484048);
+      0.23484048, 0);
 
   return t;
 }
--- a/src/pitch/pitch.c
+++ b/src/pitch/pitch.c
@@ -32,6 +32,7 @@
 #include "pitch/pitchfcomb.h"
 #include "pitch/pitchschmitt.h"
 #include "pitch/pitchyinfft.h"
+#include "pitch/pitchyinfast.h"
 #include "pitch/pitchspecacf.h"
 #include "pitch/pitch.h"
 
@@ -45,6 +46,7 @@
   aubio_pitcht_schmitt,    /**< `schmitt`, Schmitt trigger */
   aubio_pitcht_fcomb,      /**< `fcomb`, Fast comb filter */
   aubio_pitcht_yinfft,     /**< `yinfft`, Spectral YIN */
+  aubio_pitcht_yinfast,    /**< `yinfast`, YIN fast */
   aubio_pitcht_specacf,    /**< `specacf`, Spectral autocorrelation */
   aubio_pitcht_default
     = aubio_pitcht_yinfft, /**< `default` */
@@ -94,6 +96,7 @@
 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_yinfast (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);
 
 /* internal functions for frequency conversion */
@@ -111,8 +114,14 @@
 {
   aubio_pitch_t *p = AUBIO_NEW (aubio_pitch_t);
   aubio_pitch_type pitch_type;
+  if (pitch_mode == NULL) {
+    AUBIO_ERR ("pitch: can not use ‘NULL‘ for pitch detection method\n");
+    goto beach;
+  }
   if (strcmp (pitch_mode, "mcomb") == 0)
     pitch_type = aubio_pitcht_mcomb;
+  else if (strcmp (pitch_mode, "yinfast") == 0)
+    pitch_type = aubio_pitcht_yinfast;
   else if (strcmp (pitch_mode, "yinfft") == 0)
     pitch_type = aubio_pitcht_yinfft;
   else if (strcmp (pitch_mode, "yin") == 0)
@@ -138,7 +147,7 @@
     AUBIO_ERR("pitch: got buffer_size %d, but can not be < 1\n", bufsize);
     goto beach;
   } else if (bufsize < hopsize) {
-    AUBIO_ERR("pitch: 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", hopsize, bufsize);
     goto beach;
   } else if ((sint_t)samplerate < 1) {
     AUBIO_ERR("pitch: samplerate (%d) can not be < 1\n", samplerate);
@@ -155,6 +164,7 @@
     case aubio_pitcht_yin:
       p->buf = new_fvec (bufsize);
       p->p_object = new_aubio_pitchyin (bufsize);
+      if (!p->p_object) goto beach;
       p->detect_cb = aubio_pitch_do_yin;
       p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchyin_get_confidence;
       aubio_pitchyin_set_tolerance (p->p_object, 0.15);
@@ -162,6 +172,7 @@
     case aubio_pitcht_mcomb:
       p->filtered = new_fvec (hopsize);
       p->pv = new_aubio_pvoc (bufsize, hopsize);
+      if (!p->pv) goto beach;
       p->fftgrain = new_cvec (bufsize);
       p->p_object = new_aubio_pitchmcomb (bufsize, hopsize);
       p->filter = new_aubio_filter_c_weighting (samplerate);
@@ -170,6 +181,7 @@
     case aubio_pitcht_fcomb:
       p->buf = new_fvec (bufsize);
       p->p_object = new_aubio_pitchfcomb (bufsize, hopsize);
+      if (!p->p_object) goto beach;
       p->detect_cb = aubio_pitch_do_fcomb;
       break;
     case aubio_pitcht_schmitt:
@@ -180,13 +192,23 @@
     case aubio_pitcht_yinfft:
       p->buf = new_fvec (bufsize);
       p->p_object = new_aubio_pitchyinfft (samplerate, bufsize);
+      if (!p->p_object) goto beach;
       p->detect_cb = aubio_pitch_do_yinfft;
       p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchyinfft_get_confidence;
       aubio_pitchyinfft_set_tolerance (p->p_object, 0.85);
       break;
+    case aubio_pitcht_yinfast:
+      p->buf = new_fvec (bufsize);
+      p->p_object = new_aubio_pitchyinfast (bufsize);
+      if (!p->p_object) goto beach;
+      p->detect_cb = aubio_pitch_do_yinfast;
+      p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchyinfast_get_confidence;
+      aubio_pitchyinfast_set_tolerance (p->p_object, 0.15);
+      break;
     case aubio_pitcht_specacf:
       p->buf = new_fvec (bufsize);
       p->p_object = new_aubio_pitchspecacf (bufsize);
+      if (!p->p_object) goto beach;
       p->detect_cb = aubio_pitch_do_specacf;
       p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchspecacf_get_tolerance;
       aubio_pitchspecacf_set_tolerance (p->p_object, 0.85);
@@ -197,6 +219,8 @@
   return p;
 
 beach:
+  if (p->filtered) del_fvec(p->filtered);
+  if (p->buf) del_fvec(p->buf);
   AUBIO_FREE(p);
   return NULL;
 }
@@ -228,6 +252,10 @@
       del_fvec (p->buf);
       del_aubio_pitchyinfft (p->p_object);
       break;
+    case aubio_pitcht_yinfast:
+      del_fvec (p->buf);
+      del_aubio_pitchyinfast (p->p_object);
+      break;
     case aubio_pitcht_specacf:
       del_fvec (p->buf);
       del_aubio_pitchspecacf (p->p_object);
@@ -318,6 +346,9 @@
     case aubio_pitcht_yinfft:
       aubio_pitchyinfft_set_tolerance (p->p_object, tol);
       break;
+    case aubio_pitcht_yinfast:
+      aubio_pitchyinfast_set_tolerance (p->p_object, tol);
+      break;
     default:
       break;
   }
@@ -335,6 +366,9 @@
     case aubio_pitcht_yinfft:
       tolerance = aubio_pitchyinfft_get_tolerance (p->p_object);
       break;
+    case aubio_pitcht_yinfast:
+      tolerance = aubio_pitchyinfast_get_tolerance (p->p_object);
+      break;
     default:
       break;
   }
@@ -403,6 +437,21 @@
   smpl_t pitch = 0.;
   aubio_pitch_slideblock (p, ibuf);
   aubio_pitchyinfft_do (p->p_object, p->buf, obuf);
+  pitch = obuf->data[0];
+  if (pitch > 0) {
+    pitch = p->samplerate / (pitch + 0.);
+  } else {
+    pitch = 0.;
+  }
+  obuf->data[0] = pitch;
+}
+
+void
+aubio_pitch_do_yinfast (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
+{
+  smpl_t pitch = 0.;
+  aubio_pitch_slideblock (p, ibuf);
+  aubio_pitchyinfast_do (p->p_object, p->buf, obuf);
   pitch = obuf->data[0];
   if (pitch > 0) {
     pitch = p->samplerate / (pitch + 0.);
--- a/src/pitch/pitch.h
+++ b/src/pitch/pitch.h
@@ -81,6 +81,11 @@
 
   see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
 
+  \b \p yinfast : Yinfast algorithm
+
+  This algorithm is equivalent to the YIN algorithm, but computed in the
+  spectral domain for efficiency. See also `python/demos/demo_yin_compare.py`.
+
   \b \p yinfft : Yinfft algorithm
 
   This algorithm was derived from the YIN algorithm. In this implementation, a
@@ -149,6 +154,8 @@
 
   \param o pitch detection object as returned by new_aubio_pitch()
   \param mode set pitch units for output
+
+  mode can be one of "Hz", "midi", "cent", or "bin". Defaults to "Hz".
 
   \return 0 if successfull, non-zero otherwise
 
--- a/src/pitch/pitchfcomb.c
+++ b/src/pitch/pitchfcomb.c
@@ -53,12 +53,17 @@
   aubio_pitchfcomb_t *p = AUBIO_NEW (aubio_pitchfcomb_t);
   p->fftSize = bufsize;
   p->stepSize = hopsize;
+  p->fft = new_aubio_fft (bufsize);
+  if (!p->fft) goto beach;
   p->winput = new_fvec (bufsize);
   p->fftOut = new_cvec (bufsize);
   p->fftLastPhase = new_fvec (bufsize);
-  p->fft = new_aubio_fft (bufsize);
   p->win = new_aubio_window ("hanning", bufsize);
   return p;
+
+beach:
+  AUBIO_FREE(p);
+  return NULL;
 }
 
 /* input must be stepsize long */
--- a/src/pitch/pitchmcomb.c
+++ b/src/pitch/pitchmcomb.c
@@ -37,6 +37,7 @@
 /* not used but useful : sort by amplitudes (or anything else)
  * sort_pitchpeak(peaks, length);
  */
+#if 0
 /** spectral_peak comparison function (must return signed int) */
 static sint_t aubio_pitchmcomb_sort_peak_comp (const void *x, const void *y);
 /** sort spectral_peak against their mag */
@@ -44,13 +45,16 @@
 /** select the best candidates */
 uint_t aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain,
     smpl_t * cands);
+#endif
 
 /** sort spectral_candidate against their comb ene */
 void aubio_pitchmcomb_sort_cand_ene (aubio_spectralcandidate_t ** candidates,
     uint_t nbins);
+#if 0
 /** sort spectral_candidate against their frequency */
 void aubio_pitchmcomb_sort_cand_freq (aubio_spectralcandidate_t ** candidates,
     uint_t nbins);
+#endif
 
 struct _aubio_pitchmcomb_t
 {
@@ -133,6 +137,7 @@
      } */
 }
 
+#if 0
 uint_t
 aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain, smpl_t * cands)
 {
@@ -163,6 +168,7 @@
     return 0;
   }
 }
+#endif
 
 void
 aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, const fvec_t * newmag)
@@ -313,6 +319,7 @@
   return pos;
 }
 
+#if 0
 void
 aubio_pitchmcomb_sort_peak (aubio_spectralpeak_t * peaks, uint_t nbins)
 {
@@ -342,7 +349,6 @@
   }
 }
 
-
 void
 aubio_pitchmcomb_sort_cand_freq (aubio_spectralcandidate_t ** candidates,
     uint_t nbins)
@@ -356,6 +362,7 @@
     }
   }
 }
+#endif
 
 aubio_pitchmcomb_t *
 new_aubio_pitchmcomb (uint_t bufsize, uint_t hopsize)
--- a/src/pitch/pitchspecacf.c
+++ b/src/pitch/pitchspecacf.c
@@ -42,9 +42,10 @@
 new_aubio_pitchspecacf (uint_t bufsize)
 {
   aubio_pitchspecacf_t *p = AUBIO_NEW (aubio_pitchspecacf_t);
+  p->fft = new_aubio_fft (bufsize);
+  if (!p->fft) goto beach;
   p->win = new_aubio_window ("hanningz", bufsize);
   p->winput = new_fvec (bufsize);
-  p->fft = new_aubio_fft (bufsize);
   p->fftout = new_fvec (bufsize);
   p->sqrmag = new_fvec (bufsize);
   p->acf = new_fvec (bufsize / 2 + 1);
@@ -51,6 +52,10 @@
   p->tol = 1.;
   p->confidence = 0.;
   return p;
+
+beach:
+  AUBIO_FREE(p);
+  return NULL;
 }
 
 void
--- a/src/pitch/pitchyin.c
+++ b/src/pitch/pitchyin.c
@@ -36,9 +36,10 @@
 {
   fvec_t *yin;
   smpl_t tol;
-  smpl_t confidence;
+  uint_t peak_pos;
 };
 
+#if 0
 /** compute difference function
 
   \param input input signal
@@ -60,6 +61,7 @@
 
 */
 uint_t aubio_pitchyin_getpitch (const fvec_t * yinbuf);
+#endif
 
 aubio_pitchyin_t *
 new_aubio_pitchyin (uint_t bufsize)
@@ -67,6 +69,7 @@
   aubio_pitchyin_t *o = AUBIO_NEW (aubio_pitchyin_t);
   o->yin = new_fvec (bufsize / 2);
   o->tol = 0.15;
+  o->peak_pos = 0;
   return o;
 }
 
@@ -77,6 +80,7 @@
   AUBIO_FREE (o);
 }
 
+#if 0
 /* outputs the difference function */
 void
 aubio_pitchyin_diff (fvec_t * input, fvec_t * yin)
@@ -126,25 +130,29 @@
   //AUBIO_DBG("No pitch found");
   return 0;
 }
+#endif
 
-
 /* all the above in one */
 void
 aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * input, fvec_t * out)
 {
-  smpl_t tol = o->tol;
-  fvec_t *yin = o->yin;
-  uint_t j, tau = 0;
+  const smpl_t tol = o->tol;
+  fvec_t* yin = o->yin;
+  const smpl_t *input_data = input->data;
+  const uint_t length = yin->length;
+  smpl_t *yin_data = yin->data;
+  uint_t j, tau;
   sint_t period;
-  smpl_t tmp = 0., tmp2 = 0.;
-  yin->data[0] = 1.;
-  for (tau = 1; tau < yin->length; tau++) {
-    yin->data[tau] = 0.;
-    for (j = 0; j < yin->length; j++) {
-      tmp = input->data[j] - input->data[j + tau];
-      yin->data[tau] += SQR (tmp);
+  smpl_t tmp, tmp2 = 0.;
+
+  yin_data[0] = 1.;
+  for (tau = 1; tau < length; tau++) {
+    yin_data[tau] = 0.;
+    for (j = 0; j < length; j++) {
+      tmp = input_data[j] - input_data[j + tau];
+      yin_data[tau] += SQR (tmp);
     }
-    tmp2 += yin->data[tau];
+    tmp2 += yin_data[tau];
     if (tmp2 != 0) {
       yin->data[tau] *= tau / tmp2;
     } else {
@@ -151,21 +159,20 @@
       yin->data[tau] = 1.;
     }
     period = tau - 3;
-    if (tau > 4 && (yin->data[period] < tol) &&
-        (yin->data[period] < yin->data[period + 1])) {
-      out->data[0] = fvec_quadratic_peak_pos (yin, period);
-      goto beach;
+    if (tau > 4 && (yin_data[period] < tol) &&
+        (yin_data[period] < yin_data[period + 1])) {
+      o->peak_pos = (uint_t)period;
+      out->data[0] = fvec_quadratic_peak_pos (yin, o->peak_pos);
+      return;
     }
   }
-  out->data[0] = fvec_quadratic_peak_pos (yin, fvec_min_elem (yin));
-beach:
-  return;
+  o->peak_pos = (uint_t)fvec_min_elem (yin);
+  out->data[0] = fvec_quadratic_peak_pos (yin, o->peak_pos);
 }
 
 smpl_t
 aubio_pitchyin_get_confidence (aubio_pitchyin_t * o) {
-  o->confidence = 1. - fvec_min (o->yin);
-  return o->confidence;
+  return 1. - o->yin->data[o->peak_pos];
 }
 
 uint_t
--- /dev/null
+++ b/src/pitch/pitchyinfast.c
@@ -1,0 +1,201 @@
+/*
+  Copyright (C) 2003-2017 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/>.
+
+*/
+
+/* This algorithm was developed by A. de Cheveigné and H. Kawahara and
+ * published in:
+ *
+ * de Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ * estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+ *
+ * see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+ */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "cvec.h"
+#include "spectral/fft.h"
+#include "pitch/pitchyinfast.h"
+
+struct _aubio_pitchyinfast_t
+{
+  fvec_t *yin;
+  smpl_t tol;
+  uint_t peak_pos;
+  fvec_t *tmpdata;
+  fvec_t *sqdiff;
+  fvec_t *kernel;
+  fvec_t *samples_fft;
+  fvec_t *kernel_fft;
+  aubio_fft_t *fft;
+};
+
+aubio_pitchyinfast_t *
+new_aubio_pitchyinfast (uint_t bufsize)
+{
+  aubio_pitchyinfast_t *o = AUBIO_NEW (aubio_pitchyinfast_t);
+  o->yin = new_fvec (bufsize / 2);
+  o->tmpdata = new_fvec (bufsize);
+  o->sqdiff = new_fvec (bufsize / 2);
+  o->kernel = new_fvec (bufsize);
+  o->samples_fft = new_fvec (bufsize);
+  o->kernel_fft = new_fvec (bufsize);
+  o->fft = new_aubio_fft (bufsize);
+  if (!o->yin || !o->tmpdata || !o->tmpdata || !o->sqdiff
+      || !o->kernel || !o->samples_fft || !o->kernel || !o->fft)
+  {
+    del_aubio_pitchyinfast(o);
+    return NULL;
+  }
+  o->tol = 0.15;
+  o->peak_pos = 0;
+  return o;
+}
+
+void
+del_aubio_pitchyinfast (aubio_pitchyinfast_t * o)
+{
+  if (o->yin)
+    del_fvec (o->yin);
+  if (o->tmpdata)
+    del_fvec (o->tmpdata);
+  if (o->sqdiff)
+    del_fvec (o->sqdiff);
+  if (o->kernel)
+    del_fvec (o->kernel);
+  if (o->samples_fft)
+    del_fvec (o->samples_fft);
+  if (o->kernel_fft)
+    del_fvec (o->kernel_fft);
+  if (o->fft)
+    del_aubio_fft (o->fft);
+  AUBIO_FREE (o);
+}
+
+/* all the above in one */
+void
+aubio_pitchyinfast_do (aubio_pitchyinfast_t * o, const fvec_t * input, fvec_t * out)
+{
+  const smpl_t tol = o->tol;
+  fvec_t* yin = o->yin;
+  const uint_t length = yin->length;
+  uint_t B = o->tmpdata->length;
+  uint_t W = o->yin->length; // B / 2
+  fvec_t tmp_slice, kernel_ptr;
+  uint_t tau;
+  sint_t period;
+  smpl_t tmp2 = 0.;
+
+  // compute r_t(0) + r_t+tau(0)
+  {
+    fvec_t *squares = o->tmpdata;
+    fvec_weighted_copy(input, input, squares);
+#if 0
+    for (tau = 0; tau < W; tau++) {
+      tmp_slice.data = squares->data + tau;
+      tmp_slice.length = W;
+      o->sqdiff->data[tau] = fvec_sum(&tmp_slice);
+    }
+#else
+    tmp_slice.data = squares->data;
+    tmp_slice.length = W;
+    o->sqdiff->data[0] = fvec_sum(&tmp_slice);
+    for (tau = 1; tau < W; tau++) {
+      o->sqdiff->data[tau] = o->sqdiff->data[tau-1];
+      o->sqdiff->data[tau] -= squares->data[tau-1];
+      o->sqdiff->data[tau] += squares->data[W+tau-1];
+    }
+#endif
+    fvec_add(o->sqdiff, o->sqdiff->data[0]);
+  }
+  // compute r_t(tau) = -2.*ifft(fft(samples)*fft(samples[W-1::-1]))
+  {
+    fvec_t *compmul = o->tmpdata;
+    fvec_t *rt_of_tau = o->samples_fft;
+    aubio_fft_do_complex(o->fft, input, o->samples_fft);
+    // build kernel, take a copy of first half of samples
+    tmp_slice.data = input->data;
+    tmp_slice.length = W;
+    kernel_ptr.data = o->kernel->data + 1;
+    kernel_ptr.length = W;
+    fvec_copy(&tmp_slice, &kernel_ptr);
+    // reverse them
+    fvec_rev(&kernel_ptr);
+    // compute fft(kernel)
+    aubio_fft_do_complex(o->fft, o->kernel, o->kernel_fft);
+    // compute complex product
+    compmul->data[0]  = o->kernel_fft->data[0] * o->samples_fft->data[0];
+    for (tau = 1; tau < W; tau++) {
+      compmul->data[tau]    = o->kernel_fft->data[tau] * o->samples_fft->data[tau];
+      compmul->data[tau]   -= o->kernel_fft->data[B-tau] * o->samples_fft->data[B-tau];
+    }
+    compmul->data[W]    = o->kernel_fft->data[W] * o->samples_fft->data[W];
+    for (tau = 1; tau < W; tau++) {
+      compmul->data[B-tau]  = o->kernel_fft->data[B-tau] * o->samples_fft->data[tau];
+      compmul->data[B-tau] += o->kernel_fft->data[tau] * o->samples_fft->data[B-tau];
+    }
+    // compute inverse fft
+    aubio_fft_rdo_complex(o->fft, compmul, rt_of_tau);
+    // compute square difference r_t(tau) = sqdiff - 2 * r_t_tau[W-1:-1]
+    for (tau = 0; tau < W; tau++) {
+      yin->data[tau] = o->sqdiff->data[tau] - 2. * rt_of_tau->data[tau+W];
+    }
+  }
+
+  // now build yin and look for first minimum
+  fvec_zeros(out);
+  yin->data[0] = 1.;
+  for (tau = 1; tau < length; tau++) {
+    tmp2 += yin->data[tau];
+    if (tmp2 != 0) {
+      yin->data[tau] *= tau / tmp2;
+    } else {
+      yin->data[tau] = 1.;
+    }
+    period = tau - 3;
+    if (tau > 4 && (yin->data[period] < tol) &&
+        (yin->data[period] < yin->data[period + 1])) {
+      o->peak_pos = (uint_t)period;
+      out->data[0] = fvec_quadratic_peak_pos (yin, o->peak_pos);
+      return;
+    }
+  }
+  // use global minimum 
+  o->peak_pos = (uint_t)fvec_min_elem (yin);
+  out->data[0] = fvec_quadratic_peak_pos (yin, o->peak_pos);
+}
+
+smpl_t
+aubio_pitchyinfast_get_confidence (aubio_pitchyinfast_t * o) {
+  return 1. - o->yin->data[o->peak_pos];
+}
+
+uint_t
+aubio_pitchyinfast_set_tolerance (aubio_pitchyinfast_t * o, smpl_t tol)
+{
+  o->tol = tol;
+  return 0;
+}
+
+smpl_t
+aubio_pitchyinfast_get_tolerance (aubio_pitchyinfast_t * o)
+{
+  return o->tol;
+}
--- /dev/null
+++ b/src/pitch/pitchyinfast.h
@@ -1,0 +1,102 @@
+/*
+  Copyright (C) 2003-2017 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
+
+  Pitch detection using YIN algorithm (fast implementation)
+
+  This algorithm was developed by A. de Cheveigne and H. Kawahara and
+  published in:
+
+  De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+  estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+  This implementation compute the autocorrelation function using time domain
+  convolution computed in the spectral domain.
+
+  see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+      http://recherche.ircam.fr/equipes/pcm/cheveign/ps/2002_JASA_YIN_proof.pdf
+
+*/
+
+#ifndef AUBIO_PITCHYINFAST_H
+#define AUBIO_PITCHYINFAST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyinfast_t aubio_pitchyinfast_t;
+
+/** creation of the pitch detection object
+
+  \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyinfast_t *new_aubio_pitchyinfast (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+  \param o pitch detection object as returned by new_aubio_pitchyin()
+
+*/
+void del_aubio_pitchyinfast (aubio_pitchyinfast_t * o);
+
+/** execute pitch detection an input buffer
+
+  \param o pitch detection object as returned by new_aubio_pitchyin()
+  \param samples_in input signal vector (length as specified at creation time)
+  \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyinfast_do (aubio_pitchyinfast_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+
+
+/** set tolerance parameter for YIN algorithm
+
+  \param o YIN pitch detection object
+  \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyinfast_set_tolerance (aubio_pitchyinfast_t * o, smpl_t tol);
+
+/** get tolerance parameter for YIN algorithm
+
+  \param o YIN pitch detection object
+  \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyinfast_get_tolerance (aubio_pitchyinfast_t * o);
+
+/** get current confidence of YIN algorithm
+
+  \param o YIN pitch detection object
+  \return confidence parameter
+
+*/
+smpl_t aubio_pitchyinfast_get_confidence (aubio_pitchyinfast_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYINFAST_H */
+
--- a/src/pitch/pitchyinfft.c
+++ b/src/pitch/pitchyinfft.c
@@ -36,7 +36,7 @@
   aubio_fft_t *fft;   /**< fft object to compute square difference function */
   fvec_t *yinfft;     /**< Yin function */
   smpl_t tol;         /**< Yin tolerance */
-  smpl_t confidence;  /**< confidence */
+  uint_t peak_pos;    /**< currently selected peak pos*/
   uint_t short_period; /** shortest period under which to check for octave error */
 };
 
@@ -44,7 +44,7 @@
      0.,    20.,    25.,   31.5,    40.,    50.,    63.,    80.,   100.,   125.,
    160.,   200.,   250.,   315.,   400.,   500.,   630.,   800.,  1000.,  1250.,
   1600.,  2000.,  2500.,  3150.,  4000.,  5000.,  6300.,  8000.,  9000., 10000.,
- 12500., 15000., 20000., 25100
+ 12500., 15000., 20000., 25100., -1.
 };
 
 static const smpl_t weight[] = {
@@ -62,15 +62,20 @@
   aubio_pitchyinfft_t *p = AUBIO_NEW (aubio_pitchyinfft_t);
   p->winput = new_fvec (bufsize);
   p->fft = new_aubio_fft (bufsize);
+  if (!p->fft) goto beach;
   p->fftout = new_fvec (bufsize);
   p->sqrmag = new_fvec (bufsize);
   p->yinfft = new_fvec (bufsize / 2 + 1);
   p->tol = 0.85;
+  p->peak_pos = 0;
   p->win = new_aubio_window ("hanningz", bufsize);
   p->weight = new_fvec (bufsize / 2 + 1);
   for (i = 0; i < p->weight->length; i++) {
     freq = (smpl_t) i / (smpl_t) bufsize *(smpl_t) samplerate;
-    while (freq > freqs[j]) {
+    while (freq > freqs[j] && freqs[j] > 0) {
+      //AUBIO_DBG("freq %3.5f > %3.5f \tsamplerate %d (Hz) \t"
+      //    "(weight length %d, bufsize %d) %d %d\n", freq, freqs[j],
+      //    samplerate, p->weight->length, bufsize, i, j);
       j += 1;
     }
     a0 = weight[j - 1];
@@ -95,6 +100,11 @@
   // check for octave errors above 1300 Hz
   p->short_period = (uint_t)ROUND(samplerate / 1300.);
   return p;
+
+beach:
+  if (p->winput) del_fvec(p->winput);
+  AUBIO_FREE(p);
+  return NULL;
 }
 
 void
@@ -155,11 +165,13 @@
       /* should compare the minimum value of each interpolated peaks */
       halfperiod = FLOOR (tau / 2 + .5);
       if (yin->data[halfperiod] < p->tol)
-        output->data[0] = fvec_quadratic_peak_pos (yin, halfperiod);
+        p->peak_pos = halfperiod;
       else
-        output->data[0] = fvec_quadratic_peak_pos (yin, tau);
+        p->peak_pos = tau;
+      output->data[0] = fvec_quadratic_peak_pos (yin, p->peak_pos);
     }
   } else {
+    p->peak_pos = 0;
     output->data[0] = 0.;
   }
 }
@@ -179,8 +191,7 @@
 
 smpl_t
 aubio_pitchyinfft_get_confidence (aubio_pitchyinfft_t * o) {
-  o->confidence = 1. - fvec_min (o->yinfft);
-  return o->confidence;
+  return 1. - o->yinfft->data[o->peak_pos];
 }
 
 uint_t
--- /dev/null
+++ b/src/spectral/awhitening.c
@@ -1,0 +1,120 @@
+/*
+ * Copyright (C) 2003-2015 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/>.
+ *
+ */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/awhitening.h"
+
+#define aubio_spectral_whitening_default_relax_time   250   // in seconds, between 22 and 446
+#define aubio_spectral_whitening_default_decay        0.001 // -60dB attenuation
+#define aubio_spectral_whitening_default_floor        1.e-4 // from 1.e-6 to .2
+
+/** structure to store object state */
+struct _aubio_spectral_whitening_t {
+  uint_t buf_size;
+  uint_t hop_size;
+  uint_t samplerate;
+  smpl_t relax_time;
+  smpl_t r_decay;
+  smpl_t floor;
+  fvec_t *peak_values;
+};
+
+void
+aubio_spectral_whitening_do (aubio_spectral_whitening_t * o, cvec_t * fftgrain)
+{
+  uint_t i = 0;
+  for (i = 0; i < o->peak_values->length; i++) {
+    smpl_t tmp = MAX(o->r_decay * o->peak_values->data[i], o->floor);
+    o->peak_values->data[i] = MAX(fftgrain->norm[i], tmp);
+    fftgrain->norm[i] /= o->peak_values->data[i];
+  }
+}
+
+aubio_spectral_whitening_t *
+new_aubio_spectral_whitening (uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+  aubio_spectral_whitening_t *o = AUBIO_NEW (aubio_spectral_whitening_t);
+  if ((sint_t)buf_size < 1) {
+    AUBIO_ERR("spectral_whitening: got buffer_size %d, but can not be < 1\n", buf_size);
+    goto beach;
+  } else if ((sint_t)hop_size < 1) {
+    AUBIO_ERR("spectral_whitening: got hop_size %d, but can not be < 1\n", hop_size);
+    goto beach;
+  } else if ((sint_t)samplerate < 1) {
+    AUBIO_ERR("spectral_whitening: got samplerate %d, but can not be < 1\n", samplerate);
+    goto beach;
+  }
+  o->peak_values = new_fvec (buf_size / 2 + 1);
+  o->buf_size = buf_size;
+  o->hop_size = hop_size;
+  o->samplerate = samplerate;
+  o->floor = aubio_spectral_whitening_default_floor;
+  aubio_spectral_whitening_set_relax_time (o, aubio_spectral_whitening_default_relax_time);
+  aubio_spectral_whitening_reset (o);
+  return o;
+
+beach:
+  AUBIO_FREE(o);
+  return NULL;
+}
+
+uint_t
+aubio_spectral_whitening_set_relax_time (aubio_spectral_whitening_t * o, smpl_t relax_time)
+{
+  o->relax_time = relax_time;
+  o->r_decay = POW (aubio_spectral_whitening_default_decay,
+      (o->hop_size / (float) o->samplerate) / o->relax_time);
+  return AUBIO_OK;
+}
+
+smpl_t
+aubio_spectral_whitening_get_relax_time (aubio_spectral_whitening_t * o)
+{
+  return o->relax_time;
+}
+
+uint_t
+aubio_spectral_whitening_set_floor (aubio_spectral_whitening_t *o, smpl_t floor)
+{
+  o->floor = floor;
+  return AUBIO_OK;
+}
+
+smpl_t aubio_spectral_whitening_get_floor (aubio_spectral_whitening_t *o)
+{
+  return o->floor;
+}
+
+void
+aubio_spectral_whitening_reset (aubio_spectral_whitening_t * o)
+{
+  /* cover the case n == 0. */
+  fvec_set_all (o->peak_values, o->floor);
+}
+
+void
+del_aubio_spectral_whitening (aubio_spectral_whitening_t * o)
+{
+  del_fvec (o->peak_values);
+  AUBIO_FREE (o);
+}
--- /dev/null
+++ b/src/spectral/awhitening.h
@@ -1,0 +1,125 @@
+/*
+  Copyright (C) 2003-2015 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
+
+  Spectral adaptive whitening
+
+  References:
+
+  D. Stowell and M. D. Plumbley. Adaptive whitening for improved real-time
+  audio onset detection. In Proceedings of the International Computer Music
+  Conference (ICMC), 2007, Copenhagen, Denmark.
+
+  http://www.eecs.qmul.ac.uk/~markp/2007/StowellPlumbley07-icmc.pdf
+
+  S. Böck,, F. Krebs, and M. Schedl. Evaluating the Online Capabilities of
+  Onset Detection Methods. In Proceedings of the 13th International Society for
+  Music Information Retrieval Conference (ISMIR), 2012, Porto, Portugal.
+
+  http://ismir2012.ismir.net/event/papers/049_ISMIR_2012.pdf
+  http://www.cp.jku.at/research/papers/Boeck_etal_ISMIR_2012.pdf
+
+*/
+
+
+#ifndef _AUBIO_SPECTRAL_WHITENING_H
+#define _AUBIO_SPECTRAL_WHITENING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** spectral whitening structure */
+typedef struct _aubio_spectral_whitening_t aubio_spectral_whitening_t;
+
+/** execute spectral adaptive whitening, in-place
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+  \param fftgrain input signal spectrum as computed by aubio_pvoc_do() or aubio_fft_do()
+
+*/
+void aubio_spectral_whitening_do (aubio_spectral_whitening_t * o,
+                                  cvec_t * fftgrain);
+
+/** creation of a spectral whitening object
+
+  \param buf_size window size of input grains
+  \param hop_size number of samples between two consecutive input grains
+  \param samplerate sampling rate of the input signal
+
+*/
+aubio_spectral_whitening_t *new_aubio_spectral_whitening (uint_t buf_size,
+                                                          uint_t hop_size,
+                                                          uint_t samplerate);
+
+/** reset spectral whitening object
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+
+ */
+void aubio_spectral_whitening_reset (aubio_spectral_whitening_t * o);
+
+/** set relaxation time for spectral whitening
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+  \param relax_time relaxation time in seconds between 20 and 500, defaults 250
+
+  */
+uint_t aubio_spectral_whitening_set_relax_time (aubio_spectral_whitening_t * o,
+    smpl_t relax_time);
+
+/** get relaxation time of spectral whitening
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+  \return relaxation time in seconds
+
+*/
+smpl_t aubio_spectral_whitening_get_relax_time (aubio_spectral_whitening_t * o);
+
+/** set floor for spectral whitening
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+  \param floor value (typically between 1.e-6 and .2, defaults to 1.e-4)
+
+  */
+uint_t aubio_spectral_whitening_set_floor (aubio_spectral_whitening_t * o,
+    smpl_t floor);
+
+/** get floor of spectral whitening
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+  \return floor value
+
+*/
+smpl_t aubio_spectral_whitening_get_floor (aubio_spectral_whitening_t * o);
+
+/** deletion of a spectral whitening
+
+  \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+
+*/
+void del_aubio_spectral_whitening (aubio_spectral_whitening_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_SPECTRAL_WHITENING_H */
--- /dev/null
+++ b/src/spectral/dct.c
@@ -1,0 +1,174 @@
+/*
+  Copyright (C) 2018 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
+
+  Discrete Cosine Transform
+
+  Functions aubio_dct_do() and aubio_dct_rdo() are equivalent to MATLAB/Octave
+  dct() and idct() functions, as well as scipy.fftpack.dct(x, norm='ortho') and
+  scipy.fftpack.idct(x, norm='ortho')
+
+  \example spectral/test-dct.c
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "spectral/dct.h"
+
+// function pointers prototypes
+typedef void (*aubio_dct_do_t)(aubio_dct_t * s, const fvec_t * input, fvec_t * output);
+typedef void (*aubio_dct_rdo_t)(aubio_dct_t * s, const fvec_t * input, fvec_t * output);
+typedef void (*del_aubio_dct_t)(aubio_dct_t * s);
+
+#if defined(HAVE_ACCELERATE)
+typedef struct _aubio_dct_accelerate_t aubio_dct_accelerate_t;
+extern aubio_dct_accelerate_t * new_aubio_dct_accelerate (uint_t size);
+extern void aubio_dct_accelerate_do(aubio_dct_accelerate_t *s, const fvec_t *input, fvec_t *output);
+extern void aubio_dct_accelerate_rdo(aubio_dct_accelerate_t *s, const fvec_t *input, fvec_t *output);
+extern void del_aubio_dct_accelerate (aubio_dct_accelerate_t *s);
+#elif defined(HAVE_FFTW3)
+typedef struct _aubio_dct_fftw_t aubio_dct_fftw_t;
+extern aubio_dct_fftw_t * new_aubio_dct_fftw (uint_t size);
+extern void aubio_dct_fftw_do(aubio_dct_fftw_t *s, const fvec_t *input, fvec_t *output);
+extern void aubio_dct_fftw_rdo(aubio_dct_fftw_t *s, const fvec_t *input, fvec_t *output);
+extern void del_aubio_dct_fftw (aubio_dct_fftw_t *s);
+#elif defined(HAVE_INTEL_IPP)
+typedef struct _aubio_dct_ipp_t aubio_dct_ipp_t;
+extern aubio_dct_ipp_t * new_aubio_dct_ipp (uint_t size);
+extern void aubio_dct_ipp_do(aubio_dct_ipp_t *s, const fvec_t *input, fvec_t *output);
+extern void aubio_dct_ipp_rdo(aubio_dct_ipp_t *s, const fvec_t *input, fvec_t *output);
+extern void del_aubio_dct_ipp (aubio_dct_ipp_t *s);
+#else
+typedef struct _aubio_dct_ooura_t aubio_dct_ooura_t;
+extern aubio_dct_ooura_t * new_aubio_dct_ooura (uint_t size);
+extern void aubio_dct_ooura_do(aubio_dct_ooura_t *s, const fvec_t *input, fvec_t *output);
+extern void aubio_dct_ooura_rdo(aubio_dct_ooura_t *s, const fvec_t *input, fvec_t *output);
+extern void del_aubio_dct_ooura (aubio_dct_ooura_t *s);
+#endif
+
+// plain mode
+typedef struct _aubio_dct_plain_t aubio_dct_plain_t;
+extern aubio_dct_plain_t * new_aubio_dct_plain (uint_t size);
+extern void aubio_dct_plain_do(aubio_dct_plain_t *s, const fvec_t *input, fvec_t *output);
+extern void aubio_dct_plain_rdo(aubio_dct_plain_t *s, const fvec_t *input, fvec_t *output);
+extern void del_aubio_dct_plain (aubio_dct_plain_t *s);
+
+struct _aubio_dct_t {
+  void *dct;
+  aubio_dct_do_t dct_do;
+  aubio_dct_rdo_t dct_rdo;
+  del_aubio_dct_t del_dct;
+};
+
+aubio_dct_t* new_aubio_dct (uint_t size) {
+  aubio_dct_t * s = AUBIO_NEW(aubio_dct_t);
+#if defined(HAVE_ACCELERATE)
+  // vDSP supports sizes = f * 2 ** n, where n >= 4 and f in [1, 3, 5, 15]
+  // see https://developer.apple.com/documentation/accelerate/1449930-vdsp_dct_createsetup
+  {
+    uint_t radix = size;
+    uint_t order = 0;
+    while ((radix >= 1) && ((radix / 2) * 2 == radix)) {
+      radix /= 2;
+      order++;
+    }
+    if (order < 4 || (radix != 1 && radix != 3 && radix != 5 && radix != 15)) {
+      goto plain;
+    }
+  }
+  s->dct = (void *)new_aubio_dct_accelerate (size);
+  if (s->dct) {
+    s->dct_do = (aubio_dct_do_t)aubio_dct_accelerate_do;
+    s->dct_rdo = (aubio_dct_rdo_t)aubio_dct_accelerate_rdo;
+    s->del_dct = (del_aubio_dct_t)del_aubio_dct_accelerate;
+    return s;
+  }
+#elif defined(HAVE_FFTW3)
+  // fftw supports any positive integer size
+  s->dct = (void *)new_aubio_dct_fftw (size);
+  if (s->dct) {
+    s->dct_do = (aubio_dct_do_t)aubio_dct_fftw_do;
+    s->dct_rdo = (aubio_dct_rdo_t)aubio_dct_fftw_rdo;
+    s->del_dct = (del_aubio_dct_t)del_aubio_dct_fftw;
+    return s;
+  } else {
+    AUBIO_WRN("dct: unexpected error while creating dct_fftw with size %d\n",
+        size);
+    goto plain;
+  }
+#elif defined(HAVE_INTEL_IPP)
+  // unclear from the docs, but intel ipp seems to support any size
+  s->dct = (void *)new_aubio_dct_ipp (size);
+  if (s->dct) {
+    s->dct_do = (aubio_dct_do_t)aubio_dct_ipp_do;
+    s->dct_rdo = (aubio_dct_rdo_t)aubio_dct_ipp_rdo;
+    s->del_dct = (del_aubio_dct_t)del_aubio_dct_ipp;
+    return s;
+  } else {
+    AUBIO_WRN("dct: unexpected error while creating dct_ipp with size %d\n",
+        size);
+    goto plain;
+  }
+#else
+  // ooura support sizes that are power of 2
+  if (aubio_is_power_of_two(size) != 1 || size == 1) {
+    goto plain;
+  }
+  s->dct = (void *)new_aubio_dct_ooura (size);
+  if (s->dct) {
+    s->dct_do = (aubio_dct_do_t)aubio_dct_ooura_do;
+    s->dct_rdo = (aubio_dct_rdo_t)aubio_dct_ooura_rdo;
+    s->del_dct = (del_aubio_dct_t)del_aubio_dct_ooura;
+    return s;
+  }
+#endif
+  // falling back to plain mode
+  AUBIO_WRN("dct: no optimised implementation could be created for size %d\n",
+      size);
+plain:
+  s->dct = (void *)new_aubio_dct_plain (size);
+  if (s->dct) {
+    s->dct_do = (aubio_dct_do_t)aubio_dct_plain_do;
+    s->dct_rdo = (aubio_dct_rdo_t)aubio_dct_plain_rdo;
+    s->del_dct = (del_aubio_dct_t)del_aubio_dct_plain;
+    return s;
+  } else {
+    goto beach;
+  }
+beach:
+  AUBIO_ERROR("dct: failed creating with size %d, should be > 0\n", size);
+  del_aubio_dct(s);
+  return NULL;
+}
+
+void del_aubio_dct(aubio_dct_t *s) {
+  if (s->dct && s->del_dct) s->del_dct (s->dct);
+  AUBIO_FREE (s);
+}
+
+void aubio_dct_do(aubio_dct_t *s, const fvec_t *input, fvec_t *output) {
+  s->dct_do ((void *)s->dct, input, output);
+}
+
+void aubio_dct_rdo(aubio_dct_t *s, const fvec_t *input, fvec_t *output) {
+  s->dct_rdo ((void *)s->dct, input, output);
+}
--- /dev/null
+++ b/src/spectral/dct.h
@@ -1,0 +1,85 @@
+/*
+  Copyright (C) 2017 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
+
+  Discrete Cosine Transform
+
+  Functions aubio_dct_do() and aubio_dct_rdo() are equivalent to MATLAB/Octave
+  dct() and idct() functions, as well as scipy.fftpack.dct(x, norm='ortho') and
+  scipy.fftpack.idct(x, norm='ortho')
+
+  \example spectral/test-dct.c
+
+*/
+
+#ifndef AUBIO_DCT_H
+#define AUBIO_DCT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** DCT object
+
+  This object computes forward and backward DCT type 2 with orthonormal
+  scaling.
+
+*/
+typedef struct _aubio_dct_t aubio_dct_t;
+
+/** create new DCT computation object
+
+  \param size length of the DCT
+
+*/
+aubio_dct_t * new_aubio_dct(uint_t size);
+
+/** compute forward DCT
+
+  \param s dct object as returned by new_aubio_dct
+  \param input input signal
+  \param dct_output transformed input array
+
+*/
+void aubio_dct_do (aubio_dct_t *s, const fvec_t * input, fvec_t * dct_output);
+
+/** compute backward DCT
+
+  \param s dct object as returned by new_aubio_dct
+  \param input input signal
+  \param idct_output transformed input array
+
+*/
+void aubio_dct_rdo (aubio_dct_t *s, const fvec_t * input, fvec_t * idct_output);
+
+
+/** delete DCT object
+
+  \param s dct object as returned by new_aubio_dct
+
+*/
+void del_aubio_dct (aubio_dct_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_DCT_H */
--- /dev/null
+++ b/src/spectral/dct_accelerate.c
@@ -1,0 +1,102 @@
+/*
+  Copyright (C) 2017 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "spectral/dct.h"
+
+#if defined(HAVE_ACCELERATE)
+
+#if HAVE_AUBIO_DOUBLE
+#warning "no double-precision dct with accelerate"
+#endif
+
+struct _aubio_dct_accelerate_t {
+  uint_t size;
+  fvec_t *tmp;
+  vDSP_DFT_Setup setup;
+  vDSP_DFT_Setup setupInv;
+};
+
+typedef struct _aubio_dct_accelerate_t aubio_dct_accelerate_t;
+
+void del_aubio_dct_accelerate (aubio_dct_accelerate_t *s);
+
+aubio_dct_accelerate_t * new_aubio_dct_accelerate (uint_t size) {
+  aubio_dct_accelerate_t * s = AUBIO_NEW(aubio_dct_accelerate_t);
+
+  if ((sint_t)size < 16 || !aubio_is_power_of_two(size)) {
+    AUBIO_ERR("dct: can only create with sizes greater than 16 and"
+        " that are powers of two, requested %d\n", size);
+    goto beach;
+  }
+
+  s->setup = vDSP_DCT_CreateSetup(NULL, (vDSP_Length)size, vDSP_DCT_II);
+  s->setupInv = vDSP_DCT_CreateSetup(NULL, (vDSP_Length)size, vDSP_DCT_III);
+  if (s->setup == NULL || s->setupInv == NULL) {
+    goto beach;
+  }
+
+  s->size = size;
+
+  return s;
+
+beach:
+  del_aubio_dct_accelerate(s);
+  return NULL;
+}
+
+void del_aubio_dct_accelerate(aubio_dct_accelerate_t *s) {
+  if (s->setup) vDSP_DFT_DestroySetup(s->setup);
+  if (s->setupInv) vDSP_DFT_DestroySetup(s->setupInv);
+  AUBIO_FREE(s);
+}
+
+void aubio_dct_accelerate_do(aubio_dct_accelerate_t *s, const fvec_t *input, fvec_t *output) {
+
+  vDSP_DCT_Execute(s->setup, (const float *)input->data, (float *)output->data);
+
+  // apply orthonormal scaling
+  output->data[0] *= SQRT(1./s->size);
+  smpl_t scaler = SQRT(2./s->size);
+
+  aubio_vDSP_vsmul(output->data + 1, 1, &scaler, output->data + 1, 1,
+      output->length - 1);
+
+}
+
+void aubio_dct_accelerate_rdo(aubio_dct_accelerate_t *s, const fvec_t *input, fvec_t *output) {
+
+  output->data[0] = input->data[0] / SQRT(1./s->size);
+  smpl_t scaler = 1./SQRT(2./s->size);
+
+  aubio_vDSP_vsmul(input->data + 1, 1, &scaler, output->data + 1, 1,
+      output->length - 1);
+
+  vDSP_DCT_Execute(s->setupInv, (const float *)output->data,
+      (float *)output->data);
+
+  scaler = 2./s->size;
+
+  aubio_vDSP_vsmul(output->data, 1, &scaler, output->data, 1, output->length);
+
+}
+
+#endif //defined(HAVE_ACCELERATE)
--- /dev/null
+++ b/src/spectral/dct_fftw.c
@@ -1,0 +1,130 @@
+/*
+  Copyright (C) 2017 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "spectral/dct.h"
+
+#ifdef HAVE_FFTW3
+
+#include <fftw3.h>
+#include <pthread.h>
+
+#ifdef HAVE_FFTW3F
+#if HAVE_AUBIO_DOUBLE
+#error "Using aubio in double precision with fftw3 in single precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#else  /* HAVE_FFTW3F */
+#if !HAVE_AUBIO_DOUBLE
+#error "Using aubio in single precision with fftw3 in double precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_FFTW3F */
+
+#ifdef HAVE_FFTW3F
+#define fftw_malloc            fftwf_malloc
+#define fftw_free              fftwf_free
+#define fftw_execute           fftwf_execute
+#define fftw_plan_dft_r2c_1d   fftwf_plan_dft_r2c_1d
+#define fftw_plan_dft_c2r_1d   fftwf_plan_dft_c2r_1d
+#define fftw_plan_r2r_1d       fftwf_plan_r2r_1d
+#define fftw_plan              fftwf_plan
+#define fftw_destroy_plan      fftwf_destroy_plan
+#endif
+
+// defined in src/spectral/fft.c
+extern pthread_mutex_t aubio_fftw_mutex;
+
+typedef struct _aubio_dct_fftw_t aubio_dct_fftw_t;
+
+struct _aubio_dct_fftw_t {
+  uint_t size;
+  fvec_t *in, *out;
+  smpl_t *data;
+  fftw_plan pfw, pbw;
+  smpl_t scalers[5];
+};
+
+aubio_dct_fftw_t * new_aubio_dct_fftw (uint_t size) {
+  aubio_dct_fftw_t * s = AUBIO_NEW(aubio_dct_fftw_t);
+  if ((sint_t)size <= 0) {
+    AUBIO_ERR("dct_fftw: can only create with size > 0, requested %d\n",
+        size);
+    goto beach;
+  }
+  s->size = size;
+  s->in = new_fvec(size);
+  s->out = new_fvec(size);
+  pthread_mutex_lock(&aubio_fftw_mutex);
+  s->data = (smpl_t *)fftw_malloc(sizeof(smpl_t) * size);
+  s->pfw = fftw_plan_r2r_1d(size, s->in->data,  s->data, FFTW_REDFT10,
+      FFTW_ESTIMATE);
+  s->pbw = fftw_plan_r2r_1d(size, s->data, s->out->data, FFTW_REDFT01,
+      FFTW_ESTIMATE);
+  pthread_mutex_unlock(&aubio_fftw_mutex);
+  s->scalers[0] = SQRT(1./(4.*s->size));
+  s->scalers[1] = SQRT(1./(2.*s->size));
+  s->scalers[2] = 1. / s->scalers[0];
+  s->scalers[3] = 1. / s->scalers[1];
+  s->scalers[4] = .5 / s->size;
+  return s;
+beach:
+  AUBIO_FREE(s);
+  return NULL;
+}
+
+void del_aubio_dct_fftw(aubio_dct_fftw_t *s) {
+  pthread_mutex_lock(&aubio_fftw_mutex);
+  fftw_destroy_plan(s->pfw);
+  fftw_destroy_plan(s->pbw);
+  fftw_free(s->data);
+  pthread_mutex_unlock(&aubio_fftw_mutex);
+  del_fvec(s->in);
+  del_fvec(s->out);
+  AUBIO_FREE(s);
+}
+
+void aubio_dct_fftw_do(aubio_dct_fftw_t *s, const fvec_t *input, fvec_t *output) {
+  uint_t i;
+  fvec_copy(input, s->in);
+  fftw_execute(s->pfw);
+  //fvec_copy(s->out, output);
+  s->data[0] *= s->scalers[0];
+  for (i = 1; i < s->size; i++) {
+    s->data[i] *= s->scalers[1];
+  }
+  memcpy(output->data, s->data, output->length * sizeof(smpl_t));
+}
+
+void aubio_dct_fftw_rdo(aubio_dct_fftw_t *s, const fvec_t *input, fvec_t *output) {
+  uint_t i;
+  memcpy(s->data, input->data, input->length * sizeof(smpl_t));
+  //s->data[0] *= .5;
+  s->data[0] *= s->scalers[2];
+  for (i = 1; i < s->size; i++) {
+    s->data[i] *= s->scalers[3];
+  }
+  fftw_execute(s->pbw);
+  for (i = 0; i < s->size; i++) {
+    s->out->data[i] *= s->scalers[4];
+  }
+  fvec_copy(s->out, output);
+}
+
+#endif //HAVE_FFTW3
--- /dev/null
+++ b/src/spectral/dct_ipp.c
@@ -1,0 +1,150 @@
+/*
+  Copyright (C) 2017 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "spectral/dct.h"
+
+#if defined(HAVE_INTEL_IPP)
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_IppFloat                 Ipp32f
+#define aubio_ippsDCTFwdSpec           IppsDCTFwdSpec_32f
+#define aubio_ippsDCTInvSpec           IppsDCTInvSpec_32f
+#define aubio_ippsDCTFwdGetSize        ippsDCTFwdGetSize_32f
+#define aubio_ippsDCTInvGetSize        ippsDCTInvGetSize_32f
+#define aubio_ippsDCTFwdInit           ippsDCTFwdInit_32f
+#define aubio_ippsDCTInvInit           ippsDCTInvInit_32f
+#define aubio_ippsDCTFwd               ippsDCTFwd_32f
+#define aubio_ippsDCTInv               ippsDCTInv_32f
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_IppFloat                 Ipp64f
+#define aubio_ippsDCTFwdSpec           IppsDCTFwdSpec_64f
+#define aubio_ippsDCTInvSpec           IppsDCTInvSpec_64f
+#define aubio_ippsDCTFwdGetSize        ippsDCTFwdGetSize_64f
+#define aubio_ippsDCTInvGetSize        ippsDCTInvGetSize_64f
+#define aubio_ippsDCTFwdInit           ippsDCTFwdInit_64f
+#define aubio_ippsDCTInvInit           ippsDCTInvInit_64f
+#define aubio_ippsDCTFwd               ippsDCTFwd_64f
+#define aubio_ippsDCTInv               ippsDCTInv_64f
+#endif
+
+typedef struct _aubio_dct_ipp_t aubio_dct_ipp_t;
+
+struct _aubio_dct_ipp_t {
+  uint_t size;
+  Ipp8u* pSpecFwd;
+  Ipp8u* pSpecInv;
+  Ipp8u* pSpecBuffer;
+  Ipp8u* pBuffer;
+  aubio_ippsDCTFwdSpec* pFwdDCTSpec;
+  aubio_ippsDCTInvSpec* pInvDCTSpec;
+};
+
+void del_aubio_dct_ipp (aubio_dct_ipp_t *s);
+
+aubio_dct_ipp_t * new_aubio_dct_ipp (uint_t size) {
+  aubio_dct_ipp_t * s = AUBIO_NEW(aubio_dct_ipp_t);
+
+  const IppHintAlgorithm qualityHint = ippAlgHintAccurate; // ippAlgHintFast;
+  int pSpecSize, pSpecBufferSize, pBufferSize;
+  IppStatus status;
+
+  if ((sint_t)size <= 0) {
+    AUBIO_ERR("dct: can only create with sizes greater than 0, requested %d\n",
+        size);
+    goto beach;
+  }
+
+  status = aubio_ippsDCTFwdGetSize(size, qualityHint, &pSpecSize,
+      &pSpecBufferSize, &pBufferSize);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("dct: failed to initialize dct. IPP error: %d\n", status);
+    goto beach;
+  }
+
+  //AUBIO_INF("dct: fwd initialized with %d %d %d\n", pSpecSize, pSpecBufferSize,
+  //    pBufferSize);
+
+  s->pSpecFwd = ippsMalloc_8u(pSpecSize);
+  s->pSpecInv = ippsMalloc_8u(pSpecSize);
+  if (pSpecSize > 0) {
+    s->pSpecBuffer = ippsMalloc_8u(pSpecBufferSize);
+  } else {
+    s->pSpecBuffer = NULL;
+  }
+  s->pBuffer = ippsMalloc_8u(pBufferSize);
+
+  status = aubio_ippsDCTInvGetSize(size, qualityHint, &pSpecSize,
+      &pSpecBufferSize, &pBufferSize);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("dct: failed to initialize dct. IPP error: %d\n", status);
+    goto beach;
+  }
+
+  //AUBIO_INF("dct: inv initialized with %d %d %d\n", pSpecSize, pSpecBufferSize,
+  //    pBufferSize);
+
+  status = aubio_ippsDCTFwdInit(&(s->pFwdDCTSpec), size, qualityHint, s->pSpecFwd,
+      s->pSpecBuffer);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("dct: failed to initialize fwd dct. IPP error: %d\n", status);
+    goto beach;
+  }
+
+  status = aubio_ippsDCTInvInit(&(s->pInvDCTSpec), size, qualityHint, s->pSpecInv,
+      s->pSpecBuffer);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("dct: failed to initialize inv dct. IPP error: %d\n", status);
+    goto beach;
+  }
+
+  s->size = size;
+
+  return s;
+
+beach:
+  del_aubio_dct_ipp(s);
+  return NULL;
+}
+
+void del_aubio_dct_ipp(aubio_dct_ipp_t *s) {
+  ippFree(s->pSpecFwd);
+  ippFree(s->pSpecInv);
+  ippFree(s->pSpecBuffer);
+  ippFree(s->pBuffer);
+  AUBIO_FREE(s);
+}
+
+void aubio_dct_ipp_do(aubio_dct_ipp_t *s, const fvec_t *input, fvec_t *output) {
+
+  aubio_ippsDCTFwd((const aubio_IppFloat*)input->data,
+      (aubio_IppFloat*)output->data, s->pFwdDCTSpec, s->pBuffer);
+
+}
+
+void aubio_dct_ipp_rdo(aubio_dct_ipp_t *s, const fvec_t *input, fvec_t *output) {
+
+  aubio_ippsDCTInv((const aubio_IppFloat*)input->data,
+      (aubio_IppFloat*)output->data, s->pInvDCTSpec, s->pBuffer);
+
+}
+
+#endif //defined(HAVE_INTEL_IPP)
--- /dev/null
+++ b/src/spectral/dct_ooura.c
@@ -1,0 +1,96 @@
+/*
+  Copyright (C) 2017 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "spectral/dct.h"
+
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_FFTW3) && !defined(HAVE_INTEL_IPP)
+
+typedef struct _aubio_dct_ooura_t aubio_dct_ooura_t;
+
+extern void aubio_ooura_ddct(int, int, smpl_t *, int *, smpl_t *);
+
+struct _aubio_dct_ooura_t {
+  uint_t size;
+  fvec_t *input;
+  smpl_t *w;
+  int *ip;
+  smpl_t scalers[5];
+};
+
+aubio_dct_ooura_t * new_aubio_dct_ooura (uint_t size) {
+  aubio_dct_ooura_t * s = AUBIO_NEW(aubio_dct_ooura_t);
+  if (aubio_is_power_of_two(size) != 1 || (sint_t)size <= 0) {
+    AUBIO_ERR("dct_ooura: can only create with sizes power of two, requested %d\n",
+        size);
+    goto beach;
+  }
+  s->size = size;
+  s->input = new_fvec(s->size);
+  s->w = AUBIO_ARRAY(smpl_t, s->size * 5 / 4);
+  s->ip = AUBIO_ARRAY(int, 3 + (1 << (int)FLOOR(LOG(s->size/2) / LOG(2))) / 2);
+  s->ip[0] = 0;
+  s->scalers[0] = 2. * SQRT(1./(4.*s->size));
+  s->scalers[1] = 2. * SQRT(1./(2.*s->size));
+  s->scalers[2] = 1. / s->scalers[0];
+  s->scalers[3] = 1. / s->scalers[1];
+  s->scalers[4] = 2. / s->size;
+  return s;
+beach:
+  AUBIO_FREE(s);
+  return NULL;
+}
+
+void del_aubio_dct_ooura(aubio_dct_ooura_t *s) {
+  del_fvec(s->input);
+  AUBIO_FREE(s->ip);
+  AUBIO_FREE(s->w);
+  AUBIO_FREE(s);
+}
+
+void aubio_dct_ooura_do(aubio_dct_ooura_t *s, const fvec_t *input, fvec_t *output) {
+  uint_t i = 0;
+  fvec_copy(input, s->input);
+  aubio_ooura_ddct(s->size, -1, s->input->data, s->ip, s->w);
+  // apply orthonormal scaling
+  s->input->data[0] *= s->scalers[0];
+  for (i = 1; i < s->input->length; i++) {
+    s->input->data[i] *= s->scalers[1];
+  }
+  fvec_copy(s->input, output);
+}
+
+void aubio_dct_ooura_rdo(aubio_dct_ooura_t *s, const fvec_t *input, fvec_t *output) {
+  uint_t i = 0;
+  fvec_copy(input, s->input);
+  s->input->data[0] *= s->scalers[2];
+  for (i = 1; i < s->input->length; i++) {
+    s->input->data[i] *= s->scalers[3];
+  }
+  s->input->data[0] *= .5;
+  aubio_ooura_ddct(s->size, 1, s->input->data, s->ip, s->w);
+  for (i = 0; i < s->input->length; i++) {
+    s->input->data[i] *= s->scalers[4];
+  }
+  fvec_copy(s->input, output);
+}
+
+#endif //!defined(HAVE_ACCELERATE) && !defined(HAVE_FFTW3)
--- /dev/null
+++ b/src/spectral/dct_plain.c
@@ -1,0 +1,105 @@
+/*
+  Copyright (C) 2018 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/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "spectral/dct.h"
+
+typedef struct _aubio_dct_plain_t aubio_dct_plain_t;
+
+struct _aubio_dct_plain_t {
+  uint_t size;
+  fmat_t *dct_coeffs;       /** DCT type II orthonormal transform, size * size */
+  fmat_t *idct_coeffs;      /** DCT type III orthonormal transform, size * size */
+};
+
+void del_aubio_dct_plain (aubio_dct_plain_t *s);
+
+aubio_dct_plain_t * new_aubio_dct_plain (uint_t size) {
+  aubio_dct_plain_t * s = AUBIO_NEW(aubio_dct_plain_t);
+  uint_t i, j;
+  smpl_t scaling;
+  if (aubio_is_power_of_two (size) == 1 && size > 16) {
+    AUBIO_WRN("dct_plain: using plain dct but size %d is a power of two\n", size);
+  }
+  if ((sint_t)size <= 0) {
+    AUBIO_ERR("dct_plain: can only create with size > 0, requested %d\n",
+        size);
+    goto failure;
+  }
+
+  s->size = size;
+
+  s->dct_coeffs = new_fmat (size, size);
+  s->idct_coeffs = new_fmat (size, size);
+
+  /* compute DCT type-II transformation matrix
+     dct_coeffs[j][i] = cos ( j * (i+.5) * PI / n_filters )
+  */
+  scaling = SQRT (2. / size);
+  for (i = 0; i < size; i++) {
+    for (j = 1; j < size; j++) {
+      s->dct_coeffs->data[j][i] =
+          scaling * COS (j * (i + 0.5) * PI / size );
+    }
+    s->dct_coeffs->data[0][i] = 1. / SQRT (size);
+  }
+
+  /* compute DCT type-III transformation matrix
+     idct_coeffs[j][i] = cos ( i * (j+.5) * PI / n_filters )
+  */
+  scaling = SQRT (2. / size);
+  for (j = 0; j < size; j++) {
+    for (i = 1; i < size; i++) {
+      s->idct_coeffs->data[j][i] =
+          scaling * COS (i * (j + 0.5) * PI / size );
+    }
+    s->idct_coeffs->data[j][0] = 1. / SQRT (size);
+  }
+  return s;
+failure:
+  del_aubio_dct_plain(s);
+  return NULL;
+}
+
+void del_aubio_dct_plain (aubio_dct_plain_t *s) {
+  if (s->dct_coeffs)
+    del_fmat(s->dct_coeffs);
+  if (s->idct_coeffs)
+    del_fmat(s->idct_coeffs);
+  AUBIO_FREE(s);
+}
+
+void aubio_dct_plain_do(aubio_dct_plain_t *s, const fvec_t *input, fvec_t *output) {
+  if (input->length != output->length || input->length != s->size) {
+    AUBIO_WRN("dct_plain: using input length %d, but output length = %d and size = %d\n",
+        input->length, output->length, s->size);
+  }
+  fmat_vecmul(s->dct_coeffs, input, output);
+}
+
+void aubio_dct_plain_rdo(aubio_dct_plain_t *s, const fvec_t *input, fvec_t *output) {
+  if (input->length != output->length || input->length != s->size) {
+    AUBIO_WRN("dct_plain: using input length %d, but output length = %d and size = %d\n",
+        input->length, output->length, s->size);
+  }
+  fmat_vecmul(s->idct_coeffs, input, output);
+}
--- a/src/spectral/fft.c
+++ b/src/spectral/fft.c
@@ -77,8 +77,7 @@
 // a global mutex for FFTW thread safety
 pthread_mutex_t aubio_fftw_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-#else
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
+#elif defined HAVE_ACCELERATE        // using ACCELERATE
 // https://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html
 #include <Accelerate/Accelerate.h>
 
@@ -90,11 +89,12 @@
 #define aubio_vDSP_zvphas              vDSP_zvphas
 #define aubio_vDSP_vsadd               vDSP_vsadd
 #define aubio_vDSP_vsmul               vDSP_vsmul
-#define aubio_vDSP_create_fftsetup     vDSP_create_fftsetup
-#define aubio_vDSP_destroy_fftsetup    vDSP_destroy_fftsetup
 #define aubio_DSPComplex               DSPComplex
 #define aubio_DSPSplitComplex          DSPSplitComplex
-#define aubio_FFTSetup                 FFTSetup
+#define aubio_vDSP_DFT_Setup           vDSP_DFT_Setup
+#define aubio_vDSP_DFT_zrop_CreateSetup vDSP_DFT_zrop_CreateSetup
+#define aubio_vDSP_DFT_Execute         vDSP_DFT_Execute
+#define aubio_vDSP_DFT_DestroySetup    vDSP_DFT_DestroySetup
 #define aubio_vvsqrt                   vvsqrtf
 #else
 #define aubio_vDSP_ctoz                vDSP_ctozD
@@ -104,40 +104,74 @@
 #define aubio_vDSP_zvphas              vDSP_zvphasD
 #define aubio_vDSP_vsadd               vDSP_vsaddD
 #define aubio_vDSP_vsmul               vDSP_vsmulD
-#define aubio_vDSP_create_fftsetup     vDSP_create_fftsetupD
-#define aubio_vDSP_destroy_fftsetup    vDSP_destroy_fftsetupD
 #define aubio_DSPComplex               DSPDoubleComplex
 #define aubio_DSPSplitComplex          DSPDoubleSplitComplex
-#define aubio_FFTSetup                 FFTSetupD
+#define aubio_vDSP_DFT_Setup           vDSP_DFT_SetupD
+#define aubio_vDSP_DFT_zrop_CreateSetup vDSP_DFT_zrop_CreateSetupD
+#define aubio_vDSP_DFT_Execute         vDSP_DFT_ExecuteD
+#define aubio_vDSP_DFT_DestroySetup    vDSP_DFT_DestroySetupD
 #define aubio_vvsqrt                   vvsqrt
 #endif /* HAVE_AUBIO_DOUBLE */
 
-#else                         // using OOURA
+#elif defined HAVE_INTEL_IPP // using INTEL IPP
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_IppFloat                 Ipp32f
+#define aubio_IppComplex               Ipp32fc
+#define aubio_FFTSpec                  FFTSpec_R_32f
+#define aubio_ippsMalloc_complex       ippsMalloc_32fc
+#define aubio_ippsFFTInit_R            ippsFFTInit_R_32f
+#define aubio_ippsFFTGetSize_R         ippsFFTGetSize_R_32f
+#define aubio_ippsFFTInv_CCSToR        ippsFFTInv_CCSToR_32f
+#define aubio_ippsFFTFwd_RToCCS        ippsFFTFwd_RToCCS_32f
+#define aubio_ippsAtan2                ippsAtan2_32f_A21
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_IppFloat                 Ipp64f
+#define aubio_IppComplex               Ipp64fc
+#define aubio_FFTSpec                  FFTSpec_R_64f
+#define aubio_ippsMalloc_complex       ippsMalloc_64fc
+#define aubio_ippsFFTInit_R            ippsFFTInit_R_64f
+#define aubio_ippsFFTGetSize_R         ippsFFTGetSize_R_64f
+#define aubio_ippsFFTInv_CCSToR        ippsFFTInv_CCSToR_64f
+#define aubio_ippsFFTFwd_RToCCS        ippsFFTFwd_RToCCS_64f
+#define aubio_ippsAtan2                ippsAtan2_64f_A50
+#endif
+
+
+#else // using OOURA
 // let's use ooura instead
 extern void aubio_ooura_rdft(int, int, smpl_t *, int *, smpl_t *);
 
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
+#endif
 
 struct _aubio_fft_t {
   uint_t winsize;
   uint_t fft_size;
+
 #ifdef HAVE_FFTW3             // using FFTW3
   real_t *in, *out;
   fftw_plan pfw, pbw;
-  fft_data_t * specdata;      /* complex spectral data */
-#else
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
-  int log2fftsize;
-  aubio_FFTSetup fftSetup;
+  fft_data_t * specdata; /* complex spectral data */
+
+#elif defined HAVE_ACCELERATE  // using ACCELERATE
+  aubio_vDSP_DFT_Setup fftSetupFwd;
+  aubio_vDSP_DFT_Setup fftSetupBwd;
   aubio_DSPSplitComplex spec;
   smpl_t *in, *out;
+
+#elif defined HAVE_INTEL_IPP  // using Intel IPP
+  smpl_t *in, *out;
+  Ipp8u* memSpec;
+  Ipp8u* memInit;
+  Ipp8u* memBuffer;
+  struct aubio_FFTSpec* fftSpec;
+  aubio_IppComplex* complexOut;
 #else                         // using OOURA
   smpl_t *in, *out;
   smpl_t *w;
   int *ip;
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
+#endif /* using OOURA */
+
   fvec_t * compspec;
 };
 
@@ -147,6 +181,7 @@
     AUBIO_ERR("fft: got winsize %d, but can not be < 2\n", winsize);
     goto beach;
   }
+
 #ifdef HAVE_FFTW3
   uint_t i;
   s->winsize  = winsize;
@@ -175,17 +210,72 @@
   for (i = 0; i < s->fft_size; i++) {
     s->specdata[i] = 0.;
   }
-#else
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
+
+#elif defined HAVE_ACCELERATE  // using ACCELERATE
+  {
+    uint_t radix = winsize;
+    uint_t order = 0;
+    while ((radix / 2) * 2 == radix) {
+      radix /= 2;
+      order++;
+    }
+    if (order < 4 || (radix != 1 && radix != 3 && radix != 5 && radix != 15)) {
+      AUBIO_ERR("fft: vDSP/Accelerate supports FFT with sizes = "
+          "f * 2 ** n, where n > 4 and f in [1, 3, 5, 15], but requested %d. "
+          "Use the closest power of two, or try recompiling aubio with "
+          "--enable-fftw3.\n", winsize);
+      goto beach;
+    }
+  }
   s->winsize = winsize;
   s->fft_size = winsize;
   s->compspec = new_fvec(winsize);
-  s->log2fftsize = (uint_t)log2f(s->fft_size);
   s->in = AUBIO_ARRAY(smpl_t, s->fft_size);
   s->out = AUBIO_ARRAY(smpl_t, s->fft_size);
   s->spec.realp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
   s->spec.imagp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
-  s->fftSetup = aubio_vDSP_create_fftsetup(s->log2fftsize, FFT_RADIX2);
+  s->fftSetupFwd = aubio_vDSP_DFT_zrop_CreateSetup(NULL,
+      s->fft_size, vDSP_DFT_FORWARD);
+  s->fftSetupBwd = aubio_vDSP_DFT_zrop_CreateSetup(s->fftSetupFwd,
+      s->fft_size, vDSP_DFT_INVERSE);
+
+#elif defined HAVE_INTEL_IPP  // using Intel IPP
+  const IppHintAlgorithm qualityHint = ippAlgHintAccurate; // OR ippAlgHintFast;
+  const int flags = IPP_FFT_NODIV_BY_ANY; // we're scaling manually afterwards
+  int order = aubio_power_of_two_order(winsize);
+  int sizeSpec, sizeInit, sizeBuffer;
+  IppStatus status;
+
+  if (winsize <= 4 || aubio_is_power_of_two(winsize) != 1)
+  {
+    AUBIO_ERR("intel IPP fft: can only create with sizes > 4 and power of two, requested %d,"
+      " try recompiling aubio with --enable-fftw3\n", winsize);
+    goto beach;
+  }
+
+  status = aubio_ippsFFTGetSize_R(order, flags, qualityHint,
+      &sizeSpec, &sizeInit, &sizeBuffer);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("fft: failed to initialize fft. IPP error: %d\n", status);
+    goto beach;
+  }
+  s->fft_size = s->winsize = winsize;
+  s->compspec = new_fvec(winsize);
+  s->in = AUBIO_ARRAY(smpl_t, s->winsize);
+  s->out = AUBIO_ARRAY(smpl_t, s->winsize);
+  s->memSpec = ippsMalloc_8u(sizeSpec);
+  s->memBuffer = ippsMalloc_8u(sizeBuffer);
+  if (sizeInit > 0 ) {
+    s->memInit = ippsMalloc_8u(sizeInit);
+  }
+  s->complexOut = aubio_ippsMalloc_complex(s->fft_size / 2 + 1);
+  status = aubio_ippsFFTInit_R(
+    &s->fftSpec, order, flags, qualityHint, s->memSpec, s->memInit);
+  if (status != ippStsNoErr) {
+    AUBIO_ERR("fft: failed to initialize. IPP error: %d\n", status);
+    goto beach;
+  }
+
 #else                         // using OOURA
   if (aubio_is_power_of_two(winsize) != 1) {
     AUBIO_ERR("fft: can only create with sizes power of two, requested %d,"
@@ -200,9 +290,10 @@
   s->ip    = AUBIO_ARRAY(int   , s->fft_size);
   s->w     = AUBIO_ARRAY(smpl_t, s->fft_size);
   s->ip[0] = 0;
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
+#endif /* using OOURA */
+
   return s;
+
 beach:
   AUBIO_FREE(s);
   return NULL;
@@ -210,7 +301,6 @@
 
 void del_aubio_fft(aubio_fft_t * s) {
   /* destroy data */
-  del_fvec(s->compspec);
 #ifdef HAVE_FFTW3             // using FFTW3
   pthread_mutex_lock(&aubio_fftw_mutex);
   fftw_destroy_plan(s->pfw);
@@ -217,18 +307,27 @@
   fftw_destroy_plan(s->pbw);
   fftw_free(s->specdata);
   pthread_mutex_unlock(&aubio_fftw_mutex);
-#else /* HAVE_FFTW3 */
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
   AUBIO_FREE(s->spec.realp);
   AUBIO_FREE(s->spec.imagp);
-  aubio_vDSP_destroy_fftsetup(s->fftSetup);
+  aubio_vDSP_DFT_DestroySetup(s->fftSetupBwd);
+  aubio_vDSP_DFT_DestroySetup(s->fftSetupFwd);
+
+#elif defined HAVE_INTEL_IPP  // using Intel IPP
+  ippFree(s->memSpec);
+  ippFree(s->memInit);
+  ippFree(s->memBuffer);
+  ippFree(s->complexOut);
+
 #else                         // using OOURA
   AUBIO_FREE(s->w);
   AUBIO_FREE(s->ip);
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
-  AUBIO_FREE(s->out);
+#endif
+
+  del_fvec(s->compspec);
   AUBIO_FREE(s->in);
+  AUBIO_FREE(s->out);
   AUBIO_FREE(s);
 }
 
@@ -251,6 +350,7 @@
 #else
   memcpy(s->in, input->data, s->winsize * sizeof(smpl_t));
 #endif /* HAVE_MEMCPY_HACKS */
+
 #ifdef HAVE_FFTW3             // using FFTW3
   fftw_execute(s->pfw);
 #ifdef HAVE_COMPLEX_H
@@ -265,12 +365,13 @@
     compspec->data[i] = s->specdata[i];
   }
 #endif /* HAVE_COMPLEX_H */
-#else /* HAVE_FFTW3 */
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
   // convert real data to even/odd format used in vDSP
   aubio_vDSP_ctoz((aubio_DSPComplex*)s->in, 2, &s->spec, 1, s->fft_size/2);
   // compute the FFT
-  aubio_vDSP_fft_zrip(s->fftSetup, &s->spec, 1, s->log2fftsize, FFT_FORWARD);
+  aubio_vDSP_DFT_Execute(s->fftSetupFwd, s->spec.realp, s->spec.imagp,
+      s->spec.realp, s->spec.imagp);
   // convert from vDSP complex split to [ r0, r1, ..., rN, iN-1, .., i2, i1]
   compspec->data[0] = s->spec.realp[0];
   compspec->data[s->fft_size / 2] = s->spec.imagp[0];
@@ -281,6 +382,19 @@
   // apply scaling
   smpl_t scale = 1./2.;
   aubio_vDSP_vsmul(compspec->data, 1, &scale, compspec->data, 1, s->fft_size);
+
+#elif defined HAVE_INTEL_IPP  // using Intel IPP
+
+  // apply fft
+  aubio_ippsFFTFwd_RToCCS(s->in, (aubio_IppFloat*)s->complexOut, s->fftSpec, s->memBuffer);
+  // convert complex buffer to [ r0, r1, ..., rN, iN-1, .., i2, i1]
+  compspec->data[0] = s->complexOut[0].re;
+  compspec->data[s->fft_size / 2] = s->complexOut[s->fft_size / 2].re;
+  for (i = 1; i < s->fft_size / 2; i++) {
+    compspec->data[i] = s->complexOut[i].re;
+    compspec->data[s->fft_size - i] = s->complexOut[i].im;
+  }
+
 #else                         // using OOURA
   aubio_ooura_rdft(s->winsize, 1, s->in, s->ip, s->w);
   compspec->data[0] = s->in[0];
@@ -289,8 +403,7 @@
     compspec->data[i] = s->in[2 * i];
     compspec->data[s->winsize - i] = - s->in[2 * i + 1];
   }
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
+#endif /* using OOURA */
 }
 
 void aubio_fft_rdo_complex(aubio_fft_t * s, const fvec_t * compspec, fvec_t * output) {
@@ -313,8 +426,8 @@
   for (i = 0; i < output->length; i++) {
     output->data[i] = s->out[i]*renorm;
   }
-#else /* HAVE_FFTW3 */
-#ifdef HAVE_ACCELERATE        // using ACCELERATE
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
   // convert from real imag  [ r0, r1, ..., rN, iN-1, .., i2, i1]
   // to vDSP packed format   [ r0, rN, r1, i1, ..., rN-1, iN-1 ]
   s->out[0] = compspec->data[0];
@@ -326,12 +439,30 @@
   // convert to split complex format used in vDSP
   aubio_vDSP_ctoz((aubio_DSPComplex*)s->out, 2, &s->spec, 1, s->fft_size/2);
   // compute the FFT
-  aubio_vDSP_fft_zrip(s->fftSetup, &s->spec, 1, s->log2fftsize, FFT_INVERSE);
+  aubio_vDSP_DFT_Execute(s->fftSetupBwd, s->spec.realp, s->spec.imagp,
+      s->spec.realp, s->spec.imagp);
   // convert result to real output
   aubio_vDSP_ztoc(&s->spec, 1, (aubio_DSPComplex*)output->data, 2, s->fft_size/2);
   // apply scaling
   smpl_t scale = 1.0 / s->winsize;
   aubio_vDSP_vsmul(output->data, 1, &scale, output->data, 1, s->fft_size);
+
+#elif defined HAVE_INTEL_IPP  // using Intel IPP
+
+  // convert from real imag  [ r0, 0, ..., rN, iN-1, .., i2, i1, iN-1] to complex format
+  s->complexOut[0].re = compspec->data[0];
+  s->complexOut[0].im = 0;
+  s->complexOut[s->fft_size / 2].re = compspec->data[s->fft_size / 2];
+  s->complexOut[s->fft_size / 2].im = 0.0;
+  for (i = 1; i < s->fft_size / 2; i++) {
+    s->complexOut[i].re = compspec->data[i];
+    s->complexOut[i].im = compspec->data[s->fft_size - i];
+  }
+  // apply fft
+  aubio_ippsFFTInv_CCSToR((const aubio_IppFloat *)s->complexOut, output->data, s->fftSpec, s->memBuffer);
+  // apply scaling
+  aubio_ippsMulC(output->data, 1.0 / s->winsize, output->data, s->fft_size);
+
 #else                         // using OOURA
   smpl_t scale = 2.0 / s->winsize;
   s->out[0] = compspec->data[0];
@@ -344,8 +475,7 @@
   for (i=0; i < s->winsize; i++) {
     output->data[i] = s->out[i] * scale;
   }
-#endif /* HAVE_ACCELERATE */
-#endif /* HAVE_FFTW3 */
+#endif
 }
 
 void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum) {
@@ -365,15 +495,42 @@
   } else {
     spectrum->phas[0] = 0.;
   }
+#if defined(HAVE_INTEL_IPP)
+  // convert from real imag  [ r0, r1, ..., rN, iN-1, ..., i2, i1, i0]
+  //                     to  [ r0, r1, ..., rN, i0, i1, i2, ..., iN-1]
+  for (i = 1; i < spectrum->length / 2; i++) {
+    ELEM_SWAP(compspec->data[compspec->length - i],
+        compspec->data[spectrum->length + i - 1]);
+  }
+  aubio_ippsAtan2(compspec->data + spectrum->length,
+      compspec->data + 1, spectrum->phas + 1, spectrum->length - 1);
+  // revert the imaginary part back again
+  for (i = 1; i < spectrum->length / 2; i++) {
+    ELEM_SWAP(compspec->data[spectrum->length + i - 1],
+        compspec->data[compspec->length - i]);
+  }
+#else
   for (i=1; i < spectrum->length - 1; i++) {
     spectrum->phas[i] = ATAN2(compspec->data[compspec->length-i],
         compspec->data[i]);
   }
-  if (compspec->data[compspec->length/2] < 0) {
-    spectrum->phas[spectrum->length - 1] = PI;
+#endif
+#ifdef HAVE_FFTW3
+  // for even length only, make sure last element is 0 or PI
+  if (2 * (compspec->length / 2) == compspec->length) {
+#endif
+    if (compspec->data[compspec->length/2] < 0) {
+      spectrum->phas[spectrum->length - 1] = PI;
+    } else {
+      spectrum->phas[spectrum->length - 1] = 0.;
+    }
+#ifdef HAVE_FFTW3
   } else {
-    spectrum->phas[spectrum->length - 1] = 0.;
+    i = spectrum->length - 1;
+    spectrum->phas[i] = ATAN2(compspec->data[compspec->length-i],
+        compspec->data[i]);
   }
+#endif
 }
 
 void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum) {
@@ -383,8 +540,19 @@
     spectrum->norm[i] = SQRT(SQR(compspec->data[i])
         + SQR(compspec->data[compspec->length - i]) );
   }
-  spectrum->norm[spectrum->length-1] =
-    ABS(compspec->data[compspec->length/2]);
+#ifdef HAVE_FFTW3
+  // for even length, make sure last element is > 0
+  if (2 * (compspec->length / 2) == compspec->length) {
+#endif
+    spectrum->norm[spectrum->length-1] =
+      ABS(compspec->data[compspec->length/2]);
+#ifdef HAVE_FFTW3
+  } else {
+    i = spectrum->length - 1;
+    spectrum->norm[i] = SQRT(SQR(compspec->data[i])
+        + SQR(compspec->data[compspec->length - i]) );
+  }
+#endif
 }
 
 void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec) {
--- a/src/spectral/filterbank.c
+++ b/src/spectral/filterbank.c
@@ -23,6 +23,7 @@
 #include "fvec.h"
 #include "fmat.h"
 #include "cvec.h"
+#include "vecutils.h"
 #include "spectral/filterbank.h"
 #include "mathutils.h"
 
@@ -32,6 +33,8 @@
   uint_t win_s;
   uint_t n_filters;
   fmat_t *filters;
+  smpl_t norm;
+  smpl_t power;
 };
 
 aubio_filterbank_t *
@@ -39,6 +42,15 @@
 {
   /* allocate space for filterbank object */
   aubio_filterbank_t *fb = AUBIO_NEW (aubio_filterbank_t);
+
+  if ((sint_t)n_filters <= 0) {
+    AUBIO_ERR("filterbank: n_filters should be > 0, got %d\n", n_filters);
+    goto fail;
+  }
+  if ((sint_t)win_s <= 0) {
+    AUBIO_ERR("filterbank: win_s should be > 0, got %d\n", win_s);
+    goto fail;
+  }
   fb->win_s = win_s;
   fb->n_filters = n_filters;
 
@@ -45,7 +57,14 @@
   /* allocate filter tables, a matrix of length win_s and of height n_filters */
   fb->filters = new_fmat (n_filters, win_s / 2 + 1);
 
+  fb->norm = 1;
+
+  fb->power = 1;
+
   return fb;
+fail:
+  AUBIO_FREE (fb);
+  return NULL;
 }
 
 void
@@ -67,6 +86,8 @@
   tmp.length = in->length;
   tmp.data = in->norm;
 
+  if (f->power != 1.) fvec_pow(&tmp, f->power);
+
   fmat_vecmul(f->filters, &tmp, out);
 
   return;
@@ -83,4 +104,31 @@
 {
   fmat_copy(filter_coeffs, f->filters);
   return 0;
+}
+
+uint_t
+aubio_filterbank_set_norm (aubio_filterbank_t *f, smpl_t norm)
+{
+  if (norm != 0 && norm != 1) return AUBIO_FAIL;
+  f->norm = norm;
+  return AUBIO_OK;
+}
+
+smpl_t
+aubio_filterbank_get_norm (aubio_filterbank_t *f)
+{
+  return f->norm;
+}
+
+uint_t
+aubio_filterbank_set_power (aubio_filterbank_t *f, smpl_t power)
+{
+  f->power = power;
+  return AUBIO_OK;
+}
+
+smpl_t
+aubio_filterbank_get_power (aubio_filterbank_t *f)
+{
+  return f->power;
 }
--- a/src/spectral/filterbank.h
+++ b/src/spectral/filterbank.h
@@ -83,6 +83,47 @@
  */
 uint_t aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filters);
 
+/** set norm parameter
+
+  \param f filterbank object, as returned by new_aubio_filterbank()
+  \param norm `1` to norm the filters, `0` otherwise.
+
+  If set to `0`, the filters will not be normalized. If set to `1`,
+  each filter will be normalized to one. Defaults to `1`.
+
+  This function should be called *before* setting the filters with one of
+  aubio_filterbank_set_triangle_bands(), aubio_filterbank_set_mel_coeffs(),
+  aubio_filterbank_set_mel_coeffs_htk(), or
+  aubio_filterbank_set_mel_coeffs_slaney().
+
+ */
+uint_t aubio_filterbank_set_norm (aubio_filterbank_t *f, smpl_t norm);
+
+/** get norm parameter
+
+  \param f filterbank object, as returned by new_aubio_filterbank()
+  \returns `1` if norm is set, `0` otherwise. Defaults to `1`.
+
+ */
+smpl_t aubio_filterbank_get_norm (aubio_filterbank_t *f);
+
+/** set power parameter
+
+  \param f filterbank object, as returned by new_aubio_filterbank()
+  \param power Raise norm of the input spectrum norm to this power before
+  computing filterbank.  Defaults to `1`.
+
+ */
+uint_t aubio_filterbank_set_power (aubio_filterbank_t *f, smpl_t power);
+
+/** get power parameter
+
+  \param f filterbank object, as returned by new_aubio_filterbank()
+  \return current power parameter. Defaults to `1`.
+
+ */
+smpl_t aubio_filterbank_get_power (aubio_filterbank_t *f);
+
 #ifdef __cplusplus
 }
 #endif
--- a/src/spectral/filterbank_mel.c
+++ b/src/spectral/filterbank_mel.c
@@ -54,9 +54,21 @@
         n_filters, freqs->length - 2);
   }
 
-  if (freqs->data[freqs->length - 1] > samplerate / 2) {
-    AUBIO_WRN ("Nyquist frequency is %fHz, but highest frequency band ends at \
-%fHz\n", samplerate / 2, freqs->data[freqs->length - 1]);
+  for (fn = 0; fn < freqs->length; fn++) {
+    if (freqs->data[fn] < 0) {
+      AUBIO_ERR("filterbank_mel: freqs must contain only positive values.\n");
+      return AUBIO_FAIL;
+    } else if (freqs->data[fn] > samplerate / 2) {
+      AUBIO_WRN("filterbank_mel: freqs should contain only "
+          "values < samplerate / 2.\n");
+    } else if (fn > 0 && freqs->data[fn] < freqs->data[fn-1]) {
+      AUBIO_ERR("filterbank_mel: freqs should be a list of frequencies "
+          "sorted from low to high, but freq[%d] < freq[%d-1]\n", fn, fn);
+      return AUBIO_FAIL;
+    } else if (fn > 0 && freqs->data[fn] == freqs->data[fn-1]) {
+      AUBIO_WRN("filterbank_mel: set_triangle_bands received a list "
+          "with twice the frequency %f\n", freqs->data[fn]);
+    }
   }
 
   /* convenience reference to lower/center/upper frequency for each triangle */
@@ -78,9 +90,13 @@
   }
 
   /* compute triangle heights so that each triangle has unit area */
-  for (fn = 0; fn < n_filters; fn++) {
-    triangle_heights->data[fn] =
-        2. / (upper_freqs->data[fn] - lower_freqs->data[fn]);
+  if (aubio_filterbank_get_norm(fb)) {
+    for (fn = 0; fn < n_filters; fn++) {
+      triangle_heights->data[fn] =
+          2. / (upper_freqs->data[fn] - lower_freqs->data[fn]);
+    }
+  } else {
+    fvec_ones (triangle_heights);
   }
 
   /* fill fft_freqs lookup table, which assigns the frequency in hz to each bin */
@@ -92,17 +108,6 @@
   /* zeroing of all filters */
   fmat_zeros (filters);
 
-  if (fft_freqs->data[1] >= lower_freqs->data[0]) {
-    /* - 1 to make sure we don't miss the smallest power of two */
-    uint_t min_win_s =
-        (uint_t) FLOOR (samplerate / lower_freqs->data[0]) - 1;
-    AUBIO_WRN ("Lowest frequency bin (%.2fHz) is higher than lowest frequency \
-band (%.2f-%.2fHz). Consider increasing the window size from %d to %d.\n",
-        fft_freqs->data[1], lower_freqs->data[0],
-        upper_freqs->data[0], (win_s - 1) * 2,
-        aubio_next_power_of_two (min_win_s));
-  }
-
   /* building each filter table */
   for (fn = 0; fn < n_filters; fn++) {
 
@@ -116,9 +121,8 @@
     }
 
     /* compute positive slope step size */
-    riseInc =
-        triangle_heights->data[fn] /
-        (center_freqs->data[fn] - lower_freqs->data[fn]);
+    riseInc = triangle_heights->data[fn]
+      / (center_freqs->data[fn] - lower_freqs->data[fn]);
 
     /* compute coefficients in positive slope */
     for (; bin < win_s - 1; bin++) {
@@ -132,9 +136,8 @@
     }
 
     /* compute negative slope step size */
-    downInc =
-        triangle_heights->data[fn] /
-        (upper_freqs->data[fn] - center_freqs->data[fn]);
+    downInc = triangle_heights->data[fn]
+      / (upper_freqs->data[fn] - center_freqs->data[fn]);
 
     /* compute coefficents in negative slope */
     for (; bin < win_s - 1; bin++) {
@@ -160,7 +163,7 @@
   del_fvec (triangle_heights);
   del_fvec (fft_freqs);
 
-  return 0;
+  return AUBIO_OK;
 }
 
 uint_t
@@ -167,24 +170,28 @@
 aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
     smpl_t samplerate)
 {
-  uint_t retval;
-
   /* Malcolm Slaney parameters */
-  smpl_t lowestFrequency = 133.3333;
-  smpl_t linearSpacing = 66.66666666;
-  smpl_t logSpacing = 1.0711703;
+  const smpl_t lowestFrequency = 133.3333;
+  const smpl_t linearSpacing = 66.66666666;
+  const smpl_t logSpacing = 1.0711703;
 
-  uint_t linearFilters = 13;
-  uint_t logFilters = 27;
-  uint_t n_filters = linearFilters + logFilters;
+  const uint_t linearFilters = 13;
+  const uint_t logFilters = 27;
+  const uint_t n_filters = linearFilters + logFilters;
 
-  uint_t fn;                    /* filter counter */
-
+  uint_t fn, retval;
   smpl_t lastlinearCF;
 
   /* buffers to compute filter frequencies */
-  fvec_t *freqs = new_fvec (n_filters + 2);
+  fvec_t *freqs;
 
+  if (samplerate <= 0) {
+    AUBIO_ERR("filterbank: set_mel_coeffs_slaney samplerate should be > 0\n");
+    return AUBIO_FAIL;
+  }
+
+  freqs = new_fvec (n_filters + 2);
+
   /* first step: fill all the linear filter frequencies */
   for (fn = 0; fn < linearFilters; fn++) {
     freqs->data[fn] = lowestFrequency + fn * linearSpacing;
@@ -203,5 +210,89 @@
   /* destroy vector used to store frequency limits */
   del_fvec (freqs);
 
+  return retval;
+}
+
+static uint_t aubio_filterbank_check_freqs (aubio_filterbank_t *fb UNUSED,
+    smpl_t samplerate, smpl_t *freq_min, smpl_t *freq_max)
+{
+  if (samplerate <= 0) {
+    AUBIO_ERR("filterbank: set_mel_coeffs samplerate should be > 0\n");
+    return AUBIO_FAIL;
+  }
+  if (*freq_max < 0) {
+    AUBIO_ERR("filterbank: set_mel_coeffs freq_max should be > 0\n");
+    return AUBIO_FAIL;
+  } else if (*freq_max == 0) {
+    *freq_max = samplerate / 2.;
+  }
+  if (*freq_min < 0) {
+    AUBIO_ERR("filterbank: set_mel_coeffs freq_min should be > 0\n");
+    return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs (aubio_filterbank_t * fb, smpl_t samplerate,
+    smpl_t freq_min, smpl_t freq_max)
+{
+  uint_t m, retval;
+  smpl_t start = freq_min, end = freq_max, step;
+  fvec_t *freqs;
+  fmat_t *coeffs = aubio_filterbank_get_coeffs(fb);
+  uint_t n_bands = coeffs->height;
+
+  if (aubio_filterbank_check_freqs(fb, samplerate, &start, &end)) {
+    return AUBIO_FAIL;
+  }
+
+  start = aubio_hztomel(start);
+  end = aubio_hztomel(end);
+
+  freqs = new_fvec(n_bands + 2);
+  step = (end - start) / (n_bands + 1);
+
+  for (m = 0; m < n_bands + 2; m++)
+  {
+    freqs->data[m] = MIN(aubio_meltohz(start + step * m), samplerate/2.);
+  }
+
+  retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+  /* destroy vector used to store frequency limits */
+  del_fvec (freqs);
+  return retval;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs_htk (aubio_filterbank_t * fb, smpl_t samplerate,
+    smpl_t freq_min, smpl_t freq_max)
+{
+  uint_t m, retval;
+  smpl_t start = freq_min, end = freq_max, step;
+  fvec_t *freqs;
+  fmat_t *coeffs = aubio_filterbank_get_coeffs(fb);
+  uint_t n_bands = coeffs->height;
+
+  if (aubio_filterbank_check_freqs(fb, samplerate, &start, &end)) {
+    return AUBIO_FAIL;
+  }
+
+  start = aubio_hztomel_htk(start);
+  end = aubio_hztomel_htk(end);
+
+  freqs = new_fvec (n_bands + 2);
+  step = (end - start) / (n_bands + 1);
+
+  for (m = 0; m < n_bands + 2; m++)
+  {
+    freqs->data[m] = MIN(aubio_meltohz_htk(start + step * m), samplerate/2.);
+  }
+
+  retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+  /* destroy vector used to store frequency limits */
+  del_fvec (freqs);
   return retval;
 }
--- a/src/spectral/filterbank_mel.h
+++ b/src/spectral/filterbank_mel.h
@@ -55,15 +55,62 @@
 /** filterbank initialization for Mel filters using Slaney's coefficients
 
   \param fb filterbank object
-  \param samplerate audio sampling rate
+  \param samplerate audio sampling rate, in Hz
 
-  The filter coefficients are built according to Malcolm Slaney's Auditory
-  Toolbox, available at http://engineering.purdue.edu/~malcolm/interval/1998-010/
-  (see file mfcc.m).
+  The filter coefficients are built to match exactly Malcolm Slaney's Auditory
+  Toolbox implementation (see file mfcc.m). The number of filters should be 40.
 
+  References
+  ----------
+
+  Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+  https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
 */
 uint_t aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
     smpl_t samplerate);
+
+/** Mel filterbank initialization
+
+  \param fb filterbank object
+  \param samplerate audio sampling rate
+  \param fmin start frequency, in Hz
+  \param fmax end frequency, in Hz
+
+  The filterbank will be initialized with bands linearly spaced in the mel
+  scale, from `fmin` to `fmax`.
+
+  References
+  ----------
+
+  Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+  https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs(aubio_filterbank_t * fb,
+    smpl_t samplerate, smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization
+
+  \param fb filterbank object
+  \param samplerate audio sampling rate
+  \param fmin start frequency, in Hz
+  \param fmax end frequency, in Hz
+
+  The bank of filters will be initalized to to cover linearly spaced bands in
+  the Htk mel scale, from `fmin` to `fmax`.
+
+  References
+  ----------
+
+  Douglas O'Shaughnessy (1987). *Speech communication: human and machine*.
+  Addison-Wesley. p. 150. ISBN 978-0-201-16520-3.
+
+  HTK Speech Recognition Toolkit: http://htk.eng.cam.ac.uk/
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs_htk(aubio_filterbank_t * fb,
+    smpl_t samplerate, smpl_t fmin, smpl_t fmax);
 
 #ifdef __cplusplus
 }
--- a/src/spectral/mfcc.c
+++ b/src/spectral/mfcc.c
@@ -28,6 +28,7 @@
 #include "spectral/fft.h"
 #include "spectral/filterbank.h"
 #include "spectral/filterbank_mel.h"
+#include "spectral/dct.h"
 #include "spectral/mfcc.h"
 
 /** Internal structure for mfcc object */
@@ -36,11 +37,13 @@
 {
   uint_t win_s;             /** grain length */
   uint_t samplerate;        /** sample rate (needed?) */
-  uint_t n_filters;         /** number of  *filters */
+  uint_t n_filters;         /** number of filters */
   uint_t n_coefs;           /** number of coefficients (<= n_filters/2 +1) */
   aubio_filterbank_t *fb;   /** filter bank */
   fvec_t *in_dct;           /** input buffer for dct * [fb->n_filters] */
-  fmat_t *dct_coeffs;       /** DCT transform n_filters * n_coeffs */
+  aubio_dct_t *dct;         /** dct object */
+  fvec_t *output;           /** dct output */
+  smpl_t scale;
 };
 
 
@@ -51,9 +54,15 @@
 
   /* allocate space for mfcc object */
   aubio_mfcc_t *mfcc = AUBIO_NEW (aubio_mfcc_t);
-  smpl_t scaling;
 
-  uint_t i, j;
+  if ((sint_t)n_coefs <= 0) {
+    AUBIO_ERR("mfcc: n_coefs should be > 0, got %d\n", n_coefs);
+    goto failure;
+  }
+  if ((sint_t)samplerate <= 0) {
+    AUBIO_ERR("mfcc: samplerate should be > 0, got %d\n", samplerate);
+    goto failure;
+  }
 
   mfcc->win_s = win_s;
   mfcc->samplerate = samplerate;
@@ -62,39 +71,45 @@
 
   /* filterbank allocation */
   mfcc->fb = new_aubio_filterbank (n_filters, mfcc->win_s);
-  aubio_filterbank_set_mel_coeffs_slaney (mfcc->fb, samplerate);
 
+  if (!mfcc->fb)
+    goto failure;
+
+  if (n_filters == 40)
+    aubio_filterbank_set_mel_coeffs_slaney (mfcc->fb, samplerate);
+  else
+    aubio_filterbank_set_mel_coeffs(mfcc->fb, samplerate,
+        0, samplerate/2.);
+
   /* allocating buffers */
   mfcc->in_dct = new_fvec (n_filters);
 
-  mfcc->dct_coeffs = new_fmat (n_coefs, n_filters);
+  mfcc->dct = new_aubio_dct (n_filters);
+  mfcc->output = new_fvec (n_filters);
 
-  /* 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[j][i] =
-          scaling * COS (j * (i + 0.5) * PI / n_filters);
-    }
-    mfcc->dct_coeffs->data[0][i] *= SQRT (2.) / 2.;
-  }
+  if (!mfcc->in_dct || !mfcc->dct || !mfcc->output)
+    goto failure;
 
+  mfcc->scale = 1.;
+
   return mfcc;
+
+failure:
+  del_aubio_mfcc(mfcc);
+  return NULL;
 }
 
 void
 del_aubio_mfcc (aubio_mfcc_t * mf)
 {
-
-  /* delete filterbank */
-  del_aubio_filterbank (mf->fb);
-
-  /* delete buffers */
-  del_fvec (mf->in_dct);
-  del_fmat (mf->dct_coeffs);
-
-  /* delete mfcc object */
+  if (mf->fb)
+    del_aubio_filterbank (mf->fb);
+  if (mf->in_dct)
+    del_fvec (mf->in_dct);
+  if (mf->dct)
+    del_aubio_dct (mf->dct);
+  if (mf->output)
+    del_fvec (mf->output);
   AUBIO_FREE (mf);
 }
 
@@ -102,6 +117,8 @@
 void
 aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out)
 {
+  fvec_t tmp;
+
   /* compute filterbank */
   aubio_filterbank_do (mf->fb, in, mf->in_dct);
 
@@ -108,11 +125,55 @@
   /* compute log10 */
   fvec_log10 (mf->in_dct);
 
-  /* raise power */
-  //fvec_pow (mf->in_dct, 3.);
+  if (mf->scale != 1) fvec_mul (mf->in_dct, mf->scale);
 
   /* compute mfccs */
-  fmat_vecmul(mf->dct_coeffs, mf->in_dct, out);
+  aubio_dct_do(mf->dct, mf->in_dct, mf->output);
+  // copy only first n_coeffs elements
+  // TODO assert mf->output->length == n_coeffs
+  tmp.data = mf->output->data;
+  tmp.length = out->length;
+  fvec_copy(&tmp, out);
 
   return;
+}
+
+uint_t aubio_mfcc_set_power (aubio_mfcc_t *mf, smpl_t power)
+{
+  return aubio_filterbank_set_power(mf->fb, power);
+}
+
+smpl_t aubio_mfcc_get_power (aubio_mfcc_t *mf)
+{
+  return aubio_filterbank_get_power(mf->fb);
+}
+
+uint_t aubio_mfcc_set_scale (aubio_mfcc_t *mf, smpl_t scale)
+{
+  mf->scale = scale;
+  return AUBIO_OK;
+}
+
+smpl_t aubio_mfcc_get_scale (aubio_mfcc_t *mf)
+{
+  return mf->scale;
+}
+
+uint_t aubio_mfcc_set_mel_coeffs (aubio_mfcc_t *mf, smpl_t freq_min,
+    smpl_t freq_max)
+{
+  return aubio_filterbank_set_mel_coeffs(mf->fb, mf->samplerate,
+      freq_min, freq_max);
+}
+
+uint_t aubio_mfcc_set_mel_coeffs_htk (aubio_mfcc_t *mf, smpl_t freq_min,
+    smpl_t freq_max)
+{
+  return aubio_filterbank_set_mel_coeffs_htk(mf->fb, mf->samplerate,
+      freq_min, freq_max);
+}
+
+uint_t aubio_mfcc_set_mel_coeffs_slaney (aubio_mfcc_t *mf)
+{
+  return aubio_filterbank_set_mel_coeffs_slaney (mf->fb, mf->samplerate);
 }
--- a/src/spectral/mfcc.h
+++ b/src/spectral/mfcc.h
@@ -26,9 +26,10 @@
   This object computes MFCC coefficients on an input cvec_t.
 
   The implementation follows the specifications established by Malcolm Slaney
-  in its Auditory Toolbox, available online (see file mfcc.m).
+  in its Auditory Toolbox, available online at the following address (see
+  file mfcc.m):
 
-  http://engineering.ecn.purdue.edu/~malcolm/interval/1998-010/
+  https://engineering.purdue.edu/~malcolm/interval/1998-010/
 
   \example spectral/test-mfcc.c
 
@@ -71,6 +72,99 @@
 
 */
 void aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out);
+
+/** set power parameter
+
+  \param mf mfcc object, as returned by new_aubio_mfcc()
+  \param power Raise norm of the input spectrum norm to this power before
+  computing filterbank.  Defaults to `1`.
+
+  See aubio_filterbank_set_power().
+
+ */
+uint_t aubio_mfcc_set_power (aubio_mfcc_t *mf, smpl_t power);
+
+/** get power parameter
+
+  \param mf mfcc object, as returned by new_aubio_mfcc()
+  \return current power parameter. Defaults to `1`.
+
+  See aubio_filterbank_get_power().
+
+ */
+smpl_t aubio_mfcc_get_power (aubio_mfcc_t *mf);
+
+/** set scaling parameter
+
+  \param mf mfcc object, as returned by new_aubio_mfcc()
+  \param scale Scaling value to apply.
+
+  Scales the output of the filterbank after taking its logarithm and before
+  computing the DCT. Defaults to `1`.
+
+*/
+uint_t aubio_mfcc_set_scale (aubio_mfcc_t *mf, smpl_t scale);
+
+/** get scaling parameter
+
+  \param mf mfcc object, as returned by new_aubio_mfcc()
+  \return current scaling parameter. Defaults to `1`.
+
+ */
+smpl_t aubio_mfcc_get_scale (aubio_mfcc_t *mf);
+
+/** Mel filterbank initialization
+
+  \param mf mfcc object
+  \param fmin start frequency, in Hz
+  \param fmax end frequency, in Hz
+
+  The filterbank will be initialized with bands linearly spaced in the mel
+  scale, from `fmin` to `fmax`.
+
+  See also
+  --------
+
+  aubio_filterbank_set_mel_coeffs()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs (aubio_mfcc_t *mf,
+        smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization
+
+  \param mf mfcc object
+  \param fmin start frequency, in Hz
+  \param fmax end frequency, in Hz
+
+  The bank of filters will be initalized to to cover linearly spaced bands in
+  the Htk mel scale, from `fmin` to `fmax`.
+
+  See also
+  --------
+
+  aubio_filterbank_set_mel_coeffs_htk()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs_htk (aubio_mfcc_t *mf,
+        smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization (Auditory Toolbox's parameters)
+
+  \param mf mfcc object
+
+  The filter coefficients are built to match exactly Malcolm Slaney's Auditory
+  Toolbox implementation. The number of filters should be 40.
+
+  This is the default filterbank when `mf` was created with `n_filters = 40`.
+
+  See also
+  --------
+
+  aubio_filterbank_set_mel_coeffs_slaney()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs_slaney (aubio_mfcc_t *mf);
 
 #ifdef __cplusplus
 }
--- a/src/spectral/ooura_fft8g.c
+++ b/src/spectral/ooura_fft8g.c
@@ -2,7 +2,8 @@
 //  - replace all 'double' with 'smpl_t'
 //  - include "aubio_priv.h" (for config.h and types.h)
 //  - add missing prototypes
-//  - use COS and SIN macros
+//  - use COS, SIN, and ATAN macros
+//  - add cast to (smpl_t) to avoid float conversion warnings
 //  - declare initialization as static
 //  - prefix public function with aubio_ooura_
 
@@ -363,7 +364,7 @@
         a[0] += a[1];
         a[1] = xi;
     } else {
-        a[1] = 0.5 * (a[0] - a[1]);
+        a[1] = (smpl_t)0.5 * (a[0] - a[1]);
         a[0] -= a[1];
         if (n > 4) {
             rftbsub(n, a, nc, w + nw);
@@ -692,7 +693,7 @@
     ip[1] = 1;
     if (nw > 2) {
         nwh = nw >> 1;
-        delta = atan(1.0) / nwh;
+        delta = ATAN(1.0) / nwh;
         w[0] = 1;
         w[1] = 0;
         w[nwh] = COS(delta * nwh);
@@ -726,12 +727,12 @@
     ip[1] = nc;
     if (nc > 1) {
         nch = nc >> 1;
-        delta = atan(1.0) / nch;
-        c[0] = cos(delta * nch);
-        c[nch] = 0.5 * c[0];
+        delta = ATAN(1.0) / nch;
+        c[0] = COS(delta * nch);
+        c[nch] = (smpl_t)0.5 * c[0];
         for (j = 1; j < nch; j++) {
-            c[j] = 0.5 * cos(delta * j);
-            c[nc - j] = 0.5 * sin(delta * j);
+            c[j] = (smpl_t)0.5 * COS(delta * j);
+            c[nc - j] = (smpl_t)0.5 * SIN(delta * j);
         }
     }
 }
@@ -1587,7 +1588,7 @@
     for (j = 2; j < m; j += 2) {
         k = n - j;
         kk += ks;
-        wkr = 0.5 - c[nc - kk];
+        wkr = (smpl_t)0.5 - c[nc - kk];
         wki = c[kk];
         xr = a[j] - a[k];
         xi = a[j + 1] + a[k + 1];
@@ -1613,7 +1614,7 @@
     for (j = 2; j < m; j += 2) {
         k = n - j;
         kk += ks;
-        wkr = 0.5 - c[nc - kk];
+        wkr = (smpl_t)0.5 - c[nc - kk];
         wki = c[kk];
         xr = a[j] - a[k];
         xi = a[j + 1] + a[k + 1];
--- a/src/spectral/phasevoc.c
+++ b/src/spectral/phasevoc.c
@@ -88,7 +88,7 @@
     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);
+    AUBIO_ERR("pvoc: hop size (%d) is larger than win size (%d)\n", hop_s, win_s);
     goto beach;
   }
 
@@ -143,6 +143,10 @@
   return NULL;
 }
 
+uint_t aubio_pvoc_set_window(aubio_pvoc_t *pv, const char_t *window) {
+  return fvec_set_window(pv->w, (char_t*)window);
+}
+
 void del_aubio_pvoc(aubio_pvoc_t *pv) {
   del_fvec(pv->data);
   del_fvec(pv->synth);
@@ -207,4 +211,14 @@
   /* additive synth */
   for (i = 0; i < pv->end; i++)
     synthold[i] += synth[i + pv->hop_s] * pv->scale;
+}
+
+uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv)
+{
+  return pv->win_s;
+}
+
+uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv)
+{
+  return pv->hop_s;
 }
--- a/src/spectral/phasevoc.h
+++ b/src/spectral/phasevoc.h
@@ -88,6 +88,7 @@
 
 */
 uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv);
+
 /** get hop size
 
   \param pv phase vocoder to get the hop size from
@@ -94,6 +95,16 @@
 
 */
 uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv);
+
+/** set window type
+
+  \param pv phase vocoder to set the window type
+  \param window_type a string representing a window
+
+  \return 0 if successful, non-zero otherwise
+
+ */
+uint_t aubio_pvoc_set_window(aubio_pvoc_t *pv, const char_t *window_type);
 
 #ifdef __cplusplus
 }
--- a/src/spectral/specdesc.c
+++ b/src/spectral/specdesc.c
@@ -30,6 +30,7 @@
 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_wphase(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);
@@ -57,6 +58,7 @@
         aubio_onset_hfc,            /**< high frequency content */
         aubio_onset_complex,        /**< complex domain */        
         aubio_onset_phase,          /**< phase fast */            
+        aubio_onset_wphase,         /**< weighted phase */
         aubio_onset_kl,             /**< Kullback Liebler */
         aubio_onset_mkl,            /**< modified Kullback Liebler */
         aubio_onset_specflux,       /**< spectral flux */
@@ -159,6 +161,23 @@
   //onset->data[0] = fvec_mean(o->dev1);
 }
 
+/* weighted phase */
+void
+aubio_specdesc_wphase(aubio_specdesc_t *o,
+    const cvec_t *fftgrain, fvec_t *onset) {
+  uint_t i;
+  aubio_specdesc_phase(o, fftgrain, onset);
+  for (i = 0; i < fftgrain->length; i++) {
+    o->dev1->data[i] *= fftgrain->norm[i];
+  }
+  /* apply o->histogram */
+  aubio_hist_dyn_notnull(o->histog,o->dev1);
+  /* weight it */
+  aubio_hist_weight(o->histog);
+  /* its mean is the result */
+  onset->data[0] = aubio_hist_mean(o->histog);
+}
+
 /* Spectral difference method onset detection function */
 void aubio_specdesc_specdiff(aubio_specdesc_t *o,
     const cvec_t * fftgrain, fvec_t * onset){
@@ -250,6 +269,8 @@
       onset_type = aubio_onset_complex;
   else if (strcmp (onset_mode, "phase") == 0)
       onset_type = aubio_onset_phase;
+  else if (strcmp (onset_mode, "wphase") == 0)
+      onset_type = aubio_onset_wphase;
   else if (strcmp (onset_mode, "mkl") == 0)
       onset_type = aubio_onset_mkl;
   else if (strcmp (onset_mode, "kl") == 0)
@@ -270,10 +291,13 @@
       onset_type = aubio_specmethod_decrease;
   else if (strcmp (onset_mode, "rolloff") == 0)
       onset_type = aubio_specmethod_rolloff;
+  else if (strcmp (onset_mode, "old_default") == 0)
+      onset_type = aubio_onset_default;
   else if (strcmp (onset_mode, "default") == 0)
       onset_type = aubio_onset_default;
   else {
-      AUBIO_ERR("unknown spectral descriptor type %s\n", onset_mode);
+      AUBIO_ERR("specdesc: unknown spectral descriptor type '%s'\n",
+          onset_mode);
       AUBIO_FREE(o);
       return NULL;
   }
@@ -291,6 +315,7 @@
       o->theta2 = new_fvec(rsize);
       break;
     case aubio_onset_phase:
+    case aubio_onset_wphase:
       o->dev1   = new_fvec(rsize);
       o->theta1 = new_fvec(rsize);
       o->theta2 = new_fvec(rsize);
@@ -325,6 +350,9 @@
     case aubio_onset_phase:
       o->funcpointer = aubio_specdesc_phase;
       break;
+    case aubio_onset_wphase:
+      o->funcpointer = aubio_specdesc_wphase;
+      break;
     case aubio_onset_specdiff:
       o->funcpointer = aubio_specdesc_specdiff;
       break;
@@ -378,6 +406,7 @@
       del_fvec(o->theta2);
       break;
     case aubio_onset_phase:
+    case aubio_onset_wphase:
       del_fvec(o->dev1);
       del_fvec(o->theta1);
       del_fvec(o->theta2);
--- a/src/spectral/specdesc.h
+++ b/src/spectral/specdesc.h
@@ -59,6 +59,13 @@
   Conference on Acoustics Speech and Signal Processing, pages 441­444,
   Hong-Kong, 2003.
 
+  \b \p wphase : Weighted Phase Deviation onset detection function
+
+  S. Dixon. Onset detection revisited. In Proceedings of the 9th International
+  Conference on Digital Audio Ef- fects (DAFx) , pages 133–137, 2006.
+
+  http://www.eecs.qmul.ac.uk/~simond/pub/2006/dafx.pdf
+
   \b \p specdiff : Spectral difference method onset detection function
 
   Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
@@ -174,8 +181,11 @@
 
   The parameter \p method is a string that can be any of:
 
-    - `energy`, `hfc`, `complex`, `phase`, `specdiff`, `kl`, `mkl`, `specflux`
-    - `centroid`, `spread`, `skewness`, `kurtosis`, `slope`, `decrease`, `rolloff`
+    - onset novelty functions: `complex`, `energy`, `hfc`, `kl`, `mkl`,
+    `phase`, `specdiff`, `specflux`, `wphase`,
+
+    - spectral descriptors: `centroid`, `decrease`, `kurtosis`, `rolloff`,
+    `skewness`, `slope`, `spread`.
 
 */
 aubio_specdesc_t *new_aubio_specdesc (const char_t * method, uint_t buf_size);
--- a/src/synth/sampler.c
+++ b/src/synth/sampler.c
@@ -19,7 +19,6 @@
 */
 
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
--- a/src/synth/wavetable.c
+++ b/src/synth/wavetable.c
@@ -19,7 +19,6 @@
 */
 
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "fmat.h"
@@ -104,6 +103,7 @@
     for (i = 0; i < output->length; i++) {
       output->data[i] += input->data[i];
     }
+    fvec_clamp(output, 1.);
   }
 }
 
@@ -164,7 +164,14 @@
   //aubio_wavetable_set_freq (s, 0.);
   aubio_wavetable_set_amp (s, 0.);
   //s->last_pos = 0;
-  return aubio_wavetable_set_playing (s, 1);
+  return aubio_wavetable_set_playing (s, 0);
+}
+
+uint_t
+aubio_wavetable_load ( aubio_wavetable_t *s UNUSED, const char_t *uri UNUSED)
+{
+  AUBIO_ERR("wavetable: load method not implemented yet, see sampler\n");
+  return AUBIO_FAIL;
 }
 
 uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
--- a/src/synth/wavetable.h
+++ b/src/synth/wavetable.h
@@ -53,6 +53,8 @@
 
 /** load source in wavetable
 
+  TODO: This function is not implemented yet. See new_aubio_sampler() instead.
+
   \param o wavetable, created by new_aubio_wavetable()
   \param uri the uri of the source to load
 
--- a/src/tempo/beattracking.h
+++ b/src/tempo/beattracking.h
@@ -31,7 +31,7 @@
 
   Matthew E. P. Davies, Paul Brossier, and Mark D. Plumbley. Beat tracking
   towards automatic musical accompaniment. In Proceedings of the Audio
-  Engeeniring Society 118th Convention, Barcelona, Spain, May 2005.
+  Engineering Society 118th Convention, Barcelona, Spain, May 2005.
 
   \example tempo/test-beattracking.c
 
--- a/src/tempo/tempo.c
+++ b/src/tempo/tempo.c
@@ -128,8 +128,7 @@
 }
 
 uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay) {
-  o->delay = 1000. * delay * o->samplerate;
-  return AUBIO_OK;
+  return aubio_tempo_set_delay_s(o, delay / 1000.);
 }
 
 uint_t aubio_tempo_get_delay(aubio_tempo_t * o) {
@@ -141,7 +140,7 @@
 }
 
 smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o) {
-  return o->delay / (smpl_t)(o->samplerate) / 1000.;
+  return aubio_tempo_get_delay_s(o) * 1000.;
 }
 
 uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence) {
@@ -168,7 +167,7 @@
     uint_t buf_size, uint_t hop_size, uint_t samplerate)
 {
   aubio_tempo_t * o = AUBIO_NEW(aubio_tempo_t);
-  char_t specdesc_func[20];
+  char_t specdesc_func[PATH_MAX];
   o->samplerate = samplerate;
   // check parameters are valid
   if ((sint_t)hop_size < 1) {
@@ -203,9 +202,10 @@
   o->pp       = new_aubio_peakpicker();
   aubio_peakpicker_set_threshold (o->pp, o->threshold);
   if ( strcmp(tempo_mode, "default") == 0 ) {
-    strcpy(specdesc_func, "specflux");
+    strncpy(specdesc_func, "specflux", PATH_MAX - 1);
   } else {
-    strcpy(specdesc_func, tempo_mode);
+    strncpy(specdesc_func, tempo_mode, PATH_MAX - 1);
+    specdesc_func[PATH_MAX - 1] = '\0';
   }
   o->od       = new_aubio_specdesc(specdesc_func,buf_size);
   o->of       = new_fvec(1);
@@ -215,12 +215,17 @@
     o2 = new_aubio_specdesc(type_onset2,buffer_size);
     onset2 = new_fvec(1);
   }*/
+  if (!o->dfframe || !o->fftgrain || !o->out || !o->pv ||
+      !o->pp || !o->od || !o->of || !o->bt || !o->onset) {
+    AUBIO_ERR("tempo: failed creating tempo object\n");
+    goto beach;
+  }
   o->last_tatum = 0;
   o->tatum_signature = 4;
   return o;
 
 beach:
-  AUBIO_FREE(o);
+  del_aubio_tempo(o);
   return NULL;
 }
 
@@ -277,15 +282,23 @@
 
 void del_aubio_tempo (aubio_tempo_t *o)
 {
-  del_aubio_specdesc(o->od);
-  del_aubio_beattracking(o->bt);
-  del_aubio_peakpicker(o->pp);
-  del_aubio_pvoc(o->pv);
-  del_fvec(o->out);
-  del_fvec(o->of);
-  del_cvec(o->fftgrain);
-  del_fvec(o->dfframe);
-  del_fvec(o->onset);
+  if (o->od)
+    del_aubio_specdesc(o->od);
+  if (o->bt)
+    del_aubio_beattracking(o->bt);
+  if (o->pp)
+    del_aubio_peakpicker(o->pp);
+  if (o->pv)
+    del_aubio_pvoc(o->pv);
+  if (o->out)
+    del_fvec(o->out);
+  if (o->of)
+    del_fvec(o->of);
+  if (o->fftgrain)
+    del_cvec(o->fftgrain);
+  if (o->dfframe)
+    del_fvec(o->dfframe);
+  if (o->onset)
+    del_fvec(o->onset);
   AUBIO_FREE(o);
-  return;
 }
--- a/src/tempo/tempo.h
+++ b/src/tempo/tempo.h
@@ -154,8 +154,8 @@
 
   \param o beat tracking object
 
-  \return confidence with which the tempo has been observed, `0` if no
-  consistent value is found.
+  \return confidence with which the tempo has been observed, the higher the
+  more confidence, `0` if no consistent value is found.
 
 */
 smpl_t aubio_tempo_get_confidence(aubio_tempo_t * o);
--- a/src/temporal/biquad.c
+++ b/src/temporal/biquad.c
@@ -41,7 +41,7 @@
   bs->data[2] = b2;
   as->data[0] = 1.;
   as->data[1] = a1;
-  as->data[1] = a2;
+  as->data[2] = a2;
   return AUBIO_OK;
 }
 
--- a/src/temporal/resampler.c
+++ b/src/temporal/resampler.c
@@ -18,13 +18,15 @@
 
 */
 
-#include "config.h"
-
 #include "aubio_priv.h"
 #include "fvec.h"
 #include "temporal/resampler.h"
 
 #ifdef HAVE_SAMPLERATE
+
+#if HAVE_AUBIO_DOUBLE
+#error "Should not use libsamplerate with aubio in double precision"
+#endif
 
 #include <samplerate.h>         /* from libsamplerate */
 
--- a/src/utils/hist.c
+++ b/src/utils/hist.c
@@ -43,6 +43,9 @@
   smpl_t step = (fhig-flow)/(smpl_t)(nelems);
   smpl_t accum = step;
   uint_t i;
+  if ((sint_t)nelems <= 0) {
+    return NULL;
+  }
   s->nelems = nelems;
   s->hist = new_fvec(nelems);
   s->cent = new_fvec(nelems);
--- a/src/utils/log.c
+++ b/src/utils/log.c
@@ -18,7 +18,6 @@
 
 */
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "log.h"
 
@@ -35,7 +34,7 @@
 {
   FILE *out;
   out = stdout;
-  if (level == AUBIO_LOG_DBG || level == AUBIO_LOG_ERR) {
+  if (level == AUBIO_LOG_ERR || level == AUBIO_LOG_DBG || level == AUBIO_LOG_WRN) {
     out = stderr;
   }
   fprintf(out, "%s", message);
--- a/src/utils/log.h
+++ b/src/utils/log.h
@@ -45,9 +45,10 @@
 /** list of logging levels */
 enum aubio_log_level {
   AUBIO_LOG_ERR, /**< critical errors */
-  AUBIO_LOG_WRN, /**< warnings */
+  AUBIO_LOG_INF, /**< infos */
   AUBIO_LOG_MSG, /**< general messages */
   AUBIO_LOG_DBG, /**< debug messages */
+  AUBIO_LOG_WRN, /**< warnings */
   AUBIO_LOG_LAST_LEVEL, /**< number of valid levels */
 };
 
--- a/src/utils/parameter.c
+++ b/src/utils/parameter.c
@@ -18,7 +18,6 @@
 
 */
 
-#include "config.h"
 #include "aubio_priv.h"
 #include "parameter.h"
 
--- a/src/utils/windll.c
+++ b/src/utils/windll.c
@@ -24,7 +24,7 @@
 
 */
 
-#include "config.h"
+#include "aubio_priv.h"
 
 #ifdef HAVE_WIN_HACKS
 
@@ -41,9 +41,9 @@
 
 #include "aubio.h"
 
-BOOL APIENTRY DllMain( HMODULE hModule,
+BOOL APIENTRY DllMain( HMODULE hModule UNUSED,
                        DWORD  ul_reason_for_call,
-                       LPVOID lpReserved )
+                       LPVOID lpReserved UNUSED)
 {
   switch (ul_reason_for_call)
   {
--- a/src/vecutils.c
+++ b/src/vecutils.c
@@ -1,4 +1,3 @@
-#include "config.h"
 #include "aubio_priv.h"
 #include "types.h"
 #include "fvec.h"
--- a/src/wscript_build
+++ b/src/wscript_build
@@ -3,11 +3,13 @@
 uselib = []
 uselib += ['M']
 uselib += ['FFTW3', 'FFTW3F']
+uselib += ['INTEL_IPP']
 uselib += ['SAMPLERATE']
 uselib += ['SNDFILE']
 uselib += ['RUBBERBAND']
 uselib += ['AVCODEC']
 uselib += ['AVFORMAT']
+uselib += ['SWRESAMPLE']
 uselib += ['AVRESAMPLE']
 uselib += ['AVUTIL']
 uselib += ['BLAS']
@@ -24,19 +26,28 @@
 if ctx.env['DEST_OS'] in ['ios', 'iosimulator']:
     build_features = ['cstlib', 'cshlib']
 elif ctx.env['DEST_OS'] in ['win32', 'win64']:
-    build_features = ['cstlib', 'cshlib']
+    build_features = ['cstlib', 'cshlib gensyms']
 elif ctx.env['DEST_OS'] in ['emscripten']:
+    build_features = ['cstlib','cshlib']
+elif '--static' in ctx.env['LDFLAGS'] or '--static' in ctx.env['LINKFLAGS']:
+    # static in cflags, ...
     build_features = ['cstlib']
-else: #linux, darwin, android, mingw, ...
+else:
+    # linux, darwin, android, mingw, ...
     build_features = ['cstlib', 'cshlib']
 
+# also install static lib
+from waflib.Tools.c import cstlib
+cstlib.inst_to = '${LIBDIR}'
+
 for target in build_features:
     ctx(features = 'c ' + target,
             use = uselib + ['lib_objects'],
             target = 'aubio',
+            export_symbols_regex=r'(?:.*aubio|fvec|lvec|cvec|fmat|new|del)_.*',
             vnum = ctx.env['LIB_VERSION'])
 
 # install headers, except _priv.h ones
-ctx.install_files('${PREFIX}/include/aubio/',
+ctx.install_files('${INCLUDEDIR}/aubio/',
         ctx.path.ant_glob('**/*.h', excl = ['**_priv.h', 'config.h']),
         relative_trick=True)
--- /dev/null
+++ b/tests/create_tests_source.py
@@ -1,0 +1,42 @@
+#! /usr/bin/env python
+
+""" Create a simple stereo file containing a sine tone at 441 Hz, using only
+python's built-in modules. """
+
+import wave
+import math
+import struct
+
+
+def create_sine_wave(freq, samplerate, nframes, nchannels):
+    """ create a pure tone (without numpy) """
+    _x = [0.7 * math.sin(2. * math.pi * freq * t / float(samplerate))
+          for t in range(nframes)]
+    _x = [int(a * 32767) for a in _x]
+    _x = b''.join([b''.join([struct.pack('h', v)
+                             for _ in range(nchannels)])
+                   for v in _x])
+    return _x
+
+
+def create_test_sound(pathname, freq=441, duration=None,
+                      framerate=44100, nchannels=2):
+    """ create a sound file at pathname, overwriting exiting file """
+    sampwidth = 2
+    nframes = duration or framerate  # defaults to 1 second duration
+    fid = wave.open(pathname, 'w')
+    fid.setnchannels(nchannels)
+    fid.setsampwidth(sampwidth)
+    fid.setframerate(framerate)
+    fid.setnframes(nframes)
+    frames = create_sine_wave(freq, framerate, nframes, nchannels)
+    fid.writeframes(frames)
+    fid.close()
+    return 0
+
+
+if __name__ == '__main__':
+    import sys
+    if len(sys.argv) < 2:
+        sys.exit(2)
+    sys.exit(create_test_sound(sys.argv[1]))
--- a/tests/src/io/test-sink-multi.c
+++ b/tests/src/io/test-sink-multi.c
@@ -1,9 +1,8 @@
-#define AUBIO_UNSTABLE 1
 #include <aubio.h>
 #include "utils_tests.h"
 
-// this file uses the unstable aubio api, please use aubio_sink instead
-// see src/io/sink.h and tests/src/sink/test-sink.c
+// same as test-sink.c, but uses aubio_source_do_multi to read multiple
+// channels
 
 int main (int argc, char **argv)
 {
@@ -10,8 +9,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
     return err;
   }
--- a/tests/src/io/test-sink.c
+++ b/tests/src/io/test-sink.c
@@ -6,8 +6,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
     return err;
   }
--- a/tests/src/io/test-sink_apple_audio-multi.c
+++ b/tests/src/io/test-sink_apple_audio-multi.c
@@ -2,8 +2,8 @@
 #include <aubio.h>
 #include "utils_tests.h"
 
-// this file uses the unstable aubio api, please use aubio_sink instead
-// see src/io/sink.h and tests/src/sink/test-sink.c
+// this file uses the unstable aubio api to test aubio_sink_apple_audio, please
+// use aubio_sink instead see src/io/sink.h and tests/src/sink/test-sink.c
 
 int main (int argc, char **argv)
 {
@@ -10,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
     return err;
   }
@@ -71,7 +71,7 @@
   del_aubio_source(i);
 beach_source:
 #else /* HAVE_SINK_APPLE_AUDIO */
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_sink_apple_audio\n");
 #endif /* HAVE_SINK_APPLE_AUDIO */
   return err;
--- a/tests/src/io/test-sink_apple_audio.c
+++ b/tests/src/io/test-sink_apple_audio.c
@@ -10,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
     return err;
   }
@@ -60,7 +60,7 @@
   del_fvec(vec);
 beach_fvec:
 #else /* HAVE_SINK_APPLE_AUDIO */
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_apple_audio\n");
 #endif /* HAVE_SINK_APPLE_AUDIO */
   return err;
--- a/tests/src/io/test-sink_sndfile-multi.c
+++ b/tests/src/io/test-sink_sndfile-multi.c
@@ -1,10 +1,9 @@
 #define AUBIO_UNSTABLE 1
 #include <aubio.h>
-#include "config.h"
 #include "utils_tests.h"
 
-// this file uses the unstable aubio api, please use aubio_sink instead
-// see src/io/sink.h and tests/src/sink/test-sink.c
+// this file uses the unstable aubio api to test aubio_sink_sndfile, please
+// use aubio_sink instead see src/io/sink.h and tests/src/sink/test-sink.c
 
 int main (int argc, char **argv)
 {
@@ -11,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
     return err;
   }
@@ -72,7 +71,7 @@
   del_aubio_source(i);
 beach_source:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_sink_sndfile\n");
 #endif /* HAVE_SNDFILE */
   return err;
--- a/tests/src/io/test-sink_sndfile.c
+++ b/tests/src/io/test-sink_sndfile.c
@@ -1,6 +1,5 @@
 #define AUBIO_UNSTABLE 1
 #include <aubio.h>
-#include "config.h"
 #include "utils_tests.h"
 
 // this file uses the unstable aubio api, please use aubio_sink instead
@@ -11,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
     return err;
   }
@@ -61,7 +60,7 @@
   del_fvec(vec);
 beach_fvec:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_sndfile\n");
 #endif /* HAVE_SNDFILE */
   return err;
--- a/tests/src/io/test-sink_wavwrite-multi.c
+++ b/tests/src/io/test-sink_wavwrite-multi.c
@@ -2,8 +2,8 @@
 #include <aubio.h>
 #include "utils_tests.h"
 
-// this file uses the unstable aubio api, please use aubio_sink instead
-// see src/io/sink.h and tests/src/sink/test-sink.c
+// this file uses the unstable aubio api to test aubio_sink_wavwrite, please
+// use aubio_sink instead see src/io/sink.h and tests/src/sink/test-sink.c
 
 int main (int argc, char **argv)
 {
@@ -10,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
     return err;
   }
@@ -71,7 +71,7 @@
   del_aubio_source(i);
 beach_source:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_sink_wavwrite\n");
 #endif /* HAVE_WAVWRITE */
   return err;
--- a/tests/src/io/test-sink_wavwrite.c
+++ b/tests/src/io/test-sink_wavwrite.c
@@ -10,8 +10,8 @@
   sint_t err = 0;
 
   if (argc < 3) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
     return err;
   }
@@ -60,7 +60,7 @@
   del_fvec(vec);
 beach_fvec:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_sink_wavwrite\n");
 #endif /* HAVE_WAVWRITE */
   return err;
--- a/tests/src/io/test-source.c
+++ b/tests/src/io/test-source.c
@@ -5,8 +5,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -22,8 +22,8 @@
   uint_t samplerate = 0;
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
--- a/tests/src/io/test-source_apple_audio.c
+++ b/tests/src/io/test-source_apple_audio.c
@@ -9,8 +9,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -27,8 +27,8 @@
   uint_t samplerate = 0;
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
@@ -56,7 +56,7 @@
   del_aubio_source_apple_audio (s);
 beach:
 #else /* HAVE_SOURCE_APPLE_AUDIO */
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_apple_audio\n");
 #endif /* HAVE_SOURCE_APPLE_AUDIO */
   return err;
--- a/tests/src/io/test-source_avcodec.c
+++ b/tests/src/io/test-source_avcodec.c
@@ -9,8 +9,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -27,8 +27,8 @@
   uint_t samplerate = 0;
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
@@ -56,7 +56,7 @@
   del_aubio_source_avcodec (s);
 beach:
 #else /* HAVE_LIBAV */
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_avcodec\n");
 #endif /* HAVE_LIBAV */
   return err;
--- a/tests/src/io/test-source_multi.c
+++ b/tests/src/io/test-source_multi.c
@@ -5,8 +5,8 @@
 {
   sint_t err = 0;
   if (argc < 2) {
-    err = -2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
--- a/tests/src/io/test-source_seek.c
+++ b/tests/src/io/test-source_seek.c
@@ -5,8 +5,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -23,8 +23,8 @@
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
   uint_t old_n_frames_1 = 0, old_n_frames_2 = 0, old_n_frames_3 = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
--- a/tests/src/io/test-source_sndfile.c
+++ b/tests/src/io/test-source_sndfile.c
@@ -9,8 +9,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -27,8 +27,8 @@
   uint_t samplerate = 0;
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
@@ -56,7 +56,7 @@
   del_aubio_source_sndfile (s);
 beach:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_sndfile\n");
 #endif /* HAVE_SNDFILE */
   return err;
--- a/tests/src/io/test-source_wavread.c
+++ b/tests/src/io/test-source_wavread.c
@@ -9,8 +9,8 @@
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source(main);
     PRINT_MSG("read a wave file as a mono vector\n");
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     PRINT_MSG("examples:\n");
@@ -27,8 +27,8 @@
   uint_t samplerate = 0;
   uint_t hop_size = 256;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
 
@@ -35,7 +35,6 @@
 
   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);
 
@@ -57,7 +56,7 @@
   del_aubio_source_wavread (s);
 beach:
 #else
-  err = 3;
+  err = 0;
   PRINT_ERR("aubio was not compiled with aubio_source_wavread\n");
 #endif /* HAVE_WAVREAD */
   return err;
--- /dev/null
+++ b/tests/src/notes/test-notes.c
@@ -1,0 +1,24 @@
+#include <aubio.h>
+
+int main (void)
+{
+  uint_t buf_size = 2048;
+  uint_t hop_size = 512;
+  uint_t samplerate = 44100;
+  smpl_t silence, minioi_ms, release_drop;
+  aubio_notes_t *o = new_aubio_notes("default",
+      buf_size, hop_size, samplerate);
+  silence = aubio_notes_get_silence(o);
+  minioi_ms = aubio_notes_get_minioi_ms(o);
+  release_drop = aubio_notes_get_release_drop(o);
+  if (aubio_notes_set_silence(o, silence)) return 1;
+  if (aubio_notes_set_minioi_ms(o, minioi_ms)) return 1;
+  if (aubio_notes_set_release_drop(o, release_drop)) return 1;
+  del_aubio_notes(o);
+  // test wrong arguments
+  if (new_aubio_notes("unknown", buf_size, hop_size, samplerate)) return 1;
+  if (new_aubio_notes("default",        0, hop_size, samplerate)) return 1;
+  if (new_aubio_notes("default", buf_size,        0, samplerate)) return 1;
+  if (new_aubio_notes("default", buf_size, hop_size,          0)) return 1;
+  return 0;
+}
--- a/tests/src/onset/test-onset.c
+++ b/tests/src/onset/test-onset.c
@@ -1,13 +1,15 @@
 #include <aubio.h>
 #include "utils_tests.h"
 
+int test_wrong_params(void);
+
 int main (int argc, char **argv)
 {
   uint_t err = 0;
   if (argc < 2) {
     err = 2;
-    PRINT_ERR("not enough arguments\n");
-    PRINT_MSG("read a wave file as a mono vector\n");
+    PRINT_WRN("no arguments, running tests\n");
+    err = test_wrong_params();
     PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
     return err;
   }
@@ -15,8 +17,8 @@
   uint_t win_s = 1024; // window size
   uint_t hop_size = win_s / 4;
   uint_t n_frames = 0, read = 0;
-  if ( argc == 3 ) samplerate = atoi(argv[2]);
-  if ( argc == 4 ) hop_size = atoi(argv[3]);
+  if ( argc >= 3 ) samplerate = atoi(argv[2]);
+  if ( argc >= 4 ) hop_size = atoi(argv[3]);
 
   char_t *source_path = argv[1];
   aubio_source_t * source = new_aubio_source(source_path, samplerate, hop_size);
@@ -59,4 +61,40 @@
   aubio_cleanup();
 
   return err;
+}
+
+int test_wrong_params(void)
+{
+  uint_t win_size = 1024;
+  uint_t hop_size = win_size / 2;
+  uint_t samplerate = 44100;
+  // hop_size < 1
+  if (new_aubio_onset("default", 5, 0, samplerate))
+    return 1;
+  // buf_size < 2
+  if (new_aubio_onset("default", 1, 1, samplerate))
+    return 1;
+  // buf_size < hop_size
+  if (new_aubio_onset("default", hop_size, win_size, samplerate))
+    return 1;
+  // samplerate < 1
+  if (new_aubio_onset("default", 1024, 512, 0))
+    return 1;
+
+  // specdesc creation failed
+  if (new_aubio_onset("abcd", win_size, win_size/2, samplerate))
+    return 1;
+
+  aubio_onset_t *o;
+
+  // pv creation might fail
+  o = new_aubio_onset("default", 5, 2, samplerate);
+  if (o) del_aubio_onset(o);
+
+  o = new_aubio_onset("default", win_size, hop_size, samplerate);
+  if (!aubio_onset_set_default_parameters(o, "wrong_type"))
+    return 1;
+  del_aubio_onset(o);
+
+  return run_on_default_source(main);
 }
--- a/tests/src/pitch/test-pitch.c
+++ b/tests/src/pitch/test-pitch.c
@@ -30,5 +30,42 @@
   del_fvec (input);
   aubio_cleanup ();
 
+  if (new_aubio_pitch(0, win_s, hop_s, samplerate)) return 1;
+  if (new_aubio_pitch("unknown", win_s, hop_s, samplerate)) return 1;
+  if (new_aubio_pitch("default", win_s,     0, samplerate)) return 1;
+  if (new_aubio_pitch("default",     0, hop_s, samplerate)) return 1;
+  if (new_aubio_pitch("default", hop_s, win_s, samplerate)) return 1;
+  if (new_aubio_pitch("default", win_s, hop_s,          0)) return 1;
+
+  o = new_aubio_pitch("default", win_s, hop_s, samplerate);
+
+  if (aubio_pitch_set_unit(o, "freq")) return 1;
+  if (aubio_pitch_set_unit(o, "hertz")) return 1;
+  if (aubio_pitch_set_unit(o, "Hertz")) return 1;
+  if (aubio_pitch_set_unit(o, "Hz")) return 1;
+  if (aubio_pitch_set_unit(o, "f0")) return 1;
+  if (aubio_pitch_set_unit(o, "midi")) return 1;
+  if (aubio_pitch_set_unit(o, "cent")) return 1;
+  if (aubio_pitch_set_unit(o, "bin")) return 1;
+  if (!aubio_pitch_set_unit(o, "unknown")) return 1;
+
+  if (aubio_pitch_set_tolerance(o, 0.3)) return 1;
+  if (aubio_pitch_set_silence(o, 0)) return 1;
+  if (aubio_pitch_set_silence(o, -200)) return 1;
+  if (!aubio_pitch_set_silence(o, -300)) return 1;
+  del_aubio_pitch(o);
+
+  // fft based might fail with non power of 2
+  o = new_aubio_pitch("yinfft", win_s + 1, hop_s, samplerate);
+  if (o) del_aubio_pitch(o);
+  o = new_aubio_pitch("yinfast", win_s + 1, hop_s, samplerate);
+  if (o) del_aubio_pitch(o);
+  o = new_aubio_pitch("fcomb", win_s + 1, hop_s, samplerate);
+  if (o) del_aubio_pitch(o);
+  o = new_aubio_pitch("mcomb", win_s + 1, hop_s, samplerate);
+  if (o) del_aubio_pitch(o);
+  o = new_aubio_pitch("specacf", win_s + 1, hop_s, samplerate);
+  if (o) del_aubio_pitch(o);
+
   return 0;
 }
--- /dev/null
+++ b/tests/src/spectral/test-awhitening.c
@@ -1,0 +1,102 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int test_wrong_params(void);
+
+int main (int argc, char **argv)
+{
+  sint_t err = 0;
+
+  if (argc < 3) {
+    err = 2;
+    PRINT_WRN("no arguments, running tests\n");
+    err = test_wrong_params();
+    PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
+    return err;
+  }
+
+  uint_t samplerate = 0;
+  uint_t win_size = 1024;
+  uint_t hop_size = 512;
+  uint_t n_frames = 0, read = 0;
+
+  char_t *source_path = argv[1];
+  char_t *sink_path = argv[2];
+
+  if ( argc >= 4 ) samplerate = atoi(argv[3]);
+  if ( argc >= 5 ) hop_size = atoi(argv[4]);
+
+  fvec_t *vec = new_fvec(hop_size);
+  fvec_t *out = new_fvec(hop_size); // output buffer
+  fvec_t *scale = new_fvec(hop_size);
+  cvec_t *fftgrain = new_cvec(win_size); // fft norm and phase
+  if (!vec) { err = 1; goto beach_fvec; }
+
+  aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+  if (!i) { err = 1; goto beach_source; }
+
+  if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+  aubio_sink_t *o = new_aubio_sink(sink_path, samplerate);
+  if (!o) { err = 1; goto beach_sink; }
+
+  aubio_pvoc_t *pv = new_aubio_pvoc(win_size, hop_size);
+
+  aubio_spectral_whitening_t *awhitening =
+    new_aubio_spectral_whitening (win_size, hop_size, samplerate);
+
+  aubio_spectral_whitening_set_relax_time(awhitening, 20.);
+  fvec_set_all(scale, 3.);
+
+  PRINT_MSG("spectral whitening relaxation time is %f\n",
+      aubio_spectral_whitening_get_relax_time(awhitening));
+
+  do {
+    aubio_source_do(i, vec, &read);
+    aubio_pvoc_do(pv, vec, fftgrain);
+    // apply spectral whitening
+    aubio_spectral_whitening_do(awhitening, fftgrain);
+    // rebuild the signal
+    aubio_pvoc_rdo(pv, fftgrain, out);
+    // make louder
+    fvec_weight(out, scale);
+    // make sure we dont saturate
+    fvec_clamp(out, 1.);
+    // write output
+    aubio_sink_do(o, out, read);
+    n_frames += read;
+  } while ( read == hop_size );
+
+  PRINT_MSG("read %d frames at %dHz (%d blocks) from %s written to %s\n",
+      n_frames, samplerate, n_frames / hop_size,
+      source_path, sink_path);
+
+  del_aubio_sink(o);
+beach_sink:
+  del_aubio_source(i);
+beach_source:
+  del_fvec(vec);
+beach_fvec:
+  return err;
+}
+
+int test_wrong_params(void)
+{
+  uint_t buf_size = 512;
+  uint_t hop_size = 256;
+  uint_t samplerate = 44100;
+  aubio_spectral_whitening_t *o;
+
+  if (new_aubio_spectral_whitening(       0, hop_size, samplerate)) return 1;
+  if (new_aubio_spectral_whitening(buf_size,        0, samplerate)) return 1;
+  if (new_aubio_spectral_whitening(buf_size, hop_size,          0)) return 1;
+
+  o = new_aubio_spectral_whitening(buf_size, hop_size, samplerate);
+
+  aubio_spectral_whitening_get_relax_time(o);
+  aubio_spectral_whitening_get_floor(o);
+
+  del_aubio_spectral_whitening(o);
+
+  return run_on_default_source_and_sink(main);
+}
--- /dev/null
+++ b/tests/src/spectral/test-dct.c
@@ -1,0 +1,49 @@
+#include <math.h>
+#include "aubio.h"
+#include "utils_tests.h"
+
+int main (void)
+{
+  int return_code = 0;
+  uint_t win_s = 32; // window size
+  uint_t i, j, n_iters = 10; // number of iterations
+  // create dct object
+  aubio_dct_t * dct = new_aubio_dct(win_s);
+  aubio_dct_t * tmp;
+
+  if (new_aubio_dct(0)) return 1;
+
+  fvec_t * in = new_fvec (win_s); // input buffer
+  fvec_t * dctout = new_fvec (win_s); // output buffer
+  fvec_t * out = new_fvec (win_s); // input buffer
+
+  if ((tmp = new_aubio_dct(1)) == 0) return 1;
+  //aubio_dct_do(tmp, dctout, out);
+  //aubio_dct_rdo(tmp, dctout, out);
+  del_aubio_dct(tmp);
+
+  if (!dct || !in || !dctout) {
+    return_code = 1;
+    return return_code;
+  }
+
+  in->data[0] = 1.;
+  for (i = 0; i < n_iters; i++) {
+    aubio_dct_do (dct, in, dctout);
+    aubio_dct_rdo (dct, dctout, out);
+    for (j = 0; j < in->length; j++) {
+      return_code += (fabsf(in->data[j] - out->data[j]) > 10.e-4);
+    }
+  }
+
+  fvec_print(in);
+  fvec_print(dctout);
+  fvec_print(out);
+
+  del_fvec(dctout);
+  del_fvec(in);
+  del_fvec(out);
+  del_aubio_dct(dct);
+
+  return return_code;
+}
--- a/tests/src/spectral/test-filterbank.c
+++ b/tests/src/spectral/test-filterbank.c
@@ -8,8 +8,20 @@
   cvec_t *in_spec = new_cvec (win_s); // input vector of samples
   fvec_t *out_filters = new_fvec (n_filters); // per-band outputs
 
+  if (new_aubio_filterbank(0, win_s)) return 1;
+  if (new_aubio_filterbank(n_filters, 0)) return 1;
+
   // create filterbank object
   aubio_filterbank_t *o = new_aubio_filterbank (n_filters, win_s);
+
+  smpl_t power = aubio_filterbank_get_power(o);
+  smpl_t norm = aubio_filterbank_get_norm(o);
+  if (aubio_filterbank_set_power(o, power)) {
+    return 1;
+  }
+  if (aubio_filterbank_set_norm(o, norm)) {
+    return 1;
+  }
 
   // apply filterbank ten times
   uint_t n = 10;
--- a/tests/src/spectral/test-mfcc.c
+++ b/tests/src/spectral/test-mfcc.c
@@ -4,13 +4,18 @@
 {
   uint_t win_s = 512; // fft size
   uint_t n_filters = 40; // number of filters
-  uint_t n_coefs = 13; // number of coefficients
+  uint_t n_coeffs = 13; // number of coefficients
   smpl_t samplerate = 16000.; // samplerate
   cvec_t *in = new_cvec (win_s); // input buffer
-  fvec_t *out = new_fvec (n_coefs); // output coefficients
+  fvec_t *out = new_fvec (n_coeffs); // output coefficients
 
+  if (new_aubio_mfcc(    0, n_filters, n_coeffs, samplerate)) return 1;
+  if (new_aubio_mfcc(win_s,         0, n_coeffs, samplerate)) return 1;
+  if (new_aubio_mfcc(win_s, n_filters,        0, samplerate)) return 1;
+  if (new_aubio_mfcc(win_s, n_filters, n_coeffs,          0)) return 1;
+
   // create mfcc object
-  aubio_mfcc_t *o = new_aubio_mfcc (win_s, n_filters, n_coefs, samplerate);
+  aubio_mfcc_t *o = new_aubio_mfcc (win_s, n_filters, n_coeffs, samplerate);
 
   cvec_norm_set_all (in, 1.);
   aubio_mfcc_do (o, in, out);
--- a/tests/src/spectral/test-phasevoc.c
+++ b/tests/src/spectral/test-phasevoc.c
@@ -13,6 +13,13 @@
   // allocate fft and other memory space
   aubio_pvoc_t * pv = new_aubio_pvoc(win_s,hop_s);
 
+  if (new_aubio_pvoc(win_s, 0)) return 1;
+
+  if (aubio_pvoc_get_win(pv) != win_s) return 1;
+  if (aubio_pvoc_get_hop(pv) != hop_s) return 1;
+
+  if (aubio_pvoc_set_window(pv, "hanningz") != 0) return 1;
+
   // fill input with some data
   fvec_set_all (in, 1.);
   fvec_print (in);
@@ -28,7 +35,7 @@
     // ...
     cvec_print (fftgrain);
 
-    // optionnaly rebuild the signa
+    // optionally rebuild the signal
     aubio_pvoc_rdo(pv,fftgrain,out);
 
     // and do something with the result
--- a/tests/src/spectral/test-tss.c
+++ b/tests/src/spectral/test-tss.c
@@ -34,6 +34,10 @@
     aubio_pvoc_rdo (pvs, ctrans, trans);
   }
 
+  aubio_tss_set_alpha(tss, 4.);
+  aubio_tss_set_beta(tss, 3.);
+  aubio_tss_set_threshold(tss, 3.);
+
   del_aubio_pvoc(pv);
   del_aubio_pvoc(pvt);
   del_aubio_pvoc(pvs);
--- a/tests/src/synth/test-sampler.c
+++ b/tests/src/synth/test-sampler.c
@@ -1,3 +1,5 @@
+#include <string.h> // strncpy
+#include <limits.h> // PATH_MAX
 #include <aubio.h>
 #include "utils_tests.h"
 
@@ -5,9 +7,9 @@
 {
   sint_t err = 0;
 
-  if (argc < 4) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+  if (argc < 3) {
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_source_and_sink(main);
     PRINT_MSG("usage: %s <input_path> <output_path> <sample_path> [samplerate]\n", argv[0]);
     return err;
   }
@@ -18,8 +20,15 @@
 
   char_t *source_path = argv[1];
   char_t *sink_path = argv[2];
-  char_t *sample_path = argv[3];
-  if ( argc == 5 ) samplerate = atoi(argv[4]);
+  char_t sample_path[PATH_MAX];
+  if ( argc >= 4 ) {
+    strncpy(sample_path, argv[3], PATH_MAX - 1);
+  } else {
+    // use input_path as sample
+    strncpy(sample_path, source_path, PATH_MAX - 1);
+  }
+  sample_path[PATH_MAX - 1] = '\0';
+  if ( argc >= 5 ) samplerate = atoi(argv[4]);
 
   fvec_t *vec = new_fvec(hop_size);
   aubio_source_t *source = new_aubio_source(source_path, samplerate, hop_size);
--- a/tests/src/synth/test-wavetable.c
+++ b/tests/src/synth/test-wavetable.c
@@ -6,8 +6,8 @@
   sint_t err = 0;
 
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
+    PRINT_ERR("not enough arguments, running tests\n");
+    err = run_on_default_sink(main);
     PRINT_MSG("usage: %s <output_path> [freq] [samplerate]\n", argv[0]);
     return err;
   }
@@ -17,8 +17,8 @@
   smpl_t freq = 440.;
 
   char_t *sink_path = argv[1];
-  if ( argc == 4 ) samplerate = atoi(argv[3]);
-  if ( argc == 3 ) freq = atof(argv[2]);
+  if ( argc >= 4 ) samplerate = atoi(argv[3]);
+  if ( argc >= 3 ) freq = atof(argv[2]);
 
   fvec_t *vec = new_fvec(hop_size);
   aubio_sink_t *sink = new_aubio_sink(sink_path, samplerate);
--- a/tests/src/tempo/test-tempo.c
+++ b/tests/src/tempo/test-tempo.c
@@ -1,14 +1,16 @@
 #include <aubio.h>
 #include "utils_tests.h"
 
+int test_wrong_params(void);
+
 int main (int argc, char **argv)
 {
   uint_t err = 0;
   if (argc < 2) {
-    err = 2;
-    PRINT_ERR("not enough arguments\n");
-    PRINT_MSG("read a wave file as a mono vector\n");
-    PRINT_MSG("usage: %s <source_path> [samplerate] [win_size] [hop_size]\n", argv[0]);
+    PRINT_WRN("no arguments, running tests\n");
+    err = test_wrong_params();
+    PRINT_MSG("usage: %s <source_path> [samplerate] [win_size] [hop_size]\n",
+        argv[0]);
     return err;
   }
   uint_t samplerate = 0;
@@ -20,7 +22,8 @@
   uint_t n_frames = 0, read = 0;
 
   char_t *source_path = argv[1];
-  aubio_source_t * source = new_aubio_source(source_path, samplerate, hop_size);
+  aubio_source_t * source = new_aubio_source(source_path, samplerate,
+      hop_size);
   if (!source) { err = 1; goto beach; }
 
   if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(source);
@@ -30,8 +33,11 @@
   fvec_t * out = new_fvec (1); // output position
 
   // create tempo object
-  aubio_tempo_t * o = new_aubio_tempo("default", win_size, hop_size, samplerate);
+  aubio_tempo_t * o = new_aubio_tempo("default", win_size, hop_size,
+      samplerate);
 
+  if (!o) { err = 1; goto beach_tempo; }
+
   do {
     // put some fresh data in input vector
     aubio_source_do(source, in, &read);
@@ -39,9 +45,11 @@
     aubio_tempo_do(o,in,out);
     // do something with the beats
     if (out->data[0] != 0) {
-      PRINT_MSG("beat at %.3fms, %.3fs, frame %d, %.2fbpm with confidence %.2f\n",
+      PRINT_MSG("beat at %.3fms, %.3fs, frame %d, %.2f bpm "
+          "with confidence %.2f\n",
           aubio_tempo_get_last_ms(o), aubio_tempo_get_last_s(o),
-          aubio_tempo_get_last(o), aubio_tempo_get_bpm(o), aubio_tempo_get_confidence(o));
+          aubio_tempo_get_last(o), aubio_tempo_get_bpm(o),
+          aubio_tempo_get_confidence(o));
     }
     n_frames += read;
   } while ( read == hop_size );
@@ -53,6 +61,7 @@
 
   // clean up memory
   del_aubio_tempo(o);
+beach_tempo:
   del_fvec(in);
   del_fvec(out);
   del_aubio_source(source);
@@ -60,4 +69,65 @@
   aubio_cleanup();
 
   return err;
+}
+
+int test_wrong_params(void)
+{
+  uint_t win_size = 1024;
+  uint_t hop_size = 256;
+  uint_t samplerate = 44100;
+  aubio_tempo_t *t;
+  fvec_t* in, *out;
+  uint_t i;
+
+  // test wrong method fails
+  if (new_aubio_tempo("unexisting_method", win_size, hop_size, samplerate))
+    return 1;
+
+  // test hop > win fails
+  if (new_aubio_tempo("default", hop_size, win_size, samplerate))
+    return 1;
+
+  // test null hop_size fails
+  if (new_aubio_tempo("default", win_size, 0, samplerate))
+    return 1;
+
+  // test 1 buf_size fails
+  if (new_aubio_tempo("default", 1, 1, samplerate))
+    return 1;
+
+  // test null samplerate fails
+  if (new_aubio_tempo("default", win_size, hop_size, 0))
+    return 1;
+
+  // test short sizes workaround
+  t = new_aubio_tempo("default", 2048, 2048, 500);
+  if (!t)
+    return 1;
+
+  del_aubio_tempo(t);
+
+  t = new_aubio_tempo("default", win_size, hop_size, samplerate);
+  if (!t)
+    return 1;
+
+  in = new_fvec(hop_size);
+  out = new_fvec(1);
+
+  // up to step = (next_power_of_two(5.8 * samplerate / hop_size ) / 4 )
+  for (i = 0; i < 256 + 1; i++)
+  {
+    aubio_tempo_do(t,in,out);
+    PRINT_MSG("beat at %.3fms, %.3fs, frame %d, %.2f bpm "
+        "with confidence %.2f, was tatum %d\n",
+        aubio_tempo_get_last_ms(t), aubio_tempo_get_last_s(t),
+        aubio_tempo_get_last(t), aubio_tempo_get_bpm(t),
+        aubio_tempo_get_confidence(t), aubio_tempo_was_tatum(t));
+  }
+
+  del_aubio_tempo(t);
+  del_fvec(in);
+  del_fvec(out);
+
+  return run_on_default_source(main);
 }
--- a/tests/src/temporal/test-filter.c
+++ b/tests/src/temporal/test-filter.c
@@ -8,6 +8,19 @@
   fvec_t *out = new_fvec (win_s); // input buffer
 
   aubio_filter_t *o = new_aubio_filter_c_weighting (44100);
+
+  if (new_aubio_filter(0))
+    return 1;
+
+  if (aubio_filter_get_samplerate(o) != 44100)
+    return 1;
+
+  if (aubio_filter_set_c_weighting (o, -1) == 0)
+    return 1;
+
+  if (aubio_filter_set_c_weighting (0, 32000) == 0)
+    return 1;
+
   in->data[impulse_at] = 0.5;
   fvec_print (in);
   aubio_filter_do (o, in);
@@ -15,6 +28,12 @@
   del_aubio_filter (o);
 
   o = new_aubio_filter_a_weighting (32000);
+
+  if (aubio_filter_set_a_weighting (o, -1) == 0)
+    return 1;
+  if (aubio_filter_set_a_weighting (0, 32000) == 0)
+    return 1;
+
   in->data[impulse_at] = 0.5;
   fvec_print (in);
   aubio_filter_do_outplace (o, in, out);
--- a/tests/src/test-mathutils.c
+++ b/tests/src/test-mathutils.c
@@ -102,7 +102,7 @@
   fvec_print(window);
 
   window_size /= 2.;
-  window = new_aubio_window("triangle", window_size);
+  window = new_aubio_window("parzen", window_size);
   fvec_print(window);
   del_fvec(window);
 
@@ -116,5 +116,6 @@
   test_next_power_of_two();
   test_miditofreq();
   test_freqtomidi();
+  test_aubio_window();
   return 0;
 }
--- a/tests/src/utils/test-hist.c
+++ b/tests/src/utils/test-hist.c
@@ -25,6 +25,7 @@
     del_aubio_hist(o);
     del_fvec(t);
   }
+  if (new_aubio_hist(0, 1, 0)) return 1;
   return 0;
 }
 
--- a/tests/src/utils/test-log.c
+++ b/tests/src/utils/test-log.c
@@ -9,7 +9,7 @@
  * aubio debug messages on stdout instead of stderr */
 void logging(int level, const char_t *message, void *data) {
   FILE *out;
-  fprintf(stdout, "using custom logging function\n");
+  //fprintf(stdout, "using custom logging function\n");
   if (level == AUBIO_LOG_ERR) {
     out = stderr;
   } else {
@@ -25,6 +25,7 @@
 {
   fprintf(stdout, "### testing normal logging\n");
   AUBIO_ERR("testing normal AUBIO_LOG_ERR\n");
+  AUBIO_INF("testing normal AUBIO_LOG_INF\n");
   AUBIO_WRN("testing normal AUBIO_LOG_WRN\n");
   AUBIO_MSG("testing normal AUBIO_LOG_MSG\n");
   AUBIO_DBG("testing normal AUBIO_LOG_DBG\n");
@@ -31,26 +32,29 @@
 
   fprintf(stdout, "### testing with one custom function\n");
   aubio_log_set_function(logging, (void *)hdr);
-  AUBIO_ERR("testing recustom AUBIO_LOG_ERR\n");
-  AUBIO_WRN("testing recustom AUBIO_LOG_WRN\n");
-  AUBIO_MSG("testing recustom AUBIO_LOG_MSG\n");
-  AUBIO_DBG("testing recustom AUBIO_LOG_DBG\n");
+  AUBIO_ERR("testing custom set_function AUBIO_LOG_ERR\n");
+  AUBIO_INF("testing custom set_function AUBIO_LOG_INF\n");
+  AUBIO_WRN("testing custom set_function AUBIO_LOG_WRN\n");
+  AUBIO_MSG("testing custom set_function AUBIO_LOG_MSG\n");
+  AUBIO_DBG("testing custom set_function AUBIO_LOG_DBG\n");
 
   fprintf(stdout, "### testing resetted logging\n");
   aubio_log_reset();
-  AUBIO_ERR("testing uncustom AUBIO_LOG_ERR\n");
-  AUBIO_WRN("testing uncustom AUBIO_LOG_WRN\n");
-  AUBIO_MSG("testing uncustom AUBIO_LOG_MSG\n");
-  AUBIO_DBG("testing uncustom AUBIO_LOG_DBG\n");
+  AUBIO_ERR("testing again normal AUBIO_LOG_ERR\n");
+  AUBIO_INF("testing again normal AUBIO_LOG_INF\n");
+  AUBIO_WRN("testing again normal AUBIO_LOG_WRN\n");
+  AUBIO_MSG("testing again normal AUBIO_LOG_MSG\n");
+  AUBIO_DBG("testing again normal AUBIO_LOG_DBG\n");
 
   fprintf(stdout, "### testing per level customization\n");
   aubio_log_set_level_function(AUBIO_LOG_ERR, logging, (void *)hdr2);
   aubio_log_set_level_function(AUBIO_LOG_WRN, logging, NULL);
   aubio_log_set_level_function(AUBIO_LOG_MSG, logging, (void *)hdr);
-  AUBIO_ERR("testing custom AUBIO_LOG_ERR\n");
-  AUBIO_WRN("testing custom AUBIO_LOG_WRN with data=NULL\n");
-  AUBIO_MSG("testing custom AUBIO_LOG_MSG\n");
-  AUBIO_DBG("testing uncustomized AUBIO_LOG_DBG\n");
+  AUBIO_ERR("testing custom set_level_function AUBIO_LOG_ERR\n");
+  AUBIO_INF("testing again normal AUBIO_LOG_INF\n");
+  AUBIO_WRN("testing custom set_level_function AUBIO_LOG_WRN with data=NULL\n");
+  AUBIO_MSG("testing custom set_level_function AUBIO_LOG_MSG\n");
+  AUBIO_DBG("testing again normal AUBIO_LOG_DBG\n");
 
   return 0;
 }
--- a/tests/utils_tests.h
+++ b/tests/utils_tests.h
@@ -5,6 +5,36 @@
 #include <assert.h>
 #include "config.h"
 
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> // unlink, close
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h> // PATH_MAX
+#endif /* HAVE_LIMITS_H */
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#if defined(HAVE_WIN_HACKS) && !defined(__GNUC__)
+#include <io.h> // _access
+#endif
+
+// This macro is used to pass a string to msvc compiler: since msvc's -D flag
+// strips the quotes, we define the string without quotes and re-add them with
+// this macro.
+
+#define REDEFINESTRING(x) #x
+#define DEFINEDSTRING(x) REDEFINESTRING(x)
+
+#ifndef AUBIO_TESTS_SOURCE
+#error "AUBIO_TESTS_SOURCE is not defined"
+#endif
+
 #ifdef HAVE_C99_VARARGS_MACROS
 #define PRINT_ERR(...)   fprintf(stderr, "AUBIO-TESTS ERROR: " __VA_ARGS__)
 #define PRINT_MSG(...)   fprintf(stdout, __VA_ARGS__)
@@ -47,7 +77,113 @@
 void utils_init_random (void) {
   time_t now = time(0);
   struct tm *tm_struct = localtime(&now);
-  int seed = tm_struct->tm_sec;
+  size_t **tm_address = (void*)&tm_struct;
+  int seed = tm_struct->tm_sec + (size_t)tm_address;
   //PRINT_WRN("current seed: %d\n", seed);
-  srandom (seed);
+  srandom ((unsigned int)seed);
+}
+
+// create_temp_sink / close_temp_sink
+#if defined(__GNUC__) // mkstemp
+
+int check_source(char *source_path)
+{
+  return access(source_path, R_OK);
+}
+
+int create_temp_sink(char *sink_path)
+{
+  return mkstemp(sink_path);
+}
+
+int close_temp_sink(char *sink_path, int sink_fildes)
+{
+  int err;
+  if ((err = close(sink_fildes)) != 0) return err;
+  if ((err = unlink(sink_path)) != 0) return err;
+  return err;
+}
+
+#elif defined(HAVE_WIN_HACKS) //&& !defined(__GNUC__)
+// windows workaround, where mkstemp does not exist...
+
+int check_source(char *source_path)
+{
+  return _access(source_path, 04);
+}
+
+int create_temp_sink(char *templ)
+{
+  int i = 0;
+  static const char letters[] = "abcdefg0123456789";
+  int letters_len = strlen(letters);
+  int templ_len = strlen(templ);
+  if (templ_len == 0) return 0;
+  utils_init_random();
+  for (i = 0; i < 6; i++)
+  {
+    templ[templ_len - i] = letters[rand() % letters_len];
+  }
+  return 1;
+}
+
+int close_temp_sink(char* sink_path, int sink_fildes) {
+  // the file should be closed when not using mkstemp, no need to open it
+  if (sink_fildes == 0) return 1;
+  return _unlink(sink_path);
+}
+
+#else // windows workaround
+// otherwise, we don't really know what to do yet
+#error "mkstemp undefined, but not on windows. additional workaround required."
+#endif
+
+// pass progname / default
+int run_on_default_source( int main(int, char**) )
+{
+  const int argc = 2;
+  int err = 0;
+  char** argv = (char**)calloc(argc, sizeof(char*));
+  argv[0] = __FILE__;
+  argv[1] = DEFINEDSTRING(AUBIO_TESTS_SOURCE);
+  // check if the file can be read
+  if ( check_source(argv[1]) ) return 1;
+  err = main(argc, argv);
+  if (argv) free(argv);
+  return err;
+}
+
+int run_on_default_sink( int main(int, char**) )
+{
+  const int argc = 2;
+  int err = 0;
+  char** argv = (char**)calloc(argc, sizeof(char*));
+  char sink_path[PATH_MAX] = "tmp_aubio_XXXXXX";
+  int fd = create_temp_sink(sink_path);
+  if (!fd) return 1;
+  argv[0] = __FILE__;
+  argv[1] = sink_path;
+  err = main(argc, argv);
+  close_temp_sink(sink_path, fd);
+  if (argv) free(argv);
+  return err;
+}
+
+int run_on_default_source_and_sink( int main(int, char**) )
+{
+  const int argc = 3;
+  int err = 0;
+  char** argv = (char**)calloc(argc, sizeof(char*));
+  char sink_path[PATH_MAX] = "tmp_aubio_XXXXXX";
+  int fd = create_temp_sink(sink_path);
+  if (!fd) return 1;
+  argv[0] = __FILE__;
+  argv[1] = DEFINEDSTRING(AUBIO_TESTS_SOURCE);
+  argv[2] = sink_path;
+  // check if the file can be read
+  if ( check_source(argv[1]) ) return 1;
+  err = main(argc, argv);
+  close_temp_sink(sink_path, fd);
+  if (argv) free(argv);
+  return err;
 }
--- a/tests/wscript_build
+++ b/tests/wscript_build
@@ -7,13 +7,30 @@
 includes = ['../src', '.']
 programs_sources = ctx.path.ant_glob('src/**/*.c')
 
+test_sound_target = '44100Hz_44100f_sine441_stereo.wav'
+test_sound_abspath = bld.path.get_bld().make_node(test_sound_target)
+# workaround to double escape backslash characters on windows
+test_sound_abspath = str(test_sound_abspath).replace('\\', '\\\\')
+
+b = bld(name='create_tests_source',
+    rule='python ${SRC} ${TGT}',
+    source='create_tests_source.py',
+    target=test_sound_target)
+# use post() to create the task, keep a reference to it
+b.post()
+create_tests_source = b.tasks[0]
+
 for source_file in programs_sources:
     target = os.path.basename(os.path.splitext(str(source_file))[0])
-    bld(features = 'c cprogram test',
+    a = bld(features = 'c cprogram test',
             source = source_file,
             target = target,
             includes = includes,
             use = uselib,
             install_path = None,
-            defines = 'AUBIO_UNSTABLE_API=1',
+            defines = ['AUBIO_UNSTABLE_API=1',
+                        'AUBIO_TESTS_SOURCE={}'.format(test_sound_abspath)]
        )
+    a.post()
+    # make sure the unit_test task runs *after* the source is created
+    a.tasks[-1].set_run_after(create_tests_source)
--- /dev/null
+++ b/this_version.py
@@ -1,0 +1,107 @@
+#! python
+import os
+import sys
+
+__version_info = {} # keep a reference to parse VERSION once
+
+def get_version_info():
+    # read from VERSION
+    # return dictionary filled with content of version
+    if not __version_info:
+        this_file_dir = os.path.dirname(os.path.abspath(__file__))
+        version_file = os.path.join(this_file_dir, 'VERSION')
+
+        if not os.path.isfile(version_file):
+            raise SystemError("VERSION file not found.")
+
+        for l in open(version_file).readlines():
+            if l.startswith('AUBIO_MAJOR_VERSION'):
+                __version_info['AUBIO_MAJOR_VERSION'] = int(l.split('=')[1])
+            if l.startswith('AUBIO_MINOR_VERSION'):
+                __version_info['AUBIO_MINOR_VERSION'] = int(l.split('=')[1])
+            if l.startswith('AUBIO_PATCH_VERSION'):
+                __version_info['AUBIO_PATCH_VERSION'] = int(l.split('=')[1])
+            if l.startswith('AUBIO_VERSION_STATUS'):
+                __version_info['AUBIO_VERSION_STATUS'] = \
+                    l.split('=')[1].strip()[1:-1]
+
+            if l.startswith('LIBAUBIO_LT_CUR'):
+                __version_info['LIBAUBIO_LT_CUR'] = int(l.split('=')[1])
+            if l.startswith('LIBAUBIO_LT_REV'):
+                __version_info['LIBAUBIO_LT_REV'] = int(l.split('=')[1])
+            if l.startswith('LIBAUBIO_LT_AGE'):
+                __version_info['LIBAUBIO_LT_AGE'] = int(l.split('=')[1])
+
+        if len(__version_info) < 6:
+            raise SystemError("Failed parsing VERSION file.")
+
+        # switch version status with commit sha in alpha releases
+        if __version_info['AUBIO_VERSION_STATUS'] and \
+                '~alpha' in __version_info['AUBIO_VERSION_STATUS']:
+            AUBIO_GIT_SHA = get_git_revision_hash()
+            if AUBIO_GIT_SHA:
+                __version_info['AUBIO_VERSION_STATUS'] = '~git+' + AUBIO_GIT_SHA
+
+    return __version_info
+
+def get_libaubio_version():
+    verfmt = '%(LIBAUBIO_LT_CUR)s.%(LIBAUBIO_LT_REV)s.%(LIBAUBIO_LT_AGE)s'
+    return str(verfmt % get_version_info())
+
+def get_aubio_version():
+    verfmt = '%(AUBIO_MAJOR_VERSION)s.%(AUBIO_MINOR_VERSION)s.%(AUBIO_PATCH_VERSION)s%(AUBIO_VERSION_STATUS)s'
+    return str(verfmt % get_version_info())
+
+def get_aubio_pyversion():
+    # convert to version for python according to pep 440
+    # see https://www.python.org/dev/peps/pep-0440/
+    # outputs MAJ.MIN.PATCH[a0[+git.<sha>[.mods]]]
+    aubio_version = get_aubio_version()
+    if '~git+' in aubio_version:
+        pep440str = aubio_version.replace('+', '.')
+        verstr = pep440str.replace('~git.', 'a0+')
+    elif '~alpha' in aubio_version:
+        verstr = aubio_version.replace('~alpha', 'a0')
+    else:
+        verstr = aubio_version
+    return verstr
+
+def get_git_revision_hash(short=True):
+    # get commit id, with +mods if local tree is not clean
+    if not os.path.isdir('.git'):
+        # print('Version : not in git repository : can\'t get sha')
+        return None
+    import subprocess
+    aubio_dir = os.path.dirname(os.path.abspath(__file__))
+    if not os.path.exists(aubio_dir):
+        raise SystemError("git / root folder not found")
+    gitcmd = ['git', '-C', aubio_dir, 'rev-parse']
+    if short:
+        gitcmd.append('--short')
+    gitcmd.append('HEAD')
+    try:
+        gitsha = subprocess.check_output(gitcmd).strip().decode('utf8')
+    except Exception as e:
+        sys.stderr.write('git command error :%s\n' % e)
+        return None
+    # check if we have a clean tree
+    gitcmd = ['git', '-C', aubio_dir, 'status', '--porcelain']
+    try:
+        output = subprocess.check_output(gitcmd).decode('utf8')
+        if len(output):
+            sys.stderr.write('Info: current tree is not clean\n\n')
+            sys.stderr.write(output + '\n')
+            gitsha += '+mods'
+    except subprocess.CalledProcessError as e:
+        sys.stderr.write('git command error :%s\n' % e)
+        pass
+    return gitsha
+
+if __name__ == '__main__':
+    if len(sys.argv) > 1 and sys.argv[1] == '-v':
+        print (get_aubio_version())
+    elif len(sys.argv) > 1 and sys.argv[1] == '-p':
+        print (get_aubio_version())
+    else:
+        print ('%30s'% 'aubio version:', get_aubio_version())
+        print ('%30s'% 'python-aubio version:', get_aubio_pyversion())
--- /dev/null
+++ b/waf_gensyms.py
@@ -1,0 +1,40 @@
+import re
+import os.path
+from waflib import TaskGen, Task
+from waflib.Context import STDOUT
+from waflib.Utils import O644
+
+class gen_sym_file(Task.Task):
+    color = 'BLUE'
+    inst_to = '${LIBDIR}'
+    def run(self):
+        syms = {}
+        reg = getattr(self.generator, 'export_symbols_regex','.+?')
+        if 'msvc' in self.env.CC_NAME:
+            outputs = [x.abspath() for x in self.generator.link_task.outputs]
+            binary_path = list(filter(lambda x: x.endswith('lib'), outputs))[0]
+            reg_compiled = re.compile(r'External\s+\|\s+(?P<symbol>%s)\b' % reg)
+            cmd =(self.env.LINK_CC) + ['/dump', '/symbols', binary_path]
+        else: # using gcc? assume we have nm
+            outputs = [x.abspath() for x in self.generator.link_task.outputs]
+            binary_path = list(filter(lambda x: x.endswith('dll'), outputs))[0]
+            reg_compiled = re.compile(r'(T|D)\s+_(?P<symbol>%s)\b'%reg)
+            cmd = (self.env.NM or ['nm']) + ['-g', binary_path]
+        dump_output = self.generator.bld.cmd_and_log(cmd, quiet=STDOUT)
+        syms = set([])
+        for m in reg_compiled.finditer(dump_output):
+            syms.add(m.group('symbol'))
+        syms = list(syms)
+        syms.sort()
+        self.outputs[0].write('EXPORTS\n'+'\n'.join(syms))
+
+@TaskGen.feature('gensyms')
+@TaskGen.after_method('process_source','process_use','apply_link','process_uselib_local','propagate_uselib_vars')
+def gen_symbols(self):
+    #sym_file = self.path.find_or_declare(self.target + '.def')
+    sym_file_name = os.path.splitext(self.link_task.outputs[0].abspath())[0] + '.def'
+    sym_file = self.path.find_or_declare(sym_file_name)
+    symtask = self.create_task('gen_sym_file', self.link_task.outputs, sym_file)
+    self.add_install_files(install_to=self.link_task.inst_to, install_from=sym_file,
+        chmod=O644, task=self.link_task)
+
--- a/wscript
+++ b/wscript
@@ -14,20 +14,11 @@
 
 APPNAME = 'aubio'
 
-# source VERSION
-for l in open('VERSION').readlines(): exec (l.strip())
+from this_version import *
 
-VERSION = '.'.join ([str(x) for x in [
-    AUBIO_MAJOR_VERSION,
-    AUBIO_MINOR_VERSION,
-    AUBIO_PATCH_VERSION
-    ]]) + AUBIO_VERSION_STATUS
+VERSION = get_aubio_version()
+LIB_VERSION = get_libaubio_version()
 
-LIB_VERSION = '.'.join ([str(x) for x in [
-    LIBAUBIO_LT_CUR,
-    LIBAUBIO_LT_REV,
-    LIBAUBIO_LT_AGE]])
-
 top = '.'
 out = 'build'
 
@@ -47,6 +38,13 @@
             help = help_disable_str )
 
 def options(ctx):
+    ctx.add_option('--build-type', action = 'store',
+            default = "release",
+            choices = ('debug', 'release'),
+            dest = 'build_type',
+            help = 'whether to compile with (--build-type=release)' \
+                    ' or without (--build-type=debug)' \
+                    ' compiler opimizations [default: release]')
     add_option_enable_disable(ctx, 'fftw3f', default = False,
             help_str = 'compile with fftw3f instead of ooura (recommended)',
             help_disable_str = 'do not compile with fftw3f')
@@ -53,6 +51,9 @@
     add_option_enable_disable(ctx, 'fftw3', default = False,
             help_str = 'compile with fftw3 instead of ooura',
             help_disable_str = 'do not compile with fftw3')
+    add_option_enable_disable(ctx, 'intelipp', default = False,
+            help_str = 'use Intel IPP libraries (auto)',
+            help_disable_str = 'do not use Intel IPP libraries')
     add_option_enable_disable(ctx, 'complex', default = False,
             help_str ='compile with C99 complex',
             help_disable_str = 'do not use C99 complex (default)' )
@@ -86,26 +87,55 @@
     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, 'blas', default = False,
+            help_str = 'use BLAS acceleration library (no)',
+            help_disable_str = 'do not use BLAS library')
+    add_option_enable_disable(ctx, 'atlas', default = False,
+            help_str = 'use ATLAS acceleration library (no)',
+            help_disable_str = 'do not use ATLAS library')
+    add_option_enable_disable(ctx, 'wavread', default = True,
+            help_str = 'compile with source_wavread (default)',
+            help_disable_str = 'do not compile source_wavread')
+    add_option_enable_disable(ctx, 'wavwrite', default = True,
+            help_str = 'compile with source_wavwrite (default)',
+            help_disable_str = 'do not compile source_wavwrite')
 
     add_option_enable_disable(ctx, 'docs', default = None,
             help_str = 'build documentation (auto)',
             help_disable_str = 'do not build documentation')
 
+    add_option_enable_disable(ctx, 'tests', default = True,
+            help_str = 'build tests (true)',
+            help_disable_str = 'do not build or run tests')
+
+    add_option_enable_disable(ctx, 'examples', default = True,
+            help_str = 'build examples (true)',
+            help_disable_str = 'do not build examples')
+
     ctx.add_option('--with-target-platform', type='string',
-            help='set target platform for cross-compilation', dest='target_platform')
+            help='set target platform for cross-compilation',
+            dest='target_platform')
 
     ctx.load('compiler_c')
     ctx.load('waf_unit_test')
     ctx.load('gnu_dirs')
+    ctx.load('waf_gensyms', tooldir='.')
 
 def configure(ctx):
+    target_platform = sys.platform
+    if ctx.options.target_platform:
+        target_platform = ctx.options.target_platform
+
     from waflib import Options
-    ctx.load('compiler_c')
+
+    if target_platform=='emscripten':
+        ctx.load('c_emscripten')
+    else:
+        ctx.load('compiler_c')
+
     ctx.load('waf_unit_test')
     ctx.load('gnu_dirs')
+    ctx.load('waf_gensyms', tooldir='.')
 
     # check for common headers
     ctx.check(header_name='stdlib.h')
@@ -117,16 +147,46 @@
     ctx.check(header_name='getopt.h', mandatory = False)
     ctx.check(header_name='unistd.h', mandatory = False)
 
-    target_platform = sys.platform
-    if ctx.options.target_platform:
-        target_platform = ctx.options.target_platform
     ctx.env['DEST_OS'] = target_platform
 
+    if ctx.options.build_type == "debug":
+        ctx.define('DEBUG', 1)
+    else:
+        ctx.define('NDEBUG', 1)
+
     if ctx.env.CC_NAME != 'msvc':
-        ctx.env.CFLAGS += ['-g', '-Wall', '-Wextra']
+        if ctx.options.build_type == "debug":
+            # no optimization in debug mode
+            ctx.env.prepend_value('CFLAGS', ['-O0'])
+        else:
+            if target_platform == 'emscripten':
+                # -Oz for small js file generation
+                ctx.env.prepend_value('CFLAGS', ['-Oz'])
+            else:
+                # default to -O2 in release mode
+                ctx.env.prepend_value('CFLAGS', ['-O2'])
+        # enable debug symbols and configure warnings
+        ctx.env.prepend_value('CFLAGS', ['-g', '-Wall', '-Wextra'])
     else:
-        ctx.env.CFLAGS += ['/W4', '/MD']
-        ctx.env.CFLAGS += ['/D_CRT_SECURE_NO_WARNINGS']
+        # enable debug symbols
+        ctx.env.CFLAGS += ['/Z7']
+        # /FS flag available in msvc >= 12 (2013)
+        if 'MSVC_VERSION' in ctx.env and ctx.env.MSVC_VERSION >= 12:
+            ctx.env.CFLAGS += ['/FS']
+        ctx.env.LINKFLAGS += ['/DEBUG', '/INCREMENTAL:NO']
+        # configure warnings
+        ctx.env.CFLAGS += ['/W4', '/D_CRT_SECURE_NO_WARNINGS']
+        # ignore "possible loss of data" warnings
+        ctx.env.CFLAGS += ['/wd4305', '/wd4244', '/wd4245', '/wd4267']
+        # ignore "unreferenced formal parameter" warnings
+        ctx.env.CFLAGS += ['/wd4100']
+        # set optimization level and runtime libs
+        if (ctx.options.build_type == "release"):
+            ctx.env.CFLAGS += ['/Ox']
+            ctx.env.CFLAGS += ['/MD']
+        else:
+            assert(ctx.options.build_type == "debug")
+            ctx.env.CFLAGS += ['/MDd']
 
     ctx.check_cc(lib='m', uselib_store='M', mandatory=False)
 
@@ -148,9 +208,17 @@
             ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
             ctx.define('HAVE_SOURCE_APPLE_AUDIO', 1)
             ctx.define('HAVE_SINK_APPLE_AUDIO', 1)
+            ctx.msg('Checking for AudioToolbox.framework', 'yes')
+        else:
+            ctx.msg('Checking for AudioToolbox.framework', 'no (disabled)',
+                    color = 'YELLOW')
         if (ctx.options.enable_accelerate != False):
             ctx.define('HAVE_ACCELERATE', 1)
             ctx.env.FRAMEWORK += ['Accelerate']
+            ctx.msg('Checking for Accelerate framework', 'yes')
+        else:
+            ctx.msg('Checking for Accelerate framework', 'no (disabled)',
+                    color = 'YELLOW')
 
     if target_platform in [ 'ios', 'iosimulator' ]:
         MINSDKVER="6.1"
@@ -185,13 +253,39 @@
         ctx.env.LINKFLAGS += [ '-isysroot' , SDKROOT]
 
     if target_platform == 'emscripten':
-        import os.path
-        ctx.env.CFLAGS += [ '-I' + os.path.join(os.environ['EMSCRIPTEN'], 'system', 'include') ]
-        ctx.env.CFLAGS += ['-Oz']
+        if ctx.options.build_type == "debug":
+            ctx.env.cshlib_PATTERN = '%s.js'
+            ctx.env.LINKFLAGS += ['-s','ASSERTIONS=2']
+            ctx.env.LINKFLAGS += ['-s','SAFE_HEAP=1']
+            ctx.env.LINKFLAGS += ['-s','ALIASING_FUNCTION_POINTERS=0']
+            ctx.env.LINKFLAGS += ['-O0']
+        else:
+            ctx.env.LINKFLAGS += ['-Oz']
+            ctx.env.cshlib_PATTERN = '%s.min.js'
+
+        # doesnt ship file system support in lib
+        ctx.env.LINKFLAGS_cshlib += ['-s', 'NO_FILESYSTEM=1']
+        # put memory file inside generated js files for easier portability
+        ctx.env.LINKFLAGS += ['--memory-init-file', '0']
         ctx.env.cprogram_PATTERN = "%s.js"
-        if (ctx.options.enable_atlas != True):
-            ctx.options.enable_atlas = False
+        ctx.env.cstlib_PATTERN = '%s.a'
 
+        # tell emscripten functions we want to expose
+        from python.lib.gen_external import get_c_declarations, \
+                get_cpp_objects_from_c_declarations, \
+                get_all_func_names_from_lib, \
+                generate_lib_from_c_declarations
+        # emscripten can't use double
+        c_decls = get_c_declarations(usedouble=False)
+        objects = list(get_cpp_objects_from_c_declarations(c_decls))
+        # ensure that aubio structs are exported
+        objects += ['fvec_t', 'cvec_t', 'fmat_t']
+        lib = generate_lib_from_c_declarations(objects, c_decls)
+        exported_funcnames = get_all_func_names_from_lib(lib)
+        c_mangled_names = ['_' + s for s in exported_funcnames]
+        ctx.env.LINKFLAGS_cshlib += ['-s',
+                'EXPORTED_FUNCTIONS=%s' % c_mangled_names]
+
     # check support for C99 __VA_ARGS__ macros
     check_c99_varargs = '''
 #include <stdio.h>
@@ -218,12 +312,28 @@
     else:
         ctx.msg('Checking if complex.h is enabled', 'no')
 
+    # check for Intel IPP
+    if (ctx.options.enable_intelipp != False):
+        has_ipp_headers = ctx.check(header_name=['ippcore.h', 'ippvm.h',
+            'ipps.h'], mandatory = False)
+        has_ipp_libs = ctx.check(lib=['ippcore', 'ippvm', 'ipps'],
+                uselib_store='INTEL_IPP', mandatory = False)
+        if (has_ipp_headers and has_ipp_libs):
+            ctx.msg('Checking if Intel IPP is available', 'yes')
+            ctx.define('HAVE_INTEL_IPP', 1)
+            if ctx.env.CC_NAME == 'msvc':
+                # force linking multi-threaded static IPP libraries on Windows
+                # with msvc
+                ctx.define('_IPP_SEQUENTIAL_STATIC', 1)
+        else:
+            ctx.msg('Checking if Intel IPP is available', 'no')
+
     # check for fftw3
     if (ctx.options.enable_fftw3 != False or ctx.options.enable_fftw3f != False):
         # one of fftwf or fftw3f
         if (ctx.options.enable_fftw3f != False):
-            ctx.check_cfg(package = 'fftw3f', atleast_version = '3.0.0',
-                    args = '--cflags --libs',
+            ctx.check_cfg(package = 'fftw3f',
+                    args = '--cflags --libs fftw3f >= 3.0.0',
                     mandatory = ctx.options.enable_fftw3f)
             if (ctx.options.enable_double == True):
                 ctx.msg('Warning',
@@ -232,16 +342,16 @@
             # fftw3f disabled, take most sensible one according to
             # enable_double
             if (ctx.options.enable_double == True):
-                ctx.check_cfg(package = 'fftw3', atleast_version = '3.0.0',
-                        args = '--cflags --libs', mandatory =
-                        ctx.options.enable_fftw3)
+                ctx.check_cfg(package = 'fftw3',
+                        args = '--cflags --libs fftw3 >= 3.0.0.',
+                        mandatory = ctx.options.enable_fftw3)
             else:
-                ctx.check_cfg(package = 'fftw3f', atleast_version = '3.0.0',
-                        args = '--cflags --libs',
+                ctx.check_cfg(package = 'fftw3f',
+                        args = '--cflags --libs fftw3f >= 3.0.0',
                         mandatory = ctx.options.enable_fftw3)
         ctx.define('HAVE_FFTW3', 1)
 
-    # fftw not enabled, use vDSP or ooura
+    # fftw not enabled, use vDSP, intelIPP or ooura
     if 'HAVE_FFTW3F' in ctx.env.define_key:
         ctx.msg('Checking for FFT implementation', 'fftw3f')
     elif 'HAVE_FFTW3' in ctx.env.define_key:
@@ -248,19 +358,29 @@
         ctx.msg('Checking for FFT implementation', 'fftw3')
     elif 'HAVE_ACCELERATE' in ctx.env.define_key:
         ctx.msg('Checking for FFT implementation', 'vDSP')
+    elif 'HAVE_INTEL_IPP' in ctx.env.define_key:
+        ctx.msg('Checking for FFT implementation', 'Intel IPP')
     else:
         ctx.msg('Checking for FFT implementation', 'ooura')
 
     # check for libsndfile
     if (ctx.options.enable_sndfile != False):
-        ctx.check_cfg(package = 'sndfile', atleast_version = '1.0.4',
-                args = '--cflags --libs',
+        ctx.check_cfg(package = 'sndfile',
+                args = '--cflags --libs sndfile >= 1.0.4',
                 mandatory = ctx.options.enable_sndfile)
 
     # check for libsamplerate
+    if (ctx.options.enable_double):
+        if (ctx.options.enable_samplerate):
+            ctx.fatal("Could not compile aubio in double precision mode' \
+                    ' with libsamplerate")
+        else:
+            ctx.options.enable_samplerate = False
+            ctx.msg('Checking if using samplerate',
+                    'no (disabled in double precision mode)', color = 'YELLOW')
     if (ctx.options.enable_samplerate != False):
-        ctx.check_cfg(package = 'samplerate', atleast_version = '0.0.15',
-                args = '--cflags --libs',
+        ctx.check_cfg(package = 'samplerate',
+                args = '--cflags --libs samplerate >= 0.0.15',
                 mandatory = ctx.options.enable_samplerate)
 
     # check for librubberband
@@ -277,33 +397,72 @@
 
     # check for libav
     if (ctx.options.enable_avcodec != False):
-        ctx.check_cfg(package = 'libavcodec', atleast_version = '54.35.0',
-                args = '--cflags --libs', uselib_store = 'AVCODEC',
+        ctx.check_cfg(package = 'libavcodec',
+                args = '--cflags --libs libavcodec >= 54.35.0',
+                uselib_store = 'AVCODEC',
                 mandatory = ctx.options.enable_avcodec)
-        ctx.check_cfg(package = 'libavformat', atleast_version = '52.3.0',
-                args = '--cflags --libs', uselib_store = 'AVFORMAT',
+        ctx.check_cfg(package = 'libavformat',
+                args = '--cflags --libs libavformat >= 52.3.0',
+                uselib_store = 'AVFORMAT',
                 mandatory = ctx.options.enable_avcodec)
-        ctx.check_cfg(package = 'libavutil', atleast_version = '52.3.0',
-                args = '--cflags --libs', uselib_store = 'AVUTIL',
+        ctx.check_cfg(package = 'libavutil',
+                args = '--cflags --libs libavutil >= 52.3.0',
+                uselib_store = 'AVUTIL',
                 mandatory = ctx.options.enable_avcodec)
-        ctx.check_cfg(package = 'libavresample', atleast_version = '1.0.1',
-                args = '--cflags --libs', uselib_store = 'AVRESAMPLE',
-                mandatory = ctx.options.enable_avcodec)
-        if all ( 'HAVE_' + i in ctx.env
-                for i in ['AVCODEC', 'AVFORMAT', 'AVUTIL', 'AVRESAMPLE'] ):
-            ctx.define('HAVE_LIBAV', 1)
-            ctx.msg('Checking for all libav libraries', 'yes')
+        ctx.check_cfg(package = 'libswresample',
+                args = '--cflags --libs libswresample >= 1.2.0',
+                uselib_store = 'SWRESAMPLE',
+                mandatory = False)
+        if 'HAVE_SWRESAMPLE' not in ctx.env:
+            ctx.check_cfg(package = 'libavresample',
+                    args = '--cflags --libs libavresample >= 1.0.1',
+                    uselib_store = 'AVRESAMPLE',
+                    mandatory = False)
+
+        msg_check = 'Checking for all libav libraries'
+        if 'HAVE_AVCODEC' not in ctx.env:
+            ctx.msg(msg_check, 'not found (missing avcodec)', color = 'YELLOW')
+        elif 'HAVE_AVFORMAT' not in ctx.env:
+            ctx.msg(msg_check, 'not found (missing avformat)', color = 'YELLOW')
+        elif 'HAVE_AVUTIL' not in ctx.env:
+            ctx.msg(msg_check, 'not found (missing avutil)', color = 'YELLOW')
+        elif 'HAVE_SWRESAMPLE' not in ctx.env \
+                and 'HAVE_AVRESAMPLE' not in ctx.env:
+            resample_missing = 'not found (avresample or swresample required)'
+            ctx.msg(msg_check, resample_missing, color = 'YELLOW')
         else:
-            ctx.msg('Checking for all libav libraries', 'not found', color = 'YELLOW')
+            ctx.msg(msg_check, 'yes')
+            if 'HAVE_SWRESAMPLE' in ctx.env:
+                ctx.define('HAVE_SWRESAMPLE', 1)
+            elif 'HAVE_AVRESAMPLE' in ctx.env:
+                ctx.define('HAVE_AVRESAMPLE', 1)
+            ctx.define('HAVE_LIBAV', 1)
 
-    ctx.define('HAVE_WAVREAD', 1)
-    ctx.define('HAVE_WAVWRITE', 1)
+    if (ctx.options.enable_wavread != False):
+        ctx.define('HAVE_WAVREAD', 1)
+    ctx.msg('Checking if using source_wavread',
+            ctx.options.enable_wavread and 'yes' or 'no')
+    if (ctx.options.enable_wavwrite!= False):
+        ctx.define('HAVE_WAVWRITE', 1)
+    ctx.msg('Checking if using sink_wavwrite',
+            ctx.options.enable_wavwrite and 'yes' or 'no')
 
-    # 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 BLAS/ATLAS
+    if (ctx.options.enable_blas != False):
+        ctx.check_cfg(package = 'blas',
+                args = '--cflags --libs',
+                uselib_store='BLAS', mandatory = ctx.options.enable_blas)
+        if 'LIB_BLAS' in ctx.env:
+            blas_header = None
+            if ctx.env['LIBPATH_BLAS']:
+                if 'atlas' in ctx.env['LIBPATH_BLAS'][0]:
+                    blas_header = 'atlas/cblas.h'
+                elif 'openblas' in ctx.env['LIBPATH_BLAS'][0]:
+                    blas_header = 'openblas/cblas.h'
+            else:
+                blas_header = 'cblas.h'
+            ctx.check(header_name = blas_header, mandatory =
+                    ctx.options.enable_atlas)
 
     # use memcpy hacks
     if (ctx.options.enable_memcpy == True):
@@ -314,6 +473,7 @@
 
     # the following defines will be passed as arguments to the compiler
     # instead of being written to src/config.h
+    ctx.define('HAVE_CONFIG_H', 1)
 
     # add some defines used in examples
     ctx.define('AUBIO_PREFIX', ctx.env['PREFIX'])
@@ -346,19 +506,37 @@
     bld.env['VERSION'] = VERSION
     bld.env['LIB_VERSION'] = LIB_VERSION
 
-    # add sub directories
+    # main source
     bld.recurse('src')
+
+    # add sub directories
     if bld.env['DEST_OS'] not in ['ios', 'iosimulator', 'android']:
-        bld.recurse('examples')
-        bld.recurse('tests')
+        if bld.env['DEST_OS']=='emscripten' and not bld.options.testcmd:
+            bld.options.testcmd = 'node %s'
+        if bld.options.enable_examples:
+            bld.recurse('examples')
+        if bld.options.enable_tests:
+            bld.recurse('tests')
 
+    # pkg-config template
     bld( source = 'aubio.pc.in' )
 
+    # documentation
+    txt2man(bld)
+    doxygen(bld)
+    sphinx(bld)
+
+    from waflib.Tools import waf_unit_test
+    bld.add_post_fun(waf_unit_test.summary)
+    bld.add_post_fun(waf_unit_test.set_exit_code)
+
+def txt2man(bld):
     # build manpages from txt files using txt2man
     if bld.env['TXT2MAN']:
         from waflib import TaskGen
         if 'MANDIR' not in bld.env:
-            bld.env['MANDIR'] = bld.env['PREFIX'] + '/share/man'
+            bld.env['MANDIR'] = bld.env['DATAROOTDIR'] + '/man'
+        bld.env.VERSION = VERSION
         rule_str = '${TXT2MAN} -t `basename ${TGT} | cut -f 1 -d . | tr a-z A-Z`'
         rule_str += ' -r ${PACKAGE}\\ ${VERSION} -P ${PACKAGE}'
         rule_str += ' -v ${PACKAGE}\\ User\\\'s\\ manual'
@@ -373,36 +551,69 @@
                 )
         bld( source = bld.path.ant_glob('doc/*.txt') )
 
+def doxygen(bld):
     # build documentation from source files using doxygen
     if bld.env['DOXYGEN']:
-        bld( name = 'doxygen', rule = 'doxygen ${SRC} > /dev/null',
+        bld.env.VERSION = VERSION
+        rule = '( cat ${SRC} && echo PROJECT_NUMBER=${VERSION}; )'
+        rule += ' | doxygen - > /dev/null'
+        bld( name = 'doxygen', rule = rule,
                 source = 'doc/web.cfg',
+                target = '../doc/web/html/index.html',
                 cwd = 'doc')
-        bld.install_files( '${PREFIX}' + '/share/doc/libaubio-doc',
+        bld.install_files( '${DATAROOTDIR}' + '/doc/libaubio-doc',
                 bld.path.ant_glob('doc/web/html/**'),
                 cwd = bld.path.find_dir ('doc/web'),
                 relative_trick = True)
 
-    # build documentation from source files using sphinx-build
+def sphinx(bld):
+    # build documentation from source files using sphinx-build note: build in
+    # ../doc/_build/html, otherwise waf wont install unsigned files
     if bld.env['SPHINX']:
-        bld( name = 'sphinx', rule = 'make html',
-                source = ['doc/conf.py'] + bld.path.ant_glob('doc/**.rst'),
-                cwd = 'doc')
-        bld.install_files( '${PREFIX}' + '/share/doc/libaubio-doc/sphinx',
+        bld.env.VERSION = VERSION
+        bld( name = 'sphinx',
+                rule = '${SPHINX} -b html -D release=${VERSION}' \
+                        ' -D version=${VERSION} -a -q' \
+                        ' `dirname ${SRC}` `dirname ${TGT}`',
+                source = 'doc/conf.py',
+                target = '../doc/_build/html/index.html')
+        bld.install_files( '${DATAROOTDIR}' + '/doc/libaubio-doc/sphinx',
                 bld.path.ant_glob('doc/_build/html/**'),
-                cwd = bld.path.find_dir ('doc/_build/html'),
+                cwd = bld.path.find_dir('doc/_build/html'),
                 relative_trick = True)
 
+# register the previous rules as build rules
+from waflib.Build import BuildContext
+
+class build_txt2man(BuildContext):
+    cmd = 'txt2man'
+    fun = 'txt2man'
+
+class build_manpages(BuildContext):
+    cmd = 'manpages'
+    fun = 'txt2man'
+
+class build_sphinx(BuildContext):
+    cmd = 'sphinx'
+    fun = 'sphinx'
+
+class build_doxygen(BuildContext):
+    cmd = 'doxygen'
+    fun = 'doxygen'
+
 def shutdown(bld):
     from waflib import Logs
     if bld.options.target_platform in ['ios', 'iosimulator']:
-        msg ='building for %s, contact the author for a commercial license' % bld.options.target_platform
+        msg ='building for %s, contact the author for a commercial license' \
+                % bld.options.target_platform
         Logs.pprint('RED', msg)
         msg ='   Paul Brossier <piem@aubio.org>'
         Logs.pprint('RED', msg)
 
 def dist(ctx):
-    ctx.excl  = ' **/.waf-1* **/*~ **/*.pyc **/*.swp **/*.swo **/*.swn **/.lock-w* **/.git*'
+    ctx.excl  = ' **/.waf*'
+    ctx.excl += ' **/.git*'
+    ctx.excl += ' **/*~ **/*.pyc **/*.swp **/*.swo **/*.swn **/.lock-w*'
     ctx.excl += ' **/build/*'
     ctx.excl += ' doc/_build'
     ctx.excl += ' python/demos_*'
@@ -410,11 +621,17 @@
     ctx.excl += ' **/python/ext/config.h'
     ctx.excl += ' **/python/lib/aubio/_aubio.so'
     ctx.excl += ' **.egg-info'
+    ctx.excl += ' **/.eggs'
+    ctx.excl += ' **/.pytest_cache'
+    ctx.excl += ' **/.cache'
     ctx.excl += ' **/**.zip **/**.tar.bz2'
+    ctx.excl += ' **.tar.bz2'
     ctx.excl += ' **/doc/full/* **/doc/web/*'
+    ctx.excl += ' **/doc/full.cfg'
     ctx.excl += ' **/python/*.db'
     ctx.excl += ' **/python.old/*'
     ctx.excl += ' **/python/*/*.old'
+    ctx.excl += ' **/python/lib/aubio/*.so'
     ctx.excl += ' **/python/tests/sounds'
     ctx.excl += ' **/**.asc'
     ctx.excl += ' **/dist*'
@@ -422,3 +639,6 @@
     ctx.excl += ' **/.travis.yml'
     ctx.excl += ' **/.landscape.yml'
     ctx.excl += ' **/.appveyor.yml'
+    ctx.excl += ' **/.circleci/*'
+    ctx.excl += ' **/azure-pipelines.yml'
+    ctx.excl += ' **/.coverage*'