Merge branch 'master' into awhitening
authorPaul Brossier <piem@piem.org>
Fri, 10 Mar 2017 13:26:32 +0000 (14:26 +0100)
committerPaul Brossier <piem@piem.org>
Fri, 10 Mar 2017 13:26:32 +0000 (14:26 +0100)
266 files changed:
.appveyor.yml [new file with mode: 0644]
.gitignore
.landscape.yml [new file with mode: 0644]
.travis.yml
ChangeLog
MANIFEST.in [new file with mode: 0644]
Makefile
README.md
VERSION
doc/Makefile
doc/android.rst [new file with mode: 0644]
doc/aubiocut.txt
doc/aubiomfcc.txt
doc/aubionotes.txt
doc/aubioonset.txt
doc/aubiopitch.txt
doc/aubioquiet.txt
doc/aubiotrack.txt
doc/building.rst [new file with mode: 0644]
doc/cli.rst [new file with mode: 0644]
doc/cli_features.rst [new file with mode: 0644]
doc/conf.py
doc/debian_packages.rst [new file with mode: 0644]
doc/develop.rst [new file with mode: 0644]
doc/download.rst [new file with mode: 0644]
doc/full.cfg
doc/index.rst
doc/installing.rst
doc/python_module.rst
doc/requirements.rst [new file with mode: 0644]
doc/statuslinks.rst [new file with mode: 0644]
doc/web.cfg
doc/xcode_frameworks.rst [new file with mode: 0644]
examples/aubiomfcc.c
examples/aubionotes.c
examples/aubioonset.c
examples/aubiopitch.c
examples/aubioquiet.c
examples/aubiotrack.c
examples/jackio.c
examples/parse_args.h
examples/utils.c
examples/utils.h
examples/wscript_build
nose2.cfg [new file with mode: 0644]
python/MANIFEST.in [deleted file]
python/README [deleted file]
python/README.md [new file with mode: 0644]
python/VERSION [deleted file]
python/__init__.py [new file with mode: 0644]
python/demos/__init__.py [new file with mode: 0644]
python/demos/demo_a_weighting.py [deleted file]
python/demos/demo_alsa.py [new file with mode: 0755]
python/demos/demo_bench_yin.py [new file with mode: 0755]
python/demos/demo_bpm_extract.py
python/demos/demo_create_test_sounds.py [new file with mode: 0755]
python/demos/demo_filter.py [new file with mode: 0755]
python/demos/demo_filterbank.py
python/demos/demo_filterbank_slaney.py
python/demos/demo_filterbank_triangle_bands.py
python/demos/demo_keyboard.py
python/demos/demo_mel-energy.py
python/demos/demo_mfcc.py
python/demos/demo_notes.py [new file with mode: 0755]
python/demos/demo_onset.py
python/demos/demo_onset_plot.py
python/demos/demo_pitch.py
python/demos/demo_pitch_sinusoid.py
python/demos/demo_pyaudio.py [new file with mode: 0755]
python/demos/demo_pysoundcard_record.py
python/demos/demo_reading_speed.py [new file with mode: 0755]
python/demos/demo_simple_robot_voice.py
python/demos/demo_simple_spectral_weighting.py
python/demos/demo_sink.py
python/demos/demo_sink_create_woodblock.py
python/demos/demo_sink_multi.py
python/demos/demo_slicing.py
python/demos/demo_source.py
python/demos/demo_source_simple.py [new file with mode: 0755]
python/demos/demo_specdesc.py
python/demos/demo_spectrogram.py
python/demos/demo_tempo.py
python/demos/demo_tempo_plot.py
python/demos/demo_timestretch.py [new file with mode: 0755]
python/demos/demo_timestretch_online.py [new file with mode: 0755]
python/demos/demo_tss.py
python/demos/demo_waveform_plot.py
python/ext/aubio-types.h
python/ext/aubiomodule.c
python/ext/aubioproxy.c
python/ext/aubiowraphell.h [deleted file]
python/ext/py-cvec.c
python/ext/py-fft.c
python/ext/py-filter.c
python/ext/py-filterbank.c
python/ext/py-musicutils.c
python/ext/py-musicutils.h
python/ext/py-phasevoc.c
python/ext/py-sink.c
python/ext/py-source.c
python/ext/ufuncs.c
python/lib/aubio/__init__.py
python/lib/aubio/midiconv.py
python/lib/aubio/slicing.py
python/lib/gen_code.py [new file with mode: 0644]
python/lib/gen_external.py [new file with mode: 0644]
python/lib/gen_pyobject.py [deleted file]
python/lib/generator.py [deleted file]
python/lib/moresetuptools.py [new file with mode: 0644]
python/scripts/aubiocut
python/setup.py [deleted file]
python/tests/__init__.py [new file with mode: 0644]
python/tests/eval_pitch
python/tests/run_all_tests
python/tests/test_aubio.py
python/tests/test_cvec.py
python/tests/test_fft.py
python/tests/test_filter.py
python/tests/test_filterbank.py
python/tests/test_filterbank_mel.py
python/tests/test_fvec.py
python/tests/test_mathutils.py
python/tests/test_mfcc.py [new file with mode: 0755]
python/tests/test_midi2note.py
python/tests/test_musicutils.py
python/tests/test_note2midi.py
python/tests/test_notes.py [new file with mode: 0755]
python/tests/test_onset.py
python/tests/test_phasevoc.py
python/tests/test_pitch.py
python/tests/test_sink.py
python/tests/test_slicing.py
python/tests/test_source.py
python/tests/test_specdesc.py
python/tests/test_zero_crossing_rate.py
python/tests/utils.py
requirements.txt [new file with mode: 0644]
scripts/apple/Info.plist [new file with mode: 0644]
scripts/apple/Modules/module.modulemap [new file with mode: 0644]
scripts/build_android [new file with mode: 0755]
scripts/build_apple_frameworks [new file with mode: 0755]
scripts/build_emscripten [new file with mode: 0755]
scripts/build_mingw [new file with mode: 0755]
scripts/get_waf.sh [new file with mode: 0755]
scripts/setenv_local.sh [new file with mode: 0644]
setup.py [new file with mode: 0755]
src/aubio.h
src/aubio_priv.h
src/cvec.c
src/cvec.h
src/fmat.c
src/fmat.h
src/fvec.c
src/fvec.h
src/io/audio_unit.c
src/io/audio_unit.h
src/io/ioutils.c [new file with mode: 0644]
src/io/ioutils.h [new file with mode: 0644]
src/io/sink.c
src/io/sink.h
src/io/sink_apple_audio.c
src/io/sink_apple_audio.h
src/io/sink_sndfile.c
src/io/sink_sndfile.h
src/io/sink_wavwrite.c
src/io/sink_wavwrite.h
src/io/source.c
src/io/source.h
src/io/source_apple_audio.c
src/io/source_apple_audio.h
src/io/source_avcodec.c
src/io/source_avcodec.h
src/io/source_sndfile.c
src/io/source_sndfile.h
src/io/source_wavread.c
src/io/source_wavread.h
src/io/utils_apple_audio.c
src/lvec.c
src/lvec.h
src/mathutils.c
src/mathutils.h
src/musicutils.h
src/notes/notes.c [new file with mode: 0644]
src/notes/notes.h [new file with mode: 0644]
src/onset/onset.c
src/onset/onset.h
src/onset/peakpicker.c
src/onset/peakpicker.h
src/pitch/pitch.c
src/pitch/pitch.h
src/pitch/pitchfcomb.c
src/pitch/pitchfcomb.h
src/pitch/pitchmcomb.c
src/pitch/pitchmcomb.h
src/pitch/pitchschmitt.c
src/pitch/pitchschmitt.h
src/pitch/pitchspecacf.c
src/pitch/pitchspecacf.h
src/pitch/pitchyin.c
src/pitch/pitchyin.h
src/pitch/pitchyinfft.c
src/pitch/pitchyinfft.h
src/spectral/fft.c
src/spectral/fft.h
src/spectral/filterbank.c
src/spectral/filterbank.h
src/spectral/filterbank_mel.c
src/spectral/filterbank_mel.h
src/spectral/mfcc.c
src/spectral/mfcc.h
src/spectral/ooura_fft8g.c
src/spectral/phasevoc.c
src/spectral/phasevoc.h
src/spectral/specdesc.c
src/spectral/specdesc.h
src/spectral/statistics.c
src/spectral/tss.c
src/spectral/tss.h
src/synth/sampler.c
src/synth/sampler.h
src/synth/wavetable.c
src/synth/wavetable.h
src/tempo/beattracking.c
src/tempo/beattracking.h
src/tempo/tempo.c
src/tempo/tempo.h
src/temporal/a_weighting.c
src/temporal/a_weighting.h
src/temporal/biquad.c
src/temporal/biquad.h
src/temporal/c_weighting.c
src/temporal/c_weighting.h
src/temporal/filter.c
src/temporal/filter.h
src/temporal/resampler.c
src/temporal/resampler.h
src/types.h
src/utils/hist.c
src/utils/hist.h
src/utils/log.c [new file with mode: 0644]
src/utils/log.h [new file with mode: 0644]
src/utils/parameter.c
src/utils/parameter.h
src/utils/scale.c
src/utils/scale.h
src/utils/windll.c [new file with mode: 0644]
src/vecutils.c
src/vecutils.h
src/wscript_build
tests/src/io/test-sink_sndfile-multi.c
tests/src/io/test-sink_sndfile.c
tests/src/io/test-source.c
tests/src/io/test-source_apple_audio.c
tests/src/io/test-source_avcodec.c
tests/src/io/test-source_sndfile.c
tests/src/io/test-source_wavread.c
tests/src/spectral/test-fft.c
tests/src/spectral/test-phasevoc.c
tests/src/tempo/test-tempo.c
tests/src/temporal/test-a_weighting.c
tests/src/temporal/test-c_weighting.c
tests/src/test-lvec.c
tests/src/utils/test-log.c [new file with mode: 0644]
tests/utils_tests.h
tests/wscript_build
wscript

diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644 (file)
index 0000000..9e247cf
--- /dev/null
@@ -0,0 +1,69 @@
+# appveyor configuration. See http://www.appveyor.com/docs/appveyor-yml
+# and http://www.appveyor.com/docs/installed-software#python
+
+environment:
+
+  matrix:
+
+    # pre-installed python version, see:
+    # http://www.appveyor.com/docs/installed-software#python
+    - PYTHON: "C:\\Python27"
+      PYTHON_VERSION: "2.7.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python27-x64"
+      PYTHON_VERSION: "2.7.x"
+      PYTHON_ARCH: "64"
+
+    - PYTHON: "C:\\Python34"
+      PYTHON_VERSION: "3.4.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python34-x64"
+      PYTHON_VERSION: "3.4.x"
+      PYTHON_ARCH: "64"
+
+    - PYTHON: "C:\\Python35"
+      PYTHON_VERSION: "3.5.x"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python35-x64"
+      PYTHON_VERSION: "3.5.x"
+      PYTHON_ARCH: "64"
+      # add path required to run preprocessor step
+      PATH_EXTRAS: "c:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin"
+
+install:
+
+  - ECHO "Installed SDKs:"
+  - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
+
+  # Check that we have the expected version and architecture for Python
+  - "%PYTHON%\\python.exe --version"
+  - "%PYTHON%\\python.exe -c \"import struct; print(struct.calcsize('P') * 8)\""
+
+  # We need wheel installed to build wheels
+  - "%PYTHON%\\python.exe -m pip install wheel"
+
+  - "SET PATH=%PATH_EXTRAS%;%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+
+  - "pip install --disable-pip-version-check --user --upgrade pip"
+  - "pip install --upgrade setuptools"
+
+before_build:
+  - curl -fsS -o waf https://waf.io/waf-1.8.22
+  - curl -fsS -o waf.bat https://raw.githubusercontent.com/waf-project/waf/master/utils/waf.bat
+
+build_script:
+  # build python module without using libaubio
+  - "pip install -r requirements.txt"
+  - "python setup.py build"
+  - "pip install ."
+  - "python python\\demos\\demo_create_test_sounds.py"
+  - "nose2 --verbose"
+  # clean up
+  - waf distclean
+  # build libaubio
+  - waf configure build --verbose
+  # build python module using libaubio dll
+  - "python setup.py build"
index f87e629..f0d0dca 100644 (file)
@@ -30,6 +30,7 @@ build/
 # doxygen
 doc/web/
 doc/full/
+doc/_build/
 
 python/gen
 python/dist
@@ -39,3 +40,7 @@ python/*.wav
 
 aubio-*.tar.bz2
 aubio-*.zip
+
+# test sounds
+python/tests/sounds
+aubio.egg-info
diff --git a/.landscape.yml b/.landscape.yml
new file mode 100644 (file)
index 0000000..d180360
--- /dev/null
@@ -0,0 +1,5 @@
+strictness: medium
+test-warnings: true
+python-targets:
+  - 2
+  - 3
index dc50e8a..73aef64 100644 (file)
-language: c
+language: python
 
-sudo: false
+matrix:
+  include:
+    - python: 3.5
+      os: linux
+      compiler: gcc
+    - python: 3.4
+      os: linux
+      compiler: gcc
+    - python: 2.7
+      os: linux
+      compiler: gcc
+    - language: C
+      os: osx
+      osx_image: xcode8
+      compiler: clang
+    - python: 3.5
+      os: linux
+      compiler: gcc
+      env: CFLAGS="-Os" WAFOPTS="--disable-samplerate --disable-sndfile"
+    - python: 3.4
+      os: linux
+      compiler: gcc
+      env: HAVE_AUBIO_DOUBLE=1 CFLAGS="-O3" WAFOPTS="--enable-fftw3"
+    - python: 2.7
+      os: linux
+      compiler: gcc
+      env: CFLAGS="`dpkg-buildflags --get CFLAGS`" LDFLAGS="`dpkg-buildflags --get LDFLAGS`"
+    - language: C
+      os: osx
+      osx_image: xcode8
+      compiler: clang
+      env: CFLAGS="-Os" HAVE_AUBIO_DOUBLE=1 WAFOPTS="--disable-accelerate"
+    - language: C
+      os: osx
+      osx_image: xcode8
+      compiler: clang
+      env: WAFOPTS="--enable-fat --disable-avcodec --disable-sndfile"
+    - language: C
+      os: osx
+      osx_image: xcode8
+      compiler: clang
+      env: WAFOPTS="--with-target-platform=ios --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
+    - language: C
+      os: osx
+      osx_image: xcode8
+      compiler: clang
+      env: WAFOPTS="--with-target-platform=iosimulator --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
+    - language: C
+      os: osx
+      osx_image: xcode8.2
+      compiler: clang
+      env: WAFOPTS="--enable-fat --disable-avcodec --disable-sndfile"
+    - language: C
+      os: osx
+      osx_image: xcode8.2
+      compiler: clang
+      env: WAFOPTS="--with-target-platform=ios --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
+    - language: C
+      os: osx
+      osx_image: xcode8.2
+      compiler: clang
+      env: WAFOPTS="--with-target-platform=iosimulator --disable-avcodec --disable-sndfile" AUBIO_NOTESTS=1
 
-compiler:
-  - gcc
-  - clang
-
-env:
-  - ARCH=i386
-  - ARCH=x86_64
+# use trusty
+dist: trusty
+sudo: required
 
 addons:
   apt:
     packages:
     - bzip2
+    - libavcodec-dev
+    - libavformat-dev
+    - libavresample-dev
+    - libavutil-dev
     - libsndfile1-dev
     - libsamplerate-dev
     - libjack-dev
     - libasound2-dev
     - libfftw3-dev
-    - python-dev
-    - python-numpy
+    - sox
+
+before_install:
+   - |
+     if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+       brew update
+       brew install sox
+       brew install ffmpeg
+       brew install libsndfile
+       export PATH="$HOME/Library/Python/2.7/bin/:$PATH"
+     fi;
+
+install:
+  - travis_retry pip install --upgrade pip
+  - travis_retry make getwaf expandwaf deps_python
+  - which pip
+  - pip --version
 
 script:
-  - make build
-  - make build_python
-  - make clean_python
-  - make clean
-  - make distcheck
+  - make create_test_sounds
+  - |
+    if [[ -z "$AUBIO_NOTESTS" ]]; then
+      make test_lib_python_clean
+      make test_python_only_clean
+    else
+      make test_lib_only_clean
+    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
index ba1d333..d2b29d3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,450 @@
+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 ]
+
+       * src/io/source.h, src/io/source_*.h: add _get_duration
+       * src/notes/notes.h: add basic notes object
+       * src/tempo/beattracking.{c,h}: add _get_period and _get_period_s
+       * src/mathutils.h: add fvec_ishift
+       * src/fvec.{c,h}: add fvec_weighted_copy
+       * src/tempo/tempo.{c,h}: add _get_period and _get_period_s, also add tatum,
+       a subdivision of the beat period, default to 4, implement get/set_delay
+       * src/**.{c,h}: use #ifdef HAVE_FOO, not #if _HAVE_FOO, add const qualifiers
+       to unmodified pointers (see #35)
+
+       [ Library ]
+
+       * src/{fmat,fvec,mathutils}.c: optimisations (using atlas or Accelerate when
+       available) for fvec_sum, fvec_mean, fvec_shift, aubio_level_lin,
+       fvec_set_all, fvec_zeros, fvec_weight, fvec_copy, fvec_weighted_copy,
+       fmat_vecmul
+       * src/aubio_priv.h: check for atlas cblas, use cblas_xswap, vDSP_dotpr,
+       protect SQR parameters, avoid redefining MIN/MAX, define PATH_MAX and PI
+       when needed, use _isnan on windows msvc 9 to avoid linking error, more
+       windows hacks
+       * src/mathutils.c: avoid for loop initial declarations [gcc], use
+       HAVE_ATLAS, use smpl_t for constants
+       * src/fmat.c: skip asserts
+       * src/spectral/{filterbank,mfcc}.c: use accelerated fmat_vecmul
+       * src/spectral/fft.c: fftw can be used odd length sizes, not Ooura,
+       factorise double / single flags, use memcpy
+       * src/spectral/phasevoc.c: fix arguments checks, return NULL when fft
+       creation failed , apply windowing for resynthesized grain, use ishift for
+       odd windows, fix scaling factors for correct reconstruction at 50 and 75%
+       overlap
+       * src/pitch/pitch.c: allow for silence == 0, improve error messages
+       * src/pitch/pitchmcomb.c: fix candidates sorting function, really comparing
+       current to next
+       * src/notes/notes.c: equivalent to previous examples/aubionotes.c results
+       * src/onset/onset.c: simplify selection of first onset, fix for "conversion
+       from 'smpl_t' to 'uint_t', possible loss of data" with msvc
+       * src/pitch/pitchmcomb.c: scan across all spectrum
+       * src/pitch/pitchyinfft.c: use fvec_weighted_copy
+       * src/{spectral/*.c,onset/*.c,tempo/*.c}: make sure win_size > 1
+       * src/io/*.c: use custom defines for {source,sink}_apple_audio, take a copy
+       of const char* path
+       * src/io/source_avcodec.c:
+        - update to libav10, libavcodec 55.34.1
+        - avoid deprecation warning, detect if we use ffmpeg or libav version
+        - check if the uri is a network stream using av_url_split, call
+        avformat_network_init() if needed
+        - check if we still need max_analyze_duration2 (closes #53, thanks to
+        @anthonylauzon)
+       * src/io/source_{avcodec,sndfile}.c: avoid modifying input param
+       * src/io/{sink,source,utils}_apple_audio.c: fix memory leak calling
+       CFRelease (closes #26, closes #27, and closes #28)
+       * src/io/sink_apple_audio.c: disable async mode for now, factorise code
+       * src/io/source_apple_audio.c: check out of bounds _seek, set s->path, quiet
+       * src/io/source_sndfile.c: fix crash, zero-pad output vector when
+       upsampling, use sf_read_double when compiling with AUBIO_DOUBLE, approximate
+       duration when resampling
+       * src/io/sink_sndfile.c: fix for double precision
+       * src/synth/sampler.c: fix typo, keeps a copy of uri
+       * src/tempo/tempo.c: do not write novelty function in output[1]
+       * src/temporal/resampler.c: make msvc happier adding a dummy variable
+       * src/temporal/filter.c: check parameters, fix filter_do_outplace to really
+       avoid modifying input
+       * src/utils/windll.c: add dll main entry point
+
+       [ Python ]
+
+       * General:
+         - new build system, new code generator
+         - Python 3 compatibility (#33), thanks to Nils Philippsen (@nphilipp)
+         - double precision compatibility
+         - simplify memory allocations, removed unneeded malloc/free calls
+         - fix memory leak (#49), check input sizes (#63) and output sizes (#60)
+         - improve indentation, clean up unused imports and variables
+         - fix comparison to None and to False
+       * setup.py: move from python/setup.py, add option to build libaubio inside
+       python-aubio (for instance with pip), add command 'generate' with option
+       '--enable-double', build with -Wdeclaration-after-statement -Werror
+       * python/ext/aubiomodule.c: fix PyMethodDef sentinel
+       * python/ext/aubioproxy.c: factorize input checks into
+       PyAubio_IsValidVector, fix windows c89 compilation, use npy_intp, not long
+       * python/ext: rewrite and simplify, safer and improved memory usage (#49),
+       improve error strings, verify actual object creation
+       * python/ext/py-source.c: added duration, check seek is not negative
+       * python/ext/py-musicutils.c: do not overwrite PyArg_ParseTuple messages
+       * python/lib/gen_code.py: new generator, switch to using custom PyObjects
+       instead of fvec, cvec, fmat, ready for double precision (defaults to single)
+       * python/lib/aubio__init__.py: use new aubio.float_type, make sure length is
+       not zero and float_type is imported
+       * python/lib/aubio/midiconv.py: fix instance checks, make sure midi2note
+       uses midi int (#33)
+       * python/lib/aubio/slicing.py: fix samplerate
+       * python/ext/aubio-types.h: add new_py_ functions to create PyObjects
+       instead of fvec_t, apply to generated and hard-coded objects
+       * python/lib/gen_external.py: improve compiler detection, fixes build on
+       windows (#55)
+       * python/lib/moresetuptools.py: helpers for windows and macos compilations
+
+       [  Python demos ]
+
+       * python/demos/demo_reading_speed.py: new reading speed tests, external
+       packages disabled by default
+       * python/demos/demo_timestretch.py: new timescale algorithm
+       * python/demos/demo_timestretch_online.py: new timescale algorithm (online
+       version)
+       * python/demos/demo_create_test_sounds.py: add script to create simple sound
+       files to test on using sox
+       * python/demos/demo_a_weighting.py: add simple demo for a_weighting
+       * python/demos/demo_filter.py: moved from _a_weighting
+       * python/demos/demo_mfcc.py: use n_coeffs
+       * python/demos/demo_bpm_extract.py: add exception type, avoid {} as default
+       argument value
+       * python/demos/demo_pysoundcard_*: update to pysoundcard 0.5.2 (closes #42)
+       * python/scripts/aubiocut: fix usage string output
+
+       [ Python tests ]
+
+       * python/tests/run_all_tests,*.py: switch to nose2, fix most prospect warnings
+       * python/tests/test_fvec.py: add test_pass_to_numpy, cope with accumulated
+       errors
+       * python/tests/test_cvec.py: simplify, add more tests
+       * python/tests/test_fft.py: more tests, fft.do to clash on wrong size
+       inputs, f.rdo input size, cvec is large enough, memory tests, avoid
+       VisibleDeprecationWarning
+       * python/tests/test_filterbank.py: check for wrong values, ValueError raised
+       * python/tests/test_filter.py: add tests
+       * python/tests/test_musicutils.py: simplify, check TypeError is raised
+       * python/tests/test_mfcc.py: more tests, check for wrong input size (see #63)
+       * python/tests/test_mathutils: fix test_miditobin test, can also raise
+       NotImplementedError (darwin)
+       * python/tests/test_note2midi.py: more tests, use unicode_literals
+       * python/tests/test_phasevoc.py: add a note about ocasional crash check
+       perfect reconstruction for overlap > 75% add 50% overlap test, fix duplicate
+       test name, add wrong sized input tests
+       * python/tests/test_sink.py: remove useless many_sinks_not_closed and cruft
+       * python/tests/test_source.py: simplify, quieten, skip tests if no test sounds
+       * python/tests/test_specdesc.py: check for wrong values, skip wrong name
+       test, use correct input size (see #63)
+       * python/tests/utils.py: try reopening the file is deleting it fails on windows
+       * python/VERSION: removed, use same VERSION file for libaubio and python-aubio
+       * MANIFEST.in: move from python/, update contents
+       * nose2.cfg: add minimal config, set multiprocess always-on=false (fixes
+       coverage, pass -N to speed up the tests)
+
+       [ Tools ]
+
+       * examples/*.c: add time format option
+       * examples/{aubioonset,aubiotrack}.c: also emit midi note, thanks to
+       @topas-rec (closes #62)
+       * examples/: use outmsg to print notes (fixes #8)
+       * examples/aubionotes.c: use new aubio_notes object
+       * examples/aubiotrack.c: enable -O and -t options, fix is_beat/is_silence
+       types
+       * examples/{parse_args,utils}.h: check in config.h if getopt.h was found, or
+       build without for msvc, more windows hacks
+       * examples/utils.c: change send_noteon to accept floating point midi note number
+
+       [ Tests ]
+
+       * tests/src/io/test-source_apple_audio.c: shorten long line
+       * tests/src/io/test-source_avcodec.c: use HAVE_LIBAV, closes #10
+       * tests/src/temporal: avoid crash, clarify
+       * tests/src/tempo/test-tempo.c: tempo back to only one output
+       * tests/src/test-delnull.c: improve test, avoid segfaults
+       * tests/src/test-lvec.c: use AUBIO_LSMP_FMT
+       * tests/utils_tests.h: add VA_ARGS versions of variadic macros
+       * tests/utils_tests.h: also use custom srandom/random when compiling with
+       -std=c99
+       * tests/utils_tests.h: make sure M_PI and RAND_MAX are defined
+
+       [ Build ]
+
+       * Makefile: set waf to 1.8.22 for now, new targets create_test_sounds,
+       build_python, test_python, clean_python, build_python3, clean_python3,
+       test_pure_python, test_pure_python_wheel, (use test_pure_* targets to build
+       without libaubio), use 'HAVE_DOUBLE=1 make' to build in double precision
+       * scripts/build_apple_frameworks: add script to build macosx and ios
+       frameworks (see #34, #43)
+       * scripts/build_emscripten: add script to build with emcc and co
+       * scripts/build_mingw: add script to cross-compile using mingw
+       * scripts/get_waf.sh: added simple script to fetch latest waf
+       * scripts/setenv_local.sh: set environment to run from built source tree
+       * scripts/setenv_local.sh: update to new python-aubio build location
+       * tests/wscript_build: do not install test programs
+       * tests/wscript_build, src/wscript_build: use 'use =', simplify
+       * src/wscript_build: enable shared lib on ios, static lib on windows
+       * wscript:
+         - update --enable-foo to fail if foo is not found
+         - add -mmacosx-version-min=10.4 on darwin
+         - add '-fembed-bitcode' on ios (closes #31), min to 6.1
+         - make fat build, add option to not build with Accelerate framework
+         - add option to not build with CoreAudio/AudioToolbox
+         - add --disable-docs option
+         - add -lm detection
+         - pass HAVE_AUBIO_DOUBLE in compiler arguments
+         - first check for headers, make getopt.h and unistd.h optional
+         - check HAVE_AV* from ctx.env
+         - make msvc compiler quieter, add /MD and /D_CRT_SECURE_NO_WARNINGS
+         - check if we find atlas/cblas.h
+         - new build platform emscripten
+         - more cleanups and updates
+
+       [ Only in git ]
+
+       * .travis.yml: config for https://travis-ci.org/aubio/aubio
+       * .appveyor.yml: config for https://ci.appveyor.com/project/piem/aubio
+       * .landscape.yml: config for https://landscape.io/github/aubio/aubio
+       * conda recipes: see https://github.com/conda/conda-recipes#387
+       * .gitignore: add python/tests/sounds and .egg-info
+
+       [ General ]
+
+       * src/: remove trailing spaces, improve doxygen strings, update copyrights,
+       fix typos
+       * src/onset/onset.h: fix description of get/set_delay functions
+       * src/spectral/mfcc.h: add link to reference implementation
+       * src/spectral/filterbank_mel.h: update reference url
+       * src/musicutils.h: update link to Bernardini's paper, improve doc
+       * doc/aubiomfcc.txt: add a note about the output
+       * doc/*.cfg: update to Doxygen 1.8.8
+       * python/README.md: fix typo (thanks to Sam Alexander), document how to
+       build in a virtualenv (see #2)
+       * README.md: minor updates, link to python/README.md, switch to https
+       * VERSION: bump to 0.4.3
+
 2015-08-01 Paul Brossier <piem@aubio.org>
 
        [ Interface ]
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..c39c6d3
--- /dev/null
@@ -0,0 +1,27 @@
+include AUTHORS COPYING README.md VERSION ChangeLog
+include python/README.md
+include Makefile wscript */wscript_build
+include waf waflib/* waflib/*/*
+exclude waflib/__pycache__/*
+include aubio.pc.in
+include nose2.cfg
+include requirements.txt
+include src/*.c src/*.h
+include src/*/*.c src/*/*.h
+include examples/*.c examples/*.h
+include tests/*.h tests/*/*.c tests/*/*/*.c
+include python/ext/*.h
+include python/__init__.py
+include python/lib/__init__.py
+include python/lib/moresetuptools.py
+include python/lib/gen_external.py
+include python/lib/gen_code.py
+include python/tests/run_all_tests
+include python/tests/*.py
+include python/tests/eval_pitch
+include python/demos/*.py
+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/*
index 125ec28..d51516a 100644 (file)
--- a/Makefile
+++ b/Makefile
+#!/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.9.6
+
+#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
+
+SOX=sox
+
+TESTSOUNDS := python/tests/sounds
+
 all: build
 
 checkwaf:
        @[ -f waf ] || make getwaf
 
 getwaf:
-       curl https://waf.io/waf-1.8.14 > waf
-       @[ -d wafilb ] || rm -fr waflib
-       @chmod +x waf && ./waf --help > /dev/null
-       @mv .waf*/waflib . && rm -fr .waf*
-       @sed '/^#==>$$/,$$d' waf > waf2 && mv waf2 waf
-       @chmod +x waf
+       ./scripts/get_waf.sh
+
+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)
+
+build: configure
+       $(WAFCMD) build $(WAFOPTS)
 
-build: checkwaf
-       ./waf configure
-       ./waf build
+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:
-       cd python && ./setup.py build
+       # build python-aubio, using locally built libaubio if found
+       python ./setup.py build
+
+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
+
+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 $(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
+       # also run with nose, multiple processes
+       nose2 -N 4
 
 clean_python:
-       cd python && ./setup.py clean
+       ./setup.py clean
+
+check_clean_python:
+       # check cleaning a second time works
+       make clean_python
+       make clean_python
+
+clean: checkwaf
+       # optionnaly clean before build
+       -$(WAFCMD) clean
+       # remove possible left overs
+       -rm -rf doc/_build
 
-clean:
-       ./waf clean
+check_clean:
+       # check cleaning after build works
+       $(WAFCMD) clean
+       # check cleaning a second time works
+       $(WAFCMD) clean
 
-distcheck: build
-       ./waf distcheck
+distclean:
+       $(WAFCMD) distclean
+       -rm -rf doc/_build/
+       -rm -rf doc/web/
+
+check_distclean:
+       make distclean
+
+distcheck: checkwaf
+       $(WAFCMD) distcheck $(WAFOPTS)
 
 help:
-       ./waf --help
+       $(WAFCMD) --help
+
+create_test_sounds:
+       -[ -z `which $(SOX)` ] && ( echo $(SOX) could not be found) || true
+       -mkdir -p $(TESTSOUNDS)
+       -$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_1f_silence.wav"      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"      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
+
+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
index 8957a36..adaf128 100644 (file)
--- a/README.md
+++ b/README.md
@@ -30,7 +30,8 @@ Python module
 -------------
 
 A python module to access the library functions is also provided. Please see
-the file `python/README` for more information on how to use it.
+the file [`python/README.md`](python/README.md) for more information on how to
+use it.
 
 Examples tools
 --------------
@@ -70,8 +71,8 @@ The latest version of the documentation can be found at:
 
   https://aubio.org/documentation
 
-Installation and Build Instructions
------------------------------------
+Build Instructions
+------------------
 
 A number of distributions already include aubio. Check your favorite package
 management system, or have a look at the [download
@@ -81,13 +82,41 @@ aubio uses [waf](https://waf.io/) to configure, compile, and test the source:
 
     ./waf configure
     ./waf build
-    sudo ./waf install
 
 If waf is not found in the directory, you can download and install it with:
 
     make getwaf
 
-aubio compiles on Linux, Mac OS X, Cygwin, and iOS.
+aubio compiles on Linux, Mac OS X, Windows, Cygwin, and iOS.
+
+Installation
+------------
+
+To install aubio library and headers on your system, use:
+
+    sudo ./waf install
+
+To uninstall:
+
+    sudo ./waf uninstall
+
+If you don't have root access to install libaubio on your system, you can use
+libaubio without installing libaubio either by setting `LD_LIBRARY_PATH`, or by
+copying it to `~/lib`.
+
+On Linux, you should be able to set `LD_LIBRARY_PATH` with:
+
+    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/build/src
+
+On Mac OS X, a copy or a symlink can be made in `~/lib`:
+
+    $ mkdir -p ~/lib
+    $ ln -sf $PWD/build/src/libaubio*.dylib ~/lib/
+
+Note on Mac OS X systems older than El Capitan (10.11), the `DYLD_LIBRARY_PATH`
+variable can be set as follows:
+
+    $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$PWD/build/src
 
 Credits and Publications
 ------------------------
@@ -133,7 +162,7 @@ Questions, comments, suggestions, and contributions are welcome. Use the
 mailing list: <aubio-user@aubio.org>.
 
 To subscribe to the list, use the mailman form:
-http://lists.aubio.org/listinfo/aubio-user/
+https://lists.aubio.org/listinfo/aubio-user/
 
 Alternatively, feel free to contact directly the author.
 
@@ -141,7 +170,7 @@ Alternatively, feel free to contact directly the author.
 Copyright and License Information
 ---------------------------------
 
-Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+Copyright (C) 2003-2016 Paul Brossier <piem@aubio.org>
 
 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
diff --git a/VERSION b/VERSION
index f1a8a48..2a2b20a 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1,7 +1,7 @@
 AUBIO_MAJOR_VERSION=0
 AUBIO_MINOR_VERSION=4
-AUBIO_PATCH_VERSION=3
+AUBIO_PATCH_VERSION=5
 AUBIO_VERSION_STATUS='~alpha'
-LIBAUBIO_LT_CUR=4
-LIBAUBIO_LT_REV=2
-LIBAUBIO_LT_AGE=2
+LIBAUBIO_LT_CUR=5
+LIBAUBIO_LT_REV=1
+LIBAUBIO_LT_AGE=5
index 8b0b81d..b93571d 100644 (file)
@@ -39,9 +39,11 @@ help:
        @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."
diff --git a/doc/android.rst b/doc/android.rst
new file mode 100644 (file)
index 0000000..c46eb30
--- /dev/null
@@ -0,0 +1,9 @@
+.. _android:
+
+Building aubio for Android
+--------------------------
+
+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``.
index be19dad..8023460 100644 (file)
@@ -34,9 +34,9 @@ OPTIONS
   -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.
index afeafe3..6398d9a 100644 (file)
@@ -6,6 +6,7 @@ SYNOPSIS
   aubiomfcc source
   aubiomfcc [[-i] source]
             [-r rate] [-B win] [-H hop]
+            [-T time-format]
             [-v] [-h]
 
 DESCRIPTION
@@ -37,6 +38,9 @@ OPTIONS
   -H, --hopsize hop  The number of samples between two consecutive analysis.
   Defaults to 256.
 
+  -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
+  seconds.
+
   -h, --help  Print a short help message and exit.
 
   -v, --verbose  Be verbose.
index 190fc72..0355040 100644 (file)
@@ -8,6 +8,7 @@ SYNOPSIS
              [-r rate] [-B win] [-H hop]
              [-O method] [-t thres]
              [-p method] [-u unit] [-l thres]
+             [-T time-format]
              [-s sil]
              [-j] [-v] [-h]
 
@@ -49,6 +50,9 @@ OPTIONS
   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'.
 
@@ -64,6 +68,9 @@ OPTIONS
   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.
 
+  -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
+  seconds.
+
   -j, --jack  Use Jack input/output. You will need a Jack connection
   controller to feed aubio some signal and listen to its output.
 
index f9d3783..e3cb560 100644 (file)
@@ -7,8 +7,10 @@ SYNOPSIS
   aubioonset [[-i] source] [-o sink]
              [-r rate] [-B win] [-H hop]
              [-O method] [-t thres]
+             [-T time-format]
              [-s sil] [-m] [-f]
-             [-j] [-v] [-h]
+             [-j] [-N miditap-note] [-V miditap-velo]
+             [-v] [-h]
 
 DESCRIPTION
 
@@ -47,14 +49,20 @@ OPTIONS
   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.
 
+  -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
+  seconds.
+
   -m, --mix-input  Mix source signal to the output signal before writing to
   sink.
 
@@ -63,6 +71,10 @@ OPTIONS
   -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.
 
   -v, --verbose  Be verbose.
index 1fc8205..1313975 100644 (file)
@@ -7,6 +7,7 @@ SYNOPSIS
   aubiopitch [[-i] source] [-o sink]
              [-r rate] [-B win] [-H hop]
              [-p method] [-u unit] [-l thres]
+             [-T time-format]
              [-s sil] [-f]
              [-v] [-h] [-j]
 
@@ -59,6 +60,9 @@ OPTIONS
   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.
 
+  -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
+  seconds.
+
   -m, --mix-input  Mix source signal to the output signal before writing to
   sink.
 
index eb11ae0..9428315 100644 (file)
@@ -6,6 +6,7 @@ SYNOPSIS
   aubioquiet source
   aubioquiet [[-i] source]
              [-r rate] [-B win] [-H hop]
+             [-T time-format]
              [-s sil]
              [-v] [-h]
 
@@ -38,6 +39,9 @@ OPTIONS
   -s, --silence sil  Set the silence threshold, in dB, under which the pitch
   will not be detected. Defaults to -90.0.
 
+  -T, --timeformat format  Set time format (samples, ms, seconds). Defaults to
+  seconds.
+
   -h, --help  Print a short help message and exit.
 
   -v, --verbose  Be verbose.
index 753e97f..263157f 100644 (file)
@@ -6,8 +6,10 @@ SYNOPSIS
   aubiotrack source
   aubiotrack [[-i] source] [-o sink]
              [-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
 
@@ -53,6 +55,13 @@ OPTIONS
   -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.
+
   -h, --help  Print a short help message and exit.
 
   -v, --verbose  Be verbose.
diff --git a/doc/building.rst b/doc/building.rst
new file mode 100644 (file)
index 0000000..5c52a30
--- /dev/null
@@ -0,0 +1,98 @@
+.. highlight:: bash
+
+.. _building:
+
+Building aubio
+==============
+
+.. note::
+    To download a prebuilt version of aubio, see :ref:`download`.
+
+aubio uses `waf`_ to configure, compile, and test the source.
+A copy of waf is included in aubio tarball, so all you need is a terminal,
+a compiler, and a recent version of python installed.
+
+.. note::
+    Make sure you have all the :ref:`requirements` you want before building.
+
+Latest release
+--------------
+
+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
+
+Git repository
+--------------
+
+The **latest git branch** can be obtained with::
+
+        $ git clone git://git.aubio.org/git/aubio
+        $ cd aubio
+
+The following command will fetch the correct `waf`_ version (not included in
+aubio's git)::
+
+        $ ./scripts/get_waf.sh
+
+.. note::
+
+  Windows users without `Git Bash`_ installed will want to use the following
+  commands instead:
+
+  .. code:: bash
+
+        $ 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
+
+
+Compiling
+---------
+
+To compile the C library, examples programs, and tests, run::
+
+        $ ./waf configure
+
+Check out the available options using ``./waf configure --help``. Once
+you are done with configuration, you can start building::
+
+        $ ./waf build
+
+To install the freshly built C library and tools, simply run the following
+command::
+
+        $ sudo ./waf install
+
+.. note::
+  Windows users should simply run ``waf``, without the leading ``./``. For
+  instance:
+
+  .. code:: bash
+
+       $ waf configure build
+
+Cleaning
+--------
+
+If you wish to uninstall the files installed by the ``install`` command, use
+``uninstall``::
+
+        $ sudo ./waf uninstall
+
+To clean the source directory, use the ``clean`` command::
+
+        $ ./waf clean
+
+To also forget the options previously passed to the last ``./waf configure``
+invocation, use the ``distclean`` command::
+
+        $ ./waf distclean
+
+.. _waf: https://waf.io/
+
+.. _Git Bash: https://git-for-windows.github.io/
+
+.. toctree::
+   :maxdepth: 2
diff --git a/doc/cli.rst b/doc/cli.rst
new file mode 100644 (file)
index 0000000..2dc2f07
--- /dev/null
@@ -0,0 +1,59 @@
+.. _manpages:
+
+Command line tools
+==================
+
+A few simple 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
+ - ``aubiomfcc`` computes Mel-frequency Cepstrum Coefficients
+ - ``aubiotrack`` outputs the time stamp of detected beats
+ - ``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
+
+
+.. toctree::
+
+   cli_features
+
+
+``aubioonset``
+--------------
+
+.. literalinclude:: aubioonset.txt
+
+``aubiopitch``
+--------------
+
+.. literalinclude:: aubiopitch.txt
+
+``aubiomfcc``
+--------------
+
+.. literalinclude:: aubiomfcc.txt
+
+``aubiotrack``
+--------------
+
+.. literalinclude:: aubiotrack.txt
+
+``aubionotes``
+--------------
+
+.. literalinclude:: aubionotes.txt
+
+``aubioquiet``
+--------------
+
+.. literalinclude:: aubioquiet.txt
+
+``aubiocut``
+--------------
+
+.. literalinclude:: aubiocut.txt
diff --git a/doc/cli_features.rst b/doc/cli_features.rst
new file mode 100644 (file)
index 0000000..ab77c3a
--- /dev/null
@@ -0,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).
index 48e5a4e..ad030c6 100644 (file)
@@ -16,7 +16,7 @@ import sys, os
 # 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 -----------------------------------------------------
 
@@ -41,7 +41,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'aubio'
-copyright = u'2014, Paul Brossier'
+copyright = u'2016, 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
@@ -50,7 +50,7 @@ copyright = u'2014, Paul Brossier'
 # The short X.Y version.
 version = '0.4'
 # The full version, including alpha/beta/rc tags.
-release = 'latest'
+release = '0.4.5~alpha'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -91,7 +91,10 @@ modindex_common_prefix = ['aubio.']
 
 # 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 +123,7 @@ html_theme = 'default'
 # 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 +153,7 @@ html_static_path = ['_static']
 #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 +243,6 @@ texinfo_documents = [
 
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
 #texinfo_show_urls = 'footnote'
+
+def setup(app):
+    if release.endswith('~alpha'): app.tags.add('devel')
diff --git a/doc/debian_packages.rst b/doc/debian_packages.rst
new file mode 100644 (file)
index 0000000..6680f1a
--- /dev/null
@@ -0,0 +1,16 @@
+Debian/Ubuntu packages
+----------------------
+
+For the latest Debian packages, see https://packages.debian.org/src:aubio.
+
+For the latest Ubuntu packages, see http://packages.ubuntu.com/src:aubio.
+
+For the latest version of the packages, see
+https://anonscm.debian.org/cgit/collab-maint/aubio.git/. Use
+``git-buildpackage`` to build from the git repository. For instance:
+
+.. code-block:: bash
+
+    $ git clone git://anonscm.debian.org/collab-maint/aubio.git
+    $ cd aubio
+    $ git buildpackage
diff --git a/doc/develop.rst b/doc/develop.rst
new file mode 100644 (file)
index 0000000..cb39dd7
--- /dev/null
@@ -0,0 +1,102 @@
+.. _develop:
+
+Developping with aubio
+======================
+
+Read `Contribute`_ to report issues and request new features.
+
+See `Doxygen documentation`_ for the complete documentation of the C library,
+built using `Doxygen <http://www.doxygen.org/>`_.
+
+Below is a brief `Library overview`_.
+
+Library overview
+----------------
+
+Here is a brief overview of the C library. See also the `Doxygen
+documentation`_ for a more detailed list of available functions.
+
+Vectors and matrix
+``````````````````
+
+``fvec_t`` are used to hold vectors of float (``smpl_t``).
+
+.. literalinclude:: ../tests/src/test-fvec.c
+   :language: C
+   :lines: 7
+
+
+.. code-block:: C
+
+        // set some elements
+        vec->data[511] = 2.;
+        vec->data[vec->length-2] = 1.;
+
+Similarly, ``fmat_t`` are used to hold matrix of floats.
+
+.. literalinclude:: ../tests/src/test-fmat.c
+   :language: C
+   :lines: 9-19
+
+Reading a sound file
+````````````````````
+In this example, ``aubio_source`` is used to read a media file.
+
+First, create the objects we need.
+
+.. literalinclude:: ../tests/src/io/test-source.c
+   :language: C
+   :lines: 22-24, 30-32, 34
+
+.. note::
+   With ``samplerate = 0``, ``aubio_source`` will be created with the file's
+   original samplerate.
+
+Now for the processing loop:
+
+.. literalinclude:: ../tests/src/io/test-source.c
+   :language: C
+   :lines: 40-44
+
+At the end of the processing loop, clean-up and de-allocate memory:
+
+.. literalinclude:: ../tests/src/io/test-source.c
+   :language: C
+   :lines: 50-56
+
+See the complete example: :download:`test-source.c
+<../tests/src/io/test-source.c>`.
+
+Computing the spectrum
+``````````````````````
+
+Now let's create a phase vocoder:
+
+.. literalinclude:: ../tests/src/spectral/test-phasevoc.c
+   :language: C
+   :lines: 6-11
+
+The processing loop could now look like:
+
+.. literalinclude:: ../tests/src/spectral/test-phasevoc.c
+   :language: C
+   :lines: 21-35
+
+See the complete example: :download:`test-phasevoc.c
+<../tests/src/spectral/test-phasevoc.c>`.
+
+.. _doxygen-documentation:
+
+Doxygen documentation
+---------------------
+
+The latest version of the doxygen documentation is available at:
+
+    https://aubio.org/doc/latest
+
+Contribute
+----------
+
+Please report any issue and feature request at the `Github issue tracker
+<https://github.com/aubio/aubio/issues>`_. Patches and pull-requests welcome!
+
diff --git a/doc/download.rst b/doc/download.rst
new file mode 100644 (file)
index 0000000..a80cf2d
--- /dev/null
@@ -0,0 +1,20 @@
+.. _download:
+
+Downloading aubio
+=================
+
+A number of distributions already include aubio. Check your favorite package
+management system, or have a look at the `aubio download page
+<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::
+
+  debian_packages
+  xcode_frameworks
+  android
+
+To compile aubio from source, read :ref:`building`.
index 9fc2225..f7d8d84 100644 (file)
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.5
+# Doxyfile 1.8.8
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -38,7 +38,7 @@ PROJECT_NAME           = aubio
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = "0.4.2~alpha full"
+PROJECT_NUMBER         = "0.4.5~alpha"
 
 # 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
@@ -70,15 +70,25 @@ OUTPUT_DIRECTORY       = full
 
 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, Brazilian, Catalan, Chinese, Chinese-
-# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi,
-# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en,
-# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish,
-# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
-# Turkish, Ukrainian and Vietnamese.
+# 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
@@ -259,9 +269,12 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 # 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, 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.
+# 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.
 #
@@ -500,6 +513,13 @@ HIDE_SCOPE_NAMES       = NO
 
 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.
@@ -521,7 +541,8 @@ 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.
+# 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
@@ -659,8 +680,7 @@ LAYOUT_FILE            =
 # 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. Do not use file names with spaces, bibtex cannot handle them. See
-# also \cite for info how to create references.
+# search path. See also \cite for info how to create references.
 
 CITE_BIB_FILES         =
 
@@ -959,6 +979,25 @@ USE_HTAGS              = NO
 
 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
 #---------------------------------------------------------------------------
@@ -1051,13 +1090,15 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
-# defined cascading style sheet that is included after the standard style sheets
+# 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 file to the output directory. For an example
-# see the documentation.
+# 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  =
@@ -1222,7 +1263,8 @@ GENERATE_CHI           = NO
 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.
+# 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.
 
@@ -1422,7 +1464,7 @@ MATHJAX_FORMAT         = HTML-CSS
 # 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
@@ -1462,11 +1504,11 @@ 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 flavours 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.
+# 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.
 
@@ -1594,17 +1636,19 @@ EXTRA_PACKAGES         =
 #
 # 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. Doxygen will
-# replace them by respectively the title of the page, the current date and time,
-# only the current date, the version number of doxygen, the project name (see
-# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# $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.
+# 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.
@@ -1628,7 +1672,7 @@ LATEX_EXTRA_FILES      =
 
 PDF_HYPERLINKS         = YES
 
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# 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.
@@ -1754,6 +1798,13 @@ MAN_OUTPUT             = man
 
 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
@@ -1781,18 +1832,6 @@ GENERATE_XML           = NO
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_DTD                =
-
 # 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
@@ -1820,6 +1859,15 @@ GENERATE_DOCBOOK       = NO
 
 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
 #---------------------------------------------------------------------------
@@ -1939,9 +1987,9 @@ PREDEFINED             =
 EXPAND_AS_DEFINED      =
 
 # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all refrences 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
+# 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.
@@ -1961,7 +2009,7 @@ SKIP_FUNCTION_MACROS   = YES
 # 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 an unique name (where the name does NOT include
+# 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.
 
@@ -2021,6 +2069,13 @@ CLASS_DIAGRAMS         = YES
 
 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.
@@ -2032,7 +2087,7 @@ HIDE_UNDOC_RELATIONS   = NO
 # 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: NO.
+# The default value is: YES.
 
 HAVE_DOT               = NO
 
@@ -2046,7 +2101,7 @@ HAVE_DOT               = NO
 
 DOT_NUM_THREADS        = 0
 
-# When you want a differently looking font n the dot files that doxygen
+# 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
@@ -2184,7 +2239,9 @@ DIRECTORY_GRAPH        = YES
 # 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, jpg, gif and svg.
+# 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.
 
@@ -2221,6 +2278,21 @@ DOTFILE_DIRS           =
 
 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
index 70b9df8..c9dfc84 100644 (file)
@@ -1,16 +1,51 @@
-aubio documentation
-===================
+Welcome
+=======
 
-aubio is a collection of algorithms and tools 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.
+aubio is a collection of algorithms and tools to label and transform music and
+sounds. It scans or `listens` to audio signals and attempts to detect musical
+events. For instance, when a drum is hit, at which frequency is a note, or at
+what tempo is a rhythmic melody.
 
-Its features include segmenting a sound file before each of its attacks,
+aubio features include segmenting a sound file before each of its attacks,
 performing pitch detection, tapping the beat and producing midi streams from
 live audio.
 
-aubio provide several algorithms and routines, including:
+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
+========
+
+aubio provides several algorithms and routines, including:
 
 - several onset detection methods
 - different pitch detection methods
@@ -21,93 +56,40 @@ aubio provide several algorithms and routines, including:
 - 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
 found in the results.
 
-Python module
--------------
-
-A python module to access the library functions is also provided. Please see
-the file ``python/README`` for more information on how to use it.
-
-Examples tools
---------------
-
-A few simple 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
- - ``aubiomfcc`` computes Mel-frequency Cepstrum Coefficients
- - ``aubiotrack`` outputs the time stamp of detected beats
- - ``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
-
-C API basics
-------------
-
-The library is written in C and is optimised for speed and portability.
-
-The C API is designed in the following way:
-
-.. code-block:: c
-
-    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.
-
-.. code-block:: bash
-
-    ./waf configure
-    ./waf build
-    sudo ./waf install
-
-aubio compiles on Linux, Mac OS X, Cygwin, and iPhone.
-
-Documentation
--------------
-
-- Manual pages: http://aubio.org/documentation
-- API documentation: http://aubio.org/doc/latest/
-
-Contribute
-----------
-
-- Issue Tracker: https://github.com/piem/aubio/issues
-- Source Code: https://github.com/piem/aubio
-
-Contact info
-------------
+Copyright
+=========
 
-The home page of this project can be found at: http://aubio.org/
+Copyright © 2003-2016 Paul Brossier <piem@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/
+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
+<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.
 
-Alternatively, feel free to contact directly the author.
+.. note::
 
+   aubio is not MIT or BSD licensed. Contact the author if you need it in your
+   commercial product.
 
-Contents
---------
+Content
+=======
 
 .. toctree::
-   :maxdepth: 1
+   :maxdepth: 2
 
    installing
    python_module
+   cli
+   develop
index 6629e38..defbcc3 100644 (file)
@@ -1,65 +1,19 @@
-.. highlight:: bash
-
 Installing aubio
 ================
 
-A number of distributions already include aubio. Check your favorite package
-management system, or have a look at the `download page
-<http://aubio.org/download>`_.
-
-aubio uses `waf <https://waf.io/>`_ to configure, compile, and test the source.
-A copy of ``waf`` is included along aubio, so all you need is a ``terminal``
-and a recent ``python`` installed.
-
-Source code
------------
-
-Check out the `download page <http://aubio.org/download>`_ for more options:
-http://aubio.org/download.
-
-The latest stable release can be found at http://aubio.org/pub/::
-
-        $ curl -O http://aubio.org/pub/aubio-0.4.1.tar.bz2
-        $ tar xf aubio-0.4.1.tar.bz2
-        $ cd aubio-0.4.1
-
-The latest develop branch can be obtained with::
-
-        $ git clone git://git.aubio.org/git/aubio/ aubio-devel
-        $ cd aubio-devel
-        $ git fetch origin develop:develop
-        $ git checkout develop
-
-Compiling
----------
-
-To compile the C library, examples programs, and tests, run::
-
-        $ ./waf configure
-
-Check out the available options using ``./waf configure --help | less``. Once
-you are done with configuration, you can start building::
-
-        $ ./waf build
-
-To install the freshly built C library and tools, simply run the following
-command::
-
-        $ sudo ./waf install
-
-Cleaning
---------
-
-If you wish to uninstall the files installed by the ``install`` command, use
-``uninstall``::
+aubio runs on Linux, Windows, macOS, iOS, Android, and probably a few others
+operating systems.
 
-        $ sudo ./waf uninstall
+To download a pre-compiled version of the library, head to :ref:`download`.
 
-To clean the source directory, use the ``clean`` command::
+To install the python extension, head to :ref:`python`.
 
-        $ ./waf clean
+To compile aubio form source, first check the :ref:`requirements`, then read
+:ref:`building`.
 
-To also forget the options previously passed to the last ``./waf configure``
-invocation, use the ``distclean`` command::
+.. toctree::
+   :maxdepth: 2
 
-        $ ./waf distclean
+   download
+   building
+   requirements
index eab5cd4..ed834f5 100644 (file)
@@ -1,5 +1,18 @@
-aubio Python module
-===================
+.. _python:
+
+Python module
+=============
+
+The aubio extension for Python is available for Python 2.7 and Python 3.
+
+Installing aubio with pip
+-------------------------
+
+aubio can now be installed using ``pip``:
+
+.. code-block:: bash
+
+    $ pip install aubio
 
 Building the module
 -------------------
@@ -8,26 +21,53 @@ From ``aubio`` source directory, run the following:
 
 .. code-block:: bash
 
-    $ cd python
+    $ ./setup.py clean
     $ ./setup.py build
     $ sudo ./setup.py install
 
-Using the module
-----------------
+Using aubio in python
+---------------------
+
+Once you have python-aubio installed, you should be able to run ``python -c
+"import aubio; print(aubio.version)"``.
+
+A simple example
+................
+
+Here is a :download:`simple script <../python/demos/demo_source_simple.py>`
+that reads all the samples from a media file:
+
+.. literalinclude:: ../python/demos/demo_source_simple.py
+   :language: python
+
+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:
+
+* read an input media file (``aubio.source``)
+
+* filter it using an `A-weighting <https://en.wikipedia.org/wiki/A-weighting>`_
+  filter (``aubio.digital_filter``)
+
+* write result to a new file (``aubio.sink``)
+
+.. literalinclude:: ../python/demos/demo_filter.py
+   :language: python
 
-To use the python module, simply import aubio:
+More demos
+..........
 
-.. code-block:: python
+Check out the `python demos folder`_ for more examples.
 
-        #! /usr/bin/env python
-        import aubio
+Python tests
+------------
 
-        s = aubio.source(sys.argv[1], 0, 256)
-        while True:
-          samples, read = s()
-          print samples
-          if read < 256: break
+A number of `python tests`_ are provided. To run them, use
+``python/tests/run_all_tests``.
 
-Check out the `python demos for aubio
-<https://github.com/piem/aubio/blob/develop/python/demos/>`_ for more examples.
+.. _python demos folder: https://github.com/aubio/aubio/blob/master/python/demos
+.. _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
 
diff --git a/doc/requirements.rst b/doc/requirements.rst
new file mode 100644 (file)
index 0000000..8a74eb0
--- /dev/null
@@ -0,0 +1,242 @@
+.. _requirements:
+
+Build options
+=============
+
+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 formas add more features to aubio, you can use one
+or all of the `following libraries <extlibs>`_.
+
+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.
+
+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``
+
+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``
+
+Platform notes
+--------------
+
+On all platforms, you will need to have installed:
+
+ - a compiler (gcc, clang, msvc, ...)
+ - python (any version >= 2.7, including 3.x)
+ - a terminal to run command lines in
+
+Linux
+.....
+
+The following `External libraries`_ will be used if found: `libav`_,
+`libsamplerate`_, `libsndfile`_, `libfftw3`_.
+
+macOS
+.....
+
+The following system frameworks will be used on Mac OS X systems:
+
+  - `Accelerate <https://developer.apple.com/reference/accelerate>`_ to compute
+    FFTs and other vectorized operations optimally.
+
+  - `CoreAudio <https://developer.apple.com/reference/coreaudio>`_ and
+    `AudioToolbox <https://developer.apple.com/reference/audiotoolbox>`_ to
+    decode audio from files and network streams.
+
+.. note::
+
+  To build a fat binary for both ``i386`` and ``x86_64``, use ``./waf configure
+  --enable-fat``.
+
+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
+.......
+
+To use a specific version of the compiler, ``--msvc_version``. To build for a
+specific architecture, use ``--msvc_target``. For instance, to build aubio
+for ``x86`` using ``msvc 12.0``, use:
+
+.. code:: bash
+
+    waf configure --msvc_version='msvc 12.0' --msvc_target='x86'
+
+
+The following `External libraries`_ will be used if found: `libav`_,
+`libsamplerate`_, `libsndfile`_, `libfftw3`_.
+
+iOS
+...
+
+The following system frameworks will be used on iOS and iOS Simulator.
+
+  - `Accelerate <https://developer.apple.com/reference/accelerate>`_ to compute
+    FFTs and other vectorized operations optimally.
+
+  - `CoreAudio <https://developer.apple.com/reference/coreaudio>`_ and
+    `AudioToolbox <https://developer.apple.com/reference/audiotoolbox>`_ to
+    decode audio from files and network streams.
+
+To build aubio for iOS, configure with ``--with-target-platform=ios``. For the
+iOS Simulator, use ``--with-target-platform=iosimulator`` instead.
+
+By default, aubio is built with the following flags on iOS:
+
+.. code:: bash
+
+    CFLAGS="-fembed-bitcode -arch arm64 -arch armv7 -arch armv7s -miphoneos-version-min=6.1"
+
+and on iOS Simulator:
+
+.. code::
+
+    CFLAGS="-arch i386 -arch x86_64 -mios-simulator-version-min=6.1"
+
+Set ``CFLAGS`` and ``LINKFLAGS`` to change these default values, or edit
+``wscript`` directly.
+
+Other options
+-------------
+
+Some additional options can be passed to the configure step. For the complete
+list of options, run:
+
+.. code:: bash
+
+    $ ./waf --help
+
+Here is an example of a custom command:
+
+.. code:: bash
+
+    $ ./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
+
+Double precision
+................
+
+To compile aubio in double precision mode, configure with ``--enable-double``.
+
+To compile aubio in single precision mode, use ``--disable-double`` (default).
+
+Disabling the tests
+...................
+
+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.
+
+.. note::
+
+  The ``--notests`` option should be passed to both ``build`` and ``install``
+  targets, otherwise waf will try to run them.
+
+Edit wscript
+............
+
+Many of the options are gathered in the file `wscript`. a good starting point
+when looking for additional options.
+
+.. _build_docs:
+
+Building the docs
+-----------------
+
+If the following command line tools are found, the documentation will be built
+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.
+
+To disable the documentation, configure with ``--disable-docs``. To build with
+the documentation, configure with ``--enable-docs``.
diff --git a/doc/statuslinks.rst b/doc/statuslinks.rst
new file mode 100644 (file)
index 0000000..d392f58
--- /dev/null
@@ -0,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/0.4.4.svg?maxAge=2592000
+   :target: https://github.com/aubio/aubio
+   :alt: Commits since last release
+
+
index dc03fb7..0adeadd 100644 (file)
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.5
+# Doxyfile 1.8.8
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -38,7 +38,7 @@ PROJECT_NAME           = aubio
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = "0.4.2~alpha"
+PROJECT_NUMBER         = "0.4.5~alpha"
 
 # 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
@@ -70,15 +70,25 @@ OUTPUT_DIRECTORY       = web
 
 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, Brazilian, Catalan, Chinese, Chinese-
-# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi,
-# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en,
-# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish,
-# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
-# Turkish, Ukrainian and Vietnamese.
+# 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
@@ -259,9 +269,12 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 # 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, 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.
+# 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.
 #
@@ -500,6 +513,13 @@ HIDE_SCOPE_NAMES       = NO
 
 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.
@@ -521,7 +541,8 @@ 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.
+# 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
@@ -659,8 +680,7 @@ LAYOUT_FILE            =
 # 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. Do not use file names with spaces, bibtex cannot handle them. See
-# also \cite for info how to create references.
+# search path. See also \cite for info how to create references.
 
 CITE_BIB_FILES         =
 
@@ -770,6 +790,7 @@ RECURSIVE              = YES
 
 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 \
@@ -978,6 +999,25 @@ USE_HTAGS              = NO
 
 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
 #---------------------------------------------------------------------------
@@ -1070,13 +1110,15 @@ HTML_FOOTER            =
 
 HTML_STYLESHEET        =
 
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
-# defined cascading style sheet that is included after the standard style sheets
+# 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 file to the output directory. For an example
-# see the documentation.
+# 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  =
@@ -1241,7 +1283,8 @@ GENERATE_CHI           = NO
 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.
+# 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.
 
@@ -1441,7 +1484,7 @@ MATHJAX_FORMAT         = HTML-CSS
 # 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
@@ -1481,11 +1524,11 @@ 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 flavours 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.
+# 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.
 
@@ -1613,17 +1656,19 @@ EXTRA_PACKAGES         =
 #
 # 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. Doxygen will
-# replace them by respectively the title of the page, the current date and time,
-# only the current date, the version number of doxygen, the project name (see
-# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# $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.
+# 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.
@@ -1647,7 +1692,7 @@ LATEX_EXTRA_FILES      =
 
 PDF_HYPERLINKS         = YES
 
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# 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.
@@ -1773,6 +1818,13 @@ MAN_OUTPUT             = man
 
 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
@@ -1800,18 +1852,6 @@ GENERATE_XML           = NO
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_DTD                =
-
 # 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
@@ -1839,6 +1879,15 @@ GENERATE_DOCBOOK       = NO
 
 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
 #---------------------------------------------------------------------------
@@ -1958,9 +2007,9 @@ PREDEFINED             =
 EXPAND_AS_DEFINED      =
 
 # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all refrences 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
+# 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.
@@ -1980,7 +2029,7 @@ SKIP_FUNCTION_MACROS   = YES
 # 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 an unique name (where the name does NOT include
+# 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.
 
@@ -2040,6 +2089,13 @@ CLASS_DIAGRAMS         = YES
 
 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.
@@ -2051,7 +2107,7 @@ HIDE_UNDOC_RELATIONS   = YES
 # 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: NO.
+# The default value is: YES.
 
 HAVE_DOT               = NO
 
@@ -2065,7 +2121,7 @@ HAVE_DOT               = NO
 
 DOT_NUM_THREADS        = 0
 
-# When you want a differently looking font n the dot files that doxygen
+# 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
@@ -2203,7 +2259,9 @@ DIRECTORY_GRAPH        = YES
 # 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, jpg, gif and svg.
+# 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.
 
@@ -2240,6 +2298,21 @@ DOTFILE_DIRS           =
 
 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
diff --git a/doc/xcode_frameworks.rst b/doc/xcode_frameworks.rst
new file mode 100644 (file)
index 0000000..e665cfe
--- /dev/null
@@ -0,0 +1,70 @@
+.. _xcode-frameworks-label:
+
+Using aubio frameworks in Xcode
+-------------------------------
+
+`Binary frameworks`_ are available and ready to use in your XCode project, for
+`iOS`_ and `macOS`_.
+
+#. Download and extract the corresponding ``framework.zip`` file from the `Download`_ page
+
+#. Select **Build Phases** in your project setting and unfold **Link Binary with Libraries**
+
+#. Add *AudioToolbox* and *Accelerate* system frameworks (or make sure they are listed)
+
+#. Add ``aubio.framework`` from the unzipped ``framework.zip``
+
+#. Include the aubio header in your code:
+
+  * in C/C++:
+
+  .. code-block:: c
+
+    #include <aubio/aubio.h>
+
+  * in Obj-C:
+
+  .. code-block:: obj-c
+
+    #import <aubio/aubio.h>
+
+  * in Swift:
+
+  .. code-block:: swift
+
+    import aubio
+
+Using aubio from swift
+......................
+
+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
index d8bb910..0942ade 100644 (file)
@@ -48,6 +48,7 @@ void process_print (void)
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   // change some default params
   buffer_size  = 512;
   hop_size = 256;
@@ -62,6 +63,10 @@ int main(int argc, char **argv) {
   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 @@ int main(int argc, char **argv) {
   del_aubio_mfcc(mfcc);
   del_fvec(mfcc_out);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
index 544bdd8..f74063a 100644 (file)
 
 */
 
-#define AUBIO_UNSTABLE 1 // for fvec_median
 #include "utils.h"
 #define PROG_HAS_PITCH 1
 #define PROG_HAS_ONSET 1
+#define PROG_HAS_SILENCE 1
 #define PROG_HAS_JACK 1
 // TODO add PROG_HAS_OUTPUT
 #include "parse_args.h"
 
-uint_t median = 6;
-
-fvec_t *note_buffer;
-fvec_t *note_buffer2;
-
-smpl_t curnote = 0.;
-smpl_t newnote = 0.;
-uint_t isready = 0;
-
-aubio_pitch_t *pitch;
-aubio_onset_t *o;
-fvec_t *onset;
-fvec_t *pitch_obuf;
-
-/** 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.*/
-void note_append (fvec_t * note_buffer, smpl_t curnote);
-uint_t get_note (fvec_t * note_buffer, fvec_t * note_buffer2);
+aubio_notes_t *notes;
+smpl_t lastmidi = 0.;
 
 void process_block (fvec_t *ibuf, fvec_t *obuf)
 {
-  smpl_t new_pitch, curlevel;
-  fvec_zeros(obuf);
-  aubio_onset_do(o, ibuf, onset);
-
-  aubio_pitch_do (pitch, ibuf, pitch_obuf);
-  new_pitch = fvec_get_sample(pitch_obuf, 0);
-  if(median){
-    note_append(note_buffer, new_pitch);
+  aubio_notes_do (notes, ibuf, obuf);
+  // did we get a note off?
+  if (obuf->data[2] != 0) {
+    lastmidi = obuf->data[2];
+    send_noteon(lastmidi, 0);
   }
-
-  /* curlevel is negatif or 1 if silence */
-  curlevel = aubio_level_detection(ibuf, silence_threshold);
-  if (fvec_get_sample(onset, 0)) {
-    /* test for silence */
-    if (curlevel == 1.) {
-      if (median) isready = 0;
-      /* send note off */
-      send_noteon(curnote,0);
-    } else {
-      if (median) {
-        isready = 1;
-      } else {
-        /* kill old note */
-        send_noteon(curnote,0);
-        /* get and send new one */
-        send_noteon(new_pitch,127+(int)floor(curlevel));
-        curnote = new_pitch;
-      }
-    }
-  } else {
-    if (median) {
-      if (isready > 0)
-        isready++;
-      if (isready == median)
-      {
-        /* kill old note */
-        send_noteon(curnote,0);
-        newnote = get_note(note_buffer, note_buffer2);
-        curnote = newnote;
-        /* get and send new one */
-        if (curnote>45){
-          send_noteon(curnote,127+(int)floor(curlevel));
-        }
-      }
-    } // if median
+  // did we get a note on?
+  if (obuf->data[0] != 0) {
+    lastmidi = obuf->data[0];
+    send_noteon(lastmidi, obuf->data[1]);
   }
 }
 
@@ -100,28 +49,9 @@ void process_print (void)
   //if (verbose) outmsg("%f\n",pitch_obuf->data[0]);
 }
 
-void
-note_append (fvec_t * note_buffer, smpl_t curnote)
-{
-  uint_t i = 0;
-  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;
-  return;
-}
-
-uint_t
-get_note (fvec_t * note_buffer, fvec_t * note_buffer2)
-{
-  uint_t i;
-  for (i = 0; i < note_buffer->length; i++) {
-    note_buffer2->data[i] = note_buffer->data[i];
-  }
-  return fvec_median (note_buffer2);
-}
-
 int main(int argc, char **argv) {
+  int ret = 0;
+
   examples_common_init(argc,argv);
 
   verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
@@ -136,32 +66,33 @@ int main(int argc, char **argv) {
   verbmsg ("hop_size: %d, ", hop_size);
   verbmsg ("tolerance: %f\n", pitch_tolerance);
 
-  o = new_aubio_onset (onset_method, buffer_size, hop_size, samplerate);
-  if (onset_threshold != 0.) aubio_onset_set_threshold (o, onset_threshold);
-  onset = new_fvec (1);
-
-  pitch = new_aubio_pitch (pitch_method, buffer_size * 4, hop_size, samplerate);
-  if (pitch_tolerance != 0.) aubio_pitch_set_tolerance (pitch, pitch_tolerance);
-  pitch_obuf = new_fvec (1);
+  notes = new_aubio_notes ("default", buffer_size, hop_size, samplerate);
+  if (notes == NULL) { ret = 1; goto beach; }
 
-  if (median) {
-      note_buffer = new_fvec (median);
-      note_buffer2 = new_fvec (median);
+  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);
+    }
   }
 
   examples_common_process((aubio_process_func_t)process_block, process_print);
 
-  // send a last note off
-  send_noteon (curnote, 0);
-
-  del_aubio_pitch (pitch);
-  if (median) {
-      del_fvec (note_buffer);
-      del_fvec (note_buffer2);
+  // send a last note off if required
+  if (lastmidi) {
+    send_noteon (lastmidi, 0);
   }
-  del_fvec (pitch_obuf);
 
+  del_aubio_notes (notes);
+
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
index 8f30bad..032eb00 100644 (file)
@@ -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"
 
@@ -37,6 +38,8 @@ void process_block(fvec_t *ibuf, fvec_t *obuf)
   fvec_zeros(obuf);
   if ( is_onset ) {
     aubio_wavetable_play ( wavetable );
+    /* send a midi tap (default to C0) out to the midi output */
+    if (usejack) send_noteon(miditap_note, miditap_velo);
   } else {
     aubio_wavetable_stop ( wavetable );
   }
@@ -55,6 +58,7 @@ void process_print (void)
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   examples_common_init(argc,argv);
 
   verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
@@ -65,10 +69,13 @@ int main(int argc, char **argv) {
   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);
 
   onset = new_fvec (1);
 
@@ -78,10 +85,16 @@ int main(int argc, char **argv) {
 
   examples_common_process((aubio_process_func_t)process_block, process_print);
 
+  // send a last note off
+  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;
 }
index bdda950..2d7a012 100644 (file)
@@ -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 @@ void process_print (void)
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
 
   buffer_size = 2048;
 
@@ -64,6 +66,7 @@ int main(int argc, char **argv) {
   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 @@ int main(int argc, char **argv) {
   del_aubio_wavetable (wavetable);
   del_fvec (pitch);
 
+beach:
   examples_common_del();
-  return 0;
+  return ret;
 }
-
index bbe158b..f62e1ed 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "utils.h"
+#define PROG_HAS_SILENCE 1
 #include "parse_args.h"
 
 sint_t wassilence = 1, issilence;
index 330fc8c..36267cf 100644 (file)
@@ -20,6 +20,8 @@
 
 #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"
@@ -27,8 +29,8 @@
 aubio_tempo_t * tempo;
 aubio_wavetable_t *wavetable;
 fvec_t * tempo_out;
-smpl_t is_beat = 0;
-uint_t is_silence = 0.;
+smpl_t is_beat = 0.;
+uint_t is_silence = 0;
 
 void process_block(fvec_t * ibuf, fvec_t *obuf) {
   aubio_tempo_do (tempo, ibuf, tempo_out);
@@ -39,6 +41,8 @@ void process_block(fvec_t * ibuf, fvec_t *obuf) {
   fvec_zeros (obuf);
   if ( is_beat && !is_silence ) {
     aubio_wavetable_play ( wavetable );
+    /* send a midi tap (default to C0) out to the midi output */
+    if (usejack) send_noteon(miditap_note, miditap_velo);
   } else {
     aubio_wavetable_stop ( wavetable );
   }
@@ -56,6 +60,7 @@ void process_print (void) {
 }
 
 int main(int argc, char **argv) {
+  int ret = 0;
   // override general settings from utils.c
   buffer_size = 1024;
   hop_size = 512;
@@ -71,9 +76,11 @@ int main(int argc, char **argv) {
 
   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.);
@@ -81,11 +88,16 @@ int main(int argc, char **argv) {
 
   examples_common_process((aubio_process_func_t)process_block,process_print);
 
+  // send a last note off
+  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;
 }
-
index 475471f..f781fb1 100644 (file)
@@ -21,7 +21,7 @@
 #include <aubio.h>
 #include "config.h"
 
-#if HAVE_JACK
+#ifdef HAVE_JACK
 #include "utils.h" // for aubio_process_func_t
 #include "jackio.h"
 #include "aubio_priv.h"
index 0548038..f46629f 100644 (file)
 
 */
 
+#include "config.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
 extern int verbose;
 // input / output
 extern int usejack;
@@ -30,6 +36,7 @@ extern uint_t hop_size;
 // 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;
@@ -41,6 +48,9 @@ extern char_t * tempo_method;
 // more general stuff
 extern smpl_t silence_threshold;
 extern uint_t mix_input;
+// midi tap
+extern smpl_t miditap_note;
+extern smpl_t miditap_velo;
 
 extern uint_t force_overwrite;
 
@@ -63,6 +73,7 @@ void usage (FILE * stream, int exit_code);
 
 void usage (FILE * stream, int exit_code)
 {
+#ifdef HAVE_GETOPT_H
   fprintf (stream, "usage: %s [ options ] \n", prog_name);
   fprintf (stream,
       "       -i      --input            input file\n"
@@ -81,6 +92,8 @@ void usage (FILE * stream, int exit_code)
       "                 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"
@@ -90,8 +103,10 @@ void usage (FILE * stream, int exit_code)
       "       -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 */
       "       -T      --time-format      select time values output format\n"
       "                 (samples, ms, seconds) default=seconds\n"
 #ifdef PROG_HAS_OUTPUT
@@ -99,35 +114,53 @@ void usage (FILE * stream, int exit_code)
       "                 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
+#endif /* PROG_HAS_OUTPUT */
 #ifdef PROG_HAS_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 /* PROG_HAS_JACK */
       "       -v      --verbose          be verbose\n"
       "       -h      --help             display this message\n"
       );
+#else /* HAVE_GETOPT_H */
+  fprintf (stream, "warning: compiled with getopt.h, no argument parsing\n");
+  fprintf (stream, "usage: %s <filename> \n", prog_name);
+#endif /* HAVE_GETOPT_H */
   exit (exit_code);
 }
 
 int
 parse_args (int argc, char **argv)
 {
+#ifdef HAVE_GETOPT_H
   const char *options = "hv"
     "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_OUTPUT
+    "mf"
+#endif /* PROG_HAS_OUTPUT */
+    ;
   int next_option;
   struct option long_options[] = {
     {"help",                  0, NULL, 'h'},
@@ -138,6 +171,10 @@ parse_args (int argc, char **argv)
     {"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'},
@@ -145,23 +182,30 @@ parse_args (int argc, char **argv)
 #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'},
     {"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 */
     {"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];
   if (argc < 1) {
     usage (stderr, 1);
     return -1;
   }
+#ifdef HAVE_GETOPT_H
   do {
     next_option = getopt_long (argc, argv, options, long_options, NULL);
     switch (next_option) {
@@ -174,6 +218,12 @@ parse_args (int argc, char **argv)
       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;
@@ -198,6 +248,9 @@ parse_args (int argc, char **argv)
       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;
@@ -235,6 +288,9 @@ parse_args (int argc, char **argv)
     }
   }
   while (next_option != -1);
+#else /* HAVE_GETOPT_H */
+  int optind = 1;
+#endif /* HAVE_GETOPT_H */
 
   // if unique, use the non option argument as the source
   if ( source_uri == NULL ) {
index a28f409..39adef9 100644 (file)
@@ -43,6 +43,7 @@ uint_t hop_size = 256;
 // 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";
@@ -64,6 +65,9 @@ aubio_sink_t *this_sink = NULL;
 fvec_t *ibuf;
 fvec_t *obuf;
 
+smpl_t miditap_note = 69.;
+smpl_t miditap_velo = 65.;
+
 /* settings */
 int blocks = 0;
 
@@ -72,7 +76,8 @@ extern int parse_args (int argc, char **argv);
 
 #if HAVE_JACK
 aubio_jack_t *jack_setup;
-#endif
+jack_midi_event_t ev;
+#endif /* HAVE_JACK */
 
 void examples_common_init (int argc, char **argv);
 void examples_common_del (void);
@@ -114,7 +119,7 @@ void examples_common_init (int argc, char **argv)
     jack_setup = new_aubio_jack (hop_size, 1, 1, 0, 1);
     samplerate = aubio_jack_get_samplerate (jack_setup);
     source_uri = "jack";
-#endif
+#endif /* HAVE_JACK */
   }
   ibuf = new_fvec (hop_size);
   obuf = new_fvec (hop_size);
@@ -123,6 +128,9 @@ void examples_common_init (int argc, char **argv)
 
 void examples_common_del (void)
 {
+#ifdef HAVE_JACK
+  if (ev.buffer) free(ev.buffer);
+#endif
   del_fvec (ibuf);
   del_fvec (obuf);
   aubio_cleanup ();
@@ -137,16 +145,19 @@ void examples_common_process (aubio_process_func_t process_func,
   uint_t read = 0;
   if (usejack) {
 
-#if HAVE_JACK
+#ifdef HAVE_JACK
+    ev.size = 3;
+    ev.buffer = malloc (3 * sizeof (jack_midi_data_t));
+    ev.time = 0; // send it now
     debug ("Jack activation ...\n");
     aubio_jack_activate (jack_setup, process_func);
     debug ("Processing (Ctrl+C to quit) ...\n");
     pause ();
     aubio_jack_close (jack_setup);
-#else
+#else /* HAVE_JACK */
     usage (stderr, 1);
     outmsg ("Compiled without jack output, exiting.\n");
-#endif
+#endif /* HAVE_JACK */
 
   } else {
 
@@ -178,17 +189,12 @@ void examples_common_process (aubio_process_func_t process_func,
 }
 
 void
-send_noteon (int pitch, int velo)
+send_noteon (smpl_t pitch, smpl_t velo)
 {
-  smpl_t mpitch = floor (aubio_freqtomidi (pitch) + .5);
-#if HAVE_JACK
-  jack_midi_event_t ev;
-  ev.size = 3;
-  ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
-  ev.time = 0;
+#ifdef HAVE_JACK
   if (usejack) {
     ev.buffer[2] = velo;
-    ev.buffer[1] = mpitch;
+    ev.buffer[1] = pitch;
     if (velo == 0) {
       ev.buffer[0] = 0x80;      /* note off */
     } else {
@@ -201,7 +207,7 @@ send_noteon (int pitch, int velo)
     print_time (blocks * hop_size);
     outmsg ("\n");
   } else {
-    outmsg ("%f\t", mpitch);
+    outmsg ("%f\t", pitch);
     print_time (blocks * hop_size);
     outmsg ("\t");
   }
index 93b0e18..e911bef 100644 (file)
 
 */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <math.h>               /* for isfinite */
-#include <string.h>             /* for strcmp */
 #include <aubio.h>
+
 #include "config.h"
 
+#ifdef HAVE_STDIO_H
+#include <stdio.h>              // for fprintf
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>             // for exit
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>             // for access
+#elif defined(HAVE_WIN_HACKS)
+#include <io.h>
+#define access _access
+#define F_OK   0
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>               // for isfinite
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>             // for strcmp
+#endif
+
 #ifdef HAVE_C99_VARARGS_MACROS
 #ifdef HAVE_DEBUG
 #define debug(...)                fprintf (stderr, __VA_ARGS__)
@@ -49,7 +63,7 @@
 #endif
 
 typedef void (aubio_print_func_t) (void);
-void send_noteon (int pitch, int velo);
+void send_noteon (smpl_t pitch, smpl_t velo);
 
 /** common process function */
 typedef int (*aubio_process_func_t) (fvec_t * input, fvec_t * output);
index 2ef9709..7970bf6 100644 (file)
@@ -1,33 +1,27 @@
 # vim:set syntax=python:
 
-uselib = []
-uselib += ['FFTW3', 'FFTW3F']
-uselib += ['SAMPLERATE']
-uselib += ['SNDFILE']
-uselib += ['AVCODEC']
-uselib += ['AVFORMAT']
-uselib += ['AVRESAMPLE']
-uselib += ['AVUTIL']
+import os.path
+
+uselib = ['aubio']
 uselib += ['JACK']
-uselib += ['BLAS']
 
+includes = ['../src']
 utils_source = ['utils.c', 'jackio.c']
 programs_source = ctx.path.ant_glob('*.c', excl = utils_source)
 
 # build examples
 bld(features = 'c',
         source = utils_source,
-        includes = ['../src'],
-        uselib = uselib,
+        includes = includes,
+        use = uselib,
         target = 'utilsio')
 
 # loop over all *.c filenames in examples to build them all
 for source_file in programs_source:
+    target = os.path.basename(os.path.splitext(str(source_file))[0])
     bld(features = 'c cprogram',
-            includes = '../src',
-            lib = 'm',
-            use = ['aubio', 'utilsio'],
-            uselib = uselib,
             source = source_file,
-            target = str(source_file).split('.')[0]
-            )
+            target = target,
+            includes = includes,
+            use = uselib + ['utilsio'],
+       )
diff --git a/nose2.cfg b/nose2.cfg
new file mode 100644 (file)
index 0000000..d1be6d8
--- /dev/null
+++ b/nose2.cfg
@@ -0,0 +1,6 @@
+[unittest]
+start-dir = python/tests/
+plugins = nose2.plugins.mp
+
+[multiprocess]
+always-on = false
diff --git a/python/MANIFEST.in b/python/MANIFEST.in
deleted file mode 100644 (file)
index cffcceb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-include README COPYING VERSION
-include ext/*.h
-include lib/generator.py
-include lib/gen_pyobject.py
-include gen/aubio-generated.h
-include tests/run_all_tests
-include tests/*.py
-include demos/*.py
diff --git a/python/README b/python/README
deleted file mode 100644 (file)
index c49d2a7..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-Python aubio module
-===================
-
-This module wraps the aubio library for Python using the numpy module.
-
-Before compiling this module, you must have compiled libaubio.
-
-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
-----------------------
-
-After libaubio has been build successfully, and provided Python development
-headers and numpy can be found on your system, you should be able to build the
-aubio Python module:
-
-    $ ./setup.py build
-
-To find out more about `setup.py` options:
-
-    $ ./setup.py --help
-
-Installing
-----------
-
-To install the Python module:
-
-    $ ./setup.py install
-
-Using the Python module
------------------------
-
-Once the aubio library and the Python module are installed, you will be able to
-import the aubio module:
-
-    $ python
-    [...]
-    >>> import aubio
-    >>>
-
-Alternatively, you may want to use the Python module without installing it by
-setting PYTHONPATH:
-
-    $ export PYTHONPATH=$PYTHONPATH:$PWD/`ls -rtd build/lib.* | head -1`:$PWD/tests
-
-Similarly, you can use the aubio module without installing libaubio by pointing
-LD_LIBRARY_PATH to the path libaubio can be found at:
-
-    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:PWD/../build/src
-
-Or on Mac OS X systems, setting DYLD_LIBRARY_PATH:
-
-    $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$PWD/../build/src
-
-Testing the Python module
--------------------------
-
-Once both the C library and the Python module have been built correctly, and
-after you have installed them (or setting the environment variable correctly),
-you should be able to run the tests:
-
-    $ ./tests/run_all_tests
-
-And to try out the demos:
-
-    $ ./demos/demo_source.wav /path/to/sound/sample.wav
-
-You need to install additional modules to run some of the demos. For
-instance, several demos use [matplotlib](http://matplotlib.org/) to draw plots.
-Some more demos use [PySoundCard](https://github.com/bastibe/PySoundCard) to
-play and record sounds.
diff --git a/python/README.md b/python/README.md
new file mode 100644 (file)
index 0000000..dbb8ff3
--- /dev/null
@@ -0,0 +1,104 @@
+Python aubio module
+===================
+
+This module wraps the aubio library for Python using the numpy module.
+
+Using the Python aubio module
+-----------------------------
+
+After installing python-aubio, you will be able to import the aubio module:
+
+    $ python
+    [...]
+    >>> import aubio
+    >>> help(aubio.miditofreq)
+
+Finding some inspiration
+------------------------
+
+Some examples are available in the `python/demos` directory. These scripts are
+small programs written in python and using python-aubio.
+
+For instance, `demo_source.py` reads a media file.
+
+    $ ./python/demos/demo_source.py /path/to/sound/sample.wav
+
+and `demo_timestretch_online.py` stretches the original file into a new one:
+
+    $ ./python/demo/demo_timestretch_online.py loop.wav stretched_loop.wav 0.92`
+
+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.
+
+Testing the Python module
+-------------------------
+
+Python tests are in `python/tests` and use the [nose2 python package][nose2].
+
+To run the all the python tests, use the script:
+
+    $ ./python/tests/run_all_tests
+
+Each test script can also be called one at a time. For instance:
+
+    $ ./python/tests/test_note2midi.py -v
+
+[nose2]: https://github.com/nose-devs/nose2
+
+Install in a virtualenv
+-----------------------
+
+You should be able to install python-aubio directly from the top source
+directory of aubio.
+
+First, create a virtualenv to hold the required python module:
+
+    $ virtualenv pyaubio
+    $ source pyaubio/bin/activate
+
+Now install and build the python extension using:
+
+    $ pip install .
+
+Install requirements
+--------------------
+
+Before compiling this module, you must have compiled libaubio.
+
+A simple way to do this is with pip:
+
+    $ pip install -r requirements.txt
+
+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
+
diff --git a/python/VERSION b/python/VERSION
deleted file mode 100644 (file)
index ff49ec1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AUBIO_MAJOR_VERSION=0
-AUBIO_MINOR_VERSION=4
-AUBIO_PATCH_VERSION=2
-AUBIO_VERSION_STATUS='~alpha'
-LIBAUBIO_LT_CUR=4
-LIBAUBIO_LT_REV=1
-LIBAUBIO_LT_AGE=1
diff --git a/python/__init__.py b/python/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/demos/__init__.py b/python/demos/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/demos/demo_a_weighting.py b/python/demos/demo_a_weighting.py
deleted file mode 100755 (executable)
index 345e651..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#! /usr/bin/env python
-
-
-def apply_filter(path, params = {}):
-    from aubio import source, sink, digital_filter
-    from os.path import basename, splitex, splitextt
-    s = source(path)
-    f = digital_filter(7)
-    f.set_a_weighting(s.samplerate)
-    #f = digital_filter(3)
-    #f.set_biquad(...)
-    o = sink("filtered_" + splitext(basename(path))[0] + ".wav")
-    # Total number of frames read
-    total_frames = 0
-
-    while True:
-        samples, read = s()
-        filtered_samples = f(samples)
-        o(samples, read)
-        total_frames += read
-        if read < s.hop_size: break
-    print "filtered", s.uri, "to", o.uri, "using an A-weighting filter"
-
-if __name__ == '__main__':
-    import sys
-    for f in sys.argv[1:]:
-        apply_filter(f)
diff --git a/python/demos/demo_alsa.py b/python/demos/demo_alsa.py
new file mode 100755 (executable)
index 0000000..cd58a33
--- /dev/null
@@ -0,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
diff --git a/python/demos/demo_bench_yin.py b/python/demos/demo_bench_yin.py
new file mode 100755 (executable)
index 0000000..0d03c05
--- /dev/null
@@ -0,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()
index 65b1c73..ba7fbad 100755 (executable)
@@ -3,16 +3,18 @@
 from aubio import source, tempo
 from numpy import median, diff
 
-def get_file_bpm(path, params = {}):
+def get_file_bpm(path, params = None):
     """ Calculate the beats per minute (bpm) of a given file.
         path: path to the file
         param: dictionary of parameters
     """
+    if params is None:
+        params = {}
     try:
         win_s = params['win_s']
         samplerate = params['samplerate']
         hop_s = params['hop_s']
-    except:
+    except KeyError:
         """
         # super fast
         samplerate, win_s, hop_s = 4000, 128, 64 
@@ -43,12 +45,18 @@ def get_file_bpm(path, params = {}):
             break
 
     # Convert to periods and to bpm 
-    bpms = 60./diff(beats)
-    b = median(bpms)
+    if len(beats) > 1:
+        if len(beats) < 4:
+            print("few beats found in {:s}".format(path))
+        bpms = 60./diff(beats)
+        b = median(bpms)
+    else:
+        b = 0
+        print("not enough beats found in {:s}".format(path))
     return b
 
 if __name__ == '__main__':
     import sys
     for f in sys.argv[1:]:
         bpm = get_file_bpm(f)
-        print "%6s" % ("%.2f" % bpm), f
+        print("{:6s} {:s}".format("{:2f}".format(bpm), f))
diff --git a/python/demos/demo_create_test_sounds.py b/python/demos/demo_create_test_sounds.py
new file mode 100755 (executable)
index 0000000..3d2f2d0
--- /dev/null
@@ -0,0 +1,50 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys, os
+import numpy as np
+from aubio import fvec, sink, float_type
+
+if __name__ == '__main__':
+    if len(sys.argv) < 1:
+        print('usage: %s' % sys.argv[0])
+        sys.exit(1)
+
+    samplerate = 44100
+    hop_size = 256
+
+    # create python/tests/sounds if needed
+    output_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    output_dir = os.path.join(output_dir, 'tests', 'sounds')
+    if not os.path.isdir(output_dir):
+        os.makedirs(output_dir)
+
+    filenames = ['44100Hz_1f_silence.wav',
+                 '22050Hz_5s_brownnoise.wav',
+                 '32000Hz_127f_sine440.wav',
+                ]
+    samplerates = [44100, 22050, 32000]
+    durations = [1, 5*22050, 127]
+
+    for fname, samplerate, duration in zip(filenames, samplerates, durations):
+        output_name = os.path.join(output_dir, fname)
+        g = sink(output_name, samplerate)
+        total_frames = 0
+        while total_frames < duration:
+            write = min(hop_size, duration - total_frames)
+            if 'brownnoise' in fname:
+                vec = np.random.rand(write).astype(float_type) * 2. - 1.
+            elif 'sine' in fname:
+                freq = 440
+                t = np.arange(write).astype(float_type) + total_frames
+                vec = np.sin(2. * np.pi * freq * t / float(samplerate))
+            else:
+                # silence
+                vec = fvec(write)
+            g(vec, write)
+            total_frames += write
+        outstr = "wrote {:2f}s".format(total_frames / float(samplerate))
+        outstr += " ({:d} frames".format(total_frames)
+        outstr += " at {:d}Hz)".format(g.samplerate)
+        outstr += " to {:s}".format(g.uri)
+        print(outstr)
diff --git a/python/demos/demo_filter.py b/python/demos/demo_filter.py
new file mode 100755 (executable)
index 0000000..10226ce
--- /dev/null
@@ -0,0 +1,36 @@
+#! /usr/bin/env python
+
+
+def apply_filter(path):
+    from aubio import source, sink, digital_filter
+    from os.path import basename, splitext
+
+    # open input file, get its samplerate
+    s = source(path)
+    samplerate = s.samplerate
+
+    # create an A-weighting filter
+    f = digital_filter(7)
+    f.set_a_weighting(samplerate)
+    # alternatively, apply another filter
+
+    # create output file
+    o = sink("filtered_" + splitext(basename(path))[0] + ".wav", samplerate)
+
+    total_frames = 0
+    while True:
+        samples, read = s()
+        filtered_samples = f(samples)
+        o(filtered_samples, read)
+        total_frames += read
+        if read < s.hop_size: break
+
+    duration = total_frames / float(samplerate)
+    print ("read {:s}".format(s.uri))
+    print ("applied A-weighting filtered ({:d} Hz)".format(samplerate))
+    print ("wrote {:s} ({:.2f} s)".format(o.uri, duration))
+
+if __name__ == '__main__':
+    import sys
+    for f in sys.argv[1:]:
+        apply_filter(f)
index 1620a03..54aff57 100755 (executable)
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 from aubio import filterbank, fvec
-from pylab import loglog, show, subplot, xlim, ylim, xlabel, ylabel, title
+from pylab import loglog, show, xlim, ylim, xlabel, ylabel, title
 from numpy import vstack, arange
 
 win_s = 2048
@@ -19,7 +19,7 @@ coeffs[4] *= 5.
 
 f.set_coeffs(coeffs)
 
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
 title('Bank of filters built using a simple list of boundaries\nThe middle band has been amplified by 2.')
 loglog(times.T, f.get_coeffs().T, '.-')
 xlim([50, samplerate/2])
index 636dc80..f0e041e 100755 (executable)
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 from aubio import filterbank
-from numpy import array, arange, vstack
+from numpy import arange, vstack
 
 win_s = 8192
 samplerate = 16000
@@ -11,7 +11,7 @@ f.set_mel_coeffs_slaney(samplerate)
 
 from pylab import loglog, title, show, xlim, ylim, xlabel, ylabel
 xlim([0,samplerate / 2])
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * 40)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * 40)
 loglog(times.T, f.get_coeffs().T, '.-')
 title('Mel frequency bands coefficients')
 xlim([100, 7500])
index 7b02e7d..c65df93 100755 (executable)
@@ -16,7 +16,7 @@ f.set_triangle_bands(freqs, samplerate)
 
 subplot(211)
 title('Examples of filterbank built with set_triangle_bands and set_coeffs')
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
 loglog(times.T, f.get_coeffs().T, '.-')
 xlim([50, samplerate/2])
 ylim([1.0e-6, 2.0e-2])
@@ -37,7 +37,7 @@ coeffs[4] *= 5.
 f.set_coeffs(coeffs)
 
 subplot(212)
-times = vstack([arange(win_s / 2 + 1) * samplerate / win_s] * n_filters)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
 loglog(times.T, f.get_coeffs().T, '.-')
 xlim([50, samplerate/2])
 ylim([1.0e-6, 2.0e-2])
index 527d03b..63786b9 100755 (executable)
@@ -25,7 +25,6 @@ def get_keyboard_edges(firstnote = 21, lastnote = 108):
     return xb, xw, 2/3. *scaleb, 1/2. * scalew
 
 def create_keyboard_patches(firstnote, lastnote, ax = None):
-    import numpy as np
     import matplotlib.pyplot as plt
     from matplotlib.path import Path
     import matplotlib.patches as mpatches
index ac09863..db27f7e 100755 (executable)
@@ -1,14 +1,14 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import fvec, source, pvoc, filterbank
+from aubio import source, pvoc, filterbank
 from numpy import vstack, zeros
 
 win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
+hop_s = win_s // 4          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -34,14 +34,14 @@ while True:
     samples, read = s()
     fftgrain = pv(samples)
     new_energies = f(fftgrain)
-    print '%f' % (total_frames / float(samplerate) ),
-    print ' '.join(['%f' % b for b in new_energies])
+    timestr = '%f' % (total_frames / float(samplerate) )
+    print('{:s} {:s}'.format(timestr, ' '.join(['%f' % b for b in new_energies])))
     energies = vstack( [energies, new_energies] )
     total_frames += read
     if read < hop_s: break
 
 if 1:
-    print "done computing, now plotting"
+    print("done computing, now plotting")
     import matplotlib.pyplot as plt
     from demo_waveform_plot import get_waveform_plot
     from demo_waveform_plot import set_xlabels_sample2time
index 2242f0c..5a33d15 100755 (executable)
@@ -2,20 +2,27 @@
 
 import sys
 from aubio import source, pvoc, mfcc
-from numpy import array, vstack, zeros
+from numpy import vstack, zeros, diff
 
-win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
 n_filters = 40              # must be 40 for mfcc
 n_coeffs = 13
-samplerate = 44100
 
 if len(sys.argv) < 2:
-    print "Usage: %s <source_filename>" % sys.argv[0]
+    print("Usage: %s <source_filename> [samplerate] [win_s] [hop_s] [mode]" % sys.argv[0])
+    print("  where [mode] can be 'delta' or 'ddelta' for first and second derivatives")
     sys.exit(1)
 
 source_filename = sys.argv[1]
 
+if len(sys.argv) > 2: samplerate = int(sys.argv[2])
+else: samplerate = 0
+if len(sys.argv) > 3: win_s = int(sys.argv[3])
+else: win_s = 512
+if len(sys.argv) > 4: hop_s = int(sys.argv[4])
+else: hop_s = win_s // 4
+if len(sys.argv) > 5: mode = sys.argv[5]
+else: mode = "default"
+
 samplerate = 0
 if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
 
@@ -48,18 +55,28 @@ get_waveform_plot( source_filename, samplerate, block_size = hop_s, ax = wave)
 wave.xaxis.set_visible(False)
 wave.yaxis.set_visible(False)
 
+# compute first and second derivatives
+if mode in ["delta", "ddelta"]:
+    mfccs = diff(mfccs, axis = 0)
+if mode == "ddelta":
+    mfccs = diff(mfccs, axis = 0)
+
 all_times = arange(mfccs.shape[0]) * hop_s
 n_coeffs = mfccs.shape[1]
 for i in range(n_coeffs):
     ax = plt.axes ( [0.1, 0.75 - ((i+1) * 0.65 / n_coeffs),  0.8, 0.65 / n_coeffs], sharex = wave )
     ax.xaxis.set_visible(False)
-    ax.yaxis.set_visible(False)
+    ax.set_yticks([])
+    ax.set_ylabel('%d' % i)
     ax.plot(all_times, mfccs.T[i])
 
 # add time to the last axis
-set_xlabels_sample2time( ax, frames_read, samplerate) 
+set_xlabels_sample2time( ax, frames_read, samplerate)
 
 #plt.ylabel('spectral descriptor value')
 ax.xaxis.set_visible(True)
-wave.set_title('MFCC for %s' % source_filename)
+title = 'MFCC for %s' % source_filename
+if mode == "delta": title = mode + " " + title
+elif mode == "ddelta": title = "double-delta" + " " + title
+wave.set_title(title)
 plt.show()
diff --git a/python/demos/demo_notes.py b/python/demos/demo_notes.py
new file mode 100755 (executable)
index 0000000..301013a
--- /dev/null
@@ -0,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
index 949a663..43e4aed 100755 (executable)
@@ -4,10 +4,10 @@ import sys
 from aubio import source, onset
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -28,7 +28,7 @@ total_frames = 0
 while True:
     samples, read = s()
     if o(samples):
-        print "%f" % o.get_last_s()
+        print("%f" % o.get_last_s())
         onsets.append(o.get_last())
     total_frames += read
     if read < hop_s: break
index a928655..5169cf7 100755 (executable)
@@ -2,13 +2,13 @@
 
 import sys
 from aubio import onset, source
-from numpy import array, hstack, zeros
+from numpy import hstack, zeros
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -34,10 +34,10 @@ total_frames = 0
 while True:
     samples, read = s()
     if o(samples):
-        print "%f" % (o.get_last_s())
+        print("%f" % (o.get_last_s()))
         onsets.append(o.get_last())
     # keep some data to plot it later
-    new_maxes = (abs(samples.reshape(hop_s/downsample, downsample))).max(axis=0)
+    new_maxes = (abs(samples.reshape(hop_s//downsample, downsample))).max(axis=0)
     allsamples_max = hstack([allsamples_max, new_maxes])
     desc.append(o.get_descriptor())
     tdesc.append(o.get_thresholded_descriptor())
@@ -46,7 +46,6 @@ while True:
 
 if 1:
     # do plotting
-    from numpy import arange
     import matplotlib.pyplot as plt
     allsamples_max = (allsamples_max > 0) * allsamples_max
     allsamples_max_times = [ float(t) * hop_s / downsample / samplerate for t in range(len(allsamples_max)) ]
@@ -62,9 +61,10 @@ if 1:
     plt1.xaxis.set_visible(False)
     plt1.yaxis.set_visible(False)
     desc_times = [ float(t) * hop_s / samplerate for t in range(len(desc)) ]
-    desc_plot = [d / max(desc) for d in desc]
+    desc_max = max(desc) if max(desc) != 0 else 1.
+    desc_plot = [d / desc_max for d in desc]
     plt2.plot(desc_times, desc_plot, '-g')
-    tdesc_plot = [d / max(desc) for d in tdesc]
+    tdesc_plot = [d / desc_max for d in tdesc]
     for stamp in onsets:
         stamp /= float(samplerate)
         plt2.plot([stamp, stamp], [min(tdesc_plot), max(desc_plot)], '-r')
index 2eb9ba7..555a30e 100755 (executable)
@@ -1,20 +1,20 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import source, pitch, freqtomidi
+from aubio import source, pitch
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
 
 downsample = 1
-samplerate = 44100 / downsample
+samplerate = 44100 // downsample
 if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
 
-win_s = 4096 / downsample # fft size
-hop_s = 512  / downsample # hop size
+win_s = 4096 // downsample # fft size
+hop_s = 512  // downsample # hop size
 
 s = source(filename, samplerate, hop_s)
 samplerate = s.samplerate
@@ -36,7 +36,7 @@ while True:
     #pitch = int(round(pitch))
     confidence = pitch_o.get_confidence()
     #if confidence < 0.8: pitch = 0.
-    #print "%f %f %f" % (total_frames / float(samplerate), pitch, confidence)
+    print("%f %f %f" % (total_frames / float(samplerate), pitch, confidence))
     pitches += [pitch]
     confidences += [confidence]
     total_frames += read
@@ -45,6 +45,7 @@ while True:
 if 0: sys.exit(0)
 
 #print pitches
+import os.path
 from numpy import array, ma
 import matplotlib.pyplot as plt
 from demo_waveform_plot import get_waveform_plot, set_xlabels_sample2time
@@ -63,14 +64,11 @@ plt.setp(ax1.get_xticklabels(), visible = False)
 ax1.set_xlabel('')
 
 def array_from_text_file(filename, dtype = 'float'):
-    import os.path
-    from numpy import array
     filename = os.path.join(os.path.dirname(__file__), filename)
     return array([line.split() for line in open(filename).readlines()],
         dtype = dtype)
 
 ax2 = fig.add_subplot(312, sharex = ax1)
-import sys, os.path
 ground_truth = os.path.splitext(filename)[0] + '.f0.Corrected'
 if os.path.isfile(ground_truth):
     ground_truth = array_from_text_file(ground_truth)
index 6407e58..629f327 100755 (executable)
@@ -1,20 +1,17 @@
 #! /usr/bin/env python
 
-from numpy import random, sin, arange, ones, zeros
-from math import pi
-from aubio import fvec, pitch
+import numpy as np
+import aubio
 
 def build_sinusoid(length, freqs, samplerate):
-  return sin( 2. * pi * arange(length) * freqs / samplerate)
+    return np.sin( 2. * np.pi * np.arange(length) * freqs / samplerate).astype(aubio.float_type)
 
 def run_pitch(p, input_vec):
-  f = fvec (p.hop_size)
-  cands = []
-  count = 0
-  for vec_slice in input_vec.reshape((-1, p.hop_size)):
-    f[:] = vec_slice
-    cands.append(p(f))
-  return cands
+    cands = []
+    for vec_slice in input_vec.reshape((-1, p.hop_size)):
+        a = p(vec_slice)[0]
+        cands.append(a)
+    return cands
 
 methods = ['default', 'schmitt', 'fcomb', 'mcomb', 'yin', 'yinfft']
 
@@ -23,9 +20,9 @@ buf_size = 2048
 hop_size = 512
 samplerate = 44100
 sin_length = (samplerate * 10) % 512 * 512
-freqs = zeros(sin_length)
+freqs = np.zeros(sin_length)
 
-partition = sin_length / 8
+partition = sin_length // 8
 pointer = 0
 
 pointer += partition
@@ -40,29 +37,35 @@ freqs[ pointer : pointer + partition ] = 1480
 
 pointer += partition
 pointer += partition
-freqs[ pointer : pointer + partition ] = 400 + 5 * random.random(sin_length/8)
+freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length/8)
 
 a = build_sinusoid(sin_length, freqs, samplerate)
 
 for method in methods:
-  p = pitch(method, buf_size, hop_size, samplerate)
-  cands[method] = run_pitch(p, a)
+    p = aubio.pitch(method, buf_size, hop_size, samplerate)
+    cands[method] = run_pitch(p, a)
+    print(method)
+    print(cands[method])
 
-print "done computing"
+print("done computing")
 
 if 1:
-  from pylab import plot, show, xlabel, ylabel, legend, ylim
-  ramp = arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
-  for method in methods:
-    plot(ramp, cands[method],'.-')
+    import matplotlib.pyplot as plt
 
-  # plot ground truth
-  ramp = arange(0, sin_length).astype('float') / samplerate
-  plot(ramp, freqs, ':')
+    # times
+    ramp = np.arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
 
-  legend(methods+['ground truth'], 'upper right')
-  xlabel('time (s)')
-  ylabel('frequency (Hz)')
-  ylim([0,2000])
-  show()
+    # plot each result
+    for method in methods:
+        plt.plot(ramp, cands[method], '.-', label=method)
 
+    # plot ground truth
+    ramp = np.arange(0, sin_length).astype('float') / samplerate
+    plt.plot(ramp, freqs, ':', label = 'ground truth')
+
+    plt.legend(loc='upper left')
+
+    plt.xlabel('time (s)')
+    plt.ylabel('frequency (Hz)')
+    plt.ylim([0,2000])
+    plt.show()
diff --git a/python/demos/demo_pyaudio.py b/python/demos/demo_pyaudio.py
new file mode 100755 (executable)
index 0000000..4c14cd5
--- /dev/null
@@ -0,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()
index e3816d2..b97a838 100755 (executable)
@@ -10,7 +10,6 @@ def record_sink(sink_path):
     duration = 5 # in seconds
     s = Stream(blocksize = hop_size, channels = 1)
     g = sink(sink_path, samplerate = int(s.samplerate))
-    print s.channels
 
     s.start()
     total_frames = 0
@@ -21,9 +20,9 @@ def record_sink(sink_path):
             mono_vec = vec.sum(-1) / float(s.channels[0])
             g(mono_vec, hop_size)
             total_frames += hop_size
-    except KeyboardInterrupt, e:
-        print "stopped after", "%.2f seconds" % (total_frames / s.samplerate)
-        pass
+    except KeyboardInterrupt:
+        duration = total_frames / float(s.samplerate)
+        print("stopped after %.2f seconds" % duration)
     s.stop()
 
 if __name__ == '__main__':
diff --git a/python/demos/demo_reading_speed.py b/python/demos/demo_reading_speed.py
new file mode 100755 (executable)
index 0000000..90739f3
--- /dev/null
@@ -0,0 +1,139 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+
+Compare the speed of several methods for reading and loading a sound file.
+
+Optionally, this file can make use of the following packages:
+
+    - audioread     https://github.com/beetbox/audioread
+    - scipy         https://scipy.org
+    - librosa       https://github.com/bmcfee/librosa
+    - pydub         https://github.com/jiaaro/pydub
+
+Uncomment the function names below and send us your speed results!
+
+"""
+
+
+test_functions = [
+            "read_file_aubio",
+            "load_file_aubio",
+            #"load_file_scipy",
+            #"load_file_scipy_mmap",
+            #"read_file_audioread",
+            #"load_file_librosa",
+            #"read_file_pydub",
+            #"load_file_pydub",
+            ]
+
+
+import numpy as np
+
+def read_file_audioread(filename):
+    import audioread
+    # taken from librosa.util.utils
+    def convert_buffer_to_float(buf, n_bytes = 2, dtype = np.float32):
+        # Invert the scale of the data
+        scale = 1./float(1 << ((8 * n_bytes) - 1))
+        # Construct the format string
+        fmt = '<i{:d}'.format(n_bytes)
+        # Rescale and format the data buffer
+        out = scale * np.frombuffer(buf, fmt).astype(dtype)
+        return out
+
+    with audioread.audio_open(filename) as f:
+        total_frames = 0
+        for buf in f:
+            samples = convert_buffer_to_float(buf)
+            samples = samples.reshape(f.channels, -1)
+            total_frames += samples.shape[1]
+        return total_frames, f.samplerate
+
+def load_file_librosa(filename):
+    import librosa
+    y, sr = librosa.load(filename, sr = None)
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def load_file_scipy(filename):
+    import scipy.io.wavfile
+    sr, y = scipy.io.wavfile.read(filename)
+    y = y.astype('float32') / 32767
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def load_file_scipy_mmap(filename):
+    import scipy.io.wavfile
+    sr, y = scipy.io.wavfile.read(filename, mmap = True)
+    #print y.mean(), y.shape
+    return len(y), sr
+
+def read_file_pydub(filename):
+    from pydub import AudioSegment
+    song = AudioSegment.from_file(filename)
+    song.get_array_of_samples()
+    return song.frame_count(), song.frame_rate
+
+def load_file_pydub(filename):
+    from pydub import AudioSegment
+    song = AudioSegment.from_file(filename)
+    y = np.asarray(song.get_array_of_samples(), dtype = 'float32')
+    y = y.reshape(song.channels, -1) / 32767.
+    return song.frame_count(), song.frame_rate
+
+def read_file_aubio(filename):
+    import aubio
+    f = aubio.source(filename, hop_size = 1024)
+    total_frames = 0
+    while True:
+        _, read = f()
+        total_frames += read
+        if read < f.hop_size: break
+    return total_frames, f.samplerate
+
+def load_file_aubio(filename):
+    import aubio
+    f = aubio.source(filename, hop_size = 1024)
+    y = np.zeros(f.duration, dtype = aubio.float_type)
+    total_frames = 0
+    while True:
+        samples, read = f()
+        y[total_frames:total_frames + read] = samples[:read]
+        total_frames += read
+        if read < f.hop_size: break
+    assert len(y) == total_frames
+    #print y.mean(), y.shape
+    return total_frames, f.samplerate
+
+def test_speed(function, filename):
+    times = []
+    for _ in range(10):
+        start = time.time()
+        try:
+            total_frames, samplerate = function(filename)
+        except ImportError as e:
+            print ("error: failed importing {:s}".format(e))
+            return
+        elapsed = time.time() - start
+        #print ("{:5f} ".format(elapsed)),
+        times.append(elapsed)
+
+    #print
+    times = np.array(times)
+    duration_min = int(total_frames/float(samplerate) // 60)
+    str_format = '{:25s} took {:5f} seconds avg (±{:5f}) to run on a ~ {:d} minutes long file'
+    print (str_format.format(function.__name__, times.mean(), times.std(), duration_min ))
+
+if __name__ == '__main__':
+    import sys, time
+    if len(sys.argv) < 2:
+        print ("not enough arguments")
+        sys.exit(1)
+    filename = sys.argv[1]
+
+    for f in test_functions:
+        # get actual function from globals
+        test_function = globals()[f]
+        test_speed(test_function, filename)
index ac2a0f0..670f79f 100755 (executable)
@@ -4,27 +4,26 @@ import sys
 from aubio import source, sink, pvoc
 
 if __name__ == '__main__':
-  if len(sys.argv) < 2:
-    print 'usage: %s <inputfile> <outputfile>' % sys.argv[0]
-    sys.exit(1)
-  samplerate = 44100
-  f = source(sys.argv[1], samplerate, 256)
-  g = sink(sys.argv[2], samplerate)
-  total_frames, read = 0, 256
+    if len(sys.argv) < 2:
+        print('usage: %s <inputfile> <outputfile>' % sys.argv[0])
+        sys.exit(1)
+    samplerate = 44100
+    f = source(sys.argv[1], samplerate, 256)
+    g = sink(sys.argv[2], samplerate)
+    total_frames, read = 0, 256
 
-  win_s = 512                 # fft size
-  hop_s = win_s / 2           # hop size
-  pv = pvoc(win_s, hop_s)                            # phase vocoder
+    win_s = 512                          # fft size
+    hop_s = win_s // 2                   # hop size
+    pv = pvoc(win_s, hop_s)              # phase vocoder
 
-  while read:
-    samples, read = f()
-    spectrum = pv(samples)            # compute spectrum
-    #spectrum.norm *= .8               # reduce amplitude a bit
-    spectrum.phas[:] = 0.             # zero phase
-    new_samples = pv.rdo(spectrum)    # compute modified samples
-    g(new_samples, read)              # write to output
-    total_frames += read
+    while read:
+        samples, read = f()
+        spectrum = pv(samples)           # compute spectrum
+        #spectrum.norm *= .8             # reduce amplitude a bit
+        spectrum.phas[:] = 0.            # zero phase
+        new_samples = pv.rdo(spectrum)   # compute modified samples
+        g(new_samples, read)             # write to output
+        total_frames += read
 
-  print "wrote", total_frames, "from", f.uri, "to", g.uri
-
-  
+    format_str = "read {:d} samples from {:s}, written to {:s}"
+    print(format_str.format(total_frames, f.uri, g.uri))
index b84f7d8..dd4abbe 100755 (executable)
@@ -13,7 +13,7 @@ def hanningz(size):
 
 if __name__ == '__main__':
     if len(sys.argv) < 2:
-        print 'usage: %s <inputfile> <outputfile>' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile>' % sys.argv[0])
         sys.exit(1)
     samplerate = 0 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,7 +22,7 @@ if __name__ == '__main__':
     g = sink(sys.argv[2], samplerate)
 
     win_s = 512 # fft size
-    hop_s = win_s / 2 # hop size
+    hop_s = win_s // 2 # hop size
     pv = pvoc(win_s, hop_s) # phase vocoder
 
     # spectral weighting vector
@@ -30,7 +30,7 @@ if __name__ == '__main__':
         .8 * hanningz(80)[40:],
         zeros( 50 ),
         1.3 * hanningz(100),
-        zeros (win_s / 2 + 1 - 40 - 50 - 100),
+        zeros (win_s // 2 + 1 - 40 - 50 - 100),
         ] )
 
     if 0:
@@ -52,4 +52,5 @@ if __name__ == '__main__':
         g(new_samples, read)
         total_frames += read
 
-    print "read", total_frames / float(samplerate), "seconds from", f.uri
+    duration = total_frames / float(samplerate)
+    print("read {:.3f}s from {:s}".format(duration, f.uri))
index 93139ae..ce2bb1b 100755 (executable)
@@ -5,7 +5,7 @@ from aubio import source, sink
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,8 +22,10 @@ if __name__ == '__main__':
         vec, read = f()
         g(vec, read)
         total_frames += read
-    print "wrote", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri,
-    print "to", g.uri
+    outstr = "wrote %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    outstr += " to " + g.uri
+    print(outstr)
index 2c06a5f..5a42adc 100755 (executable)
@@ -2,11 +2,11 @@
 
 import sys
 from math import pi, e
-from aubio import sink
-from numpy import arange, resize, sin, exp, zeros
+from aubio import sink, float_type
+from numpy import arange, sin, exp, zeros
 
 if len(sys.argv) < 2:
-    print 'usage: %s <outputfile> [samplerate]' % sys.argv[0]
+    print('usage: %s <outputfile> [samplerate]' % sys.argv[0])
     sys.exit(1)
 
 samplerate = 44100 # samplerate in Hz
@@ -25,9 +25,9 @@ decay = .5
 period = float(samplerate) /  pitch
 # create a sine lookup table
 tablelen = 1000
-sinetable = arange(tablelen + 1, dtype = 'float32')
+sinetable = arange(tablelen + 1, dtype = float_type)
 sinetable = 0.7 * sin(twopi * sinetable/tablelen)
-sinetone = zeros((duration,), dtype = 'float32')
+sinetone = zeros((duration,), dtype = float_type)
 
 # compute sinetone at floating point period
 for i in range(duration):
@@ -39,7 +39,7 @@ for i in range(duration):
     sinetone[i] = a + frac * (b -a)
 
 # apply some envelope
-float_ramp = arange(duration, dtype = 'float32')
+float_ramp = arange(duration, dtype = float_type)
 sinetone *= exp( - e * float_ramp / duration / decay)
 sinetone[:attack] *= exp( e * ( float_ramp[:attack] / attack - 1 ) )
 
index dcf20da..70eb636 100755 (executable)
@@ -5,7 +5,7 @@ from aubio import source, sink
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
 
     if len(sys.argv) > 3: samplerate = int(sys.argv[3])
@@ -22,10 +22,11 @@ if __name__ == '__main__':
         vec, read = f.do_multi()
         g.do_multi(vec, read)
         total_frames += read
-    print "wrote", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks",
-    print "of", f.channels, "channels",
-    print "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri,
-    print "to", g.uri
+    outstr = "wrote %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " of %d channels" % f.channels
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    outstr += " to " + g.uri
+    print(outstr)
index a21252a..d10d0af 100755 (executable)
@@ -6,7 +6,7 @@ from aubio import source, sink
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print 'usage: %s <inputfile> <duration>' % sys.argv[0]
+        print('usage: %s <inputfile> <duration>' % sys.argv[0])
         sys.exit(1)
     source_file = sys.argv[1]
     duration = float(sys.argv[2])
@@ -44,7 +44,8 @@ if __name__ == '__main__':
         total_frames_written += read
     total_duration = total_frames_written / float(samplerate)
     slice_n += 1
-    print 'created %(slice_n)s slices from %(source_base_name)s%(source_ext)s' % locals(),
-    print ' (total duration %(total_duration).2fs)' % locals()
+    outstr = 'created %(slice_n)s slices from %(source_base_name)s%(source_ext)s' % locals()
+    outstr += ' (total duration %(total_duration).2fs)' % locals()
+    print(outstr)
     # close source and sink files
     del f, g
index 30318b1..c60d785 100755 (executable)
@@ -5,7 +5,7 @@ from aubio import source
 
 if __name__ == '__main__':
     if len(sys.argv) < 2:
-        print 'usage: %s <inputfile> [samplerate] [hop_size]' % sys.argv[0]
+        print('usage: %s <inputfile> [samplerate] [hop_size]' % sys.argv[0])
         sys.exit(1)
     samplerate = 0
     hop_size = 256
@@ -20,7 +20,9 @@ if __name__ == '__main__':
         vec, read = f()
         total_frames += read
         if read < f.hop_size: break
-    print "read", "%.2fs" % (total_frames / float(samplerate) ),
-    print "(", total_frames, "frames", "in",
-    print total_frames / f.hop_size, "blocks", "at", "%dHz" % f.samplerate, ")",
-    print "from", f.uri
+    outstr = "read %.2fs" % (total_frames / float(samplerate))
+    outstr += " (%d frames in" % total_frames
+    outstr += " %d blocks" % (total_frames // f.hop_size)
+    outstr += " at %dHz)" % f.samplerate
+    outstr += " from " + f.uri
+    print(outstr)
diff --git a/python/demos/demo_source_simple.py b/python/demos/demo_source_simple.py
new file mode 100755 (executable)
index 0000000..46bd8be
--- /dev/null
@@ -0,0 +1,16 @@
+#! /usr/bin/env python
+import sys, 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)
+total_frames = 0
+
+while True: # reading loop
+    samples, read = s()
+    total_frames += read
+    if read < hop_size: break # end of file reached
+
+fmt_string = "read {:d} frames at {:d}Hz from {:s}"
+print (fmt_string.format(total_frames, s.samplerate, sys.argv[1]))
+
index b152029..6afc7f4 100755 (executable)
@@ -1,14 +1,14 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import fvec, source, pvoc, specdesc
-from numpy import hstack
+import numpy as np
+from aubio import source, pvoc, specdesc
 
 win_s = 512                 # fft size
-hop_s = win_s / 4           # hop size
+hop_s = win_s // 4          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -30,7 +30,7 @@ o = {}
 
 for method in methods:
     cands = []
-    all_descs[method] = fvec(0)
+    all_descs[method] = np.array([])
     o[method] = specdesc(method, win_s)
 
 total_frames = 0
@@ -39,17 +39,17 @@ downsample = 2
 while True:
     samples, read = s()
     fftgrain = pv(samples)
-    #print "%f" % ( total_frames / float(samplerate) ),
+    #outstr = "%f" % ( total_frames / float(samplerate) )
     for method in methods:
         specdesc_val = o[method](fftgrain)[0]
-        all_descs[method] = hstack ( [all_descs[method], specdesc_val] )
-        #print "%f" % specdesc_val,
-    #print
+        all_descs[method] = np.append(all_descs[method], specdesc_val)
+        #outstr += " %f" % specdesc_val
+    #print(outstr)
     total_frames += read
     if read < hop_s: break
 
 if 1:
-    print "done computing, now plotting"
+    print("done computing, now plotting")
     import matplotlib.pyplot as plt
     from demo_waveform_plot import get_waveform_plot
     from demo_waveform_plot import set_xlabels_sample2time
index cf5f80d..51be917 100755 (executable)
@@ -1,63 +1,77 @@
 #! /usr/bin/env python
 
-import sys
-from aubio import pvoc, source
-from numpy import array, arange, zeros, shape, log10, vstack
-from pylab import imshow, show, cm, axis, ylabel, xlabel, xticks, yticks
+import sys, os.path
+from aubio import pvoc, source, float_type
+from numpy import zeros, log10, vstack
+import matplotlib.pyplot as plt
 
 def get_spectrogram(filename, samplerate = 0):
-  win_s = 512                                        # fft window size
-  hop_s = win_s / 2                                  # hop size
-  fft_s = win_s / 2 + 1                              # spectrum bins
+    win_s = 512                                        # fft window size
+    hop_s = win_s // 2                                 # hop size
+    fft_s = win_s // 2 + 1                             # spectrum bins
 
-  a = source(filename, samplerate, hop_s)            # source file
-  if samplerate == 0: samplerate = a.samplerate
-  pv = pvoc(win_s, hop_s)                            # phase vocoder
-  specgram = zeros([0, fft_s], dtype='float32')      # numpy array to store spectrogram
+    a = source(filename, samplerate, hop_s)            # source file
+    if samplerate == 0: samplerate = a.samplerate
+    pv = pvoc(win_s, hop_s)                            # phase vocoder
+    specgram = zeros([0, fft_s], dtype=float_type)     # numpy array to store spectrogram
 
-  # analysis
-  while True:
-    samples, read = a()                              # read file
-    specgram = vstack((specgram,pv(samples).norm))   # store new norm vector
-    if read < a.hop_size: break
+    # analysis
+    while True:
+        samples, read = a()                              # read file
+        specgram = vstack((specgram,pv(samples).norm))   # store new norm vector
+        if read < a.hop_size: break
 
-  # plotting
-  imshow(log10(specgram.T + .001), origin = 'bottom', aspect = 'auto', cmap=cm.gray_r)
-  axis([0, len(specgram), 0, len(specgram[0])])
-  # show axes in Hz and seconds
-  time_step = hop_s / float(samplerate)
-  total_time = len(specgram) * time_step
-  print "total time: %0.2fs" % total_time,
-  print ", samplerate: %.2fkHz" % (samplerate / 1000.)
-  n_xticks = 10
-  n_yticks = 10
+    # plotting
+    fig = plt.imshow(log10(specgram.T + .001), origin = 'bottom', aspect = 'auto', cmap=plt.cm.gray_r)
+    ax = fig.axes
+    ax.axis([0, len(specgram), 0, len(specgram[0])])
+    # show axes in Hz and seconds
+    time_step = hop_s / float(samplerate)
+    total_time = len(specgram) * time_step
+    outstr = "total time: %0.2fs" % total_time
+    print(outstr + ", samplerate: %.2fkHz" % (samplerate / 1000.))
+    n_xticks = 10
+    n_yticks = 10
 
-  def get_rounded_ticks( top_pos, step, n_ticks ):
-      top_label = top_pos * step
-      # get the first label
-      ticks_first_label = top_pos * step / n_ticks
-      # round to the closest .1
-      ticks_first_label = round ( ticks_first_label * 10. ) / 10.
-      # compute all labels from the first rounded one
-      ticks_labels = [ ticks_first_label * n for n in range(n_ticks) ] + [ top_label ]
-      # get the corresponding positions
-      ticks_positions = [ ticks_labels[n] / step for n in range(n_ticks) ] + [ top_pos ]
-      # convert to string
-      ticks_labels = [  "%.1f" % x for x in ticks_labels ]
-      # return position, label tuple to use with x/yticks
-      return ticks_positions, ticks_labels
-
-  # apply to the axis
-  xticks( *get_rounded_ticks ( len(specgram), time_step, n_xticks ) )
-  yticks( *get_rounded_ticks ( len(specgram[0]), (samplerate / 2. / 1000.) / len(specgram[0]), n_yticks ) )
-  ylabel('Frequency (kHz)')
-  xlabel('Time (s)')
+    def get_rounded_ticks( top_pos, step, n_ticks ):
+        top_label = top_pos * step
+        # get the first label
+        ticks_first_label = top_pos * step / n_ticks
+        # round to the closest .1
+        ticks_first_label = round ( ticks_first_label * 10. ) / 10.
+        # compute all labels from the first rounded one
+        ticks_labels = [ ticks_first_label * n for n in range(n_ticks) ] + [ top_label ]
+        # get the corresponding positions
+        ticks_positions = [ ticks_labels[n] / step for n in range(n_ticks) ] + [ top_pos ]
+        # convert to string
+        ticks_labels = [  "%.1f" % x for x in ticks_labels ]
+        # return position, label tuple to use with x/yticks
+        return ticks_positions, ticks_labels
+  
+    # apply to the axis
+    x_ticks, x_labels = get_rounded_ticks ( len(specgram), time_step, n_xticks )
+    y_ticks, y_labels = get_rounded_ticks ( len(specgram[0]), (samplerate / 1000. / 2.) / len(specgram[0]), n_yticks )
+    ax.set_xticks( x_ticks )
+    ax.set_yticks ( y_ticks )
+    ax.set_xticklabels( x_labels )
+    ax.set_yticklabels ( y_labels )
+    ax.set_ylabel('Frequency (kHz)')
+    ax.set_xlabel('Time (s)')
+    ax.set_title(os.path.basename(filename))
+    for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
+            ax.get_xticklabels() + ax.get_yticklabels()):
+        item.set_fontsize('x-small')
+    return fig
 
 if __name__ == '__main__':
-  if len(sys.argv) < 2:
-    print "Usage: %s <filename>" % sys.argv[0]
-  else:
-    for soundfile in sys.argv[1:]:
-      get_spectrogram(soundfile)
-      # display graph
-      show()
+    if len(sys.argv) < 2:
+        print("Usage: %s <filename>" % sys.argv[0])
+    else:
+        for soundfile in sys.argv[1:]:
+            fig = get_spectrogram(soundfile)
+            # display graph
+            plt.show()
+            #outimage = os.path.basename(soundfile) + '.png'
+            #print ("writing: " + outimage)
+            #plt.savefig(outimage)
+            plt.close()
index 17b959b..51e1ae3 100755 (executable)
@@ -4,10 +4,10 @@ import sys
 from aubio import tempo, source
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -33,7 +33,7 @@ while True:
     is_beat = o(samples)
     if is_beat:
         this_beat = int(total_frames - delay + is_beat[0] * hop_s)
-        print "%f" % (this_beat / float(samplerate))
+        print("%f" % (this_beat / float(samplerate)))
         beats.append(this_beat)
     total_frames += read
     if read < hop_s: break
index de06d00..48a6ccf 100755 (executable)
@@ -4,10 +4,10 @@ import sys
 from aubio import tempo, source
 
 win_s = 512                 # fft size
-hop_s = win_s / 2           # hop size
+hop_s = win_s // 2          # hop size
 
 if len(sys.argv) < 2:
-    print "Usage: %s <filename> [samplerate]" % sys.argv[0]
+    print("Usage: %s <filename> [samplerate]" % sys.argv[0])
     sys.exit(1)
 
 filename = sys.argv[1]
@@ -39,11 +39,11 @@ while True:
 
 if len(beats) > 1:
     # do plotting
-    from numpy import array, arange, mean, median, diff
+    from numpy import mean, median, diff
     import matplotlib.pyplot as plt
     bpms = 60./ diff(beats)
-    print 'mean period:', "%.2f" % mean(bpms), 'bpm', 'median', "%.2f" % median(bpms), 'bpm'
-    print 'plotting', filename
+    print('mean period: %.2fbpm, median: %.2fbpm' % (mean(bpms), median(bpms)))
+    print('plotting %s' % filename)
     plt1 = plt.axes([0.1, 0.75, 0.8, 0.19])
     plt2 = plt.axes([0.1, 0.1, 0.8, 0.65], sharex = plt1)
     plt.rc('lines',linewidth='.8')
@@ -75,5 +75,5 @@ if len(beats) > 1:
     plt.show()
 
 else:
-    print 'mean period:', "%.2f" % 0, 'bpm', 'median', "%.2f" % 0, 'bpm',
-    print 'nothing to plot, file too short?'
+    print('mean period: %.2fbpm, median: %.2fbpm' % (0, 0))
+    print('plotting %s' % filename)
diff --git a/python/demos/demo_timestretch.py b/python/demos/demo_timestretch.py
new file mode 100755 (executable)
index 0000000..2271d01
--- /dev/null
@@ -0,0 +1,110 @@
+#! /usr/bin/env python
+
+# Implementation of the timescale algorithm according to Dan Ellis, *A Phase
+# Vocoder in Matlab*.  http://www.ee.columbia.edu/~dpwe/resources/matlab/pvoc/
+
+# This file follows the original implementation, with analysis in a first pass,
+# and synthesis in a second pass.
+
+import sys
+from aubio import source, sink, pvoc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 1024
+hop_s = win_s // 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+    print("Usage: {:s} <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+    print("""Examples:
+    # twice faster
+    {0} track_01.mp3 track_01_faster.wav 2.0
+    # twice slower
+    {0} track_02.flac track_02_slower.wav 0.5
+    # one and a half time faster, resampling first the input to 22050
+    {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+    sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+# allocate memory to store norms and phases
+n_blocks = source_in.duration // hop_s + 1
+# adding an empty frame at end of spectrogram
+norms  = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+phases = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+
+block_read = 0
+while True:
+    # read from source
+    samples, read = source_in()
+    # compute fftgrain
+    spec = p(samples)
+    # store current grain
+    norms[block_read] = spec.norm
+    phases[block_read] = spec.phas
+    # until end of file
+    if read < hop_s: break
+    # increment block counter
+    block_read += 1
+
+# just to make sure
+#source_in.close()
+
+sink_out = sink(output_filename, samplerate)
+
+# interpolated time steps (j = alpha * i)
+steps = np.arange(0, n_blocks, rate, dtype = float_type)
+# initial phase
+phas_acc = phases[0]
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+new_grain = cvec(win_s)
+
+for (t, step) in enumerate(steps):
+
+    frac = 1. - np.mod(step, 1.0)
+    # get pair of frames
+    t_norms = norms[int(step):int(step+2)]
+    t_phases = phases[int(step):int(step+2)]
+
+    # compute interpolated frame
+    new_grain.norm = frac * t_norms[0] + (1. - frac) * t_norms[1]
+    new_grain.phas = phas_acc
+    #print t, step, new_grain.norm
+    #print t, step, phas_acc
+
+    # psola
+    samples = p.rdo(new_grain)
+    if t > warmup: # skip the first few frames to warm up phase vocoder
+        # write to sink
+        sink_out(samples, hop_s)
+
+    # calculate phase advance
+    dphas = t_phases[1] - t_phases[0] - phi_advance
+    # unwrap angle to [-pi; pi]
+    dphas = unwrap2pi(dphas)
+    # cumulate phase, to be used for next frame
+    phas_acc += phi_advance + dphas
+
+for t in range(warmup + 1): # purge the last frames from the phase vocoder
+    new_grain.norm[:] = 0
+    new_grain.phas[:] = 0
+    samples = p.rdo(new_grain)
+    sink_out(samples, read if t == warmup else hop_s)
+
+# just to make sure
+#sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+    len(steps), output_filename))
diff --git a/python/demos/demo_timestretch_online.py b/python/demos/demo_timestretch_online.py
new file mode 100755 (executable)
index 0000000..df70365
--- /dev/null
@@ -0,0 +1,112 @@
+#! /usr/bin/env python
+
+# Implementation of the timescale algorithm according to Dan Ellis, *A Phase
+# Vocoder in Matlab*.  http://www.ee.columbia.edu/~dpwe/resources/matlab/pvoc/
+
+# This file performs both analysis and synthesis in a single pass. See also
+# `demo_timestretch.py` for a version following the original implementation.
+
+import sys
+from aubio import source, sink, pvoc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 512
+hop_s = win_s // 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+    print("Usage: {:s} <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+    print("""Examples:
+    # twice faster
+    {0} track_01.mp3 track_01_faster.wav 2.0
+    # twice slower
+    {0} track_02.flac track_02_slower.wav 0.5
+    # one and a half time faster, resampling first the input to 22050
+    {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+    sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+sink_out = sink(output_filename, samplerate)
+
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+old_grain = cvec(win_s)
+new_grain = cvec(win_s)
+
+block_read = 0
+interp_read = 0
+interp_block = 0
+while True:
+
+    samples, read = source_in()
+    cur_grain = p(samples)
+
+    if block_read == 1:
+        phas_acc = old_grain.phas
+
+    #print "block_read", block_read
+    while True and (block_read > 0):
+        if interp_read >= block_read:
+            break
+        #print "`--- interp_block:", interp_block,
+        #print 'at orig_block', interp_read, '<- from', block_read - 1, block_read,
+        #print 'old_grain', old_grain, 'cur_grain', cur_grain
+        # time to compute interp grain
+        frac = 1. - np.mod(interp_read, 1.0)
+
+        # compute interpolated frame
+        new_grain.norm = frac * old_grain.norm + (1. - frac) * cur_grain.norm
+        new_grain.phas = phas_acc
+
+        # psola
+        samples = p.rdo(new_grain)
+        if interp_read > warmup: # skip the first frames to warm up phase vocoder
+            # write to sink
+            sink_out(samples, hop_s)
+
+        # calculate phase advance
+        dphas = cur_grain.phas - old_grain.phas - phi_advance
+        # unwrap angle to [-pi; pi]
+        dphas = unwrap2pi(dphas)
+        # cumulate phase, to be used for next frame
+        phas_acc += phi_advance + dphas
+
+        # prepare for next interp block
+        interp_block += 1
+        interp_read = interp_block * rate
+        if interp_read >= block_read:
+            break
+
+    # copy cur_grain to old_grain
+    old_grain.norm = np.copy(cur_grain.norm)
+    old_grain.phas = np.copy(cur_grain.phas)
+
+    # 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
+    new_grain.phas[:] = 0
+    samples = p.rdo(new_grain)
+    sink_out(samples, read if t == warmup + 1 else hop_s)
+
+# just to make sure
+source_in.close()
+sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+    interp_block, output_filename))
index 884dc9b..1a56b4f 100755 (executable)
@@ -4,44 +4,46 @@ import sys
 from aubio import source, sink, pvoc, tss
 
 if __name__ == '__main__':
-  if len(sys.argv) < 2:
-    print 'usage: %s <inputfile> <outputfile_transient> <outputfile_steady>' % sys.argv[0]
-    sys.exit(1)
-
-  samplerate = 44100
-  win_s = 1024      # fft size
-  hop_s = win_s / 4 # block size
-  threshold = 0.5
-
-  f = source(sys.argv[1], samplerate, hop_s)
-  g = sink(sys.argv[2], samplerate)
-  h = sink(sys.argv[3], samplerate)
-
-  pva = pvoc(win_s, hop_s)    # a phase vocoder
-  pvb = pvoc(win_s, hop_s)    # another phase vocoder
-  t = tss(win_s, hop_s)       # transient steady state separation
-
-  t.set_threshold(threshold)
-
-  read = hop_s
-
-  while read:
-    samples, read = f()               # read file
-    spec = pva(samples)                # compute spectrum
-    trans_spec, stead_spec = t(spec)  # transient steady-state separation
-    transients = pva.rdo(trans_spec)   # overlap-add synthesis of transients
-    steadstate = pvb.rdo(stead_spec)   # overlap-add synthesis of steady states
-    g(transients, read)               # write transients to output
-    h(steadstate, read)               # write steady states to output
-
-  del f, g, h                         # finish writing the files now
-
-  from demo_spectrogram import get_spectrogram
-  from pylab import subplot, show
-  subplot(311)
-  get_spectrogram(sys.argv[1])
-  subplot(312)
-  get_spectrogram(sys.argv[2])
-  subplot(313)
-  get_spectrogram(sys.argv[3])
-  show()
+    if len(sys.argv) < 2:
+        print('usage: %s <inputfile> <outputfile_transient> <outputfile_steady>' % sys.argv[0])
+        sys.exit(1)
+
+    samplerate = 44100
+    win_s = 1024       # fft size
+    hop_s = win_s // 8 # block size
+
+    f = source(sys.argv[1], samplerate, hop_s)
+    g = sink(sys.argv[2], samplerate)
+    h = sink(sys.argv[3], samplerate)
+
+    pva = pvoc(win_s, hop_s)    # a phase vocoder
+    pvb = pvoc(win_s, hop_s)    # another phase vocoder
+    t = tss(win_s, hop_s)       # transient steady state separation
+
+    t.set_threshold(0.01)
+    t.set_alpha(3.)
+    t.set_beta(4.)
+
+    read = hop_s
+
+    while read:
+        samples, read = f()               # read file
+        spec = pva(samples)               # compute spectrum
+        trans_spec, stead_spec = t(spec)  # transient steady-state separation
+        transients = pva.rdo(trans_spec)  # overlap-add synthesis of transients
+        steadstate = pvb.rdo(stead_spec)  # overlap-add synthesis of steady states
+        g(transients, read)               # write transients to output
+        h(steadstate, read)               # write steady states to output
+
+    del f, g, h                           # finish writing the files now
+    sys.exit(0)
+
+    from demo_spectrogram import get_spectrogram
+    from pylab import subplot, show
+    subplot(311)
+    get_spectrogram(sys.argv[1])
+    subplot(312)
+    get_spectrogram(sys.argv[2])
+    subplot(313)
+    get_spectrogram(sys.argv[3])
+    show()
index 91c6eda..5434223 100755 (executable)
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 
 import sys
-from aubio import pvoc, source
+from aubio import source
 from numpy import zeros, hstack
 
 def get_waveform_plot(filename, samplerate = 0, block_size = 4096, ax = None, downsample = 2**4):
@@ -21,7 +21,7 @@ def get_waveform_plot(filename, samplerate = 0, block_size = 4096, ax = None, do
     while True:
         samples, read = a()
         # keep some data to plot it later
-        new_maxes = (abs(samples.reshape(hop_s/downsample, downsample))).max(axis=0)
+        new_maxes = (abs(samples.reshape(hop_s//downsample, downsample))).max(axis=0)
         allsamples_max = hstack([allsamples_max, new_maxes])
         total_frames += read
         if read < hop_s: break
@@ -48,7 +48,7 @@ def set_xlabels_sample2time(ax, latest_sample, samplerate):
 if __name__ == '__main__':
     import matplotlib.pyplot as plt
     if len(sys.argv) < 2:
-        print "Usage: %s <filename>" % sys.argv[0]
+        print("Usage: %s <filename>" % sys.argv[0])
     else:
         for soundfile in sys.argv[1:]:
             get_waveform_plot(soundfile)
index 280d01b..26f8b1d 100644 (file)
@@ -1,6 +1,8 @@
 #include <Python.h>
 #include <structmember.h>
 
+#include "aubio-generated.h"
+
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
 
 // define numpy unique symbols for aubio
@@ -25,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
 #define Py_aubio_default_samplerate 44100
 
 #if HAVE_AUBIO_DOUBLE
-#error "Ouch! Python interface for aubio has not been much tested yet."
+// 64 bit precision with HAVE_AUBIO_DOUBLE=1
 #define AUBIO_NPY_SMPL NPY_DOUBLE
+#define AUBIO_NPY_SMPL_STR "float64"
+#define AUBIO_NPY_SMPL_CHR "d"
 #else
+// default is 32 bit precision
 #define AUBIO_NPY_SMPL NPY_FLOAT
+#define AUBIO_NPY_SMPL_STR "float32"
+#define AUBIO_NPY_SMPL_CHR "f"
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAX_PATH
+#define PATH_MAX MAX_PATH
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+// compat with Python < 2.6
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
 #endif
 
-// special python type for cvec
-typedef struct
-{
-  PyObject_HEAD
-  cvec_t * o;
-  uint_t length;
-  uint_t channels;
-} Py_cvec;
 extern PyTypeObject Py_cvecType;
 
+PyObject * new_py_fvec(uint_t length);
+PyObject * new_py_cvec(uint_t length);
+PyObject * new_py_fmat(uint_t height, uint_t length);
+
 // defined in aubio-proxy.c
+extern int PyAubio_IsValidVector (PyObject *input);
+
 extern PyObject *PyAubio_CFvecToArray (fvec_t * self);
-extern fvec_t *PyAubio_ArrayToCFvec (PyObject * self);
+extern int PyAubio_ArrayToCFvec (PyObject * self, fvec_t *out);
 
-extern Py_cvec *PyAubio_CCvecToPyCvec (cvec_t * self);
-extern cvec_t *PyAubio_ArrayToCCvec (PyObject *input);
+extern int PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i);
 
 extern PyObject *PyAubio_CFmatToArray (fmat_t * self);
-extern fmat_t *PyAubio_ArrayToCFmat (PyObject *input);
+extern int PyAubio_ArrayToCFmat (PyObject *input, fmat_t *out);
 
 // hand written wrappers
 extern PyTypeObject Py_filterType;
index 8278db2..76ed9c9 100644 (file)
@@ -1,8 +1,12 @@
 #define PY_AUBIO_MODULE_MAIN
 #include "aubio-types.h"
-#include "aubio-generated.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[] = ""
@@ -75,7 +79,6 @@ static char Py_min_removal_doc[] = ""
 "\n"
 ">>> min_removal(a)";
 
-extern void add_generated_objects ( PyObject *m );
 extern void add_ufuncs ( PyObject *m );
 extern int generated_types_ready(void);
 
@@ -83,11 +86,11 @@ static PyObject *
 Py_alpha_norm (PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   smpl_t alpha;
   PyObject *result;
 
-  if (!PyArg_ParseTuple (args, "Of:alpha_norm", &input, &alpha)) {
+  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":alpha_norm", &input, &alpha)) {
     return NULL;
   }
 
@@ -95,14 +98,12 @@ Py_alpha_norm (PyObject * self, PyObject * args)
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  result = Py_BuildValue ("f", fvec_alpha_norm (vec, alpha));
+  result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, fvec_alpha_norm (&vec, alpha));
   if (result == NULL) {
     return NULL;
   }
@@ -116,7 +117,7 @@ Py_bintomidi (PyObject * self, PyObject * args)
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -131,7 +132,7 @@ Py_miditobin (PyObject * self, PyObject * args)
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -146,7 +147,7 @@ Py_bintofreq (PyObject * self, PyObject * args)
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -161,7 +162,7 @@ Py_freqtobin (PyObject * self, PyObject * args)
   smpl_t input, samplerate, fftsize;
   smpl_t output;
 
-  if (!PyArg_ParseTuple (args, "|fff", &input, &samplerate, &fftsize)) {
+  if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     return NULL;
   }
 
@@ -174,7 +175,7 @@ static PyObject *
 Py_zero_crossing_rate (PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
   PyObject *result;
 
   if (!PyArg_ParseTuple (args, "O:zero_crossing_rate", &input)) {
@@ -185,14 +186,12 @@ Py_zero_crossing_rate (PyObject * self, PyObject * args)
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  result = Py_BuildValue ("f", aubio_zero_crossing_rate (vec));
+  result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, aubio_zero_crossing_rate (&vec));
   if (result == NULL) {
     return NULL;
   }
@@ -204,7 +203,7 @@ static PyObject *
 Py_min_removal(PyObject * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
+  fvec_t vec;
 
   if (!PyArg_ParseTuple (args, "O:min_removal", &input)) {
     return NULL;
@@ -214,19 +213,17 @@ Py_min_removal(PyObject * self, PyObject * args)
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     return NULL;
   }
 
   // compute the function
-  fvec_min_removal (vec);
+  fvec_min_removal (&vec);
 
   // since this function does not return, we could return None
   //Py_RETURN_NONE;
   // however it is convenient to return the modified vector
-  return (PyObject *) PyAubio_CFvecToArray(vec);
+  return (PyObject *) PyAubio_CFvecToArray(&vec);
   // or even without converting it back to an array
   //Py_INCREF(vec);
   //return (PyObject *)vec;
@@ -245,13 +242,44 @@ static PyMethodDef aubio_methods[] = {
   {"silence_detection", Py_aubio_silence_detection, METH_VARARGS, Py_aubio_silence_detection_doc},
   {"level_detection", Py_aubio_level_detection, METH_VARARGS, Py_aubio_level_detection_doc},
   {"window", Py_aubio_window, METH_VARARGS, Py_aubio_window_doc},
-  {NULL, NULL} /* Sentinel */
+  {NULL, NULL, 0, NULL} /* Sentinel */
 };
 
-PyMODINIT_FUNC
-init_aubio (void)
+#if PY_MAJOR_VERSION >= 3
+// Python3 module definition
+static struct PyModuleDef moduledef = {
+   PyModuleDef_HEAD_INIT,
+   "_aubio",          /* m_name */
+   aubio_module_doc,  /* m_doc */
+   -1,                /* m_size */
+   aubio_methods,     /* m_methods */
+   NULL,              /* m_reload */
+   NULL,              /* m_traverse */
+   NULL,              /* m_clear */
+   NULL,              /* m_free */
+};
+#endif
+
+void
+aubio_log_function(int level, const char *message, void *data)
 {
-  PyObject *m;
+  // remove trailing \n
+  char *pos;
+  if ((pos=strchr(message, '\n')) != NULL) {
+        *pos = '\0';
+  }
+  // warning or error
+  if (level == AUBIO_LOG_ERR) {
+    PyErr_Format(PyExc_RuntimeError, "%s", message);
+  } else {
+    PyErr_WarnEx(PyExc_UserWarning, message, 1);
+  }
+}
+
+static PyObject *
+initaubio (void)
+{
+  PyObject *m = NULL;
   int err;
 
   // fvec is defined in __init__.py
@@ -265,13 +293,17 @@ init_aubio (void)
       // generated objects
       || (generated_types_ready() < 0 )
   ) {
-    return;
+    return m;
   }
 
+#if PY_MAJOR_VERSION >= 3
+  m = PyModule_Create(&moduledef);
+#else
   m = Py_InitModule3 ("_aubio", aubio_methods, aubio_module_doc);
+#endif
 
   if (m == NULL) {
-    return;
+    return m;
   }
 
   err = _import_array ();
@@ -295,9 +327,30 @@ init_aubio (void)
   Py_INCREF (&Py_sinkType);
   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);
 
   // add ufunc
   add_ufuncs(m);
+
+  aubio_log_set_level_function(AUBIO_LOG_ERR, aubio_log_function, NULL);
+  aubio_log_set_level_function(AUBIO_LOG_WRN, aubio_log_function, NULL);
+  return m;
 }
+
+#if PY_MAJOR_VERSION >= 3
+    // Python3 init
+    PyMODINIT_FUNC PyInit__aubio(void)
+    {
+        return initaubio();
+    }
+#else
+    // Python 2 init
+    PyMODINIT_FUNC init_aubio(void)
+    {
+        initaubio();
+    }
+#endif
index d3c0094..f5d7fa4 100644 (file)
@@ -1,12 +1,30 @@
 #include "aubio-types.h"
 
-fvec_t *
-PyAubio_ArrayToCFvec (PyObject *input) {
-  PyObject *array;
-  fvec_t *vec;
+PyObject *
+new_py_fvec(uint_t length) {
+    npy_intp dims[] = { length, 1 };
+    return PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+}
+
+PyObject *
+new_py_fmat(uint_t height, uint_t length) {
+    npy_intp dims[] = { height, length, 1 };
+    return PyArray_ZEROS(2, dims, AUBIO_NPY_SMPL, 0);
+}
+
+PyObject *
+PyAubio_CFvecToArray (fvec_t * self)
+{
+  npy_intp dims[] = { self->length, 1 };
+  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data);
+}
+
+int
+PyAubio_IsValidVector (PyObject * input) {
+  npy_intp length;
   if (input == NULL) {
     PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+    return 0;
   }
   // parsing input object into a Py_fvec
   if (PyArray_Check(input)) {
@@ -14,74 +32,47 @@ PyAubio_ArrayToCFvec (PyObject *input) {
     // we got an array, convert it to an fvec
     if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
       PyErr_SetString (PyExc_ValueError, "input array is a scalar");
-      goto fail;
+      return 0;
     } else if (PyArray_NDIM ((PyArrayObject *)input) > 1) {
       PyErr_SetString (PyExc_ValueError,
           "input array has more than one dimensions");
-      goto fail;
+      return 0;
     }
 
     if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
       PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
+      return 0;
     } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float32");
-      goto fail;
-    } else {
-      // input data type is float32, nothing else to do
-      array = input;
+      PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+      return 0;
     }
 
-    // vec = new_fvec (vec->length);
-    // no need to really allocate fvec, just its struct member
-    vec = (fvec_t *)malloc(sizeof(fvec_t));
-    long length = PyArray_SIZE ((PyArrayObject *)array);
-    if (length > 0) {
-      vec->length = (uint_t)length;
-    } else {
+    length = PyArray_SIZE ((PyArrayObject *)input);
+    if (length <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array size should be greater than 0");
-      goto fail;
+      return 0;
     }
-    vec->data = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)array, 0);
 
   } else if (PyObject_TypeCheck (input, &PyList_Type)) {
     PyErr_SetString (PyExc_ValueError, "does not convert from list yet");
-    return NULL;
+    return 0;
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept vector of float as input");
-    return NULL;
+    return 0;
   }
-
-  return vec;
-
-fail:
-  return NULL;
+  return 1;
 }
 
-PyObject *
-PyAubio_CFvecToArray (fvec_t * self)
-{
-  npy_intp dims[] = { self->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->data);
-}
-
-Py_cvec *
-PyAubio_CCvecToPyCvec (cvec_t * input) {
-  Py_cvec *vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
-  vec->length = input->length;
-  vec->o = input;
-  Py_INCREF(vec);
-  return vec;
-}
+int
+PyAubio_ArrayToCFvec (PyObject *input, fvec_t *out) {
 
-cvec_t *
-PyAubio_ArrayToCCvec (PyObject *input) {
-  if (PyObject_TypeCheck (input, &Py_cvecType)) {
-      return ((Py_cvec*)input)->o;
-  } else {
-      PyErr_SetString (PyExc_ValueError, "input array should be float32");
-      return NULL;
+  if (!PyAubio_IsValidVector(input)){
+    return 0;
   }
+
+  out->length = (uint_t) PyArray_SIZE ((PyArrayObject *)input);
+  out->data = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)input, 0);
+  return 1;
 }
 
 PyObject *
@@ -101,14 +92,13 @@ PyAubio_CFmatToArray (fmat_t * input)
   return array;
 }
 
-fmat_t *
-PyAubio_ArrayToCFmat (PyObject *input) {
-  PyObject *array;
-  fmat_t *mat;
-  uint_t i;
+int
+PyAubio_ArrayToCFmat (PyObject *input, fmat_t *mat) {
+  uint_t i, new_height;
+  npy_intp length, height;
   if (input == NULL) {
     PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+    return 0;
   }
   // parsing input object into a Py_fvec
   if (PyArray_Check(input)) {
@@ -116,56 +106,53 @@ PyAubio_ArrayToCFmat (PyObject *input) {
     // we got an array, convert it to an fvec
     if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
       PyErr_SetString (PyExc_ValueError, "input array is a scalar");
-      goto fail;
+      return 0;
     } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
       PyErr_SetString (PyExc_ValueError,
           "input array has more than two dimensions");
-      goto fail;
+      return 0;
     }
 
     if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
       PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
+      return 0;
     } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float32");
-      goto fail;
-    } else {
-      // input data type is float32, nothing else to do
-      array = input;
+      PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+      return 0;
     }
 
     // no need to really allocate fvec, just its struct member
-    mat = (fmat_t *)malloc(sizeof(fmat_t));
-    long length = PyArray_DIM ((PyArrayObject *)array, 1);
-    if (length > 0) {
-      mat->length = (uint_t)length;
-    } else {
+    length = PyArray_DIM ((PyArrayObject *)input, 1);
+    if (length <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array dimension 1 should be greater than 0");
-      goto fail;
+      return 0;
     }
-    long height = PyArray_DIM ((PyArrayObject *)array, 0);
-    if (height > 0) {
-      mat->height = (uint_t)height;
-    } else {
+    height = PyArray_DIM ((PyArrayObject *)input, 0);
+    if (height <= 0) {
       PyErr_SetString (PyExc_ValueError, "input array dimension 0 should be greater than 0");
-      goto fail;
-    }
-    mat->data = (smpl_t **)malloc(sizeof(smpl_t*) * mat->height);
-    for (i=0; i< mat->height; i++) {
-      mat->data[i] = (smpl_t*)PyArray_GETPTR1 ((PyArrayObject *)array, i);
+      return 0;
     }
 
   } else if (PyObject_TypeCheck (input, &PyList_Type)) {
     PyErr_SetString (PyExc_ValueError, "can not convert list to fmat");
-    return NULL;
+    return 0;
   } else {
     PyErr_SetString (PyExc_ValueError, "can only accept matrix of float as input");
-    return NULL;
+    return 0;
   }
 
-  return mat;
+  new_height = (uint_t)PyArray_DIM ((PyArrayObject *)input, 0);
+  if (mat->height != new_height) {
+    if (mat->data) {
+      free(mat->data);
+    }
+    mat->data = (smpl_t **)malloc(sizeof(smpl_t*) * new_height);
+  }
 
-fail:
-  return NULL;
+  mat->height = new_height;
+  mat->length = (uint_t)PyArray_DIM ((PyArrayObject *)input, 1);
+  for (i=0; i< mat->height; i++) {
+    mat->data[i] = (smpl_t*)PyArray_GETPTR1 ((PyArrayObject *)input, i);
+  }
+  return 1;
 }
-
diff --git a/python/ext/aubiowraphell.h b/python/ext/aubiowraphell.h
deleted file mode 100644 (file)
index d60cc30..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "aubio-types.h"
-
-#define AUBIO_DECLARE(NAME, PARAMS...) \
-typedef struct { \
-  PyObject_HEAD \
-  aubio_ ## NAME ## _t * o; \
-  PARAMS; \
-} Py_## NAME;
-
-#define AUBIO_INIT(NAME, PARAMS... ) \
-static int \
-Py_ ## NAME ## _init (Py_ ## NAME * self, PyObject * args, PyObject * kwds) \
-{ \
-  self->o = new_aubio_## NAME ( PARAMS ); \
-  if (self->o == NULL) { \
-    PyErr_SetString (PyExc_StandardError, "error creating object"); \
-    return -1; \
-  } \
-\
-  return 0; \
-}
-
-#define AUBIO_DEL(NAME) \
-static void \
-Py_ ## NAME ## _del ( Py_ ## NAME * self) \
-{ \
-  del_aubio_ ## NAME (self->o); \
-  self->ob_type->tp_free ((PyObject *) self); \
-}
-
-#define AUBIO_MEMBERS_START(NAME) \
-static PyMemberDef Py_ ## NAME ## _members[] = {
-
-#define AUBIO_MEMBERS_STOP(NAME) \
-  {NULL} \
-};
-
-#define AUBIO_METHODS(NAME) \
-static PyMethodDef Py_ ## NAME ## _methods[] = { \
-  {NULL} \
-};
-
-
-#define AUBIO_TYPEOBJECT(NAME, PYNAME) \
-PyTypeObject Py_ ## NAME ## Type = { \
-  PyObject_HEAD_INIT (NULL)    \
-  0,                           \
-  PYNAME,                      \
-  sizeof (Py_ ## NAME),          \
-  0,                           \
-  (destructor) Py_ ## NAME ## _del,  \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  (ternaryfunc)Py_ ## NAME ## _do,   \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  Py_TPFLAGS_DEFAULT,          \
-  Py_ ## NAME ## _doc,               \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  Py_ ## NAME ## _methods,           \
-  Py_ ## NAME ## _members,           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  0,                           \
-  (initproc) Py_ ## NAME ## _init,   \
-  0,                           \
-  Py_ ## NAME ## _new,               \
-};
-
-// some more helpers
-#define AUBIO_NEW_VEC(name, type, lengthval) \
-  name = (type *) PyObject_New (type, & type ## Type); \
-  name->length = lengthval;
index 940508f..a393c4e 100644 (file)
@@ -1,17 +1,51 @@
 #include "aubio-types.h"
 
-/* cvec type definition 
+/* cvec type definition
 
 class cvec():
-    def __init__(self, length = 1024):
-        self.length = length 
-        self.norm = array(length)
-        self.phas = array(length)
+    def __new__(self, length = 1024):
+        self.length = length / 2 + 1
+        self.norm = np.zeros(length / 2 + 1)
+        self.phas = np.zeros(length / 2 + 1)
 
 */
 
+// special python type for cvec
+typedef struct
+{
+  PyObject_HEAD
+  PyObject *norm;
+  PyObject *phas;
+  uint_t length;
+} Py_cvec;
+
 static char Py_cvec_doc[] = "cvec object";
 
+
+PyObject *
+new_py_cvec(uint_t length) {
+  Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
+  npy_intp dims[] = { length / 2 + 1, 1 };
+  vec->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  vec->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  vec->length = length / 2 + 1;
+  return (PyObject*)vec;
+}
+
+int
+PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) {
+  if (PyObject_TypeCheck (input, &Py_cvecType)) {
+      Py_cvec * in = (Py_cvec *)input;
+      i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0);
+      i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0);
+      i->length = ((Py_cvec*)input)->length;
+      return 1;
+  } else {
+      PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
+      return 0;
+  }
+}
+
 static PyObject *
 Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -24,7 +58,6 @@ Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
     return NULL;
   }
 
-
   self = (Py_cvec *) type->tp_alloc (type, 0);
 
   self->length = Py_default_vector_length / 2 + 1;
@@ -47,19 +80,18 @@ Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 static int
 Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
 {
-  self->o = new_cvec ((self->length - 1) * 2);
-  if (self->o == NULL) {
-    return -1;
-  }
-
+  npy_intp dims[] = { self->length, 1 };
+  self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
+  self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
   return 0;
 }
 
 static void
 Py_cvec_del (Py_cvec * self)
 {
-  del_cvec (self->o);
-  self->ob_type->tp_free ((PyObject *) self);
+  Py_DECREF(self->norm);
+  Py_DECREF(self->phas);
+  Py_TYPE(self)->tp_free ((PyObject *) self);
 }
 
 static PyObject *
@@ -69,7 +101,7 @@ Py_cvec_repr (Py_cvec * self, PyObject * unused)
   PyObject *args = NULL;
   PyObject *result = NULL;
 
-  format = PyString_FromString ("aubio cvec of %d elements");
+  format = PyUnicode_FromString ("aubio cvec of %d elements");
   if (format == NULL) {
     goto fail;
   }
@@ -78,9 +110,9 @@ Py_cvec_repr (Py_cvec * self, PyObject * unused)
   if (args == NULL) {
     goto fail;
   }
-  cvec_print ( self->o );
+  // hide actual norm / phas content
 
-  result = PyString_Format (format, args);
+  result = PyUnicode_Format (format, args);
 
 fail:
   Py_XDECREF (format);
@@ -90,152 +122,61 @@ fail:
 }
 
 PyObject *
-PyAubio_CvecNormToArray (Py_cvec * self)
-{
-  npy_intp dims[] = { self->o->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->norm);
-}
-
-
-PyObject *
-PyAubio_CvecPhasToArray (Py_cvec * self)
-{
-  npy_intp dims[] = { self->o->length, 1 };
-  return PyArray_SimpleNewFromData (1, dims, NPY_FLOAT, self->o->phas);
-}
-
-PyObject *
-PyAubio_ArrayToCvecPhas (PyObject * self)
-{
-  return NULL;
-}
-
-PyObject *
 Py_cvec_get_norm (Py_cvec * self, void *closure)
 {
-  return PyAubio_CvecNormToArray(self);
+  // we want self->norm to still exist after our caller return it
+  Py_INCREF(self->norm);
+  return (PyObject*)(self->norm);
 }
 
 PyObject *
 Py_cvec_get_phas (Py_cvec * self, void *closure)
 {
-  return PyAubio_CvecPhasToArray(self);
+  // we want self->phas to still exist after our caller return it
+  Py_INCREF(self->phas);
+  return (PyObject *)(self->phas);
 }
 
 static int
 Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
 {
-  PyArrayObject * array;
-  if (input == NULL) {
-    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+  npy_intp length;
+  if (!PyAubio_IsValidVector(input)) {
+    return 1;
   }
-  if (PyArray_Check(input)) {
-
-    // we got an array, convert it to a cvec.norm 
-    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
-      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
-      goto fail;
-    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
-      PyErr_SetString (PyExc_ValueError,
-          "input array has more than two dimensions");
-      goto fail;
-    }
-
-    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
-    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float32");
-      goto fail;
-    }
-    array = (PyArrayObject *)input;
-
-    // check input array dimensions
-    if (PyArray_NDIM (array) != 1) {
-      PyErr_Format (PyExc_ValueError,
-          "input array has %d dimensions, not 1",
-          PyArray_NDIM (array));
-      goto fail;
-    } else {
-      if (vec->o->length != PyArray_SIZE (array)) {
-          PyErr_Format (PyExc_ValueError,
-                  "input array has length %d, but cvec has length %d",
-                  (int)PyArray_SIZE (array), vec->o->length);
-          goto fail;
-      }
-    }
-
-    vec->o->norm = (smpl_t *) PyArray_GETPTR1 (array, 0);
-
-  } else {
-    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
+  length = PyArray_SIZE ((PyArrayObject *)input);
+  if (length != vec->length) {
+    PyErr_Format (PyExc_ValueError,
+        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
+        vec->length);
     return 1;
   }
 
-  Py_INCREF(array);
+  Py_XDECREF(vec->norm);
+  vec->norm = input;
+  Py_INCREF(vec->norm);
   return 0;
-
-fail:
-  return 1;
 }
 
 static int
 Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
 {
-  PyArrayObject * array;
-  if (input == NULL) {
-    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
-    goto fail;
+  npy_intp length;
+  if (!PyAubio_IsValidVector(input)) {
+    return 1;
   }
-  if (PyArray_Check(input)) {
-
-    // we got an array, convert it to a cvec.phas
-    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
-      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
-      goto fail;
-    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
-      PyErr_SetString (PyExc_ValueError,
-          "input array has more than two dimensions");
-      goto fail;
-    }
-
-    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float");
-      goto fail;
-    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
-      PyErr_SetString (PyExc_ValueError, "input array should be float32");
-      goto fail;
-    }
-    array = (PyArrayObject *)input;
-
-    // check input array dimensions
-    if (PyArray_NDIM (array) != 1) {
-      PyErr_Format (PyExc_ValueError,
-          "input array has %d dimensions, not 1",
-          PyArray_NDIM (array));
-      goto fail;
-    } else {
-      if (vec->o->length != PyArray_SIZE (array)) {
-          PyErr_Format (PyExc_ValueError,
-                  "input array has length %d, but cvec has length %d",
-                  (int)PyArray_SIZE (array), vec->o->length);
-          goto fail;
-      }
-    }
-
-    vec->o->phas = (smpl_t *) PyArray_GETPTR1 (array, 0);
-
-  } else {
-    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
+  length = PyArray_SIZE ((PyArrayObject *)input);
+  if (length != vec->length) {
+    PyErr_Format (PyExc_ValueError,
+        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
+        vec->length);
     return 1;
   }
 
-  Py_INCREF(array);
+  Py_XDECREF(vec->phas);
+  vec->phas = input;
+  Py_INCREF(vec->phas);
   return 0;
-
-fail:
-  return 1;
 }
 
 static PyMemberDef Py_cvec_members[] = {
@@ -260,8 +201,7 @@ static PyGetSetDef Py_cvec_getseters[] = {
 };
 
 PyTypeObject Py_cvecType = {
-  PyObject_HEAD_INIT (NULL)
-  0,                            /* ob_size           */
+  PyVarObject_HEAD_INIT(NULL, 0)
   "aubio.cvec",                 /* tp_name           */
   sizeof (Py_cvec),             /* tp_basicsize      */
   0,                            /* tp_itemsize       */
@@ -272,7 +212,7 @@ PyTypeObject Py_cvecType = {
   0,                            /* tp_compare        */
   (reprfunc) Py_cvec_repr,      /* tp_repr           */
   0,                            /* tp_as_number      */
-  0, //&Py_cvec_tp_as_sequence,      /* tp_as_sequence    */
+  0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
   0,                            /* tp_as_mapping     */
   0,                            /* tp_hash           */
   0,                            /* tp_call           */
@@ -299,4 +239,13 @@ PyTypeObject Py_cvecType = {
   (initproc) Py_cvec_init,      /* tp_init           */
   0,                            /* tp_alloc          */
   Py_cvec_new,                  /* tp_new            */
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
 };
index 3feb545..8763632 100644 (file)
@@ -1,10 +1,20 @@
-#include "aubiowraphell.h"
+#include "aubio-types.h"
 
 static char Py_fft_doc[] = "fft object";
 
-AUBIO_DECLARE(fft, uint_t win_s)
+typedef struct
+{
+  PyObject_HEAD
+  aubio_fft_t * o;
+  uint_t win_s;
+  // do / rdo input vectors
+  fvec_t vecin;
+  cvec_t cvecin;
+  // do / rdo output results
+  PyObject *doout;
+  PyObject *rdoout;
+} Py_fft;
 
-//AUBIO_NEW(fft)
 static PyObject *
 Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
 {
@@ -36,62 +46,97 @@ Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
   return (PyObject *) self;
 }
 
+static int
+Py_fft_init (Py_fft * self, PyObject * args, PyObject * kwds)
+{
+  self->o = new_aubio_fft (self->win_s);
+  if (self->o == NULL) {
+    // PyErr_Format(PyExc_RuntimeError, ...) was set above by new_ which called
+    // AUBIO_ERR when failing
+    return -1;
+  }
+
+  self->doout = new_py_cvec(self->win_s);
+  self->rdoout = new_py_fvec(self->win_s);
 
-AUBIO_INIT(fft, self->win_s)
+  return 0;
+}
 
-AUBIO_DEL(fft)
+static void
+Py_fft_del (Py_fft *self, PyObject *unused)
+{
+  Py_XDECREF(self->doout);
+  Py_XDECREF(self->rdoout);
+  if (self->o) {
+    del_aubio_fft(self->o);
+  }
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
 
-static PyObject * 
-Py_fft_do(PyObject * self, PyObject * args)
+static PyObject *
+Py_fft_do(Py_fft * self, PyObject * args)
 {
   PyObject *input;
-  fvec_t *vec;
-  cvec_t *output;
+  cvec_t c_out;
 
   if (!PyArg_ParseTuple (args, "O", &input)) {
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCFvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_ArrayToCFvec(input, &(self->vecin))) {
     return NULL;
   }
 
-  output = new_cvec(((Py_fft *) self)->win_s);
+  if (self->vecin.length != self->win_s) {
+    PyErr_Format(PyExc_ValueError,
+                 "input array has length %d, but fft expects length %d",
+                 self->vecin.length, self->win_s);
+    return NULL;
+  }
 
+  Py_INCREF(self->doout);
+  if (!PyAubio_PyCvecToCCvec(self->doout, &c_out)) {
+    return NULL;
+  }
   // compute the function
-  aubio_fft_do (((Py_fft *)self)->o, vec, output);
-  return (PyObject *)PyAubio_CCvecToPyCvec(output);
+  aubio_fft_do (self->o, &(self->vecin), &c_out);
+  return self->doout;
 }
 
-AUBIO_MEMBERS_START(fft) 
+static PyMemberDef Py_fft_members[] = {
   {"win_s", T_INT, offsetof (Py_fft, win_s), READONLY,
     "size of the window"},
-AUBIO_MEMBERS_STOP(fft)
+  {NULL}
+};
 
-static PyObject * 
+static PyObject *
 Py_fft_rdo(Py_fft * self, PyObject * args)
 {
   PyObject *input;
-  cvec_t *vec;
-  fvec_t *output;
+  fvec_t out;
 
   if (!PyArg_ParseTuple (args, "O", &input)) {
     return NULL;
   }
 
-  vec = PyAubio_ArrayToCCvec (input);
-
-  if (vec == NULL) {
+  if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) {
     return NULL;
   }
 
-  output = new_fvec(self->win_s);
+  if (self->cvecin.length != self->win_s / 2 + 1) {
+    PyErr_Format(PyExc_ValueError,
+                 "input cvec has length %d, but fft expects length %d",
+                 self->cvecin.length, self->win_s / 2 + 1);
+    return NULL;