summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Brossier <piem@debian.org>2016-11-06 01:38:30 +0100
committerPaul Brossier <piem@debian.org>2016-11-06 01:38:30 +0100
commit7d3310ca2c7e7a289e3e52b26aa1a94efc64cbba (patch)
tree8c10264b5eb3469cd301f2d2157c0a00340fec81
Import aubio_0.4.3.orig.tar.bz2
[dgit import orig aubio_0.4.3.orig.tar.bz2]
-rw-r--r--AUTHORS1
-rw-r--r--COPYING674
-rw-r--r--ChangeLog602
-rw-r--r--MANIFEST.in25
-rw-r--r--Makefile96
-rw-r--r--README.md178
-rw-r--r--VERSION7
-rw-r--r--aubio.pc.in10
-rw-r--r--doc/Makefile153
-rw-r--r--doc/aubiocut.txt83
-rw-r--r--doc/aubiomfcc.txt67
-rw-r--r--doc/aubionotes.txt102
-rw-r--r--doc/aubioonset.txt151
-rw-r--r--doc/aubiopitch.txt134
-rw-r--r--doc/aubioquiet.txt67
-rw-r--r--doc/aubiotrack.txt88
-rw-r--r--doc/conf.py242
-rw-r--r--doc/full.cfg2354
-rw-r--r--doc/index.rst113
-rw-r--r--doc/installing.rst65
-rw-r--r--doc/make.bat190
-rw-r--r--doc/python_module.rst33
-rw-r--r--doc/web.cfg2373
-rw-r--r--examples/aubiomfcc.c76
-rw-r--r--examples/aubionotes.c78
-rw-r--r--examples/aubioonset.c92
-rw-r--r--examples/aubiopitch.c88
-rw-r--r--examples/aubioquiet.c61
-rw-r--r--examples/aubiotrack.c97
-rw-r--r--examples/jackio.c380
-rw-r--r--examples/jackio.h64
-rw-r--r--examples/parse_args.h306
-rw-r--r--examples/utils.c221
-rw-r--r--examples/utils.h74
-rw-r--r--examples/wscript_build27
-rw-r--r--nose2.cfg6
-rw-r--r--python/README.md100
-rw-r--r--python/__init__.py0
-rw-r--r--python/demos/__init__.py0
-rwxr-xr-xpython/demos/demo_bpm_extract.py62
-rwxr-xr-xpython/demos/demo_create_test_sounds.py50
-rwxr-xr-xpython/demos/demo_filter.py36
-rwxr-xr-xpython/demos/demo_filterbank.py30
-rwxr-xr-xpython/demos/demo_filterbank_slaney.py21
-rwxr-xr-xpython/demos/demo_filterbank_triangle_bands.py47
-rwxr-xr-xpython/demos/demo_keyboard.py62
-rwxr-xr-xpython/demos/demo_mel-energy.py71
-rwxr-xr-xpython/demos/demo_mfcc.py65
-rwxr-xr-xpython/demos/demo_miditofreq.py17
-rwxr-xr-xpython/demos/demo_onset.py35
-rwxr-xr-xpython/demos/demo_onset_plot.py75
-rwxr-xr-xpython/demos/demo_pitch.py103
-rwxr-xr-xpython/demos/demo_pitch_sinusoid.py71
-rwxr-xr-xpython/demos/demo_pysoundcard_play.py24
-rwxr-xr-xpython/demos/demo_pysoundcard_record.py30
-rwxr-xr-xpython/demos/demo_reading_speed.py139
-rwxr-xr-xpython/demos/demo_simple_robot_voice.py29
-rwxr-xr-xpython/demos/demo_simple_spectral_weighting.py56
-rwxr-xr-xpython/demos/demo_sink.py31
-rwxr-xr-xpython/demos/demo_sink_create_woodblock.py57
-rwxr-xr-xpython/demos/demo_sink_multi.py32
-rwxr-xr-xpython/demos/demo_slicing.py51
-rwxr-xr-xpython/demos/demo_source.py28
-rwxr-xr-xpython/demos/demo_specdesc.py80
-rwxr-xr-xpython/demos/demo_spectrogram.py77
-rwxr-xr-xpython/demos/demo_tempo.py40
-rwxr-xr-xpython/demos/demo_tempo_plot.py79
-rwxr-xr-xpython/demos/demo_timestretch.py110
-rwxr-xr-xpython/demos/demo_timestretch_online.py110
-rwxr-xr-xpython/demos/demo_tss.py47
-rwxr-xr-xpython/demos/demo_waveform_plot.py56
-rw-r--r--python/ext/aubio-types.h82
-rw-r--r--python/ext/aubiomodule.c333
-rw-r--r--python/ext/aubioproxy.c158
-rw-r--r--python/ext/py-cvec.c251
-rw-r--r--python/ext/py-fft.c199
-rw-r--r--python/ext/py-filter.c215
-rw-r--r--python/ext/py-filterbank.c258
-rw-r--r--python/ext/py-musicutils.c135
-rw-r--r--python/ext/py-musicutils.h74
-rw-r--r--python/ext/py-phasevoc.c213
-rw-r--r--python/ext/py-sink.c262
-rw-r--r--python/ext/py-source.c339
-rw-r--r--python/ext/ufuncs.c114
-rw-r--r--python/lib/__init__.py0
-rw-r--r--python/lib/aubio/__init__.py18
-rw-r--r--python/lib/aubio/midiconv.py66
-rw-r--r--python/lib/aubio/slicing.py86
-rw-r--r--python/lib/gen_code.py555
-rw-r--r--python/lib/gen_external.py249
-rw-r--r--python/lib/moresetuptools.py141
-rwxr-xr-xpython/scripts/aubiocut206
-rw-r--r--python/tests/a_weighting_test_simple.expected2
-rw-r--r--python/tests/c_weighting_test_simple.expected2
-rw-r--r--python/tests/c_weighting_test_simple_8000.expected2
-rwxr-xr-xpython/tests/eval_pitch143
-rw-r--r--python/tests/filterbank_mfcc_16000_512.expected40
-rwxr-xr-xpython/tests/run_all_tests5
-rwxr-xr-xpython/tests/test_aubio.py14
-rwxr-xr-xpython/tests/test_cvec.py145
-rwxr-xr-xpython/tests/test_fft.py188
-rwxr-xr-xpython/tests/test_filter.py87
-rwxr-xr-xpython/tests/test_filterbank.py84
-rwxr-xr-xpython/tests/test_filterbank_mel.py49
-rwxr-xr-xpython/tests/test_fvec.py143
-rwxr-xr-xpython/tests/test_mathutils.py104
-rwxr-xr-xpython/tests/test_mfcc.py114
-rwxr-xr-xpython/tests/test_midi2note.py43
-rwxr-xr-xpython/tests/test_musicutils.py88
-rwxr-xr-xpython/tests/test_note2midi.py77
-rwxr-xr-xpython/tests/test_onset.py87
-rwxr-xr-xpython/tests/test_phasevoc.py187
-rwxr-xr-xpython/tests/test_pitch.py125
-rwxr-xr-xpython/tests/test_sink.py97
-rwxr-xr-xpython/tests/test_slicing.py149
-rwxr-xr-xpython/tests/test_source.py157
-rwxr-xr-xpython/tests/test_specdesc.py234
-rwxr-xr-xpython/tests/test_zero_crossing_rate.py46
-rw-r--r--python/tests/utils.py79
-rw-r--r--requirements.txt2
-rw-r--r--scripts/apple/Info.plist28
-rw-r--r--scripts/apple/Modules/module.modulemap6
-rwxr-xr-xscripts/build_apple_frameworks100
-rwxr-xr-xscripts/build_emscripten21
-rwxr-xr-xscripts/build_mingw28
-rwxr-xr-xscripts/get_waf.sh10
-rw-r--r--scripts/setenv_local.sh32
-rwxr-xr-xsetup.py111
-rw-r--r--src/aubio.h218
-rw-r--r--src/aubio_priv.h305
-rw-r--r--src/cvec.c141
-rw-r--r--src/cvec.h237
-rw-r--r--src/fmat.c186
-rw-r--r--src/fmat.h172
-rw-r--r--src/fvec.c140
-rw-r--r--src/fvec.h178
-rw-r--r--src/io/audio_unit.c777
-rw-r--r--src/io/audio_unit.h61
-rw-r--r--src/io/sink.c140
-rw-r--r--src/io/sink.h181
-rw-r--r--src/io/sink_apple_audio.c260
-rw-r--r--src/io/sink_apple_audio.h163
-rw-r--r--src/io/sink_sndfile.c231
-rw-r--r--src/io/sink_sndfile.h162
-rw-r--r--src/io/sink_wavwrite.c298
-rw-r--r--src/io/sink_wavwrite.h162
-rw-r--r--src/io/source.c156
-rw-r--r--src/io/source.h184
-rw-r--r--src/io/source_apple_audio.c378
-rw-r--r--src/io/source_apple_audio.h156
-rw-r--r--src/io/source_avcodec.c465
-rw-r--r--src/io/source_avcodec.h155
-rw-r--r--src/io/source_sndfile.c327
-rw-r--r--src/io/source_sndfile.h155
-rw-r--r--src/io/source_wavread.c411
-rw-r--r--src/io/source_wavread.h160
-rw-r--r--src/io/utils_apple_audio.c59
-rw-r--r--src/lvec.c80
-rw-r--r--src/lvec.h118
-rw-r--r--src/mathutils.c627
-rw-r--r--src/mathutils.h316
-rw-r--r--src/musicutils.h163
-rw-r--r--src/notes/notes.c195
-rw-r--r--src/notes/notes.h64
-rw-r--r--src/onset/onset.c235
-rw-r--r--src/onset/onset.h288
-rw-r--r--src/onset/peakpicker.c203
-rw-r--r--src/onset/peakpicker.h57
-rw-r--r--src/pitch/pitch.c464
-rw-r--r--src/pitch/pitch.h182
-rw-r--r--src/pitch/pitchfcomb.c139
-rw-r--r--src/pitch/pitchfcomb.h76
-rw-r--r--src/pitch/pitchmcomb.c428
-rw-r--r--src/pitch/pitchmcomb.h77
-rw-r--r--src/pitch/pitchschmitt.c119
-rw-r--r--src/pitch/pitchschmitt.h75
-rw-r--r--src/pitch/pitchspecacf.c110
-rw-r--r--src/pitch/pitchspecacf.h103
-rw-r--r--src/pitch/pitchyin.c182
-rw-r--r--src/pitch/pitchyin.h100
-rw-r--r--src/pitch/pitchyinfft.c197
-rw-r--r--src/pitch/pitchyinfft.h99
-rw-r--r--src/spectral/fft.c402
-rw-r--r--src/spectral/fft.h144
-rw-r--r--src/spectral/filterbank.c86
-rw-r--r--src/spectral/filterbank.h90
-rw-r--r--src/spectral/filterbank_mel.c207
-rw-r--r--src/spectral/filterbank_mel.h72
-rw-r--r--src/spectral/mfcc.c118
-rw-r--r--src/spectral/mfcc.h79
-rw-r--r--src/spectral/ooura_fft8g.c1669
-rw-r--r--src/spectral/phasevoc.c210
-rw-r--r--src/spectral/phasevoc.h102
-rw-r--r--src/spectral/specdesc.c399
-rw-r--r--src/spectral/specdesc.h194
-rw-r--r--src/spectral/statistics.c204
-rw-r--r--src/spectral/tss.c134
-rw-r--r--src/spectral/tss.h103
-rw-r--r--src/synth/sampler.c141
-rw-r--r--src/synth/sampler.h140
-rw-r--r--src/synth/wavetable.c194
-rw-r--r--src/synth/wavetable.h178
-rw-r--r--src/tempo/beattracking.c443
-rw-r--r--src/tempo/beattracking.h121
-rw-r--r--src/tempo/tempo.c291
-rw-r--r--src/tempo/tempo.h255
-rw-r--r--src/temporal/a_weighting.c262
-rw-r--r--src/temporal/a_weighting.h88
-rw-r--r--src/temporal/biquad.c54
-rw-r--r--src/temporal/biquad.h75
-rw-r--r--src/temporal/c_weighting.c217
-rw-r--r--src/temporal/c_weighting.h88
-rw-r--r--src/temporal/filter.c163
-rw-r--r--src/temporal/filter.h176
-rw-r--r--src/temporal/resampler.c98
-rw-r--r--src/temporal/resampler.h65
-rw-r--r--src/types.h70
-rw-r--r--src/utils/hist.c147
-rw-r--r--src/utils/hist.h63
-rw-r--r--src/utils/parameter.c142
-rw-r--r--src/utils/parameter.h159
-rw-r--r--src/utils/scale.c79
-rw-r--r--src/utils/scale.h80
-rw-r--r--src/utils/windll.c59
-rw-r--r--src/vecutils.c37
-rw-r--r--src/vecutils.h116
-rw-r--r--src/wscript_build41
-rw-r--r--tests/src/io/test-sink-multi.c73
-rw-r--r--tests/src/io/test-sink.c58
-rw-r--r--tests/src/io/test-sink_apple_audio-multi.c78
-rw-r--r--tests/src/io/test-sink_apple_audio.c67
-rw-r--r--tests/src/io/test-sink_sndfile-multi.c79
-rw-r--r--tests/src/io/test-sink_sndfile.c68
-rw-r--r--tests/src/io/test-sink_wavwrite-multi.c78
-rw-r--r--tests/src/io/test-sink_wavwrite.c67
-rw-r--r--tests/src/io/test-source.c59
-rw-r--r--tests/src/io/test-source_apple_audio.c63
-rw-r--r--tests/src/io/test-source_avcodec.c63
-rw-r--r--tests/src/io/test-source_multi.c57
-rw-r--r--tests/src/io/test-source_seek.c92
-rw-r--r--tests/src/io/test-source_sndfile.c63
-rw-r--r--tests/src/io/test-source_wavread.c64
-rw-r--r--tests/src/onset/test-onset.c62
-rw-r--r--tests/src/onset/test-peakpicker.c23
-rw-r--r--tests/src/pitch/test-pitch.c34
-rw-r--r--tests/src/pitch/test-pitchfcomb.c29
-rw-r--r--tests/src/pitch/test-pitchmcomb.c32
-rw-r--r--tests/src/pitch/test-pitchschmitt.c29
-rw-r--r--tests/src/pitch/test-pitchspecacf.c29
-rw-r--r--tests/src/pitch/test-pitchyin.c30
-rw-r--r--tests/src/pitch/test-pitchyinfft.c31
-rw-r--r--tests/src/spectral/test-fft.c48
-rw-r--r--tests/src/spectral/test-filterbank.c39
-rw-r--r--tests/src/spectral/test-filterbank_mel.c38
-rw-r--r--tests/src/spectral/test-mfcc.c30
-rw-r--r--tests/src/spectral/test-phasevoc.c47
-rw-r--r--tests/src/spectral/test-specdesc.c44
-rw-r--r--tests/src/spectral/test-tss.c52
-rw-r--r--tests/src/synth/test-sampler.c59
-rw-r--r--tests/src/synth/test-wavetable.c68
-rw-r--r--tests/src/tempo/test-beattracking.c40
-rw-r--r--tests/src/tempo/test-tempo.c63
-rw-r--r--tests/src/temporal/test-a_weighting.c43
-rw-r--r--tests/src/temporal/test-biquad.c32
-rw-r--r--tests/src/temporal/test-c_weighting.c42
-rw-r--r--tests/src/temporal/test-filter.c35
-rw-r--r--tests/src/temporal/test-resampler.c22
-rw-r--r--tests/src/test-cvec.c48
-rw-r--r--tests/src/test-delnull.c24
-rw-r--r--tests/src/test-fmat.c30
-rw-r--r--tests/src/test-fvec.c43
-rw-r--r--tests/src/test-lvec.c18
-rw-r--r--tests/src/test-mathutils-window.c31
-rw-r--r--tests/src/test-mathutils.c120
-rw-r--r--tests/src/utils/test-hist.c30
-rw-r--r--tests/src/utils/test-parameter.c70
-rw-r--r--tests/src/utils/test-scale.c22
-rw-r--r--tests/utils_tests.h53
-rw-r--r--tests/wscript_build19
-rwxr-xr-xwaf166
-rw-r--r--waflib/Build.py759
-rw-r--r--waflib/ConfigSet.py155
-rw-r--r--waflib/Configure.py379
-rw-r--r--waflib/Context.py394
-rw-r--r--waflib/Errors.py37
-rw-r--r--waflib/Logs.py199
-rw-r--r--waflib/Node.py491
-rw-r--r--waflib/Options.py147
-rw-r--r--waflib/Runner.py207
-rw-r--r--waflib/Scripting.py418
-rw-r--r--waflib/Task.py692
-rw-r--r--waflib/TaskGen.py434
-rw-r--r--waflib/Tools/__init__.py4
-rw-r--r--waflib/Tools/ar.py13
-rw-r--r--waflib/Tools/asm.py24
-rw-r--r--waflib/Tools/bison.py28
-rw-r--r--waflib/Tools/c.py26
-rw-r--r--waflib/Tools/c_aliases.py63
-rw-r--r--waflib/Tools/c_config.py765
-rw-r--r--waflib/Tools/c_osx.py137
-rw-r--r--waflib/Tools/c_preproc.py611
-rw-r--r--waflib/Tools/c_tests.py152
-rw-r--r--waflib/Tools/ccroot.py447
-rw-r--r--waflib/Tools/clang.py20
-rw-r--r--waflib/Tools/clangxx.py20
-rw-r--r--waflib/Tools/compiler_c.py40
-rw-r--r--waflib/Tools/compiler_cxx.py40
-rw-r--r--waflib/Tools/compiler_d.py37
-rw-r--r--waflib/Tools/compiler_fc.py39
-rw-r--r--waflib/Tools/cs.py132
-rw-r--r--waflib/Tools/cxx.py26
-rw-r--r--waflib/Tools/d.py54
-rw-r--r--waflib/Tools/d_config.py52
-rw-r--r--waflib/Tools/d_scan.py133
-rw-r--r--waflib/Tools/dbus.py29
-rw-r--r--waflib/Tools/dmd.py51
-rw-r--r--waflib/Tools/errcheck.py163
-rw-r--r--waflib/Tools/fc.py115
-rw-r--r--waflib/Tools/fc_config.py286
-rw-r--r--waflib/Tools/fc_scan.py64
-rw-r--r--waflib/Tools/flex.py32
-rw-r--r--waflib/Tools/g95.py54
-rw-r--r--waflib/Tools/gas.py12
-rw-r--r--waflib/Tools/gcc.py102
-rw-r--r--waflib/Tools/gdc.py35
-rw-r--r--waflib/Tools/gfortran.py68
-rw-r--r--waflib/Tools/glib2.py234
-rw-r--r--waflib/Tools/gnu_dirs.py66
-rw-r--r--waflib/Tools/gxx.py102
-rw-r--r--waflib/Tools/icc.py22
-rw-r--r--waflib/Tools/icpc.py22
-rw-r--r--waflib/Tools/ifort.py433
-rw-r--r--waflib/Tools/intltool.py97
-rw-r--r--waflib/Tools/irixcc.py45
-rw-r--r--waflib/Tools/javaw.py319
-rw-r--r--waflib/Tools/kde4.py48
-rw-r--r--waflib/Tools/ldc2.py36
-rw-r--r--waflib/Tools/lua.py18
-rw-r--r--waflib/Tools/msvc.py809
-rw-r--r--waflib/Tools/nasm.py16
-rw-r--r--waflib/Tools/perl.py90
-rw-r--r--waflib/Tools/python.py399
-rw-r--r--waflib/Tools/qt4.py442
-rw-r--r--waflib/Tools/qt5.py489
-rw-r--r--waflib/Tools/ruby.py101
-rw-r--r--waflib/Tools/suncc.py46
-rw-r--r--waflib/Tools/suncxx.py46
-rw-r--r--waflib/Tools/tex.py317
-rw-r--r--waflib/Tools/vala.py212
-rw-r--r--waflib/Tools/waf_unit_test.py106
-rw-r--r--waflib/Tools/winres.py85
-rw-r--r--waflib/Tools/xlc.py43
-rw-r--r--waflib/Tools/xlcxx.py43
-rw-r--r--waflib/Utils.py468
-rw-r--r--waflib/__init__.py4
-rw-r--r--waflib/ansiterm.py238
-rw-r--r--waflib/extras/__init__.py4
-rw-r--r--waflib/extras/compat15.py301
-rw-r--r--waflib/fixpy2.py53
-rw-r--r--wscript394
360 files changed, 54690 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..cf25233
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Paul Brossier <piem@aubio.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..bc6b4ca
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,602 @@
+2015-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 ]
+ * src/onset/onset.h: add aubio_onset_get_silence(), fix description of
+ aubio_onset_get/set_delay functions
+ * src/tempo/tempo.h: add aubio_tempo_get_silence and aubio_tempo_get_threshold
+
+ [ Library ]
+ * src/io/audio_unit.c: fix deprecation warning (closes #16)
+ * src/io/sink_apple_audio.c: avoid opening null path
+ * src/io/sink_sndfile.c: improve error messages, set nsamples after write
+ * src/io/sink_wavwrite.c: fail if samplerate is way too large, assume
+ windows is little endian to build with mingw32
+ * src/io/source_apple_audio.c: check out of bounds _seek, set s->path, quiet
+ * src/io/source_avcodec.c: update to libav10, libavcodec 55.34.1
+ * src/io/source_sndfile.c: cast to uint_t for now, clarify some variables
+ names, fix crash, zero-pad output vector when upsampling, improve seek errors and strings
+ * src/io/source_wavread.c: avoid orphan parenthesis , cast size_t to int to
+ avoid warning on win64 , improve seek errors processing , sync error message
+ * src/onset/onset.c: avoid doubled onset at start, check parameters
+ * src/pitch/pitch.c: add Hertz as valid unit string, check parameters
+ * src/pitch/pitchyin.c, src/pitch/pitchyinfft.c: avoid producing NaN on silence (closes #7)
+ * src/pitch/pitchyin.{c,h}: fix typo, developed
+ * src/spectral/phasevoc.c: fix argument checks, improve error messages
+ * src/synth/sampler.c: make sure blocksize > 0
+ * src/tempo/beattracking.c: avoid segfault on silence (closes #24)
+ * src/tempo/tempo.c: add silence detection (closes #23), add old behavior in
+ examples/aubiotrack.c, check parameters
+ * src/*.c: fix some useless float conversion
+
+ [ Python ]
+ * python/ext/aubiomodule.c: improve documentation
+ * python/ext/py-musicutils.c: add silence_detection (closes #21),
+ level_detection, db_spl, level_lin, complete window implementation
+ * python/ext/py-source.c: add channels, add seek (closes #9)
+ * python/demos/demo_a_weighting.py: add simple demo for a_weighting
+ * python/demos/demo_sink_multi.py: add multi channel version
+ * python/demos/, python/demos/: minor improvements, improve syntax (closes #19)
+ * python/setup.py: use setuptools, add numpy to install_requires
+
+ [ Build ]
+ * waf: removed, now automatically downloaded with make, updated to 1.8.12
+ * Makefile: add target to fetch waf and basic instructions
+ * .travis.yml: added template for travis continuous integration
+ * {examples,src,tests}/wscript_build: add external libs and uselib to targets
+ * src/wscript_build: do not hardocode install path
+ * wscript, src/io/*.c: use custom defines instead of __APPLE__
+ * wscript: make fat build optional, remove iOS sdk versioning
+
+ [ General ]
+ * examples/: use outmsg to print notes (fixes #8)
+ * examples/parse_args.h: improve short documentation (closes #12)
+ * doc/*.cfg: remove html timestamps to make build reproducible (see debian bug #779216)
+ * doc/aubiocut.txt: improve documentation
+ * doc/*.rst: add sphinx documentation basis with Makefile and conf.py
+ * README.md: minor updates
+ * python.old: removed old code
+ * tests/: minor bug fixing
+
+2014-01-31 Paul Brossier <piem@aubio.org>
+
+ [ Interface ]
+ * src/io/{source_wavread,sink_wavwrite}.h: new source and sink objects to
+ read and write simple wav files when building with no external dependencies
+ * src/io/{source,sink}*.h: added close functions to explicitly close file
+ * src/io/sink*.h: added do_multi, preset_channels, preset_samplerate,
+ get_channels and get_samplerate functions
+ * src/onset/onset.h: added aubio_onset_get_threshold
+ * src/mathutils.h: add fvec_quadratic_peak_mag to find the magnitude of
+ interpolated peaks
+
+ [ Library ]
+ * src/io/source_avcodec.c: implement _seek function
+ * src/io/source_sndfile.c: fixed _seek when signal is resampled
+ * src/spectral/ooura_fft8g.c: use float when double is not needed
+ * src/io/{source,sink}_apple_audio.c: improve error messages
+ * src/spectral/phasevoc.c: optimize swapbuffers by using memcpy
+ * src/lvec.c: add missing lvec_set_sample, improve test
+ * src/tempo/beattracking.c: improve confidence values by using interpolated
+ peak magnitude and avoiding nan
+ * src/tempo/tempo_davies.c: set default novelty function to specflux
+
+ [ Python module ]
+ * python/ext/py-{sink,source}.c: add do_multi and close functions
+ * python/ext/aubio-types.h: set NPY_NO_DEPRECATED_API to version 1.7
+ * python/lib/aubio/slicing.py: new function to slice a source into a list of
+ arbitrary regions
+ * python/scripts/aubiocut: add options --cut-until-nsamples and
+ --cut-until-nsclices, thanks to Mark Suppes for requesting, sponsoring,
+ and testing this feature
+
+ [ General code ]
+ * src/aubio_priv.h: use ifdefs to avoid checking undefined defines
+ * src/**.c: add missing prototypes, avoid some declarations after statement
+ * waf, waflib: update to 1.7.15
+
+2013-12-08 Paul Brossier <piem@aubio.org>
+
+ * Overdue: After more than five years of development behind the curtain,
+ time has come to release a new version of aubio.
+
+ * General: The library has been completely revised since 0.3.2. The API has
+ seen a major clean up, and has been thoroughly tested. The following list of
+ changes is not exhaustive.
+
+ * Memory management: allocation and freeing of memory has been optimized in
+ many ways. Several memory leaks and out of bound access have been fixed.
+
+ * Optimization: the FFT, central to most algorithms, can now be computed
+ using different optimized algorithms, depending on what is available on your
+ platform (FFTW, Ooura, or vDSP). Other simple optimization tricks are
+ included. Most can be deactivated by configuring the build accordingly.
+
+ * python/: The python interface has been completely rewritten to use numpy C
+ interface, making the aubio python module order of magnitudes faster than
+ the previous version. Several demos and tests are included.
+
+ * src/: source and header files are now organized in sub-directories.
+
+ * src/io/source.h: new source readers can now use any or all of libav,
+ CoreAudio, and libsndfile. This means that aubio can now easily read most
+ uncompressed and compressed formats. Compiled with libav, aubio can also
+ read audio from video files, and over the network.
+
+ * src/io/sink.h: a new sink object lets you write wav files with any number
+ of channels, at any samplerate, using libsndfile or CoreAudio.
+
+ * src/onset, src/tempo/, src/pitch: the different methods for onset, tempo,
+ and pitch extraction have seen many bug-fixes and optimizations.
+
+ * src/spectral/specdesc.h: new onset distances and statistical measures have
+ been added.
+
+ * src/spectral/filterbank.h: new filter bank to compute the energy in any
+ custom-defined frequency bands.
+
+ * src/spectral/mfcc.h, examples/aubiomfcc.c: a standard implementation of
+ the Mel-Frequency Cepstrum Coefficients algorithm has been added.
+
+ * src/temporal/{a,c}_weighting.h: standard implementation of the C-weighting
+ and A-weighting pre-processing filters are now provided for most commons
+ sampling rates.
+
+ * src/synth/wavetable.h, src/synth/sampler.h: provide basic ways to generate
+ some sounds.
+
+ * src/fvec.h: fvec_t, the vector object central to most aubio algorithms, is
+ now single channel. This simplifies the code of each algorithm greatly.
+
+ * src/lvec.h: lvec_t provides a double precision vector, required for some
+ operations to avoid floating point overflow
+
+ * src/fmat.h: fmat_t provides a single precision matrix, useful for
+ multi-channel operations and to some algorithms such as the spectral filter
+ bank.
+
+ * examples/: several new options, including new programs, have been
+ included. Refer to the documentation for details.
+
+ * tests/: several tests and examples programs have been added. This should
+ be a good place to look at to understand how to use aubio.
+
+ * doc/web.cfg: a simplified Doxygen configuration produces a simpler html
+ documentation.
+
+ * doc/*.txt: the manpages have been rewritten for txt2man.
+
+ * Build system: the build system has been switched from autotools/automake
+ to waf. Type './waf' or see README.md for instructions on how to use waf.
+
+2006-11-10 Paul Brossier <piem@altern.org>
+ * configure.ac: check c compiler for -Wextra option
+ * examples/*: add lash support to aubioonset, aubiotrack, and aubionotes
+ * */Makefile.am: improve compilation on Mac OS X, mingw and cygwin
+ * src/{onset,tempo}.[ch]: add simple c interfaces to onset and tempo tasks
+ * src/beattracking.c: allow the use of two beat trackers simultaneously
+ * examples/tests: add test programs for most c functions
+ * src/*.c: add most missing free calls
+ * src/*.c: fix some out of array writes
+ * src/,ext/: more gcc warning fixes
+
+2006-27-06 Paul Brossier <piem@altern.org>
+ * plugins/puredata/Makefile.am: move pd help to pattern-help.pd
+ - thanks goes to Frank Barknecht
+ * ext/sndfileio.c src/aubio_priv.h: fixes memset in aubio_priv.h, remove
+ useless sfinfo.format=0 - thanks karsten wiese
+ * ext/midi/midi_alsa_seq.c: do not call pthread_ in aubio_midi_direct_output
+ - thanks karsten wiese
+ * python/aubio/task/beat.py: task beat() output seconds
+ * python/aubio/task/beat.py: ugly hack to plot beat track anyway
+ * examples/aubionotes.c: fix signed/unsigned mismatches in examples
+ * src/beattracking.c: fix signed/unsigned mismatches in beattracking
+ * src/pitchfcomb.c: fix signed/unsigned mismatches in pitchfcomb
+ * src/pitchschmitt.c: fix signed/unsigned mismatches in pitchscmitt
+ * configure.ac: use -Wextra but unused parameters, fix macos CFLAGS
+ * plugins/puredata/Makefile.am: simplify puredata Makefile.am
+ * python/aubio/Makefile.am: avoid overwriting CFLAGS
+ * examples/Makefile.am: use top_{build,src}dir instead of ../
+ * configure.ac: make configure.ac more readable
+ * python/aubio/task/cut.py: use os.path to derive default output filenames
+ * VERSION: 0.3.1
+
+2006-18-05 Paul Brossier <piem@altern.org>
+ * src/pitchyinfft.{c,h}: new pitch detection method
+ * src/beattracking.c: algorithm improved
+ * plugins/puredata/: new puredata external
+ * python/tasks: enhancements to the onset detection algorithms
+ * python/aubiocut: improved, can now slice at beats and silences
+ * python/aubiopitch: new python program to extract pitch tracks
+ * python/: plotting features for aubiocut and aubiopitch
+ * python/: interface refactored
+ * doc/: updated documentation
+ * VERSION: 0.3.0
+
+2006-18-05 Paul Brossier <piem@altern.org>
+ * src/beattracking.c: added beattracking.c
+ * various bug fixes
+ * VERSION: 0.2.0
+
+2005-29-03 Paul Brossier <piem@altern.org>
+ * python/aubio/gnuplot.py: clean up and add plotsound
+ * python/aubiocompare-onset: updated
+ * examples/aubioonset.c: fix text output when nframes<4
+ * ext/midi/midi_file.c: by default, int is unsigned on powerpc
+ * python/aubiocut, python/aubio/aubioclass.py: updated
+ * ext/midi/midi_alsa_seq.c: activated threading
+ * configure.ac,Makefile.am: added rules to check presence
+ of swig, python, puredata and docbook-to-man.
+
+2005-17-03 Paul Brossier <piem@altern.org>
+ * examples/utils.{c,h}: corrected usedoubled and -O interactions
+ * examples/aubioonset.c: added frames>=4 check (thanks Hamish Allan)
+
+2004-12-11 Paul Brossier <piem@altern,org>
+ * swig/Makefile.am: instructions moved to python/aubio and cleaned
+ * python/aubiocut: corrected slicing on multichannel files
+ * VERSION: bumped to 0.1.8
+
+2004-12-06 Paul Brossier <piem@altern.org>
+ * examples/{midi*,testforclam}.c: removed
+ * src/{sndfile,midi*,jackio}.[ch]: moved to ext
+
+2004-12-03 Paul Brossier <piem@altern.org>
+ * src/{mathutils,pitchyin}.h: got rid of some shadowed declarations
+ * plugins/puredata: first puredata plugin attempt added
+
+2004-11-30 Paul Brossier <piem@altern.org>
+ * configure.ac: added -lmx on macosx
+ * python/aubiocut: seeks for local minima before peak
+ added zero crossing search
+ * src/pitchyinc.c: adds draft for all-in-one faster function
+ * examples/*.c: added ladcca client (needs work)
+ * examples/aubioonset.c: cleaned up verbose stdout
+ * doc/aubio.css: updated
+
+2004-10-28 Paul Brossier <piem@altern.org>
+ * src/Makefile.am: added config.h installation
+ * VERSION: 0.1.7.1
+
+2004-10-26 Paul Brossier <piem@altern.org>:
+ * src/pitchdetection.*: moved to src/pitchmcomb.*, now includes a
+ draft driver for transparent use of mcomb or yin
+ * src/pitchmcomb.*: added from old src/pitchdetection.*
+ * VERSION: 0.1.7
+
+2004-10-20 Paul Brossier <piem@altern.org>:
+ * configure.ac: made fftw3f, alsa and jack optional
+ * src/fft.{c,h}: now uses FFTW3F_SUPPORT
+ * src/timer.c: #if 0 on win32 version
+
+2004-10-18 Paul Brossier <piem@altern.org>:
+ * src/{fft,cvec,pvoc}.c: fixed fft size (N/2+1)
+ * src/{onsetdetection,tss}.c: fixed sizes as well
+ * src/pvoc.c: fixed resynthesis scaling factor (still missing
+ windowing), windowing added in pvoc_rdo
+ * src/fft.h: removed FFTW typedef
+ * configure.ac: removed AC_ISC_POSIX to compile on mingw32
+ * src/fft.c: removed useless fftw3.h include
+ * src/pitchmcomb.c: removed call to vec_adapt_thres (writes out of
+ bounds)
+
+2004-10-17 Paul Brossier <piem@altern.org>
+ * src/sample.c: removed static _malloc, set all 0. (fixes nan bugs)
+ * examples/*.c: removed useless pvoc inits
+ * src/pitchyin.c: based on de Cheveigne paper
+
+2004-09-17 Paul Brossier <piem@altern.org>
+ * configure.ac,src/Makefile.am: cleaned up autotools process
+ * examples/aubio*.c: removed some useless code.
+ * src/sample.c: removed crazy call to memset
+
+2004-09-02 Paul Brossier <piem@altern.org>
+ * src/sndfileio.c: removed abusive call to AUBIO_ARRAY,
+ defined MAX_SIZE instead.
+ * src/onsetdetection.c: rewritten free_function.
+ * src/phasevoc.c: in aubio_pvoc_rdo, one way writing only
+ * swig/, python/aubio: added swig wrapper, played a bit with
+ python interface.
+ * src/aubio.h: now includes midi_driver.h
+
+2004-06-25 Paul Brossier <piem@altern.org>
+ * src/peakpick.h:
+ renamed pickparams_t to aubio_pickpeak_t
+ disabled samer_pp (broken)
+ added del_aubio_peakpick
+ added aubio_peakpick_pimrt_wt (thanks mramirez)
+ * python/aubio/onsetcompare.py: now works on huge list
+ thanks goes to Nicolas Wack
+ * examples/aubionotes.c: now outputs NOTEONs
+ * configure.ac: quick hack to disable jack and alsa
+ * examples/*usingjack*: more hacking to disable jack
+ * README: some updates
+
+2004-06-23 Paul Brossier <piem@altern.org>
+ * src/*.h: added C++ ifdefs in header files
+ * src/fft.h: removed complex.h include in header
+ * src/hist.c: fixed out of array indexes
+ thanks Miguel Ramirez!
+ * src/Makefile.am: added install headers
+ * doc/Makefile.am: removed dist-hook to update-docs
+ * sounds/Makefile.am: added install hooks
+ * aubio.pc.in: added aubio.pc generation for pkg-config
+ * python: added some evaluation functions
+ * src/aubio_priv.h: moved AUBIO_DBG to stderr
+ * examples/utils.h: now outputs on stdout
+ * examples/midi*.c: fixed compilation with gcc-2.95
+ * VERSION: 0.1.4
+
+2004-04-27 Paul Brossier <piem@altern.org>
+ * pitchdetection.c: fixed, still not great
+ * Makefile.am: fixed missing headers (thank you Charbel)
+ * aubioonset,aubionotes: renamed for install (were *demo files)
+ * First working release: 0.1.3
+
+2004-01-31 Paul Brossier <piem@altern.org>
+ * pitchdetection.c: working, still a bit too picky
+ * filter.c: sizeable biquad, fixed via pitchtest.c
+ * types.h: added file, all generic system wide types.
+ * tss.c: added some speed improvements
+
+2004-01-20 Paul Brossier <piem@altern.org>
+ * peakpick.c: working real time onset detection
+ * biquad.c: needs fixing
+
+2004-01-10 Paul Brossier <piem@altern.org>
+ * long time i didn't touch this file
+ * added various objects
+ * working onsetdetectors
+ * various examples
+ * splitted in a dynamic library
+ * functions renamed (new_. del_. aubio_._do)
+ * VERSION: 0.1.0_alpha
+
+2003-11-04 Paul Brossier <piem@altern.org>
+ * aubio.h: degrouping in modules
+ * VERSION: 0.0.6_alpha
+
+2003-11-03 Paul Brossier <piem@altern.org>
+ * phasevoc.c: fixed memory acces
+ * jackio.c: moving to ringbuffer type implementation
+ * VERSION: 0.0.4_alpha
+
+2003-11-03 Paul Brossier <piem@altern.org>
+ * jackio.c: added jack support
+ * aubioenc.c: fixed memory freeing bugs
+ * VERSION: 0.0.3_alpha
+
+2003-10-29 Paul Brossier <piem@altern.org>
+ * aubio.h: Grouping all headers
+ * makefile.am: Running first make dist
+ * VERSION: 0.0.2alpha
+
+2003-10-18 Paul Brossier <piem@altern.org>
+ * aubioenc.c: Working phase vocoder
+ * VERSION: 0.0.1alpha
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..15fd25a
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,25 @@
+include AUTHORS COPYING README.md VERSION ChangeLog
+include python/README.md
+include Makefile wscript */wscript_build
+include waf
+include aubio.pc.in
+include nose2.cfg
+include requirements.txt
+include src/*.h
+include src/*/*.h
+include examples/*.c examples/*.h
+include tests/*.h tests/*/*.c tests/*/*/*.c
+include python/ext/*.h
+include python/__init__.py
+include python/lib/__init__.py
+include python/lib/moresetuptools.py
+include python/lib/gen_external.py
+include python/lib/gen_code.py
+include python/tests/run_all_tests
+include python/tests/*.py
+include python/demos/*.py
+include python/tests/*.expected
+include doc/*.txt doc/*.rst doc/*.cfg doc/Makefile doc/make.bat doc/conf.py
+include scripts/* scripts/apple/Info.plist scripts/apple/Modules/module.modulemap
+exclude python/gen/*
+exclude python/ext/config.h
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a050ef7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,96 @@
+WAFCMD=python waf
+WAFURL=https://waf.io/waf-1.8.22
+
+SOX=sox
+
+ENABLE_DOUBLE := $(shell [ -z $(HAVE_DOUBLE) ] || echo --enable-double )
+TESTSOUNDS := python/tests/sounds
+
+all: build
+
+checkwaf:
+ @[ -f waf ] || make getwaf
+
+getwaf:
+ @./scripts/get_waf.sh
+
+expandwaf:
+ @[ -d wafilb ] || rm -fr waflib
+ @$(WAFCMD) --help > /dev/null
+ @mv .waf*/waflib . && rm -fr .waf*
+ @sed '/^#==>$$/,$$d' waf > waf2 && mv waf2 waf
+ @chmod +x waf
+
+configure: checkwaf
+ $(WAFCMD) configure $(WAFOPTS) $(ENABLE_DOUBLE)
+
+build: configure
+ $(WAFCMD) build $(WAFOPTS)
+
+build_python:
+ python ./setup.py generate $(ENABLE_DOUBLE) build
+
+test_python: export LD_LIBRARY_PATH=$(PWD)/build/src
+test_python:
+ pip install -v -r requirements.txt
+ pip install -v .
+ nose2 --verbose
+ pip uninstall -y -v aubio
+
+test_python_osx:
+ # create links from ~/lib/lib* to build/src/lib*
+ [ -f build/src/libaubio.[0-9].dylib ] && ( mkdir -p ~/lib && cp -prv build/src/libaubio.4.dylib ~/lib ) || true
+ # then run the tests
+ pip install --user -v -r requirements.txt
+ pip install --user -v .
+ nose2 --verbose
+ pip uninstall -y -v aubio
+
+clean_python:
+ ./setup.py clean
+
+test_pure_python:
+ -pip uninstall -v -y aubio
+ -rm -rf build/ python/gen/
+ -rm -f dist/*.egg
+ -pip install -v -r requirements.txt
+ CFLAGS=-Os python setup.py bdist_egg
+ [ "$(TRAVIS_OS_NAME)" == "osx" ] && easy_install --user dist/*.egg || \
+ easy_install dist/*.egg
+ nose2 -N 4
+ pip uninstall -v -y aubio
+
+test_pure_python_wheel:
+ -pip uninstall -v -y aubio
+ -rm -rf build/ python/gen/
+ -rm -f dist/*.whl
+ -pip install -v -r requirements.txt
+ -pip install -v wheel
+ CFLAGS=-Os python setup.py bdist_wheel --universal
+ wheel install dist/*.whl
+ nose2 -N 4
+ pip uninstall -v -y aubio
+
+build_python3:
+ python3 ./setup.py generate $(ENABLE_DOUBLE) build
+
+clean_python3:
+ python3 ./setup.py clean
+
+clean:
+ $(WAFCMD) clean
+
+distcheck: checkwaf
+ $(WAFCMD) distcheck $(WAFOPTS) $(ENABLE_DOUBLE)
+
+help:
+ $(WAFCMD) --help
+
+create_test_sounds:
+ -[ -z `which $(SOX)` ] && ( echo $(SOX) could not be found) || true
+ -mkdir -p $(TESTSOUNDS)
+ -$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_1f_silence.wav" synth 1s silence 0
+ -$(SOX) -r 22050 -b 16 -n "$(TESTSOUNDS)/22050Hz_5s_brownnoise.wav" synth 5 brownnoise vol 0.9
+ -$(SOX) -r 32000 -b 16 -n "$(TESTSOUNDS)/32000Hz_127f_sine440.wav" synth 127s sine 440 vol 0.9
+ -$(SOX) -r 8000 -b 16 -n "$(TESTSOUNDS)/8000Hz_30s_silence.wav" synth 30 silence 0 vol 0.9
+ -$(SOX) -r 48000 -b 32 -n "$(TESTSOUNDS)/48000Hz_60s_sweep.wav" synth 60 sine 100-20000 vol 0.9
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9068085
--- /dev/null
+++ b/README.md
@@ -0,0 +1,178 @@
+aubio library
+=============
+
+aubio is a library to label music and sounds. It listens to audio signals and
+attempts to detect events. For instance, when a drum is hit, at which frequency
+is a note, or at what tempo is a rhythmic melody.
+
+Its 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:
+
+ - several onset detection methods
+ - different pitch detection methods
+ - tempo tracking and beat detection
+ - MFCC (mel-frequency cepstrum coefficients)
+ - FFT and phase vocoder
+ - up/down-sampling
+ - digital filters (low pass, high pass, and more)
+ - spectral filtering
+ - transient/steady-state separation
+ - sound file and audio devices 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.md`](python/README.md) 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
+
+Implementation and Design Basics
+--------------------------------
+
+The library is written in C and is optimised for speed and portability.
+
+The C API is designed in the following way:
+
+ aubio_something_t * new_aubio_something (void * args);
+ audio_something_do (aubio_something_t * t, void * args);
+ smpl_t aubio_something_get_a_parameter (aubio_something_t *t);
+ uint_t aubio_something_set_a_parameter (aubio_something_t *t, smpl_t a_parameter);
+ void del_aubio_something (aubio_something_t * t);
+
+For performance and real-time operation, no memory allocation or freeing take
+place in the `_do` methods. Instead, memory allocation should always take place
+in the `new_` methods, whereas free operations are done in the `del_` methods.
+
+The latest version of the documentation can be found at:
+
+ https://aubio.org/documentation
+
+Build Instructions
+------------------
+
+A number of distributions already include aubio. Check your favorite package
+management system, or have a look at the [download
+page](https://aubio.org/download).
+
+aubio uses [waf](https://waf.io/) to configure, compile, and test the source:
+
+ ./waf configure
+ ./waf build
+
+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.
+
+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
+------------------------
+
+This library gathers music signal processing algorithms designed at the Centre
+for Digital Music and elsewhere. This software project was developed along the
+research I did at the Centre for Digital Music, Queen Mary, University of
+London. Most of this C code was written by myself, starting from published
+papers and existing code. The header files of each algorithm contains brief
+descriptions and references to the corresponding papers.
+
+Special thanks go Juan Pablo Bello, Chris Duxbury, Samer Abdallah, Alain de
+Cheveigne for their help and publications. Also many thanks to Miguel Ramirez
+and Nicolas Wack for their bug fixing.
+
+Substantial informations about the algorithms and their evaluation are gathered
+in:
+
+ - Paul Brossier, _[Automatic annotation of musical audio for interactive
+ systems](https://aubio.org/phd)_, PhD thesis, Centre for Digital music,
+Queen Mary University of London, London, UK, 2006.
+
+Additional results obtained with this software were discussed in the following
+papers:
+
+ - P. M. Brossier and J. P. Bello and M. D. Plumbley, [Real-time temporal
+ segmentation of note objects in music signals](https://aubio.org/articles/brossier04fastnotes.pdf),
+in _Proceedings of the International Computer Music Conference_, 2004, Miami,
+Florida, ICMA
+
+ - P. M. Brossier and J. P. Bello and M. D. Plumbley, [Fast labelling of note
+ objects in music signals] (https://aubio.org/articles/brossier04fastnotes.pdf),
+in _Proceedings of the International Symposium on Music Information Retrieval_,
+2004, Barcelona, Spain
+
+
+Contact Info and Mailing List
+-----------------------------
+
+The home page of this project can be found at: https://aubio.org/
+
+Questions, comments, suggestions, and contributions are welcome. Use the
+mailing list: <aubio-user@aubio.org>.
+
+To subscribe to the list, use the mailman form:
+http://lists.aubio.org/listinfo/aubio-user/
+
+Alternatively, feel free to contact directly the author.
+
+
+Copyright and License Information
+---------------------------------
+
+Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+aubio is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..cc1aba6
--- /dev/null
+++ b/VERSION
@@ -0,0 +1,7 @@
+AUBIO_MAJOR_VERSION=0
+AUBIO_MINOR_VERSION=4
+AUBIO_PATCH_VERSION=3
+AUBIO_VERSION_STATUS=''
+LIBAUBIO_LT_CUR=5
+LIBAUBIO_LT_REV=0
+LIBAUBIO_LT_AGE=4
diff --git a/aubio.pc.in b/aubio.pc.in
new file mode 100644
index 0000000..301a1b5
--- /dev/null
+++ b/aubio.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: aubio
+Description: a library for audio labelling
+Version: @VERSION@
+Libs: -L${libdir} -laubio
+Cflags: -I${includedir}
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..8b0b81d
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/aubio.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/aubio.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/aubio"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/aubio"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/aubiocut.txt b/doc/aubiocut.txt
new file mode 100644
index 0000000..be19dad
--- /dev/null
+++ b/doc/aubiocut.txt
@@ -0,0 +1,83 @@
+NAME
+ aubiocut - a command line tool to slice sound files at onset or beat timestamps
+
+SYNOPSIS
+
+ aubiocut source
+ aubiocut [[-i] source]
+ [-r rate] [-B win] [-H hop]
+ [-O method] [-t thres]
+ [-b] [-c]
+ [-v] [-q] [-h]
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If set
+ to 0, the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -O, --onset method The onset detection method to use. See ONSET METHODS
+ below. Defaults to 'default'.
+
+ -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.
+
+ -c, --cut Cut input sound file at detected labels. A new sound files for
+ each slice will be created in the current directory.
+
+ -o, --output directory Specify the directory path where slices of the
+ original source should be created.
+
+ --cut-until-nsamples n How many extra samples should be added at the end of
+ each slice (default 0).
+
+ --cut-until-nslices n How many extra slices should be added at the end of
+ each slice (default 0).
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+ -q, --quiet Be quiet.
+
+
+ONSET METHODS
+
+ Available methods: default, energy, hfc, complex, phase, specdiff, kl, mkl,
+ specflux.
+
+ See aubioonset(1) for details about these methods.
+
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiopitch(1),
+ aubiotrack(1),
+ aubionotes(1),
+ aubioquiet(1),
+ and
+ aubiomfcc(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/aubiomfcc.txt b/doc/aubiomfcc.txt
new file mode 100644
index 0000000..afeafe3
--- /dev/null
+++ b/doc/aubiomfcc.txt
@@ -0,0 +1,67 @@
+NAME
+ aubiomfcc - a command line tool to compute Mel-Frequency Cepstrum Coefficients
+
+SYNOPSIS
+
+ aubiomfcc source
+ aubiomfcc [[-i] source]
+ [-r rate] [-B win] [-H hop]
+ [-v] [-h]
+
+DESCRIPTION
+
+ aubiomfcc compute the Mel-Frequency Cepstrum Coefficients (MFCC).
+
+ MFCCs are coefficients that make up for the mel-frequency spectrum, a
+ representation of the short-term power spectrum of a sound. By default, 13
+ coefficents are computed using 40 filters.
+
+ When started with an input source (-i/--input), the coefficients are given on
+ the console, prefixed by their timestamps in seconds.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+REFERENCES
+
+ Using the default parameters, the filter coefficients will be computed
+ according to Malcolm Slaney's Auditory Toolbox, available at the following
+ url:
+
+ http://cobweb.ecn.purdue.edu/~malcolm/interval/1998-010/ (see file mfcc.m)
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiopitch(1),
+ aubiotrack(1),
+ aubionotes(1),
+ aubioquiet(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/aubionotes.txt b/doc/aubionotes.txt
new file mode 100644
index 0000000..190fc72
--- /dev/null
+++ b/doc/aubionotes.txt
@@ -0,0 +1,102 @@
+NAME
+ aubionotes - a command line tool to extract musical notes
+
+SYNOPSIS
+
+ aubionotes source
+ aubionotes [[-i] source]
+ [-r rate] [-B win] [-H hop]
+ [-O method] [-t thres]
+ [-p method] [-u unit] [-l thres]
+ [-s sil]
+ [-j] [-v] [-h]
+
+DESCRIPTION
+
+ aubionotes attempts to detect notes by looking for note onsets and pitches.
+ Consecutive events are segmented using onset detection, while a fundamental
+ frequency extraction algorithm determines their pitch.
+
+ When started with an input source (-i/--input), the detected notes are
+ printed on standard output, in seconds and midi note number.
+
+ When started without an input source, or with the jack option (-j/--jack),
+ aubionotes starts in jack mode.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -O, --onset method The onset detection method to use. See ONSET METHODS
+ 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.
+
+ -p, --pitch method The pitch detection method to use. See PITCH METHODS
+ below. Defaults to 'default'.
+
+ -u, --pitch-unit unit The unit to be used to print frequencies. Possible
+ values include midi, bin, cent, and Hz. Defaults to 'Hz'.
+
+ -l, --pitch-tolerance thres Set the tolerance for the pitch detection
+ algorithm. Typical values range between 0.2 and 0.9. Pitch candidates found
+ with a confidence less than this threshold will not be selected. The higher
+ the threshold, the more confidence in the candidates. Defaults to unset.
+
+ -s, --silence sil Set the silence threshold, in dB, under which the pitch
+ 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.
+
+ -j, --jack Use Jack input/output. You will need a Jack connection
+ controller to feed aubio some signal and listen to its output.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+ONSET METHODS
+
+ Available methods: default, energy, hfc, complex, phase, specdiff, kl, mkl,
+ specflux.
+
+ See aubioonset(1) for details about these methods.
+
+PITCH METHODS
+
+ Available methods: default, schmitt, fcomb, mcomb, specacf, yin, yinfft.
+
+ See aubiopitch(1) for details about these methods.
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiopitch(1),
+ aubiotrack(1),
+ aubioquiet(1),
+ aubiomfcc(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/aubioonset.txt b/doc/aubioonset.txt
new file mode 100644
index 0000000..f9d3783
--- /dev/null
+++ b/doc/aubioonset.txt
@@ -0,0 +1,151 @@
+NAME
+ aubioonset - a command line tool to extract musical onset times
+
+SYNOPSIS
+
+ aubioonset source
+ aubioonset [[-i] source] [-o sink]
+ [-r rate] [-B win] [-H hop]
+ [-O method] [-t thres]
+ [-s sil] [-m] [-f]
+ [-j] [-v] [-h]
+
+DESCRIPTION
+
+ aubioonset attempts to detect onset times, the beginning of discrete sound
+ events, in audio signals.
+
+ When started with an input source (-i/--input), the detected onset times are
+ given on the console, in seconds.
+
+ When started without an input source, or with the jack option (-j/--jack),
+ aubioonset starts in jack mode.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -o, --output sink Save results in this file. The file will be created on
+ the model of the input file. Onset times are marked by a short wood-block
+ like sound.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -O, --onset method The onset detection method to use. See ONSET METHODS
+ 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.
+
+ -s, --silence sil Set the silence threshold, in dB, under which the pitch
+ 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.
+
+ -m, --mix-input Mix source signal to the output signal before writing to
+ sink.
+
+ -f, --force-overwrite Overwrite output file if it already exists.
+
+ -j, --jack Use Jack input/output. You will need a Jack connection
+ controller to feed aubio some signal and listen to its output.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+ONSET METHODS
+
+ Available methods are:
+
+ default Default distance, currently hfc
+
+ Default: 'default' (currently set to hfc)
+
+ energy Energy based distance
+
+ This function calculates the local energy of the input spectral frame.
+
+ hfc High-Frequency content
+
+ This method computes the High Frequency Content (HFC) of the input
+ spectral frame. The resulting function is efficient at detecting
+ percussive onsets.
+
+ Paul Masri. Computer modeling of Sound for Transformation and Synthesis of
+ Musical Signal. PhD dissertation, University of Bristol, UK, 1996.
+
+ complex Complex domain onset detection function
+
+ This function uses information both in frequency and in phase to determine
+ changes in the spectral content that might correspond to musical onsets.
+ It is best suited for complex signals such as polyphonic recordings.
+
+ Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain
+ onset detection for musical signals. In Proceedings of the Digital Audio
+ Effects Conference, DAFx-03, pages 90-93, London, UK, 2003.
+
+ phase Phase based onset detection function
+
+ This function uses information both in frequency and in phase to determine
+ changes in the spectral content that might correspond to musical onsets. It
+ is best suited for complex signals such as polyphonic recordings.
+
+ Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note
+ onset detection for music signals. In Proceedings of the IEEE International
+ Conference on Acoustics Speech and Signal Processing, pages 441­444,
+ Hong-Kong, 2003.
+
+ specdiff Spectral difference onset detection function
+
+ Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
+ rhythm analysis. In IEEE International Conference on Multimedia and Expo
+ (ICME 2001), pages 881­884, Tokyo, Japan, August 2001.
+
+ kl Kulback-Liebler onset detection function
+
+ Stephen Hainsworth and Malcom Macleod. Onset detection in music audio
+ signals. In Proceedings of the International Computer Music Conference
+ (ICMC), Singapore, 2003.
+
+ mkl Modified Kulback-Liebler onset detection function
+
+ Paul Brossier, ``Automatic annotation of musical audio for interactive
+ systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for
+ Digital music, Queen Mary University of London, London, UK, 2006.
+
+ specflux Spectral flux
+
+ Simon Dixon, Onset Detection Revisited, in ``Proceedings of the 9th
+ International Conference on Digital Audio Effects'' (DAFx-06), Montreal,
+ Canada, 2006.
+
+SEE ALSO
+
+ aubiopitch(1),
+ aubiotrack(1),
+ aubionotes(1),
+ aubioquiet(1),
+ aubiomfcc(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/aubiopitch.txt b/doc/aubiopitch.txt
new file mode 100644
index 0000000..1fc8205
--- /dev/null
+++ b/doc/aubiopitch.txt
@@ -0,0 +1,134 @@
+NAME
+ aubiopitch - a command line tool to extract musical pitch
+
+SYNOPSIS
+
+ aubiopitch source
+ aubiopitch [[-i] source] [-o sink]
+ [-r rate] [-B win] [-H hop]
+ [-p method] [-u unit] [-l thres]
+ [-s sil] [-f]
+ [-v] [-h] [-j]
+
+DESCRIPTION
+
+ aubiopitch attempts to detect the pitch, the perceived height of a musical
+ note.
+
+ When started with an input source (-i/--input), the detected pitch are
+ printed on the console, prefixed by a timestamp in seconds. If no pitch
+ candidate is found, the output is 0.
+
+ When started without an input source, or with the jack option (-j/--jack),
+ aubiopitch starts in jack mode.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -o, --output sink Save results in this file. The file will be created on
+ the model of the input file. The detected frequency is played at the
+ detected loudness.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 2048.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -p, --pitch method The pitch detection method to use. See PITCH METHODS
+ below. Defaults to 'default'.
+
+ -u, --pitch-unit unit The unit to be used to print frequencies. Possible
+ values include midi, bin, cent, and Hz. Defaults to 'Hz'.
+
+ -l, --pitch-tolerance thres Set the tolerance for the pitch detection
+ algorithm. Typical values range between 0.2 and 0.9. Pitch candidates found
+ with a confidence less than this threshold will not be selected. The higher
+ the threshold, the more confidence in the candidates. Defaults to unset.
+
+ -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.
+
+ -m, --mix-input Mix source signal to the output signal before writing to
+ sink.
+
+ -f, --force-overwrite Overwrite output file if it already exists.
+
+ -j, --jack Use Jack input/output. You will need a Jack connection
+ controller to feed aubio some signal and listen to its output.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+PITCH METHODS
+
+ Available methods are:
+
+ default use the default method
+
+ Currently, the default method is set to yinfft.
+
+ schmitt Schmitt trigger
+
+ This pitch extraction method implements a Schmitt trigger to estimate the
+ period of a signal. It is computationally very inexpensive, but also very
+ sensitive to noise.
+
+ fcomb a fast harmonic comb filter
+
+ This pitch extraction method implements a fast harmonic comb filter to
+ determine the fundamental frequency of a harmonic sound.
+
+ mcomb multiple-comb filter
+
+ This fundamental frequency estimation algorithm implements spectral
+ flattening, multi-comb filtering and peak histogramming.
+
+ specacf Spectral auto-correlation function
+
+ yin YIN algorithm
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ was first published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ yinfft Yinfft algorithm
+
+ This algorithm was derived from the YIN algorithm. In this implementation, a
+ Fourier transform is used to compute a tapered square difference function,
+ which allows spectral weighting. Because the difference function is tapered,
+ the selection of the period is simplified.
+
+ Paul Brossier, Automatic annotation of musical audio for interactive systems,
+ Chapter 3, Pitch Analysis, PhD thesis, Centre for Digital music, Queen Mary
+ University of London, London, UK, 2006.
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiotrack(1),
+ aubionotes(1),
+ aubioquiet(1),
+ aubiomfcc(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/aubioquiet.txt b/doc/aubioquiet.txt
new file mode 100644
index 0000000..eb11ae0
--- /dev/null
+++ b/doc/aubioquiet.txt
@@ -0,0 +1,67 @@
+NAME
+ aubioquiet - a command line tool to extracts quiet and loud regions from a file
+
+SYNOPSIS
+
+ aubioquiet source
+ aubioquiet [[-i] source]
+ [-r rate] [-B win] [-H hop]
+ [-s sil]
+ [-v] [-h]
+
+DESCRIPTION
+
+ aubioquiet will print a timestamp each time it detects a new silent region or
+ a new loud region in a sound file.
+
+ When started with an input source (-i/--input), the detected timestamps are
+ printed on the console, in seconds.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -s, --silence sil Set the silence threshold, in dB, under which the pitch
+ will not be detected. Defaults to -90.0.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+EXAMPLE OUTPUT
+
+ NOISY: 28.775330
+
+ QUIET: 28.914648
+
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiopitch(1),
+ aubiotrack(1),
+ aubionotes(1),
+ aubiomfcc(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission
+ is granted to copy, distribute and/or modify this document under the terms
+ of the GNU General Public License, Version 3 any later version published
+ by the Free Software Foundation.
diff --git a/doc/aubiotrack.txt b/doc/aubiotrack.txt
new file mode 100644
index 0000000..753e97f
--- /dev/null
+++ b/doc/aubiotrack.txt
@@ -0,0 +1,88 @@
+NAME
+ aubiotrack - a command line tool to extract musical beats from audio signals
+
+SYNOPSIS
+
+ aubiotrack source
+ aubiotrack [[-i] source] [-o sink]
+ [-r rate] [-B win] [-H hop]
+ [-s sil] [-m]
+ [-j] [-v] [-h]
+
+DESCRIPTION
+
+ aubiotrack attempts to detect beats, the time where one would intuitively be
+ tapping his foot.
+
+ When started with an input source (-i/--input), the detected beats are given
+ on the console, in seconds.
+
+ When started without an input source, or with the jack option (-j/--jack),
+ aubiotrack starts in jack mode.
+
+OPTIONS
+
+ This program follows the usual GNU command line syntax, with long options
+ starting with two dashes (--). A summary of options is included below.
+
+ -i, --input source Run analysis on this audio file. Most uncompressed and
+ compressed are supported, depending on how aubio was built.
+
+ -o, --output sink Save results in this file. The file will be created on the
+ model of the input file. Beats are marked by a short wood-block like sound.
+
+ -r, --samplerate rate Fetch the input source, resampled at the given
+ sampling rate. The rate should be specified in Hertz as an integer. If 0,
+ the sampling rate of the original source will be used. Defaults to 0.
+
+ -B, --bufsize win The size of the buffer to analyze, that is the length
+ of the window used for spectral and temporal computations. Defaults to 512.
+
+ -H, --hopsize hop The number of samples between two consecutive analysis.
+ Defaults to 256.
+
+ -s, --silence sil Set the silence threshold, in dB, under which the pitch
+ 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.
+
+ -m, --mix-input Mix source signal to the output signal before writing to
+ sink.
+
+ -f, --force-overwrite Overwrite output file if it already exists.
+
+ -j, --jack Use Jack input/output. You will need a Jack connection
+ controller to feed aubio some signal and listen to its output.
+
+ -h, --help Print a short help message and exit.
+
+ -v, --verbose Be verbose.
+
+BEAT TRACKING METHODS
+
+ Aubio currently implements one the causal beat tracking algorithm designed by
+ Matthew Davies and described in the following articles:
+
+ Matthew E. P. Davies and Mark D. Plumbley. Causal tempo tracking of audio.
+ In Proceedings of the International Symposium on Music Information Retrieval
+ (ISMIR), pages 164­169, Barcelona, Spain, 2004.
+
+ Matthew E. P. Davies, Paul Brossier, and Mark D. Plumbley. Beat tracking
+ towards automatic musical accompaniment. In Proceedings of the Audio
+ Engeeniring Society 118th Convention, Barcelona, Spain, May 2005.
+
+SEE ALSO
+
+ aubioonset(1),
+ aubiopitch(1),
+ aubionotes(1),
+ aubioquiet(1),
+ aubiomfcc(1),
+ and
+ aubiocut(1).
+
+AUTHOR
+
+ This manual page was written by Paul Brossier <piem@aubio.org>. Permission is
+ granted to copy, distribute and/or modify this document under the terms of
+ the GNU General Public License as published by the Free Software Foundation,
+ either version 3 of the License, or (at your option) any later version.
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..48e5a4e
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+#
+# aubio documentation build configuration file, created by
+# sphinx-quickstart on Sun Jan 26 20:43:11 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+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'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.viewcode', 'sphinx.ext.autodoc']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'aubio'
+copyright = u'2014, 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
+# built documents.
+#
+# The short X.Y version.
+version = '0.4'
+# The full version, including alpha/beta/rc tags.
+release = 'latest'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'colorful'
+
+# A list of ignored prefixes for module index sorting.
+modindex_common_prefix = ['aubio.']
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# 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
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# 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']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'aubiodoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'aubio.tex', u'aubio Documentation',
+ u'Paul Brossier', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'aubio', u'aubio Documentation',
+ [u'Paul Brossier'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'aubio', u'aubio Documentation',
+ u'Paul Brossier', 'aubio', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/doc/full.cfg b/doc/full.cfg
new file mode 100644
index 0000000..ce341b3
--- /dev/null
+++ b/doc/full.cfg
@@ -0,0 +1,2354 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = aubio
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = "0.4.2~alpha full"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = full
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = ../src
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.h \
+ *.c
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = ../examples \
+ ../tests/src
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.aubio.aubio
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.aubio.aubio.Maintainer
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.aubio.aubio
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = YES
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..70b9df8
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,113 @@
+aubio documentation
+===================
+
+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.
+
+Its 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:
+
+- several onset detection methods
+- different pitch detection methods
+- tempo tracking and beat detection
+- MFCC (mel-frequency cepstrum coefficients)
+- FFT and phase vocoder
+- up/down-sampling
+- digital filters (low pass, high pass, and more)
+- spectral filtering
+- transient/steady-state separation
+- sound file and audio devices 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
+------------
+
+The home page of this project can be found at: http://aubio.org/
+
+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/
+
+Alternatively, feel free to contact directly the author.
+
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ installing
+ python_module
diff --git a/doc/installing.rst b/doc/installing.rst
new file mode 100644
index 0000000..6629e38
--- /dev/null
+++ b/doc/installing.rst
@@ -0,0 +1,65 @@
+.. 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``::
+
+ $ 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
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..1ac885c
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\aubio.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\aubio.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/doc/python_module.rst b/doc/python_module.rst
new file mode 100644
index 0000000..eab5cd4
--- /dev/null
+++ b/doc/python_module.rst
@@ -0,0 +1,33 @@
+aubio Python module
+===================
+
+Building the module
+-------------------
+
+From ``aubio`` source directory, run the following:
+
+.. code-block:: bash
+
+ $ cd python
+ $ ./setup.py build
+ $ sudo ./setup.py install
+
+Using the module
+----------------
+
+To use the python module, simply import aubio:
+
+.. code-block:: python
+
+ #! /usr/bin/env python
+ import aubio
+
+ s = aubio.source(sys.argv[1], 0, 256)
+ while True:
+ samples, read = s()
+ print samples
+ if read < 256: break
+
+Check out the `python demos for aubio
+<https://github.com/piem/aubio/blob/develop/python/demos/>`_ for more examples.
+
diff --git a/doc/web.cfg b/doc/web.cfg
new file mode 100644
index 0000000..a88e30e
--- /dev/null
+++ b/doc/web.cfg
@@ -0,0 +1,2373 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = aubio
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = "0.4.2~alpha"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = web
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = ../src
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = ../src/aubio_priv.h \
+ ../src/mathutils.h \
+ ../src/io/audio_unit.h \
+ ../src/io/source_sndfile.h \
+ ../src/io/source_apple_audio.h \
+ ../src/io/source_avcodec.h \
+ ../src/io/source_wavread.h \
+ ../src/io/sink_sndfile.h \
+ ../src/io/sink_apple_audio.h \
+ ../src/io/sink_wavwrite.h \
+ ../src/onset/peakpicker.h \
+ ../src/pitch/pitchmcomb.h \
+ ../src/pitch/pitchyin.h \
+ ../src/pitch/pitchyinfft.h \
+ ../src/pitch/pitchschmitt.h \
+ ../src/pitch/pitchfcomb.h \
+ ../src/pitch/pitchspecacf.h \
+ ../src/tempo/beattracking.h \
+ ../src/utils/hist.h \
+ ../src/utils/scale.h \
+ ../src/utils.h
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = ../examples \
+ ../tests/src
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.aubio.aubio
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.aubio.aubio.Maintainer
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.aubio.aubio
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = YES
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS = *.h
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/examples/aubiomfcc.c b/examples/aubiomfcc.c
new file mode 100644
index 0000000..d8bb910
--- /dev/null
+++ b/examples/aubiomfcc.c
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#include "parse_args.h"
+
+aubio_pvoc_t *pv; // a phase vocoder
+cvec_t *fftgrain; // outputs a spectrum
+aubio_mfcc_t * mfcc; // which the mfcc will process
+fvec_t * mfcc_out; // to get the output coefficients
+
+uint_t n_filters = 40;
+uint_t n_coefs = 13;
+
+void process_block (fvec_t *ibuf, fvec_t *obuf)
+{
+ fvec_zeros(obuf);
+ //compute mag spectrum
+ aubio_pvoc_do (pv, ibuf, fftgrain);
+ //compute mfccs
+ aubio_mfcc_do(mfcc, fftgrain, mfcc_out);
+}
+
+void process_print (void)
+{
+ /* output times in selected format */
+ print_time (blocks * hop_size);
+ outmsg ("\t");
+ /* output extracted mfcc */
+ fvec_print (mfcc_out);
+}
+
+int main(int argc, char **argv) {
+ // change some default params
+ buffer_size = 512;
+ hop_size = 256;
+
+ examples_common_init(argc,argv);
+
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d\n", hop_size);
+
+ pv = new_aubio_pvoc (buffer_size, hop_size);
+ fftgrain = new_cvec (buffer_size);
+ mfcc = new_aubio_mfcc(buffer_size, n_filters, n_coefs, samplerate);
+ mfcc_out = new_fvec(n_coefs);
+
+ examples_common_process((aubio_process_func_t)process_block, process_print);
+
+ del_aubio_pvoc (pv);
+ del_cvec (fftgrain);
+ del_aubio_mfcc(mfcc);
+ del_fvec(mfcc_out);
+
+ examples_common_del();
+ return 0;
+}
+
diff --git a/examples/aubionotes.c b/examples/aubionotes.c
new file mode 100644
index 0000000..7541098
--- /dev/null
+++ b/examples/aubionotes.c
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#define PROG_HAS_PITCH 1
+#define PROG_HAS_ONSET 1
+#define PROG_HAS_JACK 1
+// TODO add PROG_HAS_OUTPUT
+#include "parse_args.h"
+
+aubio_notes_t *notes;
+smpl_t lastmidi = 0.;
+
+void process_block (fvec_t *ibuf, fvec_t *obuf)
+{
+ aubio_notes_do (notes, ibuf, obuf);
+ // did we get a note off?
+ if (obuf->data[2] != 0) {
+ lastmidi = aubio_freqtomidi (obuf->data[2]) + .5;
+ send_noteon(lastmidi, 0);
+ }
+ // did we get a note on?
+ if (obuf->data[0] != 0) {
+ lastmidi = aubio_freqtomidi (obuf->data[0]) + .5;
+ send_noteon(lastmidi, obuf->data[1]);
+ }
+}
+
+void process_print (void)
+{
+ //if (verbose) outmsg("%f\n",pitch_obuf->data[0]);
+}
+
+int main(int argc, char **argv) {
+ examples_common_init(argc,argv);
+
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+
+ verbmsg ("onset method: %s, ", onset_method);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d, ", hop_size);
+ verbmsg ("threshold: %f\n", onset_threshold);
+
+ verbmsg ("pitch method: %s, ", pitch_method);
+ verbmsg ("buffer_size: %d, ", buffer_size * 4);
+ verbmsg ("hop_size: %d, ", hop_size);
+ verbmsg ("tolerance: %f\n", pitch_tolerance);
+
+ notes = new_aubio_notes ("default", buffer_size, hop_size, samplerate);
+
+ examples_common_process((aubio_process_func_t)process_block, process_print);
+
+ // send a last note off
+ send_noteon (lastmidi, 0);
+
+ del_aubio_notes (notes);
+
+ examples_common_del();
+ return 0;
+}
+
diff --git a/examples/aubioonset.c b/examples/aubioonset.c
new file mode 100644
index 0000000..69e7bc9
--- /dev/null
+++ b/examples/aubioonset.c
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#define PROG_HAS_ONSET 1
+#define PROG_HAS_OUTPUT 1
+#define PROG_HAS_JACK 1
+#include "parse_args.h"
+
+aubio_onset_t *o;
+aubio_wavetable_t *wavetable;
+fvec_t *onset;
+smpl_t is_onset;
+
+void process_block(fvec_t *ibuf, fvec_t *obuf)
+{
+ aubio_onset_do (o, ibuf, onset);
+ is_onset = fvec_get_sample(onset, 0);
+ if ( !usejack && ! sink_uri ) return;
+ 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 );
+ }
+ if (mix_input)
+ aubio_wavetable_do (wavetable, ibuf, obuf);
+ else
+ aubio_wavetable_do (wavetable, obuf, obuf);
+}
+
+void process_print (void)
+{
+ if ( is_onset ) {
+ print_time(aubio_onset_get_last (o));
+ outmsg ("\n");
+ }
+}
+
+int main(int argc, char **argv) {
+ examples_common_init(argc,argv);
+
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+ verbmsg ("onset method: %s, ", onset_method);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d, ", hop_size);
+ verbmsg ("silence: %f, ", silence_threshold);
+ verbmsg ("threshold: %f\n", onset_threshold);
+
+ o = new_aubio_onset (onset_method, buffer_size, hop_size, samplerate);
+ if (onset_threshold != 0.)
+ aubio_onset_set_threshold (o, onset_threshold);
+ if (silence_threshold != -90.)
+ aubio_onset_set_silence (o, silence_threshold);
+
+ onset = new_fvec (1);
+
+ wavetable = new_aubio_wavetable (samplerate, hop_size);
+ aubio_wavetable_set_freq ( wavetable, 2450.);
+ //aubio_sampler_load (sampler, "/archives/sounds/woodblock.aiff");
+
+ examples_common_process((aubio_process_func_t)process_block, process_print);
+
+ // send a last note off
+ send_noteon (miditap_note, 0);
+
+ del_aubio_onset (o);
+ del_aubio_wavetable (wavetable);
+ del_fvec (onset);
+
+ examples_common_del();
+ return 0;
+}
diff --git a/examples/aubiopitch.c b/examples/aubiopitch.c
new file mode 100644
index 0000000..bdda950
--- /dev/null
+++ b/examples/aubiopitch.c
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#define PROG_HAS_PITCH 1
+#define PROG_HAS_OUTPUT 1
+#define PROG_HAS_JACK 1
+#include "parse_args.h"
+
+aubio_pitch_t *o;
+aubio_wavetable_t *wavetable;
+fvec_t *pitch;
+
+void process_block(fvec_t * ibuf, fvec_t * obuf)
+{
+ smpl_t freq;
+ aubio_pitch_do (o, ibuf, pitch);
+ if ( !usejack && ! sink_uri ) return;
+ fvec_zeros(obuf);
+ freq = fvec_get_sample(pitch, 0);
+ aubio_wavetable_set_amp ( wavetable, aubio_level_lin (ibuf) );
+ aubio_wavetable_set_freq ( wavetable, freq );
+ if (mix_input)
+ aubio_wavetable_do (wavetable, ibuf, obuf);
+ else
+ aubio_wavetable_do (wavetable, obuf, obuf);
+}
+
+void process_print (void)
+{
+ smpl_t pitch_found = fvec_get_sample(pitch, 0);
+ print_time(blocks * hop_size);
+ outmsg(" %f\n", pitch_found);
+}
+
+int main(int argc, char **argv) {
+
+ buffer_size = 2048;
+
+ examples_common_init(argc,argv);
+
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+ verbmsg ("pitch method: %s, ", pitch_method);
+ verbmsg ("pitch unit: %s, ", pitch_unit);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d, ", hop_size);
+ verbmsg ("tolerance: %f\n", pitch_tolerance);
+
+ o = new_aubio_pitch (pitch_method, buffer_size, hop_size, samplerate);
+ if (pitch_tolerance != 0.)
+ aubio_pitch_set_tolerance (o, pitch_tolerance);
+ if (silence_threshold != -90.)
+ aubio_pitch_set_silence (o, silence_threshold);
+ if (pitch_unit != NULL)
+ aubio_pitch_set_unit (o, pitch_unit);
+
+ pitch = new_fvec (1);
+
+ wavetable = new_aubio_wavetable (samplerate, hop_size);
+ aubio_wavetable_play ( wavetable );
+
+ examples_common_process((aubio_process_func_t)process_block,process_print);
+
+ del_aubio_pitch (o);
+ del_aubio_wavetable (wavetable);
+ del_fvec (pitch);
+
+ examples_common_del();
+ return 0;
+}
+
diff --git a/examples/aubioquiet.c b/examples/aubioquiet.c
new file mode 100644
index 0000000..bbe158b
--- /dev/null
+++ b/examples/aubioquiet.c
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#include "parse_args.h"
+
+sint_t wassilence = 1, issilence;
+
+void process_block(fvec_t * ibuf, fvec_t * obuf) {
+ fvec_zeros (obuf);
+ if (aubio_silence_detection(ibuf, silence_threshold)==1) {
+ if (wassilence==1) issilence = 1;
+ else issilence = 2;
+ wassilence=1;
+ } else {
+ if (wassilence<=0) issilence = 0;
+ else issilence = -1;
+ wassilence=0;
+ }
+}
+
+void process_print (void) {
+ int curblocks = (blocks - 4) > 0 ? blocks - 4 : 0;
+ if (issilence == -1 || issilence == 2) {
+ if (issilence == -1) {
+ outmsg ("NOISY: ");
+ } else { // if (issilence == 2) {
+ outmsg ("QUIET: ");
+ }
+ print_time (curblocks * hop_size);
+ outmsg ("\n");
+ }
+}
+
+int main(int argc, char **argv) {
+ examples_common_init(argc,argv);
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d\n", hop_size);
+ examples_common_process((aubio_process_func_t)process_block,process_print);
+ examples_common_del();
+ return 0;
+}
+
diff --git a/examples/aubiotrack.c b/examples/aubiotrack.c
new file mode 100644
index 0000000..dcffbff
--- /dev/null
+++ b/examples/aubiotrack.c
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "utils.h"
+#define PROG_HAS_TEMPO 1
+#define PROG_HAS_ONSET 1
+#define PROG_HAS_OUTPUT 1
+#define PROG_HAS_JACK 1
+#include "parse_args.h"
+
+aubio_tempo_t * tempo;
+aubio_wavetable_t *wavetable;
+fvec_t * tempo_out;
+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);
+ is_beat = fvec_get_sample (tempo_out, 0);
+ if (silence_threshold != -90.)
+ is_silence = aubio_silence_detection(ibuf, silence_threshold);
+ if ( !usejack && ! sink_uri ) return;
+ 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 );
+ }
+ if (mix_input)
+ aubio_wavetable_do (wavetable, ibuf, obuf);
+ else
+ aubio_wavetable_do (wavetable, obuf, obuf);
+}
+
+void process_print (void) {
+ if ( is_beat && !is_silence ) {
+ print_time (aubio_tempo_get_last (tempo));
+ outmsg ("\n");
+ }
+}
+
+int main(int argc, char **argv) {
+ // override general settings from utils.c
+ buffer_size = 1024;
+ hop_size = 512;
+
+ examples_common_init(argc,argv);
+
+ verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
+
+ verbmsg ("tempo method: %s, ", tempo_method);
+ verbmsg ("buffer_size: %d, ", buffer_size);
+ verbmsg ("hop_size: %d, ", hop_size);
+ verbmsg ("threshold: %f\n", onset_threshold);
+
+ tempo_out = new_fvec(2);
+ tempo = new_aubio_tempo(tempo_method, buffer_size, hop_size, samplerate);
+ // 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);
+
+ wavetable = new_aubio_wavetable (samplerate, hop_size);
+ aubio_wavetable_set_freq ( wavetable, 2450.);
+ //aubio_sampler_load (sampler, "/archives/sounds/woodblock.aiff");
+
+ examples_common_process((aubio_process_func_t)process_block,process_print);
+
+ // send a last note off
+ send_noteon (miditap_note, 0);
+
+ del_aubio_tempo(tempo);
+ del_aubio_wavetable (wavetable);
+ del_fvec(tempo_out);
+
+ examples_common_del();
+ return 0;
+}
+
diff --git a/examples/jackio.c b/examples/jackio.c
new file mode 100644
index 0000000..f781fb1
--- /dev/null
+++ b/examples/jackio.c
@@ -0,0 +1,380 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <aubio.h>
+#include "config.h"
+
+#ifdef HAVE_JACK
+#include "utils.h" // for aubio_process_func_t
+#include "jackio.h"
+#include "aubio_priv.h"
+
+typedef jack_default_audio_sample_t jack_sample_t;
+
+#if HAVE_AUBIO_DOUBLE
+#define AUBIO_JACK_MAX_FRAMES 4096
+#define AUBIO_JACK_NEEDS_CONVERSION
+#endif
+
+#define RINGBUFFER_SIZE 1024*sizeof(jack_midi_event_t)
+
+/**
+ * jack device structure
+ */
+struct _aubio_jack_t
+{
+ /** jack client */
+ jack_client_t *client;
+ /** jack output ports */
+ jack_port_t **oports;
+ /** jack input ports */
+ jack_port_t **iports;
+ /** jack input buffer */
+ jack_sample_t **ibufs;
+ /** jack output buffer */
+ jack_sample_t **obufs;
+#ifdef AUBIO_JACK_NEEDS_CONVERSION
+ /** converted jack input buffer */
+ smpl_t **sibufs;
+ /** converted jack output buffer */
+ smpl_t **sobufs;
+#endif
+ /** jack input audio channels */
+ uint_t ichan;
+ /** jack output audio channels */
+ uint_t ochan;
+ /** jack input midi channels */
+ uint_t imidichan;
+ /** jack output midi channels */
+ uint_t omidichan;
+ /** midi output ringbuffer */
+ jack_ringbuffer_t *midi_out_ring;
+ /** jack samplerate (Hz) */
+ uint_t samplerate;
+ /** jack processing function */
+ aubio_process_func_t callback;
+ /** internal fvec */
+ fvec_t *ibuf;
+ fvec_t *obuf;
+ uint_t hop_size;
+ int pos;
+};
+
+/* static memory management */
+static aubio_jack_t *aubio_jack_alloc (uint_t ichan, uint_t ochan,
+ uint_t imidichan, uint_t omidichan);
+/* jack callback functions */
+static int aubio_jack_process (jack_nframes_t nframes, void *arg);
+static void aubio_jack_shutdown (void *arg);
+
+aubio_jack_t *
+new_aubio_jack (uint_t hop_size, uint_t ichan, uint_t ochan,
+ uint_t imidichan, uint_t omidichan)
+{
+ aubio_jack_t *jack_setup = aubio_jack_alloc (ichan, ochan,
+ imidichan, omidichan);
+ uint_t i;
+ char *client_name = "aubio";
+ char *jack_port_type;
+ char name[64];
+ /* initial jack client setup */
+ jack_options_t options = JackNullOption;
+ jack_status_t *status = NULL;
+ if ((jack_setup->client = jack_client_open (client_name, options, status)) == 0) {
+ AUBIO_ERR ("jack server not running?\n");
+ AUBIO_QUIT (AUBIO_FAIL);
+ }
+
+ if (jack_setup->omidichan) {
+ jack_setup->midi_out_ring = jack_ringbuffer_create (RINGBUFFER_SIZE);
+
+ if (jack_setup->midi_out_ring == NULL) {
+ AUBIO_ERR ("Failed creating jack midi output ringbuffer.");
+ AUBIO_QUIT (AUBIO_FAIL);
+ }
+
+ jack_ringbuffer_mlock (jack_setup->midi_out_ring);
+ }
+
+ /* set callbacks */
+ jack_set_process_callback (jack_setup->client, aubio_jack_process,
+ (void *) jack_setup);
+ jack_on_shutdown (jack_setup->client, aubio_jack_shutdown,
+ (void *) jack_setup);
+
+ /* register jack output audio and midi ports */
+ for (i = 0; i < ochan + omidichan; i++) {
+ if (i < ochan) {
+ jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
+ AUBIO_SPRINTF (name, "out_%d", i + 1);
+ } else {
+ jack_port_type = JACK_DEFAULT_MIDI_TYPE;
+ AUBIO_SPRINTF (name, "midi_out_%d", i - ochan + 1);
+ }
+ if ((jack_setup->oports[i] =
+ jack_port_register (jack_setup->client, name,
+ jack_port_type, JackPortIsOutput, 0)) == 0) {
+ goto beach;
+ }
+ AUBIO_DBG ("%s:%s\n", client_name, name);
+ }
+
+ /* register jack input audio ports */
+ for (i = 0; i < ichan + imidichan; i++) {
+ if (i < ichan) {
+ jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
+ AUBIO_SPRINTF (name, "in_%d", i + 1);
+ } else {
+ jack_port_type = JACK_DEFAULT_MIDI_TYPE;
+ AUBIO_SPRINTF (name, "midi_in_%d", i - ichan + 1);
+ }
+ if ((jack_setup->iports[i] =
+ jack_port_register (jack_setup->client, name,
+ jack_port_type, JackPortIsInput, 0)) == 0) {
+ goto beach;
+ }
+ AUBIO_DBG ("%s:%s\n", client_name, name);
+ }
+
+ /* get sample rate */
+ jack_setup->samplerate = jack_get_sample_rate (jack_setup->client);
+
+ jack_setup->hop_size = hop_size;
+ jack_setup->ibuf = new_fvec(hop_size);
+ jack_setup->obuf = new_fvec(hop_size);
+ jack_setup->pos = 0;
+ return jack_setup;
+
+beach:
+ AUBIO_ERR ("failed registering port \"%s:%s\"!\n", client_name, name);
+ jack_client_close (jack_setup->client);
+ AUBIO_QUIT (AUBIO_FAIL);
+}
+
+uint_t
+aubio_jack_get_samplerate (aubio_jack_t * jack_setup) {
+ return jack_setup->samplerate;
+}
+
+uint_t
+aubio_jack_activate (aubio_jack_t * jack_setup, aubio_process_func_t callback)
+{
+ /* set processing callback */
+ jack_setup->callback = callback;
+ /* actual jack process activation */
+ if (jack_activate (jack_setup->client)) {
+ AUBIO_ERR ("jack client activation failed");
+ return 1;
+ }
+ return 0;
+}
+
+void
+aubio_jack_close (aubio_jack_t * jack_setup)
+{
+ /* bug : should disconnect all ports first */
+ jack_client_close (jack_setup->client);
+}
+
+/* memory management */
+static aubio_jack_t *
+aubio_jack_alloc (uint_t ichan, uint_t ochan,
+ uint_t imidichan, uint_t omidichan)
+{
+ aubio_jack_t *jack_setup = AUBIO_NEW (aubio_jack_t);
+ jack_setup->ichan = ichan;
+ jack_setup->ochan = ochan;
+ jack_setup->imidichan = imidichan;
+ jack_setup->omidichan = omidichan;
+ jack_setup->oports = AUBIO_ARRAY (jack_port_t *, ichan + imidichan);
+ jack_setup->iports = AUBIO_ARRAY (jack_port_t *, ochan + omidichan);
+ jack_setup->ibufs = AUBIO_ARRAY (jack_sample_t *, ichan);
+ jack_setup->obufs = AUBIO_ARRAY (jack_sample_t *, ochan);
+#ifdef AUBIO_JACK_NEEDS_CONVERSION
+ /* allocate arrays for data conversion */
+ jack_setup->sibufs = AUBIO_ARRAY (smpl_t *, ichan);
+ uint_t i;
+ for (i = 0; i < ichan; i++) {
+ jack_setup->sibufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);
+ }
+ jack_setup->sobufs = AUBIO_ARRAY (smpl_t *, ochan);
+ for (i = 0; i < ochan; i++) {
+ jack_setup->sobufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);
+ }
+#endif
+ return jack_setup;
+}
+
+void
+del_aubio_jack (aubio_jack_t * jack_setup)
+{
+ if (jack_setup->omidichan && jack_setup->midi_out_ring) {
+ jack_ringbuffer_free (jack_setup->midi_out_ring);
+ }
+ del_fvec (jack_setup->ibuf);
+ del_fvec (jack_setup->obuf);
+ AUBIO_FREE (jack_setup->oports);
+ AUBIO_FREE (jack_setup->iports);
+ AUBIO_FREE (jack_setup->ibufs);
+ AUBIO_FREE (jack_setup->obufs);
+ AUBIO_FREE (jack_setup);
+}
+
+/* jack callback functions */
+static void
+aubio_jack_shutdown (void *arg UNUSED)
+{
+ AUBIO_ERR ("jack shutdown\n");
+ AUBIO_QUIT (AUBIO_OK);
+}
+
+static void process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes);
+
+static int block_process(aubio_jack_t *dev,
+ smpl_t **input, smpl_t **output, int nframes) {
+ unsigned int j; /*frames*/
+ for (j=0;j<(unsigned)nframes;j++) {
+ /* put synthnew in output */
+ output[0][j] = fvec_get_sample(dev->obuf, dev->pos);
+ /* write input to datanew */
+ fvec_set_sample(dev->ibuf, input[0][j], dev->pos);
+ /*time for fft*/
+ if (dev->pos == (int)(dev->hop_size) - 1) {
+ /* block loop */
+ dev->callback(dev->ibuf, dev->obuf);
+ /* end of block loop */
+ dev->pos = -1; /* so it will be zero next j loop */
+ }
+ dev->pos++;
+ }
+ return 1;
+}
+
+static int
+aubio_jack_process (jack_nframes_t nframes, void *arg)
+{
+ aubio_jack_t *dev = (aubio_jack_t *) arg;
+ uint_t i;
+ for (i = 0; i < dev->ichan; i++) {
+ /* get readable input */
+ dev->ibufs[i] =
+ (jack_sample_t *) jack_port_get_buffer (dev->iports[i], nframes);
+ }
+ for (i = 0; i < dev->ochan; i++) {
+ /* get writable output */
+ dev->obufs[i] =
+ (jack_sample_t *) jack_port_get_buffer (dev->oports[i], nframes);
+ }
+#ifndef AUBIO_JACK_NEEDS_CONVERSION
+ block_process(dev, dev->ibufs, dev->obufs, nframes);
+#else
+ uint_t j;
+ for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {
+ for (i = 0; i < dev->ichan; i++) {
+ dev->sibufs[i][j] = (smpl_t) dev->ibufs[i][j];
+ }
+ }
+ block_process(dev, dev->sibufs, dev->sobufs, nframes);
+ for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {
+ for (i = 0; i < dev->ochan; i++) {
+ dev->obufs[i][j] = (jack_sample_t) dev->sobufs[i][j];
+ }
+ }
+#endif
+
+ /* now process midi stuff */
+ if (dev->omidichan) {
+ process_midi_output (dev, nframes);
+ }
+
+ return 0;
+}
+
+void
+aubio_jack_midi_event_write (aubio_jack_t * dev, jack_midi_event_t * event)
+{
+ int written;
+
+ if (jack_ringbuffer_write_space (dev->midi_out_ring) < sizeof (*event)) {
+ AUBIO_ERR ("Not enough space to write midi output, midi event lost!\n");
+ return;
+ }
+
+ written = jack_ringbuffer_write (dev->midi_out_ring,
+ (char *) event, sizeof (*event));
+
+ if (written != sizeof (*event)) {
+ AUBIO_WRN ("Call to jack_ringbuffer_write failed, midi event lost! \n");
+ }
+}
+
+static void
+process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes)
+{
+ int read, sendtime;
+ jack_midi_event_t ev;
+ unsigned char *buffer;
+ jack_nframes_t last_frame_time = jack_last_frame_time (dev->client);
+ // TODO for each omidichan
+ void *port_buffer = jack_port_get_buffer (dev->oports[dev->ochan], nframes);
+
+ if (port_buffer == NULL) {
+ AUBIO_WRN ("Failed to get jack midi output port, will not send anything\n");
+ return;
+ }
+
+ jack_midi_clear_buffer (port_buffer);
+
+ // TODO add rate_limit
+
+ while (jack_ringbuffer_read_space (dev->midi_out_ring)) {
+ read = jack_ringbuffer_peek (dev->midi_out_ring, (char *) &ev, sizeof (ev));
+
+ if (read != sizeof (ev)) {
+ AUBIO_WRN ("Short read from the ringbuffer, possible note loss.\n");
+ jack_ringbuffer_read_advance (dev->midi_out_ring, read);
+ continue;
+ }
+
+ sendtime = ev.time + nframes - last_frame_time;
+
+ /* send time is after current period, will do this one later */
+ if (sendtime >= (int) nframes) {
+ break;
+ }
+
+ if (sendtime < 0) {
+ sendtime = 0;
+ }
+
+ jack_ringbuffer_read_advance (dev->midi_out_ring, sizeof (ev));
+
+ buffer = jack_midi_event_reserve (port_buffer, sendtime, ev.size);
+
+ if (buffer == NULL) {
+ AUBIO_WRN ("Call to jack_midi_event_reserve failed, note lost.\n");
+ break;
+ }
+
+ AUBIO_MEMCPY (buffer, ev.buffer, ev.size);
+ }
+}
+
+#endif /* HAVE_JACK */
diff --git a/examples/jackio.h b/examples/jackio.h
new file mode 100644
index 0000000..74803c7
--- /dev/null
+++ b/examples/jackio.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef JACKIO_H
+#define JACKIO_H
+
+/**
+ * @file
+ *
+ * Jack driver for aubio
+ *
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <jack/jack.h>
+#include <jack/midiport.h>
+#include <jack/ringbuffer.h>
+
+/** jack object */
+typedef struct _aubio_jack_t aubio_jack_t;
+
+/** jack device creation function */
+aubio_jack_t *new_aubio_jack (uint_t hop_size,
+ uint_t inchannels, uint_t outchannels,
+ uint_t imidichan, uint_t omidichan);
+/** activate jack client (run jackprocess function) */
+uint_t aubio_jack_activate (aubio_jack_t * jack_setup,
+ aubio_process_func_t callback);
+/** close and delete jack client */
+void aubio_jack_close (aubio_jack_t * jack_setup);
+void del_aubio_jack (aubio_jack_t * jack_setup);
+/** get samplerate */
+uint_t aubio_jack_get_samplerate (aubio_jack_t * jack_setup);
+
+/** write a jack_midi_event_t to the midi output ringbuffer */
+void aubio_jack_midi_event_write (aubio_jack_t * jack_setup,
+ jack_midi_event_t * event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* JACKIO_H */
diff --git a/examples/parse_args.h b/examples/parse_args.h
new file mode 100644
index 0000000..58423a2
--- /dev/null
+++ b/examples/parse_args.h
@@ -0,0 +1,306 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+extern int verbose;
+// input / output
+extern int usejack;
+extern char_t *source_uri;
+extern char_t *sink_uri;
+// general stuff
+extern uint_t samplerate;
+extern uint_t buffer_size;
+extern uint_t hop_size;
+// onset stuff
+extern char_t * onset_method;
+extern smpl_t onset_threshold;
+// pitch stuff
+extern char_t * pitch_method;
+extern char_t * pitch_unit;
+extern smpl_t pitch_tolerance;
+// time stuff
+extern uint_t time_format;
+// tempo stuff
+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;
+
+// functions defined in utils.c
+extern void examples_common_init (int argc, char **argv);
+extern void examples_common_del (void);
+extern void examples_common_process (aubio_process_func_t process_func,
+ aubio_print_func_t print);
+int parse_args (int argc, char **argv);
+
+// internal stuff
+extern int blocks;
+
+extern fvec_t *ibuf;
+extern fvec_t *obuf;
+
+const char *prog_name;
+
+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"
+#ifdef PROG_HAS_OUTPUT
+ " -o --output output file\n"
+#endif
+ " -r --samplerate select samplerate\n"
+ " use 0 to use input source samplerate, or 32000 to force 32kHz\n"
+ " -B --bufsize set buffer size\n"
+ " number of frames to run the analysis on\n"
+ " -H --hopsize set hopsize\n"
+ " number of frames to read from source before each analysis\n"
+#ifdef PROG_HAS_ONSET
+ " -O --onset select onset detection algorithm\n"
+ " <default|energy|hfc|complex|phase|specdiff|kl|mkl|specflux>;\n"
+ " 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"
+#endif /* PROG_HAS_ONSET */
+#ifdef PROG_HAS_PITCH
+ " -p --pitch select pitch detection algorithm\n"
+ " <default|yinfft|yin|mcomb|fcomb|schmitt>; default=yinfft\n"
+ " -u --pitch-unit select pitch output unit\n"
+ " <default|freq|hertz|Hz|midi|cent|bin>; default=freq\n"
+ " -l --pitch-tolerance select pitch tolerance\n"
+ " (yin, yinfft only) a value between 0.1 and 0.7; default=0.3\n"
+#endif /* PROG_HAS_PITCH */
+ " -s --silence select silence threshold\n"
+ " a value in dB, for instance -70, or -100; default=-90\n"
+ " -T --time-format select time values output format\n"
+ " (samples, ms, seconds) default=seconds\n"
+#ifdef PROG_HAS_OUTPUT
+ " -m --mix-input mix input signal with output signal\n"
+ " input signal will be added to output synthesis\n"
+ " -f --force-overwrite overwrite output file if needed\n"
+ " do not fail if output file already exists\n"
+#endif
+#ifdef PROG_HAS_JACK
+ " -j --jack use Jack\n"
+#endif
+ " -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"
+#endif /* PROG_HAS_JACK */
+#ifdef PROG_HAS_OUTPUT
+ "o:"
+#endif /* PROG_HAS_OUTPUT */
+#ifdef PROG_HAS_ONSET
+ "O:t:"
+#endif /* PROG_HAS_ONSET */
+#ifdef PROG_HAS_PITCH
+ "p:u:l:"
+#endif /* PROG_HAS_PITCH */
+ "T:"
+ "s:mf";
+ int next_option;
+ struct option long_options[] = {
+ {"help", 0, NULL, 'h'},
+ {"verbose", 0, NULL, 'v'},
+ {"input", 1, NULL, 'i'},
+ {"samplerate", 1, NULL, 'r'},
+ {"bufsize", 1, NULL, 'B'},
+ {"hopsize", 1, NULL, 'H'},
+#ifdef PROG_HAS_JACK
+ {"jack", 0, NULL, 'j'},
+#endif /* PROG_HAS_JACK */
+#ifdef PROG_HAS_OUTPUT
+ {"output", 1, NULL, 'o'},
+#endif /* PROG_HAS_OUTPUT */
+#ifdef PROG_HAS_ONSET
+ {"onset", 1, NULL, 'O'},
+ {"onset-threshold", 1, NULL, 't'},
+#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 */
+ {"silence", 1, NULL, 's'},
+ {"time-format", 1, NULL, 'T'},
+ {"mix-input", 0, NULL, 'm'},
+ {"force-overwrite", 0, NULL, 'f'},
+ {NULL, 0, NULL, 0}
+ };
+#endif /* HAVE_GETOPT_H */
+ prog_name = argv[0];
+ if (argc < 1) {
+ usage (stderr, 1);
+ return -1;
+ }
+#ifdef HAVE_GETOPT_H
+ do {
+ next_option = getopt_long (argc, argv, options, long_options, NULL);
+ switch (next_option) {
+ case 'h': /* help */
+ usage (stdout, 0);
+ return -1;
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+ case 'j':
+ usejack = 1;
+ break;
+ case 'i':
+ source_uri = optarg;
+ break;
+ case 'o':
+ sink_uri = optarg;
+ break;
+ case 'f': /* force_overwrite flag */
+ force_overwrite = 1;
+ break;
+ case 'r':
+ samplerate = atoi (optarg);
+ break;
+ case 'B':
+ buffer_size = atoi (optarg);
+ break;
+ case 'H':
+ hop_size = atoi (optarg);
+ break;
+ case 'O': /*onset method */
+ onset_method = optarg;
+ break;
+ case 't': /* threshold value for onset */
+ onset_threshold = (smpl_t) atof (optarg);
+ break;
+ case 'p':
+ pitch_method = optarg;
+ break;
+ case 'u':
+ pitch_unit = optarg;
+ break;
+ case 'l':
+ pitch_tolerance = (smpl_t) atof (optarg);
+ break;
+ case 'T':
+ if (strcmp (optarg, "samples") == 0) {
+ time_format = 2;
+ } else if (strcmp (optarg, "ms") == 0) {
+ time_format = 1;
+ } else if (strcmp (optarg, "seconds") == 0) {
+ time_format = 0;
+ } else {
+ errmsg ("Warning: did not get '%s' time-format string\n", optarg);
+ }
+ break;
+ case 's': /* silence threshold */
+ silence_threshold = (smpl_t) atof (optarg);
+ break;
+ case 'm': /* mix_input flag */
+ mix_input = 1;
+ break;
+ case '?': /* unknown options */
+ usage (stderr, 1);
+ break;
+ case -1: /* done with options */
+ break;
+ default: /*something else unexpected */
+ fprintf (stderr, "Error parsing option '%c'\n", next_option);
+ abort ();
+ }
+ }
+ 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 ) {
+ if (argc - optind == 1) {
+ source_uri = argv[optind];
+ } else if ( argc - optind > 1 ) {
+ errmsg ("Error: too many non-option arguments `%s'\n", argv[argc - 1]);
+ usage ( stderr, 1 );
+ }
+ } else if ( argc - optind > 0 ) {
+ errmsg ("Error: extra non-option argument %s\n", argv[optind]);
+ usage ( stderr, 1 );
+ }
+
+ // if no source, show a message
+ if (source_uri == NULL) {
+#ifdef PROG_HAS_JACK
+#if HAVE_JACK
+ verbmsg("No input source given, using jack\n");
+ usejack = 1;
+#else
+ errmsg("Error: no arguments given (and no available audio input)\n");
+ usage ( stderr, 1 );
+#endif /* HAVE_JACK */
+#else
+ errmsg("Error: no arguments given\n");
+ usage ( stderr, 1 );
+#endif /* PROG_HAS_JACK */
+ }
+
+ if ((sint_t)hop_size < 1) {
+ errmsg("Error: got hop_size %d, but can not be < 1\n", hop_size);
+ usage ( stderr, 1 );
+ } else if ((sint_t)buffer_size < 2) {
+ errmsg("Error: got buffer_size %d, but can not be < 2\n", buffer_size);
+ usage ( stderr, 1 );
+ } else if ((sint_t)buffer_size < (sint_t)hop_size) {
+ errmsg("Error: hop size (%d) is larger than win size (%d)\n",
+ hop_size, buffer_size);
+ usage ( stderr, 1 );
+ }
+
+ if ((sint_t)samplerate < 0) {
+ errmsg("Error: got samplerate %d, but can not be < 0\n", samplerate);
+ usage ( stderr, 1 );
+ }
+
+ return 0;
+}
diff --git a/examples/utils.c b/examples/utils.c
new file mode 100644
index 0000000..dc27386
--- /dev/null
+++ b/examples/utils.c
@@ -0,0 +1,221 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+
+ This file includes some tools common to all examples. Code specific to the
+ algorithm performed by each program should go in the source file of that
+ program instead.
+
+*/
+
+#include "utils.h"
+#ifdef HAVE_JACK
+#include "jackio.h"
+#endif /* HAVE_JACK */
+
+int verbose = 0;
+int usejack = 0;
+// input / output
+char_t *sink_uri = NULL;
+char_t *source_uri = NULL;
+// general stuff
+uint_t samplerate = 0;
+uint_t buffer_size = 512;
+uint_t hop_size = 256;
+// onset stuff
+char_t * onset_method = "default";
+smpl_t onset_threshold = 0.0; // will be set if != 0.
+// pitch stuff
+char_t * pitch_unit = "default";
+char_t * pitch_method = "default";
+smpl_t pitch_tolerance = 0.0; // will be set if != 0.
+// time stuff
+uint_t time_format = 0; // for "seconds", 1 for "ms", 2 for "samples"
+// tempo stuff
+char_t * tempo_method = "default";
+// more general stuff
+smpl_t silence_threshold = -90.;
+uint_t mix_input = 0;
+
+uint_t force_overwrite = 0;
+
+//
+// internal memory stuff
+aubio_source_t *this_source = NULL;
+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;
+
+extern void usage (FILE * stream, int exit_code);
+extern int parse_args (int argc, char **argv);
+
+#if HAVE_JACK
+aubio_jack_t *jack_setup;
+#endif /* HAVE_JACK */
+
+void examples_common_init (int argc, char **argv);
+void examples_common_del (void);
+void examples_common_process (aubio_process_func_t process_func,
+ aubio_print_func_t print);
+
+void examples_common_init (int argc, char **argv)
+{
+
+ /* parse command line arguments */
+ parse_args (argc, argv);
+
+ if (!usejack) {
+ debug ("Opening files ...\n");
+ this_source = new_aubio_source ((char_t*)source_uri, samplerate, hop_size);
+ if (this_source == NULL) {
+ errmsg ("Error: could not open input file %s\n", source_uri);
+ exit (1);
+ }
+ if (samplerate == 0) {
+ samplerate = aubio_source_get_samplerate(this_source);
+ }
+ if (sink_uri != NULL) {
+ uint_t sink_exists = (access(sink_uri, F_OK) == 0 );
+ if (!force_overwrite && sink_exists) {
+ errmsg ("Error: output file %s already exists, use -f to overwrite.\n",
+ sink_uri);
+ exit (1);
+ }
+ this_sink = new_aubio_sink ((char_t*)sink_uri, samplerate);
+ if (this_sink == NULL) {
+ errmsg ("Error: could not create output file %s\n", sink_uri);
+ exit (1);
+ }
+ }
+#ifdef HAVE_JACK
+ } else {
+ debug ("Jack init ...\n");
+ jack_setup = new_aubio_jack (hop_size, 1, 1, 0, 1);
+ samplerate = aubio_jack_get_samplerate (jack_setup);
+ source_uri = "jack";
+#endif /* HAVE_JACK */
+ }
+ ibuf = new_fvec (hop_size);
+ obuf = new_fvec (hop_size);
+
+}
+
+void examples_common_del (void)
+{
+ del_fvec (ibuf);
+ del_fvec (obuf);
+ aubio_cleanup ();
+ fflush(stderr);
+ fflush(stdout);
+}
+
+void examples_common_process (aubio_process_func_t process_func,
+ aubio_print_func_t print)
+{
+
+ uint_t read = 0;
+ if (usejack) {
+
+#ifdef HAVE_JACK
+ debug ("Jack activation ...\n");
+ aubio_jack_activate (jack_setup, process_func);
+ debug ("Processing (Ctrl+C to quit) ...\n");
+ pause ();
+ aubio_jack_close (jack_setup);
+#else /* HAVE_JACK */
+ usage (stderr, 1);
+ outmsg ("Compiled without jack output, exiting.\n");
+#endif /* HAVE_JACK */
+
+ } else {
+
+ uint_t total_read = 0;
+ blocks = 0;
+
+ do {
+ aubio_source_do (this_source, ibuf, &read);
+ process_func (ibuf, obuf);
+ // print to console if verbose or no output given
+ if (verbose || sink_uri == NULL) {
+ print();
+ }
+ if (this_sink) {
+ aubio_sink_do (this_sink, obuf, hop_size);
+ }
+ blocks++;
+ total_read += read;
+ } while (read == hop_size);
+
+ verbmsg ("read %.2fs (%d samples in %d blocks of %d) from %s at %dHz\n",
+ total_read * 1. / samplerate,
+ total_read, blocks, hop_size, source_uri, samplerate);
+
+ del_aubio_source (this_source);
+ del_aubio_sink (this_sink);
+
+ }
+}
+
+void
+send_noteon (smpl_t pitch, smpl_t velo)
+{
+#ifdef HAVE_JACK
+ jack_midi_event_t ev;
+ ev.size = 3;
+ ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
+ ev.time = 0;
+ if (usejack) {
+ ev.buffer[2] = velo;
+ ev.buffer[1] = pitch;
+ if (velo == 0) {
+ ev.buffer[0] = 0x80; /* note off */
+ } else {
+ ev.buffer[0] = 0x90; /* note on */
+ }
+ aubio_jack_midi_event_write (jack_setup, (jack_midi_event_t *) & ev);
+ } else
+#endif
+ if (velo == 0) {
+ print_time (blocks * hop_size);
+ outmsg ("\n");
+ } else {
+ outmsg ("%f\t", pitch);
+ print_time (blocks * hop_size);
+ outmsg ("\t");
+ }
+}
+
+void print_time (uint_t time_in_samples) {
+ /* output times in selected format */
+ if (time_format == 2) {
+ outmsg ("%d", time_in_samples);
+ } else if (time_format == 1) {
+ outmsg ("%f", 1000. * time_in_samples / (float) samplerate);
+ } else {
+ outmsg ("%f", time_in_samples / (float) samplerate);
+ }
+}
diff --git a/examples/utils.h b/examples/utils.h
new file mode 100644
index 0000000..e911bef
--- /dev/null
+++ b/examples/utils.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <aubio.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__)
+#else
+#define debug(...)
+#endif
+#define verbmsg(...) if (verbose) fprintf (stderr, __VA_ARGS__)
+#define errmsg(...) fprintf (stderr, __VA_ARGS__)
+#define outmsg(...) fprintf (stdout, __VA_ARGS__)
+#else
+#ifdef HAVE_DEBUG
+#define debug(...) fprintf (stderr, format , **args)
+#else
+#define debug(...)
+#endif
+#define verbmsg(format, args...) if (verbose) fprintf(stderr, format , ##args)
+#define errmsg(format, args...) fprintf(stderr, format , ##args)
+#define outmsg(format, args...) fprintf(stdout, format , ##args)
+#endif
+
+typedef void (aubio_print_func_t) (void);
+void send_noteon (smpl_t pitch, smpl_t velo);
+
+/** common process function */
+typedef int (*aubio_process_func_t) (fvec_t * input, fvec_t * output);
+
+void process_block (fvec_t *ibuf, fvec_t *obuf);
+void process_print (void);
+
+void print_time (uint_t samples);
diff --git a/examples/wscript_build b/examples/wscript_build
new file mode 100644
index 0000000..7970bf6
--- /dev/null
+++ b/examples/wscript_build
@@ -0,0 +1,27 @@
+# vim:set syntax=python:
+
+import os.path
+
+uselib = ['aubio']
+uselib += ['JACK']
+
+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 = 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',
+ source = source_file,
+ target = target,
+ includes = includes,
+ use = uselib + ['utilsio'],
+ )
diff --git a/nose2.cfg b/nose2.cfg
new file mode 100644
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/README.md b/python/README.md
new file mode 100644
index 0000000..7ee0fa4
--- /dev/null
+++ b/python/README.md
@@ -0,0 +1,100 @@
+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
+-------------------------
+
+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
+
+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/__init__.py b/python/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/__init__.py
diff --git a/python/demos/__init__.py b/python/demos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/demos/__init__.py
diff --git a/python/demos/demo_bpm_extract.py b/python/demos/demo_bpm_extract.py
new file mode 100755
index 0000000..ba7fbad
--- /dev/null
+++ b/python/demos/demo_bpm_extract.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python
+
+from aubio import source, tempo
+from numpy import median, diff
+
+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 KeyError:
+ """
+ # super fast
+ samplerate, win_s, hop_s = 4000, 128, 64
+ # fast
+ samplerate, win_s, hop_s = 8000, 512, 128
+ """
+ # default:
+ samplerate, win_s, hop_s = 44100, 1024, 512
+
+ s = source(path, samplerate, hop_s)
+ samplerate = s.samplerate
+ o = tempo("specdiff", win_s, hop_s, samplerate)
+ # List of beats, in samples
+ beats = []
+ # Total number of frames read
+ total_frames = 0
+
+ while True:
+ samples, read = s()
+ is_beat = o(samples)
+ if is_beat:
+ this_beat = o.get_last_s()
+ beats.append(this_beat)
+ #if o.get_confidence() > .2 and len(beats) > 2.:
+ # break
+ total_frames += read
+ if read < hop_s:
+ break
+
+ # Convert to periods and to bpm
+ if len(beats) > 1:
+ if len(beats) < 4:
+ print("few beats found in {:s}".format(path))
+ bpms = 60./diff(beats)
+ b = median(bpms)
+ else:
+ b = 0
+ print("not enough beats found in {:s}".format(path))
+ return b
+
+if __name__ == '__main__':
+ import sys
+ for f in sys.argv[1:]:
+ bpm = get_file_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
index 0000000..3d2f2d0
--- /dev/null
+++ b/python/demos/demo_create_test_sounds.py
@@ -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
index 0000000..10226ce
--- /dev/null
+++ b/python/demos/demo_filter.py
@@ -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)
diff --git a/python/demos/demo_filterbank.py b/python/demos/demo_filterbank.py
new file mode 100755
index 0000000..54aff57
--- /dev/null
+++ b/python/demos/demo_filterbank.py
@@ -0,0 +1,30 @@
+#! /usr/bin/env python
+
+from aubio import filterbank, fvec
+from pylab import loglog, show, xlim, ylim, xlabel, ylabel, title
+from numpy import vstack, arange
+
+win_s = 2048
+samplerate = 48000
+
+freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000]
+n_filters = len(freq_list) - 2
+
+f = filterbank(n_filters, win_s)
+freqs = fvec(freq_list)
+f.set_triangle_bands(freqs, samplerate)
+
+coeffs = f.get_coeffs()
+coeffs[4] *= 5.
+
+f.set_coeffs(coeffs)
+
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
+title('Bank of filters built using a simple list of boundaries\nThe middle band has been amplified by 2.')
+loglog(times.T, f.get_coeffs().T, '.-')
+xlim([50, samplerate/2])
+ylim([1.0e-6, 2.0e-2])
+xlabel('log frequency (Hz)')
+ylabel('log amplitude')
+
+show()
diff --git a/python/demos/demo_filterbank_slaney.py b/python/demos/demo_filterbank_slaney.py
new file mode 100755
index 0000000..f0e041e
--- /dev/null
+++ b/python/demos/demo_filterbank_slaney.py
@@ -0,0 +1,21 @@
+#! /usr/bin/env python
+
+from aubio import filterbank
+from numpy import arange, vstack
+
+win_s = 8192
+samplerate = 16000
+
+f = filterbank(40, win_s)
+f.set_mel_coeffs_slaney(samplerate)
+
+from pylab import loglog, title, show, xlim, ylim, xlabel, ylabel
+xlim([0,samplerate / 2])
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * 40)
+loglog(times.T, f.get_coeffs().T, '.-')
+title('Mel frequency bands coefficients')
+xlim([100, 7500])
+ylim([1.0e-3, 2.0e-2])
+xlabel('Frequency (Hz)')
+ylabel('Amplitude')
+show()
diff --git a/python/demos/demo_filterbank_triangle_bands.py b/python/demos/demo_filterbank_triangle_bands.py
new file mode 100755
index 0000000..c65df93
--- /dev/null
+++ b/python/demos/demo_filterbank_triangle_bands.py
@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+
+from aubio import filterbank, fvec
+from pylab import loglog, show, subplot, xlim, ylim, xlabel, ylabel, title
+from numpy import vstack, arange
+
+win_s = 2048
+samplerate = 48000
+
+freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000]
+n_filters = len(freq_list) - 2
+
+f = filterbank(n_filters, win_s)
+freqs = fvec(freq_list)
+f.set_triangle_bands(freqs, samplerate)
+
+subplot(211)
+title('Examples of filterbank built with set_triangle_bands and set_coeffs')
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
+loglog(times.T, f.get_coeffs().T, '.-')
+xlim([50, samplerate/2])
+ylim([1.0e-6, 2.0e-2])
+ylabel('Amplitude')
+
+## build a new filterbank
+
+freq_list = [60, 80, 200, 400, 800, 1200, 1600, 3200, 6400, 10000, 15000, 24000]
+n_filters = len(freq_list) - 2
+
+f = filterbank(n_filters, win_s)
+freqs = fvec(freq_list)
+f.set_triangle_bands(freqs, samplerate)
+
+coeffs = f.get_coeffs()
+coeffs[4] *= 5.
+
+f.set_coeffs(coeffs)
+
+subplot(212)
+times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
+loglog(times.T, f.get_coeffs().T, '.-')
+xlim([50, samplerate/2])
+ylim([1.0e-6, 2.0e-2])
+xlabel('Frequency (Hz)')
+ylabel('Amplitude')
+
+show()
diff --git a/python/demos/demo_keyboard.py b/python/demos/demo_keyboard.py
new file mode 100755
index 0000000..63786b9
--- /dev/null
+++ b/python/demos/demo_keyboard.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python
+
+def get_keyboard_edges(firstnote = 21, lastnote = 108):
+ octaves = 10
+
+ # build template of white notes
+ scalew = 12/7.
+ xw_temp = [i*scalew for i in range(0,7)]
+ # build template of black notes
+ scaleb = 6/7.
+ xb_temp = [i*scaleb for i in [1,3,7,9,11]]
+
+ xb,xw = [],[]
+ for octave in range(octaves-1):
+ for i in xb_temp:
+ curnote = i+12*octave
+ if curnote > firstnote-1 and curnote < lastnote+1:
+ xb = xb + [curnote]
+ for octave in range(octaves-1):
+ for i in xw_temp:
+ curnote = i+12*octave
+ if curnote > firstnote-1 and curnote < lastnote+1:
+ xw = xw + [curnote]
+
+ return xb, xw, 2/3. *scaleb, 1/2. * scalew
+
+def create_keyboard_patches(firstnote, lastnote, ax = None):
+ import matplotlib.pyplot as plt
+ from matplotlib.path import Path
+ import matplotlib.patches as mpatches
+
+ blacks, whites, b_width, w_width = get_keyboard_edges(firstnote, lastnote)
+
+ if not ax:
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+
+ verts, codes = [], []
+ for white in whites:
+ verts += [ (white - w_width, 0), (white - w_width, 1), (white + w_width, 1), (white + w_width, 0) ]
+ verts += [ (white - w_width, 0) ]
+ codes += [Path.MOVETO] + [Path.LINETO] * 4
+ path = Path(verts, codes)
+ patch = mpatches.PathPatch(path, facecolor= 'white', edgecolor='black', lw=1)
+ ax.add_patch(patch)
+
+ verts, codes = [], []
+ for black in blacks:
+ verts += [ (black - b_width, 0.33), (black - b_width, 1), (black + b_width, 1), (black + b_width, 0.33) ]
+ verts += [ (black - b_width, 0.33) ]
+ codes += [Path.MOVETO] + [Path.LINETO] * 4
+ path = Path(verts, codes)
+ patch = mpatches.PathPatch(path, facecolor= 'black', edgecolor='black', lw=1)
+ ax.add_patch(patch)
+
+ ax.axis(xmin = firstnote, xmax = lastnote)
+
+if __name__ == '__main__':
+
+ import matplotlib.pyplot as plt
+ create_keyboard_patches(firstnote = 58, lastnote = 84)
+ plt.show()
diff --git a/python/demos/demo_mel-energy.py b/python/demos/demo_mel-energy.py
new file mode 100755
index 0000000..db27f7e
--- /dev/null
+++ b/python/demos/demo_mel-energy.py
@@ -0,0 +1,71 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, pvoc, filterbank
+from numpy import vstack, zeros
+
+win_s = 512 # fft size
+hop_s = win_s // 4 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+pv = pvoc(win_s, hop_s)
+
+f = filterbank(40, win_s)
+f.set_mel_coeffs_slaney(samplerate)
+
+energies = zeros((40,))
+o = {}
+
+total_frames = 0
+downsample = 2
+
+while True:
+ samples, read = s()
+ fftgrain = pv(samples)
+ new_energies = f(fftgrain)
+ 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")
+ import matplotlib.pyplot as plt
+ from demo_waveform_plot import get_waveform_plot
+ from demo_waveform_plot import set_xlabels_sample2time
+ fig = plt.figure()
+ plt.rc('lines',linewidth='.8')
+ wave = plt.axes([0.1, 0.75, 0.8, 0.19])
+ get_waveform_plot(filename, samplerate, block_size = hop_s, ax = wave )
+ wave.yaxis.set_visible(False)
+ wave.xaxis.set_visible(False)
+
+ n_plots = len(energies.T)
+ all_desc_times = [ x * hop_s for x in range(len(energies)) ]
+ for i, band in enumerate(energies.T):
+ ax = plt.axes ( [0.1, 0.75 - ((i+1) * 0.65 / n_plots), 0.8, 0.65 / n_plots], sharex = wave )
+ ax.plot(all_desc_times, band, '-', label = 'band %d' % i)
+ #ax.set_ylabel(method, rotation = 0)
+ ax.xaxis.set_visible(False)
+ ax.yaxis.set_visible(False)
+ ax.axis(xmax = all_desc_times[-1], xmin = all_desc_times[0])
+ ax.annotate('band %d' % i, xy=(-10, 0), xycoords='axes points',
+ horizontalalignment='right', verticalalignment='bottom',
+ size = 'xx-small',
+ )
+ set_xlabels_sample2time( ax, all_desc_times[-1], samplerate)
+ #plt.ylabel('spectral descriptor value')
+ ax.xaxis.set_visible(True)
+ plt.show()
diff --git a/python/demos/demo_mfcc.py b/python/demos/demo_mfcc.py
new file mode 100755
index 0000000..dfbd7ed
--- /dev/null
+++ b/python/demos/demo_mfcc.py
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, pvoc, mfcc
+from numpy import vstack, zeros
+
+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])
+ sys.exit(1)
+
+source_filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(source_filename, samplerate, hop_s)
+samplerate = s.samplerate
+p = pvoc(win_s, hop_s)
+m = mfcc(win_s, n_filters, n_coeffs, samplerate)
+
+mfccs = zeros([n_coeffs,])
+frames_read = 0
+while True:
+ samples, read = s()
+ spec = p(samples)
+ mfcc_out = m(spec)
+ mfccs = vstack((mfccs, mfcc_out))
+ frames_read += read
+ if read < hop_s: break
+
+# do plotting
+from numpy import arange
+from demo_waveform_plot import get_waveform_plot
+from demo_waveform_plot import set_xlabels_sample2time
+import matplotlib.pyplot as plt
+
+fig = plt.figure()
+plt.rc('lines',linewidth='.8')
+wave = plt.axes([0.1, 0.75, 0.8, 0.19])
+
+get_waveform_plot( source_filename, samplerate, block_size = hop_s, ax = wave)
+wave.xaxis.set_visible(False)
+wave.yaxis.set_visible(False)
+
+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.plot(all_times, mfccs.T[i])
+
+# add time to the last axis
+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)
+plt.show()
diff --git a/python/demos/demo_miditofreq.py b/python/demos/demo_miditofreq.py
new file mode 100755
index 0000000..c325fb5
--- /dev/null
+++ b/python/demos/demo_miditofreq.py
@@ -0,0 +1,17 @@
+#! /usr/bin/env python
+
+from aubio import miditofreq
+from numpy import arange
+
+upsampling = 100.
+midi = arange(-10, 148 * upsampling)
+midi /= upsampling
+freq = miditofreq(midi)
+
+from matplotlib import pyplot as plt
+
+ax = plt.axes()
+ax.semilogy(midi, freq, '.')
+ax.set_xlabel('midi note')
+ax.set_ylabel('frequency (Hz)')
+plt.show()
diff --git a/python/demos/demo_onset.py b/python/demos/demo_onset.py
new file mode 100755
index 0000000..43e4aed
--- /dev/null
+++ b/python/demos/demo_onset.py
@@ -0,0 +1,35 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, onset
+
+win_s = 512 # fft size
+hop_s = win_s // 2 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+o = onset("default", win_s, hop_s, samplerate)
+
+# list of onsets, in samples
+onsets = []
+
+# total number of frames read
+total_frames = 0
+while True:
+ samples, read = s()
+ if o(samples):
+ print("%f" % o.get_last_s())
+ onsets.append(o.get_last())
+ total_frames += read
+ if read < hop_s: break
+#print len(onsets)
diff --git a/python/demos/demo_onset_plot.py b/python/demos/demo_onset_plot.py
new file mode 100755
index 0000000..5169cf7
--- /dev/null
+++ b/python/demos/demo_onset_plot.py
@@ -0,0 +1,75 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import onset, source
+from numpy import hstack, zeros
+
+win_s = 512 # fft size
+hop_s = win_s // 2 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+o = onset("default", win_s, hop_s, samplerate)
+
+# list of onsets, in samples
+onsets = []
+
+# storage for plotted data
+desc = []
+tdesc = []
+allsamples_max = zeros(0,)
+downsample = 2 # to plot n samples / hop_s
+
+# total number of frames read
+total_frames = 0
+while True:
+ samples, read = s()
+ if o(samples):
+ 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)
+ allsamples_max = hstack([allsamples_max, new_maxes])
+ desc.append(o.get_descriptor())
+ tdesc.append(o.get_thresholded_descriptor())
+ total_frames += read
+ if read < hop_s: break
+
+if 1:
+ # do plotting
+ 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)) ]
+ 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')
+ plt1.plot(allsamples_max_times, allsamples_max, '-b')
+ plt1.plot(allsamples_max_times, -allsamples_max, '-b')
+ for stamp in onsets:
+ stamp /= float(samplerate)
+ plt1.plot([stamp, stamp], [-1., 1.], '-r')
+ plt1.axis(xmin = 0., xmax = max(allsamples_max_times) )
+ plt1.xaxis.set_visible(False)
+ plt1.yaxis.set_visible(False)
+ desc_times = [ float(t) * hop_s / samplerate for t in range(len(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 / desc_max for d in tdesc]
+ for stamp in onsets:
+ stamp /= float(samplerate)
+ plt2.plot([stamp, stamp], [min(tdesc_plot), max(desc_plot)], '-r')
+ plt2.plot(desc_times, tdesc_plot, '-y')
+ plt2.axis(ymin = min(tdesc_plot), ymax = max(desc_plot))
+ plt.xlabel('time (s)')
+ #plt.savefig('/tmp/t.png', dpi=200)
+ plt.show()
diff --git a/python/demos/demo_pitch.py b/python/demos/demo_pitch.py
new file mode 100755
index 0000000..555a30e
--- /dev/null
+++ b/python/demos/demo_pitch.py
@@ -0,0 +1,103 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, pitch
+
+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 = 4096 // downsample # fft size
+hop_s = 512 // downsample # hop size
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+tolerance = 0.8
+
+pitch_o = pitch("yin", win_s, hop_s, samplerate)
+pitch_o.set_unit("midi")
+pitch_o.set_tolerance(tolerance)
+
+pitches = []
+confidences = []
+
+# total number of frames read
+total_frames = 0
+while True:
+ samples, read = s()
+ pitch = pitch_o(samples)[0]
+ #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))
+ pitches += [pitch]
+ confidences += [confidence]
+ total_frames += read
+ if read < hop_s: break
+
+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
+
+skip = 1
+
+pitches = array(pitches[skip:])
+confidences = array(confidences[skip:])
+times = [t * hop_s for t in range(len(pitches))]
+
+fig = plt.figure()
+
+ax1 = fig.add_subplot(311)
+ax1 = get_waveform_plot(filename, samplerate = samplerate, block_size = hop_s, ax = ax1)
+plt.setp(ax1.get_xticklabels(), visible = False)
+ax1.set_xlabel('')
+
+def array_from_text_file(filename, dtype = 'float'):
+ 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)
+ground_truth = os.path.splitext(filename)[0] + '.f0.Corrected'
+if os.path.isfile(ground_truth):
+ ground_truth = array_from_text_file(ground_truth)
+ true_freqs = ground_truth[:,2]
+ true_freqs = ma.masked_where(true_freqs < 2, true_freqs)
+ true_times = float(samplerate) * ground_truth[:,0]
+ ax2.plot(true_times, true_freqs, 'r')
+ ax2.axis( ymin = 0.9 * true_freqs.min(), ymax = 1.1 * true_freqs.max() )
+# plot raw pitches
+ax2.plot(times, pitches, '.g')
+# plot cleaned up pitches
+cleaned_pitches = pitches
+#cleaned_pitches = ma.masked_where(cleaned_pitches < 0, cleaned_pitches)
+#cleaned_pitches = ma.masked_where(cleaned_pitches > 120, cleaned_pitches)
+cleaned_pitches = ma.masked_where(confidences < tolerance, cleaned_pitches)
+ax2.plot(times, cleaned_pitches, '.-')
+#ax2.axis( ymin = 0.9 * cleaned_pitches.min(), ymax = 1.1 * cleaned_pitches.max() )
+#ax2.axis( ymin = 55, ymax = 70 )
+plt.setp(ax2.get_xticklabels(), visible = False)
+ax2.set_ylabel('f0 (midi)')
+
+# plot confidence
+ax3 = fig.add_subplot(313, sharex = ax1)
+# plot the confidence
+ax3.plot(times, confidences)
+# draw a line at tolerance
+ax3.plot(times, [tolerance]*len(confidences))
+ax3.axis( xmin = times[0], xmax = times[-1])
+ax3.set_ylabel('condidence')
+set_xlabels_sample2time(ax3, times[-1], samplerate)
+plt.show()
+#plt.savefig(os.path.basename(filename) + '.svg')
diff --git a/python/demos/demo_pitch_sinusoid.py b/python/demos/demo_pitch_sinusoid.py
new file mode 100755
index 0000000..629f327
--- /dev/null
+++ b/python/demos/demo_pitch_sinusoid.py
@@ -0,0 +1,71 @@
+#! /usr/bin/env python
+
+import numpy as np
+import aubio
+
+def build_sinusoid(length, freqs, samplerate):
+ return np.sin( 2. * np.pi * np.arange(length) * freqs / samplerate).astype(aubio.float_type)
+
+def run_pitch(p, input_vec):
+ 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']
+
+cands = {}
+buf_size = 2048
+hop_size = 512
+samplerate = 44100
+sin_length = (samplerate * 10) % 512 * 512
+freqs = np.zeros(sin_length)
+
+partition = sin_length // 8
+pointer = 0
+
+pointer += partition
+freqs[pointer: pointer + partition] = 440
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 740
+
+pointer += partition
+freqs[ pointer : pointer + partition ] = 1480
+
+pointer += partition
+pointer += partition
+freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length/8)
+
+a = build_sinusoid(sin_length, freqs, samplerate)
+
+for method in methods:
+ p = aubio.pitch(method, buf_size, hop_size, samplerate)
+ cands[method] = run_pitch(p, a)
+ print(method)
+ print(cands[method])
+
+print("done computing")
+
+if 1:
+ import matplotlib.pyplot as plt
+
+ # times
+ ramp = np.arange(0, sin_length / hop_size).astype('float') * hop_size / samplerate
+
+ # 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_pysoundcard_play.py b/python/demos/demo_pysoundcard_play.py
new file mode 100755
index 0000000..3517d62
--- /dev/null
+++ b/python/demos/demo_pysoundcard_play.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python
+
+def play_source(source_path):
+ """Play an audio file using pysoundcard."""
+
+ from aubio import source
+ from pysoundcard import Stream
+
+ hop_size = 256
+ f = source(source_path, hop_size = hop_size)
+ samplerate = f.samplerate
+
+ s = Stream(samplerate = samplerate, blocksize = hop_size)
+ s.start()
+ read = 0
+ while 1:
+ vec, read = f()
+ s.write(vec)
+ if read < hop_size: break
+ s.stop()
+
+if __name__ == '__main__':
+ import sys
+ play_source(sys.argv[1])
diff --git a/python/demos/demo_pysoundcard_record.py b/python/demos/demo_pysoundcard_record.py
new file mode 100755
index 0000000..b97a838
--- /dev/null
+++ b/python/demos/demo_pysoundcard_record.py
@@ -0,0 +1,30 @@
+#! /usr/bin/env python
+
+def record_sink(sink_path):
+ """Record an audio file using pysoundcard."""
+
+ from aubio import sink
+ from pysoundcard import Stream
+
+ hop_size = 256
+ duration = 5 # in seconds
+ s = Stream(blocksize = hop_size, channels = 1)
+ g = sink(sink_path, samplerate = int(s.samplerate))
+
+ s.start()
+ total_frames = 0
+ try:
+ while total_frames < duration * s.samplerate:
+ vec = s.read(hop_size)
+ # mix down to mono
+ mono_vec = vec.sum(-1) / float(s.channels[0])
+ g(mono_vec, hop_size)
+ total_frames += hop_size
+ except KeyboardInterrupt:
+ duration = total_frames / float(s.samplerate)
+ print("stopped after %.2f seconds" % duration)
+ s.stop()
+
+if __name__ == '__main__':
+ import sys
+ record_sink(sys.argv[1])
diff --git a/python/demos/demo_reading_speed.py b/python/demos/demo_reading_speed.py
new file mode 100755
index 0000000..90739f3
--- /dev/null
+++ b/python/demos/demo_reading_speed.py
@@ -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)
diff --git a/python/demos/demo_simple_robot_voice.py b/python/demos/demo_simple_robot_voice.py
new file mode 100755
index 0000000..670f79f
--- /dev/null
+++ b/python/demos/demo_simple_robot_voice.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink, pvoc
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print('usage: %s <inputfile> <outputfile>' % sys.argv[0])
+ sys.exit(1)
+ samplerate = 44100
+ f = source(sys.argv[1], samplerate, 256)
+ g = sink(sys.argv[2], samplerate)
+ total_frames, read = 0, 256
+
+ win_s = 512 # fft size
+ hop_s = win_s // 2 # hop size
+ pv = pvoc(win_s, hop_s) # phase vocoder
+
+ while read:
+ samples, read = f()
+ spectrum = pv(samples) # compute spectrum
+ #spectrum.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
+
+ format_str = "read {:d} samples from {:s}, written to {:s}"
+ print(format_str.format(total_frames, f.uri, g.uri))
diff --git a/python/demos/demo_simple_spectral_weighting.py b/python/demos/demo_simple_spectral_weighting.py
new file mode 100755
index 0000000..dd4abbe
--- /dev/null
+++ b/python/demos/demo_simple_spectral_weighting.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink, pvoc
+from numpy import arange, exp, hstack, zeros, cos
+from math import pi
+
+def gauss(size):
+ return exp(- 1.0 / (size * size) * pow(2.0* arange(size) - 1. *size, 2.));
+
+def hanningz(size):
+ return 0.5 * (1. - cos(2.*pi*arange(size) / size))
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print('usage: %s <inputfile> <outputfile>' % sys.argv[0])
+ sys.exit(1)
+ samplerate = 0
+ if len(sys.argv) > 3: samplerate = int(sys.argv[3])
+ f = source(sys.argv[1], samplerate, 256)
+ samplerate = f.samplerate
+ g = sink(sys.argv[2], samplerate)
+
+ win_s = 512 # fft size
+ hop_s = win_s // 2 # hop size
+ pv = pvoc(win_s, hop_s) # phase vocoder
+
+ # spectral weighting vector
+ spec_weight = hstack ( [
+ .8 * hanningz(80)[40:],
+ zeros( 50 ),
+ 1.3 * hanningz(100),
+ zeros (win_s // 2 + 1 - 40 - 50 - 100),
+ ] )
+
+ if 0:
+ from pylab import plot, show
+ plot(spec_weight)
+ show()
+
+ total_frames, read = 0, hop_s
+ while read:
+ # get new samples
+ samples, read = f()
+ # compute spectrum
+ spectrum = pv(samples)
+ # apply weight to spectral amplitudes
+ spectrum.norm *= spec_weight
+ # resynthesise modified samples
+ new_samples = pv.rdo(spectrum)
+ # write to output
+ g(new_samples, read)
+ total_frames += read
+
+ duration = total_frames / float(samplerate)
+ print("read {:.3f}s from {:s}".format(duration, f.uri))
diff --git a/python/demos/demo_sink.py b/python/demos/demo_sink.py
new file mode 100755
index 0000000..ce2bb1b
--- /dev/null
+++ b/python/demos/demo_sink.py
@@ -0,0 +1,31 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink
+
+if __name__ == '__main__':
+ if len(sys.argv) < 3:
+ print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
+ sys.exit(1)
+
+ if len(sys.argv) > 3: samplerate = int(sys.argv[3])
+ else: samplerate = 0
+ if len(sys.argv) > 4: hop_size = int(sys.argv[4])
+ else: hop_size = 256
+
+ f = source(sys.argv[1], samplerate, hop_size)
+ if samplerate == 0: samplerate = f.samplerate
+ g = sink(sys.argv[2], samplerate)
+
+ total_frames, read = 0, hop_size
+ while read:
+ vec, read = f()
+ g(vec, read)
+ total_frames += read
+ 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)
diff --git a/python/demos/demo_sink_create_woodblock.py b/python/demos/demo_sink_create_woodblock.py
new file mode 100755
index 0000000..5a42adc
--- /dev/null
+++ b/python/demos/demo_sink_create_woodblock.py
@@ -0,0 +1,57 @@
+#! /usr/bin/env python
+
+import sys
+from math import pi, e
+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])
+ sys.exit(1)
+
+samplerate = 44100 # samplerate in Hz
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+pitch = 2200 # in Hz
+blocksize = 256 # in samples
+duration = 0.02 # in seconds
+
+twopi = pi * 2.
+
+duration = int ( samplerate * duration ) # convert to samples
+attack = int (samplerate * .001 )
+decay = .5
+
+period = float(samplerate) / pitch
+# create a sine lookup table
+tablelen = 1000
+sinetable = arange(tablelen + 1, dtype = float_type)
+sinetable = 0.7 * sin(twopi * sinetable/tablelen)
+sinetone = zeros((duration,), dtype = float_type)
+
+# compute sinetone at floating point period
+for i in range(duration):
+ x = int((i % period) / float(period) * tablelen)
+ idx = int(x)
+ frac = x - idx
+ a = sinetable[idx]
+ b = sinetable[idx + 1]
+ sinetone[i] = a + frac * (b -a)
+
+# apply some envelope
+float_ramp = arange(duration, dtype = float_type)
+sinetone *= exp( - e * float_ramp / duration / decay)
+sinetone[:attack] *= exp( e * ( float_ramp[:attack] / attack - 1 ) )
+
+if 1:
+ import matplotlib.pyplot as plt
+ plt.plot(sinetone)
+ plt.show()
+
+my_sink = sink(sys.argv[1], samplerate)
+
+total_frames = 0
+while total_frames + blocksize < duration:
+ my_sink(sinetone[total_frames:total_frames+blocksize], blocksize)
+ total_frames += blocksize
+my_sink(sinetone[total_frames:duration], duration - total_frames)
diff --git a/python/demos/demo_sink_multi.py b/python/demos/demo_sink_multi.py
new file mode 100755
index 0000000..70eb636
--- /dev/null
+++ b/python/demos/demo_sink_multi.py
@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink
+
+if __name__ == '__main__':
+ if len(sys.argv) < 3:
+ print('usage: %s <inputfile> <outputfile> [samplerate] [hop_size]' % sys.argv[0])
+ sys.exit(1)
+
+ if len(sys.argv) > 3: samplerate = int(sys.argv[3])
+ else: samplerate = 0
+ if len(sys.argv) > 4: hop_size = int(sys.argv[4])
+ else: hop_size = 256
+
+ f = source(sys.argv[1], samplerate, hop_size)
+ if samplerate == 0: samplerate = f.samplerate
+ g = sink(sys.argv[2], samplerate, f.channels)
+
+ total_frames, read = 0, hop_size
+ while read:
+ vec, read = f.do_multi()
+ g.do_multi(vec, read)
+ total_frames += read
+ 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)
diff --git a/python/demos/demo_slicing.py b/python/demos/demo_slicing.py
new file mode 100755
index 0000000..d10d0af
--- /dev/null
+++ b/python/demos/demo_slicing.py
@@ -0,0 +1,51 @@
+#! /usr/bin/env python
+
+import sys
+import os.path
+from aubio import source, sink
+
+if __name__ == '__main__':
+ if len(sys.argv) < 3:
+ print('usage: %s <inputfile> <duration>' % sys.argv[0])
+ sys.exit(1)
+ source_file = sys.argv[1]
+ duration = float(sys.argv[2])
+ source_base_name, source_ext = os.path.splitext(os.path.basename(source_file))
+
+ hopsize = 256
+ slice_n, total_frames_written, read = 0, 0, hopsize
+
+ def new_sink_name(source_base_name, slice_n, duration = duration):
+ return source_base_name + '_%02.3f' % (slice_n*duration) + '.wav'
+
+ f = source(source_file, 0, hopsize)
+ samplerate = f.samplerate
+ g = sink(new_sink_name(source_base_name, slice_n), samplerate)
+
+ #print "new slice:", slice_n, 0, "+", 0, "=", 0
+ while read == hopsize:
+ vec, read = f()
+ start_of_next_region = int(duration * samplerate * (slice_n + 1))
+ remaining = start_of_next_region - total_frames_written
+ # number of samples remaining is less than what we got
+ if remaining <= read:
+ # write remaining samples from current region
+ g(vec[0:remaining], remaining)
+ # close this file
+ del g
+ #print "new slice", slice_n, total_frames_written, "+", remaining, "=", start_of_next_region
+ slice_n += 1
+ # create a new file for the new region
+ g = sink(new_sink_name(source_base_name, slice_n), samplerate)
+ # write the remaining samples in the new file
+ g(vec[remaining:read], read - remaining)
+ else:
+ g(vec[0:read], read)
+ total_frames_written += read
+ total_duration = total_frames_written / float(samplerate)
+ slice_n += 1
+ 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
diff --git a/python/demos/demo_source.py b/python/demos/demo_source.py
new file mode 100755
index 0000000..c60d785
--- /dev/null
+++ b/python/demos/demo_source.py
@@ -0,0 +1,28 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print('usage: %s <inputfile> [samplerate] [hop_size]' % sys.argv[0])
+ sys.exit(1)
+ samplerate = 0
+ hop_size = 256
+ if len(sys.argv) > 2: samplerate = int(sys.argv[2])
+ if len(sys.argv) > 3: hop_size = int(sys.argv[3])
+
+ f = source(sys.argv[1], samplerate, hop_size)
+ samplerate = f.samplerate
+
+ total_frames, read = 0, f.hop_size
+ while read:
+ vec, read = f()
+ total_frames += read
+ if read < f.hop_size: break
+ 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_specdesc.py b/python/demos/demo_specdesc.py
new file mode 100755
index 0000000..6afc7f4
--- /dev/null
+++ b/python/demos/demo_specdesc.py
@@ -0,0 +1,80 @@
+#! /usr/bin/env python
+
+import sys
+import numpy as np
+from aubio import source, pvoc, specdesc
+
+win_s = 512 # fft size
+hop_s = win_s // 4 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+
+pv = pvoc(win_s, hop_s)
+
+methods = ['default', 'energy', 'hfc', 'complex', 'phase', 'specdiff', 'kl',
+ 'mkl', 'specflux', 'centroid', 'slope', 'rolloff', 'spread', 'skewness',
+ 'kurtosis', 'decrease',]
+
+all_descs = {}
+o = {}
+
+for method in methods:
+ cands = []
+ all_descs[method] = np.array([])
+ o[method] = specdesc(method, win_s)
+
+total_frames = 0
+downsample = 2
+
+while True:
+ samples, read = s()
+ fftgrain = pv(samples)
+ #outstr = "%f" % ( total_frames / float(samplerate) )
+ for method in methods:
+ specdesc_val = o[method](fftgrain)[0]
+ 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")
+ import matplotlib.pyplot as plt
+ from demo_waveform_plot import get_waveform_plot
+ from demo_waveform_plot import set_xlabels_sample2time
+ fig = plt.figure()
+ plt.rc('lines',linewidth='.8')
+ wave = plt.axes([0.1, 0.75, 0.8, 0.19])
+ get_waveform_plot(filename, samplerate, block_size = hop_s, ax = wave )
+ wave.yaxis.set_visible(False)
+ wave.xaxis.set_visible(False)
+
+ all_desc_times = [ x * hop_s for x in range(len(all_descs["default"])) ]
+ n_methods = len(methods)
+ for i, method in enumerate(methods):
+ #ax = fig.add_subplot (n_methods, 1, i)
+ #plt2 = plt.axes([0.1, 0.1, 0.8, 0.65], sharex = plt1)
+ ax = plt.axes ( [0.1, 0.75 - ((i+1) * 0.65 / n_methods), 0.8, 0.65 / n_methods], sharex = wave )
+ ax.plot(all_desc_times, all_descs[method], '-', label = method)
+ #ax.set_ylabel(method, rotation = 0)
+ ax.xaxis.set_visible(False)
+ ax.yaxis.set_visible(False)
+ ax.axis(xmax = all_desc_times[-1], xmin = all_desc_times[0])
+ ax.annotate(method, xy=(-10, 0), xycoords='axes points',
+ horizontalalignment='right', verticalalignment='bottom',
+ )
+ set_xlabels_sample2time(ax, all_desc_times[-1], samplerate)
+ #plt.ylabel('spectral descriptor value')
+ ax.xaxis.set_visible(True)
+ plt.show()
diff --git a/python/demos/demo_spectrogram.py b/python/demos/demo_spectrogram.py
new file mode 100755
index 0000000..51be917
--- /dev/null
+++ b/python/demos/demo_spectrogram.py
@@ -0,0 +1,77 @@
+#! /usr/bin/env python
+
+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
+
+ 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
+
+ # 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
+ 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:]:
+ fig = get_spectrogram(soundfile)
+ # display graph
+ plt.show()
+ #outimage = os.path.basename(soundfile) + '.png'
+ #print ("writing: " + outimage)
+ #plt.savefig(outimage)
+ plt.close()
diff --git a/python/demos/demo_tempo.py b/python/demos/demo_tempo.py
new file mode 100755
index 0000000..51e1ae3
--- /dev/null
+++ b/python/demos/demo_tempo.py
@@ -0,0 +1,40 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import tempo, source
+
+win_s = 512 # fft size
+hop_s = win_s // 2 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+o = tempo("default", win_s, hop_s, samplerate)
+
+# tempo detection delay, in samples
+# default to 4 blocks delay to catch up with
+delay = 4. * hop_s
+
+# list of beats, in samples
+beats = []
+
+# total number of frames read
+total_frames = 0
+while True:
+ samples, read = s()
+ is_beat = o(samples)
+ if is_beat:
+ this_beat = int(total_frames - delay + is_beat[0] * hop_s)
+ print("%f" % (this_beat / float(samplerate)))
+ beats.append(this_beat)
+ total_frames += read
+ if read < hop_s: break
+#print len(beats)
diff --git a/python/demos/demo_tempo_plot.py b/python/demos/demo_tempo_plot.py
new file mode 100755
index 0000000..48a6ccf
--- /dev/null
+++ b/python/demos/demo_tempo_plot.py
@@ -0,0 +1,79 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import tempo, source
+
+win_s = 512 # fft size
+hop_s = win_s // 2 # hop size
+
+if len(sys.argv) < 2:
+ print("Usage: %s <filename> [samplerate]" % sys.argv[0])
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+samplerate = 0
+if len( sys.argv ) > 2: samplerate = int(sys.argv[2])
+
+s = source(filename, samplerate, hop_s)
+samplerate = s.samplerate
+o = tempo("default", win_s, hop_s, samplerate)
+
+# tempo detection delay, in samples
+# default to 4 blocks delay to catch up with
+delay = 4. * hop_s
+
+# list of beats, in samples
+beats = []
+
+# total number of frames read
+total_frames = 0
+while True:
+ samples, read = s()
+ is_beat = o(samples)
+ if is_beat:
+ this_beat = o.get_last_s()
+ beats.append(this_beat)
+ total_frames += read
+ if read < hop_s: break
+
+if len(beats) > 1:
+ # do plotting
+ from numpy import mean, median, diff
+ import matplotlib.pyplot as plt
+ bpms = 60./ diff(beats)
+ 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')
+ for stamp in beats: plt1.plot([stamp, stamp], [-1., 1.], '-r')
+ plt1.axis(xmin = 0., xmax = total_frames / float(samplerate) )
+ plt1.xaxis.set_visible(False)
+ plt1.yaxis.set_visible(False)
+
+ # plot actual periods
+ plt2.plot(beats[1:], bpms, '-', label = 'raw')
+
+ # plot moving median of 5 last periods
+ median_win_s = 5
+ bpms_median = [ median(bpms[i:i + median_win_s:1]) for i in range(len(bpms) - median_win_s ) ]
+ plt2.plot(beats[median_win_s+1:], bpms_median, '-', label = 'median of %d' % median_win_s)
+ # plot moving median of 10 last periods
+ median_win_s = 20
+ bpms_median = [ median(bpms[i:i + median_win_s:1]) for i in range(len(bpms) - median_win_s ) ]
+ plt2.plot(beats[median_win_s+1:], bpms_median, '-', label = 'median of %d' % median_win_s)
+
+ plt2.axis(ymin = min(bpms), ymax = max(bpms))
+ #plt2.axis(ymin = 40, ymax = 240)
+ plt.xlabel('time (mm:ss)')
+ plt.ylabel('beats per minute (bpm)')
+ plt2.set_xticklabels([ "%02d:%02d" % (t/60, t%60) for t in plt2.get_xticks()[:-1]], rotation = 50)
+
+ #plt.savefig('/tmp/t.png', dpi=200)
+ plt2.legend()
+ plt.show()
+
+else:
+ 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
index 0000000..8569a44
--- /dev/null
+++ b/python/demos/demo_timestretch.py
@@ -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, mfcc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 1024
+hop_s = win_s / 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+ print("Usage: %s <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+ print("""Examples:
+ # twice faster
+ {0} track_01.mp3 track_01_faster.wav 2.0
+ # twice slower
+ {0} track_02.flac track_02_slower.wav 0.5
+ # one and a half time faster, resampling first the input to 22050
+ {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+ sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+# allocate memory to store norms and phases
+n_blocks = source_in.duration // hop_s + 1
+# adding an empty frame at end of spectrogram
+norms = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+phases = np.zeros((n_blocks + 1, win_s // 2 + 1), dtype = float_type)
+
+block_read = 0
+while True:
+ # read from source
+ samples, read = source_in()
+ # compute fftgrain
+ spec = p(samples)
+ # store current grain
+ norms[block_read] = spec.norm
+ phases[block_read] = spec.phas
+ # until end of file
+ if read < hop_s: break
+ # increment block counter
+ block_read += 1
+
+# just to make sure
+#source_in.close()
+
+sink_out = sink(output_filename, samplerate)
+
+# interpolated time steps (j = alpha * i)
+steps = np.arange(0, n_blocks, rate, dtype = float_type)
+# initial phase
+phas_acc = phases[0]
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+new_grain = cvec(win_s)
+
+for (t, step) in enumerate(steps):
+
+ frac = 1. - np.mod(step, 1.0)
+ # get pair of frames
+ t_norms = norms[int(step):int(step+2)]
+ t_phases = phases[int(step):int(step+2)]
+
+ # compute interpolated frame
+ new_grain.norm = frac * t_norms[0] + (1. - frac) * t_norms[1]
+ new_grain.phas = phas_acc
+ #print t, step, new_grain.norm
+ #print t, step, phas_acc
+
+ # psola
+ samples = p.rdo(new_grain)
+ if t > warmup: # skip the first few frames to warm up phase vocoder
+ # write to sink
+ sink_out(samples, hop_s)
+
+ # calculate phase advance
+ dphas = t_phases[1] - t_phases[0] - phi_advance
+ # unwrap angle to [-pi; pi]
+ dphas = unwrap2pi(dphas)
+ # cumulate phase, to be used for next frame
+ phas_acc += phi_advance + dphas
+
+for t in range(warmup + 1): # purge the last frames from the phase vocoder
+ new_grain.norm[:] = 0
+ new_grain.phas[:] = 0
+ samples = p.rdo(new_grain)
+ sink_out(samples, read if t == warmup else hop_s)
+
+# just to make sure
+#sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+ len(steps), output_filename))
diff --git a/python/demos/demo_timestretch_online.py b/python/demos/demo_timestretch_online.py
new file mode 100755
index 0000000..e682e8e
--- /dev/null
+++ b/python/demos/demo_timestretch_online.py
@@ -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 performs both analysis and synthesis in a single pass. See also
+# `demo_timestretch.py` for a version following the original implementation.
+
+import sys
+from aubio import source, sink, pvoc, mfcc, cvec
+from aubio import unwrap2pi, float_type
+import numpy as np
+
+win_s = 1024
+hop_s = win_s / 8 # 87.5 % overlap
+
+warmup = win_s // hop_s - 1
+
+if len(sys.argv) < 3:
+ print("Usage: %s <source_filename> <output_filename> <rate> [samplerate]".format(sys.argv[0]))
+ print("""Examples:
+ # twice faster
+ {0} track_01.mp3 track_01_faster.wav 2.0
+ # twice slower
+ {0} track_02.flac track_02_slower.wav 0.5
+ # one and a half time faster, resampling first the input to 22050
+ {0} track_02.flac track_02_slower.wav 1.5 22050""".format(sys.argv[0]))
+ sys.exit(1)
+
+source_filename = sys.argv[1]
+output_filename = sys.argv[2]
+rate = float(sys.argv[3])
+
+samplerate = 0 if len(sys.argv) < 5 else int(sys.argv[4])
+source_in = source(source_filename, samplerate, hop_s)
+samplerate = source_in.samplerate
+p = pvoc(win_s, hop_s)
+
+sink_out = sink(output_filename, samplerate)
+
+# excepted phase advance in each bin
+phi_advance = np.linspace(0, np.pi * hop_s, win_s / 2 + 1).astype (float_type)
+
+old_grain = cvec(win_s)
+new_grain = cvec(win_s)
+
+block_read = 0
+interp_read = 0
+interp_block = 0
+while True:
+
+ samples, read = source_in()
+ cur_grain = p(samples)
+
+ if block_read == 1:
+ phas_acc = old_grain.phas
+
+ #print "block_read", block_read
+ while True and (block_read > 0):
+ if interp_read >= block_read:
+ break
+ #print "`--- interp_block:", interp_block,
+ #print 'at orig_block', interp_read, '<- from', block_read - 1, block_read,
+ #print 'old_grain', old_grain, 'cur_grain', cur_grain
+ # time to compute interp grain
+ frac = 1. - np.mod(interp_read, 1.0)
+
+ # compute interpolated frame
+ new_grain.norm = frac * old_grain.norm + (1. - frac) * cur_grain.norm
+ new_grain.phas = phas_acc
+
+ # psola
+ samples = p.rdo(new_grain)
+ if interp_read > warmup: # skip the first frames to warm up phase vocoder
+ # write to sink
+ sink_out(samples, hop_s)
+
+ # calculate phase advance
+ dphas = cur_grain.phas - old_grain.phas - phi_advance
+ # unwrap angle to [-pi; pi]
+ dphas = unwrap2pi(dphas)
+ # cumulate phase, to be used for next frame
+ phas_acc += phi_advance + dphas
+
+ # prepare for next interp block
+ interp_block += 1
+ interp_read = interp_block * rate
+ if interp_read >= block_read:
+ break
+
+ # copy cur_grain to old_grain
+ old_grain.norm = np.copy(cur_grain.norm)
+ old_grain.phas = np.copy(cur_grain.phas)
+
+ block_read += 1
+ if read < hop_s: break
+
+for t in range(warmup + 2): # purge the last frames from the phase vocoder
+ new_grain.norm[:] = 0
+ new_grain.phas[:] = 0
+ samples = p.rdo(new_grain)
+ sink_out(samples, read if t == warmup + 1 else hop_s)
+
+# just to make sure
+source_in.close()
+sink_out.close()
+
+format_out = "read {:d} blocks from {:s} at {:d}Hz and rate {:f}, wrote {:d} blocks to {:s}"
+print (format_out.format(block_read, source_filename, samplerate, rate,
+ interp_block, output_filename))
diff --git a/python/demos/demo_tss.py b/python/demos/demo_tss.py
new file mode 100755
index 0000000..f8c29aa
--- /dev/null
+++ b/python/demos/demo_tss.py
@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source, sink, pvoc, tss
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print('usage: %s <inputfile> <outputfile_transient> <outputfile_steady>' % sys.argv[0])
+ sys.exit(1)
+
+ samplerate = 44100
+ win_s = 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()
diff --git a/python/demos/demo_waveform_plot.py b/python/demos/demo_waveform_plot.py
new file mode 100755
index 0000000..5434223
--- /dev/null
+++ b/python/demos/demo_waveform_plot.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+
+import sys
+from aubio import source
+from numpy import zeros, hstack
+
+def get_waveform_plot(filename, samplerate = 0, block_size = 4096, ax = None, downsample = 2**4):
+ import matplotlib.pyplot as plt
+ if not ax:
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ hop_s = block_size
+
+ allsamples_max = zeros(0,)
+ downsample = downsample # to plot n samples / hop_s
+
+ a = source(filename, samplerate, hop_s) # source file
+ if samplerate == 0: samplerate = a.samplerate
+
+ total_frames = 0
+ while True:
+ samples, read = a()
+ # keep some data to plot it later
+ 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
+ allsamples_max = (allsamples_max > 0) * allsamples_max
+ allsamples_max_times = [ ( float (t) / downsample ) * hop_s for t in range(len(allsamples_max)) ]
+
+ ax.plot(allsamples_max_times, allsamples_max, '-b')
+ ax.plot(allsamples_max_times, -allsamples_max, '-b')
+ ax.axis(xmin = allsamples_max_times[0], xmax = allsamples_max_times[-1])
+
+ set_xlabels_sample2time(ax, allsamples_max_times[-1], samplerate)
+ return ax
+
+def set_xlabels_sample2time(ax, latest_sample, samplerate):
+ ax.axis(xmin = 0, xmax = latest_sample)
+ if latest_sample / float(samplerate) > 60:
+ ax.set_xlabel('time (mm:ss)')
+ ax.set_xticklabels([ "%02d:%02d" % (t/float(samplerate)/60, (t/float(samplerate))%60) for t in ax.get_xticks()[:-1]], rotation = 50)
+ else:
+ ax.set_xlabel('time (ss.mm)')
+ ax.set_xticklabels([ "%02d.%02d" % (t/float(samplerate), 100*((t/float(samplerate))%1) ) for t in ax.get_xticks()[:-1]], rotation = 50)
+
+
+if __name__ == '__main__':
+ import matplotlib.pyplot as plt
+ if len(sys.argv) < 2:
+ print("Usage: %s <filename>" % sys.argv[0])
+ else:
+ for soundfile in sys.argv[1:]:
+ get_waveform_plot(soundfile)
+ # display graph
+ plt.show()
diff --git a/python/ext/aubio-types.h b/python/ext/aubio-types.h
new file mode 100644
index 0000000..f67b2da
--- /dev/null
+++ b/python/ext/aubio-types.h
@@ -0,0 +1,82 @@
+#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
+#define PY_ARRAY_UNIQUE_SYMBOL PYAUBIO_ARRAY_API
+#define PY_UFUNC_UNIQUE_SYMBOL PYAUBIO_UFUNC_API
+
+// only import array and ufunc from main module
+#ifndef PY_AUBIO_MODULE_MAIN
+#define NO_IMPORT_ARRAY
+#endif
+#include <numpy/arrayobject.h>
+#ifndef PY_AUBIO_MODULE_UFUNC
+#define NO_IMPORT_UFUNC
+#else
+#include <numpy/ufuncobject.h>
+#endif
+
+//#include <numpy/npy_3kcompat.h>
+
+// import aubio
+#define AUBIO_UNSTABLE 1
+#ifdef USE_LOCAL_AUBIO
+#include "aubio.h"
+#else
+#include "aubio/aubio.h"
+#endif
+
+#define Py_default_vector_length 1024
+
+#define Py_aubio_default_samplerate 44100
+
+#if HAVE_AUBIO_DOUBLE
+// 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
+
+// compat with Python < 2.6
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+extern PyTypeObject Py_cvecType;
+
+PyObject * new_py_fvec(uint_t length);
+PyObject * new_py_cvec(uint_t length);
+PyObject * new_py_fmat(uint_t height, uint_t length);
+
+// defined in aubio-proxy.c
+extern int PyAubio_IsValidVector (PyObject *input);
+
+extern PyObject *PyAubio_CFvecToArray (fvec_t * self);
+extern int PyAubio_ArrayToCFvec (PyObject * self, fvec_t *out);
+
+extern int PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i);
+
+extern PyObject *PyAubio_CFmatToArray (fmat_t * self);
+extern int PyAubio_ArrayToCFmat (PyObject *input, fmat_t *out);
+
+// hand written wrappers
+extern PyTypeObject Py_filterType;
+
+extern PyTypeObject Py_filterbankType;
+
+extern PyTypeObject Py_fftType;
+
+extern PyTypeObject Py_pvocType;
+
+extern PyTypeObject Py_sourceType;
+
+extern PyTypeObject Py_sinkType;
diff --git a/python/ext/aubiomodule.c b/python/ext/aubiomodule.c
new file mode 100644
index 0000000..d3f0361
--- /dev/null
+++ b/python/ext/aubiomodule.c
@@ -0,0 +1,333 @@
+#define PY_AUBIO_MODULE_MAIN
+#include "aubio-types.h"
+#include "py-musicutils.h"
+
+static char aubio_module_doc[] = "Python module for the aubio library";
+
+static char Py_alpha_norm_doc[] = ""
+"alpha_norm(fvec, integer) -> float\n"
+"\n"
+"Compute alpha normalisation factor on vector, given alpha\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> b = alpha_norm(a, 9)";
+
+static char Py_bintomidi_doc[] = ""
+"bintomidi(float, samplerate = integer, fftsize = integer) -> float\n"
+"\n"
+"Convert bin (float) to midi (float), given the sampling rate and the FFT size\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> midi = bintomidi(float, samplerate = 44100, fftsize = 1024)";
+
+static char Py_miditobin_doc[] = ""
+"miditobin(float, samplerate = integer, fftsize = integer) -> float\n"
+"\n"
+"Convert midi (float) to bin (float), given the sampling rate and the FFT size\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> bin = miditobin(midi, samplerate = 44100, fftsize = 1024)";
+
+static char Py_bintofreq_doc[] = ""
+"bintofreq(float, samplerate = integer, fftsize = integer) -> float\n"
+"\n"
+"Convert bin number (float) in frequency (Hz), given the sampling rate and the FFT size\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> freq = bintofreq(bin, samplerate = 44100, fftsize = 1024)";
+
+static char Py_freqtobin_doc[] = ""
+"freqtobin(float, samplerate = integer, fftsize = integer) -> float\n"
+"\n"
+"Convert frequency (Hz) in bin number (float), given the sampling rate and the FFT size\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> bin = freqtobin(freq, samplerate = 44100, fftsize = 1024)";
+
+static char Py_zero_crossing_rate_doc[] = ""
+"zero_crossing_rate(fvec) -> float\n"
+"\n"
+"Compute Zero crossing rate of a vector\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> z = zero_crossing_rate(a)";
+
+static char Py_min_removal_doc[] = ""
+"min_removal(fvec) -> float\n"
+"\n"
+"Remove the minimum value of a vector, in-place modification\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> min_removal(a)";
+
+extern void add_generated_objects ( PyObject *m );
+extern void add_ufuncs ( PyObject *m );
+extern int generated_types_ready(void);
+
+static PyObject *
+Py_alpha_norm (PyObject * self, PyObject * args)
+{
+ PyObject *input;
+ fvec_t vec;
+ smpl_t alpha;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":alpha_norm", &input, &alpha)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ // compute the function
+ result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, fvec_alpha_norm (&vec, alpha));
+ if (result == NULL) {
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+Py_bintomidi (PyObject * self, PyObject * args)
+{
+ smpl_t input, samplerate, fftsize;
+ smpl_t output;
+
+ if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+ return NULL;
+ }
+
+ output = aubio_bintomidi (input, samplerate, fftsize);
+
+ return (PyObject *)PyFloat_FromDouble (output);
+}
+
+static PyObject *
+Py_miditobin (PyObject * self, PyObject * args)
+{
+ smpl_t input, samplerate, fftsize;
+ smpl_t output;
+
+ if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+ return NULL;
+ }
+
+ output = aubio_miditobin (input, samplerate, fftsize);
+
+ return (PyObject *)PyFloat_FromDouble (output);
+}
+
+static PyObject *
+Py_bintofreq (PyObject * self, PyObject * args)
+{
+ smpl_t input, samplerate, fftsize;
+ smpl_t output;
+
+ if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+ return NULL;
+ }
+
+ output = aubio_bintofreq (input, samplerate, fftsize);
+
+ return (PyObject *)PyFloat_FromDouble (output);
+}
+
+static PyObject *
+Py_freqtobin (PyObject * self, PyObject * args)
+{
+ smpl_t input, samplerate, fftsize;
+ smpl_t output;
+
+ if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+ return NULL;
+ }
+
+ output = aubio_freqtobin (input, samplerate, fftsize);
+
+ return (PyObject *)PyFloat_FromDouble (output);
+}
+
+static PyObject *
+Py_zero_crossing_rate (PyObject * self, PyObject * args)
+{
+ PyObject *input;
+ fvec_t vec;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple (args, "O:zero_crossing_rate", &input)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ // compute the function
+ result = Py_BuildValue (AUBIO_NPY_SMPL_CHR, aubio_zero_crossing_rate (&vec));
+ if (result == NULL) {
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+Py_min_removal(PyObject * self, PyObject * args)
+{
+ PyObject *input;
+ fvec_t vec;
+
+ if (!PyArg_ParseTuple (args, "O:min_removal", &input)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ // compute the function
+ 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);
+ // or even without converting it back to an array
+ //Py_INCREF(vec);
+ //return (PyObject *)vec;
+}
+
+static PyMethodDef aubio_methods[] = {
+ {"bintomidi", Py_bintomidi, METH_VARARGS, Py_bintomidi_doc},
+ {"miditobin", Py_miditobin, METH_VARARGS, Py_miditobin_doc},
+ {"bintofreq", Py_bintofreq, METH_VARARGS, Py_bintofreq_doc},
+ {"freqtobin", Py_freqtobin, METH_VARARGS, Py_freqtobin_doc},
+ {"alpha_norm", Py_alpha_norm, METH_VARARGS, Py_alpha_norm_doc},
+ {"zero_crossing_rate", Py_zero_crossing_rate, METH_VARARGS, Py_zero_crossing_rate_doc},
+ {"min_removal", Py_min_removal, METH_VARARGS, Py_min_removal_doc},
+ {"level_lin", Py_aubio_level_lin, METH_VARARGS, Py_aubio_level_lin_doc},
+ {"db_spl", Py_aubio_db_spl, METH_VARARGS, Py_aubio_db_spl_doc},
+ {"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, 0, NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+// Python3 module definition
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "_aubio", /* m_name */
+ aubio_module_doc, /* m_doc */
+ -1, /* m_size */
+ aubio_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+#endif
+
+static PyObject *
+initaubio (void)
+{
+ PyObject *m = NULL;
+ int err;
+
+ // fvec is defined in __init__.py
+ if ( (PyType_Ready (&Py_cvecType) < 0)
+ || (PyType_Ready (&Py_filterType) < 0)
+ || (PyType_Ready (&Py_filterbankType) < 0)
+ || (PyType_Ready (&Py_fftType) < 0)
+ || (PyType_Ready (&Py_pvocType) < 0)
+ || (PyType_Ready (&Py_sourceType) < 0)
+ || (PyType_Ready (&Py_sinkType) < 0)
+ // generated objects
+ || (generated_types_ready() < 0 )
+ ) {
+ 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 m;
+ }
+
+ err = _import_array ();
+ if (err != 0) {
+ fprintf (stderr,
+ "Unable to import Numpy array from aubio module (error %d)\n", err);
+ }
+
+ Py_INCREF (&Py_cvecType);
+ PyModule_AddObject (m, "cvec", (PyObject *) & Py_cvecType);
+ Py_INCREF (&Py_filterType);
+ PyModule_AddObject (m, "digital_filter", (PyObject *) & Py_filterType);
+ Py_INCREF (&Py_filterbankType);
+ PyModule_AddObject (m, "filterbank", (PyObject *) & Py_filterbankType);
+ Py_INCREF (&Py_fftType);
+ PyModule_AddObject (m, "fft", (PyObject *) & Py_fftType);
+ Py_INCREF (&Py_pvocType);
+ PyModule_AddObject (m, "pvoc", (PyObject *) & Py_pvocType);
+ Py_INCREF (&Py_sourceType);
+ PyModule_AddObject (m, "source", (PyObject *) & Py_sourceType);
+ Py_INCREF (&Py_sinkType);
+ PyModule_AddObject (m, "sink", (PyObject *) & Py_sinkType);
+
+ PyModule_AddStringConstant(m, "float_type", AUBIO_NPY_SMPL_STR);
+
+ // add generated objects
+ add_generated_objects(m);
+
+ // add ufunc
+ add_ufuncs(m);
+
+ return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+ // Python3 init
+ PyMODINIT_FUNC PyInit__aubio(void)
+ {
+ return initaubio();
+ }
+#else
+ // Python 2 init
+ PyMODINIT_FUNC init_aubio(void)
+ {
+ initaubio();
+ }
+#endif
diff --git a/python/ext/aubioproxy.c b/python/ext/aubioproxy.c
new file mode 100644
index 0000000..f5d7fa4
--- /dev/null
+++ b/python/ext/aubioproxy.c
@@ -0,0 +1,158 @@
+#include "aubio-types.h"
+
+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");
+ return 0;
+ }
+ // parsing input object into a Py_fvec
+ if (PyArray_Check(input)) {
+
+ // we got an array, convert it to an fvec
+ if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
+ PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+ return 0;
+ } else if (PyArray_NDIM ((PyArrayObject *)input) > 1) {
+ PyErr_SetString (PyExc_ValueError,
+ "input array has more than one dimensions");
+ return 0;
+ }
+
+ if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+ PyErr_SetString (PyExc_ValueError, "input array should be float");
+ return 0;
+ } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+ PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+ return 0;
+ }
+
+ length = PyArray_SIZE ((PyArrayObject *)input);
+ if (length <= 0) {
+ PyErr_SetString (PyExc_ValueError, "input array size should be greater than 0");
+ return 0;
+ }
+
+ } else if (PyObject_TypeCheck (input, &PyList_Type)) {
+ PyErr_SetString (PyExc_ValueError, "does not convert from list yet");
+ return 0;
+ } else {
+ PyErr_SetString (PyExc_ValueError, "can only accept vector of float as input");
+ return 0;
+ }
+ return 1;
+}
+
+int
+PyAubio_ArrayToCFvec (PyObject *input, fvec_t *out) {
+
+ 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 *
+PyAubio_CFmatToArray (fmat_t * input)
+{
+ PyObject *array = NULL;
+ uint_t i;
+ npy_intp dims[] = { input->length, 1 };
+ PyObject *concat = PyList_New (0), *tmp = NULL;
+ for (i = 0; i < input->height; i++) {
+ tmp = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->data[i]);
+ PyList_Append (concat, tmp);
+ Py_DECREF (tmp);
+ }
+ array = PyArray_FromObject (concat, AUBIO_NPY_SMPL, 2, 2);
+ Py_DECREF (concat);
+ return array;
+}
+
+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");
+ return 0;
+ }
+ // parsing input object into a Py_fvec
+ if (PyArray_Check(input)) {
+
+ // we got an array, convert it to an fvec
+ if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
+ PyErr_SetString (PyExc_ValueError, "input array is a scalar");
+ return 0;
+ } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
+ PyErr_SetString (PyExc_ValueError,
+ "input array has more than two dimensions");
+ return 0;
+ }
+
+ if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
+ PyErr_SetString (PyExc_ValueError, "input array should be float");
+ return 0;
+ } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
+ PyErr_SetString (PyExc_ValueError, "input array should be " AUBIO_NPY_SMPL_STR);
+ return 0;
+ }
+
+ // no need to really allocate fvec, just its struct member
+ length = PyArray_DIM ((PyArrayObject *)input, 1);
+ if (length <= 0) {
+ PyErr_SetString (PyExc_ValueError, "input array dimension 1 should be greater than 0");
+ return 0;
+ }
+ height = PyArray_DIM ((PyArrayObject *)input, 0);
+ if (height <= 0) {
+ PyErr_SetString (PyExc_ValueError, "input array dimension 0 should be greater than 0");
+ return 0;
+ }
+
+ } else if (PyObject_TypeCheck (input, &PyList_Type)) {
+ PyErr_SetString (PyExc_ValueError, "can not convert list to fmat");
+ return 0;
+ } else {
+ PyErr_SetString (PyExc_ValueError, "can only accept matrix of float as input");
+ return 0;
+ }
+
+ 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);
+ }
+
+ 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/py-cvec.c b/python/ext/py-cvec.c
new file mode 100644
index 0000000..427cc46
--- /dev/null
+++ b/python/ext/py-cvec.c
@@ -0,0 +1,251 @@
+#include "aubio-types.h"
+
+/* cvec type definition
+
+class cvec():
+ 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)
+{
+ int length= 0;
+ Py_cvec *self;
+ static char *kwlist[] = { "length", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+ &length)) {
+ return NULL;
+ }
+
+ self = (Py_cvec *) type->tp_alloc (type, 0);
+
+ self->length = Py_default_vector_length / 2 + 1;
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ if (length > 0) {
+ self->length = length / 2 + 1;
+ } else if (length < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative number of elements");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
+{
+ 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)
+{
+ Py_DECREF(self->norm);
+ Py_DECREF(self->phas);
+ Py_TYPE(self)->tp_free ((PyObject *) self);
+}
+
+static PyObject *
+Py_cvec_repr (Py_cvec * self, PyObject * unused)
+{
+ PyObject *format = NULL;
+ PyObject *args = NULL;
+ PyObject *result = NULL;
+
+ format = PyUnicode_FromString ("aubio cvec of %d elements");
+ if (format == NULL) {
+ goto fail;
+ }
+
+ args = Py_BuildValue ("I", self->length);
+ if (args == NULL) {
+ goto fail;
+ }
+ // hide actual norm / phas content
+
+ result = PyUnicode_Format (format, args);
+
+fail:
+ Py_XDECREF (format);
+ Py_XDECREF (args);
+
+ return result;
+}
+
+PyObject *
+Py_cvec_get_norm (Py_cvec * self, void *closure)
+{
+ // 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)
+{
+ // 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)
+{
+ npy_intp length;
+ if (!PyAubio_IsValidVector(input)) {
+ return 1;
+ }
+ length = PyArray_SIZE ((PyArrayObject *)input);
+ if (length != vec->length) {
+ PyErr_Format (PyExc_ValueError,
+ "input array has length %ld, but cvec has length %d", length,
+ vec->length);
+ return 1;
+ }
+
+ Py_XDECREF(vec->norm);
+ vec->norm = input;
+ Py_INCREF(vec->norm);
+ return 0;
+}
+
+static int
+Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
+{
+ npy_intp length;
+ if (!PyAubio_IsValidVector(input)) {
+ return 1;
+ }
+ length = PyArray_SIZE ((PyArrayObject *)input);
+ if (length != vec->length) {
+ PyErr_Format (PyExc_ValueError,
+ "input array has length %ld, but cvec has length %d", length,
+ vec->length);
+ return 1;
+ }
+
+ Py_XDECREF(vec->phas);
+ vec->phas = input;
+ Py_INCREF(vec->phas);
+ return 0;
+}
+
+static PyMemberDef Py_cvec_members[] = {
+ // TODO remove READONLY flag and define getter/setter
+ {"length", T_INT, offsetof (Py_cvec, length), READONLY,
+ "length attribute"},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef Py_cvec_methods[] = {
+ {NULL}
+};
+
+static PyGetSetDef Py_cvec_getseters[] = {
+ {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm,
+ "Numpy vector of shape (length,) containing the magnitude",
+ NULL},
+ {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas,
+ "Numpy vector of shape (length,) containing the phase",
+ NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject Py_cvecType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "aubio.cvec", /* tp_name */
+ sizeof (Py_cvec), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) Py_cvec_del, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc) Py_cvec_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Py_cvec_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Py_cvec_methods, /* tp_methods */
+ Py_cvec_members, /* tp_members */
+ Py_cvec_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc) Py_cvec_init, /* tp_init */
+ 0, /* tp_alloc */
+ Py_cvec_new, /* tp_new */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-fft.c b/python/ext/py-fft.c
new file mode 100644
index 0000000..7485ea3
--- /dev/null
+++ b/python/ext/py-fft.c
@@ -0,0 +1,199 @@
+#include "aubio-types.h"
+
+static char Py_fft_doc[] = "fft object";
+
+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;
+
+static PyObject *
+Py_fft_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ int win_s = 0;
+ Py_fft *self;
+ static char *kwlist[] = { "win_s", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+ &win_s)) {
+ return NULL;
+ }
+
+ self = (Py_fft *) type->tp_alloc (type, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->win_s = Py_default_vector_length;
+
+ if (win_s > 0) {
+ self->win_s = win_s;
+ } else if (win_s < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative window size");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_fft_init (Py_fft * self, PyObject * args, PyObject * kwds)
+{
+ self->o = new_aubio_fft (self->win_s);
+ if (self->o == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "error creating fft with win_s=%d "
+ "(should be a power of 2 greater than 1; "
+ "try recompiling aubio with --enable-fftw3)",
+ self->win_s);
+ return -1;
+ }
+
+ self->doout = new_py_cvec(self->win_s);
+ self->rdoout = new_py_fvec(self->win_s);
+
+ return 0;
+}
+
+static void
+Py_fft_del (Py_fft *self, PyObject *unused)
+{
+ Py_XDECREF(self->doout);
+ Py_XDECREF(self->rdoout);
+ if (self->o) {
+ del_aubio_fft(self->o);
+ }
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *
+Py_fft_do(Py_fft * self, PyObject * args)
+{
+ PyObject *input;
+ cvec_t c_out;
+
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &(self->vecin))) {
+ return NULL;
+ }
+
+ if (self->vecin.length != self->win_s) {
+ PyErr_Format(PyExc_ValueError,
+ "input array has length %d, but fft expects length %d",
+ self->vecin.length, self->win_s);
+ return NULL;
+ }
+
+ Py_INCREF(self->doout);
+ if (!PyAubio_PyCvecToCCvec(self->doout, &c_out)) {
+ return NULL;
+ }
+ // compute the function
+ aubio_fft_do (self->o, &(self->vecin), &c_out);
+ return self->doout;
+}
+
+static PyMemberDef Py_fft_members[] = {
+ {"win_s", T_INT, offsetof (Py_fft, win_s), READONLY,
+ "size of the window"},
+ {NULL}
+};
+
+static PyObject *
+Py_fft_rdo(Py_fft * self, PyObject * args)
+{
+ PyObject *input;
+ fvec_t out;
+
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) {
+ return NULL;
+ }
+
+ if (self->cvecin.length != self->win_s / 2 + 1) {
+ PyErr_Format(PyExc_ValueError,
+ "input cvec has length %d, but fft expects length %d",
+ self->cvecin.length, self->win_s / 2 + 1);
+ return NULL;
+ }
+
+ Py_INCREF(self->rdoout);
+ if (!PyAubio_ArrayToCFvec(self->rdoout, &out) ) {
+ return NULL;
+ }
+ // compute the function
+ aubio_fft_rdo (self->o, &(self->cvecin), &out);
+ return self->rdoout;
+}
+
+static PyMethodDef Py_fft_methods[] = {
+ {"rdo", (PyCFunction) Py_fft_rdo, METH_VARARGS,
+ "synthesis of spectral grain"},
+ {NULL}
+};
+
+PyTypeObject Py_fftType = {
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.fft",
+ sizeof (Py_fft),
+ 0,
+ (destructor) Py_fft_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_fft_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_fft_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_fft_methods,
+ Py_fft_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_fft_init,
+ 0,
+ Py_fft_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-filter.c b/python/ext/py-filter.c
new file mode 100644
index 0000000..df78e47
--- /dev/null
+++ b/python/ext/py-filter.c
@@ -0,0 +1,215 @@
+#include "aubio-types.h"
+
+typedef struct
+{
+ PyObject_HEAD
+ aubio_filter_t * o;
+ uint_t order;
+ fvec_t vec;
+ PyObject *out;
+ fvec_t c_out;
+} Py_filter;
+
+static char Py_filter_doc[] = "filter object";
+
+static PyObject *
+Py_filter_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ int order= 0;
+ Py_filter *self;
+ static char *kwlist[] = { "order", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
+ &order)) {
+ return NULL;
+ }
+
+ self = (Py_filter *) type->tp_alloc (type, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->order = 7;
+
+ if (order > 0) {
+ self->order = order;
+ } else if (order < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative order");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_filter_init (Py_filter * self, PyObject * args, PyObject * kwds)
+{
+ self->o = new_aubio_filter (self->order);
+ if (self->o == NULL) {
+ return -1;
+ }
+ self->out = NULL;
+ return 0;
+}
+
+static void
+Py_filter_del (Py_filter * self)
+{
+ Py_XDECREF(self->out);
+ del_aubio_filter (self->o);
+ Py_TYPE(self)->tp_free ((PyObject *) self);
+}
+
+static PyObject *
+Py_filter_do(Py_filter * self, PyObject * args)
+{
+ PyObject *input;
+
+ if (!PyArg_ParseTuple (args, "O:digital_filter.do", &input)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &(self->vec))) {
+ return NULL;
+ }
+
+ // initialize output now
+ if (self->out == NULL) {
+ self->out = new_py_fvec(self->vec.length);
+ }
+
+ Py_INCREF(self->out);
+ if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out)) ) {
+ return NULL;
+ }
+ // compute the function
+ aubio_filter_do_outplace (self->o, &(self->vec), &(self->c_out));
+ return self->out;
+}
+
+static PyObject *
+Py_filter_set_c_weighting (Py_filter * self, PyObject *args)
+{
+ uint_t err = 0;
+ uint_t samplerate;
+ if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+ return NULL;
+ }
+
+ err = aubio_filter_set_c_weighting (self->o, samplerate);
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter to C-weighting");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filter_set_a_weighting (Py_filter * self, PyObject *args)
+{
+ uint_t err = 0;
+ uint_t samplerate;
+ if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+ return NULL;
+ }
+
+ err = aubio_filter_set_a_weighting (self->o, samplerate);
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter to A-weighting");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filter_set_biquad(Py_filter * self, PyObject *args)
+{
+ uint_t err = 0;
+ lsmp_t b0, b1, b2, a1, a2;
+ if (!PyArg_ParseTuple (args, "ddddd", &b0, &b1, &b2, &a1, &a2)) {
+ return NULL;
+ }
+
+ err = aubio_filter_set_biquad (self->o, b0, b1, b2, a1, a2);
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter with biquad coefficients");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef Py_filter_members[] = {
+ // TODO remove READONLY flag and define getter/setter
+ {"order", T_INT, offsetof (Py_filter, order), READONLY,
+ "order of the filter"},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef Py_filter_methods[] = {
+ {"set_c_weighting", (PyCFunction) Py_filter_set_c_weighting, METH_VARARGS,
+ "set filter coefficients to C-weighting"},
+ {"set_a_weighting", (PyCFunction) Py_filter_set_a_weighting, METH_VARARGS,
+ "set filter coefficients to A-weighting"},
+ {"set_biquad", (PyCFunction) Py_filter_set_biquad, METH_VARARGS,
+ "set b0, b1, b2, a1, a2 biquad coefficients"},
+ {NULL}
+};
+
+PyTypeObject Py_filterType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "aubio.digital_filter", /* tp_name */
+ sizeof (Py_filter), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) Py_filter_del, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, //(reprfunc) Py_filter_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)Py_filter_do, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Py_filter_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Py_filter_methods, /* tp_methods */
+ Py_filter_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc) Py_filter_init, /* tp_init */
+ 0, /* tp_alloc */
+ Py_filter_new, /* tp_new */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-filterbank.c b/python/ext/py-filterbank.c
new file mode 100644
index 0000000..a4e0ea6
--- /dev/null
+++ b/python/ext/py-filterbank.c
@@ -0,0 +1,258 @@
+#include "aubio-types.h"
+
+static char Py_filterbank_doc[] = "filterbank object";
+
+typedef struct
+{
+ PyObject_HEAD
+ aubio_filterbank_t * o;
+ uint_t n_filters;
+ uint_t win_s;
+ cvec_t vec;
+ fvec_t freqs;
+ fmat_t coeffs;
+ PyObject *out;
+ fvec_t c_out;
+} Py_filterbank;
+
+static PyObject *
+Py_filterbank_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ int win_s = 0, n_filters = 0;
+ Py_filterbank *self;
+ static char *kwlist[] = { "n_filters", "win_s", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
+ &n_filters, &win_s)) {
+ return NULL;
+ }
+
+ self = (Py_filterbank *) type->tp_alloc (type, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->win_s = Py_default_vector_length;
+ if (win_s > 0) {
+ self->win_s = win_s;
+ } else if (win_s < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative window size");
+ return NULL;
+ }
+
+ self->n_filters = 40;
+ if (n_filters > 0) {
+ self->n_filters = n_filters;
+ } else if (n_filters < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative number of filters");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_filterbank_init (Py_filterbank * self, PyObject * args, PyObject * kwds)
+{
+ self->o = new_aubio_filterbank (self->n_filters, self->win_s);
+ if (self->o == NULL) {
+ PyErr_Format(PyExc_RuntimeError, "error creating filterbank with"
+ " n_filters=%d, win_s=%d", self->n_filters, self->win_s);
+ return -1;
+ }
+ self->out = new_py_fvec(self->n_filters);
+
+ return 0;
+}
+
+static void
+Py_filterbank_del (Py_filterbank *self, PyObject *unused)
+{
+ if (self->o) {
+ free(self->coeffs.data);
+ del_aubio_filterbank(self->o);
+ }
+ Py_XDECREF(self->out);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static PyObject *
+Py_filterbank_do(Py_filterbank * self, PyObject * args)
+{
+ PyObject *input;
+
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_PyCvecToCCvec(input, &(self->vec) )) {
+ return NULL;
+ }
+
+ if (self->vec.length != self->win_s / 2 + 1) {
+ PyErr_Format(PyExc_ValueError,
+ "input cvec has length %d, but fft expects length %d",
+ self->vec.length, self->win_s / 2 + 1);
+ return NULL;
+ }
+
+ Py_INCREF(self->out);
+ if (!PyAubio_ArrayToCFvec(self->out, &(self->c_out))) {
+ return NULL;
+ }
+ // compute the function
+ aubio_filterbank_do (self->o, &(self->vec), &(self->c_out));
+ return self->out;
+}
+
+static PyMemberDef Py_filterbank_members[] = {
+ {"win_s", T_INT, offsetof (Py_filterbank, win_s), READONLY,
+ "size of the window"},
+ {"n_filters", T_INT, offsetof (Py_filterbank, n_filters), READONLY,
+ "number of filters"},
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+Py_filterbank_set_triangle_bands (Py_filterbank * self, PyObject *args)
+{
+ uint_t err = 0;
+
+ PyObject *input;
+ uint_t samplerate;
+ if (!PyArg_ParseTuple (args, "OI", &input, &samplerate)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &(self->freqs) )) {
+ return NULL;
+ }
+
+ err = aubio_filterbank_set_triangle_bands (self->o,
+ &(self->freqs), samplerate);
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter to A-weighting");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filterbank_set_mel_coeffs_slaney (Py_filterbank * self, PyObject *args)
+{
+ uint_t err = 0;
+
+ uint_t samplerate;
+ if (!PyArg_ParseTuple (args, "I", &samplerate)) {
+ return NULL;
+ }
+
+ err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter to A-weighting");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filterbank_set_coeffs (Py_filterbank * self, PyObject *args)
+{
+ uint_t err = 0;
+
+ PyObject *input;
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFmat(input, &(self->coeffs))) {
+ return NULL;
+ }
+
+ err = aubio_filterbank_set_coeffs (self->o, &(self->coeffs));
+
+ if (err > 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when setting filter coefficients");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Py_filterbank_get_coeffs (Py_filterbank * self, PyObject *unused)
+{
+ return (PyObject *)PyAubio_CFmatToArray(
+ aubio_filterbank_get_coeffs (self->o) );
+}
+
+static PyMethodDef Py_filterbank_methods[] = {
+ {"set_triangle_bands", (PyCFunction) Py_filterbank_set_triangle_bands,
+ METH_VARARGS, "set coefficients of filterbanks"},
+ {"set_mel_coeffs_slaney", (PyCFunction) Py_filterbank_set_mel_coeffs_slaney,
+ METH_VARARGS, "set coefficients of filterbank as in Auditory Toolbox"},
+ {"get_coeffs", (PyCFunction) Py_filterbank_get_coeffs,
+ METH_NOARGS, "get coefficients of filterbank"},
+ {"set_coeffs", (PyCFunction) Py_filterbank_set_coeffs,
+ METH_VARARGS, "set coefficients of filterbank"},
+ {NULL}
+};
+
+PyTypeObject Py_filterbankType = {
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.filterbank",
+ sizeof (Py_filterbank),
+ 0,
+ (destructor) Py_filterbank_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_filterbank_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_filterbank_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_filterbank_methods,
+ Py_filterbank_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_filterbank_init,
+ 0,
+ Py_filterbank_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-musicutils.c b/python/ext/py-musicutils.c
new file mode 100644
index 0000000..3078e07
--- /dev/null
+++ b/python/ext/py-musicutils.c
@@ -0,0 +1,135 @@
+#include "aubio-types.h"
+
+PyObject *
+Py_aubio_window(PyObject *self, PyObject *args)
+{
+ char_t *wintype = NULL;
+ uint_t winlen = 0;
+ fvec_t *window = NULL;
+
+ if (!PyArg_ParseTuple (args, "|sI", &wintype, &winlen)) {
+ return NULL;
+ }
+
+ window = new_aubio_window(wintype, winlen);
+ if (window == NULL) {
+ PyErr_SetString (PyExc_ValueError, "failed computing window");
+ return NULL;
+ }
+
+ return (PyObject *) PyAubio_CFvecToArray(window);
+}
+
+PyObject *
+Py_aubio_level_lin(PyObject *self, PyObject *args)
+{
+ PyObject *input;
+ fvec_t vec;
+ PyObject *level_lin;
+
+ if (!PyArg_ParseTuple (args, "O:level_lin", &input)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ level_lin = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_level_lin(&vec));
+ if (level_lin == NULL) {
+ PyErr_SetString (PyExc_ValueError, "failed computing level_lin");
+ return NULL;
+ }
+
+ return level_lin;
+}
+
+PyObject *
+Py_aubio_db_spl(PyObject *self, PyObject *args)
+{
+ PyObject *input;
+ fvec_t vec;
+ PyObject *db_spl;
+
+ if (!PyArg_ParseTuple (args, "O:db_spl", &input)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ db_spl = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_db_spl(&vec));
+ if (db_spl == NULL) {
+ PyErr_SetString (PyExc_ValueError, "failed computing db_spl");
+ return NULL;
+ }
+
+ return db_spl;
+}
+
+PyObject *
+Py_aubio_silence_detection(PyObject *self, PyObject *args)
+{
+ PyObject *input;
+ fvec_t vec;
+ PyObject *silence_detection;
+ smpl_t threshold;
+
+ if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":silence_detection", &input, &threshold)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ silence_detection = Py_BuildValue("I", aubio_silence_detection(&vec, threshold));
+ if (silence_detection == NULL) {
+ PyErr_SetString (PyExc_ValueError, "failed computing silence_detection");
+ return NULL;
+ }
+
+ return silence_detection;
+}
+
+PyObject *
+Py_aubio_level_detection(PyObject *self, PyObject *args)
+{
+ PyObject *input;
+ fvec_t vec;
+ PyObject *level_detection;
+ smpl_t threshold;
+
+ if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR ":level_detection", &input, &threshold)) {
+ return NULL;
+ }
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec(input, &vec)) {
+ return NULL;
+ }
+
+ level_detection = Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_level_detection(&vec, threshold));
+ if (level_detection == NULL) {
+ PyErr_SetString (PyExc_ValueError, "failed computing level_detection");
+ return NULL;
+ }
+
+ return level_detection;
+}
diff --git a/python/ext/py-musicutils.h b/python/ext/py-musicutils.h
new file mode 100644
index 0000000..54ee230
--- /dev/null
+++ b/python/ext/py-musicutils.h
@@ -0,0 +1,74 @@
+#ifndef PY_AUBIO_MUSICUTILS_H
+#define PY_AUBIO_MUSICUTILS_H
+
+static char Py_aubio_window_doc[] = ""
+"window(string, integer) -> fvec\n"
+"\n"
+"Create a window\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> window('hanningz', 1024)\n"
+"array([ 0.00000000e+00, 9.41753387e-06, 3.76403332e-05, ...,\n"
+" 8.46982002e-05, 3.76403332e-05, 9.41753387e-06], dtype=float32)";
+
+PyObject * Py_aubio_window(PyObject *self, PyObject *args);
+
+static char Py_aubio_level_lin_doc[] = ""
+"level_lin(fvec) -> fvec\n"
+"\n"
+"Compute sound level on a linear scale.\n"
+"\n"
+"This gives the average of the square amplitudes.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> level_Lin(numpy.ones(1024))\n"
+"1.0";
+
+PyObject * Py_aubio_level_lin(PyObject *self, PyObject *args);
+
+static char Py_aubio_db_spl_doc[] = ""
+"Compute sound pressure level (SPL) in dB\n"
+"\n"
+"This quantity is often wrongly called 'loudness'.\n"
+"\n"
+"This gives ten times the log10 of the average of the square amplitudes.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> db_spl(numpy.ones(1024))\n"
+"1.0";
+
+PyObject * Py_aubio_db_spl(PyObject *self, PyObject *args);
+
+static char Py_aubio_silence_detection_doc[] = ""
+"Check if buffer level in dB SPL is under a given threshold\n"
+"\n"
+"Return 0 if level is under the given threshold, 1 otherwise.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> import numpy\n"""
+">>> silence_detection(numpy.ones(1024, dtype=\"float32\"), -80)\n"
+"0";
+
+PyObject * Py_aubio_silence_detection(PyObject *self, PyObject *args);
+
+static char Py_aubio_level_detection_doc[] = ""
+"Get buffer level in dB SPL if over a given threshold, 1. otherwise.\n"
+"\n"
+"Example\n"
+"-------\n"
+"\n"
+">>> import numpy\n"""
+">>> level_detection(0.7*numpy.ones(1024, dtype=\"float32\"), -80)\n"
+"0";
+
+PyObject * Py_aubio_level_detection(PyObject *self, PyObject *args);
+
+#endif /* PY_AUBIO_MUSICUTILS_H */
diff --git a/python/ext/py-phasevoc.c b/python/ext/py-phasevoc.c
new file mode 100644
index 0000000..bcd3d8b
--- /dev/null
+++ b/python/ext/py-phasevoc.c
@@ -0,0 +1,213 @@
+#include "aubio-types.h"
+
+static char Py_pvoc_doc[] = "pvoc object";
+
+typedef struct
+{
+ PyObject_HEAD
+ aubio_pvoc_t * o;
+ uint_t win_s;
+ uint_t hop_s;
+ fvec_t vecin;
+ cvec_t cvecin;
+ PyObject *output;
+ cvec_t c_output;
+ PyObject *routput;
+ fvec_t c_routput;
+} Py_pvoc;
+
+
+static PyObject *
+Py_pvoc_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ int win_s = 0, hop_s = 0;
+ Py_pvoc *self;
+ static char *kwlist[] = { "win_s", "hop_s", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|II", kwlist,
+ &win_s, &hop_s)) {
+ return NULL;
+ }
+
+ self = (Py_pvoc *) type->tp_alloc (type, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->win_s = Py_default_vector_length;
+ self->hop_s = Py_default_vector_length/2;
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ if (win_s > 0) {
+ self->win_s = win_s;
+ } else if (win_s < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative window size");
+ return NULL;
+ }
+
+ if (hop_s > 0) {
+ self->hop_s = hop_s;
+ } else if (hop_s < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative hop size");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_pvoc_init (Py_pvoc * self, PyObject * args, PyObject * kwds)
+{
+ self->o = new_aubio_pvoc ( self->win_s, self->hop_s);
+ if (self->o == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "failed creating pvoc with win_s=%d, hop_s=%d",
+ self->win_s, self->hop_s);
+ return -1;
+ }
+
+ self->output = new_py_cvec(self->win_s);
+ self->routput = new_py_fvec(self->hop_s);
+
+ return 0;
+}
+
+
+static void
+Py_pvoc_del (Py_pvoc *self, PyObject *unused)
+{
+ Py_XDECREF(self->output);
+ Py_XDECREF(self->routput);
+ if (self->o) {
+ del_aubio_pvoc(self->o);
+ }
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+
+static PyObject *
+Py_pvoc_do(Py_pvoc * self, PyObject * args)
+{
+ PyObject *input;
+
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_ArrayToCFvec (input, &(self->vecin) )) {
+ return NULL;
+ }
+
+ if (self->vecin.length != self->hop_s) {
+ PyErr_Format(PyExc_ValueError,
+ "input fvec has length %d, but pvoc expects length %d",
+ self->vecin.length, self->hop_s);
+ return NULL;
+ }
+
+ Py_INCREF(self->output);
+ if (!PyAubio_PyCvecToCCvec (self->output, &(self->c_output))) {
+ return NULL;
+ }
+ // compute the function
+ aubio_pvoc_do (self->o, &(self->vecin), &(self->c_output));
+ return self->output;
+}
+
+static PyMemberDef Py_pvoc_members[] = {
+ {"win_s", T_INT, offsetof (Py_pvoc, win_s), READONLY,
+ "size of the window"},
+ {"hop_s", T_INT, offsetof (Py_pvoc, hop_s), READONLY,
+ "size of the hop"},
+ { NULL } // sentinel
+};
+
+static PyObject *
+Py_pvoc_rdo(Py_pvoc * self, PyObject * args)
+{
+ PyObject *input;
+ if (!PyArg_ParseTuple (args, "O", &input)) {
+ return NULL;
+ }
+
+ if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin) )) {
+ return NULL;
+ }
+
+ if (self->cvecin.length != self->win_s / 2 + 1) {
+ PyErr_Format(PyExc_ValueError,
+ "input cvec has length %d, but pvoc expects length %d",
+ self->cvecin.length, self->win_s / 2 + 1);
+ return NULL;
+ }
+
+ Py_INCREF(self->routput);
+ if (!PyAubio_ArrayToCFvec(self->routput, &(self->c_routput)) ) {
+ return NULL;
+ }
+ // compute the function
+ aubio_pvoc_rdo (self->o, &(self->cvecin), &(self->c_routput));
+ return self->routput;
+}
+
+static PyMethodDef Py_pvoc_methods[] = {
+ {"rdo", (PyCFunction) Py_pvoc_rdo, METH_VARARGS,
+ "synthesis of spectral grain"},
+ {NULL}
+};
+
+PyTypeObject Py_pvocType = {
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.pvoc",
+ sizeof (Py_pvoc),
+ 0,
+ (destructor) Py_pvoc_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_pvoc_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_pvoc_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_pvoc_methods,
+ Py_pvoc_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_pvoc_init,
+ 0,
+ Py_pvoc_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-sink.c b/python/ext/py-sink.c
new file mode 100644
index 0000000..9fada06
--- /dev/null
+++ b/python/ext/py-sink.c
@@ -0,0 +1,262 @@
+#include "aubio-types.h"
+
+typedef struct
+{
+ PyObject_HEAD
+ aubio_sink_t * o;
+ char_t* uri;
+ uint_t samplerate;
+ uint_t channels;
+ fvec_t write_data;
+ fmat_t mwrite_data;
+} Py_sink;
+
+static char Py_sink_doc[] = ""
+" __new__(path, samplerate = 44100, channels = 1)\n"
+"\n"
+" Create a new sink, opening the given path for writing.\n"
+"\n"
+" Examples\n"
+" --------\n"
+"\n"
+" Create a new sink at 44100Hz, mono:\n"
+"\n"
+" >>> sink('/tmp/t.wav')\n"
+"\n"
+" Create a new sink at 8000Hz, mono:\n"
+"\n"
+" >>> sink('/tmp/t.wav', samplerate = 8000)\n"
+"\n"
+" Create a new sink at 32000Hz, stereo:\n"
+"\n"
+" >>> sink('/tmp/t.wav', samplerate = 32000, channels = 2)\n"
+"\n"
+" Create a new sink at 32000Hz, 5 channels:\n"
+"\n"
+" >>> sink('/tmp/t.wav', channels = 5, samplerate = 32000)\n"
+"\n"
+" __call__(vec, write)\n"
+" x(vec,write) <==> x.do(vec, write)\n"
+"\n"
+" Write vector to sink.\n"
+"\n"
+" See also\n"
+" --------\n"
+" aubio.sink.do\n"
+"\n";
+
+static char Py_sink_do_doc[] = ""
+"x.do(vec, write) <==> x(vec, write)\n"
+"\n"
+"write monophonic vector to sink";
+
+static char Py_sink_do_multi_doc[] = ""
+"x.do_multi(mat, write)\n"
+"\n"
+"write polyphonic vector to sink";
+
+static char Py_sink_close_doc[] = ""
+"x.close()\n"
+"\n"
+"close this sink now";
+
+static PyObject *
+Py_sink_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
+{
+ Py_sink *self;
+ char_t* uri = NULL;
+ uint_t samplerate = 0;
+ uint_t channels = 0;
+ static char *kwlist[] = { "uri", "samplerate", "channels", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|sII", kwlist,
+ &uri, &samplerate, &channels)) {
+ return NULL;
+ }
+
+ self = (Py_sink *) pytype->tp_alloc (pytype, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->uri = "none";
+ if (uri != NULL) {
+ self->uri = uri;
+ }
+
+ self->samplerate = Py_aubio_default_samplerate;
+ if ((sint_t)samplerate > 0) {
+ self->samplerate = samplerate;
+ } else if ((sint_t)samplerate < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative value for samplerate");
+ return NULL;
+ }
+
+ self->channels = 1;
+ if ((sint_t)channels > 0) {
+ self->channels = channels;
+ } else if ((sint_t)channels < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative or null value for channels");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_sink_init (Py_sink * self, PyObject * args, PyObject * kwds)
+{
+ if (self->channels == 1) {
+ self->o = new_aubio_sink ( self->uri, self->samplerate );
+ } else {
+ self->o = new_aubio_sink ( self->uri, 0 );
+ aubio_sink_preset_channels ( self->o, self->channels );
+ aubio_sink_preset_samplerate ( self->o, self->samplerate );
+ }
+ if (self->o == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, "error creating sink with this uri");
+ return -1;
+ }
+ self->samplerate = aubio_sink_get_samplerate ( self->o );
+ self->channels = aubio_sink_get_channels ( self->o );
+
+ return 0;
+}
+
+static void
+Py_sink_del (Py_sink *self, PyObject *unused)
+{
+ del_aubio_sink(self->o);
+ free(self->mwrite_data.data);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+/* function Py_sink_do */
+static PyObject *
+Py_sink_do(Py_sink * self, PyObject * args)
+{
+ /* input vectors python prototypes */
+ PyObject * write_data_obj;
+
+ /* input vectors prototypes */
+ uint_t write;
+
+
+ if (!PyArg_ParseTuple (args, "OI", &write_data_obj, &write)) {
+ return NULL;
+ }
+
+ /* input vectors parsing */
+ if (!PyAubio_ArrayToCFvec(write_data_obj, &(self->write_data))) {
+ return NULL;
+ }
+
+
+ /* compute _do function */
+ aubio_sink_do (self->o, &(self->write_data), write);
+
+ Py_RETURN_NONE;
+}
+
+/* function Py_sink_do_multi */
+static PyObject *
+Py_sink_do_multi(Py_sink * self, PyObject * args)
+{
+ /* input vectors python prototypes */
+ PyObject * write_data_obj;
+
+ /* input vectors prototypes */
+ uint_t write;
+
+
+ if (!PyArg_ParseTuple (args, "OI", &write_data_obj, &write)) {
+ return NULL;
+ }
+
+
+ /* input vectors parsing */
+ if (!PyAubio_ArrayToCFmat(write_data_obj, &(self->mwrite_data))) {
+ return NULL;
+ }
+
+ /* compute _do function */
+ aubio_sink_do_multi (self->o, &(self->mwrite_data), write);
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef Py_sink_members[] = {
+ {"uri", T_STRING, offsetof (Py_sink, uri), READONLY,
+ "path at which the sink was created"},
+ {"samplerate", T_INT, offsetof (Py_sink, samplerate), READONLY,
+ "samplerate at which the sink was created"},
+ {"channels", T_INT, offsetof (Py_sink, channels), READONLY,
+ "number of channels with which the sink was created"},
+ { NULL } // sentinel
+};
+
+static PyObject *
+Pyaubio_sink_close (Py_sink *self, PyObject *unused)
+{
+ aubio_sink_close (self->o);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef Py_sink_methods[] = {
+ {"do", (PyCFunction) Py_sink_do, METH_VARARGS, Py_sink_do_doc},
+ {"do_multi", (PyCFunction) Py_sink_do_multi, METH_VARARGS, Py_sink_do_multi_doc},
+ {"close", (PyCFunction) Pyaubio_sink_close, METH_NOARGS, Py_sink_close_doc},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject Py_sinkType = {
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.sink",
+ sizeof (Py_sink),
+ 0,
+ (destructor) Py_sink_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_sink_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_sink_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_sink_methods,
+ Py_sink_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_sink_init,
+ 0,
+ Py_sink_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/py-source.c b/python/ext/py-source.c
new file mode 100644
index 0000000..8280868
--- /dev/null
+++ b/python/ext/py-source.c
@@ -0,0 +1,339 @@
+#include "aubio-types.h"
+
+typedef struct
+{
+ PyObject_HEAD
+ aubio_source_t * o;
+ char_t* uri;
+ uint_t samplerate;
+ uint_t channels;
+ uint_t hop_size;
+ uint_t duration;
+ PyObject *read_to;
+ fvec_t c_read_to;
+ PyObject *mread_to;
+ fmat_t c_mread_to;
+} Py_source;
+
+static char Py_source_doc[] = ""
+" __new__(path, samplerate = 0, hop_size = 512, channels = 1)\n"
+"\n"
+" Create a new source, opening the given path for reading.\n"
+"\n"
+" Examples\n"
+" --------\n"
+"\n"
+" Create a new source, using the original samplerate, with hop_size = 512:\n"
+"\n"
+" >>> source('/tmp/t.wav')\n"
+"\n"
+" Create a new source, resampling the original to 8000Hz:\n"
+"\n"
+" >>> source('/tmp/t.wav', samplerate = 8000)\n"
+"\n"
+" Create a new source, resampling it at 32000Hz, hop_size = 32:\n"
+"\n"
+" >>> source('/tmp/t.wav', samplerate = 32000, hop_size = 32)\n"
+"\n"
+" Create a new source, using its original samplerate:\n"
+"\n"
+" >>> source('/tmp/t.wav', samplerate = 0)\n"
+"\n"
+" __call__()\n"
+" vec, read = x() <==> vec, read = x.do()\n"
+"\n"
+" Read vector from source.\n"
+"\n"
+" See also\n"
+" --------\n"
+" aubio.source.do\n"
+"\n";
+
+static char Py_source_get_samplerate_doc[] = ""
+"x.get_samplerate() -> source samplerate\n"
+"\n"
+"Get samplerate of source.";
+
+static char Py_source_get_channels_doc[] = ""
+"x.get_channels() -> number of channels\n"
+"\n"
+"Get number of channels in source.";
+
+static char Py_source_do_doc[] = ""
+"vec, read = x.do() <==> vec, read = x()\n"
+"\n"
+"Read monophonic vector from source.";
+
+static char Py_source_do_multi_doc[] = ""
+"mat, read = x.do_multi()\n"
+"\n"
+"Read polyphonic vector from source.";
+
+static char Py_source_close_doc[] = ""
+"x.close()\n"
+"\n"
+"Close this source now.";
+
+static char Py_source_seek_doc[] = ""
+"x.seek(position)\n"
+"\n"
+"Seek to resampled frame position.";
+
+static PyObject *
+Py_source_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
+{
+ Py_source *self;
+ char_t* uri = NULL;
+ uint_t samplerate = 0;
+ uint_t hop_size = 0;
+ uint_t channels = 0;
+ static char *kwlist[] = { "uri", "samplerate", "hop_size", "channels", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|sIII", kwlist,
+ &uri, &samplerate, &hop_size, &channels)) {
+ return NULL;
+ }
+
+ self = (Py_source *) pytype->tp_alloc (pytype, 0);
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->uri = "none";
+ if (uri != NULL) {
+ self->uri = uri;
+ }
+
+ self->samplerate = 0;
+ if ((sint_t)samplerate > 0) {
+ self->samplerate = samplerate;
+ } else if ((sint_t)samplerate < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative value for samplerate");
+ return NULL;
+ }
+
+ self->hop_size = Py_default_vector_length / 2;
+ if ((sint_t)hop_size > 0) {
+ self->hop_size = hop_size;
+ } else if ((sint_t)hop_size < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative value for hop_size");
+ return NULL;
+ }
+
+ self->channels = 1;
+ if ((sint_t)channels >= 0) {
+ self->channels = channels;
+ } else if ((sint_t)channels < 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "can not use negative value for channels");
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static int
+Py_source_init (Py_source * self, PyObject * args, PyObject * kwds)
+{
+ self->o = new_aubio_source ( self->uri, self->samplerate, self->hop_size );
+ if (self->o == NULL) {
+ PyErr_Format (PyExc_RuntimeError, "error creating source with \"%s\"",
+ self->uri);
+ return -1;
+ }
+ self->samplerate = aubio_source_get_samplerate ( self->o );
+ if (self->channels == 0) {
+ self->channels = aubio_source_get_channels ( self->o );
+ }
+ self->duration = aubio_source_get_duration ( self->o );
+
+ self->read_to = new_py_fvec(self->hop_size);
+ self->mread_to = new_py_fmat(self->channels, self->hop_size);
+
+ return 0;
+}
+
+static void
+Py_source_del (Py_source *self, PyObject *unused)
+{
+ if (self->o) {
+ del_aubio_source(self->o);
+ free(self->c_mread_to.data);
+ }
+ Py_XDECREF(self->read_to);
+ Py_XDECREF(self->mread_to);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+
+/* function Py_source_do */
+static PyObject *
+Py_source_do(Py_source * self, PyObject * args)
+{
+ PyObject *outputs;
+ uint_t read;
+ read = 0;
+
+ Py_INCREF(self->read_to);
+ if (!PyAubio_ArrayToCFvec(self->read_to, &(self->c_read_to))) {
+ return NULL;
+ }
+ /* compute _do function */
+ aubio_source_do (self->o, &(self->c_read_to), &read);
+
+ outputs = PyTuple_New(2);
+ PyTuple_SetItem( outputs, 0, self->read_to );
+ PyTuple_SetItem( outputs, 1, (PyObject *)PyLong_FromLong(read));
+ return outputs;
+}
+
+/* function Py_source_do_multi */
+static PyObject *
+Py_source_do_multi(Py_source * self, PyObject * args)
+{
+ PyObject *outputs;
+ uint_t read;
+ read = 0;
+
+ Py_INCREF(self->mread_to);
+ if (!PyAubio_ArrayToCFmat(self->mread_to, &(self->c_mread_to))) {
+ return NULL;
+ }
+ /* compute _do function */
+ aubio_source_do_multi (self->o, &(self->c_mread_to), &read);
+
+ outputs = PyTuple_New(2);
+ PyTuple_SetItem( outputs, 0, self->mread_to);
+ PyTuple_SetItem( outputs, 1, (PyObject *)PyLong_FromLong(read));
+ return outputs;
+}
+
+static PyMemberDef Py_source_members[] = {
+ {"uri", T_STRING, offsetof (Py_source, uri), READONLY,
+ "path at which the source was created"},
+ {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY,
+ "samplerate at which the source is viewed"},
+ {"channels", T_INT, offsetof (Py_source, channels), READONLY,
+ "number of channels found in the source"},
+ {"hop_size", T_INT, offsetof (Py_source, hop_size), READONLY,
+ "number of consecutive frames that will be read at each do or do_multi call"},
+ {"duration", T_INT, offsetof (Py_source, duration), READONLY,
+ "total number of frames in the source (estimated)"},
+ { NULL } // sentinel
+};
+
+static PyObject *
+Pyaubio_source_get_samplerate (Py_source *self, PyObject *unused)
+{
+ uint_t tmp = aubio_source_get_samplerate (self->o);
+ return (PyObject *)PyLong_FromLong (tmp);
+}
+
+static PyObject *
+Pyaubio_source_get_channels (Py_source *self, PyObject *unused)
+{
+ uint_t tmp = aubio_source_get_channels (self->o);
+ return (PyObject *)PyLong_FromLong (tmp);
+}
+
+static PyObject *
+Pyaubio_source_close (Py_source *self, PyObject *unused)
+{
+ aubio_source_close (self->o);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+Pyaubio_source_seek (Py_source *self, PyObject *args)
+{
+ uint_t err = 0;
+
+ int position;
+ if (!PyArg_ParseTuple (args, "I", &position)) {
+ return NULL;
+ }
+
+ if (position < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "error when seeking in source: can not seek to negative value %d",
+ position);
+ return NULL;
+ }
+
+ err = aubio_source_seek(self->o, position);
+ if (err != 0) {
+ PyErr_SetString (PyExc_ValueError,
+ "error when seeking in source");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef Py_source_methods[] = {
+ {"get_samplerate", (PyCFunction) Pyaubio_source_get_samplerate,
+ METH_NOARGS, Py_source_get_samplerate_doc},
+ {"get_channels", (PyCFunction) Pyaubio_source_get_channels,
+ METH_NOARGS, Py_source_get_channels_doc},
+ {"do", (PyCFunction) Py_source_do,
+ METH_NOARGS, Py_source_do_doc},
+ {"do_multi", (PyCFunction) Py_source_do_multi,
+ METH_NOARGS, Py_source_do_multi_doc},
+ {"close", (PyCFunction) Pyaubio_source_close,
+ METH_NOARGS, Py_source_close_doc},
+ {"seek", (PyCFunction) Pyaubio_source_seek,
+ METH_VARARGS, Py_source_seek_doc},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject Py_sourceType = {
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.source",
+ sizeof (Py_source),
+ 0,
+ (destructor) Py_source_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_source_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_source_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_source_methods,
+ Py_source_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_source_init,
+ 0,
+ Py_source_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/python/ext/ufuncs.c b/python/ext/ufuncs.c
new file mode 100644
index 0000000..8a4e917
--- /dev/null
+++ b/python/ext/ufuncs.c
@@ -0,0 +1,114 @@
+#define PY_AUBIO_MODULE_UFUNC
+#include "aubio-types.h"
+
+typedef smpl_t (*aubio_unary_func_t)(smpl_t input);
+
+static void aubio_PyUFunc_d_d(char **args, npy_intp *dimensions,
+ npy_intp* steps, void* data)
+{
+ npy_intp i;
+ npy_intp n = dimensions[0];
+ char *in = args[0], *out = args[1];
+ npy_intp in_step = steps[0], out_step = steps[1];
+ aubio_unary_func_t func = (aubio_unary_func_t)(data);
+
+ for (i = 0; i < n; i++) {
+ /*BEGIN main ufunc computation*/
+ *((double *)out) = func(*(double *)in);
+ /*END main ufunc computation*/
+
+ in += in_step;
+ out += out_step;
+ }
+}
+
+static void aubio_PyUFunc_f_f_As_d_d(char **args, npy_intp *dimensions,
+ npy_intp* steps, void* data)
+{
+ npy_intp i;
+ npy_intp n = dimensions[0];
+ char *in = args[0], *out = args[1];
+ npy_intp in_step = steps[0], out_step = steps[1];
+ aubio_unary_func_t func = (aubio_unary_func_t)(data);
+
+ for (i = 0; i < n; i++) {
+ /*BEGIN main ufunc computation*/
+ *((float *)out) = func(*(float *)in);
+ /*END main ufunc computation*/
+
+ in += in_step;
+ out += out_step;
+ }
+}
+
+static int Py_aubio_unary_n_types = 2;
+static int Py_aubio_unary_n_inputs = 1;
+static int Py_aubio_unary_n_outputs = 1;
+PyUFuncGenericFunction Py_aubio_unary_functions[] = {
+ &aubio_PyUFunc_f_f_As_d_d,
+ &aubio_PyUFunc_d_d,
+ //PyUFunc_f_f_As_d_d, PyUFunc_d_d,
+ //PyUFunc_g_g, PyUFunc_OO_O_method,
+};
+
+static char Py_aubio_unary_types[] = {
+ NPY_FLOAT, NPY_FLOAT,
+ NPY_DOUBLE, NPY_DOUBLE,
+ //NPY_LONGDOUBLE, NPY_LONGDOUBLE,
+ //NPY_OBJECT, NPY_OBJECT,
+};
+
+static char Py_unwrap2pi_doc[] = "map angle to unit circle [-pi, pi[";
+
+static void* Py_unwrap2pi_data[] = {
+ (void *)aubio_unwrap2pi,
+ (void *)aubio_unwrap2pi,
+ //(void *)unwrap2pil,
+ //(void *)unwrap2pio,
+};
+
+static char Py_freqtomidi_doc[] = "convert frequency to midi";
+
+static void* Py_freqtomidi_data[] = {
+ (void *)aubio_freqtomidi,
+ (void *)aubio_freqtomidi,
+};
+
+static char Py_miditofreq_doc[] = "convert midi to frequency";
+
+static void* Py_miditofreq_data[] = {
+ (void *)aubio_miditofreq,
+ (void *)aubio_miditofreq,
+};
+
+void add_ufuncs ( PyObject *m )
+{
+ int err = 0;
+ PyObject *dict, *f, *g, *h;
+
+ err = _import_umath ();
+ if (err != 0) {
+ fprintf (stderr,
+ "Unable to import Numpy umath from aubio module (error %d)\n", err);
+ }
+
+ dict = PyModule_GetDict(m);
+ f = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_unwrap2pi_data, Py_aubio_unary_types,
+ Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
+ PyUFunc_None, "unwrap2pi", Py_unwrap2pi_doc, 0);
+ PyDict_SetItemString(dict, "unwrap2pi", f);
+ Py_DECREF(f);
+
+ g = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_freqtomidi_data, Py_aubio_unary_types,
+ Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
+ PyUFunc_None, "freqtomidi", Py_freqtomidi_doc, 0);
+ PyDict_SetItemString(dict, "freqtomidi", g);
+ Py_DECREF(g);
+
+ h = PyUFunc_FromFuncAndData(Py_aubio_unary_functions, Py_miditofreq_data, Py_aubio_unary_types,
+ Py_aubio_unary_n_types, Py_aubio_unary_n_inputs, Py_aubio_unary_n_outputs,
+ PyUFunc_None, "miditofreq", Py_miditofreq_doc, 0);
+ PyDict_SetItemString(dict, "miditofreq", h);
+ Py_DECREF(h);
+ return;
+}
diff --git a/python/lib/__init__.py b/python/lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/lib/__init__.py
diff --git a/python/lib/aubio/__init__.py b/python/lib/aubio/__init__.py
new file mode 100644
index 0000000..316f961
--- /dev/null
+++ b/python/lib/aubio/__init__.py
@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+
+import numpy
+from ._aubio import *
+from ._aubio import float_type
+from .midiconv import *
+from .slicing import *
+
+class fvec(numpy.ndarray):
+ """a numpy vector holding audio samples"""
+
+ def __new__(cls, input_arg=1024, **kwargs):
+ if isinstance(input_arg, int):
+ if input_arg == 0:
+ raise ValueError("vector length of 1 or more expected")
+ return numpy.zeros(input_arg, dtype=float_type, **kwargs)
+ else:
+ return numpy.array(input_arg, dtype=float_type, **kwargs)
diff --git a/python/lib/aubio/midiconv.py b/python/lib/aubio/midiconv.py
new file mode 100644
index 0000000..80f28d0
--- /dev/null
+++ b/python/lib/aubio/midiconv.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+""" utilities to convert midi note number to and from note names """
+
+__all__ = ['note2midi', 'midi2note', 'freq2note']
+
+import sys
+py3 = sys.version_info[0] == 3
+if py3:
+ str_instances = str
+ int_instances = int
+else:
+ str_instances = (str, unicode)
+ int_instances = (int, long)
+
+def note2midi(note):
+ " convert note name to midi note number, e.g. [C-1, G9] -> [0, 127] "
+ _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
+ _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2,
+ 'b': -1, u'â™­': -1, u'\ufffd': -2}
+ _valid_octaves = range(-1, 10)
+ if not isinstance(note, str_instances):
+ raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
+ if len(note) not in range(2, 5):
+ raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
+ % (len(note), note))
+ notename, modifier, octave = [None]*3
+
+ if len(note) == 4:
+ notename, modifier, octave_sign, octave = note
+ octave = octave_sign + octave
+ elif len(note) == 3:
+ notename, modifier, octave = note
+ if modifier == '-':
+ octave = modifier + octave
+ modifier = None
+ else:
+ notename, octave = note
+
+ notename = notename.upper()
+ octave = int(octave)
+
+ if notename not in _valid_notenames:
+ raise ValueError("%s is not a valid note name" % notename)
+ if modifier not in _valid_modifiers:
+ raise ValueError("%s is not a valid modifier" % modifier)
+ if octave not in _valid_octaves:
+ raise ValueError("%s is not a valid octave" % octave)
+
+ midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
+ if midi > 127:
+ raise ValueError("%s is outside of the range C-2 to G8" % note)
+ return midi
+
+def midi2note(midi):
+ " convert midi note number to note name, e.g. [0, 127] -> [C-1, G9] "
+ if not isinstance(midi, int_instances):
+ raise TypeError("an integer is required, got %s" % midi)
+ if midi not in range(0, 128):
+ raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
+ _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
+ return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
+
+def freq2note(freq):
+ " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] "
+ from aubio import freqtomidi
+ return midi2note(int(freqtomidi(freq)))
diff --git a/python/lib/aubio/slicing.py b/python/lib/aubio/slicing.py
new file mode 100644
index 0000000..fa9d2e3
--- /dev/null
+++ b/python/lib/aubio/slicing.py
@@ -0,0 +1,86 @@
+"""utility routines to slice sound files at given timestamps"""
+
+import os
+from aubio import source, sink
+
+_max_timestamp = 1e120
+
+def slice_source_at_stamps(source_file, timestamps, timestamps_end=None,
+ output_dir=None, samplerate=0, hopsize=256):
+ """ slice a sound file at given timestamps """
+
+ if timestamps is None or len(timestamps) == 0:
+ raise ValueError("no timestamps given")
+
+ if timestamps[0] != 0:
+ timestamps = [0] + timestamps
+ if timestamps_end is not None:
+ timestamps_end = [timestamps[1] - 1] + timestamps_end
+
+ if timestamps_end is not None:
+ if len(timestamps_end) != len(timestamps):
+ raise ValueError("len(timestamps_end) != len(timestamps)")
+ else:
+ timestamps_end = [t - 1 for t in timestamps[1:]] + [_max_timestamp]
+
+ regions = list(zip(timestamps, timestamps_end))
+ #print regions
+
+ source_base_name, _ = os.path.splitext(os.path.basename(source_file))
+ if output_dir is not None:
+ if not os.path.isdir(output_dir):
+ os.makedirs(output_dir)
+ source_base_name = os.path.join(output_dir, source_base_name)
+
+ def new_sink_name(source_base_name, timestamp, samplerate):
+ """ create a sink based on a timestamp in samples, converted in seconds """
+ timestamp_seconds = timestamp / float(samplerate)
+ return source_base_name + "_%011.6f" % timestamp_seconds + '.wav'
+
+ # open source file
+ _source = source(source_file, samplerate, hopsize)
+ samplerate = _source.samplerate
+
+ total_frames = 0
+ slices = []
+
+ while True:
+ # get hopsize new samples from source
+ vec, read = _source.do_multi()
+ # if the total number of frames read will exceed the next region start
+ if len(regions) and total_frames + read >= regions[0][0]:
+ #print "getting", regions[0], "at", total_frames
+ # get next region
+ start_stamp, end_stamp = regions.pop(0)
+ # create a name for the sink
+ new_sink_path = new_sink_name(source_base_name, start_stamp, samplerate)
+ # create its sink
+ _sink = sink(new_sink_path, samplerate, _source.channels)
+ # create a dictionary containing all this
+ new_slice = {'start_stamp': start_stamp, 'end_stamp': end_stamp, 'sink': _sink}
+ # append the dictionary to the current list of slices
+ slices.append(new_slice)
+
+ for current_slice in slices:
+ start_stamp = current_slice['start_stamp']
+ end_stamp = current_slice['end_stamp']
+ _sink = current_slice['sink']
+ # sample index to start writing from new source vector
+ start = max(start_stamp - total_frames, 0)
+ # number of samples yet to written be until end of region
+ remaining = end_stamp - total_frames + 1
+ #print current_slice, remaining, start
+ # not enough frames remaining, time to split
+ if remaining < read:
+ if remaining > start:
+ # write remaining samples from current region
+ _sink.do_multi(vec[:, start:remaining], remaining - start)
+ #print "closing region", "remaining", remaining
+ # close this file
+ _sink.close()
+ elif read > start:
+ # write all the samples
+ _sink.do_multi(vec[:, start:read], read - start)
+ total_frames += read
+ if read < hopsize:
+ break
diff --git a/python/lib/gen_code.py b/python/lib/gen_code.py
new file mode 100644
index 0000000..1f9b9dc
--- /dev/null
+++ b/python/lib/gen_code.py
@@ -0,0 +1,555 @@
+aubiodefvalue = {
+ # we have some clean up to do
+ 'buf_size': 'Py_default_vector_length',
+ 'win_s': 'Py_default_vector_length',
+ # and here too
+ 'hop_size': 'Py_default_vector_length / 2',
+ 'hop_s': 'Py_default_vector_length / 2',
+ # these should be alright
+ 'samplerate': 'Py_aubio_default_samplerate',
+ # now for the non obvious ones
+ 'n_filters': '40',
+ 'n_coeffs': '13',
+ 'nelems': '10',
+ 'flow': '0.',
+ 'fhig': '1.',
+ 'ilow': '0.',
+ 'ihig': '1.',
+ 'thrs': '0.5',
+ 'ratio': '0.5',
+ 'method': '"default"',
+ 'uri': '"none"',
+ }
+
+member_types = {
+ 'name': 'type',
+ 'char_t*': 'T_STRING',
+ 'uint_t': 'T_INT',
+ 'smpl_t': 'AUBIO_NPY_SMPL',
+ }
+
+pyfromtype_fn = {
+ 'smpl_t': 'PyFloat_FromDouble',
+ 'uint_t': 'PyLong_FromLong', # was: 'PyInt_FromLong',
+ 'fvec_t*': 'PyAubio_CFvecToArray',
+ 'fmat_t*': 'PyAubio_CFmatToArray',
+ }
+
+pytoaubio_fn = {
+ 'fvec_t*': 'PyAubio_ArrayToCFvec',
+ 'cvec_t*': 'PyAubio_PyCvecToCCvec',
+ #'fmat_t*': 'PyAubio_ArrayToCFmat',
+ }
+
+newfromtype_fn = {
+ 'fvec_t*': 'new_py_fvec',
+ 'fmat_t*': 'new_py_fmat',
+ 'cvec_t*': 'new_py_cvec',
+ }
+
+delfromtype_fn = {
+ 'fvec_t*': 'Py_DECREF',
+ 'fmat_t*': 'Py_DECREF',
+ 'cvec_t*': 'Py_DECREF',
+ }
+
+param_init = {
+ 'char_t*': 'NULL',
+ 'uint_t': '0',
+ 'sint_t': 0,
+ 'smpl_t': 0.,
+ 'lsmp_t': 0.,
+ }
+
+pyargparse_chars = {
+ 'smpl_t': 'f', # if not usedouble else 'd',
+ 'uint_t': 'I',
+ 'sint_t': 'I',
+ 'char_t*': 's',
+ 'fmat_t*': 'O',
+ 'fvec_t*': 'O',
+ 'cvec_t*': 'O',
+ }
+
+objoutsize = {
+ 'onset': '1',
+ 'pitch': '1',
+ 'notes': '3',
+ 'wavetable': 'self->hop_size',
+ 'sampler': 'self->hop_size',
+ 'mfcc': 'self->n_coeffs',
+ 'specdesc': '1',
+ 'tempo': '1',
+ 'filterbank': 'self->n_filters',
+ 'tss': 'self->hop_size',
+ }
+
+objinputsize = {
+ 'mfcc': 'self->buf_size / 2 + 1',
+ 'notes': 'self->hop_size',
+ 'onset': 'self->hop_size',
+ 'pitch': 'self->hop_size',
+ 'sampler': 'self->hop_size',
+ 'specdesc': 'self->buf_size / 2 + 1',
+ 'tempo': 'self->hop_size',
+ 'wavetable': 'self->hop_size',
+ }
+
+def get_name(proto):
+ name = proto.replace(' *', '* ').split()[1].split('(')[0]
+ name = name.replace('*','')
+ if name == '': raise ValueError(proto + "gave empty name")
+ return name
+
+def get_return_type(proto):
+ import re
+ paramregex = re.compile('(\w+ ?\*?).*')
+ outputs = paramregex.findall(proto)
+ assert len(outputs) == 1
+ return outputs[0].replace(' ', '')
+
+def split_type(arg):
+ """ arg = 'foo *name'
+ return ['foo*', 'name'] """
+ l = arg.split()
+ type_arg = {} #'type': l[0], 'name': l[1]}
+ type_arg['type'] = " ".join(l[:-1])
+ type_arg['name'] = l[-1]
+ # fix up type / name
+ if type_arg['name'].startswith('*'):
+ # ['foo', '*name'] -> ['foo*', 'name']
+ type_arg['type'] += '*'
+ type_arg['name'] = type_arg['name'][1:]
+ if type_arg['type'].endswith(' *'):
+ # ['foo *', 'name'] -> ['foo*', 'name']
+ type_arg['type'] = type_arg['type'].replace(' *','*')
+ if type_arg['type'].startswith('const '):
+ # ['foo *', 'name'] -> ['foo*', 'name']
+ type_arg['type'] = type_arg['type'].replace('const ','')
+ return type_arg
+
+def get_params(proto):
+ """ get the list of parameters from a function prototype
+ example: proto = "int main (int argc, char ** argv)"
+ returns: ['int argc', 'char ** argv']
+ """
+ import re
+ paramregex = re.compile('.*\((.*)\);')
+ a = paramregex.findall(proto)[0].split(', ')
+ #a = [i.replace('const ', '') for i in a]
+ return a
+
+def get_input_params(proto):
+ a = get_params(proto)
+ return [i.replace('const ', '') for i in a if (i.startswith('const ') or i.startswith('uint_t ') or i.startswith('smpl_t '))]
+
+def get_output_params(proto):
+ a = get_params(proto)
+ return [i for i in a if not i.startswith('const ')][1:]
+
+def get_params_types_names(proto):
+ """ get the list of parameters from a function prototype
+ example: proto = "int main (int argc, char ** argv)"
+ returns: [['int', 'argc'], ['char **','argv']]
+ """
+ a = list(map(split_type, get_params(proto)))
+ #print proto, a
+ #import sys; sys.exit(1)
+ return a
+
+class MappedObject(object):
+
+ def __init__(self, prototypes, usedouble = False):
+ if usedouble:
+ pyargparse_chars['smpl_t'] = 'd'
+ self.prototypes = prototypes
+
+ self.shortname = prototypes['shortname']
+ self.longname = prototypes['longname']
+ self.new_proto = prototypes['new'][0]
+ self.del_proto = prototypes['del'][0]
+ self.do_proto = prototypes['do'][0]
+ self.input_params = get_params_types_names(self.new_proto)
+ self.input_params_list = "; ".join(get_input_params(self.new_proto))
+ self.outputs = get_params_types_names(self.do_proto)[2:]
+ self.do_inputs = [get_params_types_names(self.do_proto)[1]]
+ self.do_outputs = get_params_types_names(self.do_proto)[2:]
+ struct_output_str = ["PyObject *{0[name]}; {1} c_{0[name]}".format(i, i['type'][:-1]) for i in self.do_outputs]
+ self.struct_outputs = ";\n ".join(struct_output_str)
+
+ #print ("input_params: ", map(split_type, get_input_params(self.do_proto)))
+ #print ("output_params", map(split_type, get_output_params(self.do_proto)))
+
+ def gen_code(self):
+ out = ""
+ out += self.gen_struct()
+ out += self.gen_doc()
+ out += self.gen_new()
+ out += self.gen_init()
+ out += self.gen_del()
+ out += self.gen_do()
+ out += self.gen_memberdef()
+ out += self.gen_set()
+ out += self.gen_get()
+ out += self.gen_methodef()
+ out += self.gen_typeobject()
+ return out
+
+ def gen_struct(self):
+ out = """
+// {shortname} structure
+typedef struct{{
+ PyObject_HEAD
+ // pointer to aubio object
+ {longname} *o;
+ // input parameters
+ {input_params_list};
+ // do input vectors
+ {do_inputs_list};
+ // output results
+ {struct_outputs};
+}} Py_{shortname};
+"""
+ # fmat_t* / fvec_t* / cvec_t* inputs -> full fvec_t /.. struct in Py_{shortname}
+ do_inputs_list = "; ".join(get_input_params(self.do_proto)).replace('fvec_t *','fvec_t').replace('fmat_t *', 'fmat_t').replace('cvec_t *', 'cvec_t')
+ return out.format(do_inputs_list = do_inputs_list, **self.__dict__)
+
+ def gen_doc(self):
+ out = """
+// TODO: add documentation
+static char Py_{shortname}_doc[] = \"undefined\";
+"""
+ return out.format(**self.__dict__)
+
+ def gen_new(self):
+ out = """
+// new {shortname}
+static PyObject *
+Py_{shortname}_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
+{{
+ Py_{shortname} *self;
+""".format(**self.__dict__)
+ params = self.input_params
+ for p in params:
+ out += """
+ {type} {name} = {defval};""".format(defval = param_init[p['type']], **p)
+ plist = ", ".join(["\"%s\"" % p['name'] for p in params])
+ out += """
+ static char *kwlist[] = {{ {plist}, NULL }};""".format(plist = plist)
+ argchars = "".join([pyargparse_chars[p['type']] for p in params])
+ arglist = ", ".join(["&%s" % p['name'] for p in params])
+ out += """
+ if (!PyArg_ParseTupleAndKeywords (args, kwds, "|{argchars}", kwlist,
+ {arglist})) {{
+ return NULL;
+ }}
+""".format(argchars = argchars, arglist = arglist)
+ out += """
+ self = (Py_{shortname} *) pytype->tp_alloc (pytype, 0);
+ if (self == NULL) {{
+ return NULL;
+ }}
+""".format(**self.__dict__)
+ params = self.input_params
+ for p in params:
+ out += self.check_valid(p)
+ out += """
+ return (PyObject *)self;
+}
+"""
+ return out
+
+ def check_valid(self, p):
+ if p['type'] == 'uint_t':
+ return self.check_valid_uint(p)
+ if p['type'] == 'char_t*':
+ return self.check_valid_char(p)
+ else:
+ print ("ERROR, no idea how to check %s for validity" % p['type'])
+
+ def check_valid_uint(self, p):
+ name = p['name']
+ return """
+ self->{name} = {defval};
+ if ((sint_t){name} > 0) {{
+ self->{name} = {name};
+ }} else if ((sint_t){name} < 0) {{
+ PyErr_SetString (PyExc_ValueError, "can not use negative value for {name}");
+ return NULL;
+ }}
+""".format(defval = aubiodefvalue[name], name = name)
+
+ def check_valid_char(self, p):
+ name = p['name']
+ return """
+ self->{name} = {defval};
+ if ({name} != NULL) {{
+ self->{name} = {name};
+ }}
+""".format(defval = aubiodefvalue[name], name = name)
+
+ def gen_init(self):
+ out = """
+// init {shortname}
+static int
+Py_{shortname}_init (Py_{shortname} * self, PyObject * args, PyObject * kwds)
+{{
+""".format(**self.__dict__)
+ new_name = get_name(self.new_proto)
+ new_params = ", ".join(["self->%s" % s['name'] for s in self.input_params])
+ out += """
+ self->o = {new_name}({new_params});
+""".format(new_name = new_name, new_params = new_params)
+ paramchars = "%s"
+ paramvals = "self->method"
+ out += """
+ // return -1 and set error string on failure
+ if (self->o == NULL) {{
+ PyErr_Format (PyExc_Exception, "failed creating {shortname}");
+ return -1;
+ }}
+""".format(paramchars = paramchars, paramvals = paramvals, **self.__dict__)
+ output_create = ""
+ for o in self.outputs:
+ output_create += """
+ self->{name} = {create_fn}({output_size});""".format(name = o['name'], create_fn = newfromtype_fn[o['type']], output_size = objoutsize[self.shortname])
+ out += """
+ // TODO get internal params after actual object creation?
+"""
+ out += """
+ // create outputs{output_create}
+""".format(output_create = output_create)
+ out += """
+ return 0;
+}
+"""
+ return out
+
+ def gen_memberdef(self):
+ out = """
+static PyMemberDef Py_{shortname}_members[] = {{
+""".format(**self.__dict__)
+ for p in get_params_types_names(self.new_proto):
+ tmp = " {{\"{name}\", {ttype}, offsetof (Py_{shortname}, {name}), READONLY, \"TODO documentation\"}},\n"
+ pytype = member_types[p['type']]
+ out += tmp.format(name = p['name'], ttype = pytype, shortname = self.shortname)
+ out += """ {NULL}, // sentinel
+};
+"""
+ return out
+
+ def gen_del(self):
+ out = """
+// del {shortname}
+static void
+Py_{shortname}_del (Py_{shortname} * self, PyObject * unused)
+{{""".format(**self.__dict__)
+ for input_param in self.do_inputs:
+ if input_param['type'] == 'fmat_t *':
+ out += """
+ free(self->{0[name]}.data);""".format(input_param)
+ for o in self.outputs:
+ name = o['name']
+ del_out = delfromtype_fn[o['type']]
+ out += """
+ {del_out}(self->{name});""".format(del_out = del_out, name = name)
+ del_fn = get_name(self.del_proto)
+ out += """
+ if (self->o) {{
+ {del_fn}(self->o);
+ }}
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}}
+""".format(del_fn = del_fn)
+ return out
+
+ def gen_do(self):
+ out = """
+// do {shortname}
+static PyObject*
+Py_{shortname}_do (Py_{shortname} * self, PyObject * args)
+{{""".format(**self.__dict__)
+ input_params = self.do_inputs
+ output_params = self.do_outputs
+ #print input_params
+ #print output_params
+ for input_param in input_params:
+ out += """
+ PyObject *py_{0};""".format(input_param['name'])
+ refs = ", ".join(["&py_%s" % p['name'] for p in input_params])
+ pyparamtypes = "".join([pyargparse_chars[p['type']] for p in input_params])
+ out += """
+ if (!PyArg_ParseTuple (args, "{pyparamtypes}", {refs})) {{
+ return NULL;
+ }}""".format(refs = refs, pyparamtypes = pyparamtypes, **self.__dict__)
+ for input_param in input_params:
+ out += """
+
+ if (!{pytoaubio}(py_{0[name]}, &(self->{0[name]}))) {{
+ return NULL;
+ }}""".format(input_param, pytoaubio = pytoaubio_fn[input_param['type']])
+ if self.shortname in objinputsize:
+ out += """
+
+ if (self->{0[name]}.length != {expected_size}) {{
+ PyErr_Format (PyExc_ValueError,
+ "input size of {shortname} should be %d, not %d",
+ {expected_size}, self->{0[name]}.length);
+ return NULL;
+ }}""".format(input_param, expected_size = objinputsize[self.shortname], **self.__dict__)
+ else:
+ out += """
+
+ // TODO: check input sizes"""
+ for output_param in output_params:
+ out += """
+
+ Py_INCREF(self->{0[name]});
+ if (!{pytoaubio}(self->{0[name]}, &(self->c_{0[name]}))) {{
+ return NULL;
+ }}""".format(output_param, pytoaubio = pytoaubio_fn[output_param['type']])
+ do_fn = get_name(self.do_proto)
+ inputs = ", ".join(['&(self->'+p['name']+')' for p in input_params])
+ c_outputs = ", ".join(["&(self->c_%s)" % p['name'] for p in self.do_outputs])
+ outputs = ", ".join(["self->%s" % p['name'] for p in self.do_outputs])
+ out += """
+
+ {do_fn}(self->o, {inputs}, {c_outputs});
+
+ return {outputs};
+}}
+""".format(
+ do_fn = do_fn,
+ inputs = inputs, outputs = outputs, c_outputs = c_outputs,
+ )
+ return out
+
+ def gen_set(self):
+ out = """
+// {shortname} setters
+""".format(**self.__dict__)
+ for set_param in self.prototypes['set']:
+ params = get_params_types_names(set_param)[1]
+ paramtype = params['type']
+ method_name = get_name(set_param)
+ param = method_name.split('aubio_'+self.shortname+'_set_')[-1]
+ pyparamtype = pyargparse_chars[paramtype]
+ out += """
+static PyObject *
+Pyaubio_{shortname}_set_{param} (Py_{shortname} *self, PyObject *args)
+{{
+ uint_t err = 0;
+ {paramtype} {param};
+
+ if (!PyArg_ParseTuple (args, "{pyparamtype}", &{param})) {{
+ return NULL;
+ }}
+ err = aubio_{shortname}_set_{param} (self->o, {param});
+
+ if (err > 0) {{
+ PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
+ return NULL;
+ }}
+ Py_RETURN_NONE;
+}}
+""".format(param = param, paramtype = paramtype, pyparamtype = pyparamtype, **self.__dict__)
+ return out
+
+ def gen_get(self):
+ out = """
+// {shortname} getters
+""".format(**self.__dict__)
+ for method in self.prototypes['get']:
+ params = get_params_types_names(method)
+ method_name = get_name(method)
+ assert len(params) == 1, \
+ "get method has more than one parameter %s" % params
+ param = method_name.split('aubio_'+self.shortname+'_get_')[-1]
+ paramtype = get_return_type(method)
+ ptypeconv = pyfromtype_fn[paramtype]
+ out += """
+static PyObject *
+Pyaubio_{shortname}_get_{param} (Py_{shortname} *self, PyObject *unused)
+{{
+ {ptype} {param} = aubio_{shortname}_get_{param} (self->o);
+ return (PyObject *){ptypeconv} ({param});
+}}
+""".format(param = param, ptype = paramtype, ptypeconv = ptypeconv,
+ **self.__dict__)
+ return out
+
+ def gen_methodef(self):
+ out = """
+static PyMethodDef Py_{shortname}_methods[] = {{""".format(**self.__dict__)
+ for m in self.prototypes['set']:
+ name = get_name(m)
+ shortname = name.replace('aubio_%s_' % self.shortname, '')
+ out += """
+ {{"{shortname}", (PyCFunction) Py{name},
+ METH_VARARGS, ""}},""".format(name = name, shortname = shortname)
+ for m in self.prototypes['get']:
+ name = get_name(m)
+ shortname = name.replace('aubio_%s_' % self.shortname, '')
+ out += """
+ {{"{shortname}", (PyCFunction) Py{name},
+ METH_NOARGS, ""}},""".format(name = name, shortname = shortname)
+ out += """
+ {NULL} /* sentinel */
+};
+"""
+ return out
+
+ def gen_typeobject(self):
+ return """
+PyTypeObject Py_{shortname}Type = {{
+ //PyObject_HEAD_INIT (NULL)
+ //0,
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "aubio.{shortname}",
+ sizeof (Py_{shortname}),
+ 0,
+ (destructor) Py_{shortname}_del,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (ternaryfunc)Py_{shortname}_do,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Py_{shortname}_doc,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ Py_{shortname}_methods,
+ Py_{shortname}_members,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ (initproc) Py_{shortname}_init,
+ 0,
+ Py_{shortname}_new,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+}};
+""".format(**self.__dict__)
diff --git a/python/lib/gen_external.py b/python/lib/gen_external.py
new file mode 100644
index 0000000..9c501a3
--- /dev/null
+++ b/python/lib/gen_external.py
@@ -0,0 +1,249 @@
+import distutils.ccompiler
+import sys, os, subprocess, glob
+
+header = os.path.join('src', 'aubio.h')
+output_path = os.path.join('python', 'gen')
+
+source_header = """// this file is generated! do not modify
+#include "aubio-types.h"
+"""
+
+skip_objects = [
+ # already in ext/
+ 'fft',
+ 'pvoc',
+ 'filter',
+ 'filterbank',
+ #'resampler',
+ # AUBIO_UNSTABLE
+ 'hist',
+ 'parameter',
+ 'scale',
+ 'beattracking',
+ 'resampler',
+ 'peakpicker',
+ 'pitchfcomb',
+ 'pitchmcomb',
+ 'pitchschmitt',
+ 'pitchspecacf',
+ 'pitchyin',
+ 'pitchyinfft',
+ 'sink',
+ 'sink_apple_audio',
+ 'sink_sndfile',
+ 'sink_wavwrite',
+ #'mfcc',
+ 'source',
+ 'source_apple_audio',
+ 'source_sndfile',
+ 'source_avcodec',
+ 'source_wavread',
+ #'sampler',
+ 'audio_unit',
+
+ 'tss',
+ ]
+
+def get_preprocessor():
+ # findout which compiler to use
+ from distutils.sysconfig import customize_compiler
+ compiler_name = distutils.ccompiler.get_default_compiler()
+ compiler = distutils.ccompiler.new_compiler(compiler=compiler_name)
+ try:
+ customize_compiler(compiler)
+ except AttributeError as e:
+ print("Warning: failed customizing compiler ({:s})".format(repr(e)))
+
+ if hasattr(compiler, 'initialize'):
+ try:
+ compiler.initialize()
+ except ValueError as e:
+ print("Warning: failed initializing compiler ({:s})".format(repr(e)))
+
+ cpp_cmd = None
+ if hasattr(compiler, 'preprocessor'): # for unixccompiler
+ cpp_cmd = compiler.preprocessor
+ elif hasattr(compiler, 'compiler'): # for ccompiler
+ cpp_cmd = compiler.compiler.split()
+ cpp_cmd += ['-E']
+ elif hasattr(compiler, 'cc'): # for msvccompiler
+ cpp_cmd = compiler.cc.split()
+ cpp_cmd += ['-E']
+
+ if not cpp_cmd:
+ print("Warning: could not guess preprocessor, using env's CC")
+ cpp_cmd = os.environ.get('CC', 'cc').split()
+ cpp_cmd += ['-E']
+
+ return cpp_cmd
+
+def get_cpp_objects(header=header):
+ cpp_cmd = get_preprocessor()
+
+ macros = [('AUBIO_UNSTABLE', 1)]
+
+ if not os.path.isfile(header):
+ raise Exception("could not find include file " + header)
+
+ includes = [os.path.dirname(header)]
+ cpp_cmd += distutils.ccompiler.gen_preprocess_options(macros, includes)
+ cpp_cmd += [header]
+
+ print("Running command: {:s}".format(" ".join(cpp_cmd)))
+ proc = subprocess.Popen(cpp_cmd,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ assert proc, 'Proc was none'
+ cpp_output = proc.stdout.read()
+ err_output = proc.stderr.read()
+ if not cpp_output:
+ raise Exception("preprocessor output is empty:\n%s" % err_output)
+ elif err_output:
+ print ("Warning: preprocessor produced warnings:\n%s" % err_output)
+ if not isinstance(cpp_output, list):
+ cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')]
+
+ cpp_output = filter(lambda y: len(y) > 1, cpp_output)
+ cpp_output = list(filter(lambda y: not y.startswith('#'), cpp_output))
+
+ i = 1
+ while 1:
+ if i >= len(cpp_output): break
+ if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'):
+ cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i]
+ cpp_output.pop(i-1)
+ else:
+ i += 1
+
+ typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output)
+
+ cpp_objects = [a.split()[3][:-1] for a in typedefs]
+
+ return cpp_output, cpp_objects
+
+def generate_external(header=header, output_path=output_path, usedouble=False, overwrite=True):
+ if not os.path.isdir(output_path): os.mkdir(output_path)
+ elif not overwrite: return glob.glob(os.path.join(output_path, '*.c'))
+ sources_list = []
+ cpp_output, cpp_objects = get_cpp_objects(header)
+ lib = {}
+
+ for o in cpp_objects:
+ if o[:6] != 'aubio_':
+ continue
+ shortname = o[6:-2]
+ if shortname in skip_objects:
+ continue
+ lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []}
+ lib[shortname]['longname'] = o
+ lib[shortname]['shortname'] = shortname
+ for fn in cpp_output:
+ if o[:-1] in fn:
+ #print "found", o[:-1], "in", fn
+ if 'typedef struct ' in fn:
+ lib[shortname]['struct'].append(fn)
+ elif '_do' in fn:
+ lib[shortname]['do'].append(fn)
+ elif 'new_' in fn:
+ lib[shortname]['new'].append(fn)
+ elif 'del_' in fn:
+ lib[shortname]['del'].append(fn)
+ elif '_get_' in fn:
+ lib[shortname]['get'].append(fn)
+ elif '_set_' in fn:
+ lib[shortname]['set'].append(fn)
+ else:
+ #print "no idea what to do about", fn
+ lib[shortname]['other'].append(fn)
+
+ """
+ for fn in cpp_output:
+ found = 0
+ for o in lib:
+ for family in lib[o]:
+ if fn in lib[o][family]:
+ found = 1
+ if found == 0:
+ print "missing", fn
+
+ for o in lib:
+ for family in lib[o]:
+ if type(lib[o][family]) == str:
+ print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
+ elif len(lib[o][family]) == 1:
+ print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family][0] ) )
+ else:
+ print ( "{:15s} {:10s} {:d}".format(o, family, len(lib[o][family]) ) )
+ """
+
+ try:
+ from .gen_code import MappedObject
+ except (SystemError, ValueError):
+ from gen_code import MappedObject
+ for o in lib:
+ out = source_header
+ mapped = MappedObject(lib[o], usedouble = usedouble)
+ out += mapped.gen_code()
+ output_file = os.path.join(output_path, 'gen-%s.c' % o)
+ with open(output_file, 'w') as f:
+ f.write(out)
+ print ("wrote %s" % output_file )
+ sources_list.append(output_file)
+
+ out = source_header
+ out += "#include \"aubio-generated.h\""
+ check_types = "\n || ".join(["PyType_Ready(&Py_%sType) < 0" % o for o in lib])
+ out += """
+
+int generated_types_ready (void)
+{{
+ return ({pycheck_types});
+}}
+""".format(pycheck_types = check_types)
+
+ add_types = "".join(["""
+ Py_INCREF (&Py_{name}Type);
+ PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name = o) for o in lib])
+ out += """
+
+void add_generated_objects ( PyObject *m )
+{{
+{add_types}
+}}
+""".format(add_types = add_types)
+
+ output_file = os.path.join(output_path, 'aubio-generated.c')
+ with open(output_file, 'w') as f:
+ f.write(out)
+ print ("wrote %s" % output_file )
+ sources_list.append(output_file)
+
+ objlist = "".join(["extern PyTypeObject Py_%sType;\n" % p for p in lib])
+ out = """// generated list of objects created with gen_external.py
+
+#include <Python.h>
+"""
+ if usedouble:
+ out += """
+#ifndef HAVE_AUBIO_DOUBLE
+#define HAVE_AUBIO_DOUBLE 1
+#endif
+"""
+ out += """
+{objlist}
+int generated_objects ( void );
+void add_generated_objects( PyObject *m );
+""".format(objlist = objlist)
+
+ output_file = os.path.join(output_path, 'aubio-generated.h')
+ with open(output_file, 'w') as f:
+ f.write(out)
+ print ("wrote %s" % output_file )
+ # no need to add header to list of sources
+
+ return sources_list
+
+if __name__ == '__main__':
+ if len(sys.argv) > 1: header = sys.argv[1]
+ if len(sys.argv) > 2: output_path = sys.argv[2]
+ generate_external(header, output_path)
diff --git a/python/lib/moresetuptools.py b/python/lib/moresetuptools.py
new file mode 100644
index 0000000..906b871
--- /dev/null
+++ b/python/lib/moresetuptools.py
@@ -0,0 +1,141 @@
+""" A collection of function used from setup.py distutils script """
+#
+import sys, os, glob, subprocess
+import distutils, distutils.command.clean, distutils.dir_util
+from .gen_external import generate_external, header, output_path
+
+# inspired from https://gist.github.com/abergmeier/9488990
+def add_packages(packages, ext=None, **kw):
+ """ use pkg-config to search which of 'packages' are installed """
+ flag_map = {
+ '-I': 'include_dirs',
+ '-L': 'library_dirs',
+ '-l': 'libraries'}
+
+ # if a setuptools extension is passed, fill it with pkg-config results
+ if ext:
+ kw = {'include_dirs': ext.include_dirs,
+ 'extra_link_args': ext.extra_link_args,
+ 'library_dirs': ext.library_dirs,
+ 'libraries': ext.libraries,
+ }
+
+ for package in packages:
+ cmd = ['pkg-config', '--libs', '--cflags', package]
+ try:
+ tokens = subprocess.check_output(cmd)
+ except Exception as e:
+ print("Running \"{:s}\" failed: {:s}".format(' '.join(cmd), repr(e)))
+ continue
+ tokens = tokens.decode('utf8').split()
+ for token in tokens:
+ key = token[:2]
+ try:
+ arg = flag_map[key]
+ value = token[2:]
+ except KeyError:
+ arg = 'extra_link_args'
+ value = token
+ kw.setdefault(arg, []).append(value)
+ for key, value in iter(kw.items()): # remove duplicated
+ kw[key] = list(set(value))
+ return kw
+
+def add_local_aubio_header(ext):
+ """ use local "src/aubio.h", not <aubio/aubio.h>"""
+ ext.define_macros += [('USE_LOCAL_AUBIO', 1)]
+ ext.include_dirs += ['src'] # aubio.h
+
+def add_local_aubio_lib(ext):
+ """ add locally built libaubio from build/src """
+ print("Info: using locally built libaubio")
+ ext.library_dirs += [os.path.join('build', 'src')]
+ ext.libraries += ['aubio']
+
+def add_local_aubio_sources(ext):
+ """ build aubio inside python module instead of linking against libaubio """
+ print("Warning: libaubio was not built with waf, adding src/")
+ # create an empty header, macros will be passed on the command line
+ fake_config_header = os.path.join('python', 'ext', 'config.h')
+ distutils.file_util.write_file(fake_config_header, "")
+ aubio_sources = glob.glob(os.path.join('src', '**.c'))
+ aubio_sources += glob.glob(os.path.join('src', '*', '**.c'))
+ ext.sources += aubio_sources
+ # define macros (waf puts them in build/src/config.h)
+ for define_macro in ['HAVE_STDLIB_H', 'HAVE_STDIO_H',
+ 'HAVE_MATH_H', 'HAVE_STRING_H',
+ 'HAVE_C99_VARARGS_MACROS',
+ 'HAVE_LIMITS_H', 'HAVE_MEMCPY_HACKS']:
+ ext.define_macros += [(define_macro, 1)]
+
+ # loof for additional packages
+ print("Info: looking for *optional* additional packages")
+ packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample',
+ 'jack',
+ 'sndfile', 'samplerate',
+ #'fftw3f',
+ ]
+ add_packages(packages, ext=ext)
+ if 'avcodec' in ext.libraries \
+ and 'avformat' in ext.libraries \
+ and 'avutil' in ext.libraries \
+ and 'avresample' in ext.libraries:
+ ext.define_macros += [('HAVE_LIBAV', 1)]
+ if 'jack' in ext.libraries:
+ ext.define_macros += [('HAVE_JACK', 1)]
+ if 'sndfile' in ext.libraries:
+ ext.define_macros += [('HAVE_SNDFILE', 1)]
+ if 'samplerate' in ext.libraries:
+ ext.define_macros += [('HAVE_SAMPLERATE', 1)]
+ if 'fftw3f' in ext.libraries:
+ ext.define_macros += [('HAVE_FFTW3F', 1)]
+ ext.define_macros += [('HAVE_FFTW3', 1)]
+
+ # add accelerate on darwin
+ if sys.platform.startswith('darwin'):
+ ext.extra_link_args += ['-framework', 'Accelerate']
+ ext.define_macros += [('HAVE_ACCELERATE', 1)]
+ ext.define_macros += [('HAVE_SOURCE_APPLE_AUDIO', 1)]
+ ext.define_macros += [('HAVE_SINK_APPLE_AUDIO', 1)]
+
+ if sys.platform.startswith('win'):
+ ext.define_macros += [('HAVE_WIN_HACKS', 1)]
+
+ ext.define_macros += [('HAVE_WAVWRITE', 1)]
+ ext.define_macros += [('HAVE_WAVREAD', 1)]
+ # TODO:
+ # add cblas
+ if 0:
+ ext.libraries += ['cblas']
+ ext.define_macros += [('HAVE_ATLAS_CBLAS_H', 1)]
+
+def add_system_aubio(ext):
+ # use pkg-config to find aubio's location
+ add_packages(['aubio'], ext)
+ if 'aubio' not in ext.libraries:
+ print("Error: libaubio not found")
+
+class CleanGenerated(distutils.command.clean.clean):
+ def run(self):
+ distutils.dir_util.remove_tree(output_path)
+ distutils.command.clean.clean.run(self)
+
+class GenerateCommand(distutils.cmd.Command):
+ description = 'generate gen/gen-*.c files from ../src/aubio.h'
+ user_options = [
+ # The format is (long option, short option, description).
+ ('enable-double', None, 'use HAVE_AUBIO_DOUBLE=1 (default: 0)'),
+ ]
+
+ def initialize_options(self):
+ self.enable_double = False
+
+ def finalize_options(self):
+ if self.enable_double:
+ self.announce(
+ 'will generate code for aubio compiled with HAVE_AUBIO_DOUBLE=1',
+ level=distutils.log.INFO)
+
+ def run(self):
+ self.announce( 'Generating code', level=distutils.log.INFO)
+ generated_object_files = generate_external(header, output_path, usedouble=self.enable_double)
diff --git a/python/scripts/aubiocut b/python/scripts/aubiocut
new file mode 100755
index 0000000..eec68da
--- /dev/null
+++ b/python/scripts/aubiocut
@@ -0,0 +1,206 @@
+#! /usr/bin/env python
+
+""" this file was written by Paul Brossier
+ it is released under the GNU/GPL license.
+"""
+
+import sys
+#from aubio.task import *
+
+usage = "usage: %s [options] -i soundfile" % sys.argv[0]
+usage += "\n help: %s -h" % sys.argv[0]
+
+def parse_args():
+ from optparse import OptionParser
+ parser = OptionParser(usage=usage)
+ parser.add_option("-i", "--input", action = "store", dest = "source_file",
+ help="input sound file to analyse", metavar = "<source_file>")
+ parser.add_option("-O","--onset-method",
+ action="store", dest="onset_method", default='default',
+ metavar = "<onset_method>",
+ help="onset detection method [default=default] \
+ complexdomain|hfc|phase|specdiff|energy|kl|mkl")
+ # cutting methods
+ parser.add_option("-b","--beat",
+ action="store_true", dest="beat", default=False,
+ help="use beat locations")
+ """
+ parser.add_option("-S","--silencecut",
+ action="store_true", dest="silencecut", default=False,
+ help="use silence locations")
+ parser.add_option("-s","--silence",
+ metavar = "<value>",
+ action="store", dest="silence", default=-70,
+ help="silence threshold [default=-70]")
+ """
+ # algorithm parameters
+ parser.add_option("-r", "--samplerate",
+ metavar = "<freq>", type='int',
+ action="store", dest="samplerate", default=0,
+ help="samplerate at which the file should be represented")
+ parser.add_option("-B","--bufsize",
+ action="store", dest="bufsize", default=512,
+ metavar = "<size>", type='int',
+ help="buffer size [default=512]")
+ parser.add_option("-H","--hopsize",
+ metavar = "<size>", type='int',
+ action="store", dest="hopsize", default=256,
+ help="overlap size [default=256]")
+ parser.add_option("-t","--onset-threshold",
+ metavar = "<value>", type="float",
+ action="store", dest="threshold", default=0.3,
+ help="onset peak picking threshold [default=0.3]")
+ parser.add_option("-c","--cut",
+ action="store_true", dest="cut", default=False,
+ help="cut input sound file at detected labels \
+ best used with option -L")
+
+ # minioi
+ parser.add_option("-M","--minioi",
+ metavar = "<value>", type='string',
+ action="store", dest="minioi", default="12ms",
+ help="minimum inter onset interval [default=12ms]")
+
+ """
+ parser.add_option("-D","--delay",
+ action = "store", dest = "delay", type = "float",
+ metavar = "<seconds>", default=0,
+ help="number of seconds to take back [default=system]\
+ default system delay is 3*hopsize/samplerate")
+ parser.add_option("-C","--dcthreshold",
+ metavar = "<value>",
+ action="store", dest="dcthreshold", default=1.,
+ help="onset peak picking DC component [default=1.]")
+ parser.add_option("-L","--localmin",
+ action="store_true", dest="localmin", default=False,
+ help="use local minima after peak detection")
+ parser.add_option("-d","--derivate",
+ action="store_true", dest="derivate", default=False,
+ help="derivate onset detection function")
+ parser.add_option("-z","--zerocross",
+ metavar = "<value>",
+ action="store", dest="zerothres", default=0.008,
+ help="zero-crossing threshold for slicing [default=0.00008]")
+ """
+ # plotting functions
+ """
+ parser.add_option("-p","--plot",
+ action="store_true", dest="plot", default=False,
+ help="draw plot")
+ parser.add_option("-x","--xsize",
+ metavar = "<size>",
+ action="store", dest="xsize", default=1.,
+ type='float', help="define xsize for plot")
+ parser.add_option("-y","--ysize",
+ metavar = "<size>",
+ action="store", dest="ysize", default=1.,
+ type='float', help="define ysize for plot")
+ parser.add_option("-f","--function",
+ action="store_true", dest="func", default=False,
+ help="print detection function")
+ parser.add_option("-n","--no-onsets",
+ action="store_true", dest="nplot", default=False,
+ help="do not plot detected onsets")
+ parser.add_option("-O","--outplot",
+ metavar = "<output_image>",
+ action="store", dest="outplot", default=None,
+ help="save plot to output.{ps,png}")
+ parser.add_option("-F","--spectrogram",
+ action="store_true", dest="spectro", default=False,
+ help="add spectrogram to the plot")
+ """
+ parser.add_option("-o","--output", type = str,
+ metavar = "<outputdir>",
+ action="store", dest="output_directory", default=None,
+ help="specify path where slices of the original file should be created")
+ parser.add_option("--cut-until-nsamples", type = int,
+ metavar = "<samples>",
+ action = "store", dest = "cut_until_nsamples", default = None,
+ help="how many extra samples should be added at the end of each slice")
+ parser.add_option("--cut-until-nslices", type = int,
+ metavar = "<slices>",
+ action = "store", dest = "cut_until_nslices", default = None,
+ help="how many extra slices should be added at the end of each slice")
+
+ parser.add_option("-v","--verbose",
+ action="store_true", dest="verbose", default=True,
+ help="make lots of noise [default]")
+ parser.add_option("-q","--quiet",
+ action="store_false", dest="verbose", default=True,
+ help="be quiet")
+ (options, args) = parser.parse_args()
+ if not options.source_file:
+ import os.path
+ if len(args) == 1:
+ options.source_file = args[0]
+ else:
+ print ("no file name given\n" + usage)
+ sys.exit(1)
+ return options, args
+
+if __name__ == '__main__':
+ options, args = parse_args()
+
+ hopsize = options.hopsize
+ bufsize = options.bufsize
+ samplerate = options.samplerate
+ source_file = options.source_file
+
+ from aubio import onset, tempo, source, sink
+
+ s = source(source_file, samplerate, hopsize)
+ if samplerate == 0: samplerate = s.get_samplerate()
+
+ if options.beat:
+ o = tempo(options.onset_method, bufsize, hopsize)
+ else:
+ o = onset(options.onset_method, bufsize, hopsize)
+ if options.minioi:
+ if options.minioi.endswith('ms'):
+ o.set_minioi_ms(int(options.minioi[:-2]))
+ elif options.minioi.endswith('s'):
+ o.set_minioi_s(int(options.minioi[:-1]))
+ else:
+ o.set_minioi(int(options.minioi))
+ o.set_threshold(options.threshold)
+
+ timestamps = []
+ total_frames = 0
+ # analyze pass
+ while True:
+ samples, read = s()
+ if o(samples):
+ timestamps.append (o.get_last())
+ if options.verbose: print ("%.4f" % o.get_last_s())
+ total_frames += read
+ if read < hopsize: break
+ del s
+ # print some info
+ nstamps = len(timestamps)
+ duration = float (total_frames) / float(samplerate)
+ info = 'found %(nstamps)d timestamps in %(source_file)s' % locals()
+ info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
+ sys.stderr.write(info)
+
+ # cutting pass
+ if options.cut and nstamps > 0:
+ # generate output files
+ from aubio.slicing import slice_source_at_stamps
+ timestamps_end = None
+ if options.cut_until_nslices and options.cut_until_nsamples:
+ print ("warning: using cut_until_nslices, but cut_until_nsamples is set")
+ if options.cut_until_nsamples:
+ timestamps_end = [t + options.cut_until_nsamples for t in timestamps[1:]]
+ timestamps_end += [ 1e120 ]
+ if options.cut_until_nslices:
+ timestamps_end = [t for t in timestamps[1 + options.cut_until_nslices:]]
+ timestamps_end += [ 1e120 ] * (options.cut_until_nslices + 1)
+ slice_source_at_stamps(source_file, timestamps, timestamps_end = timestamps_end,
+ output_dir = options.output_directory,
+ samplerate = samplerate)
+
+ # print some info
+ duration = float (total_frames) / float(samplerate)
+ info = 'created %(nstamps)d slices from %(source_file)s' % locals()
+ info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
+ sys.stderr.write(info)
diff --git a/python/tests/a_weighting_test_simple.expected b/python/tests/a_weighting_test_simple.expected
new file mode 100644
index 0000000..6cd3ff3
--- /dev/null
+++ b/python/tests/a_weighting_test_simple.expected
@@ -0,0 +1,2 @@
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 5.00000000e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.27870563e-01 2.58244342e-01 1.18719361e-01 -4.02623805e-02 -5.61812129e-02 -5.24739734e-02 -4.72329276e-02 -4.23394349e-02 -3.79219586e-02 -3.39473148e-02 -3.03724479e-02 -2.71574847e-02 -2.42664433e-02 -2.16669285e-02 -1.93297810e-02 -1.72287543e-02 -1.53402241e-02 -1.36429261e-02 -1.21177207e-02 -1.07473802e-02
diff --git a/python/tests/c_weighting_test_simple.expected b/python/tests/c_weighting_test_simple.expected
new file mode 100644
index 0000000..70e2b15
--- /dev/null
+++ b/python/tests/c_weighting_test_simple.expected
@@ -0,0 +1,2 @@
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 5.00000000e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.08504281e-01 2.31621372e-01 1.38614617e-01 1.58040475e-02 -9.84900252e-04 -2.72686896e-03 -2.87772967e-03 -2.87932142e-03 -2.86783482e-03 -2.85529016e-03 -2.84270413e-03 -2.83016008e-03 -2.81766458e-03 -2.80521796e-03 -2.79282009e-03 -2.78047079e-03 -2.76816989e-03 -2.75591721e-03 -2.74371257e-03 -2.73155579e-03
diff --git a/python/tests/c_weighting_test_simple_8000.expected b/python/tests/c_weighting_test_simple_8000.expected
new file mode 100644
index 0000000..f34eda6
--- /dev/null
+++ b/python/tests/c_weighting_test_simple_8000.expected
@@ -0,0 +1,2 @@
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 5.00000000e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 3.39108697e-01 2.23441868e-01 -1.31029191e-01 3.33061907e-02 -2.89386407e-02 -1.68524660e-02 -5.02737225e-03 -2.47225074e-02 -3.06670933e-03 -2.20570849e-02 -5.57507292e-03 -1.81342032e-02 -7.89289483e-03 -1.50756531e-02 -9.23565472e-03 -1.29964131e-02 -9.78591684e-03 -1.16053213e-02 -9.84372912e-03 -1.06315198e-02
diff --git a/python/tests/eval_pitch b/python/tests/eval_pitch
new file mode 100755
index 0000000..226b927
--- /dev/null
+++ b/python/tests/eval_pitch
@@ -0,0 +1,143 @@
+#! /usr/bin/env python
+
+"""
+Script to evaluate pitch algorithms against TONAS database.
+
+See http://mtg.upf.edu/download/datasets/tonas/
+
+Example run:
+
+ $ ./eval_pitch /path/to/TONAS/*/*.wav
+ OK: 94.74% vx r: 96.87% vx f: 15.83% f0: 96.02% %12: 0.50% /path/to/TONAS/Deblas/01-D_AMairena.wav
+ OK: 89.89% vx r: 93.21% vx f: 13.81% f0: 90.74% %12: 1.51% /path/to/TONAS/Deblas/02-D_ChanoLobato.wav
+ OK: 96.02% vx r: 96.73% vx f: 10.91% f0: 96.42% %12: 0.00% /path/to/TONAS/Deblas/03-D_Chocolate.wav
+ [...]
+ OK: 82.35% vx r: 95.52% vx f: 67.09% f0: 89.80% %12: 0.95% /path/to/TONAS/Martinetes2/80-M2_Rancapinos.wav
+ OK: 61.97% vx r: 85.71% vx f: 22.03% f0: 55.63% %12: 8.57% /path/to/TONAS/Martinetes2/81-M2_SDonday.wav
+ OK: 75.26% vx r: 91.63% vx f: 27.27% f0: 75.99% %12: 5.05% /path/to/TONAS/Martinetes2/82-M2_TiaAnicalaPiriniaca.wav
+ OK: 82.77% vx r: 92.74% vx f: 38.27% f0: 87.33% %12: 1.67% 69 files, total_length: 1177.69s, total runtime: 25.91s
+
+
+"""
+
+import sys
+import time
+import os.path
+import numpy
+from utils import array_from_text_file, array_from_yaml_file
+from aubio import source, pitch, freqtomidi
+
+start = time.time()
+
+freq_tol = .50 # more or less half a tone
+
+methods = ["default", "yinfft", "mcomb", "yin", "fcomb", "schmitt", "specacf"]
+method = methods[0]
+
+downsample = 1
+tolerance = 0.35
+silence = -40.
+skip = 1
+if method in ["yinfft", "default"]:
+ downsample = 1
+ tolerance = 0.45
+elif method == "mcomb":
+ downsample = 4
+elif method == "yin":
+ downsample = 4
+ tolerance = 0.2
+
+samplerate = 44100 / downsample
+hop_s = 512 / downsample
+win_s = 2048 / downsample
+
+def get_pitches (filename, samplerate = samplerate, win_s = win_s, hop_s = hop_s):
+ s = source(filename, samplerate, hop_s)
+ samplerate = s.samplerate
+
+ p = pitch(method, win_s, hop_s, samplerate)
+ p.set_unit("freq")
+ p.set_tolerance(tolerance)
+ p.set_silence(silence)
+
+ # list of pitches, in samples
+ pitches = []
+
+ # total number of frames read
+ total_frames = 0
+ while True:
+ samples, read = s()
+ new_pitch = p(samples)[0]
+ pitches.append([total_frames/float(samplerate), new_pitch])
+ total_frames += read
+ if read < hop_s: break
+ return numpy.array(pitches)
+
+total_correct_f0, total_correct_sil, total_missed, total_incorrect, total_fp, total_total = 0, 0, 0, 0, 0, 0
+total_correct_chroma, total_voiced = 0, 0
+for source_file in sys.argv[1:]:
+ ground_truth_file = source_file.replace('.wav', '.f0.Corrected')
+ if os.path.isfile(ground_truth_file):
+ ground_truth = array_from_text_file(ground_truth_file)[:,[0,2]]
+ experiment = get_pitches(source_file)
+ # check that we have the same length, more or less one frame
+ assert abs(len(ground_truth) - len(experiment)) < 2
+ # align experiment by skipping first results
+ experiment = experiment[skip:]
+ experiment[:,0] -= experiment[0,0]
+ # trim to shortest list
+ maxlen = min(len(ground_truth), len(experiment))
+ experiment = experiment[:maxlen]
+ ground_truth = ground_truth[:maxlen]
+ # get difference matrix
+ diffmat = abs(experiment - ground_truth)
+ # make sure we got the timing right
+ assert max(diffmat[:,0]) < 10e-4, source_file
+ truth_pitches = freqtomidi(ground_truth[:,1])
+ exper_pitches = freqtomidi(experiment[:,1])
+
+ total = len(truth_pitches)
+ unvoiced = len(truth_pitches[truth_pitches == 0])
+ voiced = total - unvoiced
+ correct_sil, fp, missed, correct_f0, correct_chroma, incorrect = 0, 0, 0, 0, 0, 0
+ for a, b in zip(truth_pitches, exper_pitches):
+ if a == 0 and b == 0:
+ correct_sil += 1
+ elif a == 0 and b != 0:
+ fp += 1
+ elif a != 0 and b == 0:
+ missed += 1
+ elif abs(b - a) < freq_tol:
+ correct_f0 += 1
+ elif abs(b - a) % 12. < freq_tol:
+ correct_chroma += 1
+ else:
+ incorrect += 1
+ assert correct_sil + fp + missed + correct_f0 + correct_chroma + incorrect == total
+ assert unvoiced == correct_sil + fp
+ assert voiced == missed + correct_f0 + correct_chroma + incorrect
+ print "OK: %6s%%" % ("%.2f" % (100. * (correct_f0 + correct_sil) / total )),
+ print "vx r: %6s%%" % ("%.2f" % (100. - 100. * missed / voiced)),
+ print "vx f: %6s%%" % ("%.2f" % (100. * fp / unvoiced)),
+ print "f0: %6s%%" % ("%.2f" % (100. * correct_f0 / voiced)),
+ print "%%12: %6s%%" % ("%.2f" % (100. * correct_chroma / voiced)),
+ print source_file
+ total_correct_sil += correct_sil
+ total_correct_f0 += correct_f0
+ total_correct_chroma += correct_chroma
+ total_missed += missed
+ total_incorrect += incorrect
+ total_fp += fp
+ total_voiced += voiced
+ total_total += total
+ else:
+ print "ERR", "could not find ground_truth_file", ground_truth_file
+
+print "OK: %6s%%" % ("%.2f" % (100. * (total_correct_f0 + total_correct_sil) / total_total )),
+print "vx r: %6s%%" % ("%.2f" % (100. - 100. * total_missed / total_voiced)),
+print "vx f: %6s%%" % ("%.2f" % (100. * (total_fp) / (total_correct_sil + total_fp))),
+print "f0: %6s%%" % ("%.2f" % (100. * total_correct_f0 / total_voiced)),
+print "%%12: %6s%%" % ("%.2f" % (100. * total_correct_chroma / total_voiced)),
+print "%d files," % len(sys.argv[1:]),
+print "total_length: %.2fs," % ((total_total * hop_s) / float(samplerate)),
+print "total runtime: %.2fs" % (time.time() - start)
diff --git a/python/tests/filterbank_mfcc_16000_512.expected b/python/tests/filterbank_mfcc_16000_512.expected
new file mode 100644
index 0000000..aa4ba20
--- /dev/null
+++ b/python/tests/filterbank_mfcc_16000_512.expected
@@ -0,0 +1,40 @@
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00515626 0.01218751 0.01078124 0.00374999 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00421876 0.01125001 0.01171874 0.00468749 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00328126 0.01031251 0.01265624 0.00562499 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00234376 0.00937501 0.01359374 0.00656249 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00140626 0.00843751 0.01453124 0.00749999 0.00046874 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00046876 0.00750001 0.01453126 0.00843749 0.00140624 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00656251 0.01359376 0.00937499 0.00234374 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00562501 0.01265626 0.01031249 0.00328124 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00468751 0.01171876 0.01124999 0.00421874 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00375001 0.01078126 0.01218749 0.00515624 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00281251 0.00984376 0.01312499 0.00609374 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00187840 0.00892239 0.01408455 0.00701501 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00091188 0.00775088 0.01448787 0.00810326 0.00171865 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00004598 0.00600639 0.01196680 0.00950472 0.00394033 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00379635 0.00899103 0.01125415 0.00640461 0.00155507 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00132137 0.00584870 0.01037603 0.00895654 0.00473001 0.00050349 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00268047 0.00662617 0.01057188 0.00779718 0.00411363 0.00043008 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00302916 0.00646796 0.00990677 0.00747278 0.00426245 0.00105212 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00264710 0.00564413 0.00864116 0.00774243 0.00494453 0.00214663 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00175597 0.00436797 0.00697998 0.00841638 0.00597792 0.00353947 0.00110101 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00052989 0.00280633 0.00508277 0.00735922 0.00722144 0.00509625 0.00297106 0.00084587 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00108818 0.00307217 0.00505616 0.00704016 0.00671485 0.00486268 0.00301051 0.00115834 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00104089 0.00277000 0.00449911 0.00622822 0.00670490 0.00509067 0.00347645 0.00186222 0.00024800 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00056452 0.00207149 0.00357847 0.00508544 0.00659241 0.00563323 0.00422638 0.00281953 0.00141268 0.00000583 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00111160 0.00242497 0.00373835 0.00505172 0.00636509 0.00514952 0.00392340 0.00269729 0.00147118 0.00024507 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00113990 0.00228455 0.00342919 0.00457384 0.00571849 0.00509226 0.00402367 0.00295507 0.00188648 0.00081788 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00079820 0.00179580 0.00279339 0.00379099 0.00478858 0.00533362 0.00440231 0.00347100 0.00253968 0.00160837 0.00067706 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00020398 0.00107342 0.00194286 0.00281229 0.00368173 0.00455116 0.00496164 0.00414997 0.00333830 0.00252663 0.00171496 0.00090330 0.00009163 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00020687 0.00096461 0.00172235 0.00248009 0.00323783 0.00399557 0.00475331 0.00421131 0.00350392 0.00279652 0.00208913 0.00138173 0.00067434 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00058584 0.00124624 0.00190663 0.00256703 0.00322742 0.00388782 0.00448854 0.00387202 0.00325551 0.00263899 0.00202247 0.00140596 0.00078944 0.00017292 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00002690 0.00060245 0.00117800 0.00175356 0.00232911 0.00290467 0.00348022 0.00405578 0.00383061 0.00329329 0.00275598 0.00221866 0.00168135 0.00114404 0.00060672 0.00006941 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00036092 0.00086253 0.00136415 0.00186576 0.00236737 0.00286899 0.00337060 0.00387221 0.00352922 0.00306093 0.00259265 0.00212436 0.00165608 0.00118779 0.00071951 0.00025122 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00038070 0.00081787 0.00125504 0.00169221 0.00212939 0.00256656 0.00300373 0.00344090 0.00348625 0.00307813 0.00267000 0.00226188 0.00185375 0.00144562 0.00103750 0.00062937 0.00022125 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00017661 0.00055762 0.00093863 0.00131964 0.00170064 0.00208165 0.00246266 0.00284367 0.00322468 0.00326836 0.00291267 0.00255697 0.00220128 0.00184558 0.00148989 0.00113419 0.00077850 0.00042281 0.00006711 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00015205 0.00048411 0.00081617 0.00114823 0.00148029 0.00181235 0.00214442 0.00247648 0.00280854 0.00314060 0.00295174 0.00264175 0.00233175 0.00202175 0.00171175 0.00140175 0.00109175 0.00078176 0.00047176 0.00016176 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00023480 0.00052420 0.00081360 0.00110300 0.00139240 0.00168181 0.00197121 0.00226061 0.00255001 0.00283941 0.00286123 0.00259105 0.00232088 0.00205071 0.00178053 0.00151036 0.00124019 0.00097001 0.00069984 0.00042967 0.00015949 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00012061 0.00037283 0.00062506 0.00087728 0.00112950 0.00138173 0.00163395 0.00188617 0.00213839 0.00239062 0.00264284 0.00269527 0.00245981 0.00222434 0.00198888 0.00175341 0.00151795 0.00128249 0.00104702 0.00081156 0.00057609 0.00034063 0.00010516 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00009005 0.00030987 0.00052969 0.00074951 0.00096933 0.00118915 0.00140897 0.00162879 0.00184861 0.00206843 0.00228825 0.00250807 0.00249269 0.00228747 0.00208226 0.00187704 0.00167183 0.00146661 0.00126140 0.00105618 0.00085097 0.00064575 0.00044054 0.00023532 0.00003011 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00010602 0.00029760 0.00048918 0.00068076 0.00087234 0.00106392 0.00125550 0.00144708 0.00163866 0.00183024 0.00202182 0.00221340 0.00240498 0.00228047 0.00210162 0.00192277 0.00174392 0.00156507 0.00138622 0.00120737 0.00102852 0.00084967 0.00067081 0.00049196 0.00031311 0.00013426 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00014247 0.00030944 0.00047641 0.00064337 0.00081034 0.00097731 0.00114428 0.00131125 0.00147821 0.00164518 0.00181215 0.00197912 0.00214608 0.00223256 0.00207669 0.00192082 0.00176494 0.00160907 0.00145319 0.00129732 0.00114144 0.00098557 0.00082970 0.00067382 0.00051795 0.00036207 0.00020620 0.00005033 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
diff --git a/python/tests/run_all_tests b/python/tests/run_all_tests
new file mode 100755
index 0000000..bc6bb8c
--- /dev/null
+++ b/python/tests/run_all_tests
@@ -0,0 +1,5 @@
+#! /usr/bin/env python
+
+if __name__ == '__main__':
+ import nose2.main
+ nose2.discover()
diff --git a/python/tests/test_aubio.py b/python/tests/test_aubio.py
new file mode 100755
index 0000000..cac8397
--- /dev/null
+++ b/python/tests/test_aubio.py
@@ -0,0 +1,14 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+
+class aubiomodule_test_case(TestCase):
+
+ def test_import(self):
+ """ try importing aubio """
+ import aubio
+
+if __name__ == '__main__':
+ main()
+
diff --git a/python/tests/test_cvec.py b/python/tests/test_cvec.py
new file mode 100755
index 0000000..53bf8df
--- /dev/null
+++ b/python/tests/test_cvec.py
@@ -0,0 +1,145 @@
+#! /usr/bin/env python
+
+from unittest import main
+import numpy as np
+from numpy.testing import TestCase, assert_equal
+from aubio import cvec, fvec, float_type
+
+wrong_type = 'float32' if float_type == 'float64' else 'float64'
+
+class aubio_cvec_test_case(TestCase):
+
+ def test_vector_created_with_zeroes(self):
+ a = cvec(10)
+ assert_equal(a.norm.shape[0], 10 / 2 + 1)
+ assert_equal(a.phas.shape[0], 10 / 2 + 1)
+ _ = a.norm[0]
+ assert_equal(a.norm, 0.)
+ assert_equal(a.phas, 0.)
+
+ def test_vector_assign_element(self):
+ a = cvec()
+ a.norm[0] = 1
+ assert_equal(a.norm[0], 1)
+ a.phas[0] = 1
+ assert_equal(a.phas[0], 1)
+
+ def test_vector_assign_element_end(self):
+ a = cvec()
+ a.norm[-1] = 1
+ assert_equal(a.norm[-1], 1)
+ assert_equal(a.norm[len(a.norm)-1], 1)
+ a.phas[-1] = 1
+ assert_equal(a.phas[-1], 1)
+ assert_equal(a.phas[len(a.phas)-1], 1)
+
+ def test_assign_cvec_norm_slice(self):
+ spec = cvec(1024)
+ spec.norm[40:100] = 100
+ assert_equal(spec.norm[0:40], 0)
+ assert_equal(spec.norm[40:100], 100)
+ assert_equal(spec.norm[100:-1], 0)
+ assert_equal(spec.phas, 0)
+
+ def test_assign_cvec_phas_slice(self):
+ spec = cvec(1024)
+ spec.phas[39:-1] = -np.pi
+ assert_equal(spec.phas[0:39], 0)
+ assert_equal(spec.phas[39:-1], -np.pi)
+ assert_equal(spec.norm, 0)
+
+ def test_assign_cvec_with_other_cvec(self):
+ """ check dest cvec is still reachable after source was deleted """
+ spec = cvec(1024)
+ a = np.random.rand(1024//2+1).astype(float_type)
+ b = np.random.rand(1024//2+1).astype(float_type)
+ spec.norm = a
+ spec.phas = b
+ new_spec = spec
+ del spec
+ assert_equal(a, new_spec.norm)
+ assert_equal(b, new_spec.phas)
+ assert_equal(id(a), id(new_spec.norm))
+ assert_equal(id(b), id(new_spec.phas))
+
+ def test_pass_to_numpy(self):
+ spec = cvec(1024)
+ norm = spec.norm
+ phas = spec.phas
+ del spec
+ new_spec = cvec(1024)
+ new_spec.norm = norm
+ new_spec.phas = phas
+ assert_equal(norm, new_spec.norm)
+ assert_equal(phas, new_spec.phas)
+ assert_equal(id(norm), id(new_spec.norm))
+ assert_equal(id(phas), id(new_spec.phas))
+ del norm
+ del phas
+ assert_equal(new_spec.norm, 0.)
+ assert_equal(new_spec.phas, 0.)
+ del new_spec
+
+ def test_assign_norm_too_large(self):
+ a = cvec(512)
+ b = fvec(512//2+1 + 4)
+ with self.assertRaises(ValueError):
+ a.norm = b
+
+ def test_assign_norm_too_small(self):
+ a = cvec(512)
+ b = fvec(512//2+1 - 4)
+ with self.assertRaises(ValueError):
+ a.norm = b
+
+ def test_assign_phas_too_large(self):
+ a = cvec(512)
+ b = fvec(512//2+1 + 4)
+ with self.assertRaises(ValueError):
+ a.phas = b
+
+ def test_assign_phas_too_small(self):
+ a = cvec(512)
+ b = fvec(512//2+1 - 4)
+ with self.assertRaises(ValueError):
+ a.phas = b
+
+ def test_cvec_repr(self):
+ win_s = 512
+ c = cvec(win_s)
+ expected_repr = "aubio cvec of {:d} elements".format(win_s//2+1)
+ self.assertEqual(repr(c), expected_repr)
+
+class aubio_cvec_wrong_norm_input(TestCase):
+
+ def test_wrong_length(self):
+ with self.assertRaises(ValueError):
+ cvec(-1)
+
+ def test_set_norm_with_scalar(self):
+ a = cvec(512)
+ with self.assertRaises(ValueError):
+ a.norm = 1
+
+ def test_set_norm_with_scalar_array(self):
+ a = cvec(512)
+ with self.assertRaises(ValueError):
+ a.norm = np.ndarray(1, dtype = 'int')
+
+ def test_set_norm_with_int_array(self):
+ a = cvec(512)
+ with self.assertRaises(ValueError):
+ a.norm = np.zeros(512//2+1, dtype = 'int')
+
+ def test_set_norm_with_wrong_float_array(self):
+ a = cvec(512)
+ with self.assertRaises(ValueError):
+ a.norm = np.zeros(512//2+1, dtype = wrong_type)
+
+ def test_set_norm_with_wrong_2d_array(self):
+ a = cvec(512)
+ with self.assertRaises(ValueError):
+ a.norm = np.zeros((512//2+1, 2), dtype = float_type)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_fft.py b/python/tests/test_fft.py
new file mode 100755
index 0000000..fa349e5
--- /dev/null
+++ b/python/tests/test_fft.py
@@ -0,0 +1,188 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+from numpy.testing import assert_equal, assert_almost_equal
+import numpy as np
+from aubio import fvec, fft, cvec
+from math import pi, floor
+from random import random
+
+class aubio_fft_test_case(TestCase):
+
+ def test_members(self):
+ """ check members are set correctly """
+ win_s = 2048
+ f = fft(win_s)
+ assert_equal (f.win_s, win_s)
+
+ def test_output_dimensions(self):
+ """ check the dimensions of output """
+ win_s = 1024
+ timegrain = fvec(win_s)
+ f = fft (win_s)
+ fftgrain = f (timegrain)
+ del f
+ assert_equal (fftgrain.norm.shape, (win_s/2+1,))
+ assert_equal (fftgrain.phas.shape, (win_s/2+1,))
+
+ def test_zeros(self):
+ """ check the transform of zeros is all zeros """
+ win_s = 512
+ timegrain = fvec(win_s)
+ f = fft (win_s)
+ fftgrain = f (timegrain)
+ assert_equal ( fftgrain.norm, 0 )
+ assert_equal ( fftgrain.phas, 0 )
+
+ def test_impulse(self):
+ """ check the transform of one impulse at a random place """
+ win_s = 256
+ i = int(floor(random()*win_s))
+ impulse = pi * random()
+ f = fft(win_s)
+ timegrain = fvec(win_s)
+ timegrain[i] = impulse
+ fftgrain = f ( timegrain )
+ #self.plot_this ( fftgrain.phas )
+ assert_almost_equal ( fftgrain.norm, impulse, decimal = 6 )
+ assert_equal ( fftgrain.phas <= pi, True)
+ assert_equal ( fftgrain.phas >= -pi, True)
+
+ def test_impulse_negative(self):
+ """ check the transform of a negative impulse at a random place """
+ win_s = 256
+ i = int(floor(random()*win_s))
+ impulse = -.1
+ f = fft(win_s)
+ timegrain = fvec(win_s)
+ timegrain[0] = 0
+ timegrain[i] = impulse
+ fftgrain = f ( timegrain )
+ #self.plot_this ( fftgrain.phas )
+ assert_almost_equal ( fftgrain.norm, abs(impulse), decimal = 5 )
+ if impulse < 0:
+ # phase can be pi or -pi, as it is not unwrapped
+ #assert_almost_equal ( abs(fftgrain.phas[1:-1]) , pi, decimal = 6 )
+ assert_almost_equal ( fftgrain.phas[0], pi, decimal = 6)
+ assert_almost_equal ( np.fmod(fftgrain.phas[-1], pi), 0, decimal = 6)
+ else:
+ #assert_equal ( fftgrain.phas[1:-1] == 0, True)
+ assert_equal ( fftgrain.phas[0], 0)
+ assert_almost_equal ( np.fmod(fftgrain.phas[-1], pi), 0, decimal = 6)
+ # now check the resynthesis
+ synthgrain = f.rdo ( fftgrain )
+ #self.plot_this ( fftgrain.phas.T )
+ assert_equal ( fftgrain.phas <= pi, True)
+ assert_equal ( fftgrain.phas >= -pi, True)
+ #self.plot_this ( synthgrain - timegrain )
+ assert_almost_equal ( synthgrain, timegrain, decimal = 6 )
+
+ def test_impulse_at_zero(self):
+ """ check the transform of one impulse at a index 0 """
+ win_s = 1024
+ impulse = pi
+ f = fft(win_s)
+ timegrain = fvec(win_s)
+ timegrain[0] = impulse
+ fftgrain = f ( timegrain )
+ #self.plot_this ( fftgrain.phas )
+ assert_equal ( fftgrain.phas[0], 0)
+ # could be 0 or -0 depending on fft implementation (0 for fftw3, -0 for ooura)
+ assert_almost_equal ( fftgrain.phas[1], 0)
+ assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
+
+ def test_rdo_before_do(self):
+ """ check running fft.rdo before fft.do works """
+ win_s = 1024
+ f = fft(win_s)
+ fftgrain = cvec(win_s)
+ t = f.rdo( fftgrain )
+ assert_equal ( t, 0 )
+
+ def plot_this(self, this):
+ from pylab import plot, show
+ plot ( this )
+ show ()
+
+ def test_local_fftgrain(self):
+ """ check aubio.fft() result can be accessed after deletion """
+ def compute_grain(impulse):
+ win_s = 1024
+ timegrain = fvec(win_s)
+ timegrain[0] = impulse
+ f = fft(win_s)
+ fftgrain = f ( timegrain )
+ return fftgrain
+ impulse = pi
+ fftgrain = compute_grain(impulse)
+ assert_equal ( fftgrain.phas[0], 0)
+ assert_almost_equal ( fftgrain.phas[1], 0)
+ assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
+
+ def test_local_reconstruct(self):
+ """ check aubio.fft.rdo() result can be accessed after deletion """
+ def compute_grain(impulse):
+ win_s = 1024
+ timegrain = fvec(win_s)
+ timegrain[0] = impulse
+ f = fft(win_s)
+ fftgrain = f ( timegrain )
+ r = f.rdo(fftgrain)
+ return r
+ impulse = pi
+ r = compute_grain(impulse)
+ assert_almost_equal ( r[0], impulse, decimal = 6)
+ assert_almost_equal ( r[1:], 0)
+
+ def test_large_input_timegrain(self):
+ win_s = 1024
+ f = fft(win_s)
+ t = fvec(win_s + 1)
+ with self.assertRaises(ValueError):
+ f(t)
+
+ def test_small_input_timegrain(self):
+ win_s = 1024
+ f = fft(win_s)
+ t = fvec(1)
+ with self.assertRaises(ValueError):
+ f(t)
+
+ def test_large_input_fftgrain(self):
+ win_s = 1024
+ f = fft(win_s)
+ s = cvec(win_s + 5)
+ with self.assertRaises(ValueError):
+ f.rdo(s)
+
+ def test_small_input_fftgrain(self):
+ win_s = 1024
+ f = fft(win_s)
+ s = cvec(16)
+ with self.assertRaises(ValueError):
+ f.rdo(s)
+
+class aubio_fft_wrong_params(TestCase):
+
+ def test_wrong_buf_size(self):
+ win_s = -1
+ with self.assertRaises(ValueError):
+ fft(win_s)
+
+ def test_buf_size_not_power_of_two(self):
+ # when compiled with fftw3, aubio supports non power of two fft sizes
+ win_s = 320
+ try:
+ with self.assertRaises(RuntimeError):
+ fft(win_s)
+ except AssertionError:
+ self.skipTest('creating aubio.fft with size %d did not fail' % win_s)
+
+ def test_buf_size_too_small(self):
+ win_s = 1
+ with self.assertRaises(RuntimeError):
+ fft(win_s)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_filter.py b/python/tests/test_filter.py
new file mode 100755
index 0000000..eae8c18
--- /dev/null
+++ b/python/tests/test_filter.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import fvec, digital_filter
+from utils import array_from_text_file
+
+class aubio_filter_test_case(TestCase):
+
+ def test_members(self):
+ f = digital_filter()
+ assert_equal (f.order, 7)
+ f = digital_filter(5)
+ assert_equal (f.order, 5)
+ f(fvec())
+
+ def test_cweighting_error(self):
+ f = digital_filter (2)
+ self.assertRaises ( ValueError, f.set_c_weighting, 44100 )
+ f = digital_filter (8)
+ self.assertRaises ( ValueError, f.set_c_weighting, 44100 )
+ f = digital_filter (5)
+ self.assertRaises ( ValueError, f.set_c_weighting, 4000 )
+ f = digital_filter (5)
+ self.assertRaises ( ValueError, f.set_c_weighting, 193000 )
+ f = digital_filter (7)
+ self.assertRaises ( ValueError, f.set_a_weighting, 193000 )
+ f = digital_filter (5)
+ self.assertRaises ( ValueError, f.set_a_weighting, 192000 )
+
+ def test_c_weighting(self):
+ expected = array_from_text_file('c_weighting_test_simple.expected')
+ f = digital_filter(5)
+ f.set_c_weighting(44100)
+ v = fvec(32)
+ v[12] = .5
+ u = f(v)
+ assert_almost_equal (expected[1], u)
+
+ def test_c_weighting_8000(self):
+ expected = array_from_text_file('c_weighting_test_simple_8000.expected')
+ f = digital_filter(5)
+ f.set_c_weighting(8000)
+ v = fvec(32)
+ v[12] = .5
+ u = f(v)
+ assert_almost_equal (expected[1], u)
+
+ def test_a_weighting(self):
+ expected = array_from_text_file('a_weighting_test_simple.expected')
+ f = digital_filter(7)
+ f.set_a_weighting(44100)
+ v = fvec(32)
+ v[12] = .5
+ u = f(v)
+ assert_almost_equal (expected[1], u)
+
+ def test_a_weighting_parted(self):
+ expected = array_from_text_file('a_weighting_test_simple.expected')
+ f = digital_filter(7)
+ f.set_a_weighting(44100)
+ v = fvec(16)
+ v[12] = .5
+ u = f(v)
+ assert_almost_equal (expected[1][:16], u)
+ # one more time
+ v = fvec(16)
+ u = f(v)
+ assert_almost_equal (expected[1][16:], u)
+
+ def test_set_biquad(self):
+ f = digital_filter(3)
+ f.set_biquad(0., 0., 0, 0., 0.)
+
+ def test_set_biquad_wrong_order(self):
+ f = digital_filter(4)
+ with self.assertRaises(ValueError):
+ f.set_biquad(0., 0., 0, 0., 0.)
+
+class aubio_filter_wrong_params(TestCase):
+
+ def test_negative_order(self):
+ with self.assertRaises(ValueError):
+ digital_filter(-1)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_filterbank.py b/python/tests/test_filterbank.py
new file mode 100755
index 0000000..cc6e66e
--- /dev/null
+++ b/python/tests/test_filterbank.py
@@ -0,0 +1,84 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+from numpy.testing import assert_equal, assert_almost_equal
+import numpy as np
+from aubio import cvec, filterbank, float_type
+from utils import array_from_text_file
+
+class aubio_filterbank_test_case(TestCase):
+
+ def test_members(self):
+ f = filterbank(40, 512)
+ assert_equal ([f.n_filters, f.win_s], [40, 512])
+
+ def test_set_coeffs(self):
+ f = filterbank(40, 512)
+ r = np.random.random([40, int(512 / 2) + 1]).astype(float_type)
+ f.set_coeffs(r)
+ assert_equal (r, f.get_coeffs())
+
+ def test_phase(self):
+ f = filterbank(40, 512)
+ c = cvec(512)
+ c.phas[:] = np.pi
+ assert_equal( f(c), 0);
+
+ def test_norm(self):
+ f = filterbank(40, 512)
+ c = cvec(512)
+ c.norm[:] = 1
+ assert_equal( f(c), 0);
+
+ def test_random_norm(self):
+ f = filterbank(40, 512)
+ c = cvec(512)
+ c.norm[:] = np.random.random((int(512 / 2) + 1,)).astype(float_type)
+ assert_equal( f(c), 0)
+
+ def test_random_coeffs(self):
+ win_s = 128
+ f = filterbank(40, win_s)
+ c = cvec(win_s)
+ r = np.random.random([40, int(win_s / 2) + 1]).astype(float_type)
+ r /= r.sum()
+ f.set_coeffs(r)
+ c.norm[:] = np.random.random((int(win_s / 2) + 1,)).astype(float_type)
+ assert_equal ( f(c) < 1., True )
+ assert_equal ( f(c) > 0., True )
+
+ def test_mfcc_coeffs(self):
+ f = filterbank(40, 512)
+ c = cvec(512)
+ f.set_mel_coeffs_slaney(44100)
+ c.norm[:] = np.random.random((int(512 / 2) + 1,)).astype(float_type)
+ assert_equal ( f(c) < 1., True )
+ assert_equal ( f(c) > 0., True )
+
+ def test_mfcc_coeffs_16000(self):
+ expected = array_from_text_file('filterbank_mfcc_16000_512.expected')
+ f = filterbank(40, 512)
+ f.set_mel_coeffs_slaney(16000)
+ assert_almost_equal ( expected, f.get_coeffs() )
+
+class aubio_filterbank_wrong_values(TestCase):
+
+ def test_negative_window(self):
+ self.assertRaises(ValueError, filterbank, 40, -20)
+
+ def test_negative_filters(self):
+ self.assertRaises(ValueError, filterbank, -40, 1024)
+
+ def test_filterbank_long_cvec(self):
+ f = filterbank(40, 512)
+ with self.assertRaises(ValueError):
+ f(cvec(1024))
+
+ def test_filterbank_short_cvec(self):
+ f = filterbank(40, 512)
+ with self.assertRaises(ValueError):
+ f(cvec(256))
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_filterbank_mel.py b/python/tests/test_filterbank_mel.py
new file mode 100755
index 0000000..1ce38e9
--- /dev/null
+++ b/python/tests/test_filterbank_mel.py
@@ -0,0 +1,49 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+from numpy.testing import assert_equal, assert_almost_equal
+from numpy import array, shape
+from aubio import cvec, filterbank, float_type
+
+class aubio_filterbank_mel_test_case(TestCase):
+
+ def test_slaney(self):
+ f = filterbank(40, 512)
+ f.set_mel_coeffs_slaney(16000)
+ a = f.get_coeffs()
+ assert_equal(shape (a), (40, 512/2 + 1) )
+
+ def test_other_slaney(self):
+ f = filterbank(40, 512*2)
+ f.set_mel_coeffs_slaney(44100)
+ _ = f.get_coeffs()
+ #print "sum is", sum(sum(a))
+ for win_s in [256, 512, 1024, 2048, 4096]:
+ f = filterbank(40, win_s)
+ f.set_mel_coeffs_slaney(32000)
+ _ = f.get_coeffs()
+ #print "sum is", sum(sum(a))
+
+ def test_triangle_freqs_zeros(self):
+ f = filterbank(9, 1024)
+ freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
+ freqs = array(freq_list, dtype = float_type)
+ f.set_triangle_bands(freqs, 48000)
+ _ = f.get_coeffs().T
+ assert_equal ( f(cvec(1024)), 0)
+
+ def test_triangle_freqs_ones(self):
+ f = filterbank(9, 1024)
+ freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
+ freqs = array(freq_list, dtype = float_type)
+ f.set_triangle_bands(freqs, 48000)
+ _ = f.get_coeffs().T
+ spec = cvec(1024)
+ spec.norm[:] = 1
+ assert_almost_equal ( f(spec),
+ [ 0.02070313, 0.02138672, 0.02127604, 0.02135417,
+ 0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345])
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_fvec.py b/python/tests/test_fvec.py
new file mode 100755
index 0000000..4ea5533
--- /dev/null
+++ b/python/tests/test_fvec.py
@@ -0,0 +1,143 @@
+#! /usr/bin/env python
+
+from unittest import main
+import numpy as np
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import fvec, zero_crossing_rate, alpha_norm, min_removal
+from aubio import float_type
+
+wrong_type = 'float32' if float_type == 'float64' else 'float64'
+
+default_size = 512
+
+class aubio_fvec_test_case(TestCase):
+
+ def test_vector_created_with_zeroes(self):
+ a = fvec(10)
+ assert a.dtype == float_type
+ assert a.shape == (10,)
+ assert_equal(a, 0)
+
+ def test_vector_create_with_list(self):
+ a = fvec([0, 1, 2, 3])
+ assert a.dtype == float_type
+ assert a.shape == (4,)
+ assert_equal(list(range(4)), a)
+
+ def test_vector_assign_element(self):
+ a = fvec(default_size)
+ a[0] = 1
+ assert_equal(a[0], 1)
+
+ def test_vector_assign_element_end(self):
+ a = fvec(default_size)
+ a[-1] = 1
+ assert_equal(a[-1], 1)
+ assert_equal(a[len(a)-1], 1)
+
+ def test_vector(self):
+ a = fvec()
+ len(a)
+ _ = a[0]
+ np.array(a)
+ a = fvec(1)
+ a = fvec(10)
+ _ = a.T
+
+class aubio_fvec_wrong_values(TestCase):
+
+ def test_negative_length(self):
+ """ test creating fvec with negative length fails (pure python) """
+ self.assertRaises(ValueError, fvec, -10)
+
+ def test_zero_length(self):
+ """ test creating fvec with zero length fails (pure python) """
+ self.assertRaises(ValueError, fvec, 0)
+
+ def test_out_of_bound(self):
+ """ test assiging fvec out of bounds fails (pure python) """
+ a = fvec(2)
+ self.assertRaises(IndexError, a.__getitem__, 3)
+ self.assertRaises(IndexError, a.__getitem__, 2)
+
+class aubio_wrong_fvec_input(TestCase):
+ """ uses min_removal to test PyAubio_IsValidVector """
+
+ def test_no_input(self):
+ self.assertRaises(TypeError, min_removal)
+
+ def test_none(self):
+ self.assertRaises(ValueError, min_removal, None)
+
+ def test_wrong_scalar(self):
+ a = np.array(10, dtype=float_type)
+ self.assertRaises(ValueError, min_removal, a)
+
+ def test_wrong_dimensions(self):
+ a = np.array([[[1, 2], [3, 4]]], dtype=float_type)
+ self.assertRaises(ValueError, min_removal, a)
+
+ def test_wrong_array_size(self):
+ x = np.array([], dtype=float_type)
+ self.assertRaises(ValueError, min_removal, x)
+
+ def test_wrong_type(self):
+ a = np.zeros(10, dtype=wrong_type)
+ self.assertRaises(ValueError, min_removal, a)
+
+ def test_wrong_list_input(self):
+ self.assertRaises(ValueError, min_removal, [0., 1.])
+
+ def test_good_input(self):
+ a = np.zeros(10, dtype=float_type)
+ assert_equal(np.zeros(10, dtype=float_type), min_removal(a))
+
+class aubio_alpha_norm(TestCase):
+
+ def test_alpha_norm_of_random(self):
+ x = np.random.rand(1024).astype(float_type)
+ alpha = np.random.rand() * 5.
+ x_alpha_norm = (np.sum(np.abs(x)**alpha)/len(x))**(1/alpha)
+ assert_almost_equal(alpha_norm(x, alpha), x_alpha_norm, decimal = 5)
+
+class aubio_zero_crossing_rate_test(TestCase):
+
+ def test_zero_crossing_rate(self):
+ a = np.array([0, 1, -1], dtype=float_type)
+ assert_almost_equal(zero_crossing_rate(a), 1./3.)
+
+ def test_zero_crossing_rate_zeros(self):
+ a = np.zeros(100, dtype=float_type)
+ self.assertEqual(zero_crossing_rate(a), 0)
+
+ def test_zero_crossing_rate_minus_ones(self):
+ a = np.ones(100, dtype=float_type)
+ self.assertEqual(zero_crossing_rate(a), 0)
+
+ def test_zero_crossing_rate_plus_ones(self):
+ a = np.ones(100, dtype=float_type)
+ self.assertEqual(zero_crossing_rate(a), 0)
+
+class aubio_fvec_min_removal(TestCase):
+
+ def test_fvec_min_removal_of_array(self):
+ a = np.array([20, 1, 19], dtype=float_type)
+ b = min_removal(a)
+ assert_equal(b, [19, 0, 18])
+
+class aubio_fvec_test_memory(TestCase):
+
+ def test_pass_to_numpy(self):
+ a = fvec(10)
+ a[:] = 1.
+ b = a
+ del a
+ assert_equal(b, 1.)
+ c = fvec(10)
+ c = b
+ del b
+ assert_equal(c, 1.)
+ del c
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_mathutils.py b/python/tests/test_mathutils.py
new file mode 100755
index 0000000..f68fb11
--- /dev/null
+++ b/python/tests/test_mathutils.py
@@ -0,0 +1,104 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal
+from numpy import array, arange, isnan, isinf
+from aubio import bintomidi, miditobin, freqtobin, bintofreq, freqtomidi, miditofreq
+from aubio import unwrap2pi
+from aubio import fvec
+from math import pi
+
+class aubio_mathutils(TestCase):
+
+ def test_unwrap2pi(self):
+ unwrap2pi(int(23))
+ unwrap2pi(float(23.))
+ unwrap2pi(int(23.))
+ unwrap2pi(arange(10))
+ unwrap2pi(arange(10).astype("int"))
+ unwrap2pi(arange(10).astype("float"))
+ unwrap2pi(arange(10).astype("float32"))
+ unwrap2pi([1,3,5])
+ unwrap2pi([23.,24.,25.])
+ a = fvec(10)
+ a[:] = 4.
+ unwrap2pi(a)
+ a = pi/100. * arange(-600,600).astype("float")
+ unwrap2pi(a)
+ #print zip(a, b)
+
+ def test_unwrap2pi_fails_on_list(self):
+ with self.assertRaises((TypeError, NotImplementedError)):
+ unwrap2pi(["23.","24.",25.])
+
+ def test_unwrap2pi_takes_fvec(self):
+ a = fvec(10)
+ b = unwrap2pi(a)
+ #print zip(a, b)
+ assert ( b > -pi ).all()
+ assert ( b <= pi ).all()
+
+ def test_unwrap2pi_takes_array_of_float(self):
+ a = arange(-10., 10.).astype("float")
+ b = unwrap2pi(a)
+ #print zip(a, b)
+ assert ( b > -pi ).all()
+ assert ( b <= pi ).all()
+
+ def test_unwrap2pi_takes_array_of_float32(self):
+ a = arange(-10, 10).astype("float32")
+ b = unwrap2pi(a)
+ #print zip(a, b)
+ assert ( b > -pi ).all()
+ assert ( b <= pi ).all()
+
+ def test_freqtomidi(self):
+ a = array(list(range(-20, 50000, 100)) + [ -1e32, 1e32 ])
+ b = freqtomidi(a)
+ #print zip(a, b)
+ assert_equal ( isnan(array(b)), False )
+ assert_equal ( isinf(array(b)), False )
+ assert_equal ( array(b) < 0, False )
+
+ def test_miditofreq(self):
+ a = list(range(-30, 200)) + [-100000, 10000]
+ b = miditofreq(a)
+ #print zip(a, b)
+ assert_equal ( isnan(b), False )
+ assert_equal ( isinf(b), False )
+ assert_equal ( b < 0, False )
+
+ def test_miditobin(self):
+ a = list(range(-30, 200)) + [-100000, 10000]
+ b = [ miditobin(x, 44100, 512) for x in a ]
+ #print zip(a, b)
+ assert_equal ( isnan(array(b)), False )
+ assert_equal ( isinf(array(b)), False )
+ assert_equal ( array(b) < 0, False )
+
+ def test_bintomidi(self):
+ a = list(range(-100, 512))
+ b = [ bintomidi(x, 44100, 512) for x in a ]
+ #print zip(a, b)
+ assert_equal ( isnan(array(b)), False )
+ assert_equal ( isinf(array(b)), False )
+ assert_equal ( array(b) < 0, False )
+
+ def test_freqtobin(self):
+ a = list(range(-20, 50000, 100)) + [ -1e32, 1e32 ]
+ b = [ freqtobin(x, 44100, 512) for x in a ]
+ #print zip(a, b)
+ assert_equal ( isnan(array(b)), False )
+ assert_equal ( isinf(array(b)), False )
+ assert_equal ( array(b) < 0, False )
+
+ def test_bintofreq(self):
+ a = list(range(-20, 148))
+ b = [ bintofreq(x, 44100, 512) for x in a ]
+ #print zip(a, b)
+ assert_equal ( isnan(array(b)), False )
+ assert_equal ( isinf(array(b)), False )
+ assert_equal ( array(b) < 0, False )
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_mfcc.py b/python/tests/test_mfcc.py
new file mode 100755
index 0000000..e7f3b18
--- /dev/null
+++ b/python/tests/test_mfcc.py
@@ -0,0 +1,114 @@
+#! /usr/bin/env python
+
+from nose2 import main
+from nose2.tools import params
+from numpy import random, count_nonzero
+from numpy.testing import TestCase
+from aubio import mfcc, cvec, float_type
+
+buf_size = 2048
+n_filters = 40
+n_coeffs = 13
+samplerate = 44100
+
+
+new_params = ['buf_size', 'n_filters', 'n_coeffs', 'samplerate']
+new_deflts = [1024, 40, 13, 44100]
+
+class aubio_mfcc(TestCase):
+
+ def setUp(self):
+ self.o = mfcc()
+
+ def test_default_creation(self):
+ pass
+
+ def test_delete(self):
+ del self.o
+
+ @params(*new_params)
+ def test_read_only_member(self, name):
+ o = self.o
+ with self.assertRaises((TypeError, AttributeError)):
+ setattr(o, name, 0)
+
+ @params(*zip(new_params, new_deflts))
+ def test_default_param(self, name, expected):
+ """ test mfcc.{:s} = {:d} """.format(name, expected)
+ o = self.o
+ self.assertEqual( getattr(o, name), expected)
+
+class aubio_mfcc_wrong_params(TestCase):
+
+ def test_wrong_buf_size(self):
+ with self.assertRaises(ValueError):
+ mfcc(buf_size = -1)
+
+ def test_wrong_n_filters(self):
+ with self.assertRaises(ValueError):
+ mfcc(n_filters = -1)
+
+ def test_wrong_n_coeffs(self):
+ with self.assertRaises(ValueError):
+ mfcc(n_coeffs = -1)
+
+ def test_wrong_samplerate(self):
+ with self.assertRaises(ValueError):
+ mfcc(samplerate = -1)
+
+ def test_wrong_input_size(self):
+ m = mfcc(buf_size = 1024)
+ with self.assertRaises(ValueError):
+ m(cvec(512))
+
+class aubio_mfcc_compute(TestCase):
+
+ def test_members(self):
+
+ o = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+ #assert_equal ([o.buf_size, o.method], [buf_size, method])
+
+ spec = cvec(buf_size)
+ #spec.norm[0] = 1
+ #spec.norm[1] = 1./2.
+ #print "%20s" % method, str(o(spec))
+ coeffs = o(spec)
+ self.assertEqual(coeffs.size, n_coeffs)
+ #print coeffs
+ spec.norm = random.random_sample((len(spec.norm),)).astype(float_type)
+ spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+ #print "%20s" % method, str(o(spec))
+ self.assertEqual(count_nonzero(o(spec) != 0.), n_coeffs)
+ #print coeffs
+
+
+class aubio_mfcc_all_parameters(TestCase):
+
+ @params(
+ (2048, 40, 13, 44100),
+ (1024, 40, 13, 44100),
+ (512, 40, 13, 44100),
+ (512, 40, 13, 16000),
+ (256, 40, 13, 16000),
+ (128, 40, 13, 16000),
+ (128, 40, 12, 16000),
+ (128, 40, 13, 15000),
+ (512, 40, 20, 44100),
+ (512, 40, 40, 44100),
+ (512, 40, 3, 44100),
+ (1024, 40, 20, 44100),
+ #(1024, 30, 20, 44100),
+ (1024, 40, 40, 44100),
+ (1024, 40, 3, 44100),
+ )
+ def test_run_with_params(self, buf_size, n_filters, n_coeffs, samplerate):
+ " check mfcc can run with reasonable parameters "
+ o = mfcc(buf_size, n_filters, n_coeffs, samplerate)
+ spec = cvec(buf_size)
+ spec.phas[0] = 0.2
+ for _ in range(10):
+ o(spec)
+ #print coeffs
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_midi2note.py b/python/tests/test_midi2note.py
new file mode 100755
index 0000000..1c2ccf5
--- /dev/null
+++ b/python/tests/test_midi2note.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from aubio import midi2note
+import unittest
+
+list_of_known_midis = (
+ ( 0, 'C-1' ),
+ ( 1, 'C#-1' ),
+ ( 38, 'D2' ),
+ ( 48, 'C3' ),
+ ( 59, 'B3' ),
+ ( 60, 'C4' ),
+ ( 127, 'G9' ),
+ )
+
+class midi2note_good_values(unittest.TestCase):
+
+ def test_midi2note_known_values(self):
+ " known values are correctly converted "
+ for midi, note in list_of_known_midis:
+ self.assertEqual ( midi2note(midi), note )
+
+class midi2note_wrong_values(unittest.TestCase):
+
+ def test_midi2note_negative_value(self):
+ " fails when passed a negative value "
+ self.assertRaises(ValueError, midi2note, -2)
+
+ def test_midi2note_large(self):
+ " fails when passed a value greater than 127 "
+ self.assertRaises(ValueError, midi2note, 128)
+
+ def test_midi2note_floating_value(self):
+ " fails when passed a floating point "
+ self.assertRaises(TypeError, midi2note, 69.2)
+
+ def test_midi2note_character_value(self):
+ " fails when passed a value that can not be transformed to integer "
+ self.assertRaises(TypeError, midi2note, "a")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/tests/test_musicutils.py b/python/tests/test_musicutils.py
new file mode 100755
index 0000000..dd54abb
--- /dev/null
+++ b/python/tests/test_musicutils.py
@@ -0,0 +1,88 @@
+#! /usr/bin/env python
+
+from unittest import main
+import numpy as np
+from numpy.testing import TestCase
+from numpy.testing.utils import assert_equal, assert_almost_equal
+from aubio import window, level_lin, db_spl, silence_detection, level_detection
+from aubio import fvec, float_type
+
+class aubio_window(TestCase):
+
+ def test_accept_name_and_size(self):
+ window("default", 1024)
+
+ def test_fail_name_not_string(self):
+ with self.assertRaises(TypeError):
+ window(10, 1024)
+
+ def test_fail_size_not_int(self):
+ with self.assertRaises(TypeError):
+ window("default", "default")
+
+ def test_compute_hanning_1024(self):
+ size = 1024
+ aubio_window = window("hanning", size)
+ numpy_window = .5 - .5 * np.cos(2. * np.pi * np.arange(size) / size)
+ assert_almost_equal(aubio_window, numpy_window)
+
+class aubio_level_lin(TestCase):
+ def test_accept_fvec(self):
+ level_lin(fvec(1024))
+
+ def test_fail_not_fvec(self):
+ with self.assertRaises(ValueError):
+ level_lin("default")
+
+ def test_zeros_is_zeros(self):
+ assert_equal(level_lin(fvec(1024)), 0.)
+
+ def test_minus_ones_is_one(self):
+ assert_equal(level_lin(-np.ones(1024, dtype = float_type)), 1.)
+
+class aubio_db_spl(TestCase):
+ def test_accept_fvec(self):
+ db_spl(fvec(1024))
+
+ def test_fail_not_fvec(self):
+ with self.assertRaises(ValueError):
+ db_spl("default")
+
+ def test_zeros_is_inf(self):
+ assert np.isinf(db_spl(fvec(1024)))
+
+ def test_minus_ones_is_zero(self):
+ assert_equal(db_spl(-np.ones(1024, dtype = float_type)), 0.)
+
+class aubio_silence_detection(TestCase):
+ def test_accept_fvec(self):
+ silence_detection(fvec(1024), -70.)
+
+ def test_fail_not_fvec(self):
+ with self.assertRaises(ValueError):
+ silence_detection("default", -70)
+
+ def test_zeros_is_one(self):
+ assert silence_detection(fvec(1024), -70) == 1
+
+ def test_minus_ones_is_zero(self):
+ from numpy import ones
+ assert silence_detection(ones(1024, dtype = float_type), -70) == 0
+
+class aubio_level_detection(TestCase):
+ def test_accept_fvec(self):
+ level_detection(fvec(1024), -70.)
+
+ def test_fail_not_fvec(self):
+ with self.assertRaises(ValueError):
+ level_detection("default", -70)
+
+ def test_zeros_is_one(self):
+ assert level_detection(fvec(1024), -70) == 1
+
+ def test_minus_ones_is_zero(self):
+ from numpy import ones
+ assert level_detection(ones(1024, dtype = float_type), -70) == 0
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_note2midi.py b/python/tests/test_note2midi.py
new file mode 100755
index 0000000..968c34a
--- /dev/null
+++ b/python/tests/test_note2midi.py
@@ -0,0 +1,77 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+
+from aubio import note2midi, freq2note
+import unittest
+
+list_of_known_notes = (
+ ( 'C-1', 0 ),
+ ( 'C#-1', 1 ),
+ ( 'd2', 38 ),
+ ( 'C3', 48 ),
+ ( 'B3', 59 ),
+ ( 'B#3', 60 ),
+ ( 'A4', 69 ),
+ ( 'A#4', 70 ),
+ ( 'Bb4', 70 ),
+ ( 'Bâ™­4', 70 ),
+ ( 'G8', 115 ),
+ ( 'G♯8', 116 ),
+ ( 'G9', 127 ),
+ ( 'G\udd2a2', 45 ),
+ ( 'B\ufffd2', 45 ),
+ ( 'Aâ™®2', 45 ),
+ )
+
+class note2midi_good_values(unittest.TestCase):
+
+ def test_note2midi_known_values(self):
+ " known values are correctly converted "
+ for note, midi in list_of_known_notes:
+ self.assertEqual ( note2midi(note), midi )
+
+class note2midi_wrong_values(unittest.TestCase):
+
+ def test_note2midi_missing_octave(self):
+ " fails when passed only one character"
+ self.assertRaises(ValueError, note2midi, 'C')
+
+ def test_note2midi_wrong_modifier(self):
+ " fails when passed a note with an invalid modifier "
+ self.assertRaises(ValueError, note2midi, 'C.1')
+
+ def test_note2midi_another_wrong_modifier_again(self):
+ " fails when passed a note with a invalid note name "
+ self.assertRaises(ValueError, note2midi, 'CB-3')
+
+ def test_note2midi_wrong_octave(self):
+ " fails when passed a wrong octave number "
+ self.assertRaises(ValueError, note2midi, 'CBc')
+
+ def test_note2midi_out_of_range(self):
+ " fails when passed a note out of range"
+ self.assertRaises(ValueError, note2midi, 'A9')
+
+ def test_note2midi_wrong_note_name(self):
+ " fails when passed a note with a wrong name"
+ self.assertRaises(ValueError, note2midi, 'W9')
+
+ def test_note2midi_low_octave(self):
+ " fails when passed a note with a too low octave"
+ self.assertRaises(ValueError, note2midi, 'C-9')
+
+ def test_note2midi_wrong_data_type(self):
+ " fails when passed a non-string value "
+ self.assertRaises(TypeError, note2midi, 123)
+
+
+class freq2note_simple_test(unittest.TestCase):
+
+ def test_freq2note(self):
+ " make sure freq2note(441) == A4 "
+ self.assertEqual("A4", freq2note(441))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/tests/test_onset.py b/python/tests/test_onset.py
new file mode 100755
index 0000000..dcb6dab
--- /dev/null
+++ b/python/tests/test_onset.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from aubio import onset
+
+class aubio_onset_default(TestCase):
+
+ def test_members(self):
+ o = onset()
+ assert_equal ([o.buf_size, o.hop_size, o.method, o.samplerate],
+ [1024,512,'default',44100])
+
+class aubio_onset_params(TestCase):
+
+ samplerate = 44100
+
+ def setUp(self):
+ self.o = onset(samplerate = self.samplerate)
+
+ def test_get_delay(self):
+ assert_equal (self.o.get_delay(), int(4.3 * self.o.hop_size))
+
+ def test_get_delay_s(self):
+ assert_almost_equal (self.o.get_delay_s(), self.o.get_delay() / float(self.samplerate))
+
+ def test_get_delay_ms(self):
+ assert_almost_equal (self.o.get_delay_ms(), self.o.get_delay() * 1000. / self.samplerate, 5)
+
+ def test_get_minioi(self):
+ assert_almost_equal (self.o.get_minioi(), 0.02 * self.samplerate)
+
+ def test_get_minioi_s(self):
+ assert_almost_equal (self.o.get_minioi_s(), 0.02)
+
+ def test_get_minioi_ms(self):
+ assert_equal (self.o.get_minioi_ms(), 20.)
+
+ def test_get_threshold(self):
+ assert_almost_equal (self.o.get_threshold(), 0.3)
+
+ def test_set_delay(self):
+ val = 256
+ self.o.set_delay(val)
+ assert_equal (self.o.get_delay(), val)
+
+ def test_set_delay_s(self):
+ val = .05
+ self.o.set_delay_s(val)
+ assert_almost_equal (self.o.get_delay_s(), val)
+
+ def test_set_delay_ms(self):
+ val = 50.
+ self.o.set_delay_ms(val)
+ assert_almost_equal (self.o.get_delay_ms(), val)
+
+ def test_set_minioi(self):
+ val = 200
+ self.o.set_minioi(val)
+ assert_equal (self.o.get_minioi(), val)
+
+ def test_set_minioi_s(self):
+ val = 0.04
+ self.o.set_minioi_s(val)
+ assert_almost_equal (self.o.get_minioi_s(), val)
+
+ def test_set_minioi_ms(self):
+ val = 40.
+ self.o.set_minioi_ms(val)
+ assert_almost_equal (self.o.get_minioi_ms(), val)
+
+ def test_set_threshold(self):
+ val = 0.2
+ self.o.set_threshold(val)
+ assert_almost_equal (self.o.get_threshold(), val)
+
+class aubio_onset_96000(aubio_onset_params):
+ samplerate = 96000
+
+class aubio_onset_32000(aubio_onset_params):
+ samplerate = 32000
+
+class aubio_onset_8000(aubio_onset_params):
+ samplerate = 8000
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_phasevoc.py b/python/tests/test_phasevoc.py
new file mode 100755
index 0000000..23cbad5
--- /dev/null
+++ b/python/tests/test_phasevoc.py
@@ -0,0 +1,187 @@
+#! /usr/bin/env python
+
+from numpy.testing import TestCase, assert_equal, assert_array_less
+from aubio import fvec, cvec, pvoc, float_type
+from nose2 import main
+from nose2.tools import params
+import numpy as np
+
+if float_type == 'float32':
+ max_sq_error = 1.e-12
+else:
+ max_sq_error = 1.e-29
+
+def create_sine(hop_s, freq, samplerate):
+ t = np.arange(hop_s).astype(float_type)
+ return np.sin( 2. * np.pi * freq * t / float(samplerate))
+
+def create_noise(hop_s):
+ return np.random.rand(hop_s).astype(float_type) * 2. - 1.
+
+class aubio_pvoc_test_case(TestCase):
+ """ pvoc object test case """
+
+ def test_members_automatic_sizes_default(self):
+ """ check object creation with default parameters """
+ f = pvoc()
+ assert_equal ([f.win_s, f.hop_s], [1024, 512])
+
+ def test_members_unnamed_params(self):
+ """ check object creation with unnamed parameters """
+ f = pvoc(2048, 128)
+ assert_equal ([f.win_s, f.hop_s], [2048, 128])
+
+ def test_members_named_params(self):
+ """ check object creation with named parameters """
+ f = pvoc(hop_s = 128, win_s = 2048)
+ assert_equal ([f.win_s, f.hop_s], [2048, 128])
+
+ def test_zeros(self):
+ """ check the resynthesis of zeros gives zeros """
+ win_s, hop_s = 1024, 256
+ f = pvoc (win_s, hop_s)
+ t = fvec (hop_s)
+ for _ in range( int ( 4 * win_s / hop_s ) ):
+ s = f(t)
+ r = f.rdo(s)
+ assert_equal ( t, 0.)
+ assert_equal ( s.norm, 0.)
+ assert_equal ( s.phas, 0.)
+ assert_equal ( r, 0.)
+
+ @params(
+ ( 256, 8),
+ ( 256, 4),
+ ( 256, 2),
+ ( 512, 8),
+ ( 512, 4),
+ ( 512, 2),
+ #( 129, 2),
+ #( 320, 4),
+ #( 13, 8),
+ (1024, 8),
+ (1024, 4),
+ (1024, 2),
+ (2048, 8),
+ (2048, 4),
+ (2048, 2),
+ (4096, 8),
+ (4096, 4),
+ (4096, 2),
+ (8192, 8),
+ (8192, 4),
+ (8192, 2),
+ )
+ def test_resynth_steps_noise(self, hop_s, ratio):
+ """ check the resynthesis of a random signal is correct """
+ sigin = create_noise(hop_s)
+ self.reconstruction(sigin, hop_s, ratio)
+
+ @params(
+ (44100, 256, 8, 441),
+ (44100, 256, 4, 1203),
+ (44100, 256, 2, 3045),
+ (44100, 512, 8, 445),
+ (44100, 512, 4, 445),
+ (44100, 512, 2, 445),
+ (44100, 1024, 8, 445),
+ (44100, 1024, 4, 445),
+ (44100, 1024, 2, 445),
+ ( 8000, 1024, 2, 445),
+ (22050, 1024, 2, 445),
+ (22050, 256, 8, 445),
+ (96000, 1024, 8, 47000),
+ (96000, 1024, 8, 20),
+ )
+ def test_resynth_steps_sine(self, samplerate, hop_s, ratio, freq):
+ """ check the resynthesis of a sine is correct """
+ sigin = create_sine(hop_s, freq, samplerate)
+ self.reconstruction(sigin, hop_s, ratio)
+
+ def reconstruction(self, sigin, hop_s, ratio):
+ buf_s = hop_s * ratio
+ f = pvoc(buf_s, hop_s)
+ zeros = fvec(hop_s)
+ r2 = f.rdo( f(sigin) )
+ for _ in range(1, ratio):
+ r2 = f.rdo( f(zeros) )
+ # compute square errors
+ sq_error = (r2 - sigin)**2
+ # make sure all square errors are less than desired precision
+ assert_array_less(sq_error, max_sq_error)
+
+class aubio_pvoc_strange_params(TestCase):
+
+ def test_win_size_short(self):
+ with self.assertRaises(RuntimeError):
+ pvoc(1, 1)
+
+ def test_hop_size_long(self):
+ with self.assertRaises(RuntimeError):
+ pvoc(1024, 1025)
+
+ def test_large_input_timegrain(self):
+ win_s = 1024
+ f = pvoc(win_s)
+ t = fvec(win_s + 1)
+ with self.assertRaises(ValueError):
+ f(t)
+
+ def test_small_input_timegrain(self):
+ win_s = 1024
+ f = pvoc(win_s)
+ t = fvec(1)
+ with self.assertRaises(ValueError):
+ f(t)
+
+ def test_large_input_fftgrain(self):
+ win_s = 1024
+ f = pvoc(win_s)
+ s = cvec(win_s + 5)
+ with self.assertRaises(ValueError):
+ f.rdo(s)
+
+ def test_small_input_fftgrain(self):
+ win_s = 1024
+ f = pvoc(win_s)
+ s = cvec(16)
+ with self.assertRaises(ValueError):
+ f.rdo(s)
+
+class aubio_pvoc_wrong_params(TestCase):
+
+ def test_wrong_buf_size(self):
+ win_s = -1
+ with self.assertRaises(ValueError):
+ pvoc(win_s)
+
+ def test_buf_size_too_small(self):
+ win_s = 1
+ with self.assertRaises(RuntimeError):
+ pvoc(win_s)
+
+ def test_hop_size_negative(self):
+ win_s = 512
+ hop_s = -2
+ with self.assertRaises(ValueError):
+ pvoc(win_s, hop_s)
+
+ def test_hop_size_too_small(self):
+ win_s = 1
+ hop_s = 1
+ with self.assertRaises(RuntimeError):
+ pvoc(win_s, hop_s)
+
+ def test_buf_size_not_power_of_two(self):
+ win_s = 320
+ hop_s = win_s // 2
+ try:
+ with self.assertRaises(RuntimeError):
+ pvoc(win_s, hop_s)
+ except AssertionError:
+ # when compiled with fftw3, aubio supports non power of two fft sizes
+ self.skipTest('creating aubio.pvoc with size %d did not fail' % win_s)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/python/tests/test_pitch.py b/python/tests/test_pitch.py
new file mode 100755
index 0000000..00c8eea
--- /dev/null
+++ b/python/tests/test_pitch.py
@@ -0,0 +1,125 @@
+#! /usr/bin/env python
+
+from unittest import TestCase, main
+from numpy.testing import assert_equal
+from numpy import sin, arange, mean, median, isnan, pi
+from aubio import fvec, pitch, freqtomidi, float_type
+
+class aubio_pitch_Good_Values(TestCase):
+
+ def skip_test_new_default(self):
+ " creating a pitch object without parameters "
+ p = pitch()
+ assert_equal ( [p.method, p.buf_size, p.hop_size, p.samplerate],
+ ['default', 1024, 512, 44100])
+
+ def test_run_on_silence(self):
+ " creating a pitch object with parameters "
+ p = pitch('default', 2048, 512, 32000)
+ assert_equal ( [p.method, p.buf_size, p.hop_size, p.samplerate],
+ ['default', 2048, 512, 32000])
+
+ def test_run_on_zeros(self):
+ " running on silence gives 0 "
+ p = pitch('default', 2048, 512, 32000)
+ f = fvec (512)
+ for _ in range(10): assert_equal (p(f), 0.)
+
+ def test_run_on_ones(self):
+ " running on ones gives 0 "
+ p = pitch('default', 2048, 512, 32000)
+ f = fvec (512)
+ f[:] = 1
+ for _ in range(10): assert_equal (p(f), 0.)
+
+class aubio_pitch_Sinusoid(TestCase):
+
+ def run_pitch_on_sinusoid(self, method, buf_size, hop_size, samplerate, freq):
+ # create pitch object
+ p = pitch(method, buf_size, hop_size, samplerate)
+ # duration in seconds
+ seconds = .3
+ # duration in samples
+ duration = seconds * samplerate
+ # increase to the next multiple of hop_size
+ duration = duration - duration % hop_size + hop_size;
+ # build sinusoid
+ sinvec = self.build_sinusoid(duration, freq, samplerate)
+
+ self.run_pitch(p, sinvec, freq)
+
+ def build_sinusoid(self, length, freq, samplerate):
+ return sin( 2. * pi * arange(length).astype(float_type) * freq / samplerate)
+
+ def run_pitch(self, p, input_vec, freq):
+ pitches, errors = [], []
+ input_blocks = input_vec.reshape((-1, p.hop_size))
+ for new_block in input_blocks:
+ pitch = p(new_block)[0]
+ pitches.append(pitch)
+ errors.append(1. - freqtomidi(pitch) / freqtomidi(freq))
+ assert_equal ( len(input_blocks), len(pitches) )
+ assert_equal ( isnan(pitches), False )
+ # cut the first candidates
+ #cut = ( p.buf_size - p.hop_size ) / p.hop_size
+ pitches = pitches[2:]
+ errors = errors[2:]
+ # check that the mean of all relative errors is less than 10%
+ #assert abs (mean(errors) ) < 0.1, pitches
+ assert abs (median(errors) ) < 0.06, "median of relative errors is bigger than 0.06 (%f)\n found %s\n errors %s" % (mean(errors), pitches, errors)
+ #print 'len(pitches), cut:', len(pitches), cut
+ #print 'median errors: ', median(errors), 'median pitches: ', median(pitches)
+
+pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" , "specacf" ]
+pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" ]
+
+#freqs = [ 27.5, 55., 110., 220., 440., 880., 1760., 3520. ]
+freqs = [ 110., 220., 440., 880., 1760., 3520. ]
+signal_modes = []
+for freq in freqs:
+ signal_modes += [
+ ( 4096, 2048, 44100, freq ),
+ ( 2048, 512, 44100, freq ),
+ ( 2048, 1024, 44100, freq ),
+ ( 2048, 1024, 32000, freq ),
+ ]
+
+freqs = [ ] #55., 110., 220., 440., 880., 1760., 3520. ]
+for freq in freqs:
+ signal_modes += [
+ ( 2048, 1024, 22050, freq ),
+ ( 1024, 256, 16000, freq ),
+ ( 1024, 256, 8000, freq ),
+ ( 1024, 512+256, 8000, freq ),
+ ]
+
+"""
+signal_modes = [
+ ( 4096, 512, 44100, 2.*882. ),
+ ( 4096, 512, 44100, 882. ),
+ ( 4096, 512, 44100, 440. ),
+ ( 2048, 512, 44100, 440. ),
+ ( 2048, 1024, 44100, 440. ),
+ ( 2048, 1024, 44100, 440. ),
+ ( 2048, 1024, 32000, 440. ),
+ ( 2048, 1024, 22050, 440. ),
+ ( 1024, 256, 16000, 440. ),
+ ( 1024, 256, 8000, 440. ),
+ ( 1024, 512+256, 8000, 440. ),
+ ]
+"""
+
+def create_test (algo, mode):
+ def do_test_pitch(self):
+ self.run_pitch_on_sinusoid(algo, mode[0], mode[1], mode[2], mode[3])
+ return do_test_pitch
+
+for algo in pitch_algorithms:
+ for mode in signal_modes:
+ test_method = create_test (algo, mode)
+ test_method.__name__ = 'test_pitch_%s_%d_%d_%dHz_sin_%.0f' % ( algo,
+ mode[0], mode[1], mode[2], mode[3] )
+ setattr (aubio_pitch_Sinusoid, test_method.__name__, test_method)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_sink.py b/python/tests/test_sink.py
new file mode 100755
index 0000000..e90b5f8
--- /dev/null
+++ b/python/tests/test_sink.py
@@ -0,0 +1,97 @@
+#! /usr/bin/env python
+
+from nose2 import main
+from nose2.tools import params
+from numpy.testing import TestCase
+from aubio import fvec, source, sink
+from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
+
+list_of_sounds = list_all_sounds('sounds')
+samplerates = [0, 44100, 8000, 32000]
+hop_sizes = [512, 1024, 64]
+
+path = None
+
+many_files = 300 # 256 opened files is too much
+
+all_params = []
+for soundfile in list_of_sounds:
+ for hop_size in hop_sizes:
+ for samplerate in samplerates:
+ all_params.append((hop_size, samplerate, soundfile))
+
+class aubio_sink_test_case(TestCase):
+
+ def setUp(self):
+ if not len(list_of_sounds):
+ self.skipTest('add some sound files in \'python/tests/sounds\'')
+
+ def test_many_sinks(self):
+ from tempfile import mkdtemp
+ import os.path
+ import shutil
+ tmpdir = mkdtemp()
+ sink_list = []
+ for i in range(many_files):
+ path = os.path.join(tmpdir, 'f-' + str(i) + '.wav')
+ g = sink(path, 0)
+ sink_list.append(g)
+ write = 32
+ for _ in range(200):
+ vec = fvec(write)
+ g(vec, write)
+ g.close()
+ shutil.rmtree(tmpdir)
+
+ @params(*all_params)
+ def test_read_and_write(self, hop_size, samplerate, path):
+
+ try:
+ f = source(path, samplerate, hop_size)
+ except RuntimeError as e:
+ self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+ if samplerate == 0: samplerate = f.samplerate
+ sink_path = get_tmp_sink_path()
+ g = sink(sink_path, samplerate)
+ total_frames = 0
+ while True:
+ vec, read = f()
+ g(vec, read)
+ total_frames += read
+ if read < f.hop_size: break
+ del_tmp_sink_path(sink_path)
+
+ @params(*all_params)
+ def test_read_and_write_multi(self, hop_size, samplerate, path):
+ try:
+ f = source(path, samplerate, hop_size)
+ except RuntimeError as e:
+ self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+ if samplerate == 0: samplerate = f.samplerate
+ sink_path = get_tmp_sink_path()
+ g = sink(sink_path, samplerate, channels = f.channels)
+ total_frames = 0
+ while True:
+ vec, read = f.do_multi()
+ g.do_multi(vec, read)
+ total_frames += read
+ if read < f.hop_size: break
+ del_tmp_sink_path(sink_path)
+
+ def test_close_file(self):
+ samplerate = 44100
+ sink_path = get_tmp_sink_path()
+ g = sink(sink_path, samplerate)
+ g.close()
+ del_tmp_sink_path(sink_path)
+
+ def test_close_file_twice(self):
+ samplerate = 44100
+ sink_path = get_tmp_sink_path()
+ g = sink(sink_path, samplerate)
+ g.close()
+ g.close()
+ del_tmp_sink_path(sink_path)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_slicing.py b/python/tests/test_slicing.py
new file mode 100755
index 0000000..0252f5d
--- /dev/null
+++ b/python/tests/test_slicing.py
@@ -0,0 +1,149 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal
+from aubio import slice_source_at_stamps
+from utils import count_files_in_directory, get_default_test_sound
+from utils import count_samples_in_directory, count_samples_in_file
+
+import tempfile
+import shutil
+
+n_slices = 4
+
+class aubio_slicing_test_case(TestCase):
+
+ def setUp(self):
+ self.source_file = get_default_test_sound(self)
+ self.output_dir = tempfile.mkdtemp(suffix = 'aubio_slicing_test_case')
+
+ def test_slice_start_only(self):
+ regions_start = [i*1000 for i in range(n_slices)]
+ slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+
+ def test_slice_start_only_no_zero(self):
+ regions_start = [i*1000 for i in range(1, n_slices)]
+ slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+
+ def test_slice_start_beyond_end(self):
+ regions_start = [i*1000 for i in range(1, n_slices)]
+ regions_start += [count_samples_in_file(self.source_file) + 1000]
+ slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+
+ def test_slice_start_every_blocksize(self):
+ hopsize = 200
+ regions_start = [i*hopsize for i in range(1, n_slices)]
+ slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
+ hopsize = 200)
+
+ def tearDown(self):
+ original_samples = count_samples_in_file(self.source_file)
+ written_samples = count_samples_in_directory(self.output_dir)
+ total_files = count_files_in_directory(self.output_dir)
+ assert_equal(n_slices, total_files,
+ "number of slices created different from expected")
+ assert_equal(written_samples, original_samples,
+ "number of samples written different from number of original samples")
+ shutil.rmtree(self.output_dir)
+
+class aubio_slicing_with_ends_test_case(TestCase):
+
+ def setUp(self):
+ self.source_file = get_default_test_sound(self)
+ self.output_dir = tempfile.mkdtemp(suffix = 'aubio_slicing_test_case')
+
+ def test_slice_start_and_ends_no_gap(self):
+ regions_start = [i*1000 for i in range(n_slices)]
+ regions_ends = [start - 1 for start in regions_start[1:]] + [1e120]
+ slice_source_at_stamps(self.source_file, regions_start, regions_ends,
+ output_dir = self.output_dir)
+ original_samples = count_samples_in_file(self.source_file)
+ written_samples = count_samples_in_directory(self.output_dir)
+ total_files = count_files_in_directory(self.output_dir)
+ assert_equal(n_slices, total_files,
+ "number of slices created different from expected")
+ assert_equal(written_samples, original_samples,
+ "number of samples written different from number of original samples")
+
+ def test_slice_start_and_ends_200_gap(self):
+ regions_start = [i*1000 for i in range(n_slices)]
+ regions_ends = [start + 199 for start in regions_start]
+ slice_source_at_stamps(self.source_file, regions_start, regions_ends,
+ output_dir = self.output_dir)
+ expected_samples = 200 * n_slices
+ written_samples = count_samples_in_directory(self.output_dir)
+ total_files = count_files_in_directory(self.output_dir)
+ assert_equal(n_slices, total_files,
+ "number of slices created different from expected")
+ assert_equal(written_samples, expected_samples,
+ "number of samples written different from number of original samples")
+
+ def test_slice_start_and_ends_overlaping(self):
+ regions_start = [i*1000 for i in range(n_slices)]
+ regions_ends = [start + 1199 for start in regions_start]
+ slice_source_at_stamps(self.source_file, regions_start, regions_ends,
+ output_dir = self.output_dir)
+ expected_samples = 1200 * n_slices
+ written_samples = count_samples_in_directory(self.output_dir)
+ total_files = count_files_in_directory(self.output_dir)
+ assert_equal(n_slices, total_files,
+ "number of slices created different from expected")
+ assert_equal(written_samples, expected_samples,
+ "number of samples written different from number of original samples")
+
+ def tearDown(self):
+ shutil.rmtree(self.output_dir)
+
+
+class aubio_slicing_wrong_starts_test_case(TestCase):
+
+ def setUp(self):
+ self.source_file = get_default_test_sound(self)
+ self.output_dir = tempfile.mkdtemp(suffix = 'aubio_slicing_test_case')
+
+ def test_slice_start_empty(self):
+ regions_start = []
+ self.assertRaises(ValueError,
+ slice_source_at_stamps,
+ self.source_file, regions_start, output_dir = self.output_dir)
+
+ def test_slice_start_none(self):
+ regions_start = None
+ self.assertRaises(ValueError,
+ slice_source_at_stamps,
+ self.source_file, regions_start, output_dir = self.output_dir)
+
+ def tearDown(self):
+ shutil.rmtree(self.output_dir)
+
+class aubio_slicing_wrong_ends_test_case(TestCase):
+
+ def setUp(self):
+ self.source_file = get_default_test_sound(self)
+ self.output_dir = tempfile.mkdtemp(suffix = 'aubio_slicing_test_case')
+
+ def test_slice_wrong_ends(self):
+ regions_start = [i*1000 for i in range(1, n_slices)]
+ regions_end = []
+ self.assertRaises (ValueError,
+ slice_source_at_stamps, self.source_file, regions_start, regions_end,
+ output_dir = self.output_dir)
+
+ def test_slice_no_ends(self):
+ regions_start = [i*1000 for i in range(1, n_slices)]
+ regions_end = None
+ slice_source_at_stamps (self.source_file, regions_start, regions_end,
+ output_dir = self.output_dir)
+ total_files = count_files_in_directory(self.output_dir)
+ assert_equal(n_slices, total_files,
+ "number of slices created different from expected")
+ original_samples = count_samples_in_file(self.source_file)
+ written_samples = count_samples_in_directory(self.output_dir)
+ assert_equal(written_samples, original_samples,
+ "number of samples written different from number of original samples")
+
+ def tearDown(self):
+ shutil.rmtree(self.output_dir)
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_source.py b/python/tests/test_source.py
new file mode 100755
index 0000000..ed51ead
--- /dev/null
+++ b/python/tests/test_source.py
@@ -0,0 +1,157 @@
+#! /usr/bin/env python
+
+from nose2 import main
+from nose2.tools import params
+from numpy.testing import TestCase
+from aubio import source
+from utils import list_all_sounds
+
+list_of_sounds = list_all_sounds('sounds')
+samplerates = [0, 44100, 8000, 32000]
+hop_sizes = [512, 1024, 64]
+
+path = None
+
+all_params = []
+for soundfile in list_of_sounds:
+ for hop_size in hop_sizes:
+ for samplerate in samplerates:
+ all_params.append((hop_size, samplerate, soundfile))
+
+
+class aubio_source_test_case_base(TestCase):
+
+ def setUp(self):
+ if not len(list_of_sounds): self.skipTest('add some sound files in \'python/tests/sounds\'')
+ self.default_test_sound = list_of_sounds[0]
+
+class aubio_source_test_case(aubio_source_test_case_base):
+
+ def test_close_file(self):
+ samplerate = 0 # use native samplerate
+ hop_size = 256
+ for p in list_of_sounds:
+ f = source(p, samplerate, hop_size)
+ f.close()
+
+ def test_close_file_twice(self):
+ samplerate = 0 # use native samplerate
+ hop_size = 256
+ for p in list_of_sounds:
+ f = source(p, samplerate, hop_size)
+ f.close()
+ f.close()
+
+class aubio_source_read_test_case(aubio_source_test_case_base):
+
+ def read_from_source(self, f):
+ total_frames = 0
+ while True:
+ _ , read = f()
+ total_frames += read
+ if read < f.hop_size: break
+ #result_str = "read {:.2f}s ({:d} frames in {:d} blocks at {:d}Hz) from {:s}"
+ #result_params = total_frames / float(f.samplerate), total_frames, total_frames//f.hop_size, f.samplerate, f.uri
+ #print (result_str.format(*result_params))
+ return total_frames
+
+ @params(*all_params)
+ def test_samplerate_hopsize(self, hop_size, samplerate, soundfile):
+ try:
+ f = source(soundfile, samplerate, hop_size)
+ except RuntimeError as e:
+ self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
+ assert f.samplerate != 0
+ self.read_from_source(f)
+
+ @params(*list_of_sounds)
+ def test_samplerate_none(self, p):
+ f = source(p)
+ assert f.samplerate != 0
+ self.read_from_source(f)
+
+ @params(*list_of_sounds)
+ def test_samplerate_0(self, p):
+ f = source(p, 0)
+ assert f.samplerate != 0
+ self.read_from_source(f)
+
+ @params(*list_of_sounds)
+ def test_zero_hop_size(self, p):
+ f = source(p, 0, 0)
+ assert f.samplerate != 0
+ assert f.hop_size != 0
+ self.read_from_source(f)
+
+ @params(*list_of_sounds)
+ def test_seek_to_half(self, p):
+ from random import randint
+ f = source(p, 0, 0)
+ assert f.samplerate != 0
+ assert f.hop_size != 0
+ a = self.read_from_source(f)
+ c = randint(0, a)
+ f.seek(c)
+ b = self.read_from_source(f)
+ assert a == b + c
+
+ @params(*list_of_sounds)
+ def test_duration(self, p):
+ total_frames = 0
+ f = source(p)
+ duration = f.duration
+ while True:
+ _, read = f()
+ total_frames += read
+ if read < f.hop_size: break
+ self.assertEqual(duration, total_frames)
+
+
+class aubio_source_test_wrong_params(TestCase):
+
+ def test_wrong_file(self):
+ with self.assertRaises(RuntimeError):
+ source('path_to/unexisting file.mp3')
+
+class aubio_source_test_wrong_params_with_file(aubio_source_test_case_base):
+
+ def test_wrong_samplerate(self):
+ with self.assertRaises(ValueError):
+ source(self.default_test_sound, -1)
+
+ def test_wrong_hop_size(self):
+ with self.assertRaises(ValueError):
+ source(self.default_test_sound, 0, -1)
+
+ def test_wrong_channels(self):
+ with self.assertRaises(ValueError):
+ source(self.default_test_sound, 0, 0, -1)
+
+ def test_wrong_seek(self):
+ f = source(self.default_test_sound)
+ with self.assertRaises(ValueError):
+ f.seek(-1)
+
+ def test_wrong_seek_too_large(self):
+ f = source(self.default_test_sound)
+ try:
+ with self.assertRaises(ValueError):
+ f.seek(f.duration + f.samplerate * 10)
+ except AssertionError:
+ self.skipTest('seeking after end of stream failed raising ValueError')
+
+class aubio_source_readmulti_test_case(aubio_source_read_test_case):
+
+ def read_from_source(self, f):
+ total_frames = 0
+ while True:
+ _, read = f.do_multi()
+ total_frames += read
+ if read < f.hop_size: break
+ #result_str = "read {:.2f}s ({:d} frames in {:d} channels and {:d} blocks at {:d}Hz) from {:s}"
+ #result_params = total_frames / float(f.samplerate), total_frames, f.channels, int(total_frames/f.hop_size), f.samplerate, f.uri
+ #print (result_str.format(*result_params))
+ return total_frames
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_specdesc.py b/python/tests/test_specdesc.py
new file mode 100755
index 0000000..063d13d
--- /dev/null
+++ b/python/tests/test_specdesc.py
@@ -0,0 +1,234 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase, assert_equal, assert_almost_equal
+from numpy import random, arange, log, zeros
+from aubio import specdesc, cvec, float_type
+
+methods = ["default",
+ "energy",
+ "hfc",
+ "complex",
+ "phase",
+ "specdiff",
+ "kl",
+ "mkl",
+ "specflux",
+ "centroid",
+ "spread",
+ "skewness",
+ "kurtosis",
+ "slope",
+ "decrease",
+ "rolloff"]
+buf_size = 2048
+
+class aubio_specdesc(TestCase):
+
+ def test_members(self):
+ o = specdesc()
+
+ for method in methods:
+ o = specdesc(method, buf_size)
+ assert_equal ([o.buf_size, o.method], [buf_size, method])
+
+ spec = cvec(buf_size)
+ spec.norm[0] = 1
+ spec.norm[1] = 1./2.
+ #print "%20s" % method, str(o(spec))
+ o(spec)
+ spec.norm = random.random_sample((len(spec.norm),)).astype(float_type)
+ spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+ #print "%20s" % method, str(o(spec))
+ assert (o(spec) != 0.)
+
+ def test_phase(self):
+ o = specdesc("phase", buf_size)
+ spec = cvec(buf_size)
+ # phase of zeros is zero
+ assert_equal (o(spec), 0.)
+ spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+ # phase of random is not zero
+ spec.norm[:] = 1
+ assert (o(spec) != 0.)
+
+ def test_specdiff(self):
+ o = specdesc("phase", buf_size)
+ spec = cvec(buf_size)
+ # specdiff of zeros is zero
+ assert_equal (o(spec), 0.)
+ spec.phas = random.random_sample((len(spec.phas),)).astype(float_type)
+ # phase of random is not zero
+ spec.norm[:] = 1
+ assert (o(spec) != 0.)
+
+ def test_hfc(self):
+ o = specdesc("hfc")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ assert_equal (a, c.norm)
+ assert_equal ( sum(a*(a+1)), o(c))
+
+ def test_complex(self):
+ o = specdesc("complex")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ assert_equal (a, c.norm)
+ # the previous run was on zeros, so previous frames are still 0
+ # so we have sqrt ( abs ( r2 ^ 2) ) == r2
+ assert_equal ( sum(a), o(c))
+ # second time. c.norm = a, so, r1 = r2, and the euclidian distance is 0
+ assert_equal ( 0, o(c))
+
+ def test_kl(self):
+ o = specdesc("kl")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ assert_almost_equal( sum(a * log(1.+ a/1.e-1 ) ) / o(c), 1., decimal=6)
+
+ def test_mkl(self):
+ o = specdesc("mkl")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ assert_almost_equal( sum(log(1.+ a/1.e-1 ) ) / o(c), 1, decimal=6)
+
+ def test_specflux(self):
+ o = specdesc("specflux")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ assert_equal( sum(a), o(c))
+ assert_equal( 0, o(c))
+ c.norm = zeros(c.length, dtype=float_type)
+ assert_equal( 0, o(c))
+
+ def test_centroid(self):
+ o = specdesc("centroid")
+ c = cvec()
+ # make sure centroid of zeros is zero
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ centroid = sum(a*a) / sum(a)
+ assert_almost_equal (centroid, o(c), decimal = 2)
+
+ c.norm = a * .5
+ assert_almost_equal (centroid, o(c), decimal = 2)
+
+ def test_spread(self):
+ o = specdesc("spread")
+ c = cvec(1024)
+ ramp = arange(c.length, dtype=float_type)
+ assert_equal( 0., o(c))
+
+ a = ramp
+ c.norm = a
+ centroid = sum(a*a) / sum(a)
+ spread = sum( a * pow(ramp - centroid, 2.) ) / sum(a)
+ assert_almost_equal (o(c), spread, decimal = 1)
+
+ def test_skewness(self):
+ o = specdesc("skewness")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ centroid = sum(a*a) / sum(a)
+ spread = sum( (a - centroid)**2 *a) / sum(a)
+ skewness = sum( (a - centroid)**3 *a) / sum(a) / spread **1.5
+ assert_almost_equal (skewness, o(c), decimal = 2)
+
+ c.norm = a * 3
+ assert_almost_equal (skewness, o(c), decimal = 2)
+
+ def test_kurtosis(self):
+ o = specdesc("kurtosis")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length, dtype=float_type)
+ c.norm = a
+ centroid = sum(a*a) / sum(a)
+ spread = sum( (a - centroid)**2 *a) / sum(a)
+ kurtosis = sum( (a - centroid)**4 *a) / sum(a) / spread **2
+ assert_almost_equal (kurtosis, o(c), decimal = 2)
+
+ def test_slope(self):
+ o = specdesc("slope")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length * 2, 0, -2, dtype=float_type)
+ k = arange(c.length, dtype=float_type)
+ c.norm = a
+ num = len(a) * sum(k*a) - sum(k)*sum(a)
+ den = (len(a) * sum(k**2) - sum(k)**2)
+ slope = num/den/sum(a)
+ assert_almost_equal (slope, o(c), decimal = 5)
+
+ a = arange(0, c.length * 2, +2, dtype=float_type)
+ c.norm = a
+ num = len(a) * sum(k*a) - sum(k)*sum(a)
+ den = (len(a) * sum(k**2) - sum(k)**2)
+ slope = num/den/sum(a)
+ assert_almost_equal (slope, o(c), decimal = 5)
+
+ a = arange(0, c.length * 2, +2, dtype=float_type)
+ c.norm = a * 2
+ assert_almost_equal (slope, o(c), decimal = 5)
+
+ def test_decrease(self):
+ o = specdesc("decrease")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length * 2, 0, -2, dtype=float_type)
+ k = arange(c.length, dtype=float_type)
+ c.norm = a
+ decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:])
+ assert_almost_equal (decrease, o(c), decimal = 5)
+
+ a = arange(0, c.length * 2, +2, dtype=float_type)
+ c.norm = a
+ decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:])
+ assert_almost_equal (decrease, o(c), decimal = 5)
+
+ a = arange(0, c.length * 2, +2, dtype=float_type)
+ c.norm = a * 2
+ decrease = sum((a[1:] - a [0]) / k[1:]) / sum(a[1:])
+ assert_almost_equal (decrease, o(c), decimal = 5)
+
+ def test_rolloff(self):
+ o = specdesc("rolloff")
+ c = cvec()
+ assert_equal( 0., o(c))
+ a = arange(c.length * 2, 0, -2, dtype=float_type)
+ c.norm = a
+ cumsum = .95*sum(a*a)
+ i = 0; rollsum = 0
+ while rollsum < cumsum:
+ rollsum += a[i]*a[i]
+ i+=1
+ rolloff = i
+ assert_equal (rolloff, o(c))
+
+class aubio_specdesc_wrong(TestCase):
+
+ def test_negative(self):
+ with self.assertRaises(ValueError):
+ specdesc("default", -10)
+
+ def test_unknown(self):
+ # FIXME should fail?
+ with self.assertRaises(ValueError):
+ specdesc("unknown", 512)
+ self.skipTest('todo: new_specdesc should fail on wrong method')
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/test_zero_crossing_rate.py b/python/tests/test_zero_crossing_rate.py
new file mode 100755
index 0000000..7f6d479
--- /dev/null
+++ b/python/tests/test_zero_crossing_rate.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+
+from unittest import main
+from numpy.testing import TestCase
+from aubio import fvec, zero_crossing_rate
+
+buf_size = 2048
+
+class zero_crossing_rate_test_case(TestCase):
+
+ def setUp(self):
+ self.vector = fvec(buf_size)
+
+ def test_zeroes(self):
+ """ check zero crossing rate on a buffer of 0. """
+ self.assertEqual(0., zero_crossing_rate(self.vector))
+
+ def test_ones(self):
+ """ check zero crossing rate on a buffer of 1. """
+ self.vector[:] = 1.
+ self.assertEqual(0., zero_crossing_rate(self.vector))
+
+ def test_impulse(self):
+ """ check zero crossing rate on a buffer with an impulse """
+ self.vector[int(buf_size / 2)] = 1.
+ self.assertEqual(0., zero_crossing_rate(self.vector))
+
+ def test_negative_impulse(self):
+ """ check zero crossing rate on a buffer with a negative impulse """
+ self.vector[int(buf_size / 2)] = -1.
+ self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
+
+ def test_single(self):
+ """ check zero crossing rate on single crossing """
+ self.vector[int(buf_size / 2) - 1] = 1.
+ self.vector[int(buf_size / 2)] = -1.
+ self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
+
+ def test_single_with_gap(self):
+ """ check zero crossing rate on single crossing with a gap"""
+ self.vector[int(buf_size / 2) - 2] = 1.
+ self.vector[int(buf_size / 2)] = -1.
+ self.assertEqual(2./buf_size, zero_crossing_rate(self.vector))
+
+if __name__ == '__main__':
+ main()
diff --git a/python/tests/utils.py b/python/tests/utils.py
new file mode 100644
index 0000000..2e3c31e
--- /dev/null
+++ b/python/tests/utils.py
@@ -0,0 +1,79 @@
+#! /usr/bin/env python
+
+import os
+import glob
+import numpy as np
+from tempfile import mkstemp
+
+def array_from_text_file(filename, dtype = 'float'):
+ filename = os.path.join(os.path.dirname(__file__), filename)
+ with open(filename) as f:
+ lines = f.readlines()
+ return np.array([line.split() for line in lines],
+ dtype = dtype)
+
+def list_all_sounds(rel_dir):
+ datadir = os.path.join(os.path.dirname(__file__), rel_dir)
+ return glob.glob(os.path.join(datadir,'*.*'))
+
+def get_default_test_sound(TestCase, rel_dir = 'sounds'):
+ all_sounds = list_all_sounds(rel_dir)
+ if len(all_sounds) == 0:
+ TestCase.skipTest("please add some sounds in \'python/tests/sounds\'")
+ else:
+ return all_sounds[0]
+
+def get_tmp_sink_path():
+ fd, path = mkstemp()
+ os.close(fd)
+ return path
+
+def del_tmp_sink_path(path):
+ try:
+ os.unlink(path)
+ except WindowsError as e:
+ print("deleting {:s} failed ({:s}), reopening".format(path, repr(e)))
+ with open(path, 'wb') as f:
+ f.close()
+ try:
+ os.unlink(path)
+ except WindowsError as f:
+ print("deleting {:s} failed ({:s}), aborting".format(path, repr(e)))
+
+def array_from_yaml_file(filename):
+ import yaml
+ f = open(filename)
+ yaml_data = yaml.safe_load(f)
+ f.close()
+ return yaml_data
+
+def count_samples_in_file(file_path):
+ from aubio import source
+ hopsize = 256
+ s = source(file_path, 0, hopsize)
+ total_frames = 0
+ while True:
+ _, read = s()
+ total_frames += read
+ if read < hopsize: break
+ return total_frames
+
+def count_samples_in_directory(samples_dir):
+ total_frames = 0
+ for f in os.walk(samples_dir):
+ if len(f[2]):
+ for each in f[2]:
+ file_path = os.path.join(f[0], each)
+ if file_path:
+ total_frames += count_samples_in_file(file_path)
+ return total_frames
+
+def count_files_in_directory(samples_dir):
+ total_files = 0
+ for f in os.walk(samples_dir):
+ if len(f[2]):
+ for each in f[2]:
+ file_path = os.path.join(f[0], each)
+ if file_path:
+ total_files += 1
+ return total_files
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..99ce0ab
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+numpy
+nose2
diff --git a/scripts/apple/Info.plist b/scripts/apple/Info.plist
new file mode 100644
index 0000000..e5ac0ba
--- /dev/null
+++ b/scripts/apple/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.aubio.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(CURRENT_PROJECT_VERSION)</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2015 Paul Brossier. All rights reserved.</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
diff --git a/scripts/apple/Modules/module.modulemap b/scripts/apple/Modules/module.modulemap
new file mode 100644
index 0000000..0fba24c
--- /dev/null
+++ b/scripts/apple/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module aubio {
+ umbrella header "aubio.h"
+
+ export *
+ module * { export * }
+}
diff --git a/scripts/build_apple_frameworks b/scripts/build_apple_frameworks
new file mode 100755
index 0000000..08df8f6
--- /dev/null
+++ b/scripts/build_apple_frameworks
@@ -0,0 +1,100 @@
+#! /bin/sh
+
+AUBIO_TMPDIR=`mktemp -d /var/tmp/aubio-build-XXXX`
+PACKAGE=aubio
+source VERSION
+VERSION=$AUBIO_MAJOR_VERSION.$AUBIO_MINOR_VERSION.$AUBIO_PATCH_VERSION$AUBIO_VERSION_STATUS
+LIBVERSION=$LIBAUBIO_LT_CUR.$LIBAUBIO_LT_REV.$LIBAUBIO_LT_AGE
+OUTPUTDIR=$PWD/dist
+mkdir -p "$OUTPUTDIR"
+# add git abbreviated commit hash
+#VERSION+=+$(git log --pretty=format:"%h" -1)
+
+CFLAGS="-Werror -Ofast"
+WAFCONF="--disable-sndfile --disable-avcodec --disable-samplerate --enable-fat" # --disable-memcpy --disable-accelerate"
+
+export VERSION
+
+function cleanup () {
+ rm -rf $AUBIO_TMPDIR
+}
+
+trap cleanup SIGINT SIGTERM
+
+function create_tarballs() {
+ # name version platform
+ # create tarball
+ tarfile=$OUTPUTDIR/$1-$2.$3_binary.tar.bz2
+ tar -C $AUBIO_TMPDIR/dist-$3/ -jcf "$tarfile" .
+ #rm -rf $AUBIO_TMPDIR/dist-$3
+}
+
+function create_framework() {
+ rm -rf $AUBIO_TMPDIR/framework-$3
+ mkdir -p $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework
+ cp -pr COPYING README.md $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework
+ pushd $AUBIO_TMPDIR/framework-$3
+ cp -pr "$OLDPWD/build/src/lib$1.a" $1-$2.$3_framework/$1.framework/$1 || \
+ cp -pr $AUBIO_TMPDIR/dist-$3/usr/local/lib/lib$1.$LIBVERSION.dylib \
+ $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework/$1
+ cp -pr $AUBIO_TMPDIR/dist-$3/usr/local/include/$1 $1-$2.$3_framework/$1.framework/Headers
+ cp -pr "$OLDPWD/scripts/apple/Modules" $1-$2.$3_framework/$1.framework/
+ popd
+}
+
+function create_framework_fat() {
+ rm -rf $AUBIO_TMPDIR/framework-$3
+ mkdir -p $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework
+ cp -pr COPYING README.md $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework
+ pushd $AUBIO_TMPDIR/framework-$3
+ cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Headers $1-$2.$3_framework/$1.framework
+ cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Modules $1-$2.$3_framework/$1.framework
+ lipo $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/$1 \
+ $AUBIO_TMPDIR/framework-iosimulator/$1-$2.iosimulator_framework/$1.framework/$1 \
+ -output $1-$2.$3_framework/$1.framework/$1 -create
+ popd
+}
+
+function create_framework_zip() {
+ # create zip
+ pushd $AUBIO_TMPDIR/framework-$3
+ zipfile=$1-$2.$3_framework.zip
+ zip -qr $zipfile $1-$2.$3_framework
+ popd
+ mv $AUBIO_TMPDIR/framework-$3/$zipfile "$OUTPUTDIR"
+}
+
+set -x
+set -e
+
+#./waf dist --verbose
+
+for PLATFORM in darwin ios iosimulator
+do
+ rm -rf $AUBIO_TMPDIR/dist-$PLATFORM
+ WAF_OPTIONS="--verbose --destdir $AUBIO_TMPDIR/dist-$PLATFORM --with-target-platform $PLATFORM $WAFCONF"
+ for target in distclean configure build install
+ do
+ CFLAGS="$CFLAGS" ./waf $target $WAF_OPTIONS
+ done
+
+ create_framework $PACKAGE $VERSION $PLATFORM
+ if [ $PLATFORM == 'darwin' ]
+ then
+ # on darwin, build a .tar.bz2 of /usr and a .zip of aubio.framework
+ create_tarballs $PACKAGE $VERSION $PLATFORM
+ create_framework_zip $PACKAGE $VERSION $PLATFORM
+ fi
+ ./waf uninstall $WAF_OPTIONS
+
+done
+
+# after both ios and iosimulator have been built
+PLATFORM=iosuniversal
+create_framework_fat $PACKAGE $VERSION $PLATFORM
+create_framework_zip $PACKAGE $VERSION $PLATFORM
+
+./waf clean
+./waf distclean
+
+cleanup
diff --git a/scripts/build_emscripten b/scripts/build_emscripten
new file mode 100755
index 0000000..9d4fc54
--- /dev/null
+++ b/scripts/build_emscripten
@@ -0,0 +1,21 @@
+#! /bin/sh
+
+function checkprog() {
+ type $1 >/dev/null 2>&1 || { echo >&2 "$1 required but not found, aborting."; exit 1; }
+}
+
+checkprog emcc
+checkprog emconfigure
+checkprog emmake
+
+# clean
+emmake ./waf distclean
+
+# configure
+emconfigure ./waf configure --prefix=$EMSCRIPTEN/system/local/ --with-target-platform emscripten
+
+# build
+emmake ./waf --testcmd="node %s"
+
+# intall
+#emmake ./waf install
diff --git a/scripts/build_mingw b/scripts/build_mingw
new file mode 100755
index 0000000..8c02894
--- /dev/null
+++ b/scripts/build_mingw
@@ -0,0 +1,28 @@
+#! /bin/bash
+
+# This script cross compiles aubio for windows using mingw, both for 32 and 64
+# bits. Built binaries will be placed in ./dist-win32 and ./dist-win64.
+
+# On debian or ubuntu, you will want to 'apt-get install gcc-mingw-w64'
+
+set -e
+set -x
+
+WAFOPTS="-v --disable-avcodec --disable-samplerate --disable-jack --disable-sndfile"
+
+[ -d dist-win32 ] && rm -rf dist-win32
+[ -d dist-win64 ] && rm -rf dist-win64
+
+CFLAGS="-Os" \
+ LDFLAGS="" \
+ CC=x86_64-w64-mingw32-gcc \
+ ./waf distclean configure build install --destdir=$PWD/dist-win64 \
+ --testcmd="echo %s" \
+ $WAFOPTS --with-target-platform=win64
+
+CFLAGS="-Os" \
+ LDFLAGS="" \
+ CC=i686-w64-mingw32-gcc \
+ ./waf distclean configure build install --destdir=$PWD/dist-win32 \
+ --testcmd="echo %s" \
+ $WAFOPTS --with-target-platform=win32
diff --git a/scripts/get_waf.sh b/scripts/get_waf.sh
new file mode 100755
index 0000000..5b41d8d
--- /dev/null
+++ b/scripts/get_waf.sh
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+set -e
+set -x
+
+WAFURL=https://waf.io/waf-1.8.22
+
+( which wget > /dev/null && wget -qO waf $WAFURL ) || ( which curl > /dev/null && curl $WAFURL > waf )
+
+chmod +x waf
diff --git a/scripts/setenv_local.sh b/scripts/setenv_local.sh
new file mode 100644
index 0000000..ac9a5cf
--- /dev/null
+++ b/scripts/setenv_local.sh
@@ -0,0 +1,32 @@
+#! /usr/bin/env bash
+
+# This script sets the environment to execute aubio binaries and python code
+# directly from build/ python/build/ without installing libaubio on the system
+
+# Usage: $ source ./scripts/setenv_local.sh
+
+# WARNING: this script will *overwrite* existing (DY)LD_LIBRARY_PATH and
+# PYTHONPATH variables.
+
+PYTHON_PLATFORM=`python -c "import pkg_resources, sys; print '%s-%s' % (pkg_resources.get_build_platform(), '.'.join(map(str, sys.version_info[0:2])))"`
+
+AUBIODIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
+AUBIOLIB=$AUBIODIR/build/src
+AUBIOPYTHON=$AUBIODIR/build/lib.$PYTHON_PLATFORM
+
+if [ "$(dirname $PWD)" == "scripts" ]; then
+ AUBIODIR=$(basename $PWD)
+else
+ AUBIODIR=$(basename $PWD)
+fi
+
+if [ "$(uname)" == "Darwin" ]; then
+ export DYLD_LIBRARY_PATH=$AUBIOLIB
+ echo export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH
+else
+ export LD_LIBRARY_PATH=$AUBIOLIB
+ echo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+fi
+
+export PYTHONPATH=$AUBIOPYTHON
+echo export PYTHONPATH=$PYTHONPATH
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..8c9552b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,111 @@
+#! /usr/bin/env python
+
+import sys, os.path, glob
+from setuptools import setup, Extension
+from python.lib.moresetuptools import *
+# function to generate gen/*.{c,h}
+from python.lib.gen_external import generate_external, header, output_path
+
+# read from VERSION
+for l in open('VERSION').readlines(): exec (l.strip())
+
+if AUBIO_MAJOR_VERSION is None or AUBIO_MINOR_VERSION is None \
+ or AUBIO_PATCH_VERSION is None:
+ raise SystemError("Failed parsing VERSION file.")
+
+__version__ = '.'.join(map(str, [AUBIO_MAJOR_VERSION,
+ AUBIO_MINOR_VERSION,
+ AUBIO_PATCH_VERSION]))
+if AUBIO_VERSION_STATUS is not None:
+ if AUBIO_VERSION_STATUS.startswith('~'):
+ AUBIO_VERSION_STATUS = AUBIO_VERSION_STATUS[1:]
+ __version__ += AUBIO_VERSION_STATUS
+
+include_dirs = []
+library_dirs = []
+define_macros = []
+extra_link_args = []
+
+include_dirs += [ 'python/ext' ]
+include_dirs += [ output_path ] # aubio-generated.h
+try:
+ import numpy
+ include_dirs += [ numpy.get_include() ]
+except ImportError:
+ pass
+
+if sys.platform.startswith('darwin'):
+ extra_link_args += ['-framework','CoreFoundation', '-framework','AudioToolbox']
+
+sources = glob.glob(os.path.join('python', 'ext', '*.c'))
+
+aubio_extension = Extension("aubio._aubio",
+ sources,
+ include_dirs = include_dirs,
+ library_dirs = library_dirs,
+ extra_link_args = extra_link_args,
+ define_macros = define_macros)
+
+if os.path.isfile('src/aubio.h'):
+ # if aubio headers are found in this directory
+ add_local_aubio_header(aubio_extension)
+ # was waf used to build the shared lib?
+ if os.path.isdir(os.path.join('build','src')):
+ # link against build/src/libaubio, built with waf
+ add_local_aubio_lib(aubio_extension)
+ else:
+ # add libaubio sources and look for optional deps with pkg-config
+ add_local_aubio_sources(aubio_extension)
+ __version__ += '_libaubio'
+else:
+ # look for aubio headers and lib using pkg-config
+ add_system_aubio(aubio_extension)
+
+
+classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Console',
+ 'Intended Audience :: Science/Research',
+ 'Topic :: Software Development :: Libraries',
+ 'Topic :: Multimedia :: Sound/Audio :: Analysis',
+ 'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis',
+ 'Operating System :: POSIX',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Programming Language :: C',
+ 'Programming Language :: Python',
+ 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+ ]
+
+from distutils.command.build_ext import build_ext as _build_ext
+class build_ext(_build_ext):
+
+ def build_extension(self, extension):
+ # generate files python/gen/*.c, python/gen/aubio-generated.h
+ extension.sources += generate_external(header, output_path, overwrite = False)
+ return _build_ext.build_extension(self, extension)
+
+distrib = setup(name='aubio',
+ version = __version__,
+ packages = ['aubio'],
+ package_dir = {'aubio':'python/lib/aubio'},
+ scripts = ['python/scripts/aubiocut'],
+ ext_modules = [aubio_extension],
+ description = 'interface to the aubio library',
+ long_description = 'interface to the aubio library',
+ license = 'GNU/GPL version 3',
+ author = 'Paul Brossier',
+ author_email = 'piem@aubio.org',
+ maintainer = 'Paul Brossier',
+ maintainer_email = 'piem@aubio.org',
+ url = 'http://aubio.org/',
+ platforms = 'any',
+ classifiers = classifiers,
+ install_requires = ['numpy'],
+ cmdclass = {
+ 'clean': CleanGenerated,
+ 'generate': GenerateCommand,
+ 'build_ext': build_ext,
+ },
+ test_suite = 'nose2.collector.collector',
+ )
diff --git a/src/aubio.h b/src/aubio.h
new file mode 100644
index 0000000..0d2b416
--- /dev/null
+++ b/src/aubio.h
@@ -0,0 +1,218 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \mainpage
+
+ \section introduction Introduction
+
+ aubio is a library to extract annotations from audio signals: it provides a
+ set of functions that take an input audio signal, and output pitch estimates,
+ attack times (onset), beat location estimates, and other annotation tasks.
+
+ \section basics Basics
+
+ All object structures in aubio share the same function prefixes and suffixes:
+
+ - \p new_aubio_foo creates the object \p foo
+ - \p aubio_foo_do executes the object \p foo
+ - \p del_aubio_foo destroys the object \p foo
+
+ All memory allocation and deallocation take place in the \p new_ and \p del_
+ functions. Optionally, more than one \p _do methods are available.
+ Additional parameters can be adjusted and observed using:
+
+ - \p aubio_foo_get_param, getter function, gets the value of a parameter
+ - \p aubio_foo_set_param, setter function, changes the value of a parameter
+
+ Unless specified in its documentation, no memory operations take place in the
+ getter functions. However, memory resizing can take place in setter
+ functions.
+
+ \subsection vectors Vectors
+
+ Two basic structures are being used in aubio: ::fvec_t and ::cvec_t. The
+ ::fvec_t structures are used to store vectors of floating pointer number.
+ ::cvec_t are used to store complex number, as two vectors of norm and phase
+ elements.
+
+ Additionally, the ::lvec_t structure can be used to store floating point
+ numbers in double precision. They are mostly used to store filter
+ coefficients, to avoid instability.
+
+ \subsection objects Available objects
+
+ Here is a list of some of the most common objects for aubio:
+
+ \code
+
+ // fast Fourier transform (FFT)
+ aubio_fft_t *fft = new_aubio_fft (winsize);
+ // phase vocoder
+ aubio_pvoc_t *pv = new_aubio_pvoc (winsize, stepsize);
+ // onset detection
+ aubio_onset_t *onset = new_aubio_onset (method, winsize, stepsize, samplerate);
+ // pitch detection
+ aubio_pitch_t *pitch = new_aubio_pitch (method, winsize, stepsize, samplerate);
+ // beat tracking
+ aubio_tempo_t *tempo = new_aubio_tempo (method, winsize, stepsize, samplerate);
+
+ \endcode
+
+ See the <a href="globals_type.html">list of typedefs</a> for a complete list.
+
+ \subsection example Example
+
+ Here is a simple example that creates an A-Weighting filter and applies it to a
+ vector.
+
+ \code
+
+ // set window size, and sampling rate
+ uint_t winsize = 1024, sr = 44100;
+ // create a vector
+ fvec_t *this_buffer = new_fvec (winsize);
+ // create the a-weighting filter
+ aubio_filter_t *this_filter = new_aubio_filter_a_weighting (sr);
+
+ while (running) {
+ // here some code to put some data in this_buffer
+ // ...
+
+ // apply the filter, in place
+ aubio_filter_do (this_filter, this_buffer);
+
+ // here some code to get some data from this_buffer
+ // ...
+ }
+
+ // and free the structures
+ del_aubio_filter (this_filter);
+ del_fvec (this_buffer);
+
+ \endcode
+
+ Several examples of C programs are available in the \p examples/ and \p tests/src
+ directories of the source tree.
+
+ \subsection unstable_api Unstable API
+
+ Several more functions are available and used within aubio, but not
+ documented here, either because they are not considered useful to the user,
+ or because they may need to be changed in the future. However, they can still
+ be used by defining AUBIO_UNSTABLE to 1 before including the aubio header:
+
+ \code
+ #define AUBIO_UNSTABLE 1
+ #include <aubio/aubio.h>
+ \endcode
+
+ Future versions of aubio could break API compatibility with these functions
+ without warning. If you choose to use functions in AUBIO_UNSTABLE, you are on
+ your own.
+
+ \section download Download
+
+ Latest versions, further documentation, examples, wiki, and mailing lists can
+ be found at http://aubio.org .
+
+ */
+
+#ifndef AUBIO_H
+#define AUBIO_H
+
+/** @file aubio.h Global aubio include file.
+
+ You will want to include this file as:
+
+ @code
+ #include <aubio/aubio.h>
+ @endcode
+
+ To access headers with unstable prototypes, use:
+
+ @code
+ #define AUBIO_UNSTABLE 1
+ #include <aubio/aubio.h>
+ @endcode
+
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* in this order */
+#include "types.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "lvec.h"
+#include "fmat.h"
+#include "musicutils.h"
+#include "vecutils.h"
+#include "temporal/resampler.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+#include "temporal/a_weighting.h"
+#include "temporal/c_weighting.h"
+#include "spectral/fft.h"
+#include "spectral/phasevoc.h"
+#include "spectral/filterbank.h"
+#include "spectral/filterbank_mel.h"
+#include "spectral/mfcc.h"
+#include "spectral/specdesc.h"
+#include "spectral/tss.h"
+#include "pitch/pitch.h"
+#include "onset/onset.h"
+#include "tempo/tempo.h"
+#include "notes/notes.h"
+#include "io/source.h"
+#include "io/sink.h"
+#include "synth/sampler.h"
+#include "synth/wavetable.h"
+#include "utils/parameter.h"
+
+#if AUBIO_UNSTABLE
+#include "mathutils.h"
+#include "io/source_sndfile.h"
+#include "io/source_apple_audio.h"
+#include "io/source_avcodec.h"
+#include "io/source_wavread.h"
+#include "io/sink_sndfile.h"
+#include "io/sink_apple_audio.h"
+#include "io/sink_wavwrite.h"
+#include "io/audio_unit.h"
+#include "onset/peakpicker.h"
+#include "pitch/pitchmcomb.h"
+#include "pitch/pitchyin.h"
+#include "pitch/pitchyinfft.h"
+#include "pitch/pitchschmitt.h"
+#include "pitch/pitchfcomb.h"
+#include "pitch/pitchspecacf.h"
+#include "tempo/beattracking.h"
+#include "utils/scale.h"
+#include "utils/hist.h"
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/aubio_priv.h b/src/aubio_priv.h
new file mode 100644
index 0000000..530edc9
--- /dev/null
+++ b/src/aubio_priv.h
@@ -0,0 +1,305 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file
+ * Private include file
+ *
+ * This file is for inclusion from _within_ the library only.
+ */
+
+#ifndef AUBIO_PRIV_H
+#define AUBIO_PRIV_H
+
+/*********************
+ *
+ * External includes
+ *
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+/* must be included before fftw3.h */
+#ifdef HAVE_COMPLEX_H
+#include <complex.h>
+#endif
+
+#if defined(HAVE_FFTW3) || defined(HAVE_FFTW3F)
+#include <fftw3.h>
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h> // for CHAR_BIT, in C99 standard
+#endif
+
+#ifdef HAVE_ACCELERATE
+#define HAVE_ATLAS 1
+#include <Accelerate/Accelerate.h>
+#elif defined(HAVE_ATLAS_CBLAS_H)
+#define HAVE_ATLAS 1
+#include <atlas/cblas.h>
+#else
+#undef HAVE_ATLAS
+#endif
+
+#ifdef HAVE_ACCELERATE
+#include <Accelerate/Accelerate.h>
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_vDSP_mmov vDSP_mmov
+#define aubio_vDSP_vmul vDSP_vmul
+#define aubio_vDSP_vfill vDSP_vfill
+#define aubio_vDSP_meanv vDSP_meanv
+#define aubio_vDSP_sve vDSP_sve
+#define aubio_vDSP_maxv vDSP_maxv
+#define aubio_vDSP_maxvi vDSP_maxvi
+#define aubio_vDSP_minv vDSP_minv
+#define aubio_vDSP_minvi vDSP_minvi
+#define aubio_vDSP_dotpr vDSP_dotpr
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_vDSP_mmov vDSP_mmovD
+#define aubio_vDSP_vmul vDSP_vmulD
+#define aubio_vDSP_vfill vDSP_vfillD
+#define aubio_vDSP_meanv vDSP_meanvD
+#define aubio_vDSP_sve vDSP_sveD
+#define aubio_vDSP_maxv vDSP_maxvD
+#define aubio_vDSP_maxvi vDSP_maxviD
+#define aubio_vDSP_minv vDSP_minvD
+#define aubio_vDSP_minvi vDSP_minviD
+#define aubio_vDSP_dotpr vDSP_dotprD
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_ACCELERATE */
+
+#ifdef HAVE_ATLAS
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_catlas_set catlas_sset
+#define aubio_cblas_copy cblas_scopy
+#define aubio_cblas_swap cblas_sswap
+#define aubio_cblas_dot cblas_sdot
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_catlas_set catlas_dset
+#define aubio_cblas_copy cblas_dcopy
+#define aubio_cblas_swap cblas_dswap
+#define aubio_cblas_dot cblas_ddot
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_ATLAS */
+
+#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+#define HAVE_NOOPT 1
+#else
+#undef HAVE_NOOPT
+#endif
+
+#include "types.h"
+
+#define AUBIO_UNSTABLE 1
+
+#include "mathutils.h"
+
+/****
+ *
+ * SYSTEM INTERFACE
+ *
+ */
+
+/* Memory management */
+#define AUBIO_MALLOC(_n) malloc(_n)
+#define AUBIO_REALLOC(_p,_n) realloc(_p,_n)
+#define AUBIO_NEW(_t) (_t*)calloc(sizeof(_t), 1)
+#define AUBIO_ARRAY(_t,_n) (_t*)calloc((_n)*sizeof(_t), 1)
+#define AUBIO_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
+#define AUBIO_MEMSET(_dst,_src,_t) memset(_dst,_src,_t)
+#define AUBIO_FREE(_p) free(_p)
+
+
+/* file interface */
+#define AUBIO_FOPEN(_f,_m) fopen(_f,_m)
+#define AUBIO_FCLOSE(_f) fclose(_f)
+#define AUBIO_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
+#define AUBIO_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
+
+/* strings */
+#define AUBIO_STRLEN(_s) strlen(_s)
+#define AUBIO_STRCMP(_s,_t) strcmp(_s,_t)
+#define AUBIO_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
+#define AUBIO_STRCPY(_dst,_src) strcpy(_dst,_src)
+#define AUBIO_STRCHR(_s,_c) strchr(_s,_c)
+#ifdef strdup
+#define AUBIO_STRDUP(s) strdup(s)
+#else
+#define AUBIO_STRDUP(s) AUBIO_STRCPY(AUBIO_MALLOC(AUBIO_STRLEN(s) + 1), s)
+#endif
+
+
+/* Error reporting */
+typedef enum {
+ AUBIO_OK = 0,
+ AUBIO_FAIL = 1
+} aubio_status;
+
+#ifdef HAVE_C99_VARARGS_MACROS
+#define AUBIO_ERR(...) fprintf(stderr, "AUBIO ERROR: " __VA_ARGS__)
+#define AUBIO_MSG(...) fprintf(stdout, __VA_ARGS__)
+#define AUBIO_DBG(...) fprintf(stderr, __VA_ARGS__)
+#define AUBIO_WRN(...) fprintf(stderr, "AUBIO WARNING: " __VA_ARGS__)
+#else
+#define AUBIO_ERR(format, args...) fprintf(stderr, "AUBIO ERROR: " format , ##args)
+#define AUBIO_MSG(format, args...) fprintf(stdout, format , ##args)
+#define AUBIO_DBG(format, args...) fprintf(stderr, format , ##args)
+#define AUBIO_WRN(format, args...) fprintf(stderr, "AUBIO WARNING: " format, ##args)
+#endif
+
+#define AUBIO_ERROR AUBIO_ERR
+
+#define AUBIO_QUIT(_s) exit(_s)
+#define AUBIO_SPRINTF sprintf
+
+/* pi and 2*pi */
+#ifndef M_PI
+#define PI (3.14159265358979323846)
+#else
+#define PI (M_PI)
+#endif
+#define TWO_PI (PI*2.)
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/* aliases to math.h functions */
+#if !HAVE_AUBIO_DOUBLE
+#define EXP expf
+#define COS cosf
+#define SIN sinf
+#define ABS fabsf
+#define POW powf
+#define SQRT sqrtf
+#define LOG10 log10f
+#define LOG logf
+#define FLOOR floorf
+#define CEIL ceilf
+#define ATAN2 atan2f
+#else
+#define EXP exp
+#define COS cos
+#define SIN sin
+#define ABS fabs
+#define POW pow
+#define SQRT sqrt
+#define LOG10 log10
+#define LOG log
+#define FLOOR floor
+#define CEIL ceil
+#define ATAN2 atan2
+#endif
+#define ROUND(x) FLOOR(x+.5)
+
+/* aliases to complex.h functions */
+#if HAVE_AUBIO_DOUBLE || !defined(HAVE_COMPLEX_H) || defined(WIN32)
+/* mingw32 does not know about c*f functions */
+#define EXPC cexp
+/** complex = CEXPC(complex) */
+#define CEXPC cexp
+/** sample = ARGC(complex) */
+#define ARGC carg
+/** sample = ABSC(complex) norm */
+#define ABSC cabs
+/** sample = REAL(complex) */
+#define REAL creal
+/** sample = IMAG(complex) */
+#define IMAG cimag
+#else
+/** sample = EXPC(complex) */
+#define EXPC cexpf
+/** complex = CEXPC(complex) */
+#define CEXPC cexp
+/** sample = ARGC(complex) */
+#define ARGC cargf
+/** sample = ABSC(complex) norm */
+#define ABSC cabsf
+/** sample = REAL(complex) */
+#define REAL crealf
+/** sample = IMAG(complex) */
+#define IMAG cimagf
+#endif
+
+/* avoid unresolved symbol with msvc 9 */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define isnan _isnan
+#endif
+
+/* handy shortcuts */
+#define DB2LIN(g) (POW(10.0,(g)*0.05f))
+#define LIN2DB(v) (20.0*LOG10(v))
+#define SQR(_a) ((_a)*(_a))
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif /* MAX */
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif /* MIN */
+
+#define ELEM_SWAP(a,b) { register smpl_t t=(a);(a)=(b);(b)=t; }
+
+#define VERY_SMALL_NUMBER 2.e-42 //1.e-37
+
+/** if ABS(f) < VERY_SMALL_NUMBER, returns 1, else 0 */
+#define IS_DENORMAL(f) ABS(f) < VERY_SMALL_NUMBER
+
+/** if ABS(f) < VERY_SMALL_NUMBER, returns 0., else f */
+#define KILL_DENORMAL(f) IS_DENORMAL(f) ? 0. : f
+
+/** if f > VERY_SMALL_NUMBER, returns f, else returns VERY_SMALL_NUMBER */
+#define CEIL_DENORMAL(f) f < VERY_SMALL_NUMBER ? VERY_SMALL_NUMBER : f
+
+#define SAFE_LOG10(f) LOG10(CEIL_DENORMAL(f))
+#define SAFE_LOG(f) LOG(CEIL_DENORMAL(f))
+
+/** silence unused parameter warning by adding an attribute */
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+/* are we using gcc -std=c99 ? */
+#if defined(__STRICT_ANSI__)
+#define strnlen(a,b) MIN(strlen(a),b)
+#if !HAVE_AUBIO_DOUBLE
+#define floorf floor
+#endif
+#endif /* __STRICT_ANSI__ */
+
+#endif /* AUBIO_PRIV_H */
diff --git a/src/cvec.c b/src/cvec.c
new file mode 100644
index 0000000..2e98cf5
--- /dev/null
+++ b/src/cvec.c
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "cvec.h"
+
+cvec_t * new_cvec(uint_t length) {
+ cvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(cvec_t);
+ s->length = length/2 + 1;
+ s->norm = AUBIO_ARRAY(smpl_t,s->length);
+ s->phas = AUBIO_ARRAY(smpl_t,s->length);
+ return s;
+}
+
+void del_cvec(cvec_t *s) {
+ AUBIO_FREE(s->norm);
+ AUBIO_FREE(s->phas);
+ AUBIO_FREE(s);
+}
+
+void cvec_norm_set_sample (cvec_t *s, smpl_t data, uint_t position) {
+ s->norm[position] = data;
+}
+
+void cvec_phas_set_sample (cvec_t *s, smpl_t data, uint_t position) {
+ s->phas[position] = data;
+}
+
+smpl_t cvec_norm_get_sample (cvec_t *s, uint_t position) {
+ return s->norm[position];
+}
+
+smpl_t cvec_phas_get_sample (cvec_t *s, uint_t position) {
+ return s->phas[position];
+}
+
+smpl_t * cvec_norm_get_data (const cvec_t *s) {
+ return s->norm;
+}
+
+smpl_t * cvec_phas_get_data (const cvec_t *s) {
+ return s->phas;
+}
+
+/* helper functions */
+
+void cvec_print(const cvec_t *s) {
+ uint_t j;
+ AUBIO_MSG("norm: ");
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->norm[j]);
+ }
+ AUBIO_MSG("\n");
+ AUBIO_MSG("phas: ");
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->phas[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void cvec_copy(const cvec_t *s, cvec_t *t) {
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d elements to %d elements \n",
+ s->length, t->length);
+ return;
+ }
+#ifdef HAVE_MEMCPY_HACKS
+ memcpy(t->norm, s->norm, t->length * sizeof(smpl_t));
+ memcpy(t->phas, s->phas, t->length * sizeof(smpl_t));
+#else /* HAVE_MEMCPY_HACKS */
+ uint_t j;
+ for (j=0; j< t->length; j++) {
+ t->norm[j] = s->norm[j];
+ t->phas[j] = s->phas[j];
+ }
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void cvec_norm_set_all (cvec_t *s, smpl_t val) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->norm[j] = val;
+ }
+}
+
+void cvec_norm_zeros(cvec_t *s) {
+#ifdef HAVE_MEMCPY_HACKS
+ memset(s->norm, 0, s->length * sizeof(smpl_t));
+#else /* HAVE_MEMCPY_HACKS */
+ cvec_norm_set_all (s, 0.);
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void cvec_norm_ones(cvec_t *s) {
+ cvec_norm_set_all (s, 1.);
+}
+
+void cvec_phas_set_all (cvec_t *s, smpl_t val) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->phas[j] = val;
+ }
+}
+
+void cvec_phas_zeros(cvec_t *s) {
+#ifdef HAVE_MEMCPY_HACKS
+ memset(s->phas, 0, s->length * sizeof(smpl_t));
+#else
+ cvec_phas_set_all (s, 0.);
+#endif
+}
+
+void cvec_phas_ones(cvec_t *s) {
+ cvec_phas_set_all (s, 1.);
+}
+
+void cvec_zeros(cvec_t *s) {
+ cvec_norm_zeros(s);
+ cvec_phas_zeros(s);
+}
diff --git a/src/cvec.h b/src/cvec.h
new file mode 100644
index 0000000..d0a9c2b
--- /dev/null
+++ b/src/cvec.h
@@ -0,0 +1,237 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_CVEC_H
+#define AUBIO_CVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of complex-valued data, stored in polar coordinates
+
+ This file specifies the ::cvec_t buffer type, which is used throughout aubio
+ to store complex data. Complex values are stored in terms of ::cvec_t.phas
+ and norm, within 2 vectors of ::smpl_t of size (size/2+1) each.
+
+ \example test-cvec.c
+
+*/
+
+/** Vector of real-valued phase and spectrum data
+
+ \code
+
+ uint_t buffer_size = 1024;
+
+ // create a complex vector of 512 values
+ cvec_t * input = new_cvec (buffer_size);
+
+ // set some values of the vector
+ input->norm[23] = 2.;
+ input->phas[23] = M_PI;
+ // ..
+
+ // compute the mean of the vector
+ mean = cvec_mean(input);
+
+ // destroy the vector
+ del_cvec (input);
+
+ \endcode
+
+ */
+typedef struct {
+ uint_t length; /**< length of buffer = (requested length)/2 + 1 */
+ smpl_t *norm; /**< norm array of size ::cvec_t.length */
+ smpl_t *phas; /**< phase array of size ::cvec_t.length */
+} cvec_t;
+
+/** cvec_t buffer creation function
+
+ This function creates a cvec_t structure holding two arrays of size
+ [length/2+1], corresponding to the norm and phase values of the
+ spectral frame. The length stored in the structure is the actual size of both
+ arrays, not the length of the complex and symmetrical vector, specified as
+ creation argument.
+
+ \param length the length of the buffer to create
+
+*/
+cvec_t * new_cvec(uint_t length);
+
+/** cvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_cvec()
+
+*/
+void del_cvec(cvec_t *s);
+
+/** write norm value in a complex buffer
+
+ This is equivalent to:
+ \code
+ s->norm[position] = val;
+ \endcode
+
+ \param s vector to write to
+ \param val norm value to write in s->norm[position]
+ \param position sample position to write to
+
+*/
+void cvec_norm_set_sample (cvec_t *s, smpl_t val, uint_t position);
+
+/** write phase value in a complex buffer
+
+ This is equivalent to:
+ \code
+ s->phas[position] = val;
+ \endcode
+
+ \param s vector to write to
+ \param val phase value to write in s->phas[position]
+ \param position sample position to write to
+
+*/
+void cvec_phas_set_sample (cvec_t *s, smpl_t val, uint_t position);
+
+/** read norm value from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t foo = s->norm[position];
+ \endcode
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+smpl_t cvec_norm_get_sample (cvec_t *s, uint_t position);
+
+/** read phase value from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t foo = s->phas[position];
+ \endcode
+
+ \param s vector to read from
+ \param position sample position to read from
+ \returns the value of the sample at position
+
+*/
+smpl_t cvec_phas_get_sample (cvec_t *s, uint_t position);
+
+/** read norm data from a complex buffer
+
+ \code
+ smpl_t *data = s->norm;
+ \endcode
+
+ \param s vector to read from
+
+*/
+smpl_t * cvec_norm_get_data (const cvec_t *s);
+
+/** read phase data from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t *data = s->phas;
+ \endcode
+
+ \param s vector to read from
+
+*/
+smpl_t * cvec_phas_get_data (const cvec_t *s);
+
+/** print out cvec data
+
+ \param s vector to print out
+
+*/
+void cvec_print(const cvec_t *s);
+
+/** make a copy of a vector
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void cvec_copy(const cvec_t *s, cvec_t *t);
+
+/** set all norm elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void cvec_norm_set_all (cvec_t *s, smpl_t val);
+
+/** set all norm elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_norm_zeros(cvec_t *s);
+
+/** set all norm elements to one
+
+ \param s vector to modify
+
+*/
+void cvec_norm_ones(cvec_t *s);
+
+/** set all phase elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void cvec_phas_set_all (cvec_t *s, smpl_t val);
+
+/** set all phase elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_phas_zeros(cvec_t *s);
+
+/** set all phase elements to one
+
+ \param s vector to modify
+
+*/
+void cvec_phas_ones(cvec_t *s);
+
+/** set all norm and phas elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_zeros(cvec_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_CVEC_H */
diff --git a/src/fmat.c b/src/fmat.c
new file mode 100644
index 0000000..2d404d8
--- /dev/null
+++ b/src/fmat.c
@@ -0,0 +1,186 @@
+/*
+ Copyright (C) 2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+
+fmat_t * new_fmat (uint_t height, uint_t length) {
+ fmat_t * s;
+ uint_t i,j;
+ if ((sint_t)length <= 0 || (sint_t)height <= 0 ) {
+ return NULL;
+ }
+ s = AUBIO_NEW(fmat_t);
+ s->height = height;
+ s->length = length;
+ s->data = AUBIO_ARRAY(smpl_t*,s->height);
+ for (i=0; i< s->height; i++) {
+ s->data[i] = AUBIO_ARRAY(smpl_t, s->length);
+ for (j=0; j< s->length; j++) {
+ s->data[i][j]=0.;
+ }
+ }
+ return s;
+}
+
+void del_fmat (fmat_t *s) {
+ uint_t i;
+ for (i=0; i<s->height; i++) {
+ AUBIO_FREE(s->data[i]);
+ }
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void fmat_set_sample(fmat_t *s, smpl_t data, uint_t channel, uint_t position) {
+ s->data[channel][position] = data;
+}
+
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position) {
+ return s->data[channel][position];
+}
+
+void fmat_get_channel(const fmat_t *s, uint_t channel, fvec_t *output) {
+ output->data = s->data[channel];
+ output->length = s->length;
+ return;
+}
+
+smpl_t * fmat_get_channel_data(const fmat_t *s, uint_t channel) {
+ return s->data[channel];
+}
+
+smpl_t ** fmat_get_data(const fmat_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void fmat_print(const fmat_t *s) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->data[i][j]);
+ }
+ AUBIO_MSG("\n");
+ }
+}
+
+void fmat_set(fmat_t *s, smpl_t val) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< s->length; j++) {
+ s->data[i][j] = val;
+ }
+ }
+}
+
+void fmat_zeros(fmat_t *s) {
+#ifdef HAVE_MEMCPY_HACKS
+ uint_t i;
+ for (i=0; i< s->height; i++) {
+ memset(s->data[i], 0, s->length * sizeof(smpl_t));
+ }
+#else /* HAVE_MEMCPY_HACKS */
+ fmat_set(s, 0.);
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void fmat_ones(fmat_t *s) {
+ fmat_set(s, 1.);
+}
+
+void fmat_rev(fmat_t *s) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< FLOOR(s->length/2); j++) {
+ ELEM_SWAP(s->data[i][j], s->data[i][s->length-1-j]);
+ }
+ }
+}
+
+void fmat_weight(fmat_t *s, const fmat_t *weight) {
+ uint_t i,j;
+ uint_t length = MIN(s->length, weight->length);
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< length; j++) {
+ s->data[i][j] *= weight->data[0][j];
+ }
+ }
+}
+
+void fmat_copy(const fmat_t *s, fmat_t *t) {
+ uint_t i;
+#ifndef HAVE_MEMCPY_HACKS
+ uint_t j;
+#endif /* HAVE_MEMCPY_HACKS */
+ if (s->height != t->height) {
+ AUBIO_ERR("trying to copy %d rows to %d rows \n",
+ s->height, t->height);
+ return;
+ }
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d columns to %d columns\n",
+ s->length, t->length);
+ return;
+ }
+#ifdef HAVE_MEMCPY_HACKS
+ for (i=0; i< s->height; i++) {
+ memcpy(t->data[i], s->data[i], t->length * sizeof(smpl_t));
+ }
+#else /* HAVE_MEMCPY_HACKS */
+ for (i=0; i< t->height; i++) {
+ for (j=0; j< t->length; j++) {
+ t->data[i][j] = s->data[i][j];
+ }
+ }
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output) {
+ uint_t k;
+#if 0
+ assert(s->height == output->length);
+ assert(s->length == scale->length);
+#endif
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+ uint_t j;
+ fvec_zeros(output);
+ for (j = 0; j < s->length; j++) {
+ for (k = 0; k < s->height; k++) {
+ output->data[k] += scale->data[j]
+ * s->data[k][j];
+ }
+ }
+#elif defined(HAVE_ATLAS)
+ for (k = 0; k < s->height; k++) {
+ output->data[k] = aubio_cblas_dot( s->length, scale->data, 1, s->data[k], 1);
+ }
+#elif defined(HAVE_ACCELERATE)
+#if 0
+ // seems slower and less precise (and dangerous?)
+ vDSP_mmul (s->data[0], 1, scale->data, 1, output->data, 1, s->height, 1, s->length);
+#else
+ for (k = 0; k < s->height; k++) {
+ aubio_vDSP_dotpr( scale->data, 1, s->data[k], 1, &(output->data[k]), s->length);
+ }
+#endif
+#endif
+}
diff --git a/src/fmat.h b/src/fmat.h
new file mode 100644
index 0000000..8e65d11
--- /dev/null
+++ b/src/fmat.h
@@ -0,0 +1,172 @@
+/*
+ Copyright (C) 2009-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FMAT_H
+#define AUBIO_FMAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Matrix of real valued data
+
+ This file specifies the fmat_t type, which is used in aubio to store arrays
+ of floating point values.
+
+ \example test-fmat.c
+
+*/
+
+/** Buffer for real data */
+typedef struct {
+ uint_t length; /**< length of matrix */
+ uint_t height; /**< height of matrix */
+ smpl_t **data; /**< data array of size [length] * [height] */
+} fmat_t;
+
+/** fmat_t buffer creation function
+
+ \param length the length of the matrix to create
+ \param height the height of the matrix to create
+
+*/
+fmat_t * new_fmat(uint_t height, uint_t length);
+
+/** fmat_t buffer deletion function
+
+ \param s buffer to delete as returned by new_fmat()
+
+*/
+void del_fmat(fmat_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param channel channel to read from
+ \param position sample position to read from
+
+*/
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[channel][position]
+ \param channel channel to write to
+ \param position sample position to write to
+
+*/
+void fmat_set_sample(fmat_t *s, smpl_t data, uint_t channel, uint_t position);
+
+/** read channel vector from a buffer
+
+ \param s vector to read from
+ \param channel channel to read from
+ \param output ::fvec_t to output to
+
+*/
+void fmat_get_channel (const fmat_t *s, uint_t channel, fvec_t *output);
+
+/** get vector buffer from an fmat data
+
+ \param s vector to read from
+ \param channel channel to read from
+
+*/
+smpl_t * fmat_get_channel_data (const fmat_t *s, uint_t channel);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+smpl_t ** fmat_get_data(const fmat_t *s);
+
+/** print out fmat data
+
+ \param s vector to print out
+
+*/
+void fmat_print(const fmat_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void fmat_set(fmat_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void fmat_zeros(fmat_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void fmat_ones(fmat_t *s);
+
+/** revert order of vector elements
+
+ \param s vector to revert
+
+*/
+void fmat_rev(fmat_t *s);
+
+/** apply weight to vector
+
+ If the weight vector is longer than s, only the first elements are used. If
+ the weight vector is shorter than s, the last elements of s are not weighted.
+
+ \param s vector to weight
+ \param weight weighting coefficients
+
+*/
+void fmat_weight(fmat_t *s, const fmat_t *weight);
+
+/** make a copy of a matrix
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void fmat_copy(const fmat_t *s, fmat_t *t);
+
+/** compute the product of a matrix by a vector
+
+ \param s matrix to compute product with
+ \param scale vector to compute product with
+ \param output vector to store restults in
+
+*/
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FMAT_H */
diff --git a/src/fvec.c b/src/fvec.c
new file mode 100644
index 0000000..bd253b4
--- /dev/null
+++ b/src/fvec.c
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+
+fvec_t * new_fvec(uint_t length) {
+ fvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(fvec_t);
+ s->length = length;
+ s->data = AUBIO_ARRAY(smpl_t, s->length);
+ return s;
+}
+
+void del_fvec(fvec_t *s) {
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void fvec_set_sample(fvec_t *s, smpl_t data, uint_t position) {
+ s->data[position] = data;
+}
+
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position) {
+ return s->data[position];
+}
+
+smpl_t * fvec_get_data(const fvec_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void fvec_print(const fvec_t *s) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->data[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void fvec_set_all (fvec_t *s, smpl_t val) {
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS)
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->data[j] = val;
+ }
+#elif defined(HAVE_ATLAS)
+ aubio_catlas_set(s->length, val, s->data, 1);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_vfill(&val, s->data, 1, s->length);
+#endif
+}
+
+void fvec_zeros(fvec_t *s) {
+#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE)
+ fvec_set_all (s, 0.);
+#else
+#if defined(HAVE_MEMCPY_HACKS)
+ memset(s->data, 0, s->length * sizeof(smpl_t));
+#else
+ aubio_vDSP_vclr(s->data, 1, s->length);
+#endif
+#endif
+}
+
+void fvec_ones(fvec_t *s) {
+ fvec_set_all (s, 1.);
+}
+
+void fvec_rev(fvec_t *s) {
+ uint_t j;
+ for (j=0; j< FLOOR(s->length/2); j++) {
+ ELEM_SWAP(s->data[j], s->data[s->length-1-j]);
+ }
+}
+
+void fvec_weight(fvec_t *s, const fvec_t *weight) {
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ uint_t length = MIN(s->length, weight->length);
+ for (j=0; j< length; j++) {
+ s->data[j] *= weight->data[j];
+ }
+#else
+ aubio_vDSP_vmul(s->data, 1, weight->data, 1, s->data, 1, s->length);
+#endif /* HAVE_ACCELERATE */
+}
+
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out) {
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ uint_t length = MIN(out->length, weight->length);
+ for (j=0; j< length; j++) {
+ out->data[j] = in->data[j] * weight->data[j];
+ }
+#else
+ aubio_vDSP_vmul(in->data, 1, weight->data, 1, out->data, 1, out->length);
+#endif /* HAVE_ACCELERATE */
+}
+
+void fvec_copy(const fvec_t *s, fvec_t *t) {
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d elements to %d elements \n",
+ s->length, t->length);
+ return;
+ }
+#ifdef HAVE_NOOPT
+ uint_t j;
+ for (j=0; j< t->length; j++) {
+ t->data[j] = s->data[j];
+ }
+#elif defined(HAVE_MEMCPY_HACKS)
+ memcpy(t->data, s->data, t->length * sizeof(smpl_t));
+#elif defined(HAVE_ATLAS)
+ aubio_cblas_copy(s->length, s->data, 1, t->data, 1);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_mmov(s->data, t->data, 1, s->length, 1, 1);
+#endif
+}
diff --git a/src/fvec.h b/src/fvec.h
new file mode 100644
index 0000000..bd8c5a6
--- /dev/null
+++ b/src/fvec.h
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FVEC_H
+#define AUBIO_FVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of real-valued data
+
+ This file specifies the ::fvec_t buffer type, which is used throughout aubio
+ to store vector of real-valued ::smpl_t.
+
+ \example test-fvec.c
+
+*/
+
+/** Buffer for real data
+
+ Vector of real-valued data
+
+ ::fvec_t is is the structure used to store vector of real-valued data, ::smpl_t .
+
+ \code
+
+ uint_t buffer_size = 1024;
+
+ // create a vector of 512 values
+ fvec_t * input = new_fvec (buffer_size);
+
+ // set some values of the vector
+ input->data[23] = 2.;
+ // ..
+
+ // compute the mean of the vector
+ mean = fvec_mean(a_vector);
+
+ // destroy the vector
+ del_fvec(a_vector);
+
+ \endcode
+
+ See `examples/` and `tests/src` directories for more examples.
+
+ */
+typedef struct {
+ uint_t length; /**< length of buffer */
+ smpl_t *data; /**< data vector of length ::fvec_t.length */
+} fvec_t;
+
+/** fvec_t buffer creation function
+
+ \param length the length of the buffer to create
+
+*/
+fvec_t * new_fvec(uint_t length);
+
+/** fvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_fvec()
+
+*/
+void del_fvec(fvec_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[position]
+ \param position sample position to write to
+
+*/
+void fvec_set_sample(fvec_t *s, smpl_t data, uint_t position);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+smpl_t * fvec_get_data(const fvec_t *s);
+
+/** print out fvec data
+
+ \param s vector to print out
+
+*/
+void fvec_print(const fvec_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void fvec_set_all (fvec_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void fvec_zeros(fvec_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void fvec_ones(fvec_t *s);
+
+/** revert order of vector elements
+
+ \param s vector to revert
+
+*/
+void fvec_rev(fvec_t *s);
+
+/** apply weight to vector
+
+ If the weight vector is longer than s, only the first elements are used. If
+ the weight vector is shorter than s, the last elements of s are not weighted.
+
+ \param s vector to weight
+ \param weight weighting coefficients
+
+*/
+void fvec_weight(fvec_t *s, const fvec_t *weight);
+
+/** make a copy of a vector
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void fvec_copy(const fvec_t *s, fvec_t *t);
+
+/** make a copy of a vector, applying weights to each element
+
+ \param in input vector
+ \param weight weights vector
+ \param out output vector
+
+*/
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FVEC_H */
diff --git a/src/io/audio_unit.c b/src/io/audio_unit.c
new file mode 100644
index 0000000..a21906a
--- /dev/null
+++ b/src/io/audio_unit.c
@@ -0,0 +1,777 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+#ifdef HAVE_AUDIO_UNIT
+#include "aubio_priv.h"
+
+#include "fvec.h"
+#include "fmat.h"
+#include "io/audio_unit.h"
+
+#include <AudioToolbox/AudioToolbox.h>
+
+#define AU_IOS_MAX_OUT 64
+#define AU_IOS_MAX_FRAMES AU_IOS_MAX_OUT * 16 * 2
+#define PREFERRED_LATENCY 0.010
+#define MAX_FPS 4096
+
+#define INT_TO_FLOAT 3.0517578125e-05 // 1. / 32768.
+
+struct _aubio_audio_unit_t {
+ AudioUnit audio_unit;
+ uint_t samplerate;
+ uint_t blocksize;
+ uint_t sw_input_channels;
+ uint_t sw_output_channels;
+ uint_t hw_output_channels;
+ uint_t hw_input_channels;
+ Float32 latency;
+ sint_t total_frames;
+ fmat_t *input_frames;
+ fmat_t *output_frames;
+ SInt16 *au_ios_inbuf;
+ SInt16 *au_ios_outbuf;
+ aubio_device_callback_t callback;
+ void *callback_closure;
+ int dio_error; // flag to check if we had a read error
+ bool input_enabled;
+ bool prevent_feedback;
+ bool verbose;
+ int au_ios_start;
+ int au_ios_end;
+ AURenderCallbackStruct au_ios_cb_struct;
+};
+
+
+static OSStatus
+aubio_audio_unit_process(void *closure, AudioUnitRenderActionFlags * action_flags,
+ const AudioTimeStamp * time_stamp, UInt32 bus_number, UInt32 inNumber_frames,
+ AudioBufferList * input_output);
+
+static int aubio_audio_unit_blocking(aubio_audio_unit_t *o);
+
+static void audio_unit_check_audio_route(aubio_audio_unit_t *o);
+
+static void audio_unit_interruption_listener(void *closure, UInt32 inInterruptionState);
+static void audio_unit_route_change_listener(void *closure, AudioSessionPropertyID
+ inID, UInt32 dataSize, const void *inData);
+static OSStatus audio_unit_set_audio_session_category(bool has_input, bool verbose);
+static UInt32 audio_unit_get_audio_session_category ();
+
+aubio_audio_unit_t * new_aubio_audio_unit(uint_t samplerate,
+ uint_t sw_input_channels, uint_t sw_output_channels,
+ uint_t blocksize)
+{
+ aubio_audio_unit_t * o = AUBIO_NEW(aubio_audio_unit_t);
+ o->hw_output_channels = 2;
+ o->hw_input_channels = 2;
+ o->sw_output_channels = sw_output_channels;
+ o->sw_input_channels = sw_input_channels;
+ o->samplerate = samplerate;
+ o->latency = PREFERRED_LATENCY;
+ o->blocksize = blocksize;
+
+ o->au_ios_start = 0;
+ o->au_ios_end = 0;
+
+ o->verbose = 0;
+ o->input_enabled = true;
+ o->prevent_feedback = 1;
+ o->dio_error = 0;
+
+ o->total_frames = 0;
+
+ /* the integers coming from and to the audio unit */
+ o->au_ios_outbuf = AUBIO_ARRAY(SInt16, AU_IOS_MAX_FRAMES * o->hw_output_channels);
+ o->au_ios_inbuf = AUBIO_ARRAY(SInt16, AU_IOS_MAX_FRAMES * o->hw_input_channels);
+
+ /* the floats coming from and to the device callback */
+ o->output_frames = new_fmat(sw_output_channels, blocksize);
+ o->input_frames = new_fmat(sw_input_channels, blocksize);
+
+ /* check for some sizes */
+ if ( o->hw_output_channels != o->output_frames->height ) {
+ AUBIO_ERR ("got hw_output_channels = %d, but output_frames has %d rows\n",
+ o->hw_output_channels, o->output_frames->height);
+ }
+ if ( o->blocksize != o->output_frames->length ) {
+ AUBIO_ERR ("got blocksize = %d, but output_frames has length %d\n",
+ o->blocksize, o->output_frames->length);
+ }
+ if ( o->hw_input_channels != o->input_frames->height ) {
+ AUBIO_ERR ("got hw_input_channels = %d, but input_frames has %d rows\n",
+ o->hw_input_channels, o->input_frames->height);
+ }
+ if ( o->blocksize != o->input_frames->length ) {
+ AUBIO_ERR ("got blocksize = %d, but input_frames has length %d\n",
+ o->blocksize, o->input_frames->length);
+ }
+
+ return o;
+}
+
+sint_t aubio_audio_unit_set_preferred_latency (aubio_audio_unit_t *o, smpl_t latency)
+{
+ o->latency = latency;
+ return 0;
+}
+
+sint_t aubio_audio_unit_set_prevent_feedback (aubio_audio_unit_t *o, uint_t prevent_feedback)
+{
+ o->prevent_feedback = prevent_feedback;
+ return 0;
+}
+
+sint_t aubio_audio_unit_set_verbose (aubio_audio_unit_t *o, uint_t verbose)
+{
+ o->verbose = verbose;
+ return 0;
+}
+
+
+sint_t aubio_audio_unit_init (aubio_audio_unit_t *o)
+{
+ OSStatus err = noErr;
+ Float32 latency = o->latency;
+ Float64 samplerate = (Float64)o->samplerate;
+
+ o->au_ios_cb_struct.inputProc = aubio_audio_unit_process;
+ o->au_ios_cb_struct.inputProcRefCon = o;
+
+ /* setting up audio session with interruption listener */
+ err = AudioSessionInitialize(NULL, NULL, audio_unit_interruption_listener, o);
+ if (err) { AUBIO_ERR("audio_unit: could not initialize audio session (%d)\n", (int)err); goto fail; }
+
+ audio_unit_set_audio_session_category(o->input_enabled, o->verbose);
+ audio_unit_check_audio_route(o);
+
+ /* add route change listener */
+ err = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,
+ audio_unit_route_change_listener, o);
+ if (err) { AUBIO_ERR("audio_unit: could not set route change listener (%d)\n", (int)err); goto fail; }
+
+ /* set latency */
+ err = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration,
+ sizeof(latency), &latency);
+ if (err) { AUBIO_ERR("audio_unit: could not set preferred latency (%d)\n", (int)err); goto fail; }
+
+#if 0 // only for iphone OS >= 3.1
+ UInt32 val = 1; // set to 0 (default) to use ear speaker in voice application
+ err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
+ sizeof(UInt32), &val);
+ if (err) { AUBIO_ERR("audio_unit: could not set session property to default to speaker\n"); }
+#endif
+
+ /* setting up audio unit */
+ AudioComponentDescription desc;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentSubType = kAudioUnitSubType_RemoteIO;
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ AudioStreamBasicDescription audioFormat;
+
+ /* look for a component that match the description */
+ AudioComponent comp = AudioComponentFindNext(NULL, &desc);
+
+ /* create the audio component */
+ AudioUnit *audio_unit = &(o->audio_unit);
+
+ err = AudioComponentInstanceNew(comp, &(o->audio_unit));
+ if (err) { AUBIO_ERR("audio_unit: failed creating the audio unit\n"); goto fail; }
+
+ /* enable IO */
+ UInt32 enabled = 1;
+ err = AudioUnitSetProperty (*audio_unit, kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Input, 1, &enabled, sizeof(enabled));
+ if (err) {
+ AUBIO_ERR("audio_unit: failed enabling input of audio unit\n");
+ goto fail;
+ }
+
+ /* set max fps */
+ UInt32 max_fps = MIN(o->blocksize, MAX_FPS);
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Global, 0, &max_fps, sizeof(max_fps));
+ if (err) {
+ AUBIO_ERR("audio_unit: could not set maximum frames per slice property (%d)\n", (int)err);
+ goto fail;
+ }
+
+ AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Input, 0, &(o->au_ios_cb_struct), sizeof(o->au_ios_cb_struct));
+ if (err) { AUBIO_ERR("audio_unit: failed setting audio unit render callback\n"); goto fail; }
+
+#if 0
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_SampleRate,
+ kAudioUnitScope_Input, 0, &samplerate, sizeof(Float64));
+ if (err) { AUBIO_ERR("audio_unit: could not set audio input sample rate\n"); goto fail; }
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_SampleRate,
+ kAudioUnitScope_Output, 1, &samplerate, sizeof(Float64));
+ if (err) { AUBIO_ERR("audio_unit: could not set audio input sample rate\n"); goto fail; }
+#endif
+
+ audioFormat.mSampleRate = (Float64)samplerate;
+ audioFormat.mChannelsPerFrame = 2;
+ audioFormat.mFormatID = kAudioFormatLinearPCM;
+ audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
+ audioFormat.mFramesPerPacket = 1;
+ audioFormat.mBitsPerChannel = 8 * sizeof(SInt16);
+#if 1 // interleaving
+ audioFormat.mBytesPerFrame = 2 * sizeof(SInt16);
+ audioFormat.mBytesPerPacket = 2 * sizeof(SInt16);
+#else
+ audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame = sizeof(SInt32);
+ audioFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
+#endif
+
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input, 0, &audioFormat, sizeof(audioFormat));
+ if (err) { AUBIO_ERR("audio_unit: could not set audio output format\n"); goto fail; }
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat));
+ if (err) { AUBIO_ERR("audio_unit: could not set audio input format\n"); goto fail; }
+
+#if 0
+ AudioStreamBasicDescription thruFormat;
+ thissize = sizeof(thruFormat);
+ err = AudioUnitGetProperty (*audio_unit, kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input, 0, &thruFormat, &thissize);
+ if (err) { AUBIO_ERR("audio_unit: could not get speaker output format, err: %d\n", (int)err); goto fail; }
+ err = AudioUnitSetProperty (*audio_unit, kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output, 1, &thruFormat, sizeof(thruFormat));
+ if (err) { AUBIO_ERR("audio_unit: could not set input audio format, err: %d\n", (int)err); goto fail; }
+#endif
+
+ /* time to initialize the unit */
+ err = AudioUnitInitialize(*audio_unit);
+ if (err) { AUBIO_ERR("audio_unit: failed initializing audio, err: %d\n", (int)err); goto fail; }
+
+ return 0;
+
+fail:
+ return err;
+}
+
+/* perform function */
+OSStatus
+aubio_audio_unit_process(void *closure, AudioUnitRenderActionFlags * action_flags,
+ const AudioTimeStamp * time_stamp, UNUSED UInt32 bus_number, UInt32 inNumber_frames,
+ AudioBufferList * input_output)
+{
+ UInt32 b; int err = 0;
+ aubio_audio_unit_t *o = (aubio_audio_unit_t *)closure;
+ AudioUnit thisUnit = o->audio_unit;
+
+ if (o->input_enabled) {
+ err = AudioUnitRender(thisUnit, action_flags, time_stamp, 1,
+ inNumber_frames, input_output);
+ if (err) {
+ AUBIO_ERR("audio_unit: error performing AudioUnitRender (%d)\n", err);
+ return err;
+ }
+ }
+
+ // get the number of frames from the audio buffer list, NOT inNumber_frames
+ UInt32 number_frames = input_output->mBuffers[0].mDataByteSize/ sizeof(SInt16) / 2;
+
+ // FIXME find out why this happens
+ if (number_frames < 10) {
+ AUBIO_ERR("audio_unit: got number_frames %d\n", (int)number_frames);
+ return -1;
+ }
+
+ if (o->total_frames >= (signed)number_frames) {
+
+ SInt16 *data;
+ if (o->au_ios_start + number_frames > AU_IOS_MAX_FRAMES) {
+ // start reminder samples writing at reminder
+ int reminder = AU_IOS_MAX_FRAMES - o->au_ios_start;
+ int starter = (o->au_ios_start + number_frames) - AU_IOS_MAX_FRAMES;
+ for (b = 0; b < input_output->mNumberBuffers; b++) {
+ data = (SInt16 *)(input_output->mBuffers[b].mData);
+ /* copy microphone output to input buffer */
+ memcpy (o->au_ios_inbuf + o->au_ios_start * 2, data, reminder * 2 * sizeof(SInt16));
+ memcpy (o->au_ios_inbuf, data + reminder * 2, starter * 2 * sizeof(SInt16));
+ /* silence data before copying from output */
+ //memset (data, 0, input_output->mBuffers[b].mDataByteSize);
+ /* copy output buffer to speakers */
+ memcpy (data, o->au_ios_outbuf + o->au_ios_start * 2, reminder * 2 * sizeof(SInt16));
+ memcpy (data + reminder * 2, o->au_ios_outbuf, starter * 2 * sizeof(SInt16));
+ }
+ } else {
+ for (b = 0; b < input_output->mNumberBuffers; b++) {
+ data = (SInt16 *)(input_output->mBuffers[b].mData);
+ /* copy microphone samples to au_ios_inbuf */
+ memcpy(o->au_ios_inbuf + o->au_ios_start * 2, data, number_frames * 2 * sizeof(SInt16));
+ /* silence data before copying from output */
+ //memset (data, 0, input_output->mBuffers[b].mDataByteSize);
+ /* copy output buffer to speakers */
+ memcpy(data, o->au_ios_outbuf + o->au_ios_start * 2, number_frames * 2 * sizeof(SInt16));
+ }
+ }
+ o->au_ios_start += number_frames;
+ o->au_ios_start %= AU_IOS_MAX_FRAMES;
+ o->total_frames -= number_frames;
+
+#if 1
+ } else {
+ if (o->total_frames > 0) o->dio_error = 1;
+ for (b = 0; b < input_output->mNumberBuffers; b++) {
+ memset (input_output->mBuffers[b].mData, 0,
+ input_output->mBuffers[b].mDataByteSize);
+ }
+ //total_frames = 0;
+#endif
+ }
+
+ // now call callback
+ while ( o->total_frames < (signed)number_frames ) {
+ //AUBIO_DBG ("audio_unit: total_frames = %d, number_frames = %d, o->au_ios_start = %d, o->au_ios_end = %d",
+ // o->total_frames, number_frames, o->au_ios_start, o->au_ios_end);
+ aubio_audio_unit_blocking(o);
+ }
+
+ return err;
+}
+
+int aubio_audio_unit_blocking(aubio_audio_unit_t *o)
+{
+ uint_t sw_output_channels, sw_input_channels,
+ hw_output_channels, hw_input_channels,
+ i, j, blocksize;
+ if (! o->callback) return -1;
+
+ smpl_t ** tbuf;
+
+ sw_output_channels = o->sw_output_channels;
+ sw_input_channels = o->sw_input_channels;
+ hw_output_channels = o->hw_output_channels;
+ hw_input_channels = o->hw_input_channels;
+ blocksize = o->blocksize;
+
+ if (!sw_input_channels && !sw_output_channels) goto fail;
+
+ if (o->dio_error) {
+ AUBIO_WRN("audio_unit: dio error %d\n", o->total_frames);
+ o->dio_error = 0;
+ }
+
+ if (o->au_ios_inbuf) {
+ /* copy samples from input buffer */
+ tbuf = o->input_frames->data;
+ if (o->input_enabled) {
+ for (j = 0; j < blocksize;j++) {
+ for (i = 0; i < sw_input_channels && i < hw_input_channels; i++) {
+ //tbuf[i][j] =
+ // (smpl_t)(o->au_ios_inbuf[i + (j + o->au_ios_end) * sw_input_channels] / 32768.);
+ // on iphone, input is mono, copy right to left channel
+ tbuf[i][j] =
+ (smpl_t) o->au_ios_inbuf[0 + (j + o->au_ios_end) * hw_input_channels]
+ * INT_TO_FLOAT;
+ }
+ }
+ } else {
+ // input is disabled, fill with zeroes
+ for (j = 0; j < blocksize; j++) {
+ for (i = 0; i < sw_input_channels && i < hw_input_channels; i++) {
+ tbuf[i][j] = 0;
+ }
+ }
+ }
+ }
+
+ o->callback(o->callback_closure, o->input_frames, o->output_frames);
+
+ /* copy samples to output buffer */
+ tbuf = o->output_frames->data;
+ for (i = 0; i < o->output_frames->height; i++) {
+ for (j = 0; j < o->output_frames->length; j++) {
+ smpl_t val = tbuf[i][j];
+ if (val < -1.0) val = -1.0;
+ if (val > 1.0) val = 1.0;
+ o->au_ios_outbuf[i + (j + o->au_ios_end) * hw_output_channels ] = (SInt16)(val * 32767);
+ }
+ }
+
+ o->au_ios_end += blocksize;
+ o->au_ios_end %= AU_IOS_MAX_FRAMES;
+ o->total_frames += blocksize;
+
+ return 0;
+
+fail:
+ AUBIO_ERR("audio_unit: callback() failed\n");
+ o->total_frames += AU_IOS_MAX_FRAMES;
+ return 1;
+}
+
+sint_t aubio_audio_unit_get_info (aubio_audio_unit_t *o)
+{
+ UInt32 thissize, input_hw_channels, output_hw_channels, max_fps;
+ Float32 latency, input_latency, output_latency, input_hw_volume, output_hw_volume;
+ Float64 samplerate;
+ OSStatus err = 0;
+
+ // Show some info about the opened unit
+
+ /* get sampling rate */
+ thissize = sizeof(samplerate);
+ err = AudioUnitGetProperty (o->audio_unit, kAudioUnitProperty_SampleRate,
+ kAudioUnitScope_Output, 1, &samplerate, &thissize);
+ if (err) { AUBIO_ERR("audio_unit: could not get audio unit sample rate (%d)\n",
+ (int)err); goto fail; }
+
+ /* get hardware input channels */
+ thissize = sizeof(input_hw_channels);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels,
+ &thissize, &input_hw_channels);
+ if (err) { AUBIO_ERR("audio_unit: could not get hardware input channels (%d)\n",
+ (int)err); goto fail; }
+
+ /* get hardware output channels */
+ thissize = sizeof(output_hw_channels);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels,
+ &thissize, &output_hw_channels);
+ if (err) { AUBIO_ERR("audio_unit: could not get hardware output channels (%d)\n",
+ (int)err); goto fail; }
+
+ /* get hardware input volume */
+ thissize = sizeof(input_hw_volume);
+ err = AudioSessionGetProperty(kAudioSessionProperty_InputGainScalar,
+ &thissize, &input_hw_volume);
+ if (err) { AUBIO_ERR("audio_unit: could not get hardware input volume (%d)\n",
+ (int)err); goto fail; }
+
+ /* get hardware output volume */
+ thissize = sizeof(output_hw_volume);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputVolume,
+ &thissize, &output_hw_volume);
+ if (err) { AUBIO_ERR("audio_unit: could not get hardware output volume (%d)\n",
+ (int)err); goto fail; }
+
+ AUBIO_MSG("audio_unit: opened at %.0fHz, sw channels %din/%dout, hw channels %din/%dout, hw vol %.2fin/%.2fout\n",
+ samplerate,
+ o->sw_input_channels, o->sw_output_channels,
+ (unsigned int)input_hw_channels, (unsigned int)output_hw_channels,
+ input_hw_volume, output_hw_volume);
+
+ /* get max frames per slice */
+ thissize = sizeof(max_fps);
+ err = AudioUnitGetProperty (o->audio_unit, kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Global, 0, &max_fps, &thissize);
+ if (err) { AUBIO_ERR("audio_unit: could not get maximum frames per slice property %d\n",
+ (int)err); goto fail; }
+
+ /* get hardware latency */
+ thissize = sizeof(latency);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration,
+ &thissize, &latency);
+ if (err) { AUBIO_ERR("audio_unit: could not get hardware latency %d\n",
+ (int)err); goto fail; }
+
+ /* get input latency */
+ thissize = sizeof(input_latency);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency,
+ &thissize, &input_latency);
+ if (err) { AUBIO_ERR("audio_unit: could not get input latency %d\n",
+ (int)err); goto fail; }
+
+ /* get output harlatency */
+ thissize = sizeof(output_latency);
+ err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency,
+ &thissize, &output_latency);
+ if (err) { AUBIO_ERR("audio_unit: could not get output latency %d\n",
+ (int)err); goto fail; }
+
+ AUBIO_MSG("audio_unit: I/O latency: %.2fms, %d frames, (%.2fms, %d frames in, %.2fms %d frames out)\n",
+ latency*1000., (sint_t)round(latency*samplerate),
+ input_latency*1000., (sint_t)ROUND(input_latency*samplerate),
+ output_latency*1000., (sint_t)ROUND(output_latency*samplerate));
+
+fail:
+ return err;
+}
+
+sint_t aubio_audio_unit_start(aubio_audio_unit_t *o) {
+ OSStatus err = 0;
+
+ if (o->verbose) {
+ // print some info about the current settings
+ aubio_audio_unit_get_info (o);
+ }
+
+ /* time to start the unit */
+ err = AudioOutputUnitStart (o->audio_unit);
+ if (err) { AUBIO_ERR("audio_unit: could not start unit (%d)\n", (int)err); }
+ return err;
+}
+
+sint_t aubio_audio_unit_stop(aubio_audio_unit_t *o)
+{
+ if (o->audio_unit == NULL) return -1;
+ OSStatus err = AudioOutputUnitStop (o->audio_unit);
+ if (err) { AUBIO_WRN("audio_unit: failed stopping audio unit (%d)\n", (int)err); }
+ err = AudioUnitUninitialize (o->audio_unit);
+ if (err) { AUBIO_WRN("audio_unit: failed unitializing audio unit (%d)\n", (int)err); }
+ err = AudioSessionSetActive(false);
+ if (err) { AUBIO_WRN("audio_unit: failed stopping audio session (%d)\n", (int)err); }
+ return err;
+}
+
+uint_t aubio_audio_unit_set_callback(aubio_audio_unit_t *o,
+ aubio_device_callback_t callback, void *closure) {
+ o->callback = callback;
+ o->callback_closure = closure;
+ return 0;
+}
+
+/* interruption listeners */
+void audio_unit_interruption_listener(void *closure, UInt32 inInterruptionState)
+{
+ OSStatus err = 0;
+ aubio_audio_unit_t *o = (aubio_audio_unit_t *) closure;
+ AudioUnit this_unit = o->audio_unit;
+
+ if (inInterruptionState == kAudioSessionEndInterruption) {
+ AUBIO_WRN("audio_unit: session interruption ended\n");
+ err = AudioSessionSetActive(true);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not make session active after interruption (%d)\n", (int)err);
+ goto fail;
+ }
+ err = AudioOutputUnitStart(this_unit);
+ if (err) {
+ AUBIO_ERR("audio_unit: failed starting unit (%d)\n", (int)err);
+ goto fail;
+ }
+ }
+ if (inInterruptionState == kAudioSessionBeginInterruption) {
+ AUBIO_WRN("audio_unit: session interruption started\n");
+ err = AudioOutputUnitStop(this_unit);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not stop unit at interruption (%d)\n", (int)err);
+ goto fail;
+ }
+ err = AudioSessionSetActive(false);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not make session inactive after interruption (%d)\n", (int)err);
+ goto fail;
+ }
+ }
+fail:
+ return;
+}
+
+UInt32 audio_unit_get_audio_session_category () {
+ UInt32 category, thissize;
+ thissize = sizeof(category);
+ OSStatus err = AudioSessionGetProperty(kAudioSessionProperty_AudioCategory,
+ &thissize, &category);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not get audio category (%d)\n", (int)err);
+ return err;
+ }
+ if (category == kAudioSessionCategory_AmbientSound) {
+ AUBIO_MSG("audio_unit: session category is AmbiantSound\n");
+ } else if (category == kAudioSessionCategory_SoloAmbientSound) {
+ AUBIO_MSG("audio_unit: session category is SoloAmbiantSound\n");
+ } else if (category == kAudioSessionCategory_MediaPlayback) {
+ AUBIO_MSG("audio_unit: session category is MediaPlayback\n");
+ } else if (category == kAudioSessionCategory_RecordAudio) {
+ AUBIO_MSG("audio_unit: session category is RecordAudio\n");
+ } else if (category == kAudioSessionCategory_PlayAndRecord) {
+ AUBIO_MSG("audio_unit: session category is PlayAndRecord\n");
+ } else if (category == kAudioSessionCategory_AudioProcessing) {
+ AUBIO_MSG("audio_unit: session category is AudioProcessing\n");
+ }
+ return category;
+}
+
+OSStatus audio_unit_set_audio_session_category(bool has_input, bool verbose)
+{
+ //if we have input, set the session category accordingly
+ OSStatus err = 0;
+ UInt32 category;
+ if (has_input) {
+ category = kAudioSessionCategory_PlayAndRecord;
+ if (verbose) AUBIO_MSG("audio_unit: setting category to PlayAndRecord\n");
+ } else {
+ category = kAudioSessionCategory_MediaPlayback;
+ if (verbose) AUBIO_MSG("audio_unit: setting category to MediaPlayback\n");
+ }
+ err = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
+ sizeof(category), &category);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not set audio category\n");
+ }
+
+ // Audiob.us style
+ UInt32 allowMixing = 1;
+ AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,
+ sizeof (allowMixing), &allowMixing);
+ if (err) {
+ AUBIO_ERR("audio_unit: could not set audio session to mix with others\n");
+ }
+
+ return err;
+}
+
+void audio_unit_check_audio_route(aubio_audio_unit_t *o) {
+ CFStringRef currentRoute;
+ UInt32 val, thissize = sizeof(currentRoute);
+ OSStatus err = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &thissize, &currentRoute);
+ if (err) { AUBIO_ERR("audio_unit: could not get current route\n"); goto fail; }
+ else {
+ char *route = (char *)CFStringGetCStringPtr ( currentRoute, kCFStringEncodingUTF8);
+ if (route == NULL) {
+ int bufferSize = 25;
+ route = calloc(bufferSize, sizeof(char));
+ CFStringGetCString ( currentRoute, route, bufferSize,
+ kCFStringEncodingUTF8);
+ }
+ if (o->verbose) {
+ AUBIO_MSG ("audio_unit: current route is %s\n", route);
+ }
+ //free(route);
+ }
+ if( currentRoute ) {
+ if( CFStringCompare( currentRoute, CFSTR("Headset"), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_None;
+ } else if( CFStringCompare( currentRoute, CFSTR("Receiver" ), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_Speaker;
+ } else if( CFStringCompare( currentRoute, CFSTR("ReceiverAndMicrophone" ), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_Speaker;
+ } else if( CFStringCompare( currentRoute, CFSTR("SpeakerAndMicrophone" ), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_Speaker;
+ } else if( CFStringCompare( currentRoute, CFSTR("HeadphonesAndMicrophone" ), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_None;
+ } else if( CFStringCompare( currentRoute, CFSTR("HeadsetInOut" ), 0 ) == kCFCompareEqualTo ) {
+ val = kAudioSessionOverrideAudioRoute_None;
+ } else {
+ val = kAudioSessionOverrideAudioRoute_None;
+ }
+
+ o->input_enabled = true;
+ if (val == kAudioSessionOverrideAudioRoute_Speaker) {
+ if (o->prevent_feedback) {
+ o->input_enabled = false;
+ if (o->verbose) {
+ AUBIO_MSG ("audio_unit: disabling input to avoid feedback\n");
+ }
+ } else {
+ AUBIO_WRN ("audio_unit: input not disabled as prevent_feedback set to 0, risking feedback\n");
+ }
+ }
+
+ err = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute,
+ sizeof(UInt32), &val);
+ if (err) { AUBIO_ERR("audio_unit: could not set session OverrideAudioRoute to Speaker\n"); }
+
+ }
+
+fail:
+ if ( currentRoute ) free((void*)currentRoute);
+ return;
+
+}
+
+SInt32
+audio_unit_get_route_change_reason(CFDictionaryRef routeChangeDic) {
+ CFNumberRef routeChangeReasonRef = (CFNumberRef)CFDictionaryGetValue(routeChangeDic,
+ CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
+ SInt32 change_reason_number;
+ CFNumberGetValue ( routeChangeReasonRef, kCFNumberSInt32Type, &change_reason_number);
+ switch (change_reason_number) {
+ case kAudioSessionRouteChangeReason_NewDeviceAvailable:
+ AUBIO_MSG("audio_unit: route changed to NewDeviceAvailable\n");
+ break;
+ case kAudioSessionRouteChangeReason_OldDeviceUnavailable:
+ AUBIO_MSG("audio_unit: route changed to OldDeviceUnavailable\n");
+ break;
+ case kAudioSessionRouteChangeReason_CategoryChange:
+ AUBIO_MSG("audio_unit: route changed to CategoryChange\n");
+ audio_unit_get_audio_session_category();
+ break;
+ case kAudioSessionRouteChangeReason_Override:
+ AUBIO_MSG("audio_unit: route changed to Override\n");
+ break;
+ case kAudioSessionRouteChangeReason_WakeFromSleep:
+ AUBIO_MSG("audio_unit: route changed to WakeFromSleep\n");
+ break;
+ case kAudioSessionRouteChangeReason_NoSuitableRouteForCategory:
+ AUBIO_MSG("audio_unit: route changed to NoSuitableRouteForCategory\n");
+ break;
+ case kAudioSessionRouteChangeReason_Unknown:
+ default:
+ AUBIO_ERR("audio_unit: route changed for an unknown reason!?\n");
+ break;
+ }
+ return change_reason_number;
+}
+
+/* route change listeners */
+void
+audio_unit_route_change_listener(void *closure, AudioSessionPropertyID inID,
+ UInt32 dataSize, const void *inData)
+{
+
+ UNUSED aubio_audio_unit_t *o = (aubio_audio_unit_t *)closure;
+ UNUSED UInt32 size = dataSize;
+ if (inID == kAudioSessionProperty_AudioRouteChange) {
+
+ // OSStatus err = 0;
+ //AudioUnit audio_unit = o->audio_unit;
+
+ if (o->verbose) {
+ // show route change reason
+ audio_unit_get_route_change_reason((CFDictionaryRef)inData);
+ }
+
+ // check current audio route, changing it to prevent feedback as needed
+ audio_unit_check_audio_route(o);
+
+ if (o->verbose) {
+ // print some info about the current settings
+ aubio_audio_unit_get_info(o);
+ }
+
+ }
+
+}
+
+/* delete object */
+uint_t del_aubio_audio_unit(aubio_audio_unit_t *o)
+{
+ int err = 0;
+ err = aubio_audio_unit_stop(o);
+ if (o->au_ios_inbuf) free(o->au_ios_inbuf);
+ o->au_ios_inbuf = NULL;
+ if (o->au_ios_outbuf) free(o->au_ios_outbuf);
+ o->au_ios_outbuf = NULL;
+ del_fmat (o->input_frames);
+ del_fmat (o->output_frames);
+ o->audio_unit = NULL;
+ return (int)err;
+}
+
+#endif /* HAVE_AUDIO_UNIT */
diff --git a/src/io/audio_unit.h b/src/io/audio_unit.h
new file mode 100644
index 0000000..46f86b1
--- /dev/null
+++ b/src/io/audio_unit.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_AUDIO_UNIT_H
+#define AUBIO_AUDIO_UNIT_H
+
+/** \file
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_audio_unit_t aubio_audio_unit_t;
+
+aubio_audio_unit_t * new_aubio_audio_unit(uint_t samplerate, uint_t inchannels,
+ uint_t outchannels, uint_t blocksize);
+
+typedef uint_t (*aubio_device_callback_t) (void * closure, fmat_t *ibuf, fmat_t *obuf);
+
+uint_t aubio_audio_unit_set_callback(aubio_audio_unit_t *o,
+ aubio_device_callback_t callback, void *closure);
+
+sint_t aubio_audio_unit_set_verbose (aubio_audio_unit_t *o, uint_t verbose);
+sint_t aubio_audio_unit_set_preferred_latency (aubio_audio_unit_t *o, smpl_t
+ latency);
+sint_t aubio_audio_unit_set_prevent_feedback (aubio_audio_unit_t *o, uint_t
+ prevent_feedback);
+
+sint_t aubio_audio_unit_get_info (aubio_audio_unit_t *o);
+
+sint_t aubio_audio_unit_init (aubio_audio_unit_t *o);
+
+sint_t aubio_audio_unit_start (aubio_audio_unit_t *o);
+sint_t aubio_audio_unit_stop (aubio_audio_unit_t *o);
+
+uint_t del_aubio_audio_unit(aubio_audio_unit_t *o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_AUDIO_UNIT_H */
diff --git a/src/io/sink.c b/src/io/sink.c
new file mode 100644
index 0000000..a13316a
--- /dev/null
+++ b/src/io/sink.c
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/sink.h"
+#ifdef HAVE_SINK_APPLE_AUDIO
+#include "io/sink_apple_audio.h"
+#endif /* HAVE_SINK_APPLE_AUDIO */
+#ifdef HAVE_SNDFILE
+#include "io/sink_sndfile.h"
+#endif
+#ifdef HAVE_WAVWRITE
+#include "io/sink_wavwrite.h"
+#endif
+
+typedef void (*aubio_sink_do_t)(aubio_sink_t * s, fvec_t * data, uint_t write);
+typedef void (*aubio_sink_do_multi_t)(aubio_sink_t * s, fmat_t * data, uint_t write);
+typedef uint_t (*aubio_sink_preset_samplerate_t)(aubio_sink_t * s, uint_t samplerate);
+typedef uint_t (*aubio_sink_preset_channels_t)(aubio_sink_t * s, uint_t channels);
+typedef uint_t (*aubio_sink_get_samplerate_t)(aubio_sink_t * s);
+typedef uint_t (*aubio_sink_get_channels_t)(aubio_sink_t * s);
+typedef uint_t (*aubio_sink_close_t)(aubio_sink_t * s);
+typedef void (*del_aubio_sink_t)(aubio_sink_t * s);
+
+struct _aubio_sink_t {
+ void *sink;
+ aubio_sink_do_t s_do;
+ aubio_sink_do_multi_t s_do_multi;
+ aubio_sink_preset_samplerate_t s_preset_samplerate;
+ aubio_sink_preset_channels_t s_preset_channels;
+ aubio_sink_get_samplerate_t s_get_samplerate;
+ aubio_sink_get_channels_t s_get_channels;
+ aubio_sink_close_t s_close;
+ del_aubio_sink_t s_del;
+};
+
+aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate) {
+ aubio_sink_t * s = AUBIO_NEW(aubio_sink_t);
+#ifdef HAVE_SINK_APPLE_AUDIO
+ s->sink = (void *)new_aubio_sink_apple_audio(uri, samplerate);
+ if (s->sink) {
+ s->s_do = (aubio_sink_do_t)(aubio_sink_apple_audio_do);
+ s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_apple_audio_do_multi);
+ s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_apple_audio_preset_samplerate);
+ s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_apple_audio_preset_channels);
+ s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_apple_audio_get_samplerate);
+ s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_apple_audio_get_channels);
+ s->s_close = (aubio_sink_close_t)(aubio_sink_apple_audio_close);
+ s->s_del = (del_aubio_sink_t)(del_aubio_sink_apple_audio);
+ return s;
+ }
+#endif /* HAVE_SINK_APPLE_AUDIO */
+#ifdef HAVE_SNDFILE
+ s->sink = (void *)new_aubio_sink_sndfile(uri, samplerate);
+ if (s->sink) {
+ s->s_do = (aubio_sink_do_t)(aubio_sink_sndfile_do);
+ s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_sndfile_do_multi);
+ s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_sndfile_preset_samplerate);
+ s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_sndfile_preset_channels);
+ s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_sndfile_get_samplerate);
+ s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_sndfile_get_channels);
+ s->s_close = (aubio_sink_close_t)(aubio_sink_sndfile_close);
+ s->s_del = (del_aubio_sink_t)(del_aubio_sink_sndfile);
+ return s;
+ }
+#endif /* HAVE_SNDFILE */
+#ifdef HAVE_WAVWRITE
+ s->sink = (void *)new_aubio_sink_wavwrite(uri, samplerate);
+ if (s->sink) {
+ s->s_do = (aubio_sink_do_t)(aubio_sink_wavwrite_do);
+ s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_wavwrite_do_multi);
+ s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_wavwrite_preset_samplerate);
+ s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_wavwrite_preset_channels);
+ s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_wavwrite_get_samplerate);
+ s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_wavwrite_get_channels);
+ s->s_close = (aubio_sink_close_t)(aubio_sink_wavwrite_close);
+ s->s_del = (del_aubio_sink_t)(del_aubio_sink_wavwrite);
+ return s;
+ }
+#endif /* HAVE_WAVWRITE */
+ AUBIO_ERROR("sink: failed creating %s with samplerate %dHz\n",
+ uri, samplerate);
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+void aubio_sink_do(aubio_sink_t * s, fvec_t * write_data, uint_t write) {
+ s->s_do((void *)s->sink, write_data, write);
+}
+
+void aubio_sink_do_multi(aubio_sink_t * s, fmat_t * write_data, uint_t write) {
+ s->s_do_multi((void *)s->sink, write_data, write);
+}
+
+uint_t aubio_sink_preset_samplerate(aubio_sink_t * s, uint_t samplerate) {
+ return s->s_preset_samplerate((void *)s->sink, samplerate);
+}
+
+uint_t aubio_sink_preset_channels(aubio_sink_t * s, uint_t channels) {
+ return s->s_preset_channels((void *)s->sink, channels);
+}
+
+uint_t aubio_sink_get_samplerate(const aubio_sink_t * s) {
+ return s->s_get_samplerate((void *)s->sink);
+}
+
+uint_t aubio_sink_get_channels(const aubio_sink_t * s) {
+ return s->s_get_channels((void *)s->sink);
+}
+
+uint_t aubio_sink_close(aubio_sink_t *s) {
+ return s->s_close((void *)s->sink);
+}
+
+void del_aubio_sink(aubio_sink_t * s) {
+ if (!s) return;
+ s->s_del((void *)s->sink);
+ AUBIO_FREE(s);
+ return;
+}
diff --git a/src/io/sink.h b/src/io/sink.h
new file mode 100644
index 0000000..ee0f5cf
--- /dev/null
+++ b/src/io/sink.h
@@ -0,0 +1,181 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SINK_H
+#define AUBIO_SINK_H
+
+/** \file
+
+ Media sink to write blocks of consecutive audio samples to file.
+
+ To read from file, use ::aubio_source_t.
+
+ Depending on how aubio was compiled, the following sinks will be available.
+
+ When creating a new sink using ::new_aubio_sink, the new function of each of
+ the compiled-in sinks will be attempted, in the following order, until one of
+ them gets successfully created. If all sinks returned NULL, ::new_aubio_sink
+ will return NULL.
+
+ \b \p sink_apple_audio : ExtAudioFileRef
+
+ This sink uses CoreAudio [Extended Audio File Services]
+ (https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+ to write 16-bits encoded WAV files.
+
+ \b \p sink_sndfile : libsndfile
+
+ This sink uses [libsndfile](http://www.mega-nerd.com/libsndfile/) to write
+ 16-bits encoded WAV files.
+
+ \b \p sink_wavwrite : native WAV write
+
+ A simple sink to write 16-bits PCM RIFF encoded WAV files.
+
+ \example io/test-sink.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** media sink object */
+typedef struct _aubio_sink_t aubio_sink_t;
+
+/**
+
+ create new ::aubio_sink_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_samplerate(aubio_sink_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_channels(aubio_sink_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_get_samplerate(const aubio_sink_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink
+ \return number of channels
+
+*/
+uint_t aubio_sink_get_channels(const aubio_sink_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_do(aubio_sink_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_do_multi(aubio_sink_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink object, created with ::new_aubio_sink
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_close(aubio_sink_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink object, created with ::new_aubio_sink
+
+*/
+void del_aubio_sink(aubio_sink_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_H */
diff --git a/src/io/sink_apple_audio.c b/src/io/sink_apple_audio.c
new file mode 100644
index 0000000..b6fd358
--- /dev/null
+++ b/src/io/sink_apple_audio.c
@@ -0,0 +1,260 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_SINK_APPLE_AUDIO
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/sink_apple_audio.h"
+
+// CFURLRef, CFURLCreateWithFileSystemPath, ...
+#include <CoreFoundation/CoreFoundation.h>
+// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
+#include <AudioToolbox/AudioToolbox.h>
+
+#define FLOAT_TO_SHORT(x) (short)(x * 32768)
+
+extern int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize);
+extern void freeAudioBufferList(AudioBufferList *bufferList);
+extern CFURLRef createURLFromPath(const char * path);
+char_t *getPrintableOSStatusError(char_t *str, OSStatus error);
+
+uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s);
+
+#define MAX_SIZE 4096 // the maximum number of frames that can be written at a time
+
+void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write);
+
+struct _aubio_sink_apple_audio_t {
+ uint_t samplerate;
+ uint_t channels;
+ char_t *path;
+
+ uint_t max_frames;
+
+ AudioBufferList bufferList;
+ ExtAudioFileRef audioFile;
+ bool async;
+};
+
+aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate) {
+ aubio_sink_apple_audio_t * s = AUBIO_NEW(aubio_sink_apple_audio_t);
+ s->max_frames = MAX_SIZE;
+ s->async = false;
+
+ if (uri == NULL) {
+ AUBIO_ERROR("sink_apple_audio: Aborted opening null path\n");
+ goto beach;
+ }
+ if (s->path != NULL) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX) + 1);
+ strncpy(s->path, uri, strnlen(uri, PATH_MAX) + 1);
+
+ s->samplerate = 0;
+ s->channels = 0;
+
+ // negative samplerate given, abort
+ if ((sint_t)samplerate < 0) goto beach;
+ // zero samplerate given. do not open yet
+ if ((sint_t)samplerate == 0) return s;
+
+ s->samplerate = samplerate;
+ s->channels = 1;
+
+ if (aubio_sink_apple_audio_open(s) != AUBIO_OK) {
+ // open failed, abort
+ goto beach;
+ }
+
+ return s;
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+uint_t aubio_sink_apple_audio_preset_samplerate(aubio_sink_apple_audio_t *s, uint_t samplerate)
+{
+ if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+ s->samplerate = samplerate;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_apple_audio_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_apple_audio_preset_channels(aubio_sink_apple_audio_t *s, uint_t channels)
+{
+ if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+ s->channels = channels;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_apple_audio_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s)
+{
+ return s->samplerate;
+}
+
+uint_t aubio_sink_apple_audio_get_channels(const aubio_sink_apple_audio_t *s)
+{
+ return s->channels;
+}
+
+uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s) {
+
+ if (s->samplerate == 0 || s->channels == 0) return AUBIO_FAIL;
+
+ AudioStreamBasicDescription clientFormat;
+ memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
+ clientFormat.mFormatID = kAudioFormatLinearPCM;
+ clientFormat.mSampleRate = (Float64)(s->samplerate);
+ clientFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+ clientFormat.mChannelsPerFrame = s->channels;
+ clientFormat.mBitsPerChannel = sizeof(short) * 8;
+ clientFormat.mFramesPerPacket = 1;
+ clientFormat.mBytesPerFrame = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
+ clientFormat.mBytesPerPacket = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
+ clientFormat.mReserved = 0;
+
+ AudioFileTypeID fileType = kAudioFileWAVEType;
+ CFURLRef fileURL = createURLFromPath(s->path);
+ bool overwrite = true;
+ OSStatus err = noErr;
+ err = ExtAudioFileCreateWithURL(fileURL, fileType, &clientFormat, NULL,
+ overwrite ? kAudioFileFlags_EraseFile : 0, &s->audioFile);
+ CFRelease(fileURL);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERR("sink_apple_audio: error when trying to create %s with "
+ "ExtAudioFileCreateWithURL (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+ if (createAubioBufferList(&s->bufferList, s->channels, s->max_frames * s->channels)) {
+ AUBIO_ERR("sink_apple_audio: error when creating buffer list for %s, "
+ "out of memory? \n", s->path);
+ goto beach;
+ }
+ return AUBIO_OK;
+
+beach:
+ return AUBIO_FAIL;
+}
+
+void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data, uint_t write) {
+ UInt32 c, v;
+ short *data = (short*)s->bufferList.mBuffers[0].mData;
+ if (write > s->max_frames) {
+ AUBIO_WRN("sink_apple_audio: trying to write %d frames, max %d\n", write, s->max_frames);
+ write = s->max_frames;
+ }
+ smpl_t *buf = write_data->data;
+
+ if (buf) {
+ for (c = 0; c < s->channels; c++) {
+ for (v = 0; v < write; v++) {
+ data[v * s->channels + c] =
+ FLOAT_TO_SHORT(buf[ v * s->channels + c]);
+ }
+ }
+ }
+ aubio_sink_apple_audio_write(s, write);
+}
+
+void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * write_data, uint_t write) {
+ UInt32 c, v;
+ short *data = (short*)s->bufferList.mBuffers[0].mData;
+ if (write > s->max_frames) {
+ AUBIO_WRN("sink_apple_audio: trying to write %d frames, max %d\n", write, s->max_frames);
+ write = s->max_frames;
+ }
+ smpl_t **buf = write_data->data;
+
+ if (buf) {
+ for (c = 0; c < s->channels; c++) {
+ for (v = 0; v < write; v++) {
+ data[v * s->channels + c] =
+ FLOAT_TO_SHORT(buf[c][v]);
+ }
+ }
+ }
+ aubio_sink_apple_audio_write(s, write);
+}
+
+void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write) {
+ OSStatus err = noErr;
+ if (s->async) {
+ err = ExtAudioFileWriteAsync(s->audioFile, write, &s->bufferList);
+ if (err) {
+ char_t errorstr[20];
+ if (err == kExtAudioFileError_AsyncWriteBufferOverflow) {
+ sprintf(errorstr,"buffer overflow");
+ } else if (err == kExtAudioFileError_AsyncWriteTooLarge) {
+ sprintf(errorstr,"write too large");
+ } else {
+ // unknown error
+ getPrintableOSStatusError(errorstr, err);
+ }
+ AUBIO_ERROR("sink_apple_audio: error while writing %s "
+ "in ExtAudioFileWriteAsync (%s)\n", s->path, errorstr);
+ }
+ } else {
+ err = ExtAudioFileWrite(s->audioFile, write, &s->bufferList);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("sink_apple_audio: error while writing %s "
+ "in ExtAudioFileWrite (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ }
+ }
+}
+
+uint_t aubio_sink_apple_audio_close(aubio_sink_apple_audio_t * s) {
+ OSStatus err = noErr;
+ if (!s->audioFile) {
+ return AUBIO_FAIL;
+ }
+ err = ExtAudioFileDispose(s->audioFile);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("sink_apple_audio: error while closing %s "
+ "in ExtAudioFileDispose (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ }
+ s->audioFile = NULL;
+ return err;
+}
+
+void del_aubio_sink_apple_audio(aubio_sink_apple_audio_t * s) {
+ if (s->audioFile) aubio_sink_apple_audio_close (s);
+ if (s->path) AUBIO_FREE(s->path);
+ freeAudioBufferList(&s->bufferList);
+ AUBIO_FREE(s);
+ return;
+}
+
+#endif /* HAVE_SINK_APPLE_AUDIO */
diff --git a/src/io/sink_apple_audio.h b/src/io/sink_apple_audio.h
new file mode 100644
index 0000000..14d6a8a
--- /dev/null
+++ b/src/io/sink_apple_audio.h
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SINK_APPLE_AUDIO_H
+#define AUBIO_SINK_APPLE_AUDIO_H
+
+/** \file
+
+ Write to file using Apple AudioToolbox's
+ [ExtAudioFileRef](https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_apple_audio.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_apple_audio object */
+typedef struct _aubio_sink_apple_audio_t aubio_sink_apple_audio_t;
+
+/**
+
+ create new ::aubio_sink_apple_audio_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_apple_audio_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_apple_audio_preset_samplerate(aubio_sink_apple_audio_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_apple_audio_preset_channels(aubio_sink_apple_audio_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_apple_audio
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_apple_audio
+ \return number of channels
+
+*/
+uint_t aubio_sink_apple_audio_get_channels(const aubio_sink_apple_audio_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_apple_audio object, created with ::new_aubio_sink_apple_audio
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_apple_audio_close(aubio_sink_apple_audio_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+
+*/
+void del_aubio_sink_apple_audio(aubio_sink_apple_audio_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_APPLE_AUDIO_H */
diff --git a/src/io/sink_sndfile.c b/src/io/sink_sndfile.c
new file mode 100644
index 0000000..99392c3
--- /dev/null
+++ b/src/io/sink_sndfile.c
@@ -0,0 +1,231 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+
+#ifdef HAVE_SNDFILE
+
+#include <sndfile.h>
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/sink_sndfile.h"
+
+#define MAX_CHANNELS 6
+#define MAX_SIZE 4096
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_sf_write_smpl sf_write_float
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_sf_write_smpl sf_write_double
+#endif /* HAVE_AUBIO_DOUBLE */
+
+struct _aubio_sink_sndfile_t {
+ uint_t samplerate;
+ uint_t channels;
+ char_t *path;
+
+ uint_t max_size;
+
+ SNDFILE *handle;
+ uint_t scratch_size;
+ smpl_t *scratch_data;
+};
+
+uint_t aubio_sink_sndfile_open(aubio_sink_sndfile_t *s);
+
+aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * path, uint_t samplerate) {
+ aubio_sink_sndfile_t * s = AUBIO_NEW(aubio_sink_sndfile_t);
+ s->max_size = MAX_SIZE;
+
+ if (path == NULL) {
+ AUBIO_ERR("sink_sndfile: Aborted opening null path\n");
+ return NULL;
+ }
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ s->samplerate = 0;
+ s->channels = 0;
+
+ // negative samplerate given, abort
+ if ((sint_t)samplerate < 0) goto beach;
+ // zero samplerate given. do not open yet
+ if ((sint_t)samplerate == 0) return s;
+
+ s->samplerate = samplerate;
+ s->channels = 1;
+
+ if (aubio_sink_sndfile_open(s) != AUBIO_OK) {;
+ goto beach;
+ }
+ return s;
+
+beach:
+ del_aubio_sink_sndfile(s);
+ return NULL;
+}
+
+uint_t aubio_sink_sndfile_preset_samplerate(aubio_sink_sndfile_t *s, uint_t samplerate)
+{
+ if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+ s->samplerate = samplerate;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_sndfile_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_sndfile_preset_channels(aubio_sink_sndfile_t *s, uint_t channels)
+{
+ if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+ s->channels = channels;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_sndfile_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s)
+{
+ return s->samplerate;
+}
+
+uint_t aubio_sink_sndfile_get_channels(const aubio_sink_sndfile_t *s)
+{
+ return s->channels;
+}
+
+uint_t aubio_sink_sndfile_open(aubio_sink_sndfile_t *s) {
+ /* set output format */
+ SF_INFO sfinfo;
+ AUBIO_MEMSET(&sfinfo, 0, sizeof (sfinfo));
+ sfinfo.samplerate = s->samplerate;
+ sfinfo.channels = s->channels;
+ sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+
+ /* try creating the file */
+ s->handle = sf_open (s->path, SFM_WRITE, &sfinfo);
+
+ if (s->handle == NULL) {
+ /* show libsndfile err msg */
+ AUBIO_ERR("sink_sndfile: Failed opening %s. %s\n", s->path, sf_strerror (NULL));
+ return AUBIO_FAIL;
+ }
+
+ s->scratch_size = s->max_size*s->channels;
+ /* allocate data for de/interleaving reallocated when needed. */
+ if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
+ AUBIO_ERR("sink_sndfile: %d x %d exceeds maximum aubio_sink_sndfile buffer size %d\n",
+ s->max_size, s->channels, MAX_CHANNELS * MAX_CHANNELS);
+ return AUBIO_FAIL;
+ }
+ s->scratch_data = AUBIO_ARRAY(smpl_t,s->scratch_size);
+
+ return AUBIO_OK;
+}
+
+void aubio_sink_sndfile_do(aubio_sink_sndfile_t *s, fvec_t * write_data, uint_t write){
+ uint_t i, j, channels = s->channels;
+ int nsamples = 0;
+ smpl_t *pwrite;
+ sf_count_t written_frames;
+
+ if (write > s->max_size) {
+ AUBIO_WRN("sink_sndfile: trying to write %d frames, but only %d can be written at a time\n",
+ write, s->max_size);
+ write = s->max_size;
+ }
+
+ nsamples = channels * write;
+
+ /* interleaving data */
+ for ( i = 0; i < channels; i++) {
+ pwrite = (smpl_t *)write_data->data;
+ for (j = 0; j < write; j++) {
+ s->scratch_data[channels*j+i] = pwrite[j];
+ }
+ }
+
+ written_frames = aubio_sf_write_smpl (s->handle, s->scratch_data, nsamples);
+ if (written_frames/channels != write) {
+ AUBIO_WRN("sink_sndfile: trying to write %d frames to %s, but only %d could be written\n",
+ write, s->path, (uint_t)written_frames);
+ }
+ return;
+}
+
+void aubio_sink_sndfile_do_multi(aubio_sink_sndfile_t *s, fmat_t * write_data, uint_t write){
+ uint_t i, j, channels = s->channels;
+ int nsamples = 0;
+ smpl_t *pwrite;
+ sf_count_t written_frames;
+
+ if (write > s->max_size) {
+ AUBIO_WRN("sink_sndfile: trying to write %d frames, but only %d can be written at a time\n",
+ write, s->max_size);
+ write = s->max_size;
+ }
+
+ nsamples = channels * write;
+
+ /* interleaving data */
+ for ( i = 0; i < write_data->height; i++) {
+ pwrite = (smpl_t *)write_data->data[i];
+ for (j = 0; j < write; j++) {
+ s->scratch_data[channels*j+i] = pwrite[j];
+ }
+ }
+
+ written_frames = aubio_sf_write_smpl (s->handle, s->scratch_data, nsamples);
+ if (written_frames/channels != write) {
+ AUBIO_WRN("sink_sndfile: trying to write %d frames to %s, but only %d could be written\n",
+ write, s->path, (uint_t)written_frames);
+ }
+ return;
+}
+
+uint_t aubio_sink_sndfile_close (aubio_sink_sndfile_t *s) {
+ if (!s->handle) {
+ return AUBIO_FAIL;
+ }
+ if (sf_close(s->handle)) {
+ AUBIO_ERR("sink_sndfile: Error closing file %s: %s", s->path, sf_strerror (NULL));
+ return AUBIO_FAIL;
+ }
+ s->handle = NULL;
+ return AUBIO_OK;
+}
+
+void del_aubio_sink_sndfile(aubio_sink_sndfile_t * s){
+ if (!s) return;
+ if (s->path) AUBIO_FREE(s->path);
+ aubio_sink_sndfile_close(s);
+ AUBIO_FREE(s->scratch_data);
+ AUBIO_FREE(s);
+}
+
+#endif /* HAVE_SNDFILE */
diff --git a/src/io/sink_sndfile.h b/src/io/sink_sndfile.h
new file mode 100644
index 0000000..083c4ca
--- /dev/null
+++ b/src/io/sink_sndfile.h
@@ -0,0 +1,162 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SINK_SNDFILE_H
+#define AUBIO_SINK_SNDFILE_H
+
+/** \file
+
+ Write to file using [libsndfile](http://www.mega-nerd.com/libsndfile/)
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_sndfile.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_sndfile object */
+typedef struct _aubio_sink_sndfile_t aubio_sink_sndfile_t;
+
+/**
+
+ create new ::aubio_sink_sndfile_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_sndfile_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_sndfile_preset_samplerate(aubio_sink_sndfile_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_sndfile_preset_channels(aubio_sink_sndfile_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_sndfile
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_sndfile
+ \return number of channels
+
+*/
+uint_t aubio_sink_sndfile_get_channels(const aubio_sink_sndfile_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_sndfile_do(aubio_sink_sndfile_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_sndfile_do_multi(aubio_sink_sndfile_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_sndfile object, created with ::new_aubio_sink_sndfile
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_sndfile_close(aubio_sink_sndfile_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+
+*/
+void del_aubio_sink_sndfile(aubio_sink_sndfile_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_SNDFILE_H */
diff --git a/src/io/sink_wavwrite.c b/src/io/sink_wavwrite.c
new file mode 100644
index 0000000..761f6e5
--- /dev/null
+++ b/src/io/sink_wavwrite.c
@@ -0,0 +1,298 @@
+/*
+ Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+
+#ifdef HAVE_WAVWRITE
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/sink_wavwrite.h"
+
+#include <errno.h>
+
+#define MAX_CHANNELS 6
+#define MAX_SIZE 4096
+
+#define FLOAT_TO_SHORT(x) (short)(x * 32768)
+
+// swap endian of a short
+#define SWAPS(x) ((x & 0xff) << 8) | ((x & 0xff00) >> 8)
+
+// swap host to little endian
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define HTOLES(x) SWAPS(x)
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define HTOLES(x) x
+#else
+#ifdef HAVE_WIN_HACKS
+#define HTOLES(x) x
+#else
+#define HTOLES(x) SWAPS(htons(x))
+#endif
+#endif
+
+uint_t aubio_sink_wavwrite_open(aubio_sink_wavwrite_t *s);
+
+struct _aubio_sink_wavwrite_t {
+ char_t *path;
+ uint_t samplerate;
+ uint_t channels;
+ uint_t bitspersample;
+ uint_t total_frames_written;
+
+ FILE *fid;
+
+ uint_t max_size;
+
+ uint_t scratch_size;
+ unsigned short *scratch_data;
+};
+
+unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length);
+unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length) {
+ uint_t i;
+ for (i = 0; i < length; i++) {
+ str[i] = s >> (i * 8);
+ }
+ return str;
+}
+
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * path, uint_t samplerate) {
+ aubio_sink_wavwrite_t * s = AUBIO_NEW(aubio_sink_wavwrite_t);
+
+ if (path == NULL) {
+ AUBIO_ERR("sink_wavwrite: Aborted opening null path\n");
+ goto beach;
+ }
+ if ((sint_t)samplerate < 0) {
+ AUBIO_ERR("sink_wavwrite: Can not create %s with samplerate %d\n", path, samplerate);
+ goto beach;
+ }
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ s->max_size = MAX_SIZE;
+ s->bitspersample = 16;
+ s->total_frames_written = 0;
+
+ s->samplerate = 0;
+ s->channels = 0;
+
+ // negative samplerate given, abort
+ if ((sint_t)samplerate < 0) goto beach;
+ // zero samplerate given. do not open yet
+ if ((sint_t)samplerate == 0) return s;
+ // samplerate way too large, fail
+ if ((sint_t)samplerate > 192000 * 4) goto beach;
+
+ s->samplerate = samplerate;
+ s->channels = 1;
+
+ if (aubio_sink_wavwrite_open(s) != AUBIO_OK) {
+ // open failed, abort
+ goto beach;
+ }
+
+ return s;
+beach:
+ //AUBIO_ERR("sink_wavwrite: failed creating %s with samplerate %dHz\n",
+ // s->path, s->samplerate);
+ del_aubio_sink_wavwrite(s);
+ return NULL;
+}
+
+uint_t aubio_sink_wavwrite_preset_samplerate(aubio_sink_wavwrite_t *s, uint_t samplerate)
+{
+ if ((sint_t)(samplerate) <= 0) return AUBIO_FAIL;
+ s->samplerate = samplerate;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_wavwrite_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_wavwrite_preset_channels(aubio_sink_wavwrite_t *s, uint_t channels)
+{
+ if ((sint_t)(channels) <= 0) return AUBIO_FAIL;
+ s->channels = channels;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_wavwrite_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s)
+{
+ return s->samplerate;
+}
+
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s)
+{
+ return s->channels;
+}
+
+uint_t aubio_sink_wavwrite_open(aubio_sink_wavwrite_t *s) {
+ unsigned char buf[5];
+ uint_t byterate, blockalign;
+
+ /* open output file */
+ s->fid = fopen((const char *)s->path, "wb");
+ if (!s->fid) {
+ AUBIO_ERR("sink_wavwrite: could not open %s (%s)\n", s->path, strerror(errno));
+ goto beach;
+ }
+
+ // ChunkID
+ fwrite("RIFF", 4, 1, s->fid);
+
+ // ChunkSize (0 for now, actual size will be written in _close)
+ fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
+
+ // Format
+ fwrite("WAVE", 4, 1, s->fid);
+
+ // Subchunk1ID
+ fwrite("fmt ", 4, 1, s->fid);
+
+ // Subchunk1Size
+ fwrite(write_little_endian(16, buf, 4), 4, 1, s->fid);
+
+ // AudioFormat
+ fwrite(write_little_endian(1, buf, 2), 2, 1, s->fid);
+
+ // NumChannels
+ fwrite(write_little_endian(s->channels, buf, 2), 2, 1, s->fid);
+
+ // SampleRate
+ fwrite(write_little_endian(s->samplerate, buf, 4), 4, 1, s->fid);
+
+ // ByteRate
+ byterate = s->samplerate * s->channels * s->bitspersample / 8;
+ fwrite(write_little_endian(byterate, buf, 4), 4, 1, s->fid);
+
+ // BlockAlign
+ blockalign = s->channels * s->bitspersample / 8;
+ fwrite(write_little_endian(blockalign, buf, 2), 2, 1, s->fid);
+
+ // BitsPerSample
+ fwrite(write_little_endian(s->bitspersample, buf, 2), 2, 1, s->fid);
+
+ // Subchunk2ID
+ fwrite("data", 4, 1, s->fid);
+
+ // Subchunk1Size (0 for now, actual size will be written in _close)
+ fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
+
+ s->scratch_size = s->max_size * s->channels;
+ /* allocate data for de/interleaving reallocated when needed. */
+ if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
+ AUBIO_ERR("sink_wavwrite: %d x %d exceeds SIZE maximum buffer size %d\n",
+ s->max_size, s->channels, MAX_SIZE * MAX_CHANNELS);
+ goto beach;
+ }
+ s->scratch_data = AUBIO_ARRAY(unsigned short,s->scratch_size);
+
+ return AUBIO_OK;
+
+beach:
+ return AUBIO_FAIL;
+}
+
+
+void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t *s, fvec_t * write_data, uint_t write){
+ uint_t i = 0, written_frames = 0;
+
+ if (write > s->max_size) {
+ AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+ "but only %d can be written at a time\n", write, s->path, s->max_size);
+ write = s->max_size;
+ }
+
+ for (i = 0; i < write; i++) {
+ s->scratch_data[i] = HTOLES(FLOAT_TO_SHORT(write_data->data[i]));
+ }
+ written_frames = fwrite(s->scratch_data, 2, write, s->fid);
+
+ if (written_frames != write) {
+ AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+ "but only %d could be written\n", write, s->path, written_frames);
+ }
+ s->total_frames_written += written_frames;
+ return;
+}
+
+void aubio_sink_wavwrite_do_multi(aubio_sink_wavwrite_t *s, fmat_t * write_data, uint_t write){
+ uint_t c = 0, i = 0, written_frames = 0;
+
+ if (write > s->max_size) {
+ AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+ "but only %d can be written at a time\n", write, s->path, s->max_size);
+ write = s->max_size;
+ }
+
+ for (c = 0; c < s->channels; c++) {
+ for (i = 0; i < write; i++) {
+ s->scratch_data[i * s->channels + c] = HTOLES(FLOAT_TO_SHORT(write_data->data[c][i]));
+ }
+ }
+ written_frames = fwrite(s->scratch_data, 2, write * s->channels, s->fid);
+
+ if (written_frames != write * s->channels) {
+ AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
+ "but only %d could be written\n", write, s->path, written_frames / s->channels);
+ }
+ s->total_frames_written += written_frames;
+ return;
+}
+
+uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
+ uint_t data_size = s->total_frames_written * s->bitspersample * s->channels / 8;
+ unsigned char buf[5];
+ if (!s->fid) return AUBIO_FAIL;
+ // ChunkSize
+ fseek(s->fid, 4, SEEK_SET);
+ fwrite(write_little_endian(data_size + 36, buf, 4), 4, 1, s->fid);
+ // Subchunk2Size
+ fseek(s->fid, 40, SEEK_SET);
+ fwrite(write_little_endian(data_size, buf, 4), 4, 1, s->fid);
+ // close file
+ if (fclose(s->fid)) {
+ AUBIO_ERR("sink_wavwrite: Error closing file %s (%s)\n", s->path, strerror(errno));
+ }
+ s->fid = NULL;
+ return AUBIO_OK;
+}
+
+void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s){
+ if (!s) return;
+ aubio_sink_wavwrite_close(s);
+ if (s->path) AUBIO_FREE(s->path);
+ AUBIO_FREE(s->scratch_data);
+ AUBIO_FREE(s);
+}
+
+#endif /* HAVE_WAVWRITE */
diff --git a/src/io/sink_wavwrite.h b/src/io/sink_wavwrite.h
new file mode 100644
index 0000000..bb479e4
--- /dev/null
+++ b/src/io/sink_wavwrite.h
@@ -0,0 +1,162 @@
+/*
+ Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SINK_WAVWRITE_H
+#define AUBIO_SINK_WAVWRITE_H
+
+/** \file
+
+ Write to file using native file writer.
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_wavwrite.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_wavwrite object */
+typedef struct _aubio_sink_wavwrite_t aubio_sink_wavwrite_t;
+
+/**
+
+ create new ::aubio_sink_wavwrite_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_wavwrite_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_wavwrite_preset_samplerate(aubio_sink_wavwrite_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_wavwrite_preset_channels(aubio_sink_wavwrite_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_wavwrite
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_wavwrite
+ \return number of channels
+
+*/
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_wavwrite_do_multi(aubio_sink_wavwrite_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_wavwrite object, create with ::new_aubio_sink_wavwrite
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+
+*/
+void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_WAVWRITE_H */
diff --git a/src/io/source.c b/src/io/source.c
new file mode 100644
index 0000000..246eb90
--- /dev/null
+++ b/src/io/source.c
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2012 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/source.h"
+#ifdef HAVE_LIBAV
+#include "io/source_avcodec.h"
+#endif /* HAVE_LIBAV */
+#ifdef HAVE_SOURCE_APPLE_AUDIO
+#include "io/source_apple_audio.h"
+#endif /* HAVE_SOURCE_APPLE_AUDIO */
+#ifdef HAVE_SNDFILE
+#include "io/source_sndfile.h"
+#endif /* HAVE_SNDFILE */
+#ifdef HAVE_WAVREAD
+#include "io/source_wavread.h"
+#endif /* HAVE_WAVREAD */
+
+typedef void (*aubio_source_do_t)(aubio_source_t * s, fvec_t * data, uint_t * read);
+typedef void (*aubio_source_do_multi_t)(aubio_source_t * s, fmat_t * data, uint_t * read);
+typedef uint_t (*aubio_source_get_samplerate_t)(aubio_source_t * s);
+typedef uint_t (*aubio_source_get_channels_t)(aubio_source_t * s);
+typedef uint_t (*aubio_source_get_duration_t)(aubio_source_t * s);
+typedef uint_t (*aubio_source_seek_t)(aubio_source_t * s, uint_t seek);
+typedef uint_t (*aubio_source_close_t)(aubio_source_t * s);
+typedef void (*del_aubio_source_t)(aubio_source_t * s);
+
+struct _aubio_source_t {
+ void *source;
+ aubio_source_do_t s_do;
+ aubio_source_do_multi_t s_do_multi;
+ aubio_source_get_samplerate_t s_get_samplerate;
+ aubio_source_get_channels_t s_get_channels;
+ aubio_source_get_duration_t s_get_duration;
+ aubio_source_seek_t s_seek;
+ aubio_source_close_t s_close;
+ del_aubio_source_t s_del;
+};
+
+aubio_source_t * new_aubio_source(const char_t * uri, uint_t samplerate, uint_t hop_size) {
+ aubio_source_t * s = AUBIO_NEW(aubio_source_t);
+#ifdef HAVE_LIBAV
+ s->source = (void *)new_aubio_source_avcodec(uri, samplerate, hop_size);
+ if (s->source) {
+ s->s_do = (aubio_source_do_t)(aubio_source_avcodec_do);
+ s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_avcodec_do_multi);
+ s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_avcodec_get_channels);
+ s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_avcodec_get_samplerate);
+ s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_avcodec_get_duration);
+ s->s_seek = (aubio_source_seek_t)(aubio_source_avcodec_seek);
+ s->s_close = (aubio_source_close_t)(aubio_source_avcodec_close);
+ s->s_del = (del_aubio_source_t)(del_aubio_source_avcodec);
+ return s;
+ }
+#endif /* HAVE_LIBAV */
+#ifdef HAVE_SOURCE_APPLE_AUDIO
+ s->source = (void *)new_aubio_source_apple_audio(uri, samplerate, hop_size);
+ if (s->source) {
+ s->s_do = (aubio_source_do_t)(aubio_source_apple_audio_do);
+ s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_apple_audio_do_multi);
+ s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_apple_audio_get_channels);
+ s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_apple_audio_get_samplerate);
+ s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_apple_audio_get_duration);
+ s->s_seek = (aubio_source_seek_t)(aubio_source_apple_audio_seek);
+ s->s_close = (aubio_source_close_t)(aubio_source_apple_audio_close);
+ s->s_del = (del_aubio_source_t)(del_aubio_source_apple_audio);
+ return s;
+ }
+#endif /* HAVE_SOURCE_APPLE_AUDIO */
+#ifdef HAVE_SNDFILE
+ s->source = (void *)new_aubio_source_sndfile(uri, samplerate, hop_size);
+ if (s->source) {
+ s->s_do = (aubio_source_do_t)(aubio_source_sndfile_do);
+ s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_sndfile_do_multi);
+ s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_sndfile_get_channels);
+ s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_sndfile_get_samplerate);
+ s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_sndfile_get_duration);
+ s->s_seek = (aubio_source_seek_t)(aubio_source_sndfile_seek);
+ s->s_close = (aubio_source_close_t)(aubio_source_sndfile_close);
+ s->s_del = (del_aubio_source_t)(del_aubio_source_sndfile);
+ return s;
+ }
+#endif /* HAVE_SNDFILE */
+#ifdef HAVE_WAVREAD
+ s->source = (void *)new_aubio_source_wavread(uri, samplerate, hop_size);
+ if (s->source) {
+ s->s_do = (aubio_source_do_t)(aubio_source_wavread_do);
+ s->s_do_multi = (aubio_source_do_multi_t)(aubio_source_wavread_do_multi);
+ s->s_get_channels = (aubio_source_get_channels_t)(aubio_source_wavread_get_channels);
+ s->s_get_samplerate = (aubio_source_get_samplerate_t)(aubio_source_wavread_get_samplerate);
+ s->s_get_duration = (aubio_source_get_duration_t)(aubio_source_wavread_get_duration);
+ s->s_seek = (aubio_source_seek_t)(aubio_source_wavread_seek);
+ s->s_close = (aubio_source_close_t)(aubio_source_wavread_close);
+ s->s_del = (del_aubio_source_t)(del_aubio_source_wavread);
+ return s;
+ }
+#endif /* HAVE_WAVREAD */
+ AUBIO_ERROR("source: failed creating aubio source with %s"
+ " at samplerate %d with hop_size %d\n", uri, samplerate, hop_size);
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+void aubio_source_do(aubio_source_t * s, fvec_t * data, uint_t * read) {
+ s->s_do((void *)s->source, data, read);
+}
+
+void aubio_source_do_multi(aubio_source_t * s, fmat_t * data, uint_t * read) {
+ s->s_do_multi((void *)s->source, data, read);
+}
+
+uint_t aubio_source_close(aubio_source_t * s) {
+ return s->s_close((void *)s->source);
+}
+
+void del_aubio_source(aubio_source_t * s) {
+ if (!s) return;
+ s->s_del((void *)s->source);
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_source_get_samplerate(aubio_source_t * s) {
+ return s->s_get_samplerate((void *)s->source);
+}
+
+uint_t aubio_source_get_channels(aubio_source_t * s) {
+ return s->s_get_channels((void *)s->source);
+}
+
+uint_t aubio_source_get_duration(aubio_source_t *s) {
+ return s->s_get_duration((void *)s->source);
+}
+
+uint_t aubio_source_seek (aubio_source_t * s, uint_t seek ) {
+ return s->s_seek((void *)s->source, seek);
+}
diff --git a/src/io/source.h b/src/io/source.h
new file mode 100644
index 0000000..2df2584
--- /dev/null
+++ b/src/io/source.h
@@ -0,0 +1,184 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SOURCE_H
+#define AUBIO_SOURCE_H
+
+/** \file
+
+ Media source to read blocks of consecutive audio samples from file.
+
+ To write to file, use ::aubio_sink_t.
+
+ Depending on how aubio was compiled, the following sources will be available.
+
+ When creating a new source using ::new_aubio_source, the new function of each
+ of the compiled-in sources will be used, in the following order, until one of
+ them gets successfully created. If all sources returned NULL,
+ ::new_aubio_source will return NULL.
+
+ \b \p source_avcodec : libav
+
+ aubio can be optionally compiled with [libav](http://libav.org), which can
+ read from a very large number of audio and video formats, including over
+ different network protocols such as HTTP.
+
+ \b \p source_apple_audio : ExtAudioFileRef
+
+ On Mac and iOS platforms, aubio should be compiled with CoreAudio [Extended
+ Audio File Services]
+ (https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html).
+ This provides access to most common audio file formats, including compressed
+ ones.
+
+ \b \p source_sndfile : libsndfile
+
+ Also optional, aubio can be built against
+ [libsndfile](http://www.mega-nerd.com/libsndfile/), which can read [most
+ uncompressed formats](http://www.mega-nerd.com/libsndfile/#Features).
+
+ \b \p source_wavread : native WAV reader
+
+ A simple source to read from 16-bits PCM RIFF encoded WAV files.
+
+ \example io/test-source.c
+ \example io/test-source_multi.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** media source object */
+typedef struct _aubio_source_t aubio_source_t;
+
+/**
+
+ create new ::aubio_source_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_get_samplerate.
+
+*/
+aubio_source_t * new_aubio_source(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source
+ \param read_to ::fmat_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_do_multi(aubio_source_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_get_samplerate(aubio_source_t * s);
+
+/**
+
+ get channels of source object
+
+ \param s source object, created with ::new_aubio_source
+ \return channels
+
+*/
+uint_t aubio_source_get_channels (aubio_source_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_seek (aubio_source_t * s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source
+ \return number of frames in file
+
+*/
+uint_t aubio_source_get_duration (aubio_source_t * s);
+
+/**
+
+ close source object
+
+ \param s source object, created with ::new_aubio_source
+
+ \return 0 if sucessful, non-zero on failure
+
+ */
+uint_t aubio_source_close (aubio_source_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source
+
+*/
+void del_aubio_source(aubio_source_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_H */
diff --git a/src/io/source_apple_audio.c b/src/io/source_apple_audio.c
new file mode 100644
index 0000000..a86d4a3
--- /dev/null
+++ b/src/io/source_apple_audio.c
@@ -0,0 +1,378 @@
+/*
+ Copyright (C) 2012 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_SOURCE_APPLE_AUDIO
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/source_apple_audio.h"
+
+// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
+#include <AudioToolbox/AudioToolbox.h>
+
+#define RT_BYTE1( a ) ( (a) & 0xff )
+#define RT_BYTE2( a ) ( ((a) >> 8) & 0xff )
+#define RT_BYTE3( a ) ( ((a) >> 16) & 0xff )
+#define RT_BYTE4( a ) ( ((a) >> 24) & 0xff )
+
+#define SHORT_TO_FLOAT(x) (smpl_t)(x * 3.0517578125e-05)
+
+struct _aubio_source_apple_audio_t {
+ uint_t channels;
+ uint_t samplerate; //< requested samplerate
+ uint_t source_samplerate; //< actual source samplerate
+ uint_t block_size;
+
+ char_t *path;
+
+ ExtAudioFileRef audioFile;
+ AudioBufferList bufferList;
+};
+
+extern int createAubioBufferList(AudioBufferList *bufferList, int channels, int max_source_samples);
+extern void freeAudioBufferList(AudioBufferList *bufferList);
+extern CFURLRef createURLFromPath(const char * path);
+char_t *getPrintableOSStatusError(char_t *str, OSStatus error);
+
+uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, const char_t * path);
+
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(const char_t * path, uint_t samplerate, uint_t block_size)
+{
+ aubio_source_apple_audio_t * s = AUBIO_NEW(aubio_source_apple_audio_t);
+
+ if (path == NULL) {
+ AUBIO_ERROR("source_apple_audio: Aborted opening null path\n");
+ goto beach;
+ }
+
+ if ( (sint_t)block_size <= 0 ) {
+ AUBIO_ERROR("source_apple_audio: Can not open %s with null or negative block_size %d\n",
+ path, block_size);
+ goto beach;
+ }
+
+ if ( (sint_t)samplerate < 0 ) {
+ AUBIO_ERROR("source_apple_audio: Can not open %s with negative samplerate %d\n",
+ path, samplerate);
+ goto beach;
+ }
+
+ s->block_size = block_size;
+ s->samplerate = samplerate;
+
+ if ( aubio_source_apple_audio_open ( s, path ) ) {
+ goto beach;
+ }
+ return s;
+
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+uint_t aubio_source_apple_audio_open (aubio_source_apple_audio_t *s, const char_t * path)
+{
+ OSStatus err = noErr;
+ UInt32 propSize;
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ // open the resource url
+ CFURLRef fileURL = createURLFromPath(s->path);
+ err = ExtAudioFileOpenURL(fileURL, &s->audioFile);
+ CFRelease(fileURL);
+ if (err == -43) {
+ AUBIO_ERR("source_apple_audio: Failed opening %s, "
+ "file not found, or no read access\n", s->path);
+ goto beach;
+ } else if (err) {
+ char_t errorstr[20];
+ AUBIO_ERR("source_apple_audio: Failed opening %s, "
+ "error in ExtAudioFileOpenURL (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+
+ // create an empty AudioStreamBasicDescription
+ AudioStreamBasicDescription fileFormat;
+ propSize = sizeof(fileFormat);
+ memset(&fileFormat, 0, sizeof(AudioStreamBasicDescription));
+
+ // fill it with the file description
+ err = ExtAudioFileGetProperty(s->audioFile,
+ kExtAudioFileProperty_FileDataFormat, &propSize, &fileFormat);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: Failed opening %s, "
+ "error in ExtAudioFileGetProperty (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+
+ if (s->samplerate == 0) {
+ s->samplerate = fileFormat.mSampleRate;
+ //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
+ }
+
+ s->source_samplerate = fileFormat.mSampleRate;
+ s->channels = fileFormat.mChannelsPerFrame;
+
+ AudioStreamBasicDescription clientFormat;
+ propSize = sizeof(clientFormat);
+ memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
+ clientFormat.mFormatID = kAudioFormatLinearPCM;
+ clientFormat.mSampleRate = (Float64)(s->samplerate);
+ clientFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+ clientFormat.mChannelsPerFrame = s->channels;
+ clientFormat.mBitsPerChannel = sizeof(short) * 8;
+ clientFormat.mFramesPerPacket = 1;
+ clientFormat.mBytesPerFrame = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
+ clientFormat.mBytesPerPacket = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
+ clientFormat.mReserved = 0;
+
+ // set the client format description
+ err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat,
+ propSize, &clientFormat);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: Failed opening %s, "
+ "error in ExtAudioFileSetProperty (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+#if 0
+ // print client and format descriptions
+ AUBIO_DBG("Opened %s\n", s->path);
+ AUBIO_DBG("file/client Format.mFormatID: : %3c%c%c%c / %c%c%c%c\n",
+ (int)RT_BYTE4(fileFormat.mFormatID), (int)RT_BYTE3(fileFormat.mFormatID), (int)RT_BYTE2(fileFormat.mFormatID), (int)RT_BYTE1(fileFormat.mFormatID),
+ (int)RT_BYTE4(clientFormat.mFormatID), (int)RT_BYTE3(clientFormat.mFormatID), (int)RT_BYTE2(clientFormat.mFormatID), (int)RT_BYTE1(clientFormat.mFormatID)
+ );
+
+ AUBIO_DBG("file/client Format.mSampleRate : %6.0f / %.0f\n", fileFormat.mSampleRate , clientFormat.mSampleRate);
+ AUBIO_DBG("file/client Format.mFormatFlags : %6d / %d\n", (int)fileFormat.mFormatFlags , (int)clientFormat.mFormatFlags);
+ AUBIO_DBG("file/client Format.mChannelsPerFrame : %6d / %d\n", (int)fileFormat.mChannelsPerFrame, (int)clientFormat.mChannelsPerFrame);
+ AUBIO_DBG("file/client Format.mBitsPerChannel : %6d / %d\n", (int)fileFormat.mBitsPerChannel , (int)clientFormat.mBitsPerChannel);
+ AUBIO_DBG("file/client Format.mFramesPerPacket : %6d / %d\n", (int)fileFormat.mFramesPerPacket , (int)clientFormat.mFramesPerPacket);
+ AUBIO_DBG("file/client Format.mBytesPerFrame : %6d / %d\n", (int)fileFormat.mBytesPerFrame , (int)clientFormat.mBytesPerFrame);
+ AUBIO_DBG("file/client Format.mBytesPerPacket : %6d / %d\n", (int)fileFormat.mBytesPerPacket , (int)clientFormat.mBytesPerPacket);
+ AUBIO_DBG("file/client Format.mReserved : %6d / %d\n", (int)fileFormat.mReserved , (int)clientFormat.mReserved);
+#endif
+ goto beach;
+ }
+
+ smpl_t ratio = s->source_samplerate * 1. / s->samplerate;
+ if (ratio < 1.) {
+ AUBIO_WRN("source_apple_audio: up-sampling %s from %0dHz to %0dHz\n",
+ s->path, s->source_samplerate, s->samplerate);
+ }
+
+ // allocate the AudioBufferList
+ freeAudioBufferList(&s->bufferList);
+ if (createAubioBufferList(&s->bufferList, s->channels, s->block_size * s->channels)) {
+ AUBIO_ERR("source_apple_audio: failed creating bufferList\n");
+ goto beach;
+ }
+
+beach:
+ return err;
+}
+
+void aubio_source_apple_audio_do(aubio_source_apple_audio_t *s, fvec_t * read_to, uint_t * read) {
+ UInt32 c, v, loadedPackets = s->block_size;
+ OSStatus err = ExtAudioFileRead(s->audioFile, &loadedPackets, &s->bufferList);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: error while reading %s "
+ "with ExtAudioFileRead (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+
+ short *data = (short*)s->bufferList.mBuffers[0].mData;
+
+ smpl_t *buf = read_to->data;
+
+ for (v = 0; v < loadedPackets; v++) {
+ buf[v] = 0.;
+ for (c = 0; c < s->channels; c++) {
+ buf[v] += SHORT_TO_FLOAT(data[ v * s->channels + c]);
+ }
+ buf[v] /= (smpl_t)s->channels;
+ }
+ // short read, fill with zeros
+ if (loadedPackets < s->block_size) {
+ for (v = loadedPackets; v < s->block_size; v++) {
+ buf[v] = 0.;
+ }
+ }
+
+ *read = (uint_t)loadedPackets;
+ return;
+beach:
+ *read = 0;
+ return;
+}
+
+void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t *s, fmat_t * read_to, uint_t * read) {
+ UInt32 c, v, loadedPackets = s->block_size;
+ OSStatus err = ExtAudioFileRead(s->audioFile, &loadedPackets, &s->bufferList);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: error while reading %s "
+ "with ExtAudioFileRead (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+
+ short *data = (short*)s->bufferList.mBuffers[0].mData;
+
+ smpl_t **buf = read_to->data;
+
+ for (v = 0; v < loadedPackets; v++) {
+ for (c = 0; c < read_to->height; c++) {
+ buf[c][v] = SHORT_TO_FLOAT(data[ v * s->channels + c]);
+ }
+ }
+ // if read_data has more channels than the file
+ if (read_to->height > s->channels) {
+ // copy last channel to all additional channels
+ for (v = 0; v < loadedPackets; v++) {
+ for (c = s->channels; c < read_to->height; c++) {
+ buf[c][v] = SHORT_TO_FLOAT(data[ v * s->channels + (s->channels - 1)]);
+ }
+ }
+ }
+ // short read, fill with zeros
+ if (loadedPackets < s->block_size) {
+ for (v = loadedPackets; v < s->block_size; v++) {
+ for (c = 0; c < read_to->height; c++) {
+ buf[c][v] = 0.;
+ }
+ }
+ }
+ *read = (uint_t)loadedPackets;
+ return;
+beach:
+ *read = 0;
+ return;
+}
+
+uint_t aubio_source_apple_audio_close (aubio_source_apple_audio_t *s)
+{
+ OSStatus err = noErr;
+ if (!s->audioFile) { return AUBIO_FAIL; }
+ err = ExtAudioFileDispose(s->audioFile);
+ s->audioFile = NULL;
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: error while closing %s "
+ "in ExtAudioFileDispose (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ return err;
+ }
+ return AUBIO_OK;
+}
+
+void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){
+ aubio_source_apple_audio_close (s);
+ if (s->path) AUBIO_FREE(s->path);
+ freeAudioBufferList(&s->bufferList);
+ AUBIO_FREE(s);
+ return;
+}
+
+uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos) {
+ OSStatus err = noErr;
+ if ((sint_t)pos < 0) {
+ AUBIO_ERROR("source_apple_audio: error while seeking in %s "
+ "(can not seek at negative position %d)\n",
+ s->path, pos);
+ err = -1;
+ goto beach;
+ }
+ // check if we are not seeking out of the file
+ uint_t fileLengthFrames = aubio_source_apple_audio_get_duration(s);
+ // compute position in the source file, before resampling
+ smpl_t ratio = s->source_samplerate * 1. / s->samplerate;
+ SInt64 resampled_pos = (SInt64)ROUND( pos * ratio );
+ if (resampled_pos > fileLengthFrames) {
+ AUBIO_ERR("source_apple_audio: trying to seek in %s at pos %d, "
+ "but file has only %d frames\n",
+ s->path, pos, (uint_t)(fileLengthFrames / ratio));
+ err = -1;
+ goto beach;
+ }
+ // after a short read, the bufferList size needs to resetted to prepare for a full read
+ AudioBufferList *bufferList = &s->bufferList;
+ bufferList->mBuffers[0].mDataByteSize = s->block_size * s->channels * sizeof (short);
+ // do the actual seek
+ err = ExtAudioFileSeek(s->audioFile, resampled_pos);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: error while seeking %s at %d "
+ "in ExtAudioFileSeek (%s)\n", s->path, pos,
+ getPrintableOSStatusError(errorstr, err));
+ }
+#if 0
+ // check position after seek
+ {
+ SInt64 outFrameOffset = 0;
+ err = ExtAudioFileTell(s->audioFile, &outFrameOffset);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: error while seeking %s at %d "
+ "in ExtAudioFileTell (%s)\n", s->path, pos,
+ getPrintableOSStatusError(errorstr, err));
+ }
+ AUBIO_DBG("source_apple_audio: asked seek at %d, tell got %d\n",
+ pos, (uint_t)(outFrameOffset / ratio + .5));
+ }
+#endif
+beach:
+ return err;
+}
+
+uint_t aubio_source_apple_audio_get_samplerate(const aubio_source_apple_audio_t * s) {
+ return s->samplerate;
+}
+
+uint_t aubio_source_apple_audio_get_channels(const aubio_source_apple_audio_t * s) {
+ return s->channels;
+}
+
+uint_t aubio_source_apple_audio_get_duration(const aubio_source_apple_audio_t * s) {
+ SInt64 fileLengthFrames = 0;
+ UInt32 propSize = sizeof(fileLengthFrames);
+ OSStatus err = ExtAudioFileGetProperty(s->audioFile,
+ kExtAudioFileProperty_FileLengthFrames, &propSize, &fileLengthFrames);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERROR("source_apple_audio: Failed getting %s duration, "
+ "error in ExtAudioFileGetProperty (%s)\n", s->path,
+ getPrintableOSStatusError(errorstr, err));
+ return err;
+ }
+ return (uint_t)fileLengthFrames;
+}
+
+#endif /* HAVE_SOURCE_APPLE_AUDIO */
diff --git a/src/io/source_apple_audio.h b/src/io/source_apple_audio.h
new file mode 100644
index 0000000..0ad5569
--- /dev/null
+++ b/src/io/source_apple_audio.h
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SOURCE_APPLE_AUDIO_H
+#define AUBIO_SOURCE_APPLE_AUDIO_H
+
+/** \file
+
+ Read from file using CoreAudio Extended Audio File Services
+ [ExtAudioFileRef](https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_apple_audio.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** apple audio media source object */
+typedef struct _aubio_source_apple_audio_t aubio_source_apple_audio_t;
+
+/**
+
+ create new ::aubio_source_apple_audio_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_apple_audio_get_samplerate.
+
+*/
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_apple_audio_get_samplerate(const aubio_source_apple_audio_t * s);
+
+/**
+
+ get channels of source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return number of channels
+
+*/
+uint_t aubio_source_apple_audio_get_channels(const aubio_source_apple_audio_t * s);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return number of frames in file
+
+*/
+uint_t aubio_source_apple_audio_get_duration(const aubio_source_apple_audio_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_apple_audio_close(aubio_source_apple_audio_t * s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+
+*/
+void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_APPLE_AUDIO_H */
diff --git a/src/io/source_avcodec.c b/src/io/source_avcodec.c
new file mode 100644
index 0000000..a4cbf6d
--- /dev/null
+++ b/src/io/source_avcodec.c
@@ -0,0 +1,465 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+
+#ifdef HAVE_LIBAV
+
+// determine whether we use libavformat from ffmpeg or from libav
+#define FFMPEG_LIBAVFORMAT (LIBAVFORMAT_VERSION_MICRO > 99 )
+// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 through 57.2.100
+#define FFMPEG_LIBAVFORMAT_MAX_DUR2 FFMPEG_LIBAVFORMAT && ( \
+ (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 43) \
+ || (LIBAVFORMAT_VERSION_MAJOR == 56) \
+ || (LIBAVFORMAT_VERSION_MAJOR == 57 && LIBAVFORMAT_VERSION_MINOR < 2) \
+ )
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavresample/avresample.h>
+#include <libavutil/opt.h>
+#include <stdlib.h>
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "source_avcodec.h"
+
+#define AUBIO_AVCODEC_MAX_BUFFER_SIZE FF_MIN_BUFFER_SIZE
+
+struct _aubio_source_avcodec_t {
+ uint_t hop_size;
+ uint_t samplerate;
+ uint_t channels;
+
+ // some data about the file
+ char_t *path;
+ uint_t input_samplerate;
+ uint_t input_channels;
+
+ // avcodec stuff
+ AVFormatContext *avFormatCtx;
+ AVCodecContext *avCodecCtx;
+ AVFrame *avFrame;
+ AVAudioResampleContext *avr;
+ float *output;
+ uint_t read_samples;
+ uint_t read_index;
+ sint_t selected_stream;
+ uint_t eof;
+ uint_t multi;
+};
+
+// hack to create or re-create the context the first time _do or _do_multi is called
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi);
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples);
+
+uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s);
+
+uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s) {
+ char proto[20], authorization[256], hostname[128], uripath[256];
+ int proto_size = 20, authorization_size = 256, hostname_size = 128,
+ *port_ptr = 0, path_size = 256;
+ av_url_split(proto, proto_size, authorization, authorization_size, hostname,
+ hostname_size, port_ptr, uripath, path_size, s->path);
+ if (strlen(proto)) {
+ return 1;
+ }
+ return 0;
+}
+
+
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path, uint_t samplerate, uint_t hop_size) {
+ aubio_source_avcodec_t * s = AUBIO_NEW(aubio_source_avcodec_t);
+ int err;
+ if (path == NULL) {
+ AUBIO_ERR("source_avcodec: Aborted opening null path\n");
+ goto beach;
+ }
+ if ((sint_t)samplerate < 0) {
+ AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n", path, samplerate);
+ goto beach;
+ }
+ if ((sint_t)hop_size <= 0) {
+ AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n", path, hop_size);
+ goto beach;
+ }
+
+ s->hop_size = hop_size;
+ s->channels = 1;
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ // register all formats and codecs
+ av_register_all();
+
+ if (aubio_source_avcodec_has_network_url(s)) {
+ avformat_network_init();
+ }
+
+ // try opening the file and get some info about it
+ AVFormatContext *avFormatCtx = s->avFormatCtx;
+ avFormatCtx = NULL;
+ if ( (err = avformat_open_input(&avFormatCtx, s->path, NULL, NULL) ) < 0 ) {
+ char errorstr[256];
+ av_strerror (err, errorstr, sizeof(errorstr));
+ AUBIO_ERR("source_avcodec: Failed opening %s (%s)\n", s->path, errorstr);
+ goto beach;
+ }
+
+ // try to make sure max_analyze_duration is big enough for most songs
+#if FFMPEG_LIBAVFORMAT_MAX_DUR2
+ avFormatCtx->max_analyze_duration2 *= 100;
+#else
+ avFormatCtx->max_analyze_duration *= 100;
+#endif
+
+ // retrieve stream information
+ if ( (err = avformat_find_stream_info(avFormatCtx, NULL)) < 0 ) {
+ char errorstr[256];
+ av_strerror (err, errorstr, sizeof(errorstr));
+ AUBIO_ERR("source_avcodec: Could not find stream information " "for %s (%s)\n", s->path,
+ errorstr);
+ goto beach;
+ }
+
+ // dump information about file onto standard error
+ //av_dump_format(avFormatCtx, 0, s->path, 0);
+
+ // look for the first audio stream
+ uint_t i;
+ sint_t selected_stream = -1;
+ for (i = 0; i < avFormatCtx->nb_streams; i++) {
+ if (avFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (selected_stream == -1) {
+ selected_stream = i;
+ } else {
+ AUBIO_WRN("source_avcodec: More than one audio stream in %s, "
+ "taking the first one\n", s->path);
+ }
+ }
+ }
+ if (selected_stream == -1) {
+ AUBIO_ERR("source_avcodec: No audio stream in %s\n", s->path);
+ goto beach;
+ }
+ //AUBIO_DBG("Taking stream %d in file %s\n", selected_stream, s->path);
+ s->selected_stream = selected_stream;
+
+ AVCodecContext *avCodecCtx = s->avCodecCtx;
+ avCodecCtx = avFormatCtx->streams[selected_stream]->codec;
+ AVCodec *codec = avcodec_find_decoder(avCodecCtx->codec_id);
+ if (codec == NULL) {
+ AUBIO_ERR("source_avcodec: Could not find decoder for %s", s->path);
+ goto beach;
+ }
+
+ if ( ( err = avcodec_open2(avCodecCtx, codec, NULL) ) < 0) {
+ char errorstr[256];
+ av_strerror (err, errorstr, sizeof(errorstr));
+ AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path, errorstr);
+ goto beach;
+ }
+
+ /* get input specs */
+ s->input_samplerate = avCodecCtx->sample_rate;
+ s->input_channels = avCodecCtx->channels;
+ //AUBIO_DBG("input_samplerate: %d\n", s->input_samplerate);
+ //AUBIO_DBG("input_channels: %d\n", s->input_channels);
+
+ if (samplerate == 0) {
+ s->samplerate = s->input_samplerate;
+ } else {
+ s->samplerate = samplerate;
+ }
+
+ if (s->samplerate > s->input_samplerate) {
+ AUBIO_WRN("source_avcodec: upsampling %s from %d to %d\n", s->path,
+ s->input_samplerate, s->samplerate);
+ }
+
+ AVFrame *avFrame = s->avFrame;
+ avFrame = av_frame_alloc();
+ if (!avFrame) {
+ AUBIO_ERR("source_avcodec: Could not allocate frame for (%s)\n", s->path);
+ }
+
+ /* allocate output for avr */
+ s->output = (float *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE * sizeof(float));
+
+ s->read_samples = 0;
+ s->read_index = 0;
+
+ s->avFormatCtx = avFormatCtx;
+ s->avCodecCtx = avCodecCtx;
+ s->avFrame = avFrame;
+
+ // default to mono output
+ aubio_source_avcodec_reset_resampler(s, 0);
+
+ s->eof = 0;
+ s->multi = 0;
+
+ //av_log_set_level(AV_LOG_QUIET);
+
+ return s;
+
+beach:
+ //AUBIO_ERR("can not read %s at samplerate %dHz with a hop_size of %d\n",
+ // s->path, s->samplerate, s->hop_size);
+ del_aubio_source_avcodec(s);
+ return NULL;
+}
+
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi) {
+ if ( (multi != s->multi) || (s->avr == NULL) ) {
+ int64_t input_layout = av_get_default_channel_layout(s->input_channels);
+ uint_t output_channels = multi ? s->input_channels : 1;
+ int64_t output_layout = av_get_default_channel_layout(output_channels);
+ if (s->avr != NULL) {
+ avresample_close( s->avr );
+ av_free ( s->avr );
+ s->avr = NULL;
+ }
+ AVAudioResampleContext *avr = s->avr;
+ avr = avresample_alloc_context();
+
+ av_opt_set_int(avr, "in_channel_layout", input_layout, 0);
+ av_opt_set_int(avr, "out_channel_layout", output_layout, 0);
+ av_opt_set_int(avr, "in_sample_rate", s->input_samplerate, 0);
+ av_opt_set_int(avr, "out_sample_rate", s->samplerate, 0);
+ av_opt_set_int(avr, "in_sample_fmt", s->avCodecCtx->sample_fmt, 0);
+ av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
+ int err;
+ if ( ( err = avresample_open(avr) ) < 0) {
+ char errorstr[256];
+ av_strerror (err, errorstr, sizeof(errorstr));
+ AUBIO_ERR("source_avcodec: Could not open AVAudioResampleContext for %s (%s)\n",
+ s->path, errorstr);
+ //goto beach;
+ return;
+ }
+ s->avr = avr;
+ s->multi = multi;
+ }
+}
+
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples) {
+ AVFormatContext *avFormatCtx = s->avFormatCtx;
+ AVCodecContext *avCodecCtx = s->avCodecCtx;
+ AVFrame *avFrame = s->avFrame;
+ AVPacket avPacket;
+ av_init_packet (&avPacket);
+ AVAudioResampleContext *avr = s->avr;
+ float *output = s->output;
+ *read_samples = 0;
+
+ do
+ {
+ int err = av_read_frame (avFormatCtx, &avPacket);
+ if (err == AVERROR_EOF) {
+ s->eof = 1;
+ goto beach;
+ }
+ if (err != 0) {
+ char errorstr[256];
+ av_strerror (err, errorstr, sizeof(errorstr));
+ AUBIO_ERR("Could not read frame in %s (%s)\n", s->path, errorstr);
+ goto beach;
+ }
+ } while (avPacket.stream_index != s->selected_stream);
+
+ int got_frame = 0;
+ int len = avcodec_decode_audio4(avCodecCtx, avFrame, &got_frame, &avPacket);
+
+ if (len < 0) {
+ AUBIO_ERR("Error while decoding %s\n", s->path);
+ goto beach;
+ }
+ if (got_frame == 0) {
+ //AUBIO_ERR("Could not get frame for (%s)\n", s->path);
+ goto beach;
+ }
+
+ int in_linesize = 0;
+ av_samples_get_buffer_size(&in_linesize, avCodecCtx->channels,
+ avFrame->nb_samples, avCodecCtx->sample_fmt, 1);
+ int in_samples = avFrame->nb_samples;
+ int out_linesize = 0;
+ int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
+ int out_samples = avresample_convert ( avr,
+ (uint8_t **)&output, out_linesize, max_out_samples,
+ (uint8_t **)avFrame->data, in_linesize, in_samples);
+ if (out_samples <= 0) {
+ //AUBIO_ERR("No sample found while converting frame (%s)\n", s->path);
+ goto beach;
+ }
+
+ *read_samples = out_samples;
+
+beach:
+ s->avFormatCtx = avFormatCtx;
+ s->avCodecCtx = avCodecCtx;
+ s->avFrame = avFrame;
+ s->avr = avr;
+ s->output = output;
+
+ av_packet_unref(&avPacket);
+}
+
+void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data, uint_t * read){
+ if (s->multi == 1) aubio_source_avcodec_reset_resampler(s, 0);
+ uint_t i;
+ uint_t end = 0;
+ uint_t total_wrote = 0;
+ while (total_wrote < s->hop_size) {
+ end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ for (i = 0; i < end; i++) {
+ read_data->data[i + total_wrote] = s->output[i + s->read_index];
+ }
+ total_wrote += end;
+ if (total_wrote < s->hop_size) {
+ uint_t avcodec_read = 0;
+ aubio_source_avcodec_readframe(s, &avcodec_read);
+ s->read_samples = avcodec_read;
+ s->read_index = 0;
+ if (s->eof) {
+ break;
+ }
+ } else {
+ s->read_index += end;
+ }
+ }
+ if (total_wrote < s->hop_size) {
+ for (i = end; i < s->hop_size; i++) {
+ read_data->data[i] = 0.;
+ }
+ }
+ *read = total_wrote;
+}
+
+void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s, fmat_t * read_data, uint_t * read){
+ if (s->multi == 0) aubio_source_avcodec_reset_resampler(s, 1);
+ uint_t i,j;
+ uint_t end = 0;
+ uint_t total_wrote = 0;
+ while (total_wrote < s->hop_size) {
+ end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ for (j = 0; j < read_data->height; j++) {
+ for (i = 0; i < end; i++) {
+ read_data->data[j][i + total_wrote] =
+ s->output[(i + s->read_index) * s->input_channels + j];
+ }
+ }
+ total_wrote += end;
+ if (total_wrote < s->hop_size) {
+ uint_t avcodec_read = 0;
+ aubio_source_avcodec_readframe(s, &avcodec_read);
+ s->read_samples = avcodec_read;
+ s->read_index = 0;
+ if (s->eof) {
+ break;
+ }
+ } else {
+ s->read_index += end;
+ }
+ }
+ if (total_wrote < s->hop_size) {
+ for (j = 0; j < read_data->height; j++) {
+ for (i = end; i < s->hop_size; i++) {
+ read_data->data[j][i] = 0.;
+ }
+ }
+ }
+ *read = total_wrote;
+}
+
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s) {
+ return s->samplerate;
+}
+
+uint_t aubio_source_avcodec_get_channels(const aubio_source_avcodec_t * s) {
+ return s->input_channels;
+}
+
+uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t * s, uint_t pos) {
+ int64_t resampled_pos = (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
+ int64_t min_ts = MAX(resampled_pos - 2000, 0);
+ int64_t max_ts = MIN(resampled_pos + 2000, INT64_MAX);
+ int seek_flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY;
+ int ret = avformat_seek_file(s->avFormatCtx, s->selected_stream,
+ min_ts, resampled_pos, max_ts, seek_flags);
+ if (ret < 0) {
+ AUBIO_ERR("Failed seeking to %d in file %s", pos, s->path);
+ }
+ // reset read status
+ s->eof = 0;
+ s->read_index = 0;
+ s->read_samples = 0;
+ // reset the AVAudioResampleContext
+ avresample_close(s->avr);
+ avresample_open(s->avr);
+ return ret;
+}
+
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s) {
+ if (s && &(s->avFormatCtx) != NULL) {
+ int64_t duration = s->avFormatCtx->duration;
+ return s->samplerate * ((uint_t)duration / 1e6 );
+ }
+ return 0;
+}
+
+uint_t aubio_source_avcodec_close(aubio_source_avcodec_t * s) {
+ if (s->avr != NULL) {
+ avresample_close( s->avr );
+ av_free ( s->avr );
+ }
+ s->avr = NULL;
+ if (s->avCodecCtx != NULL) {
+ avcodec_close ( s->avCodecCtx );
+ }
+ s->avCodecCtx = NULL;
+ if (s->avFormatCtx != NULL) {
+ avformat_close_input ( &(s->avFormatCtx) );
+ }
+ s->avFormatCtx = NULL;
+ return AUBIO_OK;
+}
+
+void del_aubio_source_avcodec(aubio_source_avcodec_t * s){
+ if (!s) return;
+ aubio_source_avcodec_close(s);
+ if (s->output != NULL) {
+ av_free(s->output);
+ }
+ s->output = NULL;
+ if (s->avFrame != NULL) {
+ av_frame_free( &(s->avFrame) );
+ }
+ if (s->path) AUBIO_FREE(s->path);
+ s->avFrame = NULL;
+ AUBIO_FREE(s);
+}
+
+#endif /* HAVE_LIBAV */
diff --git a/src/io/source_avcodec.h b/src/io/source_avcodec.h
new file mode 100644
index 0000000..81f657d
--- /dev/null
+++ b/src/io/source_avcodec.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SOURCE_AVCODEC_H
+#define AUBIO_SOURCE_AVCODEC_H
+
+/** \file
+
+ Read from file using [libavcodec](http://libav.org/)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_avcodec.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** avcodec media source object */
+typedef struct _aubio_source_avcodec_t aubio_source_avcodec_t;
+
+/**
+
+ create new ::aubio_source_avcodec_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_avcodec_get_samplerate.
+
+*/
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param read_to ::fvec_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return number of channels
+
+*/
+uint_t aubio_source_avcodec_get_channels (const aubio_source_avcodec_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return number of frames in file
+
+*/
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_avcodec
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_avcodec_close (aubio_source_avcodec_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_avcodec
+
+*/
+void del_aubio_source_avcodec(aubio_source_avcodec_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_AVCODEC_H */
diff --git a/src/io/source_sndfile.c b/src/io/source_sndfile.c
new file mode 100644
index 0000000..5c8d5a5
--- /dev/null
+++ b/src/io/source_sndfile.c
@@ -0,0 +1,327 @@
+/*
+ Copyright (C) 2012 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+
+#ifdef HAVE_SNDFILE
+
+#include <sndfile.h>
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "source_sndfile.h"
+
+#include "temporal/resampler.h"
+
+#define MAX_CHANNELS 6
+#define MAX_SIZE 4096
+#define MAX_SAMPLES MAX_CHANNELS * MAX_SIZE
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_sf_read_smpl sf_read_float
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_sf_read_smpl sf_read_double
+#endif /* HAVE_AUBIO_DOUBLE */
+
+struct _aubio_source_sndfile_t {
+ uint_t hop_size;
+ uint_t samplerate;
+ uint_t channels;
+
+ // some data about the file
+ char_t *path;
+ SNDFILE *handle;
+ int input_samplerate;
+ int input_channels;
+ int input_format;
+ int duration;
+
+ // resampling stuff
+ smpl_t ratio;
+ uint_t input_hop_size;
+#ifdef HAVE_SAMPLERATE
+ aubio_resampler_t *resampler;
+ fvec_t *input_data;
+#endif /* HAVE_SAMPLERATE */
+
+ // some temporary memory for sndfile to write at
+ uint_t scratch_size;
+ smpl_t *scratch_data;
+};
+
+aubio_source_sndfile_t * new_aubio_source_sndfile(const char_t * path, uint_t samplerate, uint_t hop_size) {
+ aubio_source_sndfile_t * s = AUBIO_NEW(aubio_source_sndfile_t);
+ SF_INFO sfinfo;
+
+ if (path == NULL) {
+ AUBIO_ERR("source_sndfile: Aborted opening null path\n");
+ goto beach;
+ }
+ if ((sint_t)samplerate < 0) {
+ AUBIO_ERR("source_sndfile: Can not open %s with samplerate %d\n", path, samplerate);
+ goto beach;
+ }
+ if ((sint_t)hop_size <= 0) {
+ AUBIO_ERR("source_sndfile: Can not open %s with hop_size %d\n", path, hop_size);
+ goto beach;
+ }
+
+ s->hop_size = hop_size;
+ s->channels = 1;
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ // try opening the file, getting the info in sfinfo
+ AUBIO_MEMSET(&sfinfo, 0, sizeof (sfinfo));
+ s->handle = sf_open (s->path, SFM_READ, &sfinfo);
+
+ if (s->handle == NULL) {
+ /* show libsndfile err msg */
+ AUBIO_ERR("source_sndfile: Failed opening %s: %s\n", s->path, sf_strerror (NULL));
+ goto beach;
+ }
+
+ /* get input specs */
+ s->input_samplerate = sfinfo.samplerate;
+ s->input_channels = sfinfo.channels;
+ s->input_format = sfinfo.format;
+ s->duration = sfinfo.frames;
+
+ if (samplerate == 0) {
+ s->samplerate = s->input_samplerate;
+ //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
+ } else {
+ s->samplerate = samplerate;
+ }
+ /* compute input block size required before resampling */
+ s->ratio = s->samplerate/(smpl_t)s->input_samplerate;
+ s->input_hop_size = (uint_t)FLOOR(s->hop_size / s->ratio + .5);
+
+ if (s->input_hop_size * s->input_channels > MAX_SAMPLES) {
+ AUBIO_ERR("source_sndfile: Not able to process more than %d frames of %d channels\n",
+ MAX_SAMPLES / s->input_channels, s->input_channels);
+ goto beach;
+ }
+
+#ifdef HAVE_SAMPLERATE
+ s->resampler = NULL;
+ s->input_data = NULL;
+ if (s->ratio != 1) {
+ s->input_data = new_fvec(s->input_hop_size);
+ s->resampler = new_aubio_resampler(s->ratio, 4);
+ if (s->ratio > 1) {
+ // we would need to add a ring buffer for these
+ if ( (uint_t)(s->input_hop_size * s->ratio + .5) != s->hop_size ) {
+ AUBIO_ERR("source_sndfile: can not upsample %s from %d to %d\n", s->path,
+ s->input_samplerate, s->samplerate);
+ goto beach;
+ }
+ AUBIO_WRN("source_sndfile: upsampling %s from %d to %d\n", s->path,
+ s->input_samplerate, s->samplerate);
+ }
+ s->duration = (uint_t)FLOOR(s->duration * s->ratio);
+ }
+#else
+ if (s->ratio != 1) {
+ AUBIO_ERR("source_sndfile: aubio was compiled without aubio_resampler\n");
+ goto beach;
+ }
+#endif /* HAVE_SAMPLERATE */
+
+ /* allocate data for de/interleaving reallocated when needed. */
+ s->scratch_size = s->input_hop_size * s->input_channels;
+ s->scratch_data = AUBIO_ARRAY(smpl_t, s->scratch_size);
+
+ return s;
+
+beach:
+ //AUBIO_ERR("can not read %s at samplerate %dHz with a hop_size of %d\n",
+ // s->path, s->samplerate, s->hop_size);
+ del_aubio_source_sndfile(s);
+ return NULL;
+}
+
+void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uint_t * read){
+ uint_t i,j, input_channels = s->input_channels;
+ /* read from file into scratch_data */
+ sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
+
+ /* where to store de-interleaved data */
+ smpl_t *ptr_data;
+#ifdef HAVE_SAMPLERATE
+ if (s->ratio != 1) {
+ ptr_data = s->input_data->data;
+ } else
+#endif /* HAVE_SAMPLERATE */
+ {
+ ptr_data = read_data->data;
+ }
+
+ /* de-interleaving and down-mixing data */
+ for (j = 0; j < read_samples / input_channels; j++) {
+ ptr_data[j] = 0;
+ for (i = 0; i < input_channels; i++) {
+ ptr_data[j] += s->scratch_data[input_channels*j+i];
+ }
+ ptr_data[j] /= (smpl_t)input_channels;
+ }
+
+#ifdef HAVE_SAMPLERATE
+ if (s->resampler) {
+ aubio_resampler_do(s->resampler, s->input_data, read_data);
+ }
+#endif /* HAVE_SAMPLERATE */
+
+ *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
+
+ if (*read < s->hop_size) {
+ for (j = *read; j < s->hop_size; j++) {
+ read_data->data[j] = 0;
+ }
+ }
+
+}
+
+void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_data, uint_t * read){
+ uint_t i,j, input_channels = s->input_channels;
+ /* do actual reading */
+ sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
+
+ /* where to store de-interleaved data */
+ smpl_t **ptr_data;
+#ifdef HAVE_SAMPLERATE
+ if (s->ratio != 1) {
+ AUBIO_ERR("source_sndfile: no multi channel resampling yet\n");
+ return;
+ //ptr_data = s->input_data->data;
+ } else
+#endif /* HAVE_SAMPLERATE */
+ {
+ ptr_data = read_data->data;
+ }
+
+ if (read_data->height < input_channels) {
+ // destination matrix has less channels than the file; copy only first
+ // channels of the file, de-interleaving data
+ for (j = 0; j < read_samples / input_channels; j++) {
+ for (i = 0; i < read_data->height; i++) {
+ ptr_data[i][j] = s->scratch_data[j * input_channels + i];
+ }
+ }
+ } else {
+ // destination matrix has as many or more channels than the file; copy each
+ // channel from the file to the destination matrix, de-interleaving data
+ for (j = 0; j < read_samples / input_channels; j++) {
+ for (i = 0; i < input_channels; i++) {
+ ptr_data[i][j] = s->scratch_data[j * input_channels + i];
+ }
+ }
+ }
+
+ if (read_data->height > input_channels) {
+ // destination matrix has more channels than the file; copy last channel
+ // of the file to each additional channels, de-interleaving data
+ for (j = 0; j < read_samples / input_channels; j++) {
+ for (i = input_channels; i < read_data->height; i++) {
+ ptr_data[i][j] = s->scratch_data[j * input_channels + (input_channels - 1)];
+ }
+ }
+ }
+
+#ifdef HAVE_SAMPLERATE
+ if (s->resampler) {
+ //aubio_resampler_do(s->resampler, s->input_data, read_data);
+ }
+#endif /* HAVE_SAMPLERATE */
+
+ *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
+
+ if (*read < s->hop_size) {
+ for (i = 0; i < read_data->height; i++) {
+ for (j = *read; j < s->hop_size; j++) {
+ read_data->data[i][j] = 0.;
+ }
+ }
+ }
+
+}
+
+uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s) {
+ return s->samplerate;
+}
+
+uint_t aubio_source_sndfile_get_channels(aubio_source_sndfile_t * s) {
+ return s->input_channels;
+}
+
+uint_t aubio_source_sndfile_get_duration (const aubio_source_sndfile_t * s) {
+ if (s && s->duration) {
+ return s->duration;
+ }
+ return 0;
+}
+
+uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t * s, uint_t pos) {
+ uint_t resampled_pos = (uint_t)ROUND(pos / s->ratio);
+ sf_count_t sf_ret = sf_seek (s->handle, resampled_pos, SEEK_SET);
+ if (sf_ret == -1) {
+ AUBIO_ERR("source_sndfile: Failed seeking %s at %d: %s\n", s->path, pos, sf_strerror (NULL));
+ return AUBIO_FAIL;
+ }
+ if (sf_ret != resampled_pos) {
+ AUBIO_ERR("source_sndfile: Tried seeking %s at %d, but got %d: %s\n",
+ s->path, resampled_pos, (uint_t)sf_ret, sf_strerror (NULL));
+ return AUBIO_FAIL;
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_source_sndfile_close (aubio_source_sndfile_t *s) {
+ if (!s->handle) {
+ return AUBIO_FAIL;
+ }
+ if(sf_close(s->handle)) {
+ AUBIO_ERR("source_sndfile: Error closing file %s: %s\n", s->path, sf_strerror (NULL));
+ return AUBIO_FAIL;
+ }
+ return AUBIO_OK;
+}
+
+void del_aubio_source_sndfile(aubio_source_sndfile_t * s){
+ if (!s) return;
+ aubio_source_sndfile_close(s);
+#ifdef HAVE_SAMPLERATE
+ if (s->resampler != NULL) {
+ del_aubio_resampler(s->resampler);
+ }
+ if (s->input_data) {
+ del_fvec(s->input_data);
+ }
+#endif /* HAVE_SAMPLERATE */
+ if (s->path) AUBIO_FREE(s->path);
+ AUBIO_FREE(s->scratch_data);
+ AUBIO_FREE(s);
+}
+
+#endif /* HAVE_SNDFILE */
diff --git a/src/io/source_sndfile.h b/src/io/source_sndfile.h
new file mode 100644
index 0000000..210a40d
--- /dev/null
+++ b/src/io/source_sndfile.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SOURCE_SNDFILE_H
+#define AUBIO_SOURCE_SNDFILE_H
+
+/** \file
+
+ Read from file using [libsndfile](http://www.mega-nerd.com/libsndfile/)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_sndfile.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sndfile media source object */
+typedef struct _aubio_source_sndfile_t aubio_source_sndfile_t;
+
+/**
+
+ create new ::aubio_source_sndfile_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_sndfile_get_samplerate.
+
+*/
+aubio_source_sndfile_t * new_aubio_source_sndfile(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of channels
+
+*/
+uint_t aubio_source_sndfile_get_channels (aubio_source_sndfile_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of frames in file
+
+*/
+uint_t aubio_source_sndfile_get_duration (const aubio_source_sndfile_t *s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_sndfile
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_sndfile_close (aubio_source_sndfile_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_sndfile
+
+*/
+void del_aubio_source_sndfile(aubio_source_sndfile_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_SNDFILE_H */
diff --git a/src/io/source_wavread.c b/src/io/source_wavread.c
new file mode 100644
index 0000000..d1b1f3a
--- /dev/null
+++ b/src/io/source_wavread.c
@@ -0,0 +1,411 @@
+/*
+ Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_WAVREAD
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "source_wavread.h"
+
+#include <errno.h>
+
+#define AUBIO_WAVREAD_BUFSIZE 1024
+
+#define SHORT_TO_FLOAT(x) (smpl_t)(x * 3.0517578125e-05)
+
+struct _aubio_source_wavread_t {
+ uint_t hop_size;
+ uint_t samplerate;
+ uint_t channels;
+
+ // some data about the file
+ char_t *path;
+ uint_t input_samplerate;
+ uint_t input_channels;
+
+ // internal stuff
+ FILE *fid;
+
+ uint_t read_samples;
+ uint_t blockalign;
+ uint_t bitspersample;
+ uint_t read_index;
+ uint_t eof;
+
+ uint_t duration;
+
+ size_t seek_start;
+
+ unsigned char *short_output;
+ fmat_t *output;
+};
+
+unsigned int read_little_endian (unsigned char *buf, unsigned int length);
+unsigned int read_little_endian (unsigned char *buf, unsigned int length) {
+ uint_t i, ret = 0;
+ for (i = 0; i < length; i++) {
+ ret += buf[i] << (i * 8);
+ }
+ return ret;
+}
+
+aubio_source_wavread_t * new_aubio_source_wavread(const char_t * path, uint_t samplerate, uint_t hop_size) {
+ aubio_source_wavread_t * s = AUBIO_NEW(aubio_source_wavread_t);
+ size_t bytes_read = 0, bytes_expected = 44;
+ unsigned char buf[5];
+ unsigned int format, channels, sr, byterate, blockalign, duration, bitspersample;//, data_size;
+
+ if (path == NULL) {
+ AUBIO_ERR("source_wavread: Aborted opening null path\n");
+ goto beach;
+ }
+ if ((sint_t)samplerate < 0) {
+ AUBIO_ERR("source_wavread: Can not open %s with samplerate %d\n", path, samplerate);
+ goto beach;
+ }
+ if ((sint_t)hop_size <= 0) {
+ AUBIO_ERR("source_wavread: Can not open %s with hop_size %d\n", path, hop_size);
+ goto beach;
+ }
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
+
+ s->samplerate = samplerate;
+ s->hop_size = hop_size;
+
+ s->fid = fopen((const char *)path, "rb");
+ if (!s->fid) {
+ AUBIO_ERR("source_wavread: Failed opening %s (System error: %s)\n", s->path, strerror(errno));
+ goto beach;
+ }
+
+ // ChunkID
+ bytes_read += fread(buf, 1, 4, s->fid);
+ buf[4] = '\0';
+ if ( strcmp((const char *)buf, "RIFF") != 0 ) {
+ AUBIO_ERR("source_wavread: could not find RIFF header in %s\n", s->path);
+ goto beach;
+ }
+
+ // ChunkSize
+ bytes_read += fread(buf, 1, 4, s->fid);
+
+ // Format
+ bytes_read += fread(buf, 1, 4, s->fid);
+ buf[4] = '\0';
+ if ( strcmp((const char *)buf, "WAVE") != 0 ) {
+ AUBIO_ERR("source_wavread: wrong format in RIFF header in %s\n", s->path);
+ goto beach;
+ }
+
+ // Subchunk1ID
+ bytes_read += fread(buf, 1, 4, s->fid);
+ buf[4] = '\0';
+ if ( strcmp((const char *)buf, "fmt ") != 0 ) {
+ AUBIO_ERR("source_wavread: fmt RIFF header in %s\n", s->path);
+ goto beach;
+ }
+
+ // Subchunk1Size
+ bytes_read += fread(buf, 1, 4, s->fid);
+ format = read_little_endian(buf, 4);
+ if ( format != 16 ) {
+ // TODO accept format 18
+ AUBIO_ERR("source_wavread: file %s is not encoded with PCM\n", s->path);
+ goto beach;
+ }
+ if ( buf[1] || buf[2] | buf[3] ) {
+ AUBIO_ERR("source_wavread: Subchunk1Size should be 0, in %s\n", s->path);
+ goto beach;
+ }
+
+ // AudioFormat
+ bytes_read += fread(buf, 1, 2, s->fid);
+ if ( buf[0] != 1 || buf[1] != 0) {
+ AUBIO_ERR("source_wavread: AudioFormat should be PCM, in %s\n", s->path);
+ goto beach;
+ }
+
+ // NumChannels
+ bytes_read += fread(buf, 1, 2, s->fid);
+ channels = read_little_endian(buf, 2);
+
+ // SampleRate
+ bytes_read += fread(buf, 1, 4, s->fid);
+ sr = read_little_endian(buf, 4);
+
+ // ByteRate
+ bytes_read += fread(buf, 1, 4, s->fid);
+ byterate = read_little_endian(buf, 4);
+
+ // BlockAlign
+ bytes_read += fread(buf, 1, 2, s->fid);
+ blockalign = read_little_endian(buf, 2);
+
+ // BitsPerSample
+ bytes_read += fread(buf, 1, 2, s->fid);
+ bitspersample = read_little_endian(buf, 2);
+#if 0
+ if ( bitspersample != 16 ) {
+ AUBIO_ERR("source_wavread: can not process %dbit file %s\n",
+ bitspersample, s->path);
+ goto beach;
+ }
+#endif
+
+ if ( byterate * 8 != sr * channels * bitspersample ) {
+ AUBIO_ERR("source_wavread: wrong byterate in %s\n", s->path);
+ goto beach;
+ }
+
+ if ( blockalign * 8 != channels * bitspersample ) {
+ AUBIO_ERR("source_wavread: wrong blockalign in %s\n", s->path);
+ goto beach;
+ }
+
+ s->input_samplerate = sr;
+ s->input_channels = channels;
+
+#if 0
+ AUBIO_DBG("channels %d\n", channels);
+ AUBIO_DBG("sr %d\n", sr);
+ AUBIO_DBG("byterate %d\n", byterate);
+ AUBIO_DBG("blockalign %d\n", blockalign);
+ AUBIO_DBG("bitspersample %d\n", bitspersample);
+
+ AUBIO_DBG("found %d channels in %s\n", s->input_channels, s->path);
+ AUBIO_DBG("found %d samplerate in %s\n", s->input_samplerate, s->path);
+#endif
+
+ if (samplerate == 0) {
+ s->samplerate = s->input_samplerate;
+ } else if (samplerate != s->input_samplerate) {
+ AUBIO_ERR("source_wavread: can not resample %s from %d to %dHz\n",
+ s->path, s->input_samplerate, samplerate);
+ goto beach;
+ }
+
+ // Subchunk2ID
+ bytes_read += fread(buf, 1, 4, s->fid);
+ buf[4] = '\0';
+ if ( strcmp((const char *)buf, "data") != 0 ) {
+ AUBIO_ERR("source_wavread: data RIFF header not found in %s\n", s->path);
+ goto beach;
+ }
+
+ // Subchunk2Size
+ bytes_read += fread(buf, 1, 4, s->fid);
+ duration = read_little_endian(buf, 4) / blockalign;
+
+ //data_size = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+ //AUBIO_MSG("found %d frames in %s\n", 8 * data_size / bitspersample / channels, s->path);
+
+ // check the total number of bytes read is correct
+ if ( bytes_read != bytes_expected ) {
+#ifndef HAVE_WIN_HACKS
+ AUBIO_ERR("source_wavread: short read (%zd instead of %zd) in %s\n",
+ bytes_read, bytes_expected, s->path);
+#else // mingw does not know about %zd...
+ AUBIO_ERR("source_wavread: short read (%d instead of %d) in %s\n",
+ (int)bytes_read, (int)bytes_expected, s->path);
+#endif
+ goto beach;
+ }
+ s->seek_start = bytes_read;
+
+ s->output = new_fmat(s->input_channels, AUBIO_WAVREAD_BUFSIZE);
+ s->blockalign= blockalign;
+ s->bitspersample = bitspersample;
+
+ s->duration = duration;
+
+ s->short_output = (unsigned char *)calloc(s->blockalign, AUBIO_WAVREAD_BUFSIZE);
+ s->read_index = 0;
+ s->read_samples = 0;
+ s->eof = 0;
+
+ return s;
+
+beach:
+ //AUBIO_ERR("source_wavread: can not read %s at samplerate %dHz with a hop_size of %d\n",
+ // s->path, s->samplerate, s->hop_size);
+ del_aubio_source_wavread(s);
+ return NULL;
+}
+
+void aubio_source_wavread_readframe(aubio_source_wavread_t *s, uint_t *wavread_read);
+
+void aubio_source_wavread_readframe(aubio_source_wavread_t *s, uint_t *wavread_read) {
+ unsigned char *short_ptr = s->short_output;
+ size_t read = fread(short_ptr, s->blockalign, AUBIO_WAVREAD_BUFSIZE, s->fid);
+ uint_t i, j, b, bitspersample = s->bitspersample;
+ uint_t wrap_at = (1 << ( bitspersample - 1 ) );
+ uint_t wrap_with = (1 << bitspersample);
+ smpl_t scaler = 1. / wrap_at;
+ int signed_val = 0;
+ unsigned int unsigned_val = 0;
+
+ for (j = 0; j < read; j++) {
+ for (i = 0; i < s->input_channels; i++) {
+ unsigned_val = 0;
+ for (b = 0; b < bitspersample; b+=8 ) {
+ unsigned_val += *(short_ptr) << b;
+ short_ptr++;
+ }
+ signed_val = unsigned_val;
+ // FIXME why does 8 bit conversion maps [0;255] to [-128;127]
+ // instead of [0;127] to [0;127] and [128;255] to [-128;-1]
+ if (bitspersample == 8) signed_val -= wrap_at;
+ else if (unsigned_val >= wrap_at) signed_val = unsigned_val - wrap_with;
+ s->output->data[i][j] = signed_val * scaler;
+ }
+ }
+
+ *wavread_read = read;
+
+ if (read == 0) s->eof = 1;
+}
+
+void aubio_source_wavread_do(aubio_source_wavread_t * s, fvec_t * read_data, uint_t * read){
+ uint_t i, j;
+ uint_t end = 0;
+ uint_t total_wrote = 0;
+ while (total_wrote < s->hop_size) {
+ end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ for (i = 0; i < end; i++) {
+ read_data->data[i + total_wrote] = 0;
+ for (j = 0; j < s->input_channels; j++ ) {
+ read_data->data[i + total_wrote] += s->output->data[j][i + s->read_index];
+ }
+ read_data->data[i + total_wrote] /= (smpl_t)(s->input_channels);
+ }
+ total_wrote += end;
+ if (total_wrote < s->hop_size) {
+ uint_t wavread_read = 0;
+ aubio_source_wavread_readframe(s, &wavread_read);
+ s->read_samples = wavread_read;
+ s->read_index = 0;
+ if (s->eof) {
+ break;
+ }
+ } else {
+ s->read_index += end;
+ }
+ }
+ if (total_wrote < s->hop_size) {
+ for (i = end; i < s->hop_size; i++) {
+ read_data->data[i] = 0.;
+ }
+ }
+ *read = total_wrote;
+}
+
+void aubio_source_wavread_do_multi(aubio_source_wavread_t * s, fmat_t * read_data, uint_t * read){
+ uint_t i,j;
+ uint_t end = 0;
+ uint_t total_wrote = 0;
+ while (total_wrote < s->hop_size) {
+ end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ for (j = 0; j < read_data->height; j++) {
+ for (i = 0; i < end; i++) {
+ read_data->data[j][i + total_wrote] = s->output->data[j][i];
+ }
+ }
+ total_wrote += end;
+ if (total_wrote < s->hop_size) {
+ uint_t wavread_read = 0;
+ aubio_source_wavread_readframe(s, &wavread_read);
+ s->read_samples = wavread_read;
+ s->read_index = 0;
+ if (s->eof) {
+ break;
+ }
+ } else {
+ s->read_index += end;
+ }
+ }
+ if (total_wrote < s->hop_size) {
+ for (j = 0; j < read_data->height; j++) {
+ for (i = end; i < s->hop_size; i++) {
+ read_data->data[j][i] = 0.;
+ }
+ }
+ }
+ *read = total_wrote;
+}
+
+uint_t aubio_source_wavread_get_samplerate(aubio_source_wavread_t * s) {
+ return s->samplerate;
+}
+
+uint_t aubio_source_wavread_get_channels(aubio_source_wavread_t * s) {
+ return s->input_channels;
+}
+
+uint_t aubio_source_wavread_seek (aubio_source_wavread_t * s, uint_t pos) {
+ uint_t ret = 0;
+ if ((sint_t)pos < 0) {
+ return AUBIO_FAIL;
+ }
+ ret = fseek(s->fid, s->seek_start + pos * s->blockalign, SEEK_SET);
+ if (ret != 0) {
+ AUBIO_ERR("source_wavread: could not seek %s at %d (%s)\n", s->path, pos, strerror(errno));
+ return AUBIO_FAIL;
+ }
+ // reset some values
+ s->eof = 0;
+ s->read_index = 0;
+ return AUBIO_OK;
+}
+
+uint_t aubio_source_wavread_get_duration (const aubio_source_wavread_t * s) {
+ if (s && s->duration) {
+ return s->duration;
+ }
+ return 0;
+}
+
+uint_t aubio_source_wavread_close (aubio_source_wavread_t * s) {
+ if (!s->fid) {
+ return AUBIO_FAIL;
+ }
+ if (fclose(s->fid)) {
+ AUBIO_ERR("source_wavread: could not close %s (%s)\n", s->path, strerror(errno));
+ return AUBIO_FAIL;
+ }
+ s->fid = NULL;
+ return AUBIO_OK;
+}
+
+void del_aubio_source_wavread(aubio_source_wavread_t * s) {
+ if (!s) return;
+ aubio_source_wavread_close(s);
+ if (s->short_output) AUBIO_FREE(s->short_output);
+ if (s->output) del_fmat(s->output);
+ if (s->path) AUBIO_FREE(s->path);
+ AUBIO_FREE(s);
+}
+
+#endif /* HAVE_WAVREAD */
diff --git a/src/io/source_wavread.h b/src/io/source_wavread.h
new file mode 100644
index 0000000..65f752f
--- /dev/null
+++ b/src/io/source_wavread.h
@@ -0,0 +1,160 @@
+/*
+ Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SOURCE_WAVREAD_H
+#define AUBIO_SOURCE_WAVREAD_H
+
+/** \file
+
+ Read from file using custom wav reading routines.
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ References:
+
+ - http://netghost.narod.ru/gff/graphics/summary/micriff.htm
+ - https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+
+ \example io/test-source_wavread.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** wavread media source object */
+typedef struct _aubio_source_wavread_t aubio_source_wavread_t;
+
+/**
+
+ create new ::aubio_source_wavread_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_wavread_get_samplerate.
+
+*/
+aubio_source_wavread_t * new_aubio_source_wavread(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param read_to ::fvec_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_wavread_do(aubio_source_wavread_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_wavread_do_multi(aubio_source_wavread_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_wavread_get_samplerate(aubio_source_wavread_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \return number of channels
+
+*/
+uint_t aubio_source_wavread_get_channels (aubio_source_wavread_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_wavread_seek (aubio_source_wavread_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of frames in file
+
+*/
+uint_t aubio_source_wavread_get_duration (const aubio_source_wavread_t *s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_wavread
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_wavread_close (aubio_source_wavread_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_wavread
+
+*/
+void del_aubio_source_wavread(aubio_source_wavread_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_WAVREAD_H */
diff --git a/src/io/utils_apple_audio.c b/src/io/utils_apple_audio.c
new file mode 100644
index 0000000..2e651d5
--- /dev/null
+++ b/src/io/utils_apple_audio.c
@@ -0,0 +1,59 @@
+#include "config.h"
+
+#if defined(HAVE_SOURCE_APPLE_AUDIO) || defined(HAVE_SINK_APPLE_AUDIO)
+
+// CFURLRef, CFURLCreateWithFileSystemPath, ...
+#include <CoreFoundation/CoreFoundation.h>
+// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
+#include <AudioToolbox/AudioToolbox.h>
+#include "aubio_priv.h"
+
+int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize);
+void freeAudioBufferList(AudioBufferList *bufferList);
+CFURLRef getURLFromPath(const char * path);
+char_t *getPrintableOSStatusError(char_t *str, OSStatus error);
+
+int createAubioBufferList(AudioBufferList * bufferList, int channels, int max_source_samples) {
+ bufferList->mNumberBuffers = 1;
+ bufferList->mBuffers[0].mNumberChannels = channels;
+ bufferList->mBuffers[0].mData = AUBIO_ARRAY(short, max_source_samples);
+ bufferList->mBuffers[0].mDataByteSize = max_source_samples * sizeof(short);
+ return 0;
+}
+
+void freeAudioBufferList(AudioBufferList *bufferList) {
+ UInt32 i = 0;
+ if (!bufferList) return;
+ for (i = 0; i < bufferList->mNumberBuffers; i++) {
+ if (bufferList->mBuffers[i].mData) {
+ AUBIO_FREE(bufferList->mBuffers[i].mData);
+ bufferList->mBuffers[i].mData = NULL;
+ }
+ }
+ bufferList = NULL;
+}
+
+CFURLRef createURLFromPath(const char * path) {
+ CFStringRef cfTotalPath = CFStringCreateWithCString (kCFAllocatorDefault,
+ path, kCFStringEncodingUTF8);
+
+ CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfTotalPath,
+ kCFURLPOSIXPathStyle, false);
+ CFRelease(cfTotalPath);
+ return url;
+}
+
+char_t *getPrintableOSStatusError(char_t *str, OSStatus error)
+{
+ // see if it appears to be a 4-char-code
+ *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
+ if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
+ str[0] = str[5] = '\'';
+ str[6] = '\0';
+ } else
+ // no, format it as an integer
+ sprintf(str, "%d", (int)error);
+ return str;
+}
+
+#endif /* defined(HAVE_SOURCE_APPLE_AUDIO) || defined(HAVE_SINK_APPLE_AUDIO) */
diff --git a/src/lvec.c b/src/lvec.c
new file mode 100644
index 0000000..dd63bf4
--- /dev/null
+++ b/src/lvec.c
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "lvec.h"
+
+lvec_t * new_lvec(uint_t length) {
+ lvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(lvec_t);
+ s->length = length;
+ s->data = AUBIO_ARRAY(lsmp_t, s->length);
+ return s;
+}
+
+void del_lvec(lvec_t *s) {
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void lvec_set_sample(lvec_t *s, lsmp_t data, uint_t position) {
+ s->data[position] = data;
+}
+
+lsmp_t lvec_get_sample(lvec_t *s, uint_t position) {
+ return s->data[position];
+}
+
+lsmp_t * lvec_get_data(const lvec_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void lvec_print(const lvec_t *s) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_LSMP_FMT " ", s->data[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void lvec_set_all (lvec_t *s, smpl_t val) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->data[j] = val;
+ }
+}
+
+void lvec_zeros(lvec_t *s) {
+#if HAVE_MEMCPY_HACKS
+ memset(s->data, 0, s->length * sizeof(lsmp_t));
+#else
+ lvec_set_all (s, 0.);
+#endif
+}
+
+void lvec_ones(lvec_t *s) {
+ lvec_set_all (s, 1.);
+}
+
diff --git a/src/lvec.h b/src/lvec.h
new file mode 100644
index 0000000..402ba0f
--- /dev/null
+++ b/src/lvec.h
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_LVEC_H
+#define AUBIO_LVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of real-valued data in double precision
+
+ This file specifies the ::lvec_t buffer type, which is used in some places in
+ aubio to store a vector of ::lsmp_t.
+
+ Note: the lvec_t data type is required in some algorithms such as IIR filters
+ (see temporal/filter.h).
+
+ \example test-lvec.c
+
+*/
+
+/** Buffer for real data in double precision */
+typedef struct {
+ uint_t length; /**< length of buffer */
+ lsmp_t *data; /**< data array of size [length] */
+} lvec_t;
+
+/** lvec_t buffer creation function
+
+ \param length the length of the buffer to create
+
+*/
+lvec_t * new_lvec(uint_t length);
+/** lvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_lvec()
+
+*/
+void del_lvec(lvec_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+lsmp_t lvec_get_sample(lvec_t *s, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[position]
+ \param position sample position to write to
+
+*/
+void lvec_set_sample(lvec_t *s, lsmp_t data, uint_t position);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+lsmp_t * lvec_get_data(const lvec_t *s);
+
+/** print out lvec data
+
+ \param s vector to print out
+
+*/
+void lvec_print(const lvec_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void lvec_set_all(lvec_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void lvec_zeros(lvec_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void lvec_ones(lvec_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_LVEC_H */
diff --git a/src/mathutils.c b/src/mathutils.c
new file mode 100644
index 0000000..01b3519
--- /dev/null
+++ b/src/mathutils.c
@@ -0,0 +1,627 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* see in mathutils.h for doc */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "musicutils.h"
+#include "config.h"
+
+/** Window types */
+typedef enum
+{
+ aubio_win_rectangle,
+ aubio_win_hamming,
+ aubio_win_hanning,
+ aubio_win_hanningz,
+ aubio_win_blackman,
+ aubio_win_blackman_harris,
+ aubio_win_gaussian,
+ aubio_win_welch,
+ aubio_win_parzen,
+ aubio_win_default = aubio_win_hanningz,
+} aubio_window_type;
+
+fvec_t *
+new_aubio_window (char_t * window_type, uint_t length)
+{
+ fvec_t * win = new_fvec (length);
+ uint_t err;
+ if (win == NULL) {
+ return NULL;
+ }
+ err = fvec_set_window (win, window_type);
+ if (err != 0) {
+ del_fvec(win);
+ return NULL;
+ }
+ return win;
+}
+
+uint_t fvec_set_window (fvec_t *win, char_t *window_type) {
+ smpl_t * w = win->data;
+ uint_t i, size = win->length;
+ aubio_window_type wintype;
+ if (window_type == NULL) {
+ AUBIO_ERR ("window type can not be null.\n");
+ return 1;
+ } else if (strcmp (window_type, "rectangle") == 0)
+ wintype = aubio_win_rectangle;
+ else if (strcmp (window_type, "hamming") == 0)
+ wintype = aubio_win_hamming;
+ else if (strcmp (window_type, "hanning") == 0)
+ wintype = aubio_win_hanning;
+ else if (strcmp (window_type, "hanningz") == 0)
+ wintype = aubio_win_hanningz;
+ else if (strcmp (window_type, "blackman") == 0)
+ wintype = aubio_win_blackman;
+ else if (strcmp (window_type, "blackman_harris") == 0)
+ wintype = aubio_win_blackman_harris;
+ else if (strcmp (window_type, "gaussian") == 0)
+ wintype = aubio_win_gaussian;
+ else if (strcmp (window_type, "welch") == 0)
+ wintype = aubio_win_welch;
+ else if (strcmp (window_type, "parzen") == 0)
+ wintype = aubio_win_parzen;
+ else if (strcmp (window_type, "default") == 0)
+ wintype = aubio_win_default;
+ else {
+ AUBIO_ERR ("unknown window type `%s`.\n", window_type);
+ return 1;
+ }
+ switch(wintype) {
+ case aubio_win_rectangle:
+ for (i=0;i<size;i++)
+ w[i] = 0.5;
+ break;
+ case aubio_win_hamming:
+ for (i=0;i<size;i++)
+ w[i] = 0.54 - 0.46 * COS(TWO_PI * i / (size));
+ break;
+ case aubio_win_hanning:
+ for (i=0;i<size;i++)
+ w[i] = 0.5 - (0.5 * COS(TWO_PI * i / (size)));
+ break;
+ case aubio_win_hanningz:
+ for (i=0;i<size;i++)
+ w[i] = 0.5 * (1.0 - COS(TWO_PI * i / (size)));
+ break;
+ case aubio_win_blackman:
+ for (i=0;i<size;i++)
+ w[i] = 0.42
+ - 0.50 * COS( TWO_PI*i/(size-1.0))
+ + 0.08 * COS(2.0*TWO_PI*i/(size-1.0));
+ break;
+ case aubio_win_blackman_harris:
+ for (i=0;i<size;i++)
+ w[i] = 0.35875
+ - 0.48829 * COS( TWO_PI*i/(size-1.0))
+ + 0.14128 * COS(2.0*TWO_PI*i/(size-1.0))
+ - 0.01168 * COS(3.0*TWO_PI*i/(size-1.0));
+ break;
+ case aubio_win_gaussian:
+ {
+ lsmp_t a, b, c = 0.5;
+ uint_t n;
+ for (n = 0; n < size; n++)
+ {
+ a = (n-c*(size-1))/(SQR(c)*(size-1));
+ b = -c*SQR(a);
+ w[n] = EXP(b);
+ }
+ }
+ break;
+ case aubio_win_welch:
+ for (i=0;i<size;i++)
+ w[i] = 1.0 - SQR((2.*i-size)/(size+1.0));
+ break;
+ case aubio_win_parzen:
+ for (i=0;i<size;i++)
+ w[i] = 1.0 - ABS((2.f*i-size)/(size+1.0f));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+smpl_t
+aubio_unwrap2pi (smpl_t phase)
+{
+ /* mod(phase+pi,-2pi)+pi */
+ return phase + TWO_PI * (1. + FLOOR (-(phase + PI) / TWO_PI));
+}
+
+smpl_t
+fvec_mean (fvec_t * s)
+{
+ smpl_t tmp = 0.0;
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->data[j];
+ }
+ return tmp / (smpl_t) (s->length);
+#else
+ aubio_vDSP_meanv(s->data, 1, &tmp, s->length);
+ return tmp;
+#endif /* HAVE_ACCELERATE */
+}
+
+smpl_t
+fvec_sum (fvec_t * s)
+{
+ smpl_t tmp = 0.0;
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->data[j];
+ }
+#else
+ aubio_vDSP_sve(s->data, 1, &tmp, s->length);
+#endif /* HAVE_ACCELERATE */
+ return tmp;
+}
+
+smpl_t
+fvec_max (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ smpl_t tmp = 0.0;
+ for (j = 0; j < s->length; j++) {
+ tmp = (tmp > s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ aubio_vDSP_maxv(s->data, 1, &tmp, s->length);
+#endif
+ return tmp;
+}
+
+smpl_t
+fvec_min (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j;
+ smpl_t tmp = s->data[0];
+ for (j = 0; j < s->length; j++) {
+ tmp = (tmp < s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ aubio_vDSP_minv(s->data, 1, &tmp, s->length);
+#endif
+ return tmp;
+}
+
+uint_t
+fvec_min_elem (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j, pos = 0.;
+ smpl_t tmp = s->data[0];
+ for (j = 0; j < s->length; j++) {
+ pos = (tmp < s->data[j]) ? pos : j;
+ tmp = (tmp < s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ uint_t pos = 0.;
+ aubio_vDSP_minvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+#endif
+ return pos;
+}
+
+uint_t
+fvec_max_elem (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j, pos = 0;
+ smpl_t tmp = 0.0;
+ for (j = 0; j < s->length; j++) {
+ pos = (tmp > s->data[j]) ? pos : j;
+ tmp = (tmp > s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ uint_t pos = 0.;
+ aubio_vDSP_maxvi(s->data, 1, &tmp, (vDSP_Length *)&pos, s->length);
+#endif
+ return pos;
+}
+
+void
+fvec_shift (fvec_t * s)
+{
+ uint_t half = s->length / 2, start = half, j;
+ // if length is odd, middle element is moved to the end
+ if (2 * half < s->length) start ++;
+#ifndef HAVE_ATLAS
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j], s->data[j + start]);
+ }
+#else
+ aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+ if (start != half) {
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j + start - 1], s->data[j + start]);
+ }
+ }
+}
+
+void
+fvec_ishift (fvec_t * s)
+{
+ uint_t half = s->length / 2, start = half, j;
+ // if length is odd, middle element is moved to the beginning
+ if (2 * half < s->length) start ++;
+#ifndef HAVE_ATLAS
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j], s->data[j + start]);
+ }
+#else
+ aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+ if (start != half) {
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[half], s->data[j]);
+ }
+ }
+}
+
+smpl_t
+aubio_level_lin (const fvec_t * f)
+{
+ smpl_t energy = 0.;
+#ifndef HAVE_ATLAS
+ uint_t j;
+ for (j = 0; j < f->length; j++) {
+ energy += SQR (f->data[j]);
+ }
+#else
+ energy = aubio_cblas_dot(f->length, f->data, 1, f->data, 1);
+#endif
+ return energy / f->length;
+}
+
+smpl_t
+fvec_local_hfc (fvec_t * v)
+{
+ smpl_t hfc = 0.;
+ uint_t j;
+ for (j = 0; j < v->length; j++) {
+ hfc += (j + 1) * v->data[j];
+ }
+ return hfc;
+}
+
+void
+fvec_min_removal (fvec_t * v)
+{
+ smpl_t v_min = fvec_min (v);
+ fvec_add (v, - v_min );
+}
+
+smpl_t
+fvec_alpha_norm (fvec_t * o, smpl_t alpha)
+{
+ uint_t j;
+ smpl_t tmp = 0.;
+ for (j = 0; j < o->length; j++) {
+ tmp += POW (ABS (o->data[j]), alpha);
+ }
+ return POW (tmp / o->length, 1. / alpha);
+}
+
+void
+fvec_alpha_normalise (fvec_t * o, smpl_t alpha)
+{
+ uint_t j;
+ smpl_t norm = fvec_alpha_norm (o, alpha);
+ for (j = 0; j < o->length; j++) {
+ o->data[j] /= norm;
+ }
+}
+
+void
+fvec_add (fvec_t * o, smpl_t val)
+{
+ uint_t j;
+ for (j = 0; j < o->length; j++) {
+ o->data[j] += val;
+ }
+}
+
+void fvec_adapt_thres(fvec_t * vec, fvec_t * tmp,
+ uint_t post, uint_t pre) {
+ uint_t length = vec->length, j;
+ for (j=0;j<length;j++) {
+ vec->data[j] -= fvec_moving_thres(vec, tmp, post, pre, j);
+ }
+}
+
+smpl_t
+fvec_moving_thres (fvec_t * vec, fvec_t * tmpvec,
+ uint_t post, uint_t pre, uint_t pos)
+{
+ uint_t k;
+ smpl_t *medar = (smpl_t *) tmpvec->data;
+ uint_t win_length = post + pre + 1;
+ uint_t length = vec->length;
+ /* post part of the buffer does not exist */
+ if (pos < post + 1) {
+ for (k = 0; k < post + 1 - pos; k++)
+ medar[k] = 0.; /* 0-padding at the beginning */
+ for (k = post + 1 - pos; k < win_length; k++)
+ medar[k] = vec->data[k + pos - post];
+ /* the buffer is fully defined */
+ } else if (pos + pre < length) {
+ for (k = 0; k < win_length; k++)
+ medar[k] = vec->data[k + pos - post];
+ /* pre part of the buffer does not exist */
+ } else {
+ for (k = 0; k < length - pos + post; k++)
+ medar[k] = vec->data[k + pos - post];
+ for (k = length - pos + post; k < win_length; k++)
+ medar[k] = 0.; /* 0-padding at the end */
+ }
+ return fvec_median (tmpvec);
+}
+
+smpl_t fvec_median (fvec_t * input) {
+ uint_t n = input->length;
+ smpl_t * arr = (smpl_t *) input->data;
+ uint_t low, high ;
+ uint_t median;
+ uint_t middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+ if (high <= low) /* One element only */
+ return arr[median] ;
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median] ;
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]);
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]);
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t pos) {
+ smpl_t s0, s1, s2; uint_t x0, x2;
+ smpl_t half = .5, two = 2.;
+ if (pos == 0 || pos == x->length - 1) return pos;
+ x0 = (pos < 1) ? pos : pos - 1;
+ x2 = (pos + 1 < x->length) ? pos + 1 : pos;
+ if (x0 == pos) return (x->data[pos] <= x->data[x2]) ? pos : x2;
+ if (x2 == pos) return (x->data[pos] <= x->data[x0]) ? pos : x0;
+ s0 = x->data[x0];
+ s1 = x->data[pos];
+ s2 = x->data[x2];
+ return pos + half * (s0 - s2 ) / (s0 - two * s1 + s2);
+}
+
+smpl_t fvec_quadratic_peak_mag (fvec_t *x, smpl_t pos) {
+ smpl_t x0, x1, x2;
+ uint_t index = (uint_t)(pos - .5) + 1;
+ if (pos >= x->length || pos < 0.) return 0.;
+ if ((smpl_t)index == pos) return x->data[index];
+ x0 = x->data[index - 1];
+ x1 = x->data[index];
+ x2 = x->data[index + 1];
+ return x1 - .25 * (x0 - x2) * (pos - index);
+}
+
+uint_t fvec_peakpick(const fvec_t * onset, uint_t pos) {
+ uint_t tmp=0;
+ tmp = (onset->data[pos] > onset->data[pos-1]
+ && onset->data[pos] > onset->data[pos+1]
+ && onset->data[pos] > 0.);
+ return tmp;
+}
+
+smpl_t
+aubio_quadfrac (smpl_t s0, smpl_t s1, smpl_t s2, smpl_t pf)
+{
+ smpl_t tmp =
+ s0 + (pf / 2.) * (pf * (s0 - 2. * s1 + s2) - 3. * s0 + 4. * s1 - s2);
+ return tmp;
+}
+
+smpl_t
+aubio_freqtomidi (smpl_t freq)
+{
+ smpl_t midi;
+ if (freq < 2. || freq > 100000.) return 0.; // avoid nans and infs
+ /* log(freq/A-2)/log(2) */
+ midi = freq / 6.875;
+ midi = LOG (midi) / 0.69314718055995;
+ midi *= 12;
+ midi -= 3;
+ return midi;
+}
+
+smpl_t
+aubio_miditofreq (smpl_t midi)
+{
+ smpl_t freq;
+ if (midi > 140.) return 0.; // avoid infs
+ freq = (midi + 3.) / 12.;
+ freq = EXP (freq * 0.69314718055995);
+ freq *= 6.875;
+ return freq;
+}
+
+smpl_t
+aubio_bintofreq (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t freq = samplerate / fftsize;
+ return freq * MAX(bin, 0);
+}
+
+smpl_t
+aubio_bintomidi (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t midi = aubio_bintofreq (bin, samplerate, fftsize);
+ return aubio_freqtomidi (midi);
+}
+
+smpl_t
+aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t bin = fftsize / samplerate;
+ return MAX(freq, 0) * bin;
+}
+
+smpl_t
+aubio_miditobin (smpl_t midi, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t freq = aubio_miditofreq (midi);
+ return aubio_freqtobin (freq, samplerate, fftsize);
+}
+
+uint_t
+aubio_is_power_of_two (uint_t a)
+{
+ if ((a & (a - 1)) == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+uint_t
+aubio_next_power_of_two (uint_t a)
+{
+ uint_t i = 1;
+ while (i < a) i <<= 1;
+ return i;
+}
+
+smpl_t
+aubio_db_spl (const fvec_t * o)
+{
+ return 10. * LOG10 (aubio_level_lin (o));
+}
+
+uint_t
+aubio_silence_detection (const fvec_t * o, smpl_t threshold)
+{
+ return (aubio_db_spl (o) < threshold);
+}
+
+smpl_t
+aubio_level_detection (const fvec_t * o, smpl_t threshold)
+{
+ smpl_t db_spl = aubio_db_spl (o);
+ if (db_spl < threshold) {
+ return 1.;
+ } else {
+ return db_spl;
+ }
+}
+
+smpl_t
+aubio_zero_crossing_rate (fvec_t * input)
+{
+ uint_t j;
+ uint_t zcr = 0;
+ for (j = 1; j < input->length; j++) {
+ // previous was strictly negative
+ if (input->data[j - 1] < 0.) {
+ // current is positive or null
+ if (input->data[j] >= 0.) {
+ zcr += 1;
+ }
+ // previous was positive or null
+ } else {
+ // current is strictly negative
+ if (input->data[j] < 0.) {
+ zcr += 1;
+ }
+ }
+ }
+ return zcr / (smpl_t) input->length;
+}
+
+void
+aubio_autocorr (const fvec_t * input, fvec_t * output)
+{
+ uint_t i, j, length = input->length;
+ smpl_t *data, *acf;
+ smpl_t tmp = 0;
+ data = input->data;
+ acf = output->data;
+ for (i = 0; i < length; i++) {
+ tmp = 0.;
+ for (j = i; j < length; j++) {
+ tmp += data[j - i] * data[j];
+ }
+ acf[i] = tmp / (smpl_t) (length - i);
+ }
+}
+
+void
+aubio_cleanup (void)
+{
+#ifdef HAVE_FFTW3F
+ fftwf_cleanup ();
+#else
+#ifdef HAVE_FFTW3
+ fftw_cleanup ();
+#endif
+#endif
+}
diff --git a/src/mathutils.h b/src/mathutils.h
new file mode 100644
index 0000000..6638f69
--- /dev/null
+++ b/src/mathutils.h
@@ -0,0 +1,316 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Various math functions
+
+ \example test-mathutils.c
+ \example test-mathutils-window.c
+
+ */
+
+#ifndef AUBIO_MATHUTILS_H
+#define AUBIO_MATHUTILS_H
+
+#include "fvec.h"
+#include "musicutils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** compute the mean of a vector
+
+ \param s vector to compute mean from
+ \return the mean of `v`
+
+*/
+smpl_t fvec_mean (fvec_t * s);
+
+/** find the max of a vector
+
+ \param s vector to get the max from
+
+ \return the value of the minimum of v
+
+*/
+smpl_t fvec_max (fvec_t * s);
+
+/** find the min of a vector
+
+ \param s vector to get the min from
+
+ \return the value of the maximum of v
+
+*/
+smpl_t fvec_min (fvec_t * s);
+
+/** find the index of the min of a vector
+
+ \param s vector to get the index from
+
+ \return the index of the minimum element of v
+
+*/
+uint_t fvec_min_elem (fvec_t * s);
+
+/** find the index of the max of a vector
+
+ \param s vector to get the index from
+
+ \return the index of the maximum element of v
+
+*/
+uint_t fvec_max_elem (fvec_t * s);
+
+/** swap the left and right halves of a vector
+
+ This function swaps the left part of the signal with the right part of the
+signal. Therefore
+
+ \f$ a[0], a[1], ..., a[\frac{N}{2}], a[\frac{N}{2}+1], ..., a[N-1], a[N] \f$
+
+ becomes
+
+ \f$ a[\frac{N}{2}+1], ..., a[N-1], a[N], a[0], a[1], ..., a[\frac{N}{2}] \f$
+
+ This operation, known as 'fftshift' in the Matlab Signal Processing Toolbox,
+can be used before computing the FFT to simplify the phase relationship of the
+resulting spectrum. See Amalia de Götzen's paper referred to above.
+
+*/
+void fvec_shift (fvec_t * v);
+
+/** swap the left and right halves of a vector
+
+ This function swaps the left part of the signal with the right part of the
+signal. Therefore
+
+ \f$ a[0], a[1], ..., a[\frac{N}{2}], a[\frac{N}{2}+1], ..., a[N-1], a[N] \f$
+
+ becomes
+
+ \f$ a[\frac{N}{2}+1], ..., a[N-1], a[N], a[0], a[1], ..., a[\frac{N}{2}] \f$
+
+ This operation, known as 'ifftshift' in the Matlab Signal Processing Toolbox,
+can be used after computing the inverse FFT to simplify the phase relationship
+of the resulting spectrum. See Amalia de Götzen's paper referred to above.
+
+*/
+void fvec_ishift (fvec_t * v);
+
+/** compute the sum of all elements of a vector
+
+ \param v vector to compute the sum of
+
+ \return the sum of v
+
+*/
+smpl_t fvec_sum (fvec_t * v);
+
+/** compute the High Frequency Content of a vector
+
+ The High Frequency Content is defined as \f$ \sum_0^{N-1} (k+1) v[k] \f$.
+
+ \param v vector to get the energy from
+
+ \return the HFC of v
+
+*/
+smpl_t fvec_local_hfc (fvec_t * v);
+
+/** computes the p-norm of a vector
+
+ Computes the p-norm of a vector for \f$ p = \alpha \f$
+
+ \f$ L^p = ||x||_p = (|x_1|^p + |x_2|^p + ... + |x_n|^p ) ^ \frac{1}{p} \f$
+
+ If p = 1, the result is the Manhattan distance.
+
+ If p = 2, the result is the Euclidean distance.
+
+ As p tends towards large values, \f$ L^p \f$ tends towards the maximum of the
+input vector.
+
+ References:
+
+ - <a href="http://en.wikipedia.org/wiki/Lp_space">\f$L^p\f$ space</a> on
+ Wikipedia
+
+ \param v vector to compute norm from
+ \param p order of the computed norm
+
+ \return the p-norm of v
+
+*/
+smpl_t fvec_alpha_norm (fvec_t * v, smpl_t p);
+
+/** alpha normalisation
+
+ This function divides all elements of a vector by the p-norm as computed by
+fvec_alpha_norm().
+
+ \param v vector to compute norm from
+ \param p order of the computed norm
+
+*/
+void fvec_alpha_normalise (fvec_t * v, smpl_t p);
+
+/** add a constant to each elements of a vector
+
+ \param v vector to add constant to
+ \param c constant to add to v
+
+*/
+void fvec_add (fvec_t * v, smpl_t c);
+
+/** remove the minimum value of the vector to each elements
+
+ \param v vector to remove minimum from
+
+*/
+void fvec_min_removal (fvec_t * v);
+
+/** compute moving median threshold of a vector
+
+ This function computes the moving median threshold value of at the given
+position of a vector, taking the median among post elements before and up to
+pre elements after pos.
+
+ \param v input vector
+ \param tmp temporary vector of length post+1+pre
+ \param post length of causal part to take before pos
+ \param pre length of anti-causal part to take after pos
+ \param pos index to compute threshold for
+
+ \return moving median threshold value
+
+*/
+smpl_t fvec_moving_thres (fvec_t * v, fvec_t * tmp, uint_t post, uint_t pre,
+ uint_t pos);
+
+/** apply adaptive threshold to a vector
+
+ For each points at position p of an input vector, this function remove the
+moving median threshold computed at p.
+
+ \param v input vector
+ \param tmp temporary vector of length post+1+pre
+ \param post length of causal part to take before pos
+ \param pre length of anti-causal part to take after pos
+
+*/
+void fvec_adapt_thres (fvec_t * v, fvec_t * tmp, uint_t post, uint_t pre);
+
+/** returns the median of a vector
+
+ The QuickSelect routine is based on the algorithm described in "Numerical
+recipes in C", Second Edition, Cambridge University Press, 1992, Section 8.5,
+ISBN 0-521-43108-5
+
+ This implementation of the QuickSelect routine is based on Nicolas
+Devillard's implementation, available at http://ndevilla.free.fr/median/median/
+and in the Public Domain.
+
+ \param v vector to get median from
+
+ \return the median of v
+
+*/
+smpl_t fvec_median (fvec_t * v);
+
+/** finds exact peak index by quadratic interpolation
+
+ See [Quadratic Interpolation of Spectral
+ Peaks](https://ccrma.stanford.edu/~jos/sasp/Quadratic_Peak_Interpolation.html),
+ by Julius O. Smith III
+
+ \f$ p_{frac} = \frac{1}{2} \frac {x[p-1] - x[p+1]} {x[p-1] - 2 x[p] + x[p+1]} \in [ -.5, .5] \f$
+
+ \param x vector to get the interpolated peak position from
+ \param p index of the peak in vector `x`
+ \return \f$ p + p_{frac} \f$ exact peak position of interpolated maximum or minimum
+
+*/
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t p);
+
+/** finds magnitude of peak by quadratic interpolation
+
+ See [Quadratic Interpolation of Spectral
+ Peaks](https://ccrma.stanford.edu/~jos/sasp/Quadratic_Peak_Interpolation.html),
+ by Julius O. Smith III
+
+ \param x vector to get the magnitude of the interpolated peak position from
+ \param p index of the peak in vector `x`
+ \return magnitude of interpolated peak
+
+*/
+smpl_t fvec_quadratic_peak_mag (fvec_t * x, smpl_t p);
+
+/** Quadratic interpolation using Lagrange polynomial.
+
+ Inspired from ``Comparison of interpolation algorithms in real-time sound
+processing'', Vladimir Arnost,
+
+ \param s0,s1,s2 are 3 consecutive samples of a curve
+ \param pf is the floating point index [0;2]
+
+ \return \f$ s0 + (pf/2.)*((pf-3.)*s0-2.*(pf-2.)*s1+(pf-1.)*s2); \f$
+
+*/
+smpl_t aubio_quadfrac (smpl_t s0, smpl_t s1, smpl_t s2, smpl_t pf);
+
+/** return 1 if v[p] is a peak and positive, 0 otherwise
+
+ This function returns 1 if a peak is found at index p in the vector v. The
+peak is defined as follows:
+
+ - v[p] is positive
+ - v[p-1] < v[p]
+ - v[p] > v[p+1]
+
+ \param v input vector
+ \param p position of supposed for peak
+
+ \return 1 if a peak is found, 0 otherwise
+
+*/
+uint_t fvec_peakpick (const fvec_t * v, uint_t p);
+
+/** return 1 if a is a power of 2, 0 otherwise */
+uint_t aubio_is_power_of_two(uint_t a);
+
+/** return the next power of power of 2 greater than a */
+uint_t aubio_next_power_of_two(uint_t a);
+
+/** compute normalised autocorrelation function
+
+ \param input vector to compute autocorrelation from
+ \param output vector to store autocorrelation function to
+
+*/
+void aubio_autocorr (const fvec_t * input, fvec_t * output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MATHUTILS_H */
diff --git a/src/musicutils.h b/src/musicutils.h
new file mode 100644
index 0000000..f71d20b
--- /dev/null
+++ b/src/musicutils.h
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file
+ * various functions useful in audio signal processing
+ */
+
+#ifndef AUBIO_MUSICUTILS_H
+#define AUBIO_MUSICUTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create window
+
+ \param window_type type of the window to create
+ \param size length of the window to create (see fvec_set_window())
+
+*/
+fvec_t *new_aubio_window (char_t * window_type, uint_t size);
+
+/** set elements of a vector to window coefficients
+
+ \param window exsting ::fvec_t to use
+ \param window_type type of the window to create
+
+ List of available window types: "rectangle", "hamming", "hanning",
+ "hanningz", "blackman", "blackman_harris", "gaussian", "welch", "parzen",
+ "default".
+
+ "default" is equivalent to "hanningz".
+
+ References:
+
+ - <a href="http://en.wikipedia.org/wiki/Window_function">Window
+function</a> on Wikipedia
+ - Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional (?)
+implementations of a phase vocoder: the tricks of the trade. In Proceedings of
+the International Conference on Digital Audio Effects (DAFx-00), pages 37–44,
+Uni- versity of Verona, Italy, 2000.
+ (<a href="http://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf">
+ pdf</a>)
+
+ */
+uint_t fvec_set_window (fvec_t * window, char_t * window_type);
+
+/** compute the principal argument
+
+ This function maps the input phase to its corresponding value wrapped in the
+range \f$ [-\pi, \pi] \f$.
+
+ \param phase unwrapped phase to map to the unit circle
+
+ \return equivalent phase wrapped to the unit circle
+
+*/
+smpl_t aubio_unwrap2pi (smpl_t phase);
+
+/** convert frequency bin to midi value */
+smpl_t aubio_bintomidi (smpl_t bin, smpl_t samplerate, smpl_t fftsize);
+
+/** convert midi value to frequency bin */
+smpl_t aubio_miditobin (smpl_t midi, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency bin to frequency (Hz) */
+smpl_t aubio_bintofreq (smpl_t bin, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency (Hz) to frequency bin */
+smpl_t aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency (Hz) to midi value (0-128) */
+smpl_t aubio_freqtomidi (smpl_t freq);
+
+/** convert midi value (0-128) to frequency (Hz) */
+smpl_t aubio_miditofreq (smpl_t midi);
+
+/** clean up cached memory at the end of program
+
+ This function should be used at the end of programs to purge all cached
+ memory. So far it is only useful to clean FFTW's cache.
+
+*/
+void aubio_cleanup (void);
+
+/** zero-crossing rate (ZCR)
+
+ The zero-crossing rate is the number of times a signal changes sign,
+ divided by the length of this signal.
+
+ \param v vector to compute ZCR from
+
+ \return zero-crossing rate of v
+
+*/
+smpl_t aubio_zero_crossing_rate (fvec_t * v);
+
+/** compute sound level on a linear scale
+
+ This gives the average of the square amplitudes.
+
+ \param v vector to compute level from
+
+ \return level of v
+
+*/
+smpl_t aubio_level_lin (const fvec_t * v);
+
+/** compute sound pressure level (SPL) in dB
+
+ This quantity is often wrongly called 'loudness'.
+
+ This gives ten times the log10 of the average of the square amplitudes.
+
+ \param v vector to compute dB SPL from
+
+ \return level of v in dB SPL
+
+*/
+smpl_t aubio_db_spl (const fvec_t * v);
+
+/** check if buffer level in dB SPL is under a given threshold
+
+ \param v vector to get level from
+ \param threshold threshold in dB SPL
+
+ \return 0 if level is under the given threshold, 1 otherwise
+
+*/
+uint_t aubio_silence_detection (const fvec_t * v, smpl_t threshold);
+
+/** get buffer level if level >= threshold, 1. otherwise
+
+ \param v vector to get level from
+ \param threshold threshold in dB SPL
+
+ \return level in dB SPL if level >= threshold, 1. otherwise
+
+*/
+smpl_t aubio_level_detection (const fvec_t * v, smpl_t threshold);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MUSICUTILS_H */
diff --git a/src/notes/notes.c b/src/notes/notes.c
new file mode 100644
index 0000000..22a7cd8
--- /dev/null
+++ b/src/notes/notes.c
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "pitch/pitch.h"
+#include "onset/onset.h"
+#include "notes/notes.h"
+
+struct _aubio_notes_t {
+
+ uint_t onset_buf_size;
+ uint_t pitch_buf_size;
+ uint_t hop_size;
+
+ uint_t samplerate;
+
+ uint_t median;
+ fvec_t *note_buffer;
+ fvec_t *note_buffer2;
+
+ aubio_pitch_t *pitch;
+ fvec_t *pitch_output;
+ smpl_t pitch_tolerance;
+
+ aubio_onset_t *onset;
+ fvec_t *onset_output;
+ smpl_t onset_threshold;
+
+ smpl_t curnote;
+ smpl_t newnote;
+
+ smpl_t silence_threshold;
+
+ uint_t isready;
+};
+
+aubio_notes_t * new_aubio_notes (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate) {
+ aubio_notes_t *o = AUBIO_NEW(aubio_notes_t);
+
+ const char_t * onset_method = "default";
+ const char_t * pitch_method = "default";
+
+ o->onset_buf_size = buf_size;
+ o->pitch_buf_size = buf_size * 4;
+ o->hop_size = hop_size;
+
+ o->onset_threshold = 0.;
+ o->pitch_tolerance = 0.;
+
+ o->samplerate = samplerate;
+
+ o->median = 6;
+
+ o->isready = 0;
+
+ o->onset = new_aubio_onset (onset_method, o->onset_buf_size, o->hop_size, o->samplerate);
+ if (o->onset_threshold != 0.) aubio_onset_set_threshold (o->onset, o->onset_threshold);
+ o->onset_output = new_fvec (1);
+
+ o->pitch = new_aubio_pitch (pitch_method, o->pitch_buf_size, o->hop_size, o->samplerate);
+ if (o->pitch_tolerance != 0.) aubio_pitch_set_tolerance (o->pitch, o->pitch_tolerance);
+ o->pitch_output = new_fvec (1);
+
+ if (strcmp(method, "default") != 0) {
+ AUBIO_ERR("unknown notes detection method %s, using default.\n",
+ method);
+ goto fail;
+ }
+ o->note_buffer = new_fvec(o->median);
+ o->note_buffer2 = new_fvec(o->median);
+
+ o->curnote = -1.;
+ o->newnote = 0.;
+
+ o->silence_threshold = -90.;
+
+ return o;
+
+fail:
+ del_aubio_notes(o);
+ return NULL;
+}
+
+/** append new note candidate to the note_buffer and return filtered value. we
+ * need to copy the input array as fvec_median destroy its input data.*/
+static void
+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;
+}
+
+static uint_t
+aubio_notes_get_latest_note (aubio_notes_t *o)
+{
+ uint_t i;
+ for (i = 0; i < o->note_buffer->length; i++) {
+ o->note_buffer2->data[i] = o->note_buffer->data[i];
+ }
+ return fvec_median (o->note_buffer2);
+}
+
+
+void aubio_notes_do (aubio_notes_t *o, const fvec_t * input, fvec_t * notes)
+{
+ smpl_t new_pitch, curlevel;
+ fvec_zeros(notes);
+ aubio_onset_do(o->onset, input, o->onset_output);
+
+ aubio_pitch_do (o->pitch, input, o->pitch_output);
+ new_pitch = o->pitch_output->data[0];
+ if(o->median){
+ note_append(o->note_buffer, new_pitch);
+ }
+
+ /* curlevel is negatif or 1 if silence */
+ curlevel = aubio_level_detection(input, o->silence_threshold);
+ if (o->onset_output->data[0] != 0) {
+ /* test for silence */
+ if (curlevel == 1.) {
+ if (o->median) o->isready = 0;
+ /* send note off */
+ //send_noteon(o->curnote,0);
+ //notes->data[0] = o->curnote;
+ //notes->data[1] = 0.;
+ notes->data[2] = o->curnote;
+ } else {
+ if (o->median) {
+ o->isready = 1;
+ } else {
+ /* kill old note */
+ //send_noteon(o->curnote,0, o->samplerate);
+ notes->data[2] = o->curnote;
+ /* get and send new one */
+ //send_noteon(new_pitch,127+(int)floor(curlevel), o->samplerate);
+ notes->data[0] = new_pitch;
+ notes->data[1] = 127 + (int)floor(curlevel);
+ o->curnote = new_pitch;
+ }
+ }
+ } else {
+ if (o->median) {
+ if (o->isready > 0)
+ o->isready++;
+ if (o->isready == o->median)
+ {
+ /* kill old note */
+ //send_noteon(curnote,0);
+ notes->data[2] = o->curnote;
+ notes->data[3] = 0;
+ o->newnote = aubio_notes_get_latest_note(o);
+ o->curnote = o->newnote;
+ /* get and send new one */
+ if (o->curnote>45){
+ //send_noteon(curnote,127+(int)floor(curlevel));
+ notes->data[0] = o->curnote;
+ notes->data[1] = 127 + (int) floor(curlevel);
+ }
+ }
+ } // if median
+ }
+}
+
+void del_aubio_notes (aubio_notes_t *o) {
+ if (o->note_buffer) del_fvec(o->note_buffer);
+ if (o->note_buffer2) del_fvec(o->note_buffer2);
+ if (o->pitch_output) del_fvec(o->pitch_output);
+ if (o->pitch) del_aubio_pitch(o->pitch);
+ if (o->onset_output) del_fvec(o->onset_output);
+ if (o->onset) del_aubio_onset(o->onset);
+ AUBIO_FREE(o);
+}
diff --git a/src/notes/notes.h b/src/notes/notes.h
new file mode 100644
index 0000000..fc12bad
--- /dev/null
+++ b/src/notes/notes.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _AUBIO_NOTES_H
+#define _AUBIO_NOTES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** notes detection object */
+typedef struct _aubio_notes_t aubio_notes_t;
+
+/** create notes detection object
+
+ \param method notes detection type as specified in specdesc.h
+ \param buf_size buffer size for phase vocoder
+ \param hop_size hop size for phase vocoder
+ \param samplerate sampling rate of the input signal
+
+ \return newly created ::aubio_notes_t
+
+*/
+aubio_notes_t * new_aubio_notes (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** delete notes detection object
+
+ \param o notes detection object to delete
+
+*/
+void del_aubio_notes(aubio_notes_t * o);
+
+/** execute note detection on an input signal frame
+
+ \param o note detection object as returned by new_aubio_notes()
+ \param in input signal of size [hop_size]
+ \param out output notes of size [3] ? FIXME
+
+*/
+void aubio_notes_do (aubio_notes_t *o, const fvec_t * input, fvec_t * output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_NOTES_H */
diff --git a/src/onset/onset.c b/src/onset/onset.c
new file mode 100644
index 0000000..9d241df
--- /dev/null
+++ b/src/onset/onset.c
@@ -0,0 +1,235 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+#include "spectral/phasevoc.h"
+#include "onset/peakpicker.h"
+#include "mathutils.h"
+#include "onset/onset.h"
+
+/** structure to store object state */
+struct _aubio_onset_t {
+ aubio_pvoc_t * pv; /**< phase vocoder */
+ aubio_specdesc_t * od; /**< spectral descriptor */
+ aubio_peakpicker_t * pp; /**< peak picker */
+ cvec_t * fftgrain; /**< phase vocoder output */
+ fvec_t * desc; /**< spectral description */
+ smpl_t silence; /**< silence threhsold */
+ uint_t minioi; /**< minimum inter onset interval */
+ uint_t delay; /**< constant delay, in samples, removed from detected onset times */
+ uint_t samplerate; /**< sampling rate of the input signal */
+ uint_t hop_size; /**< number of samples between two runs */
+
+ uint_t total_frames; /**< total number of frames processed since the beginning */
+ uint_t last_onset; /**< last detected onset location, in frames */
+};
+
+/* execute onset detection function on iput buffer */
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset)
+{
+ smpl_t isonset = 0;
+ aubio_pvoc_do (o->pv,input, o->fftgrain);
+ aubio_specdesc_do (o->od, o->fftgrain, o->desc);
+ aubio_peakpicker_do(o->pp, o->desc, onset);
+ isonset = onset->data[0];
+ if (isonset > 0.) {
+ if (aubio_silence_detection(input, o->silence)==1) {
+ //AUBIO_DBG ("silent onset, not marking as onset\n");
+ isonset = 0;
+ } else {
+ uint_t new_onset = o->total_frames + (uint_t)ROUND(isonset * o->hop_size);
+ if (o->last_onset + o->minioi < new_onset) {
+ //AUBIO_DBG ("accepted detection, marking as onset\n");
+ o->last_onset = new_onset;
+ } else {
+ //AUBIO_DBG ("doubled onset, not marking as onset\n");
+ isonset = 0;
+ }
+ }
+ } else {
+ // we are at the beginning of the file
+ if (o->total_frames <= o->delay) {
+ // and we don't find silence
+ if (aubio_silence_detection(input, o->silence) == 0) {
+ uint_t new_onset = o->total_frames;
+ if (o->total_frames == 0 || o->last_onset + o->minioi < new_onset) {
+ isonset = o->delay / o->hop_size;
+ o->last_onset = o->total_frames + o->delay;
+ }
+ }
+ }
+ }
+ onset->data[0] = isonset;
+ o->total_frames += o->hop_size;
+ return;
+}
+
+uint_t aubio_onset_get_last (const aubio_onset_t *o)
+{
+ return o->last_onset - o->delay;
+}
+
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o)
+{
+ return aubio_onset_get_last (o) / (smpl_t) (o->samplerate);
+}
+
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o)
+{
+ return aubio_onset_get_last_s (o) * 1000.;
+}
+
+uint_t aubio_onset_set_silence(aubio_onset_t * o, smpl_t silence) {
+ o->silence = silence;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o) {
+ return o->silence;
+}
+
+uint_t aubio_onset_set_threshold(aubio_onset_t * o, smpl_t threshold) {
+ aubio_peakpicker_set_threshold(o->pp, threshold);
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o) {
+ return aubio_peakpicker_get_threshold(o->pp);
+}
+
+uint_t aubio_onset_set_minioi(aubio_onset_t * o, uint_t minioi) {
+ o->minioi = minioi;
+ return AUBIO_OK;
+}
+
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o) {
+ return o->minioi;
+}
+
+uint_t aubio_onset_set_minioi_s(aubio_onset_t * o, smpl_t minioi) {
+ return aubio_onset_set_minioi (o, (uint_t)ROUND(minioi * o->samplerate));
+}
+
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o) {
+ return aubio_onset_get_minioi (o) / (smpl_t) o->samplerate;
+}
+
+uint_t aubio_onset_set_minioi_ms(aubio_onset_t * o, smpl_t minioi) {
+ return aubio_onset_set_minioi_s (o, minioi / 1000.);
+}
+
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o) {
+ return aubio_onset_get_minioi_s (o) * 1000.;
+}
+
+uint_t aubio_onset_set_delay(aubio_onset_t * o, uint_t delay) {
+ o->delay = delay;
+ return AUBIO_OK;
+}
+
+uint_t aubio_onset_get_delay(const aubio_onset_t * o) {
+ return o->delay;
+}
+
+uint_t aubio_onset_set_delay_s(aubio_onset_t * o, smpl_t delay) {
+ return aubio_onset_set_delay (o, delay * o->samplerate);
+}
+
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o) {
+ return aubio_onset_get_delay (o) / (smpl_t) o->samplerate;
+}
+
+uint_t aubio_onset_set_delay_ms(aubio_onset_t * o, smpl_t delay) {
+ return aubio_onset_set_delay_s (o, delay / 1000.);
+}
+
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o) {
+ return aubio_onset_get_delay_s (o) * 1000.;
+}
+
+smpl_t aubio_onset_get_descriptor(const aubio_onset_t * o) {
+ return o->desc->data[0];
+}
+
+smpl_t aubio_onset_get_thresholded_descriptor(const aubio_onset_t * o) {
+ fvec_t * thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
+ return thresholded->data[0];
+}
+
+/* Allocate memory for an onset detection */
+aubio_onset_t * new_aubio_onset (const char_t * onset_mode,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+ aubio_onset_t * o = AUBIO_NEW(aubio_onset_t);
+
+ /* check parameters are valid */
+ if ((sint_t)hop_size < 1) {
+ AUBIO_ERR("onset: got hop_size %d, but can not be < 1\n", hop_size);
+ goto beach;
+ } else if ((sint_t)buf_size < 2) {
+ AUBIO_ERR("onset: got buffer_size %d, but can not be < 2\n", buf_size);
+ goto beach;
+ } else if (buf_size < hop_size) {
+ AUBIO_ERR("onset: hop size (%d) is larger than win size (%d)\n", buf_size, hop_size);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("onset: samplerate (%d) can not be < 1\n", samplerate);
+ goto beach;
+ }
+
+ /* store creation parameters */
+ o->samplerate = samplerate;
+ o->hop_size = hop_size;
+
+ /* allocate memory */
+ o->pv = new_aubio_pvoc(buf_size, o->hop_size);
+ o->pp = new_aubio_peakpicker();
+ o->od = new_aubio_specdesc(onset_mode,buf_size);
+ o->fftgrain = new_cvec(buf_size);
+ o->desc = new_fvec(1);
+
+ /* set some default parameter */
+ aubio_onset_set_threshold (o, 0.3);
+ aubio_onset_set_delay(o, 4.3 * hop_size);
+ aubio_onset_set_minioi_ms(o, 20.);
+ aubio_onset_set_silence(o, -70.);
+
+ /* initialize internal variables */
+ o->last_onset = 0;
+ o->total_frames = 0;
+ return o;
+
+beach:
+ AUBIO_FREE(o);
+ return NULL;
+}
+
+void del_aubio_onset (aubio_onset_t *o)
+{
+ del_aubio_specdesc(o->od);
+ del_aubio_peakpicker(o->pp);
+ del_aubio_pvoc(o->pv);
+ del_fvec(o->desc);
+ del_cvec(o->fftgrain);
+ AUBIO_FREE(o);
+}
diff --git a/src/onset/onset.h b/src/onset/onset.h
new file mode 100644
index 0000000..e788603
--- /dev/null
+++ b/src/onset/onset.h
@@ -0,0 +1,288 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Onset detection object
+
+ The following routines compute the onset detection function and detect peaks
+ in these functions. When onsets are found above a given silence threshold,
+ and after a minimum inter-onset interval, the output vector returned by
+ aubio_onset_do() is filled with `1`. Otherwise, the output vector remains
+ `0`.
+
+ The peak-picking threshold, the silence threshold, and the minimum
+ inter-onset interval can be adjusted during the execution of the
+ aubio_onset_do routine using the corresponding functions.
+
+ \example onset/test-onset.c
+ \example examples/aubioonset.c
+ \example examples/aubionotes.c
+
+*/
+
+
+#ifndef AUBIO_ONSET_H
+#define AUBIO_ONSET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** onset detection object */
+typedef struct _aubio_onset_t aubio_onset_t;
+
+/** create onset detection object
+
+ \param method onset detection type as specified in specdesc.h
+ \param buf_size buffer size for phase vocoder
+ \param hop_size hop size for phase vocoder
+ \param samplerate sampling rate of the input signal
+
+ \return newly created ::aubio_onset_t
+
+*/
+aubio_onset_t * new_aubio_onset (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** execute onset detection
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param input new audio vector of length hop_size
+ \param onset output vector of length 1, containing 0 if no onset was found,
+ and a value equal or greater than 1 otherwise
+
+ When no onset was detected, the first element of the output vector `onset`
+ is set to 0.
+
+ When an onset is found, the first element of the output vector `onset` is set
+ to `offset = 1 + a` where `a` is a number in the range`[0, 1]`.
+
+ The final onset detection time, in samples, can be obtained with
+ aubio_onset_get_last(). It can also be derived from `offset` as
+ follows:
+
+ \code
+ t = total_frames + offset * hop_size - delay
+ \endcode
+
+ where `total_frames` is the total number of frames processed so far, and
+ `delay` is the current delay of the onset object, as returned by
+ aubio_onset_get_delay().
+
+*/
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset);
+
+/** get the time of the latest onset detected, in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in samples)
+
+*/
+uint_t aubio_onset_get_last (const aubio_onset_t *o);
+
+/** get the time of the latest onset detected, in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in seconds)
+
+*/
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o);
+
+/** get the time of the latest onset detected, in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in milliseconds)
+
+*/
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o);
+
+/** set onset detection silence threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param silence new silence detection threshold
+
+*/
+uint_t aubio_onset_set_silence(aubio_onset_t * o, smpl_t silence);
+
+/** get onset detection silence threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return current silence threshold
+
+*/
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o);
+
+/** get onset detection function
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return the current value of the descriptor
+
+*/
+smpl_t aubio_onset_get_descriptor (const aubio_onset_t *o);
+
+/** get thresholded onset detection function
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return the value of the thresholded descriptor
+
+*/
+smpl_t aubio_onset_get_thresholded_descriptor (const aubio_onset_t *o);
+
+/** set onset detection peak picking threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param threshold new peak-picking threshold
+
+*/
+uint_t aubio_onset_set_threshold(aubio_onset_t * o, smpl_t threshold);
+
+/** set minimum inter onset interval in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ samples)
+
+*/
+uint_t aubio_onset_set_minioi(aubio_onset_t * o, uint_t minioi);
+
+/** set minimum inter onset interval in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ seconds)
+
+*/
+uint_t aubio_onset_set_minioi_s(aubio_onset_t * o, smpl_t minioi);
+
+/** set minimum inter onset interval in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ milliseconds)
+
+*/
+uint_t aubio_onset_set_minioi_ms(aubio_onset_t * o, smpl_t minioi);
+
+/** set delay in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in samples)
+
+*/
+uint_t aubio_onset_set_delay(aubio_onset_t * o, uint_t delay);
+
+/** set delay in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in seconds)
+
+*/
+uint_t aubio_onset_set_delay_s(aubio_onset_t * o, smpl_t delay);
+
+/** set delay in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in milliseconds)
+
+*/
+uint_t aubio_onset_set_delay_ms(aubio_onset_t * o, smpl_t delay);
+
+/** get minimum inter onset interval in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ samples)
+
+*/
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o);
+
+/** get minimum inter onset interval in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ seconds)
+
+*/
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o);
+
+/** get minimum inter onset interval in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ milliseconds)
+
+*/
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o);
+
+/** get delay in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in samples)
+
+*/
+uint_t aubio_onset_get_delay(const aubio_onset_t * o);
+
+/** get delay in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in seconds)
+
+*/
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o);
+
+/** get delay in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in milliseconds)
+
+*/
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o);
+
+/** get onset peak picking threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return current onset detection threshold
+
+*/
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o);
+
+/** delete onset detection object
+
+ \param o onset detection object to delete
+
+*/
+void del_aubio_onset(aubio_onset_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_ONSET_H */
diff --git a/src/onset/peakpicker.c b/src/onset/peakpicker.c
new file mode 100644
index 0000000..0d83bec
--- /dev/null
+++ b/src/onset/peakpicker.c
@@ -0,0 +1,203 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+#include "onset/peakpicker.h"
+
+/** function pointer to thresholding function */
+typedef smpl_t (*aubio_thresholdfn_t)(fvec_t *input);
+/** function pointer to peak-picking function */
+typedef uint_t (*aubio_pickerfn_t)(fvec_t *input, uint_t pos);
+
+/** set peak picker thresholding function */
+uint_t aubio_peakpicker_set_thresholdfn(aubio_peakpicker_t * p, aubio_thresholdfn_t thresholdfn);
+/** get peak picker thresholding function */
+aubio_thresholdfn_t aubio_peakpicker_get_thresholdfn(aubio_peakpicker_t * p);
+
+/* peak picking parameters, default values in brackets
+ *
+ * [<----post----|--pre-->]
+ * .................|.............
+ * time-> ^now
+ */
+struct _aubio_peakpicker_t
+{
+ /** thresh: offset threshold [0.033 or 0.01] */
+ smpl_t threshold;
+ /** win_post: median filter window length (causal part) [8] */
+ uint_t win_post;
+ /** pre: median filter window (anti-causal part) [post-1] */
+ uint_t win_pre;
+ /** threshfn: name or handle of fn for computing adaptive threshold [median] */
+ aubio_thresholdfn_t thresholdfn;
+ /** picker: name or handle of fn for picking event times [peakpick] */
+ aubio_pickerfn_t pickerfn;
+
+ /** biquad lowpass filter */
+ aubio_filter_t *biquad;
+ /** original onsets */
+ fvec_t *onset_keep;
+ /** modified onsets */
+ fvec_t *onset_proc;
+ /** peak picked window [3] */
+ fvec_t *onset_peek;
+ /** thresholded function */
+ fvec_t *thresholded;
+ /** scratch pad for biquad and median */
+ fvec_t *scratch;
+
+ /** \bug should be used to calculate filter coefficients */
+ /* cutoff: low-pass filter cutoff [0.34, 1] */
+ /* smpl_t cutoff; */
+
+ /* not used anymore */
+ /* time precision [512/44100 winlength/samplerate, fs/buffer_size */
+ /* smpl_t tau; */
+ /* alpha: normalisation exponent [9] */
+ /* smpl_t alpha; */
+};
+
+
+/** modified version for real time, moving mean adaptive threshold this method
+ * is slightly more permissive than the offline one, and yelds to an increase
+ * of false positives. best */
+void
+aubio_peakpicker_do (aubio_peakpicker_t * p, fvec_t * onset, fvec_t * out)
+{
+ fvec_t *onset_keep = p->onset_keep;
+ fvec_t *onset_proc = p->onset_proc;
+ fvec_t *onset_peek = p->onset_peek;
+ fvec_t *thresholded = p->thresholded;
+ fvec_t *scratch = p->scratch;
+ smpl_t mean = 0., median = 0.;
+ uint_t length = p->win_post + p->win_pre + 1;
+ uint_t j = 0;
+
+ /* store onset in onset_keep */
+ /* shift all elements but last, then write last */
+ for (j = 0; j < length - 1; j++) {
+ onset_keep->data[j] = onset_keep->data[j + 1];
+ onset_proc->data[j] = onset_keep->data[j];
+ }
+ onset_keep->data[length - 1] = onset->data[0];
+ onset_proc->data[length - 1] = onset->data[0];
+
+ /* filter onset_proc */
+ /** \bug filtfilt calculated post+pre times, should be only once !? */
+ aubio_filter_do_filtfilt (p->biquad, onset_proc, scratch);
+
+ /* calculate mean and median for onset_proc */
+ mean = fvec_mean (onset_proc);
+ /* copy to scratch */
+ for (j = 0; j < length; j++)
+ scratch->data[j] = onset_proc->data[j];
+ median = p->thresholdfn (scratch);
+
+ /* shift peek array */
+ for (j = 0; j < 3 - 1; j++)
+ onset_peek->data[j] = onset_peek->data[j + 1];
+ /* calculate new tresholded value */
+ thresholded->data[0] =
+ onset_proc->data[p->win_post] - median - mean * p->threshold;
+ onset_peek->data[2] = thresholded->data[0];
+ out->data[0] = (p->pickerfn) (onset_peek, 1);
+ if (out->data[0]) {
+ out->data[0] = fvec_quadratic_peak_pos (onset_peek, 1);
+ }
+}
+
+/** this method returns the current value in the pick peaking buffer
+ * after smoothing
+ */
+fvec_t *
+aubio_peakpicker_get_thresholded_input (aubio_peakpicker_t * p)
+{
+ return p->thresholded;
+}
+
+uint_t
+aubio_peakpicker_set_threshold (aubio_peakpicker_t * p, smpl_t threshold)
+{
+ p->threshold = threshold;
+ return AUBIO_OK;
+}
+
+smpl_t
+aubio_peakpicker_get_threshold (aubio_peakpicker_t * p)
+{
+ return p->threshold;
+}
+
+uint_t
+aubio_peakpicker_set_thresholdfn (aubio_peakpicker_t * p,
+ aubio_thresholdfn_t thresholdfn)
+{
+ p->thresholdfn = thresholdfn;
+ return AUBIO_OK;
+}
+
+aubio_thresholdfn_t
+aubio_peakpicker_get_thresholdfn (aubio_peakpicker_t * p)
+{
+ return (aubio_thresholdfn_t) (p->thresholdfn);
+}
+
+aubio_peakpicker_t *
+new_aubio_peakpicker (void)
+{
+ aubio_peakpicker_t *t = AUBIO_NEW (aubio_peakpicker_t);
+ t->threshold = 0.1; /* 0.0668; 0.33; 0.082; 0.033; */
+ t->win_post = 5;
+ t->win_pre = 1;
+
+ t->thresholdfn = (aubio_thresholdfn_t) (fvec_median); /* (fvec_mean); */
+ t->pickerfn = (aubio_pickerfn_t) (fvec_peakpick);
+
+ t->scratch = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_keep = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_proc = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_peek = new_fvec (3);
+ t->thresholded = new_fvec (1);
+
+ /* cutoff: low-pass filter with cutoff reduced frequency at 0.34
+ generated with octave butter function: [b,a] = butter(2, 0.34);
+ */
+ t->biquad = new_aubio_filter_biquad (0.15998789, 0.31997577, 0.15998789,
+ -0.59488894, 0.23484048);
+
+ return t;
+}
+
+void
+del_aubio_peakpicker (aubio_peakpicker_t * p)
+{
+ del_aubio_filter (p->biquad);
+ del_fvec (p->onset_keep);
+ del_fvec (p->onset_proc);
+ del_fvec (p->onset_peek);
+ del_fvec (p->thresholded);
+ del_fvec (p->scratch);
+ AUBIO_FREE (p);
+}
diff --git a/src/onset/peakpicker.h b/src/onset/peakpicker.h
new file mode 100644
index 0000000..dafaf91
--- /dev/null
+++ b/src/onset/peakpicker.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Peak picking utilities function
+
+ \example onset/test-peakpicker.c
+
+*/
+
+#ifndef AUBIO_PEAKPICK_H
+#define AUBIO_PEAKPICK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** peak-picker structure */
+typedef struct _aubio_peakpicker_t aubio_peakpicker_t;
+
+/** peak-picker creation function */
+aubio_peakpicker_t * new_aubio_peakpicker(void);
+/** real time peak picking function */
+void aubio_peakpicker_do(aubio_peakpicker_t * p, fvec_t * in, fvec_t * out);
+/** destroy peak picker structure */
+void del_aubio_peakpicker(aubio_peakpicker_t * p);
+
+/** get current peak value */
+fvec_t *aubio_peakpicker_get_thresholded_input (aubio_peakpicker_t * p);
+/** set peak picking threshold */
+uint_t aubio_peakpicker_set_threshold(aubio_peakpicker_t * p, smpl_t threshold);
+/** get peak picking threshold */
+smpl_t aubio_peakpicker_get_threshold(aubio_peakpicker_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PEAKPICK_H */
diff --git a/src/pitch/pitch.c b/src/pitch/pitch.c
new file mode 100644
index 0000000..bee0ea3
--- /dev/null
+++ b/src/pitch/pitch.c
@@ -0,0 +1,464 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "lvec.h"
+#include "mathutils.h"
+#include "musicutils.h"
+#include "spectral/phasevoc.h"
+#include "temporal/filter.h"
+#include "temporal/c_weighting.h"
+#include "pitch/pitchmcomb.h"
+#include "pitch/pitchyin.h"
+#include "pitch/pitchfcomb.h"
+#include "pitch/pitchschmitt.h"
+#include "pitch/pitchyinfft.h"
+#include "pitch/pitchspecacf.h"
+#include "pitch/pitch.h"
+
+#define DEFAULT_PITCH_SILENCE -50.
+
+/** pitch detection algorithms */
+typedef enum
+{
+ aubio_pitcht_yin, /**< `yin`, YIN algorithm */
+ aubio_pitcht_mcomb, /**< `mcomb`, Multi-comb filter */
+ aubio_pitcht_schmitt, /**< `schmitt`, Schmitt trigger */
+ aubio_pitcht_fcomb, /**< `fcomb`, Fast comb filter */
+ aubio_pitcht_yinfft, /**< `yinfft`, Spectral YIN */
+ aubio_pitcht_specacf, /**< `specacf`, Spectral autocorrelation */
+ aubio_pitcht_default
+ = aubio_pitcht_yinfft, /**< `default` */
+} aubio_pitch_type;
+
+/** pitch detection output modes */
+typedef enum
+{
+ aubio_pitchm_freq, /**< Frequency (Hz) */
+ aubio_pitchm_midi, /**< MIDI note (0.,127) */
+ aubio_pitchm_cent, /**< Cent */
+ aubio_pitchm_bin, /**< Frequency bin (0,bufsize) */
+ aubio_pitchm_default = aubio_pitchm_freq, /**< the one used when "default" is asked */
+} aubio_pitch_mode;
+
+/** callback to get pitch candidate, defined below */
+typedef void (*aubio_pitch_detect_t) (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+
+/** callback to convert pitch from one unit to another, defined below */
+typedef smpl_t(*aubio_pitch_convert_t) (smpl_t value, uint_t samplerate, uint_t bufsize);
+
+/** callback to fetch the confidence of the algorithm */
+typedef smpl_t (*aubio_pitch_get_conf_t) (void * p);
+
+/** generic pitch detection structure */
+struct _aubio_pitch_t
+{
+ aubio_pitch_type type; /**< pitch detection mode */
+ aubio_pitch_mode mode; /**< pitch detection output mode */
+ uint_t samplerate; /**< samplerate */
+ uint_t bufsize; /**< buffer size */
+ void *p_object; /**< pointer to pitch object */
+ aubio_filter_t *filter; /**< filter */
+ fvec_t *filtered; /**< filtered input */
+ aubio_pvoc_t *pv; /**< phase vocoder for mcomb */
+ cvec_t *fftgrain; /**< spectral frame for mcomb */
+ fvec_t *buf; /**< temporary buffer for yin */
+ aubio_pitch_detect_t detect_cb; /**< callback to get the pitch candidates */
+ aubio_pitch_convert_t conv_cb; /**< callback to convert it to the desired unit */
+ aubio_pitch_get_conf_t conf_cb; /**< pointer to the current confidence callback */
+ smpl_t silence; /**< silence threshold */
+};
+
+/* callback functions for pitch detection */
+static void aubio_pitch_do_mcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_yin (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_schmitt (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_fcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_yinfft (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+static void aubio_pitch_do_specacf (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf);
+
+/* conversion functions for frequency conversions */
+smpl_t freqconvbin (smpl_t f, uint_t samplerate, uint_t bufsize);
+smpl_t freqconvmidi (smpl_t f, uint_t samplerate, uint_t bufsize);
+smpl_t freqconvpass (smpl_t f, uint_t samplerate, uint_t bufsize);
+
+/* adapter to stack ibuf new samples at the end of buf, and trim `buf` to `bufsize` */
+void aubio_pitch_slideblock (aubio_pitch_t * p, const fvec_t * ibuf);
+
+
+aubio_pitch_t *
+new_aubio_pitch (const char_t * pitch_mode,
+ uint_t bufsize, uint_t hopsize, uint_t samplerate)
+{
+ aubio_pitch_t *p = AUBIO_NEW (aubio_pitch_t);
+ aubio_pitch_type pitch_type;
+ if (strcmp (pitch_mode, "mcomb") == 0)
+ pitch_type = aubio_pitcht_mcomb;
+ else if (strcmp (pitch_mode, "yinfft") == 0)
+ pitch_type = aubio_pitcht_yinfft;
+ else if (strcmp (pitch_mode, "yin") == 0)
+ pitch_type = aubio_pitcht_yin;
+ else if (strcmp (pitch_mode, "schmitt") == 0)
+ pitch_type = aubio_pitcht_schmitt;
+ else if (strcmp (pitch_mode, "fcomb") == 0)
+ pitch_type = aubio_pitcht_fcomb;
+ else if (strcmp (pitch_mode, "specacf") == 0)
+ pitch_type = aubio_pitcht_specacf;
+ else if (strcmp (pitch_mode, "default") == 0)
+ pitch_type = aubio_pitcht_default;
+ else {
+ AUBIO_ERR ("unknown pitch detection method %s, using default.\n",
+ pitch_mode);
+ pitch_type = aubio_pitcht_default;
+ }
+
+ // check parameters are valid
+ if ((sint_t)hopsize < 1) {
+ AUBIO_ERR("pitch: got hopsize %d, but can not be < 1\n", hopsize);
+ goto beach;
+ } else if ((sint_t)bufsize < 1) {
+ AUBIO_ERR("pitch: got buffer_size %d, but can not be < 1\n", bufsize);
+ goto beach;
+ } else if (bufsize < hopsize) {
+ AUBIO_ERR("pitch: hop size (%d) is larger than win size (%d)\n", bufsize, hopsize);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("pitch: samplerate (%d) can not be < 1\n", samplerate);
+ goto beach;
+ }
+
+ p->samplerate = samplerate;
+ p->type = pitch_type;
+ aubio_pitch_set_unit (p, "default");
+ p->bufsize = bufsize;
+ p->silence = DEFAULT_PITCH_SILENCE;
+ p->conf_cb = NULL;
+ switch (p->type) {
+ case aubio_pitcht_yin:
+ p->buf = new_fvec (bufsize);
+ p->p_object = new_aubio_pitchyin (bufsize);
+ p->detect_cb = aubio_pitch_do_yin;
+ p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchyin_get_confidence;
+ aubio_pitchyin_set_tolerance (p->p_object, 0.15);
+ break;
+ case aubio_pitcht_mcomb:
+ p->filtered = new_fvec (hopsize);
+ p->pv = new_aubio_pvoc (bufsize, hopsize);
+ p->fftgrain = new_cvec (bufsize);
+ p->p_object = new_aubio_pitchmcomb (bufsize, hopsize);
+ p->filter = new_aubio_filter_c_weighting (samplerate);
+ p->detect_cb = aubio_pitch_do_mcomb;
+ break;
+ case aubio_pitcht_fcomb:
+ p->buf = new_fvec (bufsize);
+ p->p_object = new_aubio_pitchfcomb (bufsize, hopsize);
+ p->detect_cb = aubio_pitch_do_fcomb;
+ break;
+ case aubio_pitcht_schmitt:
+ p->buf = new_fvec (bufsize);
+ p->p_object = new_aubio_pitchschmitt (bufsize);
+ p->detect_cb = aubio_pitch_do_schmitt;
+ break;
+ case aubio_pitcht_yinfft:
+ p->buf = new_fvec (bufsize);
+ p->p_object = new_aubio_pitchyinfft (samplerate, bufsize);
+ p->detect_cb = aubio_pitch_do_yinfft;
+ p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchyinfft_get_confidence;
+ aubio_pitchyinfft_set_tolerance (p->p_object, 0.85);
+ break;
+ case aubio_pitcht_specacf:
+ p->buf = new_fvec (bufsize);
+ p->p_object = new_aubio_pitchspecacf (bufsize);
+ p->detect_cb = aubio_pitch_do_specacf;
+ p->conf_cb = (aubio_pitch_get_conf_t)aubio_pitchspecacf_get_tolerance;
+ aubio_pitchspecacf_set_tolerance (p->p_object, 0.85);
+ break;
+ default:
+ break;
+ }
+ return p;
+
+beach:
+ AUBIO_FREE(p);
+ return NULL;
+}
+
+void
+del_aubio_pitch (aubio_pitch_t * p)
+{
+ switch (p->type) {
+ case aubio_pitcht_yin:
+ del_fvec (p->buf);
+ del_aubio_pitchyin (p->p_object);
+ break;
+ case aubio_pitcht_mcomb:
+ del_fvec (p->filtered);
+ del_aubio_pvoc (p->pv);
+ del_cvec (p->fftgrain);
+ del_aubio_filter (p->filter);
+ del_aubio_pitchmcomb (p->p_object);
+ break;
+ case aubio_pitcht_schmitt:
+ del_fvec (p->buf);
+ del_aubio_pitchschmitt (p->p_object);
+ break;
+ case aubio_pitcht_fcomb:
+ del_fvec (p->buf);
+ del_aubio_pitchfcomb (p->p_object);
+ break;
+ case aubio_pitcht_yinfft:
+ del_fvec (p->buf);
+ del_aubio_pitchyinfft (p->p_object);
+ break;
+ case aubio_pitcht_specacf:
+ del_fvec (p->buf);
+ del_aubio_pitchspecacf (p->p_object);
+ break;
+ default:
+ break;
+ }
+ AUBIO_FREE (p);
+}
+
+void
+aubio_pitch_slideblock (aubio_pitch_t * p, const fvec_t * ibuf)
+{
+ uint_t overlap_size = p->buf->length - ibuf->length;
+#if 1 //!HAVE_MEMCPY_HACKS
+ uint_t j;
+ for (j = 0; j < overlap_size; j++) {
+ p->buf->data[j] = p->buf->data[j + ibuf->length];
+ }
+ for (j = 0; j < ibuf->length; j++) {
+ p->buf->data[j + overlap_size] = ibuf->data[j];
+ }
+#else
+ smpl_t *data = p->buf->data;
+ smpl_t *newdata = ibuf->data;
+ memmove(data, data + ibuf->length, overlap_size);
+ memcpy(data + overlap_size, newdata, ibuf->length);
+#endif
+}
+
+uint_t
+aubio_pitch_set_unit (aubio_pitch_t * p, const char_t * pitch_unit)
+{
+ uint_t err = AUBIO_OK;
+ aubio_pitch_mode pitch_mode;
+ if (strcmp (pitch_unit, "freq") == 0)
+ pitch_mode = aubio_pitchm_freq;
+ else if (strcmp (pitch_unit, "hertz") == 0)
+ pitch_mode = aubio_pitchm_freq;
+ else if (strcmp (pitch_unit, "Hertz") == 0)
+ pitch_mode = aubio_pitchm_freq;
+ else if (strcmp (pitch_unit, "Hz") == 0)
+ pitch_mode = aubio_pitchm_freq;
+ else if (strcmp (pitch_unit, "f0") == 0)
+ pitch_mode = aubio_pitchm_freq;
+ else if (strcmp (pitch_unit, "midi") == 0)
+ pitch_mode = aubio_pitchm_midi;
+ else if (strcmp (pitch_unit, "cent") == 0)
+ pitch_mode = aubio_pitchm_cent;
+ else if (strcmp (pitch_unit, "bin") == 0)
+ pitch_mode = aubio_pitchm_bin;
+ else if (strcmp (pitch_unit, "default") == 0)
+ pitch_mode = aubio_pitchm_default;
+ else {
+ AUBIO_ERR ("unknown pitch detection unit %s, using default\n", pitch_unit);
+ pitch_mode = aubio_pitchm_default;
+ err = AUBIO_FAIL;
+ }
+ p->mode = pitch_mode;
+ switch (p->mode) {
+ case aubio_pitchm_freq:
+ p->conv_cb = freqconvpass;
+ break;
+ case aubio_pitchm_midi:
+ p->conv_cb = freqconvmidi;
+ break;
+ case aubio_pitchm_cent:
+ /* bug: not implemented */
+ p->conv_cb = freqconvmidi;
+ break;
+ case aubio_pitchm_bin:
+ p->conv_cb = freqconvbin;
+ break;
+ default:
+ break;
+ }
+ return err;
+}
+
+uint_t
+aubio_pitch_set_tolerance (aubio_pitch_t * p, smpl_t tol)
+{
+ switch (p->type) {
+ case aubio_pitcht_yin:
+ aubio_pitchyin_set_tolerance (p->p_object, tol);
+ break;
+ case aubio_pitcht_yinfft:
+ aubio_pitchyinfft_set_tolerance (p->p_object, tol);
+ break;
+ default:
+ break;
+ }
+ return AUBIO_OK;
+}
+
+uint_t
+aubio_pitch_set_silence (aubio_pitch_t * p, smpl_t silence)
+{
+ if (silence <= 0 && silence >= -200) {
+ p->silence = silence;
+ return AUBIO_OK;
+ } else {
+ AUBIO_ERR("pitch: could not set silence to %.2f", silence);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_pitch_get_silence (aubio_pitch_t * p)
+{
+ return p->silence;
+}
+
+
+/* do method, calling the detection callback, then the conversion callback */
+void
+aubio_pitch_do (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
+{
+ p->detect_cb (p, ibuf, obuf);
+ if (aubio_silence_detection(ibuf, p->silence) == 1) {
+ obuf->data[0] = 0.;
+ }
+ obuf->data[0] = p->conv_cb (obuf->data[0], p->samplerate, p->bufsize);
+}
+
+/* do method for each algorithm */
+void
+aubio_pitch_do_mcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
+{
+ aubio_filter_do_outplace (p->filter, ibuf, p->filtered);
+ aubio_pvoc_do (p->pv, ibuf, p->fftgrain);
+ aubio_pitchmcomb_do (p->p_object, p->fftgrain, obuf);
+ obuf->data[0] = aubio_bintofreq (obuf->data[0], p->samplerate, p->bufsize);
+}
+
+void
+aubio_pitch_do_yin (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
+{
+ smpl_t pitch = 0.;
+ aubio_pitch_slideblock (p, ibuf);
+ aubio_pitchyin_do (p->p_object, p->buf, obuf);
+ pitch = obuf->data[0];
+ if (pitch > 0) {
+ pitch = p->samplerate / (pitch + 0.);
+ } else {
+ pitch = 0.;
+ }
+ obuf->data[0] = pitch;
+}
+
+
+void
+aubio_pitch_do_yinfft (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * obuf)
+{
+ smpl_t pitch = 0.;
+ aubio_pitch_slideblock (p, ibuf);
+ aubio_pitchyinfft_do (p->p_object, p->buf, obuf);
+ pitch = obuf->data[0];
+ if (pitch > 0) {
+ pitch = p->samplerate / (pitch + 0.);
+ } else {
+ pitch = 0.;
+ }
+ obuf->data[0] = pitch;
+}
+
+void
+aubio_pitch_do_specacf (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
+{
+ smpl_t pitch = 0., period;
+ aubio_pitch_slideblock (p, ibuf);
+ aubio_pitchspecacf_do (p->p_object, p->buf, out);
+ //out->data[0] = aubio_bintofreq (out->data[0], p->samplerate, p->bufsize);
+ period = out->data[0];
+ if (period > 0) {
+ pitch = p->samplerate / period;
+ } else {
+ pitch = 0.;
+ }
+ out->data[0] = pitch;
+}
+
+void
+aubio_pitch_do_fcomb (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
+{
+ aubio_pitch_slideblock (p, ibuf);
+ aubio_pitchfcomb_do (p->p_object, p->buf, out);
+ out->data[0] = aubio_bintofreq (out->data[0], p->samplerate, p->bufsize);
+}
+
+void
+aubio_pitch_do_schmitt (aubio_pitch_t * p, const fvec_t * ibuf, fvec_t * out)
+{
+ smpl_t period, pitch = 0.;
+ aubio_pitch_slideblock (p, ibuf);
+ aubio_pitchschmitt_do (p->p_object, p->buf, out);
+ period = out->data[0];
+ if (period > 0) {
+ pitch = p->samplerate / period;
+ } else {
+ pitch = 0.;
+ }
+ out->data[0] = pitch;
+}
+
+/* conversion callbacks */
+smpl_t
+freqconvbin(smpl_t f, uint_t samplerate, uint_t bufsize)
+{
+ return aubio_freqtobin(f, samplerate, bufsize);
+}
+
+smpl_t
+freqconvmidi (smpl_t f, uint_t samplerate UNUSED, uint_t bufsize UNUSED)
+{
+ return aubio_freqtomidi (f);
+}
+
+smpl_t
+freqconvpass (smpl_t f, uint_t samplerate UNUSED, uint_t bufsize UNUSED)
+{
+ return f;
+}
+
+/* confidence callbacks */
+smpl_t
+aubio_pitch_get_confidence (aubio_pitch_t * p)
+{
+ if (p->conf_cb) {
+ return p->conf_cb(p->p_object);
+ }
+ return 0.;
+}
diff --git a/src/pitch/pitch.h b/src/pitch/pitch.h
new file mode 100644
index 0000000..e0ae545
--- /dev/null
+++ b/src/pitch/pitch.h
@@ -0,0 +1,182 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_PITCH_H
+#define AUBIO_PITCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Pitch detection object
+
+ This file creates the objects required for the computation of the selected
+ pitch detection algorithm and output the results, in midi note or Hz.
+
+ \section pitch Pitch detection methods
+
+ A list of the pitch detection methods currently available follows.
+
+ \b \p default : use the default method
+
+ Currently, the default method is set to \p yinfft .
+
+ \b \p schmitt : Schmitt trigger
+
+ This pitch extraction method implements a Schmitt trigger to estimate the
+ period of a signal.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \b \p fcomb : a fast harmonic comb filter
+
+ This pitch extraction method implements a fast harmonic comb filter to
+ determine the fundamental frequency of a harmonic sound.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \b \p mcomb : multiple-comb filter
+
+ This fundamental frequency estimation algorithm implements spectral
+ flattening, multi-comb filtering and peak histogramming.
+
+ This method was designed by Juan P. Bello and described in:
+
+ Juan-Pablo Bello. ``Towards the Automated Analysis of Simple Polyphonic
+ Music''. PhD thesis, Centre for Digital Music, Queen Mary University of
+ London, London, UK, 2003.
+
+ \b \p yin : YIN algorithm
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+
+ \b \p yinfft : Yinfft algorithm
+
+ This algorithm was derived from the YIN algorithm. In this implementation, a
+ Fourier transform is used to compute a tapered square difference function,
+ which allows spectral weighting. Because the difference function is tapered,
+ the selection of the period is simplified.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, PhD thesis,
+ Centre for Digital music, Queen Mary University of London, London, UK, 2006.
+
+ \example pitch/test-pitch.c
+ \example examples/aubiopitch.c
+
+*/
+
+/** pitch detection object */
+typedef struct _aubio_pitch_t aubio_pitch_t;
+
+/** execute pitch detection on an input signal frame
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param in input signal of size [hop_size]
+ \param out output pitch candidates of size [1]
+
+*/
+void aubio_pitch_do (aubio_pitch_t * o, const fvec_t * in, fvec_t * out);
+
+/** change yin or yinfft tolerance threshold
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param tol tolerance default is 0.15 for yin and 0.85 for yinfft
+
+*/
+uint_t aubio_pitch_set_tolerance (aubio_pitch_t * o, smpl_t tol);
+
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+
+*/
+void del_aubio_pitch (aubio_pitch_t * o);
+
+/** creation of the pitch detection object
+
+ \param method set pitch detection algorithm
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_pitch_t
+
+*/
+aubio_pitch_t *new_aubio_pitch (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** set the output unit of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param mode set pitch units for output
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_pitch_set_unit (aubio_pitch_t * o, const char_t * mode);
+
+/** set the silence threshold of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param silence level threshold under which pitch should be ignored, in dB
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_pitch_set_silence (aubio_pitch_t * o, smpl_t silence);
+
+/** set the silence threshold of the pitch detection object
+
+ \param o pitch detection object as returned by ::new_aubio_pitch()
+
+ \return level threshold under which pitch should be ignored, in dB
+
+*/
+smpl_t aubio_pitch_get_silence (aubio_pitch_t * o);
+
+/** get the current confidence
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+
+ \return the current confidence of the pitch algorithm
+
+*/
+smpl_t aubio_pitch_get_confidence (aubio_pitch_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCH_H */
diff --git a/src/pitch/pitchfcomb.c b/src/pitch/pitchfcomb.c
new file mode 100644
index 0000000..2bdc509
--- /dev/null
+++ b/src/pitch/pitchfcomb.c
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2004, 2005 Mario Lang <mlang@delysid.org>
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "musicutils.h"
+#include "spectral/fft.h"
+#include "pitch/pitchfcomb.h"
+
+#define MAX_PEAKS 8
+
+typedef struct
+{
+ smpl_t bin;
+ smpl_t db;
+} aubio_fpeak_t;
+
+struct _aubio_pitchfcomb_t
+{
+ uint_t fftSize;
+ uint_t stepSize;
+ uint_t rate;
+ fvec_t *winput;
+ fvec_t *win;
+ cvec_t *fftOut;
+ fvec_t *fftLastPhase;
+ aubio_fft_t *fft;
+};
+
+aubio_pitchfcomb_t *
+new_aubio_pitchfcomb (uint_t bufsize, uint_t hopsize)
+{
+ aubio_pitchfcomb_t *p = AUBIO_NEW (aubio_pitchfcomb_t);
+ p->fftSize = bufsize;
+ p->stepSize = hopsize;
+ p->winput = new_fvec (bufsize);
+ p->fftOut = new_cvec (bufsize);
+ p->fftLastPhase = new_fvec (bufsize);
+ p->fft = new_aubio_fft (bufsize);
+ p->win = new_aubio_window ("hanning", bufsize);
+ return p;
+}
+
+/* input must be stepsize long */
+void
+aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, const fvec_t * input, fvec_t * output)
+{
+ uint_t k, l, maxharm = 0;
+ smpl_t phaseDifference = TWO_PI * (smpl_t) p->stepSize / (smpl_t) p->fftSize;
+ aubio_fpeak_t peaks[MAX_PEAKS];
+
+ for (k = 0; k < MAX_PEAKS; k++) {
+ peaks[k].db = -200.;
+ peaks[k].bin = 0.;
+ }
+
+ for (k = 0; k < input->length; k++) {
+ p->winput->data[k] = p->win->data[k] * input->data[k];
+ }
+ aubio_fft_do (p->fft, p->winput, p->fftOut);
+
+ for (k = 0; k <= p->fftSize / 2; k++) {
+ smpl_t
+ magnitude =
+ 20. * LOG10 (2. * p->fftOut->norm[k] / (smpl_t) p->fftSize),
+ phase = p->fftOut->phas[k], tmp, bin;
+
+ /* compute phase difference */
+ tmp = phase - p->fftLastPhase->data[k];
+ p->fftLastPhase->data[k] = phase;
+
+ /* subtract expected phase difference */
+ tmp -= (smpl_t) k *phaseDifference;
+
+ /* map delta phase into +/- Pi interval */
+ tmp = aubio_unwrap2pi (tmp);
+
+ /* get deviation from bin frequency from the +/- Pi interval */
+ tmp = p->fftSize / (smpl_t) p->stepSize * tmp / (TWO_PI);
+
+ /* compute the k-th partials' true bin */
+ bin = (smpl_t) k + tmp;
+
+ if (bin > 0.0 && magnitude > peaks[0].db) { // && magnitude < 0) {
+ memmove (peaks + 1, peaks, sizeof (aubio_fpeak_t) * (MAX_PEAKS - 1));
+ peaks[0].bin = bin;
+ peaks[0].db = magnitude;
+ }
+ }
+
+ k = 0;
+ for (l = 1; l < MAX_PEAKS && peaks[l].bin > 0.0; l++) {
+ sint_t harmonic;
+ for (harmonic = 5; harmonic > 1; harmonic--) {
+ if (peaks[0].bin / peaks[l].bin < harmonic + .02 &&
+ peaks[0].bin / peaks[l].bin > harmonic - .02) {
+ if (harmonic > (sint_t) maxharm && peaks[0].db < peaks[l].db / 2) {
+ maxharm = harmonic;
+ k = l;
+ }
+ }
+ }
+ }
+ output->data[0] = peaks[k].bin;
+ /* quick hack to clean output a bit */
+ if (peaks[k].bin > 5000.)
+ output->data[0] = 0.;
+}
+
+void
+del_aubio_pitchfcomb (aubio_pitchfcomb_t * p)
+{
+ del_cvec (p->fftOut);
+ del_fvec (p->fftLastPhase);
+ del_fvec (p->win);
+ del_fvec (p->winput);
+ del_aubio_fft (p->fft);
+ AUBIO_FREE (p);
+}
diff --git a/src/pitch/pitchfcomb.h b/src/pitch/pitchfcomb.h
new file mode 100644
index 0000000..5016708
--- /dev/null
+++ b/src/pitch/pitchfcomb.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using a fast harmonic comb filter
+
+ This pitch extraction method implements a fast harmonic comb filter to
+ determine the fundamental frequency of a harmonic sound.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \example pitch/test-pitchfcomb.c
+
+*/
+
+#ifndef AUBIO_PITCHFCOMB_H
+#define AUBIO_PITCHFCOMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchfcomb_t aubio_pitchfcomb_t;
+
+/** execute pitch detection on an input buffer
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+ \param input input signal window (length as specified at creation time)
+ \param output pitch candidates in bins
+
+*/
+void aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, const fvec_t * input,
+ fvec_t * output);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+
+*/
+aubio_pitchfcomb_t *new_aubio_pitchfcomb (uint_t buf_size, uint_t hop_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+
+*/
+void del_aubio_pitchfcomb (aubio_pitchfcomb_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHFCOMB_H */
diff --git a/src/pitch/pitchmcomb.c b/src/pitch/pitchmcomb.c
new file mode 100644
index 0000000..f9ec610
--- /dev/null
+++ b/src/pitch/pitchmcomb.c
@@ -0,0 +1,428 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "pitch/pitchmcomb.h"
+
+#define CAND_SWAP(a,b) { register aubio_spectralcandidate_t *t=(a);(a)=(b);(b)=t; }
+
+typedef struct _aubio_spectralpeak_t aubio_spectralpeak_t;
+typedef struct _aubio_spectralcandidate_t aubio_spectralcandidate_t;
+uint_t aubio_pitchmcomb_get_root_peak (aubio_spectralpeak_t * peaks,
+ uint_t length);
+uint_t aubio_pitchmcomb_quadpick (aubio_spectralpeak_t * spectral_peaks,
+ const fvec_t * X);
+void aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, const fvec_t * oldmag);
+void aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, const fvec_t * newmag);
+/* not used but useful : sort by amplitudes (or anything else)
+ * sort_pitchpeak(peaks, length);
+ */
+/** spectral_peak comparison function (must return signed int) */
+static sint_t aubio_pitchmcomb_sort_peak_comp (const void *x, const void *y);
+/** sort spectral_peak against their mag */
+void aubio_pitchmcomb_sort_peak (aubio_spectralpeak_t * peaks, uint_t nbins);
+/** select the best candidates */
+uint_t aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain,
+ smpl_t * cands);
+
+/** sort spectral_candidate against their comb ene */
+void aubio_pitchmcomb_sort_cand_ene (aubio_spectralcandidate_t ** candidates,
+ uint_t nbins);
+/** sort spectral_candidate against their frequency */
+void aubio_pitchmcomb_sort_cand_freq (aubio_spectralcandidate_t ** candidates,
+ uint_t nbins);
+
+struct _aubio_pitchmcomb_t
+{
+ smpl_t threshold; /**< offset threshold [0.033 or 0.01] */
+ smpl_t alpha; /**< normalisation exponent [9] */
+ smpl_t cutoff; /**< low-pass filter cutoff [0.34, 1] */
+ smpl_t tol; /**< tolerance [0.05] */
+ // smpl_t tau; /**< frequency precision [44100/4096] */
+ uint_t win_post; /**< median filter window length */
+ uint_t win_pre; /**< median filter window */
+ uint_t ncand; /**< maximum number of candidates (combs) */
+ uint_t npartials; /**< maximum number of partials per combs */
+ uint_t count; /**< picked picks */
+ uint_t goodcandidate; /**< best candidate */
+ uint_t spec_partition; /**< spectrum partition to consider */
+ aubio_spectralpeak_t *peaks; /**< up to length win/spec_partition */
+ aubio_spectralcandidate_t **candidates; /** up to five candidates */
+ /* some scratch pads */
+ /** \bug (unnecessary copied from fftgrain?) */
+ fvec_t *newmag; /**< vec to store mag */
+ fvec_t *scratch; /**< vec to store modified mag */
+ fvec_t *scratch2; /**< vec to compute moving median */
+ fvec_t *theta; /**< vec to store phase */
+ smpl_t phasediff;
+ smpl_t phasefreq;
+ /** threshfn: name or handle of fn for computing adaptive threshold [median] */
+ /** aubio_thresholdfn_t thresholdfn; */
+ /** picker: name or handle of fn for picking event times [quadpick] */
+ /** aubio_pickerfn_t pickerfn; */
+};
+
+/** spectral peak object */
+struct _aubio_spectralpeak_t
+{
+ uint_t bin; /**< bin [0-(length-1)] */
+ smpl_t ebin; /**< estimated bin */
+ smpl_t mag; /**< peak magnitude */
+};
+
+/** spectral candidates array object */
+struct _aubio_spectralcandidate_t
+{
+ smpl_t ebin; /**< interpolated bin */
+ smpl_t *ecomb; /**< comb */
+ smpl_t ene; /**< candidate energy */
+ smpl_t len; /**< length */
+};
+
+
+void
+aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, const cvec_t * fftgrain, fvec_t * output)
+{
+ uint_t j;
+ smpl_t instfreq;
+ fvec_t *newmag = (fvec_t *) p->newmag;
+ //smpl_t hfc; //fe=instfreq(theta1,theta,ops); //theta1=theta;
+ /* copy incoming grain to newmag */
+ for (j = 0; j < newmag->length; j++)
+ newmag->data[j] = fftgrain->norm[j];
+ /* detect only if local energy > 10. */
+ //if (aubio_level_lin (newmag) * newmag->length > 10.) {
+ //hfc = fvec_local_hfc(newmag); //not used
+ aubio_pitchmcomb_spectral_pp (p, newmag);
+ aubio_pitchmcomb_combdet (p, newmag);
+ //aubio_pitchmcomb_sort_cand_freq(p->candidates,p->ncand);
+ //return p->candidates[p->goodcandidate]->ebin;
+ j = (uint_t) FLOOR (p->candidates[p->goodcandidate]->ebin + .5);
+ instfreq = aubio_unwrap2pi (fftgrain->phas[j]
+ - p->theta->data[j] - j * p->phasediff);
+ instfreq *= p->phasefreq;
+ /* store phase for next run */
+ for (j = 0; j < p->theta->length; j++) {
+ p->theta->data[j] = fftgrain->phas[j];
+ }
+ //return p->candidates[p->goodcandidate]->ebin;
+ output->data[0] =
+ FLOOR (p->candidates[p->goodcandidate]->ebin + .5) + instfreq;
+ /*} else {
+ return -1.;
+ } */
+}
+
+uint_t
+aubio_pitch_cands (aubio_pitchmcomb_t * p, const cvec_t * fftgrain, smpl_t * cands)
+{
+ uint_t j;
+ uint_t k;
+ fvec_t *newmag = (fvec_t *) p->newmag;
+ aubio_spectralcandidate_t **scands =
+ (aubio_spectralcandidate_t **) (p->candidates);
+ //smpl_t hfc; //fe=instfreq(theta1,theta,ops); //theta1=theta;
+ /* copy incoming grain to newmag */
+ for (j = 0; j < newmag->length; j++)
+ newmag->data[j] = fftgrain->norm[j];
+ /* detect only if local energy > 10. */
+ if (aubio_level_lin (newmag) * newmag->length > 10.) {
+ /* hfc = fvec_local_hfc(newmag); do not use */
+ aubio_pitchmcomb_spectral_pp (p, newmag);
+ aubio_pitchmcomb_combdet (p, newmag);
+ aubio_pitchmcomb_sort_cand_freq (scands, p->ncand);
+ /* store ncand comb energies in cands[1:ncand] */
+ for (k = 0; k < p->ncand; k++)
+ cands[k] = p->candidates[k]->ene;
+ /* store ncand[end] freq in cands[end] */
+ cands[p->ncand] = p->candidates[p->ncand - 1]->ebin;
+ return 1;
+ } else {
+ for (k = 0; k < p->ncand; k++)
+ cands[k] = 0;
+ return 0;
+ }
+}
+
+void
+aubio_pitchmcomb_spectral_pp (aubio_pitchmcomb_t * p, const fvec_t * newmag)
+{
+ fvec_t *mag = (fvec_t *) p->scratch;
+ fvec_t *tmp = (fvec_t *) p->scratch2;
+ uint_t j;
+ uint_t length = mag->length;
+ /* copy newmag to mag (scracth) */
+ for (j = 0; j < length; j++) {
+ mag->data[j] = newmag->data[j];
+ }
+ fvec_min_removal (mag); /* min removal */
+ fvec_alpha_normalise (mag, p->alpha); /* alpha normalisation */
+ /* skipped *//* low pass filtering */
+ /** \bug fvec_moving_thres may write out of bounds */
+ fvec_adapt_thres (mag, tmp, p->win_post, p->win_pre); /* adaptative threshold */
+ fvec_add (mag, -p->threshold); /* fixed threshold */
+ {
+ aubio_spectralpeak_t *peaks = (aubio_spectralpeak_t *) p->peaks;
+ uint_t count;
+ /* return bin and ebin */
+ count = aubio_pitchmcomb_quadpick (peaks, mag);
+ for (j = 0; j < count; j++)
+ peaks[j].mag = newmag->data[peaks[j].bin];
+ /* reset non peaks */
+ for (j = count; j < length; j++)
+ peaks[j].mag = 0.;
+ p->peaks = peaks;
+ p->count = count;
+ }
+}
+
+void
+aubio_pitchmcomb_combdet (aubio_pitchmcomb_t * p, const fvec_t * newmag)
+{
+ aubio_spectralpeak_t *peaks = (aubio_spectralpeak_t *) p->peaks;
+ aubio_spectralcandidate_t **candidate =
+ (aubio_spectralcandidate_t **) p->candidates;
+
+ /* parms */
+ uint_t N = p->npartials; /* maximum number of partials to be considered 10 */
+ uint_t M = p->ncand; /* maximum number of combs to be considered 5 */
+ uint_t length = newmag->length;
+ uint_t count = p->count;
+ uint_t k;
+ uint_t l;
+ uint_t d;
+ uint_t curlen = 0;
+
+ smpl_t delta2;
+ smpl_t xx;
+ uint_t position = 0;
+
+ uint_t root_peak = 0;
+ uint_t tmpl = 0;
+ smpl_t tmpene = 0.;
+
+ /* get the biggest peak in the spectrum */
+ root_peak = aubio_pitchmcomb_get_root_peak (peaks, count);
+ /* not enough partials in highest notes, could be forced */
+ //if (peaks[root_peak].ebin >= aubio_miditofreq(85.)/p->tau) N=2;
+ //if (peaks[root_peak].ebin >= aubio_miditofreq(90.)/p->tau) N=1;
+ /* now calculate the energy of each of the 5 combs */
+ for (l = 0; l < M; l++) {
+ smpl_t scaler = (1. / (l + 1.));
+ candidate[l]->ene = 0.; /* reset ene and len sums */
+ candidate[l]->len = 0.;
+ candidate[l]->ebin = scaler * peaks[root_peak].ebin;
+ /* if less than N peaks available, curlen < N */
+ if (candidate[l]->ebin != 0.)
+ curlen = (uint_t) FLOOR (length / (candidate[l]->ebin));
+ curlen = (N < curlen) ? N : curlen;
+ /* fill candidate[l]->ecomb[k] with (k+1)*candidate[l]->ebin */
+ for (k = 0; k < curlen; k++)
+ candidate[l]->ecomb[k] = (candidate[l]->ebin) * (k + 1.);
+ for (k = curlen; k < length; k++)
+ candidate[l]->ecomb[k] = 0.;
+ /* for each in candidate[l]->ecomb[k] */
+ for (k = 0; k < curlen; k++) {
+ xx = 100000.;
+ /** get the candidate->ecomb the closer to peaks.ebin
+ * (to cope with the inharmonicity)*/
+ for (d = 0; d < count; d++) {
+ delta2 = ABS (candidate[l]->ecomb[k] - peaks[d].ebin);
+ if (delta2 <= xx) {
+ position = d;
+ xx = delta2;
+ }
+ }
+ /* for a Q factor of 17, maintaining "constant Q filtering",
+ * and sum energy and length over non null combs */
+ if (17. * xx < candidate[l]->ecomb[k]) {
+ candidate[l]->ecomb[k] = peaks[position].ebin;
+ candidate[l]->ene += /* ecomb rounded to nearest int */
+ POW (newmag->data[(uint_t) FLOOR (candidate[l]->ecomb[k] + .5)],
+ 0.25);
+ candidate[l]->len += 1. / curlen;
+ } else
+ candidate[l]->ecomb[k] = 0.;
+ }
+ /* punishment */
+ /*if (candidate[l]->len<0.6)
+ candidate[l]->ene=0.; */
+ /* remember best candidate energy (in polyphonic, could check for
+ * tmpene*1.1 < candidate->ene to reduce jumps towards low frequencies) */
+ if (tmpene < candidate[l]->ene) {
+ tmpl = l;
+ tmpene = candidate[l]->ene;
+ }
+ }
+ //p->candidates=candidate;
+ //p->peaks=peaks;
+ p->goodcandidate = tmpl;
+}
+
+/** T=quadpick(X): return indices of elements of X which are peaks and positive
+ * exact peak positions are retrieved by quadratic interpolation
+ *
+ * \bug peak-picking too picky, sometimes counts too many peaks ?
+ */
+uint_t
+aubio_pitchmcomb_quadpick (aubio_spectralpeak_t * spectral_peaks, const fvec_t * X)
+{
+ uint_t j, ispeak, count = 0;
+ for (j = 1; j < X->length - 1; j++) {
+ ispeak = fvec_peakpick (X, j);
+ if (ispeak) {
+ count += ispeak;
+ spectral_peaks[count - 1].bin = j;
+ spectral_peaks[count - 1].ebin = fvec_quadratic_peak_pos (X, j);
+ }
+ }
+ return count;
+}
+
+/* get predominant partial */
+uint_t
+aubio_pitchmcomb_get_root_peak (aubio_spectralpeak_t * peaks, uint_t length)
+{
+ uint_t i, pos = 0;
+ smpl_t tmp = 0.;
+ for (i = 0; i < length; i++)
+ if (tmp <= peaks[i].mag) {
+ pos = i;
+ tmp = peaks[i].mag;
+ }
+ return pos;
+}
+
+void
+aubio_pitchmcomb_sort_peak (aubio_spectralpeak_t * peaks, uint_t nbins)
+{
+ qsort (peaks, nbins, sizeof (aubio_spectralpeak_t),
+ aubio_pitchmcomb_sort_peak_comp);
+}
+
+static sint_t
+aubio_pitchmcomb_sort_peak_comp (const void *x, const void *y)
+{
+ return (((aubio_spectralpeak_t *) y)->mag -
+ ((aubio_spectralpeak_t *) x)->mag);
+}
+
+
+void
+aubio_pitchmcomb_sort_cand_ene (aubio_spectralcandidate_t ** candidates,
+ uint_t nbins)
+{
+ uint_t cur = 0;
+ uint_t run = 0;
+ for (cur = 0; cur < nbins; cur++) {
+ for (run = cur + 1; run < nbins; run++) {
+ if (candidates[run]->ene > candidates[cur]->ene)
+ CAND_SWAP (candidates[run], candidates[cur]);
+ }
+ }
+}
+
+
+void
+aubio_pitchmcomb_sort_cand_freq (aubio_spectralcandidate_t ** candidates,
+ uint_t nbins)
+{
+ uint_t cur = 0;
+ uint_t run = 0;
+ for (cur = 0; cur < nbins; cur++) {
+ for (run = cur + 1; run < nbins; run++) {
+ if (candidates[run]->ebin < candidates[cur]->ebin)
+ CAND_SWAP (candidates[run], candidates[cur]);
+ }
+ }
+}
+
+aubio_pitchmcomb_t *
+new_aubio_pitchmcomb (uint_t bufsize, uint_t hopsize)
+{
+ aubio_pitchmcomb_t *p = AUBIO_NEW (aubio_pitchmcomb_t);
+ /* bug: should check if size / 8 > post+pre+1 */
+ uint_t i, j;
+ uint_t spec_size;
+ p->spec_partition = 2;
+ p->ncand = 5;
+ p->npartials = 5;
+ p->cutoff = 1.;
+ p->threshold = 0.01;
+ p->win_post = 8;
+ p->win_pre = 7;
+ // p->tau = samplerate/bufsize;
+ p->alpha = 9.;
+ p->goodcandidate = 0;
+ p->phasefreq = bufsize / hopsize / TWO_PI;
+ p->phasediff = TWO_PI * hopsize / bufsize;
+ spec_size = bufsize / p->spec_partition + 1;
+ //p->pickerfn = quadpick;
+ //p->biquad = new_biquad(0.1600,0.3200,0.1600, -0.5949, 0.2348);
+ /* allocate temp memory */
+ p->newmag = new_fvec (spec_size);
+ /* array for median */
+ p->scratch = new_fvec (spec_size);
+ /* array for phase */
+ p->theta = new_fvec (spec_size);
+ /* array for adaptative threshold */
+ p->scratch2 = new_fvec (p->win_post + p->win_pre + 1);
+ /* array of spectral peaks */
+ p->peaks = AUBIO_ARRAY (aubio_spectralpeak_t, spec_size);
+ for (i = 0; i < spec_size; i++) {
+ p->peaks[i].bin = 0.;
+ p->peaks[i].ebin = 0.;
+ p->peaks[i].mag = 0.;
+ }
+ /* array of pointers to spectral candidates */
+ p->candidates = AUBIO_ARRAY (aubio_spectralcandidate_t *, p->ncand);
+ for (i = 0; i < p->ncand; i++) {
+ p->candidates[i] = AUBIO_NEW (aubio_spectralcandidate_t);
+ p->candidates[i]->ecomb = AUBIO_ARRAY (smpl_t, spec_size);
+ for (j = 0; j < spec_size; j++) {
+ p->candidates[i]->ecomb[j] = 0.;
+ }
+ p->candidates[i]->ene = 0.;
+ p->candidates[i]->ebin = 0.;
+ p->candidates[i]->len = 0.;
+ }
+ return p;
+}
+
+
+void
+del_aubio_pitchmcomb (aubio_pitchmcomb_t * p)
+{
+ uint_t i;
+ del_fvec (p->newmag);
+ del_fvec (p->scratch);
+ del_fvec (p->theta);
+ del_fvec (p->scratch2);
+ AUBIO_FREE (p->peaks);
+ for (i = 0; i < p->ncand; i++) {
+ AUBIO_FREE (p->candidates[i]->ecomb);
+ AUBIO_FREE (p->candidates[i]);
+ }
+ AUBIO_FREE (p->candidates);
+ AUBIO_FREE (p);
+}
diff --git a/src/pitch/pitchmcomb.h b/src/pitch/pitchmcomb.h
new file mode 100644
index 0000000..88f117f
--- /dev/null
+++ b/src/pitch/pitchmcomb.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using multiple-comb filter
+
+ This fundamental frequency estimation algorithm implements spectral
+ flattening, multi-comb filtering and peak histogramming.
+
+ This method was designed by Juan P. Bello and described in:
+
+ Juan-Pablo Bello. ``Towards the Automated Analysis of Simple Polyphonic
+ Music''. PhD thesis, Centre for Digital Music, Queen Mary University of
+ London, London, UK, 2003.
+
+ \example pitch/test-pitchmcomb.c
+
+*/
+
+#ifndef AUBIO_PITCHMCOMB_H
+#define AUBIO_PITCHMCOMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchmcomb_t aubio_pitchmcomb_t;
+
+/** execute pitch detection on an input spectral frame
+
+ \param p pitch detection object as returned by new_aubio_pitchmcomb
+ \param in_fftgrain input signal spectrum as computed by aubio_pvoc_do
+ \param out_cands pitch candidate frequenciess, in bins
+
+*/
+void aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, const cvec_t * in_fftgrain,
+ fvec_t * out_cands);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+
+*/
+aubio_pitchmcomb_t *new_aubio_pitchmcomb (uint_t buf_size, uint_t hop_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+
+*/
+void del_aubio_pitchmcomb (aubio_pitchmcomb_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHMCOMB_H */
diff --git a/src/pitch/pitchschmitt.c b/src/pitch/pitchschmitt.c
new file mode 100644
index 0000000..06a34e8
--- /dev/null
+++ b/src/pitch/pitchschmitt.c
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2004, 2005 Mario Lang <mlang@delysid.org>
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "pitch/pitchschmitt.h"
+
+smpl_t aubio_schmittS16LE (aubio_pitchschmitt_t * p, uint_t nframes,
+ signed short int *indata);
+
+struct _aubio_pitchschmitt_t
+{
+ uint_t blockSize;
+ uint_t rate;
+ signed short int *schmittBuffer;
+ signed short int *schmittPointer;
+ signed short int *buf;
+};
+
+aubio_pitchschmitt_t *
+new_aubio_pitchschmitt (uint_t size)
+{
+ aubio_pitchschmitt_t *p = AUBIO_NEW (aubio_pitchschmitt_t);
+ p->blockSize = size;
+ p->schmittBuffer = AUBIO_ARRAY (signed short int, p->blockSize);
+ p->buf = AUBIO_ARRAY (signed short int, p->blockSize);
+ p->schmittPointer = p->schmittBuffer;
+ return p;
+}
+
+void
+aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, const fvec_t * input,
+ fvec_t * output)
+{
+ uint_t j;
+ for (j = 0; j < input->length; j++) {
+ p->buf[j] = input->data[j] * 32768.;
+ }
+ output->data[0] = aubio_schmittS16LE (p, input->length, p->buf);
+}
+
+smpl_t
+aubio_schmittS16LE (aubio_pitchschmitt_t * p, uint_t nframes,
+ signed short int *indata)
+{
+ uint_t i, j;
+ uint_t blockSize = p->blockSize;
+ signed short int *schmittBuffer = p->schmittBuffer;
+ signed short int *schmittPointer = p->schmittPointer;
+
+ smpl_t period = 0., trigfact = 0.6;
+
+ for (i = 0; i < nframes; i++) {
+ *schmittPointer++ = indata[i];
+ if (schmittPointer - schmittBuffer >= (sint_t) blockSize) {
+ sint_t endpoint, startpoint, t1, t2, A1, A2, tc, schmittTriggered;
+
+ schmittPointer = schmittBuffer;
+
+ for (j = 0, A1 = 0, A2 = 0; j < blockSize; j++) {
+ if (schmittBuffer[j] > 0 && A1 < schmittBuffer[j])
+ A1 = schmittBuffer[j];
+ if (schmittBuffer[j] < 0 && A2 < -schmittBuffer[j])
+ A2 = -schmittBuffer[j];
+ }
+ t1 = (sint_t) (A1 * trigfact + 0.5);
+ t2 = -(sint_t) (A2 * trigfact + 0.5);
+ startpoint = 0;
+ for (j = 1; j < blockSize && schmittBuffer[j] <= t1; j++);
+ for ( ; j < blockSize - 1 && !(schmittBuffer[j] >= t2 &&
+ schmittBuffer[j + 1] < t2); j++);
+ startpoint = j;
+ schmittTriggered = 0;
+ endpoint = startpoint + 1;
+ for (j = startpoint, tc = 0; j < blockSize; j++) {
+ if (!schmittTriggered) {
+ schmittTriggered = (schmittBuffer[j] >= t1);
+ } else if (schmittBuffer[j] >= t2 && schmittBuffer[j + 1] < t2) {
+ endpoint = j;
+ tc++;
+ schmittTriggered = 0;
+ }
+ }
+ if ((endpoint > startpoint) && (tc > 0)) {
+ period = (smpl_t) (endpoint - startpoint) / tc;
+ }
+ }
+ }
+
+ p->schmittBuffer = schmittBuffer;
+ p->schmittPointer = schmittPointer;
+ return period;
+}
+
+void
+del_aubio_pitchschmitt (aubio_pitchschmitt_t * p)
+{
+ AUBIO_FREE (p->schmittBuffer);
+ AUBIO_FREE (p->buf);
+ AUBIO_FREE (p);
+}
diff --git a/src/pitch/pitchschmitt.h b/src/pitch/pitchschmitt.h
new file mode 100644
index 0000000..db952c3
--- /dev/null
+++ b/src/pitch/pitchschmitt.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using a Schmitt trigger
+
+ This pitch extraction method implements a Schmitt trigger to estimate the
+ period of a signal.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \example pitch/test-pitchschmitt.c
+
+*/
+
+#ifndef AUBIO_PITCHSCHMITT_H
+#define AUBIO_PITCHSCHMITT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchschmitt_t aubio_pitchschmitt_t;
+
+/** execute pitch detection on an input buffer
+
+ \param p pitch detection object as returned by new_aubio_pitchschmitt
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period estimates, in samples
+
+*/
+void aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, const fvec_t * samples_in,
+ fvec_t * cands_out);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchschmitt_t *new_aubio_pitchschmitt (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchschmitt
+
+*/
+void del_aubio_pitchschmitt (aubio_pitchschmitt_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSCHMITT_H */
diff --git a/src/pitch/pitchspecacf.c b/src/pitch/pitchspecacf.c
new file mode 100644
index 0000000..a010041
--- /dev/null
+++ b/src/pitch/pitchspecacf.c
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+#include "pitch/pitchspecacf.h"
+
+/** pitch specacf structure */
+struct _aubio_pitchspecacf_t
+{
+ fvec_t *win; /**< temporal weighting window */
+ fvec_t *winput; /**< windowed spectrum */
+ aubio_fft_t *fft; /**< fft object to compute*/
+ fvec_t *fftout; /**< Fourier transform output */
+ fvec_t *sqrmag; /**< square magnitudes */
+ fvec_t *acf; /**< auto correlation function */
+ smpl_t tol; /**< tolerance */
+ smpl_t confidence; /**< confidence */
+};
+
+aubio_pitchspecacf_t *
+new_aubio_pitchspecacf (uint_t bufsize)
+{
+ aubio_pitchspecacf_t *p = AUBIO_NEW (aubio_pitchspecacf_t);
+ p->win = new_aubio_window ("hanningz", bufsize);
+ p->winput = new_fvec (bufsize);
+ p->fft = new_aubio_fft (bufsize);
+ p->fftout = new_fvec (bufsize);
+ p->sqrmag = new_fvec (bufsize);
+ p->acf = new_fvec (bufsize / 2 + 1);
+ p->tol = 1.;
+ p->confidence = 0.;
+ return p;
+}
+
+void
+aubio_pitchspecacf_do (aubio_pitchspecacf_t * p, const fvec_t * input, fvec_t * output)
+{
+ uint_t l, tau;
+ fvec_t *fftout = p->fftout;
+ // window the input
+ for (l = 0; l < input->length; l++) {
+ p->winput->data[l] = p->win->data[l] * input->data[l];
+ }
+ // get the real / imag parts of its fft
+ aubio_fft_do_complex (p->fft, p->winput, fftout);
+ for (l = 0; l < input->length / 2 + 1; l++) {
+ p->sqrmag->data[l] = SQR(fftout->data[l]);
+ }
+ // get the real / imag parts of the fft of the squared magnitude
+ aubio_fft_do_complex (p->fft, p->sqrmag, fftout);
+ // copy real part to acf
+ for (l = 0; l < fftout->length / 2 + 1; l++) {
+ p->acf->data[l] = fftout->data[l];
+ }
+ // get the minimum
+ tau = fvec_min_elem (p->acf);
+ // get the interpolated minimum
+ output->data[0] = fvec_quadratic_peak_pos (p->acf, tau) * 2.;
+}
+
+void
+del_aubio_pitchspecacf (aubio_pitchspecacf_t * p)
+{
+ del_fvec (p->win);
+ del_fvec (p->winput);
+ del_aubio_fft (p->fft);
+ del_fvec (p->sqrmag);
+ del_fvec (p->fftout);
+ AUBIO_FREE (p);
+}
+
+smpl_t
+aubio_pitchspecacf_get_confidence (const aubio_pitchspecacf_t * o) {
+ // no confidence for now
+ return o->confidence;
+}
+
+uint_t
+aubio_pitchspecacf_set_tolerance (aubio_pitchspecacf_t * p, smpl_t tol)
+{
+ p->tol = tol;
+ return 0;
+}
+
+smpl_t
+aubio_pitchspecacf_get_tolerance (const aubio_pitchspecacf_t * p)
+{
+ return p->tol;
+}
diff --git a/src/pitch/pitchspecacf.h b/src/pitch/pitchspecacf.h
new file mode 100644
index 0000000..e3c9c4c
--- /dev/null
+++ b/src/pitch/pitchspecacf.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using spectral auto correlation
+
+ This algorithm implements pitch detection by computing the autocorrelation
+ function as the cosine transform of the square spectral magnitudes.
+
+ Anssi Klapuri. Qualitative and quantitative aspects in the design of
+ periodicity esti- mation algorithms. In Proceedings of the European Signal
+ Processing Conference (EUSIPCO), 2000.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, Autocorrelation,
+ pp. 75-77, PhD thesis, Centre for Digital music, Queen Mary University of
+ London, London, UK, 2006.
+
+ \example pitch/test-pitchspecacf.c
+
+*/
+
+#ifndef AUBIO_PITCHSPECACF_H
+#define AUBIO_PITCHSPECACF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchspecacf_t aubio_pitchspecacf_t;
+
+/** execute pitch detection on an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchspecacf
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchspecacf_do (aubio_pitchspecacf_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchspecacf_t *new_aubio_pitchspecacf (uint_t buf_size);
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchspecacf()
+
+*/
+void del_aubio_pitchspecacf (aubio_pitchspecacf_t * o);
+
+/** get tolerance parameter for `specacf` pitch detection object
+
+ \param o pitch detection object
+
+ \return tolerance parameter for minima selection [default 1.]
+
+*/
+smpl_t aubio_pitchspecacf_get_tolerance (const aubio_pitchspecacf_t * o);
+
+/** set tolerance parameter for `specacf` pitch detection object
+
+ \param o pitch detection object
+ \param tol tolerance parameter for minima selection [default 1.]
+
+ \return `1` on error, `0` on success
+
+*/
+uint_t aubio_pitchspecacf_set_tolerance (aubio_pitchspecacf_t * o, smpl_t tol);
+
+/** get currenct confidence for `specacf` pitch detection object
+
+ \param o pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchspecacf_get_confidence (const aubio_pitchspecacf_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSPECACF_H */
diff --git a/src/pitch/pitchyin.c b/src/pitch/pitchyin.c
new file mode 100644
index 0000000..b65e3f7
--- /dev/null
+++ b/src/pitch/pitchyin.c
@@ -0,0 +1,182 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* This algorithm was developed by A. de Cheveigné and H. Kawahara and
+ * published in:
+ *
+ * de Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ * estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+ *
+ * see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+ */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "pitch/pitchyin.h"
+
+struct _aubio_pitchyin_t
+{
+ fvec_t *yin;
+ smpl_t tol;
+ smpl_t confidence;
+};
+
+/** compute difference function
+
+ \param input input signal
+ \param yinbuf output buffer to store difference function (half shorter than input)
+
+*/
+void aubio_pitchyin_diff (fvec_t * input, fvec_t * yinbuf);
+
+/** in place computation of the YIN cumulative normalised function
+
+ \param yinbuf input signal (a square difference function), also used to store function
+
+*/
+void aubio_pitchyin_getcum (fvec_t * yinbuf);
+
+/** detect pitch in a YIN function
+
+ \param yinbuf input buffer as computed by aubio_pitchyin_getcum
+
+*/
+uint_t aubio_pitchyin_getpitch (const fvec_t * yinbuf);
+
+aubio_pitchyin_t *
+new_aubio_pitchyin (uint_t bufsize)
+{
+ aubio_pitchyin_t *o = AUBIO_NEW (aubio_pitchyin_t);
+ o->yin = new_fvec (bufsize / 2);
+ o->tol = 0.15;
+ return o;
+}
+
+void
+del_aubio_pitchyin (aubio_pitchyin_t * o)
+{
+ del_fvec (o->yin);
+ AUBIO_FREE (o);
+}
+
+/* outputs the difference function */
+void
+aubio_pitchyin_diff (fvec_t * input, fvec_t * yin)
+{
+ uint_t j, tau;
+ smpl_t tmp;
+ for (tau = 0; tau < yin->length; tau++) {
+ yin->data[tau] = 0.;
+ }
+ for (tau = 1; tau < yin->length; tau++) {
+ for (j = 0; j < yin->length; j++) {
+ tmp = input->data[j] - input->data[j + tau];
+ yin->data[tau] += SQR (tmp);
+ }
+ }
+}
+
+/* cumulative mean normalized difference function */
+void
+aubio_pitchyin_getcum (fvec_t * yin)
+{
+ uint_t tau;
+ smpl_t tmp = 0.;
+ yin->data[0] = 1.;
+ //AUBIO_DBG("%f\t",yin->data[0]);
+ for (tau = 1; tau < yin->length; tau++) {
+ tmp += yin->data[tau];
+ yin->data[tau] *= tau / tmp;
+ //AUBIO_DBG("%f\t",yin->data[tau]);
+ }
+ //AUBIO_DBG("\n");
+}
+
+uint_t
+aubio_pitchyin_getpitch (const fvec_t * yin)
+{
+ uint_t tau = 1;
+ do {
+ if (yin->data[tau] < 0.1) {
+ while (yin->data[tau + 1] < yin->data[tau]) {
+ tau++;
+ }
+ return tau;
+ }
+ tau++;
+ } while (tau < yin->length);
+ //AUBIO_DBG("No pitch found");
+ return 0;
+}
+
+
+/* all the above in one */
+void
+aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * input, fvec_t * out)
+{
+ smpl_t tol = o->tol;
+ fvec_t *yin = o->yin;
+ uint_t j, tau = 0;
+ sint_t period;
+ smpl_t tmp = 0., tmp2 = 0.;
+ yin->data[0] = 1.;
+ for (tau = 1; tau < yin->length; tau++) {
+ yin->data[tau] = 0.;
+ for (j = 0; j < yin->length; j++) {
+ tmp = input->data[j] - input->data[j + tau];
+ yin->data[tau] += SQR (tmp);
+ }
+ tmp2 += yin->data[tau];
+ if (tmp2 != 0) {
+ yin->data[tau] *= tau / tmp2;
+ } else {
+ yin->data[tau] = 1.;
+ }
+ period = tau - 3;
+ if (tau > 4 && (yin->data[period] < tol) &&
+ (yin->data[period] < yin->data[period + 1])) {
+ out->data[0] = fvec_quadratic_peak_pos (yin, period);
+ goto beach;
+ }
+ }
+ out->data[0] = fvec_quadratic_peak_pos (yin, fvec_min_elem (yin));
+beach:
+ return;
+}
+
+smpl_t
+aubio_pitchyin_get_confidence (aubio_pitchyin_t * o) {
+ o->confidence = 1. - fvec_min (o->yin);
+ return o->confidence;
+}
+
+uint_t
+aubio_pitchyin_set_tolerance (aubio_pitchyin_t * o, smpl_t tol)
+{
+ o->tol = tol;
+ return 0;
+}
+
+smpl_t
+aubio_pitchyin_get_tolerance (aubio_pitchyin_t * o)
+{
+ return o->tol;
+}
diff --git a/src/pitch/pitchyin.h b/src/pitch/pitchyin.h
new file mode 100644
index 0000000..fa32b8d
--- /dev/null
+++ b/src/pitch/pitchyin.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using the YIN algorithm
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+ http://recherche.ircam.fr/equipes/pcm/cheveign/ps/2002_JASA_YIN_proof.pdf
+
+ \example pitch/test-pitchyin.c
+
+*/
+
+#ifndef AUBIO_PITCHYIN_H
+#define AUBIO_PITCHYIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyin_t aubio_pitchyin_t;
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyin_t *new_aubio_pitchyin (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+
+*/
+void del_aubio_pitchyin (aubio_pitchyin_t * o);
+
+/** execute pitch detection an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+
+
+/** set tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyin_set_tolerance (aubio_pitchyin_t * o, smpl_t tol);
+
+/** get tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyin_get_tolerance (aubio_pitchyin_t * o);
+
+/** get current confidence of YIN algorithm
+
+ \param o YIN pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchyin_get_confidence (aubio_pitchyin_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYIN_H */
diff --git a/src/pitch/pitchyinfft.c b/src/pitch/pitchyinfft.c
new file mode 100644
index 0000000..98de63c
--- /dev/null
+++ b/src/pitch/pitchyinfft.c
@@ -0,0 +1,197 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+#include "pitch/pitchyinfft.h"
+
+/** pitch yinfft structure */
+struct _aubio_pitchyinfft_t
+{
+ fvec_t *win; /**< temporal weighting window */
+ fvec_t *winput; /**< windowed spectrum */
+ fvec_t *sqrmag; /**< square difference function */
+ fvec_t *weight; /**< spectral weighting window (psychoacoustic model) */
+ fvec_t *fftout; /**< Fourier transform output */
+ aubio_fft_t *fft; /**< fft object to compute square difference function */
+ fvec_t *yinfft; /**< Yin function */
+ smpl_t tol; /**< Yin tolerance */
+ smpl_t confidence; /**< confidence */
+ uint_t short_period; /** shortest period under which to check for octave error */
+};
+
+static const smpl_t freqs[] = {
+ 0., 20., 25., 31.5, 40., 50., 63., 80., 100., 125.,
+ 160., 200., 250., 315., 400., 500., 630., 800., 1000., 1250.,
+ 1600., 2000., 2500., 3150., 4000., 5000., 6300., 8000., 9000., 10000.,
+ 12500., 15000., 20000., 25100
+};
+
+static const smpl_t weight[] = {
+ -75.8, -70.1, -60.8, -52.1, -44.2, -37.5, -31.3, -25.6, -20.9, -16.5,
+ -12.6, -9.60, -7.00, -4.70, -3.00, -1.80, -0.80, -0.20, -0.00, 0.50,
+ 1.60, 3.20, 5.40, 7.80, 8.10, 5.30, -2.40, -11.1, -12.8, -12.2,
+ -7.40, -17.8, -17.8, -17.8
+};
+
+aubio_pitchyinfft_t *
+new_aubio_pitchyinfft (uint_t samplerate, uint_t bufsize)
+{
+ uint_t i = 0, j = 1;
+ smpl_t freq = 0, a0 = 0, a1 = 0, f0 = 0, f1 = 0;
+ aubio_pitchyinfft_t *p = AUBIO_NEW (aubio_pitchyinfft_t);
+ p->winput = new_fvec (bufsize);
+ p->fft = new_aubio_fft (bufsize);
+ p->fftout = new_fvec (bufsize);
+ p->sqrmag = new_fvec (bufsize);
+ p->yinfft = new_fvec (bufsize / 2 + 1);
+ p->tol = 0.85;
+ p->win = new_aubio_window ("hanningz", bufsize);
+ p->weight = new_fvec (bufsize / 2 + 1);
+ for (i = 0; i < p->weight->length; i++) {
+ freq = (smpl_t) i / (smpl_t) bufsize *(smpl_t) samplerate;
+ while (freq > freqs[j]) {
+ j += 1;
+ }
+ a0 = weight[j - 1];
+ f0 = freqs[j - 1];
+ a1 = weight[j];
+ f1 = freqs[j];
+ if (f0 == f1) { // just in case
+ p->weight->data[i] = a0;
+ } else if (f0 == 0) { // y = ax+b
+ p->weight->data[i] = (a1 - a0) / f1 * freq + a0;
+ } else {
+ p->weight->data[i] = (a1 - a0) / (f1 - f0) * freq +
+ (a0 - (a1 - a0) / (f1 / f0 - 1.));
+ }
+ while (freq > freqs[j]) {
+ j += 1;
+ }
+ //AUBIO_DBG("%f\n",p->weight->data[i]);
+ p->weight->data[i] = DB2LIN (p->weight->data[i]);
+ //p->weight->data[i] = SQRT(DB2LIN(p->weight->data[i]));
+ }
+ // check for octave errors above 1300 Hz
+ p->short_period = (uint_t)ROUND(samplerate / 1300.);
+ return p;
+}
+
+void
+aubio_pitchyinfft_do (aubio_pitchyinfft_t * p, const fvec_t * input, fvec_t * output)
+{
+ uint_t tau, l;
+ uint_t length = p->fftout->length;
+ uint_t halfperiod;
+ fvec_t *fftout = p->fftout;
+ fvec_t *yin = p->yinfft;
+ smpl_t tmp = 0., sum = 0.;
+ // window the input
+ fvec_weighted_copy(input, p->win, p->winput);
+ // get the real / imag parts of its fft
+ aubio_fft_do_complex (p->fft, p->winput, fftout);
+ // get the squared magnitude spectrum, applying some weight
+ p->sqrmag->data[0] = SQR(fftout->data[0]);
+ p->sqrmag->data[0] *= p->weight->data[0];
+ for (l = 1; l < length / 2; l++) {
+ p->sqrmag->data[l] = SQR(fftout->data[l]) + SQR(fftout->data[length - l]);
+ p->sqrmag->data[l] *= p->weight->data[l];
+ p->sqrmag->data[length - l] = p->sqrmag->data[l];
+ }
+ p->sqrmag->data[length / 2] = SQR(fftout->data[length / 2]);
+ p->sqrmag->data[length / 2] *= p->weight->data[length / 2];
+ // get sum of weighted squared mags
+ for (l = 0; l < length / 2 + 1; l++) {
+ sum += p->sqrmag->data[l];
+ }
+ sum *= 2.;
+ // get the real / imag parts of the fft of the squared magnitude
+ aubio_fft_do_complex (p->fft, p->sqrmag, fftout);
+ yin->data[0] = 1.;
+ for (tau = 1; tau < yin->length; tau++) {
+ // compute the square differences
+ yin->data[tau] = sum - fftout->data[tau];
+ // and the cumulative mean normalized difference function
+ tmp += yin->data[tau];
+ if (tmp != 0) {
+ yin->data[tau] *= tau / tmp;
+ } else {
+ yin->data[tau] = 1.;
+ }
+ }
+ // find best candidates
+ tau = fvec_min_elem (yin);
+ if (yin->data[tau] < p->tol) {
+ // no interpolation, directly return the period as an integer
+ //output->data[0] = tau;
+ //return;
+
+ // 3 point quadratic interpolation
+ //return fvec_quadratic_peak_pos (yin,tau,1);
+ /* additional check for (unlikely) octave doubling in higher frequencies */
+ if (tau > p->short_period) {
+ output->data[0] = fvec_quadratic_peak_pos (yin, tau);
+ } else {
+ /* should compare the minimum value of each interpolated peaks */
+ halfperiod = FLOOR (tau / 2 + .5);
+ if (yin->data[halfperiod] < p->tol)
+ output->data[0] = fvec_quadratic_peak_pos (yin, halfperiod);
+ else
+ output->data[0] = fvec_quadratic_peak_pos (yin, tau);
+ }
+ } else {
+ output->data[0] = 0.;
+ }
+}
+
+void
+del_aubio_pitchyinfft (aubio_pitchyinfft_t * p)
+{
+ del_fvec (p->win);
+ del_aubio_fft (p->fft);
+ del_fvec (p->yinfft);
+ del_fvec (p->sqrmag);
+ del_fvec (p->fftout);
+ del_fvec (p->winput);
+ del_fvec (p->weight);
+ AUBIO_FREE (p);
+}
+
+smpl_t
+aubio_pitchyinfft_get_confidence (aubio_pitchyinfft_t * o) {
+ o->confidence = 1. - fvec_min (o->yinfft);
+ return o->confidence;
+}
+
+uint_t
+aubio_pitchyinfft_set_tolerance (aubio_pitchyinfft_t * p, smpl_t tol)
+{
+ p->tol = tol;
+ return 0;
+}
+
+smpl_t
+aubio_pitchyinfft_get_tolerance (aubio_pitchyinfft_t * p)
+{
+ return p->tol;
+}
diff --git a/src/pitch/pitchyinfft.h b/src/pitch/pitchyinfft.h
new file mode 100644
index 0000000..ccd4e51
--- /dev/null
+++ b/src/pitch/pitchyinfft.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Pitch detection using a spectral implementation of the YIN algorithm
+
+ This algorithm was derived from the YIN algorithm. In this implementation, a
+ Fourier transform is used to compute a tapered square difference function,
+ which allows spectral weighting. Because the difference function is tapered,
+ the selection of the period is simplified.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, PhD thesis,
+ Centre for Digital music, Queen Mary University of London, London, UK, 2006.
+
+ \example pitch/test-pitchyinfft.c
+
+*/
+
+#ifndef AUBIO_PITCHYINFFT_H
+#define AUBIO_PITCHYINFFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyinfft_t aubio_pitchyinfft_t;
+
+/** execute pitch detection on an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchyinfft
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyinfft_do (aubio_pitchyinfft_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+/** creation of the pitch detection object
+
+ \param samplerate samplerate of the input signal
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyinfft_t *new_aubio_pitchyinfft (uint_t samplerate, uint_t buf_size);
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchyinfft()
+
+*/
+void del_aubio_pitchyinfft (aubio_pitchyinfft_t * o);
+
+/** get tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+
+ \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyinfft_get_tolerance (aubio_pitchyinfft_t * o);
+
+/** set tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyinfft_set_tolerance (aubio_pitchyinfft_t * o, smpl_t tol);
+
+/** get current confidence of YIN algorithm
+
+ \param o YIN pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchyinfft_get_confidence (aubio_pitchyinfft_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYINFFT_H */
diff --git a/src/spectral/fft.c b/src/spectral/fft.c
new file mode 100644
index 0000000..e8dfc1a
--- /dev/null
+++ b/src/spectral/fft.c
@@ -0,0 +1,402 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+
+#ifdef HAVE_FFTW3 // using FFTW3
+/* note that <complex.h> is not included here but only in aubio_priv.h, so that
+ * c++ projects can still use their own complex definition. */
+#include <fftw3.h>
+#include <pthread.h>
+
+#ifdef HAVE_COMPLEX_H
+#ifdef HAVE_FFTW3F
+/** fft data type with complex.h and fftw3f */
+#define FFTW_TYPE fftwf_complex
+#else
+/** fft data type with complex.h and fftw3 */
+#define FFTW_TYPE fftw_complex
+#endif
+#else
+#ifdef HAVE_FFTW3F
+/** fft data type without complex.h and with fftw3f */
+#define FFTW_TYPE float
+#else
+/** fft data type without complex.h and with fftw */
+#define FFTW_TYPE double
+#endif
+#endif
+
+/** fft data type */
+typedef FFTW_TYPE fft_data_t;
+
+#ifdef HAVE_FFTW3F
+#define fftw_malloc fftwf_malloc
+#define fftw_free fftwf_free
+#define fftw_execute fftwf_execute
+#define fftw_plan_dft_r2c_1d fftwf_plan_dft_r2c_1d
+#define fftw_plan_dft_c2r_1d fftwf_plan_dft_c2r_1d
+#define fftw_plan_r2r_1d fftwf_plan_r2r_1d
+#define fftw_plan fftwf_plan
+#define fftw_destroy_plan fftwf_destroy_plan
+#endif
+
+#ifdef HAVE_FFTW3F
+#if HAVE_AUBIO_DOUBLE
+#error "Using aubio in double precision with fftw3 in single precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#define real_t float
+#elif defined (HAVE_FFTW3) /* HAVE_FFTW3F */
+#if !HAVE_AUBIO_DOUBLE
+#error "Using aubio in single precision with fftw3 in double precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#define real_t double
+#endif /* HAVE_FFTW3F */
+
+// a global mutex for FFTW thread safety
+pthread_mutex_t aubio_fftw_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#else
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+// https://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html
+#include <Accelerate/Accelerate.h>
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_vDSP_ctoz vDSP_ctoz
+#define aubio_vDSP_fft_zrip vDSP_fft_zrip
+#define aubio_vDSP_ztoc vDSP_ztoc
+#define aubio_vDSP_zvmags vDSP_zvmags
+#define aubio_vDSP_zvphas vDSP_zvphas
+#define aubio_vDSP_vsadd vDSP_vsadd
+#define aubio_vDSP_vsmul vDSP_vsmul
+#define aubio_vDSP_create_fftsetup vDSP_create_fftsetup
+#define aubio_vDSP_destroy_fftsetup vDSP_destroy_fftsetup
+#define aubio_DSPComplex DSPComplex
+#define aubio_DSPSplitComplex DSPSplitComplex
+#define aubio_FFTSetup FFTSetup
+#define aubio_vvsqrt vvsqrtf
+#else
+#define aubio_vDSP_ctoz vDSP_ctozD
+#define aubio_vDSP_fft_zrip vDSP_fft_zripD
+#define aubio_vDSP_ztoc vDSP_ztocD
+#define aubio_vDSP_zvmags vDSP_zvmagsD
+#define aubio_vDSP_zvphas vDSP_zvphasD
+#define aubio_vDSP_vsadd vDSP_vsaddD
+#define aubio_vDSP_vsmul vDSP_vsmulD
+#define aubio_vDSP_create_fftsetup vDSP_create_fftsetupD
+#define aubio_vDSP_destroy_fftsetup vDSP_destroy_fftsetupD
+#define aubio_DSPComplex DSPDoubleComplex
+#define aubio_DSPSplitComplex DSPDoubleSplitComplex
+#define aubio_FFTSetup FFTSetupD
+#define aubio_vvsqrt vvsqrt
+#endif /* HAVE_AUBIO_DOUBLE */
+
+#else // using OOURA
+// let's use ooura instead
+extern void rdft(int, int, smpl_t *, int *, smpl_t *);
+
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+
+struct _aubio_fft_t {
+ uint_t winsize;
+ uint_t fft_size;
+#ifdef HAVE_FFTW3 // using FFTW3
+ real_t *in, *out;
+ fftw_plan pfw, pbw;
+ fft_data_t * specdata; /* complex spectral data */
+#else
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+ int log2fftsize;
+ aubio_FFTSetup fftSetup;
+ aubio_DSPSplitComplex spec;
+ smpl_t *in, *out;
+#else // using OOURA
+ smpl_t *in, *out;
+ smpl_t *w;
+ int *ip;
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+ fvec_t * compspec;
+};
+
+aubio_fft_t * new_aubio_fft (uint_t winsize) {
+ aubio_fft_t * s = AUBIO_NEW(aubio_fft_t);
+ if ((sint_t)winsize < 2) {
+ AUBIO_ERR("fft: got winsize %d, but can not be < 2\n", winsize);
+ goto beach;
+ }
+#ifdef HAVE_FFTW3
+ uint_t i;
+ s->winsize = winsize;
+ /* allocate memory */
+ s->in = AUBIO_ARRAY(real_t,winsize);
+ s->out = AUBIO_ARRAY(real_t,winsize);
+ s->compspec = new_fvec(winsize);
+ /* create plans */
+ pthread_mutex_lock(&aubio_fftw_mutex);
+#ifdef HAVE_COMPLEX_H
+ s->fft_size = winsize/2 + 1;
+ s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
+ s->pfw = fftw_plan_dft_r2c_1d(winsize, s->in, s->specdata, FFTW_ESTIMATE);
+ s->pbw = fftw_plan_dft_c2r_1d(winsize, s->specdata, s->out, FFTW_ESTIMATE);
+#else
+ s->fft_size = winsize;
+ s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
+ s->pfw = fftw_plan_r2r_1d(winsize, s->in, s->specdata, FFTW_R2HC, FFTW_ESTIMATE);
+ s->pbw = fftw_plan_r2r_1d(winsize, s->specdata, s->out, FFTW_HC2R, FFTW_ESTIMATE);
+#endif
+ pthread_mutex_unlock(&aubio_fftw_mutex);
+ for (i = 0; i < s->winsize; i++) {
+ s->in[i] = 0.;
+ s->out[i] = 0.;
+ }
+ for (i = 0; i < s->fft_size; i++) {
+ s->specdata[i] = 0.;
+ }
+#else
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+ s->winsize = winsize;
+ s->fft_size = winsize;
+ s->compspec = new_fvec(winsize);
+ s->log2fftsize = (uint_t)log2f(s->fft_size);
+ s->in = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->out = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->spec.realp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
+ s->spec.imagp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
+ s->fftSetup = aubio_vDSP_create_fftsetup(s->log2fftsize, FFT_RADIX2);
+#else // using OOURA
+ if (aubio_is_power_of_two(winsize) != 1) {
+ AUBIO_ERR("fft: can only create with sizes power of two,"
+ " requested %d\n", winsize);
+ goto beach;
+ }
+ s->winsize = winsize;
+ s->fft_size = winsize / 2 + 1;
+ s->compspec = new_fvec(winsize);
+ s->in = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->out = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->ip = AUBIO_ARRAY(int , s->fft_size);
+ s->w = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->ip[0] = 0;
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+ return s;
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+void del_aubio_fft(aubio_fft_t * s) {
+ /* destroy data */
+ del_fvec(s->compspec);
+#ifdef HAVE_FFTW3 // using FFTW3
+ fftw_destroy_plan(s->pfw);
+ fftw_destroy_plan(s->pbw);
+ fftw_free(s->specdata);
+#else /* HAVE_FFTW3 */
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+ AUBIO_FREE(s->spec.realp);
+ AUBIO_FREE(s->spec.imagp);
+ aubio_vDSP_destroy_fftsetup(s->fftSetup);
+#else // using OOURA
+ AUBIO_FREE(s->w);
+ AUBIO_FREE(s->ip);
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+ AUBIO_FREE(s->out);
+ AUBIO_FREE(s->in);
+ AUBIO_FREE(s);
+}
+
+void aubio_fft_do(aubio_fft_t * s, const fvec_t * input, cvec_t * spectrum) {
+ aubio_fft_do_complex(s, input, s->compspec);
+ aubio_fft_get_spectrum(s->compspec, spectrum);
+}
+
+void aubio_fft_rdo(aubio_fft_t * s, const cvec_t * spectrum, fvec_t * output) {
+ aubio_fft_get_realimag(spectrum, s->compspec);
+ aubio_fft_rdo_complex(s, s->compspec, output);
+}
+
+void aubio_fft_do_complex(aubio_fft_t * s, const fvec_t * input, fvec_t * compspec) {
+ uint_t i;
+#ifndef HAVE_MEMCPY_HACKS
+ for (i=0; i < s->winsize; i++) {
+ s->in[i] = input->data[i];
+ }
+#else
+ memcpy(s->in, input->data, s->winsize * sizeof(smpl_t));
+#endif /* HAVE_MEMCPY_HACKS */
+#ifdef HAVE_FFTW3 // using FFTW3
+ fftw_execute(s->pfw);
+#ifdef HAVE_COMPLEX_H
+ compspec->data[0] = REAL(s->specdata[0]);
+ for (i = 1; i < s->fft_size -1 ; i++) {
+ compspec->data[i] = REAL(s->specdata[i]);
+ compspec->data[compspec->length - i] = IMAG(s->specdata[i]);
+ }
+ compspec->data[s->fft_size-1] = REAL(s->specdata[s->fft_size-1]);
+#else /* HAVE_COMPLEX_H */
+ for (i = 0; i < s->fft_size; i++) {
+ compspec->data[i] = s->specdata[i];
+ }
+#endif /* HAVE_COMPLEX_H */
+#else /* HAVE_FFTW3 */
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+ // convert real data to even/odd format used in vDSP
+ aubio_vDSP_ctoz((aubio_DSPComplex*)s->in, 2, &s->spec, 1, s->fft_size/2);
+ // compute the FFT
+ aubio_vDSP_fft_zrip(s->fftSetup, &s->spec, 1, s->log2fftsize, FFT_FORWARD);
+ // convert from vDSP complex split to [ r0, r1, ..., rN, iN-1, .., i2, i1]
+ compspec->data[0] = s->spec.realp[0];
+ compspec->data[s->fft_size / 2] = s->spec.imagp[0];
+ for (i = 1; i < s->fft_size / 2; i++) {
+ compspec->data[i] = s->spec.realp[i];
+ compspec->data[s->fft_size - i] = s->spec.imagp[i];
+ }
+ // apply scaling
+ smpl_t scale = 1./2.;
+ aubio_vDSP_vsmul(compspec->data, 1, &scale, compspec->data, 1, s->fft_size);
+#else // using OOURA
+ rdft(s->winsize, 1, s->in, s->ip, s->w);
+ compspec->data[0] = s->in[0];
+ compspec->data[s->winsize / 2] = s->in[1];
+ for (i = 1; i < s->fft_size - 1; i++) {
+ compspec->data[i] = s->in[2 * i];
+ compspec->data[s->winsize - i] = - s->in[2 * i + 1];
+ }
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+}
+
+void aubio_fft_rdo_complex(aubio_fft_t * s, const fvec_t * compspec, fvec_t * output) {
+ uint_t i;
+#ifdef HAVE_FFTW3
+ const smpl_t renorm = 1./(smpl_t)s->winsize;
+#ifdef HAVE_COMPLEX_H
+ s->specdata[0] = compspec->data[0];
+ for (i=1; i < s->fft_size - 1; i++) {
+ s->specdata[i] = compspec->data[i] +
+ I * compspec->data[compspec->length - i];
+ }
+ s->specdata[s->fft_size - 1] = compspec->data[s->fft_size - 1];
+#else
+ for (i=0; i < s->fft_size; i++) {
+ s->specdata[i] = compspec->data[i];
+ }
+#endif
+ fftw_execute(s->pbw);
+ for (i = 0; i < output->length; i++) {
+ output->data[i] = s->out[i]*renorm;
+ }
+#else /* HAVE_FFTW3 */
+#ifdef HAVE_ACCELERATE // using ACCELERATE
+ // convert from real imag [ r0, r1, ..., rN, iN-1, .., i2, i1]
+ // to vDSP packed format [ r0, rN, r1, i1, ..., rN-1, iN-1 ]
+ s->out[0] = compspec->data[0];
+ s->out[1] = compspec->data[s->winsize / 2];
+ for (i = 1; i < s->fft_size / 2; i++) {
+ s->out[2 * i] = compspec->data[i];
+ s->out[2 * i + 1] = compspec->data[s->winsize - i];
+ }
+ // convert to split complex format used in vDSP
+ aubio_vDSP_ctoz((aubio_DSPComplex*)s->out, 2, &s->spec, 1, s->fft_size/2);
+ // compute the FFT
+ aubio_vDSP_fft_zrip(s->fftSetup, &s->spec, 1, s->log2fftsize, FFT_INVERSE);
+ // convert result to real output
+ aubio_vDSP_ztoc(&s->spec, 1, (aubio_DSPComplex*)output->data, 2, s->fft_size/2);
+ // apply scaling
+ smpl_t scale = 1.0 / s->winsize;
+ aubio_vDSP_vsmul(output->data, 1, &scale, output->data, 1, s->fft_size);
+#else // using OOURA
+ smpl_t scale = 2.0 / s->winsize;
+ s->out[0] = compspec->data[0];
+ s->out[1] = compspec->data[s->winsize / 2];
+ for (i = 1; i < s->fft_size - 1; i++) {
+ s->out[2 * i] = compspec->data[i];
+ s->out[2 * i + 1] = - compspec->data[s->winsize - i];
+ }
+ rdft(s->winsize, -1, s->out, s->ip, s->w);
+ for (i=0; i < s->winsize; i++) {
+ output->data[i] = s->out[i] * scale;
+ }
+#endif /* HAVE_ACCELERATE */
+#endif /* HAVE_FFTW3 */
+}
+
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum) {
+ aubio_fft_get_phas(compspec, spectrum);
+ aubio_fft_get_norm(compspec, spectrum);
+}
+
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec) {
+ aubio_fft_get_imag(spectrum, compspec);
+ aubio_fft_get_real(spectrum, compspec);
+}
+
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum) {
+ uint_t i;
+ if (compspec->data[0] < 0) {
+ spectrum->phas[0] = PI;
+ } else {
+ spectrum->phas[0] = 0.;
+ }
+ for (i=1; i < spectrum->length - 1; i++) {
+ spectrum->phas[i] = ATAN2(compspec->data[compspec->length-i],
+ compspec->data[i]);
+ }
+ if (compspec->data[compspec->length/2] < 0) {
+ spectrum->phas[spectrum->length - 1] = PI;
+ } else {
+ spectrum->phas[spectrum->length - 1] = 0.;
+ }
+}
+
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum) {
+ uint_t i = 0;
+ spectrum->norm[0] = ABS(compspec->data[0]);
+ for (i=1; i < spectrum->length - 1; i++) {
+ spectrum->norm[i] = SQRT(SQR(compspec->data[i])
+ + SQR(compspec->data[compspec->length - i]) );
+ }
+ spectrum->norm[spectrum->length-1] =
+ ABS(compspec->data[compspec->length/2]);
+}
+
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec) {
+ uint_t i;
+ for (i = 1; i < ( compspec->length + 1 ) / 2 /*- 1 + 1*/; i++) {
+ compspec->data[compspec->length - i] =
+ spectrum->norm[i]*SIN(spectrum->phas[i]);
+ }
+}
+
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec) {
+ uint_t i;
+ for (i = 0; i < compspec->length / 2 + 1; i++) {
+ compspec->data[i] =
+ spectrum->norm[i]*COS(spectrum->phas[i]);
+ }
+}
diff --git a/src/spectral/fft.h b/src/spectral/fft.h
new file mode 100644
index 0000000..9c8a99c
--- /dev/null
+++ b/src/spectral/fft.h
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Fast Fourier Transform
+
+ Depending on how aubio was compiled, FFT are computed using one of:
+ - [Ooura](http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html)
+ - [FFTW3](http://www.fftw.org)
+ - [vDSP](https://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html)
+
+ \example src/spectral/test-fft.c
+
+*/
+
+#ifndef AUBIO_FFT_H
+#define AUBIO_FFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** FFT object
+
+ This object computes forward and backward FFTs.
+
+*/
+typedef struct _aubio_fft_t aubio_fft_t;
+
+/** create new FFT computation object
+
+ \param size length of the FFT
+
+*/
+aubio_fft_t * new_aubio_fft (uint_t size);
+/** delete FFT object
+
+ \param s fft object as returned by new_aubio_fft
+
+*/
+void del_aubio_fft(aubio_fft_t * s);
+
+/** compute forward FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param input input signal
+ \param spectrum output spectrum
+
+*/
+void aubio_fft_do (aubio_fft_t *s, const fvec_t * input, cvec_t * spectrum);
+/** compute backward (inverse) FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param spectrum input spectrum
+ \param output output signal
+
+*/
+void aubio_fft_rdo (aubio_fft_t *s, const cvec_t * spectrum, fvec_t * output);
+
+/** compute forward FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param input real input signal
+ \param compspec complex output fft real/imag
+
+*/
+void aubio_fft_do_complex (aubio_fft_t *s, const fvec_t * input, fvec_t * compspec);
+/** compute backward (inverse) FFT from real/imag
+
+ \param s fft object as returned by new_aubio_fft
+ \param compspec real/imag input fft array
+ \param output real output array
+
+*/
+void aubio_fft_rdo_complex (aubio_fft_t *s, const fvec_t * compspec, fvec_t * output);
+
+/** convert real/imag spectrum to norm/phas spectrum
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum);
+/** convert real/imag spectrum to norm/phas spectrum
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec);
+
+/** compute phas spectrum from real/imag parts
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum);
+/** compute imaginary part from the norm/phas cvec
+
+ \param spectrum norm/phas input array
+ \param compspec real/imag output fft array
+
+*/
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec);
+
+/** compute norm component from real/imag parts
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum);
+/** compute real part from norm/phas components
+
+ \param spectrum norm/phas input array
+ \param compspec real/imag output fft array
+
+*/
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FFT_H */
diff --git a/src/spectral/filterbank.c b/src/spectral/filterbank.c
new file mode 100644
index 0000000..0323700
--- /dev/null
+++ b/src/spectral/filterbank.c
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "cvec.h"
+#include "spectral/filterbank.h"
+#include "mathutils.h"
+
+/** \brief A structure to store a set of n_filters filters of lenghts win_s */
+struct _aubio_filterbank_t
+{
+ uint_t win_s;
+ uint_t n_filters;
+ fmat_t *filters;
+};
+
+aubio_filterbank_t *
+new_aubio_filterbank (uint_t n_filters, uint_t win_s)
+{
+ /* allocate space for filterbank object */
+ aubio_filterbank_t *fb = AUBIO_NEW (aubio_filterbank_t);
+ fb->win_s = win_s;
+ fb->n_filters = n_filters;
+
+ /* allocate filter tables, a matrix of length win_s and of height n_filters */
+ fb->filters = new_fmat (n_filters, win_s / 2 + 1);
+
+ return fb;
+}
+
+void
+del_aubio_filterbank (aubio_filterbank_t * fb)
+{
+ del_fmat (fb->filters);
+ AUBIO_FREE (fb);
+}
+
+void
+aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out)
+{
+ /* apply filter to all input channel, provided out has enough channels */
+ //uint_t max_filters = MIN (f->n_filters, out->length);
+ //uint_t max_length = MIN (in->length, f->filters->length);
+
+ // view cvec->norm as fvec->data
+ fvec_t tmp;
+ tmp.length = in->length;
+ tmp.data = in->norm;
+
+ fmat_vecmul(f->filters, &tmp, out);
+
+ return;
+}
+
+fmat_t *
+aubio_filterbank_get_coeffs (const aubio_filterbank_t * f)
+{
+ return f->filters;
+}
+
+uint_t
+aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filter_coeffs)
+{
+ fmat_copy(filter_coeffs, f->filters);
+ return 0;
+}
diff --git a/src/spectral/filterbank.h b/src/spectral/filterbank.h
new file mode 100644
index 0000000..769b5e7
--- /dev/null
+++ b/src/spectral/filterbank.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Filterbank object
+
+ General-purpose spectral filterbank object.
+
+ \example spectral/test-filterbank.c
+
+*/
+
+#ifndef AUBIO_FILTERBANK_H
+#define AUBIO_FILTERBANK_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** filterbank object
+
+ This object stores a matrix of spectral filter coefficients.
+
+ */
+typedef struct _aubio_filterbank_t aubio_filterbank_t;
+
+/** create filterbank object
+
+ \param n_filters number of filters to create
+ \param win_s size of analysis buffer (and length the FFT transform)
+
+*/
+aubio_filterbank_t *new_aubio_filterbank (uint_t n_filters, uint_t win_s);
+
+/** destroy filterbank object
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+
+*/
+void del_aubio_filterbank (aubio_filterbank_t * f);
+
+/** compute filterbank
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param in input spectrum containing an input spectrum of length `win_s`
+ \param out output vector containing the energy found in each band, `nfilt` output values
+
+*/
+void aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out);
+
+/** return a pointer to the matrix object containing all filter coefficients
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+
+ */
+fmat_t *aubio_filterbank_get_coeffs (const aubio_filterbank_t * f);
+
+/** copy filter coefficients to the filterbank
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param filters filter bank coefficients to copy from
+
+ */
+uint_t aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filters);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTERBANK_H */
diff --git a/src/spectral/filterbank_mel.c b/src/spectral/filterbank_mel.c
new file mode 100644
index 0000000..f059540
--- /dev/null
+++ b/src/spectral/filterbank_mel.c
@@ -0,0 +1,207 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/filterbank.h"
+#include "spectral/filterbank_mel.h"
+#include "mathutils.h"
+
+uint_t
+aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
+ const fvec_t * freqs, smpl_t samplerate)
+{
+
+ fmat_t *filters = aubio_filterbank_get_coeffs (fb);
+ uint_t n_filters = filters->height, win_s = filters->length;
+ fvec_t *lower_freqs, *upper_freqs, *center_freqs;
+ fvec_t *triangle_heights, *fft_freqs;
+
+ uint_t fn; /* filter counter */
+ uint_t bin; /* bin counter */
+
+ smpl_t riseInc, downInc;
+
+ /* freqs define the bands of triangular overlapping windows.
+ throw a warning if filterbank object fb is too short. */
+ if (freqs->length - 2 > n_filters) {
+ AUBIO_WRN ("not enough filters, %d allocated but %d requested\n",
+ n_filters, freqs->length - 2);
+ }
+
+ if (freqs->length - 2 < n_filters) {
+ AUBIO_WRN ("too many filters, %d allocated but %d requested\n",
+ n_filters, freqs->length - 2);
+ }
+
+ if (freqs->data[freqs->length - 1] > samplerate / 2) {
+ AUBIO_WRN ("Nyquist frequency is %fHz, but highest frequency band ends at \
+%fHz\n", samplerate / 2, freqs->data[freqs->length - 1]);
+ }
+
+ /* convenience reference to lower/center/upper frequency for each triangle */
+ lower_freqs = new_fvec (n_filters);
+ upper_freqs = new_fvec (n_filters);
+ center_freqs = new_fvec (n_filters);
+
+ /* height of each triangle */
+ triangle_heights = new_fvec (n_filters);
+
+ /* lookup table of each bin frequency in hz */
+ fft_freqs = new_fvec (win_s);
+
+ /* fill up the lower/center/upper */
+ for (fn = 0; fn < n_filters; fn++) {
+ lower_freqs->data[fn] = freqs->data[fn];
+ center_freqs->data[fn] = freqs->data[fn + 1];
+ upper_freqs->data[fn] = freqs->data[fn + 2];
+ }
+
+ /* compute triangle heights so that each triangle has unit area */
+ for (fn = 0; fn < n_filters; fn++) {
+ triangle_heights->data[fn] =
+ 2. / (upper_freqs->data[fn] - lower_freqs->data[fn]);
+ }
+
+ /* fill fft_freqs lookup table, which assigns the frequency in hz to each bin */
+ for (bin = 0; bin < win_s; bin++) {
+ fft_freqs->data[bin] =
+ aubio_bintofreq (bin, samplerate, (win_s - 1) * 2);
+ }
+
+ /* zeroing of all filters */
+ fmat_zeros (filters);
+
+ if (fft_freqs->data[1] >= lower_freqs->data[0]) {
+ /* - 1 to make sure we don't miss the smallest power of two */
+ uint_t min_win_s =
+ (uint_t) FLOOR (samplerate / lower_freqs->data[0]) - 1;
+ AUBIO_WRN ("Lowest frequency bin (%.2fHz) is higher than lowest frequency \
+band (%.2f-%.2fHz). Consider increasing the window size from %d to %d.\n",
+ fft_freqs->data[1], lower_freqs->data[0],
+ upper_freqs->data[0], (win_s - 1) * 2,
+ aubio_next_power_of_two (min_win_s));
+ }
+
+ /* building each filter table */
+ for (fn = 0; fn < n_filters; fn++) {
+
+ /* skip first elements */
+ for (bin = 0; bin < win_s - 1; bin++) {
+ if (fft_freqs->data[bin] <= lower_freqs->data[fn] &&
+ fft_freqs->data[bin + 1] > lower_freqs->data[fn]) {
+ bin++;
+ break;
+ }
+ }
+
+ /* compute positive slope step size */
+ riseInc =
+ triangle_heights->data[fn] /
+ (center_freqs->data[fn] - lower_freqs->data[fn]);
+
+ /* compute coefficients in positive slope */
+ for (; bin < win_s - 1; bin++) {
+ filters->data[fn][bin] =
+ (fft_freqs->data[bin] - lower_freqs->data[fn]) * riseInc;
+
+ if (fft_freqs->data[bin + 1] >= center_freqs->data[fn]) {
+ bin++;
+ break;
+ }
+ }
+
+ /* compute negative slope step size */
+ downInc =
+ triangle_heights->data[fn] /
+ (upper_freqs->data[fn] - center_freqs->data[fn]);
+
+ /* compute coefficents in negative slope */
+ for (; bin < win_s - 1; bin++) {
+ filters->data[fn][bin] +=
+ (upper_freqs->data[fn] - fft_freqs->data[bin]) * downInc;
+
+ if (filters->data[fn][bin] < 0.) {
+ filters->data[fn][bin] = 0.;
+ }
+
+ if (fft_freqs->data[bin + 1] >= upper_freqs->data[fn])
+ break;
+ }
+ /* nothing else to do */
+
+ }
+
+ /* destroy temporarly allocated vectors */
+ del_fvec (lower_freqs);
+ del_fvec (upper_freqs);
+ del_fvec (center_freqs);
+
+ del_fvec (triangle_heights);
+ del_fvec (fft_freqs);
+
+ return 0;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
+ smpl_t samplerate)
+{
+ uint_t retval;
+
+ /* Malcolm Slaney parameters */
+ smpl_t lowestFrequency = 133.3333;
+ smpl_t linearSpacing = 66.66666666;
+ smpl_t logSpacing = 1.0711703;
+
+ uint_t linearFilters = 13;
+ uint_t logFilters = 27;
+ uint_t n_filters = linearFilters + logFilters;
+
+ uint_t fn; /* filter counter */
+
+ smpl_t lastlinearCF;
+
+ /* buffers to compute filter frequencies */
+ fvec_t *freqs = new_fvec (n_filters + 2);
+
+ /* first step: fill all the linear filter frequencies */
+ for (fn = 0; fn < linearFilters; fn++) {
+ freqs->data[fn] = lowestFrequency + fn * linearSpacing;
+ }
+ lastlinearCF = freqs->data[fn - 1];
+
+ /* second step: fill all the log filter frequencies */
+ for (fn = 0; fn < logFilters + 2; fn++) {
+ freqs->data[fn + linearFilters] =
+ lastlinearCF * (POW (logSpacing, fn + 1));
+ }
+
+ /* now compute the actual coefficients */
+ retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+ /* destroy vector used to store frequency limits */
+ del_fvec (freqs);
+
+ return retval;
+}
diff --git a/src/spectral/filterbank_mel.h b/src/spectral/filterbank_mel.h
new file mode 100644
index 0000000..77f0be0
--- /dev/null
+++ b/src/spectral/filterbank_mel.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Filterbank object coefficients initialization
+
+ Functions to create set the ::aubio_filterbank_t coefficients to
+ - ::aubio_filterbank_set_triangle_bands: overlapping triangular bands,
+ - ::aubio_filterbank_set_mel_coeffs_slaney: Mel frequency bands.
+
+ \example spectral/test-filterbank_mel.c
+
+*/
+
+#ifndef AUBIO_FILTERBANK_MEL_H
+#define AUBIO_FILTERBANK_MEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** filterbank initialization with triangular and overlapping bands
+
+ \param fb filterbank object
+ \param freqs arbitrary array of boundary frequencies
+ \param samplerate audio sampling rate
+
+ This function computes the coefficients of the filterbank based on the
+ boundaries found in freqs, in Hz, and using triangular overlapping bands.
+
+*/
+uint_t aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
+ const fvec_t * freqs, smpl_t samplerate);
+
+/** filterbank initialization for Mel filters using Slaney's coefficients
+
+ \param fb filterbank object
+ \param samplerate audio sampling rate
+
+ The filter coefficients are built according to Malcolm Slaney's Auditory
+ Toolbox, available at http://engineering.purdue.edu/~malcolm/interval/1998-010/
+ (see file mfcc.m).
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
+ smpl_t samplerate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTERBANK_MEL_H */
diff --git a/src/spectral/mfcc.c b/src/spectral/mfcc.c
new file mode 100644
index 0000000..101deb8
--- /dev/null
+++ b/src/spectral/mfcc.c
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "vecutils.h"
+#include "spectral/fft.h"
+#include "spectral/filterbank.h"
+#include "spectral/filterbank_mel.h"
+#include "spectral/mfcc.h"
+
+/** Internal structure for mfcc object */
+
+struct _aubio_mfcc_t
+{
+ uint_t win_s; /** grain length */
+ uint_t samplerate; /** sample rate (needed?) */
+ uint_t n_filters; /** number of *filters */
+ uint_t n_coefs; /** number of coefficients (<= n_filters/2 +1) */
+ aubio_filterbank_t *fb; /** filter bank */
+ fvec_t *in_dct; /** input buffer for dct * [fb->n_filters] */
+ fmat_t *dct_coeffs; /** DCT transform n_filters * n_coeffs */
+};
+
+
+aubio_mfcc_t *
+new_aubio_mfcc (uint_t win_s, uint_t n_filters, uint_t n_coefs,
+ uint_t samplerate)
+{
+
+ /* allocate space for mfcc object */
+ aubio_mfcc_t *mfcc = AUBIO_NEW (aubio_mfcc_t);
+ smpl_t scaling;
+
+ uint_t i, j;
+
+ mfcc->win_s = win_s;
+ mfcc->samplerate = samplerate;
+ mfcc->n_filters = n_filters;
+ mfcc->n_coefs = n_coefs;
+
+ /* filterbank allocation */
+ mfcc->fb = new_aubio_filterbank (n_filters, mfcc->win_s);
+ aubio_filterbank_set_mel_coeffs_slaney (mfcc->fb, samplerate);
+
+ /* allocating buffers */
+ mfcc->in_dct = new_fvec (n_filters);
+
+ mfcc->dct_coeffs = new_fmat (n_coefs, n_filters);
+
+ /* compute DCT transform dct_coeffs[j][i] as
+ cos ( j * (i+.5) * PI / n_filters ) */
+ scaling = 1. / SQRT (n_filters / 2.);
+ for (i = 0; i < n_filters; i++) {
+ for (j = 0; j < n_coefs; j++) {
+ mfcc->dct_coeffs->data[j][i] =
+ scaling * COS (j * (i + 0.5) * PI / n_filters);
+ }
+ mfcc->dct_coeffs->data[0][i] *= SQRT (2.) / 2.;
+ }
+
+ return mfcc;
+}
+
+void
+del_aubio_mfcc (aubio_mfcc_t * mf)
+{
+
+ /* delete filterbank */
+ del_aubio_filterbank (mf->fb);
+
+ /* delete buffers */
+ del_fvec (mf->in_dct);
+ del_fmat (mf->dct_coeffs);
+
+ /* delete mfcc object */
+ AUBIO_FREE (mf);
+}
+
+
+void
+aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out)
+{
+ /* compute filterbank */
+ aubio_filterbank_do (mf->fb, in, mf->in_dct);
+
+ /* compute log10 */
+ fvec_log10 (mf->in_dct);
+
+ /* raise power */
+ //fvec_pow (mf->in_dct, 3.);
+
+ /* compute mfccs */
+ fmat_vecmul(mf->dct_coeffs, mf->in_dct, out);
+
+ return;
+}
diff --git a/src/spectral/mfcc.h b/src/spectral/mfcc.h
new file mode 100644
index 0000000..a170e12
--- /dev/null
+++ b/src/spectral/mfcc.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier <piem@aubio.org>
+ and Amaury Hazan <ahazan@iua.upf.edu>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Mel-Frequency Cepstrum Coefficients object
+
+ This object computes MFCC coefficients on an input cvec_t.
+
+ The implementation follows the specifications established by Malcolm Slaney
+ in its Auditory Toolbox, available online (see file mfcc.m).
+
+ http://engineering.ecn.purdue.edu/~malcolm/interval/1998-010/
+
+ \example spectral/test-mfcc.c
+
+*/
+
+#ifndef AUBIO_MFCC_H
+#define AUBIO_MFCC_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** mfcc object */
+typedef struct _aubio_mfcc_t aubio_mfcc_t;
+
+/** create mfcc object
+
+ \param buf_size size of analysis buffer (and length the FFT transform)
+ \param samplerate audio sampling rate
+ \param n_coeffs number of desired coefficients
+ \param n_filters number of desired filters
+
+*/
+aubio_mfcc_t *new_aubio_mfcc (uint_t buf_size,
+ uint_t n_filters, uint_t n_coeffs, uint_t samplerate);
+
+/** delete mfcc object
+
+ \param mf mfcc object as returned by new_aubio_mfcc
+
+*/
+void del_aubio_mfcc (aubio_mfcc_t * mf);
+
+/** mfcc object processing
+
+ \param mf mfcc object as returned by new_aubio_mfcc
+ \param in input spectrum (buf_size long)
+ \param out output mel coefficients buffer (n_coeffs long)
+
+*/
+void aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MFCC_H */
diff --git a/src/spectral/ooura_fft8g.c b/src/spectral/ooura_fft8g.c
new file mode 100644
index 0000000..004d8de
--- /dev/null
+++ b/src/spectral/ooura_fft8g.c
@@ -0,0 +1,1669 @@
+// modifications made for aubio:
+// - replace all 'double' with 'smpl_t'
+// - include "aubio_priv.h" (for config.h and types.h)
+// - add missing prototypes
+// - use COS and SIN macros
+
+#include "aubio_priv.h"
+
+void cdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void rdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void ddct(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void ddst(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void dfct(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w);
+void dfst(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w);
+void makewt(int nw, int *ip, smpl_t *w);
+void makect(int nc, int *ip, smpl_t *c);
+void bitrv2(int n, int *ip, smpl_t *a);
+void bitrv2conj(int n, int *ip, smpl_t *a);
+void cftfsub(int n, smpl_t *a, smpl_t *w);
+void cftbsub(int n, smpl_t *a, smpl_t *w);
+void cft1st(int n, smpl_t *a, smpl_t *w);
+void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+
+/*
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :8, 4, 2
+ data :inplace
+ table :use
+functions
+ cdft: Complex Discrete Fourier Transform
+ rdft: Real Discrete Fourier Transform
+ ddct: Discrete Cosine Transform
+ ddst: Discrete Sine Transform
+ dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+ dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+ void cdft(int, int, smpl_t *, int *, smpl_t *);
+ void rdft(int, int, smpl_t *, int *, smpl_t *);
+ void ddct(int, int, smpl_t *, int *, smpl_t *);
+ void ddst(int, int, smpl_t *, int *, smpl_t *);
+ void dfct(int, smpl_t *, smpl_t *, int *, smpl_t *);
+ void dfst(int, smpl_t *, smpl_t *, int *, smpl_t *);
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+ <case1>
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+ <case2>
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+ (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ cdft(2*n, -1, a, ip, w);
+ [parameters]
+ 2*n :data length (int)
+ n >= 1, n = power of 2
+ a[0...2*n-1] :input/output data (smpl_t *)
+ input data
+ a[2*j] = Re(x[j]),
+ a[2*j+1] = Im(x[j]), 0<=j<n
+ output data
+ a[2*k] = Re(X[k]),
+ a[2*k+1] = Im(X[k]), 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ cdft(2*n, -1, a, ip, w);
+ is
+ cdft(2*n, 1, a, ip, w);
+ for (j = 0; j <= 2 * n - 1; j++) {
+ a[j] *= 1.0 / n;
+ }
+ .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+ [definition]
+ <case1> RDFT
+ R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+ I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
+ <case2> IRDFT (excluding scale)
+ a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
+ sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
+ sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ rdft(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ <case1>
+ output data
+ a[2*k] = R[k], 0<=k<n/2
+ a[2*k+1] = I[k], 0<k<n/2
+ a[1] = R[n/2]
+ <case2>
+ input data
+ a[2*j] = R[j], 0<=j<n/2
+ a[2*j+1] = I[j], 0<j<n/2
+ a[1] = R[n/2]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ rdft(n, 1, a, ip, w);
+ is
+ rdft(n, -1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+ [definition]
+ <case1> IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddct(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ output data
+ a[k] = C[k], 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddct(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddct(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+ [definition]
+ <case1> IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddst(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ <case1>
+ input data
+ a[j] = A[j], 0<j<n
+ a[0] = A[n]
+ output data
+ a[k] = S[k], 0<=k<n
+ <case2>
+ output data
+ a[k] = S[k], 0<k<n
+ a[0] = S[n]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddst(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddst(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+ [definition]
+ C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+ [usage]
+ ip[0] = 0; // first time only
+ dfct(n, a, t, ip, w);
+ [parameters]
+ n :data length - 1 (int)
+ n >= 2, n = power of 2
+ a[0...n] :input/output data (smpl_t *)
+ output data
+ a[k] = C[k], 0<=k<=n
+ t[0...n/2] :work area (smpl_t *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ is
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ for (j = 0; j <= n; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+ [definition]
+ S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
+ [usage]
+ ip[0] = 0; // first time only
+ dfst(n, a, t, ip, w);
+ [parameters]
+ n :data length + 1 (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ output data
+ a[k] = S[k], 0<k<n
+ (a[0] is used for work area)
+ t[0...n/2-1] :work area (smpl_t *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ dfst(n, a, t, ip, w);
+ is
+ dfst(n, a, t, ip, w);
+ for (j = 1; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+Appendix :
+ The cos/sin table is recalculated when the larger table required.
+ w[] and ip[] are compatible with all routines.
+*/
+
+
+void cdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void bitrv2conj(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+
+ if (n > (ip[0] << 2)) {
+ makewt(n >> 2, ip, w);
+ }
+ if (n > 4) {
+ if (isgn >= 0) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ } else {
+ bitrv2conj(n, ip + 2, a);
+ cftbsub(n, a, w);
+ }
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+}
+
+
+void rdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int nw, nc;
+ smpl_t xi;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 2)) {
+ nc = n >> 2;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xi = a[0] - a[1];
+ a[0] += a[1];
+ a[1] = xi;
+ } else {
+ a[1] = 0.5 * (a[0] - a[1]);
+ a[0] -= a[1];
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+}
+
+
+void ddct(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, nw, nc;
+ smpl_t xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = a[j] - a[j - 1];
+ a[j] += a[j - 1];
+ }
+ a[1] = a[0] - xr;
+ a[0] += xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+ dctsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = a[j] - a[j + 1];
+ a[j] += a[j + 1];
+ }
+ a[n - 1] = xr;
+ }
+}
+
+
+void ddst(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, nw, nc;
+ smpl_t xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = -a[j] - a[j - 1];
+ a[j] -= a[j - 1];
+ }
+ a[1] = a[0] + xr;
+ a[0] -= xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+ dstsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = -a[j] - a[j + 1];
+ a[j] -= a[j + 1];
+ }
+ a[n - 1] = -xr;
+ }
+}
+
+
+void dfct(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, k, l, m, mh, nw, nc;
+ smpl_t xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ m = n >> 1;
+ yi = a[m];
+ xi = a[0] + a[n];
+ a[0] -= a[n];
+ t[0] = xi - yi;
+ t[m] = xi + yi;
+ if (n > 2) {
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] - a[n - j];
+ xi = a[j] + a[n - j];
+ yr = a[k] - a[n - k];
+ yi = a[k] + a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi - yi;
+ t[k] = xi + yi;
+ }
+ t[mh] = a[mh] + a[n - mh];
+ a[mh] -= a[n - mh];
+ dctsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[0] - a[1];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] + a[j + 1];
+ a[2 * j - 1] = a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dctsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[0] - t[1];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = t[j] - t[j + 1];
+ a[k + l] = t[j] + t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 0; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] - t[m + j];
+ t[k] = t[m + k] + t[m + j];
+ }
+ t[mh] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ a[n] = t[2] - t[1];
+ a[0] = t[2] + t[1];
+ } else {
+ a[1] = a[0];
+ a[2] = t[0];
+ a[0] = t[1];
+ }
+}
+
+
+void dfst(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, k, l, m, mh, nw, nc;
+ smpl_t xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ if (n > 2) {
+ m = n >> 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] + a[n - j];
+ xi = a[j] - a[n - j];
+ yr = a[k] + a[n - k];
+ yi = a[k] - a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi + yi;
+ t[k] = xi - yi;
+ }
+ t[0] = a[mh] - a[n - mh];
+ a[mh] += a[n - mh];
+ a[0] = a[m];
+ dstsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[1] - a[0];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] - a[j + 1];
+ a[2 * j - 1] = -a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dstsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[1] - t[0];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = -t[j] - t[j + 1];
+ a[k + l] = t[j] - t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] + t[m + j];
+ t[k] = t[m + k] - t[m + j];
+ }
+ t[0] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ }
+ a[0] = 0;
+}
+
+
+/* -------- initializing routines -------- */
+
+
+#include <math.h>
+
+void makewt(int nw, int *ip, smpl_t *w)
+{
+ void bitrv2(int n, int *ip, smpl_t *a);
+ int j, nwh;
+ smpl_t delta, x, y;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = atan(1.0) / nwh;
+ w[0] = 1;
+ w[1] = 0;
+ w[nwh] = COS(delta * nwh);
+ w[nwh + 1] = w[nwh];
+ if (nwh > 2) {
+ for (j = 2; j < nwh; j += 2) {
+ x = COS(delta * j);
+ y = SIN(delta * j);
+ w[j] = x;
+ w[j + 1] = y;
+ w[nw - j] = y;
+ w[nw - j + 1] = x;
+ }
+ for (j = nwh - 2; j >= 2; j -= 2) {
+ x = w[2 * j];
+ y = w[2 * j + 1];
+ w[nwh + j] = x;
+ w[nwh + j + 1] = y;
+ }
+ bitrv2(nw, ip + 2, w);
+ }
+ }
+}
+
+
+void makect(int nc, int *ip, smpl_t *c)
+{
+ int j, nch;
+ smpl_t delta;
+
+ ip[1] = nc;
+ if (nc > 1) {
+ nch = nc >> 1;
+ delta = atan(1.0) / nch;
+ c[0] = cos(delta * nch);
+ c[nch] = 0.5 * c[0];
+ for (j = 1; j < nch; j++) {
+ c[j] = 0.5 * cos(delta * j);
+ c[nc - j] = 0.5 * sin(delta * j);
+ }
+ }
+}
+
+
+/* -------- child routines -------- */
+
+
+void bitrv2(int n, int *ip, smpl_t *a)
+{
+ int j, j1, k, k1, l, m, m2;
+ smpl_t xr, xi, yr, yi;
+
+ ip[0] = 0;
+ l = n;
+ m = 1;
+ while ((m << 3) < l) {
+ l >>= 1;
+ for (j = 0; j < m; j++) {
+ ip[m + j] = ip[j] + l;
+ }
+ m <<= 1;
+ }
+ m2 = 2 * m;
+ if ((m << 3) == l) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 -= m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ j1 = 2 * k + m2 + ip[k];
+ k1 = j1 + m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ } else {
+ for (k = 1; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ }
+ }
+}
+
+
+void bitrv2conj(int n, int *ip, smpl_t *a)
+{
+ int j, j1, k, k1, l, m, m2;
+ smpl_t xr, xi, yr, yi;
+
+ ip[0] = 0;
+ l = n;
+ m = 1;
+ while ((m << 3) < l) {
+ l >>= 1;
+ for (j = 0; j < m; j++) {
+ ip[m + j] = ip[j] + l;
+ }
+ m <<= 1;
+ }
+ m2 = 2 * m;
+ if ((m << 3) == l) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 -= m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ j1 = k1 + m2;
+ k1 = j1 + m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ k1 += m2;
+ a[k1 + 1] = -a[k1 + 1];
+ }
+ } else {
+ a[1] = -a[1];
+ a[m2 + 1] = -a[m2 + 1];
+ for (k = 1; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ a[k1 + m2 + 1] = -a[k1 + m2 + 1];
+ }
+ }
+}
+
+
+void cftfsub(int n, smpl_t *a, smpl_t *w)
+{
+ void cft1st(int n, smpl_t *a, smpl_t *w);
+ void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+ int j, j1, j2, j3, l;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ l = 2;
+ if (n >= 16) {
+ cft1st(n, a, w);
+ l = 16;
+ while ((l << 3) <= n) {
+ cftmdl(n, l, a, w);
+ l <<= 3;
+ }
+ }
+ if ((l << 1) < n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i - x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ }
+ } else if ((l << 1) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = a[j + 1] - a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] += a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+
+void cftbsub(int n, smpl_t *a, smpl_t *w)
+{
+ void cft1st(int n, smpl_t *a, smpl_t *w);
+ void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+ int j, j1, j2, j3, j4, j5, j6, j7, l;
+ smpl_t wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ l = 2;
+ if (n > 16) {
+ cft1st(n, a, w);
+ l = 16;
+ while ((l << 3) < n) {
+ cftmdl(n, l, a, w);
+ l <<= 3;
+ }
+ }
+ if ((l << 2) < n) {
+ wn4r = w[2];
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i - x2i;
+ y2r = x0r - x2r;
+ y2i = x0i + x2i;
+ y1r = x1r - x3i;
+ y1i = x1i - x3r;
+ y3r = x1r + x3i;
+ y3i = x1i + x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[j1] = y1r + y5r;
+ a[j1 + 1] = y1i - y5i;
+ a[j5] = y1r - y5r;
+ a[j5 + 1] = y1i + y5i;
+ a[j3] = y3r - y7i;
+ a[j3 + 1] = y3i - y7r;
+ a[j7] = y3r + y7i;
+ a[j7 + 1] = y3i + y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i - y4i;
+ a[j4] = y0r - y4r;
+ a[j4 + 1] = y0i + y4i;
+ a[j2] = y2r - y6i;
+ a[j2 + 1] = y2i - y6r;
+ a[j6] = y2r + y6i;
+ a[j6 + 1] = y2i + y6r;
+ }
+ } else if ((l << 2) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i + x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i - x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i + x3r;
+ }
+ } else {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = -a[j + 1] + a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] = -a[j + 1] - a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+
+void cft1st(int n, smpl_t *a, smpl_t *w)
+{
+ int j, k1;
+ smpl_t wn4r, wtmp, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ wk4r, wk4i, wk5r, wk5i, wk6r, wk6i, wk7r, wk7i;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[2];
+ x0r = a[0] + a[2];
+ x0i = a[1] + a[3];
+ x1r = a[0] - a[2];
+ x1i = a[1] - a[3];
+ x2r = a[4] + a[6];
+ x2i = a[5] + a[7];
+ x3r = a[4] - a[6];
+ x3i = a[5] - a[7];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[8] + a[10];
+ x0i = a[9] + a[11];
+ x1r = a[8] - a[10];
+ x1i = a[9] - a[11];
+ x2r = a[12] + a[14];
+ x2i = a[13] + a[15];
+ x3r = a[12] - a[14];
+ x3i = a[13] - a[15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[2] = y1r + y5r;
+ a[3] = y1i + y5i;
+ a[10] = y1r - y5r;
+ a[11] = y1i - y5i;
+ a[6] = y3r - y7i;
+ a[7] = y3i + y7r;
+ a[14] = y3r + y7i;
+ a[15] = y3i - y7r;
+ a[0] = y0r + y4r;
+ a[1] = y0i + y4i;
+ a[8] = y0r - y4r;
+ a[9] = y0i - y4i;
+ a[4] = y2r - y6i;
+ a[5] = y2i + y6r;
+ a[12] = y2r + y6i;
+ a[13] = y2i - y6r;
+ if (n > 16) {
+ wk1r = w[4];
+ wk1i = w[5];
+ x0r = a[16] + a[18];
+ x0i = a[17] + a[19];
+ x1r = a[16] - a[18];
+ x1i = a[17] - a[19];
+ x2r = a[20] + a[22];
+ x2i = a[21] + a[23];
+ x3r = a[20] - a[22];
+ x3i = a[21] - a[23];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[24] + a[26];
+ x0i = a[25] + a[27];
+ x1r = a[24] - a[26];
+ x1i = a[25] - a[27];
+ x2r = a[28] + a[30];
+ x2i = a[29] + a[31];
+ x3r = a[28] - a[30];
+ x3i = a[29] - a[31];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x3r - x1i;
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ y7r = wk1r * x2r + wk1i * x2i;
+ y7i = wk1r * x2i - wk1i * x2r;
+ x0r = wk1r * y1r - wk1i * y1i;
+ x0i = wk1r * y1i + wk1i * y1r;
+ a[18] = x0r + y5r;
+ a[19] = x0i + y5i;
+ a[26] = y5i - x0i;
+ a[27] = x0r - y5r;
+ x0r = wk1i * y3r - wk1r * y3i;
+ x0i = wk1i * y3i + wk1r * y3r;
+ a[22] = x0r - y7r;
+ a[23] = x0i + y7i;
+ a[30] = y7i - x0i;
+ a[31] = x0r + y7r;
+ a[16] = y0r + y4r;
+ a[17] = y0i + y4i;
+ a[24] = y4i - y0i;
+ a[25] = y0r - y4r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[20] = wn4r * (x0r - x0i);
+ a[21] = wn4r * (x0i + x0r);
+ x0r = y6r - y2i;
+ x0i = y2r + y6i;
+ a[28] = wn4r * (x0r - x0i);
+ a[29] = wn4r * (x0i + x0r);
+ k1 = 4;
+ for (j = 32; j < n; j += 16) {
+ k1 += 4;
+ wk1r = w[k1];
+ wk1i = w[k1 + 1];
+ wk2r = w[k1 + 2];
+ wk2i = w[k1 + 3];
+ wtmp = 2 * wk2i;
+ wk3r = wk1r - wtmp * wk1i;
+ wk3i = wtmp * wk1r - wk1i;
+ wk4r = 1 - wtmp * wk2i;
+ wk4i = wtmp * wk2r;
+ wtmp = 2 * wk4i;
+ wk5r = wk3r - wtmp * wk1i;
+ wk5i = wtmp * wk1r - wk3i;
+ wk6r = wk2r - wtmp * wk2i;
+ wk6i = wtmp * wk2r - wk2i;
+ wk7r = wk1r - wtmp * wk3i;
+ wk7i = wtmp * wk3r - wk1i;
+ x0r = a[j] + a[j + 2];
+ x0i = a[j + 1] + a[j + 3];
+ x1r = a[j] - a[j + 2];
+ x1i = a[j + 1] - a[j + 3];
+ x2r = a[j + 4] + a[j + 6];
+ x2i = a[j + 5] + a[j + 7];
+ x3r = a[j + 4] - a[j + 6];
+ x3i = a[j + 5] - a[j + 7];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j + 8] + a[j + 10];
+ x0i = a[j + 9] + a[j + 11];
+ x1r = a[j + 8] - a[j + 10];
+ x1i = a[j + 9] - a[j + 11];
+ x2r = a[j + 12] + a[j + 14];
+ x2i = a[j + 13] + a[j + 15];
+ x3r = a[j + 12] - a[j + 14];
+ x3i = a[j + 13] - a[j + 15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ x0r = y1r + y5r;
+ x0i = y1i + y5i;
+ a[j + 2] = wk1r * x0r - wk1i * x0i;
+ a[j + 3] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y5r;
+ x0i = y1i - y5i;
+ a[j + 10] = wk5r * x0r - wk5i * x0i;
+ a[j + 11] = wk5r * x0i + wk5i * x0r;
+ x0r = y3r - y7i;
+ x0i = y3i + y7r;
+ a[j + 6] = wk3r * x0r - wk3i * x0i;
+ a[j + 7] = wk3r * x0i + wk3i * x0r;
+ x0r = y3r + y7i;
+ x0i = y3i - y7r;
+ a[j + 14] = wk7r * x0r - wk7i * x0i;
+ a[j + 15] = wk7r * x0i + wk7i * x0r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ x0r = y0r - y4r;
+ x0i = y0i - y4i;
+ a[j + 8] = wk4r * x0r - wk4i * x0i;
+ a[j + 9] = wk4r * x0i + wk4i * x0r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j + 4] = wk2r * x0r - wk2i * x0i;
+ a[j + 5] = wk2r * x0i + wk2i * x0r;
+ x0r = y2r + y6i;
+ x0i = y2i - y6r;
+ a[j + 12] = wk6r * x0r - wk6i * x0i;
+ a[j + 13] = wk6r * x0i + wk6i * x0r;
+ }
+ }
+}
+
+
+void cftmdl(int n, int l, smpl_t *a, smpl_t *w)
+{
+ int j, j1, j2, j3, j4, j5, j6, j7, k, k1, m;
+ smpl_t wn4r, wtmp, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ wk4r, wk4i, wk5r, wk5i, wk6r, wk6i, wk7r, wk7i;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ m = l << 3;
+ wn4r = w[2];
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[j1] = y1r + y5r;
+ a[j1 + 1] = y1i + y5i;
+ a[j5] = y1r - y5r;
+ a[j5 + 1] = y1i - y5i;
+ a[j3] = y3r - y7i;
+ a[j3 + 1] = y3i + y7r;
+ a[j7] = y3r + y7i;
+ a[j7 + 1] = y3i - y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ a[j4] = y0r - y4r;
+ a[j4 + 1] = y0i - y4i;
+ a[j2] = y2r - y6i;
+ a[j2 + 1] = y2i + y6r;
+ a[j6] = y2r + y6i;
+ a[j6 + 1] = y2i - y6r;
+ }
+ if (m < n) {
+ wk1r = w[4];
+ wk1i = w[5];
+ for (j = m; j < l + m; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x3r - x1i;
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ y7r = wk1r * x2r + wk1i * x2i;
+ y7i = wk1r * x2i - wk1i * x2r;
+ x0r = wk1r * y1r - wk1i * y1i;
+ x0i = wk1r * y1i + wk1i * y1r;
+ a[j1] = x0r + y5r;
+ a[j1 + 1] = x0i + y5i;
+ a[j5] = y5i - x0i;
+ a[j5 + 1] = x0r - y5r;
+ x0r = wk1i * y3r - wk1r * y3i;
+ x0i = wk1i * y3i + wk1r * y3r;
+ a[j3] = x0r - y7r;
+ a[j3 + 1] = x0i + y7i;
+ a[j7] = y7i - x0i;
+ a[j7 + 1] = x0r + y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ a[j4] = y4i - y0i;
+ a[j4 + 1] = y0r - y4r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = y6r - y2i;
+ x0i = y2r + y6i;
+ a[j6] = wn4r * (x0r - x0i);
+ a[j6 + 1] = wn4r * (x0i + x0r);
+ }
+ k1 = 4;
+ for (k = 2 * m; k < n; k += m) {
+ k1 += 4;
+ wk1r = w[k1];
+ wk1i = w[k1 + 1];
+ wk2r = w[k1 + 2];
+ wk2i = w[k1 + 3];
+ wtmp = 2 * wk2i;
+ wk3r = wk1r - wtmp * wk1i;
+ wk3i = wtmp * wk1r - wk1i;
+ wk4r = 1 - wtmp * wk2i;
+ wk4i = wtmp * wk2r;
+ wtmp = 2 * wk4i;
+ wk5r = wk3r - wtmp * wk1i;
+ wk5i = wtmp * wk1r - wk3i;
+ wk6r = wk2r - wtmp * wk2i;
+ wk6i = wtmp * wk2r - wk2i;
+ wk7r = wk1r - wtmp * wk3i;
+ wk7i = wtmp * wk3r - wk1i;
+ for (j = k; j < l + k; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ x0r = y1r + y5r;
+ x0i = y1i + y5i;
+ a[j1] = wk1r * x0r - wk1i * x0i;
+ a[j1 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y5r;
+ x0i = y1i - y5i;
+ a[j5] = wk5r * x0r - wk5i * x0i;
+ a[j5 + 1] = wk5r * x0i + wk5i * x0r;
+ x0r = y3r - y7i;
+ x0i = y3i + y7r;
+ a[j3] = wk3r * x0r - wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i + wk3i * x0r;
+ x0r = y3r + y7i;
+ x0i = y3i - y7r;
+ a[j7] = wk7r * x0r - wk7i * x0i;
+ a[j7 + 1] = wk7r * x0i + wk7i * x0r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ x0r = y0r - y4r;
+ x0i = y0i - y4i;
+ a[j4] = wk4r * x0r - wk4i * x0i;
+ a[j4 + 1] = wk4r * x0i + wk4i * x0r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j2] = wk2r * x0r - wk2i * x0i;
+ a[j2 + 1] = wk2r * x0i + wk2i * x0r;
+ x0r = y2r + y6i;
+ x0i = y2i - y6r;
+ a[j6] = wk6r * x0r - wk6i * x0i;
+ a[j6 + 1] = wk6r * x0i + wk6i * x0r;
+ }
+ }
+ }
+}
+
+
+void rftfsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr - wki * xi;
+ yi = wkr * xi + wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+void rftbsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr, xi, yr, yi;
+
+ a[1] = -a[1];
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr + wki * xi;
+ yi = wkr * xi - wki * xr;
+ a[j] -= yr;
+ a[j + 1] = yi - a[j + 1];
+ a[k] += yr;
+ a[k + 1] = yi - a[k + 1];
+ }
+ a[m + 1] = -a[m + 1];
+}
+
+
+void dctsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[j] - wkr * a[k];
+ a[j] = wkr * a[j] + wki * a[k];
+ a[k] = xr;
+ }
+ a[m] *= c[0];
+}
+
+
+void dstsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[k] - wkr * a[j];
+ a[k] = wkr * a[k] + wki * a[j];
+ a[j] = xr;
+ }
+ a[m] *= c[0];
+}
+
diff --git a/src/spectral/phasevoc.c b/src/spectral/phasevoc.c
new file mode 100644
index 0000000..e48e91a
--- /dev/null
+++ b/src/spectral/phasevoc.c
@@ -0,0 +1,210 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+#include "spectral/phasevoc.h"
+
+/** phasevocoder internal object */
+struct _aubio_pvoc_t {
+ uint_t win_s; /** grain length */
+ uint_t hop_s; /** overlap step */
+ aubio_fft_t * fft; /** fft object */
+ fvec_t * data; /** current input grain, [win_s] frames */
+ fvec_t * dataold; /** memory of past grain, [win_s-hop_s] frames */
+ fvec_t * synth; /** current output grain, [win_s] frames */
+ fvec_t * synthold; /** memory of past grain, [win_s-hop_s] frames */
+ fvec_t * w; /** grain window [win_s] */
+ uint_t start; /** where to start additive synthesis */
+ uint_t end; /** where to end it */
+ smpl_t scale; /** scaling factor for synthesis */
+ uint_t end_datasize; /** size of memory to end */
+ uint_t hop_datasize; /** size of memory to hop_s */
+};
+
+
+/** returns data and dataold slided by hop_s */
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new);
+
+/** do additive synthesis from 'old' and 'cur' */
+static void aubio_pvoc_addsynth(aubio_pvoc_t *pv, fvec_t * synthnew);
+
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t * datanew, cvec_t *fftgrain) {
+ /* slide */
+ aubio_pvoc_swapbuffers(pv, datanew);
+ /* windowing */
+ fvec_weight(pv->data, pv->w);
+ /* shift */
+ fvec_shift(pv->data);
+ /* calculate fft */
+ aubio_fft_do (pv->fft,pv->data,fftgrain);
+}
+
+void aubio_pvoc_rdo(aubio_pvoc_t *pv,cvec_t * fftgrain, fvec_t * synthnew) {
+ /* calculate rfft */
+ aubio_fft_rdo(pv->fft,fftgrain,pv->synth);
+ /* unshift */
+ fvec_ishift(pv->synth);
+ /* windowing */
+ // if overlap = 50%, do not apply window (identity)
+ if (pv->hop_s * 2 < pv->win_s) {
+ fvec_weight(pv->synth, pv->w);
+ }
+ /* additive synthesis */
+ aubio_pvoc_addsynth(pv, synthnew);
+}
+
+aubio_pvoc_t * new_aubio_pvoc (uint_t win_s, uint_t hop_s) {
+ aubio_pvoc_t * pv = AUBIO_NEW(aubio_pvoc_t);
+
+ /* if (win_s < 2*hop_s) {
+ AUBIO_WRN("Hop size bigger than half the window size!\n");
+ } */
+
+ if ((sint_t)hop_s < 1) {
+ AUBIO_ERR("pvoc: got hop_size %d, but can not be < 1\n", hop_s);
+ goto beach;
+ } else if ((sint_t)win_s < 2) {
+ AUBIO_ERR("pvoc: got buffer_size %d, but can not be < 2\n", win_s);
+ goto beach;
+ } else if (win_s < hop_s) {
+ AUBIO_ERR("pvoc: hop size (%d) is larger than win size (%d)\n", win_s, hop_s);
+ goto beach;
+ }
+
+ pv->fft = new_aubio_fft (win_s);
+ if (pv->fft == NULL) {
+ goto beach;
+ }
+
+ /* remember old */
+ pv->data = new_fvec (win_s);
+ pv->synth = new_fvec (win_s);
+
+ /* new input output */
+ if (win_s > hop_s) {
+ pv->dataold = new_fvec (win_s-hop_s);
+ pv->synthold = new_fvec (win_s-hop_s);
+ } else {
+ pv->dataold = new_fvec (1);
+ pv->synthold = new_fvec (1);
+ }
+ pv->w = new_aubio_window ("hanningz", win_s);
+
+ pv->hop_s = hop_s;
+ pv->win_s = win_s;
+
+ /* more than 50% overlap, overlap anyway */
+ if (win_s < 2 * hop_s) pv->start = 0;
+ /* less than 50% overlap, reset latest grain trail */
+ else pv->start = win_s - hop_s - hop_s;
+
+ if (win_s > hop_s) pv->end = win_s - hop_s;
+ else pv->end = 0;
+
+ pv->end_datasize = pv->end * sizeof(smpl_t);
+ pv->hop_datasize = pv->hop_s * sizeof(smpl_t);
+
+ // for reconstruction with 75% overlap
+ if (win_s == hop_s * 4) {
+ pv->scale = 2./3.;
+ } else if (win_s == hop_s * 8) {
+ pv->scale = 1./3.;
+ } else if (win_s == hop_s * 2) {
+ pv->scale = 1.;
+ } else {
+ pv->scale = .5;
+ }
+
+ return pv;
+
+beach:
+ AUBIO_FREE (pv);
+ return NULL;
+}
+
+void del_aubio_pvoc(aubio_pvoc_t *pv) {
+ del_fvec(pv->data);
+ del_fvec(pv->synth);
+ del_fvec(pv->dataold);
+ del_fvec(pv->synthold);
+ del_fvec(pv->w);
+ del_aubio_fft(pv->fft);
+ AUBIO_FREE(pv);
+}
+
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new)
+{
+ /* some convenience pointers */
+ smpl_t * data = pv->data->data;
+ smpl_t * dataold = pv->dataold->data;
+ smpl_t * datanew = new->data;
+#ifndef HAVE_MEMCPY_HACKS
+ uint_t i;
+ for (i = 0; i < pv->end; i++)
+ data[i] = dataold[i];
+ for (i = 0; i < pv->hop_s; i++)
+ data[pv->end + i] = datanew[i];
+ for (i = 0; i < pv->end; i++)
+ dataold[i] = data[i + pv->hop_s];
+#else
+ memcpy(data, dataold, pv->end_datasize);
+ data += pv->end;
+ memcpy(data, datanew, pv->hop_datasize);
+ data -= pv->end;
+ data += pv->hop_s;
+ memcpy(dataold, data, pv->end_datasize);
+#endif
+}
+
+static void aubio_pvoc_addsynth(aubio_pvoc_t *pv, fvec_t *synth_new)
+{
+ uint_t i;
+ /* some convenience pointers */
+ smpl_t * synth = pv->synth->data;
+ smpl_t * synthold = pv->synthold->data;
+ smpl_t * synthnew = synth_new->data;
+
+ /* put new result in synthnew */
+ for (i = 0; i < pv->hop_s; i++)
+ synthnew[i] = synth[i] * pv->scale;
+
+ /* no overlap, nothing else to do */
+ if (pv->end == 0) return;
+
+ /* add new synth to old one */
+ for (i = 0; i < pv->hop_s; i++)
+ synthnew[i] += synthold[i];
+
+ /* shift synthold */
+ for (i = 0; i < pv->start; i++)
+ synthold[i] = synthold[i + pv->hop_s];
+
+ /* erase last frame in synthold */
+ for (i = pv->start; i < pv->end; i++)
+ synthold[i] = 0.;
+
+ /* additive synth */
+ for (i = 0; i < pv->end; i++)
+ synthold[i] += synth[i + pv->hop_s] * pv->scale;
+}
diff --git a/src/spectral/phasevoc.h b/src/spectral/phasevoc.h
new file mode 100644
index 0000000..d1e440d
--- /dev/null
+++ b/src/spectral/phasevoc.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Phase vocoder object
+
+ This object implements a phase vocoder. The spectral frames are computed
+ using a HanningZ window and a swapped version of the signal to simplify the
+ phase relationships across frames. The window sizes and overlap are specified
+ at creation time.
+
+ \example spectral/test-phasevoc.c
+
+*/
+
+#ifndef AUBIO_PHASEVOC_H
+#define AUBIO_PHASEVOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** phasevocoder object */
+typedef struct _aubio_pvoc_t aubio_pvoc_t;
+
+/** create phase vocoder object
+
+ \param win_s size of analysis buffer (and length the FFT transform)
+ \param hop_s step size between two consecutive analysis
+
+*/
+aubio_pvoc_t * new_aubio_pvoc (uint_t win_s, uint_t hop_s);
+/** delete phase vocoder object
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+
+*/
+void del_aubio_pvoc(aubio_pvoc_t *pv);
+
+/** compute spectral frame
+
+ This function accepts an input vector of size [hop_s]. The
+ analysis buffer is rotated and filled with the new data. After windowing of
+ this signal window, the Fourier transform is computed and returned in
+ fftgrain as two vectors, magnitude and phase.
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+ \param in new input signal (hop_s long)
+ \param fftgrain output spectral frame
+
+*/
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t *in, cvec_t * fftgrain);
+/** compute signal from spectral frame
+
+ This function takes an input spectral frame fftgrain of size
+ [buf_s] and computes its inverse Fourier transform. Overlap-add
+ synthesis is then computed using the previously synthetised frames, and the
+ output stored in out.
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+ \param fftgrain input spectral frame
+ \param out output signal (hop_s long)
+
+*/
+void aubio_pvoc_rdo(aubio_pvoc_t *pv, cvec_t * fftgrain, fvec_t *out);
+
+/** get window size
+
+ \param pv phase vocoder to get the window size from
+
+*/
+uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv);
+/** get hop size
+
+ \param pv phase vocoder to get the hop size from
+
+*/
+uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PHASEVOC_H */
diff --git a/src/spectral/specdesc.c b/src/spectral/specdesc.c
new file mode 100644
index 0000000..fb9b2f7
--- /dev/null
+++ b/src/spectral/specdesc.c
@@ -0,0 +1,399 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/fft.h"
+#include "spectral/specdesc.h"
+#include "mathutils.h"
+#include "utils/hist.h"
+
+void aubio_specdesc_energy(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_hfc(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_complex(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_phase(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specdiff(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+
+extern void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+
+/** onsetdetection types */
+typedef enum {
+ aubio_onset_energy, /**< energy based */
+ aubio_onset_specdiff, /**< spectral diff */
+ aubio_onset_hfc, /**< high frequency content */
+ aubio_onset_complex, /**< complex domain */
+ aubio_onset_phase, /**< phase fast */
+ aubio_onset_kl, /**< Kullback Liebler */
+ aubio_onset_mkl, /**< modified Kullback Liebler */
+ aubio_onset_specflux, /**< spectral flux */
+ aubio_specmethod_centroid, /**< spectral centroid */
+ aubio_specmethod_spread, /**< spectral spread */
+ aubio_specmethod_skewness, /**< spectral skewness */
+ aubio_specmethod_kurtosis, /**< spectral kurtosis */
+ aubio_specmethod_slope, /**< spectral kurtosis */
+ aubio_specmethod_decrease, /**< spectral decrease */
+ aubio_specmethod_rolloff, /**< spectral rolloff */
+ aubio_onset_default = aubio_onset_hfc, /**< default mode, set to hfc */
+} aubio_specdesc_type;
+
+/** structure to store object state */
+struct _aubio_specdesc_t {
+ aubio_specdesc_type onset_type; /**< onset detection type */
+ /** Pointer to aubio_specdesc_<type> function */
+ void (*funcpointer)(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset);
+ smpl_t threshold; /**< minimum norm threshold for phase and specdiff */
+ fvec_t *oldmag; /**< previous norm vector */
+ fvec_t *dev1 ; /**< current onset detection measure vector */
+ fvec_t *theta1; /**< previous phase vector, one frame behind */
+ fvec_t *theta2; /**< previous phase vector, two frames behind */
+ aubio_hist_t * histog; /**< histogram */
+};
+
+
+/* Energy based onset detection function */
+void aubio_specdesc_energy (aubio_specdesc_t *o UNUSED,
+ const cvec_t * fftgrain, fvec_t * onset) {
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;j<fftgrain->length;j++) {
+ onset->data[0] += SQR(fftgrain->norm[j]);
+ }
+}
+
+/* High Frequency Content onset detection function */
+void aubio_specdesc_hfc(aubio_specdesc_t *o UNUSED,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;j<fftgrain->length;j++) {
+ onset->data[0] += (j+1)*fftgrain->norm[j];
+ }
+}
+
+
+/* Complex Domain Method onset detection function */
+void aubio_specdesc_complex (aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset) {
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.;
+ for (j=0;j<nbins; j++) {
+ // compute the predicted phase
+ o->dev1->data[j] = 2. * o->theta1->data[j] - o->theta2->data[j];
+ // compute the euclidean distance in the complex domain
+ // sqrt ( r_1^2 + r_2^2 - 2 * r_1 * r_2 * \cos ( \phi_1 - \phi_2 ) )
+ onset->data[0] +=
+ SQRT (ABS (SQR (o->oldmag->data[j]) + SQR (fftgrain->norm[j])
+ - 2 * o->oldmag->data[j] * fftgrain->norm[j]
+ * COS (o->dev1->data[j] - fftgrain->phas[j])));
+ /* swap old phase data (need to remember 2 frames behind)*/
+ o->theta2->data[j] = o->theta1->data[j];
+ o->theta1->data[j] = fftgrain->phas[j];
+ /* swap old magnitude data (1 frame is enough) */
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+}
+
+
+/* Phase Based Method onset detection function */
+void aubio_specdesc_phase(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.0;
+ o->dev1->data[0]=0.;
+ for ( j=0;j<nbins; j++ ) {
+ o->dev1->data[j] =
+ aubio_unwrap2pi(
+ fftgrain->phas[j]
+ -2.0*o->theta1->data[j]
+ +o->theta2->data[j]);
+ if ( o->threshold < fftgrain->norm[j] )
+ o->dev1->data[j] = ABS(o->dev1->data[j]);
+ else
+ o->dev1->data[j] = 0.0;
+ /* keep a track of the past frames */
+ o->theta2->data[j] = o->theta1->data[j];
+ o->theta1->data[j] = fftgrain->phas[j];
+ }
+ /* apply o->histogram */
+ aubio_hist_dyn_notnull(o->histog,o->dev1);
+ /* weight it */
+ aubio_hist_weight(o->histog);
+ /* its mean is the result */
+ onset->data[0] = aubio_hist_mean(o->histog);
+ //onset->data[0] = fvec_mean(o->dev1);
+}
+
+/* Spectral difference method onset detection function */
+void aubio_specdesc_specdiff(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.0;
+ for (j=0;j<nbins; j++) {
+ o->dev1->data[j] = SQRT(
+ ABS(SQR( fftgrain->norm[j])
+ - SQR(o->oldmag->data[j])));
+ if (o->threshold < fftgrain->norm[j] )
+ o->dev1->data[j] = ABS(o->dev1->data[j]);
+ else
+ o->dev1->data[j] = 0.0;
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+
+ /* apply o->histogram (act somewhat as a low pass on the
+ * overall function)*/
+ aubio_hist_dyn_notnull(o->histog,o->dev1);
+ /* weight it */
+ aubio_hist_weight(o->histog);
+ /* its mean is the result */
+ onset->data[0] = aubio_hist_mean(o->histog);
+}
+
+/* Kullback Liebler onset detection function
+ * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
+ * negative (1.+) and infinite values (+1.e-10) */
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;j<fftgrain->length;j++) {
+ onset->data[0] += fftgrain->norm[j]
+ *LOG(1.+fftgrain->norm[j]/(o->oldmag->data[j]+1.e-1));
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+ if (isnan(onset->data[0])) onset->data[0] = 0.;
+}
+
+/* Modified Kullback Liebler onset detection function
+ * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
+ * negative (1.+) and infinite values (+1.e-10) */
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;j<fftgrain->length;j++) {
+ onset->data[0] += LOG(1.+fftgrain->norm[j]/(o->oldmag->data[j]+1.e-1));
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+ if (isnan(onset->data[0])) onset->data[0] = 0.;
+}
+
+/* Spectral flux */
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;j<fftgrain->length;j++) {
+ if (fftgrain->norm[j] > o->oldmag->data[j])
+ onset->data[0] += fftgrain->norm[j] - o->oldmag->data[j];
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+}
+
+/* Generic function pointing to the choosen one */
+void
+aubio_specdesc_do (aubio_specdesc_t *o, const cvec_t * fftgrain,
+ fvec_t * onset) {
+ o->funcpointer(o,fftgrain,onset);
+}
+
+/* Allocate memory for an onset detection
+ * depending on the choosen type, allocate memory as needed
+ */
+aubio_specdesc_t *
+new_aubio_specdesc (const char_t * onset_mode, uint_t size){
+ aubio_specdesc_t * o = AUBIO_NEW(aubio_specdesc_t);
+ uint_t rsize = size/2+1;
+ aubio_specdesc_type onset_type;
+ if (strcmp (onset_mode, "energy") == 0)
+ onset_type = aubio_onset_energy;
+ else if (strcmp (onset_mode, "specdiff") == 0)
+ onset_type = aubio_onset_specdiff;
+ else if (strcmp (onset_mode, "hfc") == 0)
+ onset_type = aubio_onset_hfc;
+ else if (strcmp (onset_mode, "complexdomain") == 0)
+ onset_type = aubio_onset_complex;
+ else if (strcmp (onset_mode, "complex") == 0)
+ onset_type = aubio_onset_complex;
+ else if (strcmp (onset_mode, "phase") == 0)
+ onset_type = aubio_onset_phase;
+ else if (strcmp (onset_mode, "mkl") == 0)
+ onset_type = aubio_onset_mkl;
+ else if (strcmp (onset_mode, "kl") == 0)
+ onset_type = aubio_onset_kl;
+ else if (strcmp (onset_mode, "specflux") == 0)
+ onset_type = aubio_onset_specflux;
+ else if (strcmp (onset_mode, "centroid") == 0)
+ onset_type = aubio_specmethod_centroid;
+ else if (strcmp (onset_mode, "spread") == 0)
+ onset_type = aubio_specmethod_spread;
+ else if (strcmp (onset_mode, "skewness") == 0)
+ onset_type = aubio_specmethod_skewness;
+ else if (strcmp (onset_mode, "kurtosis") == 0)
+ onset_type = aubio_specmethod_kurtosis;
+ else if (strcmp (onset_mode, "slope") == 0)
+ onset_type = aubio_specmethod_slope;
+ else if (strcmp (onset_mode, "decrease") == 0)
+ onset_type = aubio_specmethod_decrease;
+ else if (strcmp (onset_mode, "rolloff") == 0)
+ onset_type = aubio_specmethod_rolloff;
+ else if (strcmp (onset_mode, "default") == 0)
+ onset_type = aubio_onset_default;
+ else {
+ AUBIO_ERR("unknown spectral descriptor type %s, using default.\n", onset_mode);
+ onset_type = aubio_onset_default;
+ }
+ switch(onset_type) {
+ /* for both energy and hfc, only fftgrain->norm is required */
+ case aubio_onset_energy:
+ break;
+ case aubio_onset_hfc:
+ break;
+ /* the other approaches will need some more memory spaces */
+ case aubio_onset_complex:
+ o->oldmag = new_fvec(rsize);
+ o->dev1 = new_fvec(rsize);
+ o->theta1 = new_fvec(rsize);
+ o->theta2 = new_fvec(rsize);
+ break;
+ case aubio_onset_phase:
+ o->dev1 = new_fvec(rsize);
+ o->theta1 = new_fvec(rsize);
+ o->theta2 = new_fvec(rsize);
+ o->histog = new_aubio_hist(0.0, PI, 10);
+ o->threshold = 0.1;
+ break;
+ case aubio_onset_specdiff:
+ o->oldmag = new_fvec(rsize);
+ o->dev1 = new_fvec(rsize);
+ o->histog = new_aubio_hist(0.0, PI, 10);
+ o->threshold = 0.1;
+ break;
+ case aubio_onset_kl:
+ case aubio_onset_mkl:
+ case aubio_onset_specflux:
+ o->oldmag = new_fvec(rsize);
+ break;
+ default:
+ break;
+ }
+
+ switch(onset_type) {
+ case aubio_onset_energy:
+ o->funcpointer = aubio_specdesc_energy;
+ break;
+ case aubio_onset_hfc:
+ o->funcpointer = aubio_specdesc_hfc;
+ break;
+ case aubio_onset_complex:
+ o->funcpointer = aubio_specdesc_complex;
+ break;
+ case aubio_onset_phase:
+ o->funcpointer = aubio_specdesc_phase;
+ break;
+ case aubio_onset_specdiff:
+ o->funcpointer = aubio_specdesc_specdiff;
+ break;
+ case aubio_onset_kl:
+ o->funcpointer = aubio_specdesc_kl;
+ break;
+ case aubio_onset_mkl:
+ o->funcpointer = aubio_specdesc_mkl;
+ break;
+ case aubio_onset_specflux:
+ o->funcpointer = aubio_specdesc_specflux;
+ break;
+ case aubio_specmethod_centroid:
+ o->funcpointer = aubio_specdesc_centroid;
+ break;
+ case aubio_specmethod_spread:
+ o->funcpointer = aubio_specdesc_spread;
+ break;
+ case aubio_specmethod_skewness:
+ o->funcpointer = aubio_specdesc_skewness;
+ break;
+ case aubio_specmethod_kurtosis:
+ o->funcpointer = aubio_specdesc_kurtosis;
+ break;
+ case aubio_specmethod_slope:
+ o->funcpointer = aubio_specdesc_slope;
+ break;
+ case aubio_specmethod_decrease:
+ o->funcpointer = aubio_specdesc_decrease;
+ break;
+ case aubio_specmethod_rolloff:
+ o->funcpointer = aubio_specdesc_rolloff;
+ break;
+ default:
+ break;
+ }
+ o->onset_type = onset_type;
+ return o;
+}
+
+void del_aubio_specdesc (aubio_specdesc_t *o){
+ switch(o->onset_type) {
+ case aubio_onset_energy:
+ break;
+ case aubio_onset_hfc:
+ break;
+ case aubio_onset_complex:
+ del_fvec(o->oldmag);
+ del_fvec(o->dev1);
+ del_fvec(o->theta1);
+ del_fvec(o->theta2);
+ break;
+ case aubio_onset_phase:
+ del_fvec(o->dev1);
+ del_fvec(o->theta1);
+ del_fvec(o->theta2);
+ del_aubio_hist(o->histog);
+ break;
+ case aubio_onset_specdiff:
+ del_fvec(o->oldmag);
+ del_fvec(o->dev1);
+ del_aubio_hist(o->histog);
+ break;
+ case aubio_onset_kl:
+ case aubio_onset_mkl:
+ case aubio_onset_specflux:
+ del_fvec(o->oldmag);
+ break;
+ default:
+ break;
+ }
+ AUBIO_FREE(o);
+}
diff --git a/src/spectral/specdesc.h b/src/spectral/specdesc.h
new file mode 100644
index 0000000..2cdb87a
--- /dev/null
+++ b/src/spectral/specdesc.h
@@ -0,0 +1,194 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Spectral description functions
+
+ All of the following spectral description functions take as arguments the FFT
+ of a windowed signal (as created with aubio_pvoc). They output one smpl_t per
+ buffer (stored in a vector of size [1]).
+
+ \section specdesc Spectral description functions
+
+ A list of the spectral description methods currently available follows.
+
+ \subsection onsetdesc Onset detection functions
+
+ These functions are designed to raise at notes attacks in music signals.
+
+ \b \p energy : Energy based onset detection function
+
+ This function calculates the local energy of the input spectral frame.
+
+ \b \p hfc : High Frequency Content onset detection function
+
+ This method computes the High Frequency Content (HFC) of the input spectral
+ frame. The resulting function is efficient at detecting percussive onsets.
+
+ Paul Masri. Computer modeling of Sound for Transformation and Synthesis of
+ Musical Signal. PhD dissertation, University of Bristol, UK, 1996.
+
+ \b \p complex : Complex Domain Method onset detection function
+
+ Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain
+ onset detection for musical signals. In Proceedings of the Digital Audio
+ Effects Conference, DAFx-03, pages 90-93, London, UK, 2003.
+
+ \b \p phase : Phase Based Method onset detection function
+
+ Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset
+ detection for music signals. In Proceedings of the IEEE International
+ Conference on Acoustics Speech and Signal Processing, pages 441­444,
+ Hong-Kong, 2003.
+
+ \b \p specdiff : Spectral difference method onset detection function
+
+ Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
+ rhythm analysis. In IEEE International Conference on Multimedia and Expo
+ (ICME 2001), pages 881­884, Tokyo, Japan, August 2001.
+
+ \b \p kl : Kullback-Liebler onset detection function
+
+ Stephen Hainsworth and Malcom Macleod. Onset detection in music audio
+ signals. In Proceedings of the International Computer Music Conference
+ (ICMC), Singapore, 2003.
+
+ \b \p mkl : Modified Kullback-Liebler onset detection function
+
+ Paul Brossier, ``Automatic annotation of musical audio for interactive
+ systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital
+ music, Queen Mary University of London, London, UK, 2006.
+
+ \b \p specflux : Spectral Flux
+
+ Simon Dixon, Onset Detection Revisited, in ``Proceedings of the 9th
+ International Conference on Digital Audio Effects'' (DAFx-06), Montreal,
+ Canada, 2006.
+
+ \subsection shapedesc Spectral shape descriptors
+
+ The following descriptors are described in:
+
+ Geoffroy Peeters, <i>A large set of audio features for sound description
+ (similarity and classification) in the CUIDADO project</i>, CUIDADO I.S.T.
+ Project Report 2004 (<a
+ href="http://www.ircam.fr/anasyn/peeters/ARTICLES/Peeters_2003_cuidadoaudiofeatures.pdf">pdf</a>)
+
+ \b \p centroid : Spectral centroid
+
+ The spectral centroid represents the barycenter of the spectrum.
+
+ \e Note: This function returns the result in bin. To get the spectral
+ centroid in Hz, aubio_bintofreq() should be used.
+
+ \b \p spread : Spectral spread
+
+ The spectral spread is the variance of the spectral distribution around its
+ centroid.
+
+ See also <a href="http://en.wikipedia.org/wiki/Standard_deviation">Standard
+ deviation</a> on Wikipedia.
+
+ \b \p skewness : Spectral skewness
+
+ Similarly, the skewness is computed from the third order moment of the
+ spectrum. A negative skewness indicates more energy on the lower part of the
+ spectrum. A positive skewness indicates more energy on the high frequency of
+ the spectrum.
+
+ See also <a href="http://en.wikipedia.org/wiki/Skewness">Skewness</a> on
+ Wikipedia.
+
+ \b \p kurtosis : Spectral kurtosis
+
+ The kurtosis is a measure of the flatness of the spectrum, computed from the
+ fourth order moment.
+
+ See also <a href="http://en.wikipedia.org/wiki/Kurtosis">Kurtosis</a> on
+ Wikipedia.
+
+ \b \p slope : Spectral slope
+
+ The spectral slope represents decreasing rate of the spectral amplitude,
+ computed using a linear regression.
+
+ \b \p decrease : Spectral decrease
+
+ The spectral decrease is another representation of the decreasing rate,
+ based on perceptual criteria.
+
+ \b \p rolloff : Spectral roll-off
+
+ This function returns the bin number below which 95% of the spectrum energy
+ is found.
+
+ \example spectral/test-specdesc.c
+
+*/
+
+
+#ifndef AUBIO_SPECDESC_H
+#define AUBIO_SPECDESC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** spectral description structure */
+typedef struct _aubio_specdesc_t aubio_specdesc_t;
+
+/** execute spectral description function on a spectral frame
+
+ Generic function to compute spectral description.
+
+ \param o spectral description object as returned by new_aubio_specdesc()
+ \param fftgrain input signal spectrum as computed by aubio_pvoc_do
+ \param desc output vector (one sample long, to send to the peak picking)
+
+*/
+void aubio_specdesc_do (aubio_specdesc_t * o, const cvec_t * fftgrain,
+ fvec_t * desc);
+
+/** creation of a spectral description object
+
+ \param method spectral description method
+ \param buf_size length of the input spectrum frame
+
+ The parameter \p method is a string that can be any of:
+
+ - `energy`, `hfc`, `complex`, `phase`, `specdiff`, `kl`, `mkl`, `specflux`
+ - `centroid`, `spread`, `skewness`, `kurtosis`, `slope`, `decrease`, `rolloff`
+
+*/
+aubio_specdesc_t *new_aubio_specdesc (const char_t * method, uint_t buf_size);
+
+/** deletion of a spectral descriptor
+
+ \param o spectral descriptor object as returned by new_aubio_specdesc()
+
+*/
+void del_aubio_specdesc (aubio_specdesc_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SPECDESC_H */
diff --git a/src/spectral/statistics.c b/src/spectral/statistics.c
new file mode 100644
index 0000000..4fd66c0
--- /dev/null
+++ b/src/spectral/statistics.c
@@ -0,0 +1,204 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+
+void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+
+
+smpl_t cvec_sum (const cvec_t * s);
+smpl_t cvec_mean (const cvec_t * s);
+smpl_t cvec_centroid (const cvec_t * s);
+smpl_t cvec_moment (const cvec_t * s, uint_t moment);
+
+smpl_t
+cvec_sum (const cvec_t * s)
+{
+ uint_t j;
+ smpl_t tmp = 0.0;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->norm[j];
+ }
+ return tmp;
+}
+
+smpl_t
+cvec_mean (const cvec_t * s)
+{
+ return cvec_sum (s) / (smpl_t) (s->length);
+}
+
+smpl_t
+cvec_centroid (const cvec_t * spec)
+{
+ smpl_t sum = 0., sc = 0.;
+ uint_t j;
+ sum = cvec_sum (spec);
+ if (sum == 0.) {
+ return 0.;
+ } else {
+ for (j = 0; j < spec->length; j++) {
+ sc += (smpl_t) j *spec->norm[j];
+ }
+ return sc / sum;
+ }
+}
+
+smpl_t
+cvec_moment (const cvec_t * spec, uint_t order)
+{
+ smpl_t sum = 0., centroid = 0., sc = 0.;
+ uint_t j;
+ sum = cvec_sum (spec);
+ if (sum == 0.) {
+ return 0.;
+ } else {
+ centroid = cvec_centroid (spec);
+ for (j = 0; j < spec->length; j++) {
+ sc += (smpl_t) POW(j - centroid, order) * spec->norm[j];
+ }
+ return sc / sum;
+ }
+}
+
+void
+aubio_specdesc_centroid (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ desc->data[0] = cvec_centroid (spec);
+}
+
+void
+aubio_specdesc_spread (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ desc->data[0] = cvec_moment (spec, 2);
+}
+
+void
+aubio_specdesc_skewness (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ smpl_t spread;
+ spread = cvec_moment (spec, 2);
+ if (spread == 0) {
+ desc->data[0] = 0.;
+ } else {
+ desc->data[0] = cvec_moment (spec, 3);
+ desc->data[0] /= POW ( SQRT (spread), 3);
+ }
+}
+
+void
+aubio_specdesc_kurtosis (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ smpl_t spread;
+ spread = cvec_moment (spec, 2);
+ if (spread == 0) {
+ desc->data[0] = 0.;
+ } else {
+ desc->data[0] = cvec_moment (spec, 4);
+ desc->data[0] /= SQR (spread);
+ }
+}
+
+void
+aubio_specdesc_slope (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ uint_t j;
+ smpl_t norm = 0, sum = 0.;
+ // compute N * sum(j**2) - sum(j)**2
+ for (j = 0; j < spec->length; j++) {
+ norm += j*j;
+ }
+ norm *= spec->length;
+ // sum_0^N(j) = length * (length + 1) / 2
+ norm -= SQR( (spec->length) * (spec->length - 1.) / 2. );
+ sum = cvec_sum (spec);
+ desc->data[0] = 0.;
+ if (sum == 0.) {
+ return;
+ } else {
+ for (j = 0; j < spec->length; j++) {
+ desc->data[0] += j * spec->norm[j];
+ }
+ desc->data[0] *= spec->length;
+ desc->data[0] -= sum * spec->length * (spec->length - 1) / 2.;
+ desc->data[0] /= norm;
+ desc->data[0] /= sum;
+ }
+}
+
+void
+aubio_specdesc_decrease (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ uint_t j; smpl_t sum;
+ sum = cvec_sum (spec);
+ desc->data[0] = 0;
+ if (sum == 0.) {
+ return;
+ } else {
+ sum -= spec->norm[0];
+ for (j = 1; j < spec->length; j++) {
+ desc->data[0] += (spec->norm[j] - spec->norm[0]) / j;
+ }
+ desc->data[0] /= sum;
+ }
+}
+
+void
+aubio_specdesc_rolloff (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
+ fvec_t *desc)
+{
+ uint_t j; smpl_t cumsum, rollsum;
+ cumsum = 0.; rollsum = 0.;
+ for (j = 0; j < spec->length; j++) {
+ cumsum += SQR (spec->norm[j]);
+ }
+ if (cumsum == 0) {
+ desc->data[0] = 0.;
+ } else {
+ cumsum *= 0.95;
+ j = 0;
+ while (rollsum < cumsum) {
+ rollsum += SQR (spec->norm[j]);
+ j++;
+ }
+ desc->data[0] = j;
+ }
+}
diff --git a/src/spectral/tss.c b/src/spectral/tss.c
new file mode 100644
index 0000000..8b57bf3
--- /dev/null
+++ b/src/spectral/tss.c
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* default values : alpha=4, beta=3, threshold=0.25 */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/tss.h"
+
+struct _aubio_tss_t
+{
+ smpl_t threshold;
+ smpl_t alpha;
+ smpl_t beta;
+ smpl_t parm;
+ smpl_t thrsfact;
+ fvec_t *theta1;
+ fvec_t *theta2;
+ fvec_t *oft1;
+ fvec_t *oft2;
+ fvec_t *dev;
+};
+
+void aubio_tss_do(aubio_tss_t *o, const cvec_t * input,
+ cvec_t * trans, cvec_t * stead)
+{
+ uint_t j;
+ uint_t test;
+ uint_t nbins = input->length;
+ smpl_t alpha = o->alpha;
+ smpl_t beta = o->beta;
+ smpl_t parm = o->parm;
+ smpl_t * dev = (smpl_t *)o->dev->data;
+ smpl_t * oft1 = (smpl_t *)o->oft1->data;
+ smpl_t * oft2 = (smpl_t *)o->oft2->data;
+ smpl_t * theta1 = (smpl_t *)o->theta1->data;
+ smpl_t * theta2 = (smpl_t *)o->theta2->data;
+ /* second phase derivative */
+ for (j=0;j<nbins; j++){
+ dev[j] = aubio_unwrap2pi(input->phas[j]
+ -2.0*theta1[j]+theta2[j]);
+ theta2[j] = theta1[j];
+ theta1[j] = input->phas[j];
+
+ /* transient analysis */
+ test = (ABS(dev[j]) > parm*oft1[j]);
+ trans->norm[j] = input->norm[j] * test;
+ trans->phas[j] = input->phas[j] * test;
+
+ /* steady state analysis */
+ test = (ABS(dev[j]) < parm*oft2[j]);
+ stead->norm[j] = input->norm[j] * test;
+ stead->phas[j] = input->phas[j] * test;
+
+ /*increase probability for transient */
+ test = (trans->norm[j]==0.);
+ oft1[j] = test;
+ test = (trans->norm[j]>0.);
+ oft1[j] += alpha*test;
+ test = (oft1[j]>1. && trans->norm[j]>0.);
+ oft1[j] += beta*test;
+
+ /*increase probability for steady states */
+ test = (stead->norm[j]==0.);
+ oft2[j] = test;
+ test = (stead->norm[j]>0.);
+ oft2[j] += alpha*test;
+ test = (oft2[j]>1. && stead->norm[j]>0.);
+ oft2[j] += beta*test;
+ }
+}
+
+uint_t aubio_tss_set_threshold(aubio_tss_t *o, smpl_t threshold){
+ o->threshold = threshold;
+ o->parm = o->threshold * o->thrsfact;
+ return AUBIO_OK;
+}
+
+aubio_tss_t * new_aubio_tss(uint_t buf_size, uint_t hop_size)
+{
+ aubio_tss_t * o = AUBIO_NEW(aubio_tss_t);
+ uint_t rsize = buf_size/2+1;
+ o->threshold = 0.25;
+ o->thrsfact = TWO_PI*hop_size/rsize;
+ o->alpha = 3.;
+ o->beta = 4.;
+ o->parm = o->threshold*o->thrsfact;
+ o->theta1 = new_fvec(rsize);
+ o->theta2 = new_fvec(rsize);
+ o->oft1 = new_fvec(rsize);
+ o->oft2 = new_fvec(rsize);
+ o->dev = new_fvec(rsize);
+ return o;
+}
+
+void del_aubio_tss(aubio_tss_t *s)
+{
+ del_fvec(s->theta1);
+ del_fvec(s->theta2);
+ del_fvec(s->oft1);
+ del_fvec(s->oft2);
+ del_fvec(s->dev);
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_tss_set_alpha(aubio_tss_t *o, smpl_t alpha){
+ o->alpha = alpha;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tss_set_beta(aubio_tss_t *o, smpl_t beta){
+ o->beta = beta;
+ return AUBIO_OK;
+}
+
diff --git a/src/spectral/tss.h b/src/spectral/tss.h
new file mode 100644
index 0000000..a4f54a1
--- /dev/null
+++ b/src/spectral/tss.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Transient / Steady-state Separation (TSS)
+
+ This file implement a Transient / Steady-state Separation (TSS) as described
+ in:
+
+ Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Separation of
+ transient information in musical audio using multiresolution analysis
+ techniques. In Proceedings of the Digital Audio Effects Conference, DAFx-01,
+ pages 1--5, Limerick, Ireland, 2001.
+
+ Available at http://www.csis.ul.ie/dafx01/proceedings/papers/duxbury.pdf
+
+ \example spectral/test-tss.c
+
+*/
+
+#ifndef AUBIO_TSS_H
+#define AUBIO_TSS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Transient / Steady-state Separation object */
+typedef struct _aubio_tss_t aubio_tss_t;
+
+/** create tss object
+
+ \param buf_size buffer size
+ \param hop_size step size
+
+*/
+aubio_tss_t *new_aubio_tss (uint_t buf_size, uint_t hop_size);
+
+/** delete tss object
+
+ \param o tss object as returned by new_aubio_tss()
+
+*/
+void del_aubio_tss (aubio_tss_t * o);
+
+/** split input into transient and steady states components
+
+ \param o tss object as returned by new_aubio_tss()
+ \param input input spectral frame
+ \param trans output transient components
+ \param stead output steady state components
+
+*/
+void aubio_tss_do (aubio_tss_t * o, const cvec_t * input, cvec_t * trans,
+ cvec_t * stead);
+
+/** set transient / steady state separation threshold
+
+ \param o tss object as returned by new_aubio_tss()
+ \param thrs new threshold value
+
+*/
+uint_t aubio_tss_set_threshold (aubio_tss_t * o, smpl_t thrs);
+
+/** set parameter a, defaults to 3
+
+ \param o tss object as returned by new_aubio_tss()
+ \param alpha new value for alpha parameter
+
+*/
+uint_t aubio_tss_set_alpha (aubio_tss_t * o, smpl_t alpha);
+
+/** set parameter b, defaults to 3
+
+ \param o tss object as returned by new_aubio_tss()
+ \param beta new value for beta parameter
+
+*/
+uint_t aubio_tss_set_beta (aubio_tss_t * o, smpl_t beta);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TSS_H */
diff --git a/src/synth/sampler.c b/src/synth/sampler.c
new file mode 100644
index 0000000..7df1b5f
--- /dev/null
+++ b/src/synth/sampler.c
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/source.h"
+#include "synth/sampler.h"
+
+struct _aubio_sampler_t {
+ uint_t samplerate;
+ uint_t blocksize;
+ aubio_source_t *source;
+ fvec_t *source_output;
+ fmat_t *source_output_multi;
+ char_t *uri;
+ uint_t playing;
+};
+
+aubio_sampler_t *new_aubio_sampler(uint_t samplerate, uint_t blocksize)
+{
+ aubio_sampler_t *s = AUBIO_NEW(aubio_sampler_t);
+ if ((sint_t)blocksize < 1) {
+ AUBIO_ERR("sampler: got blocksize %d, but can not be < 1\n", blocksize);
+ goto beach;
+ }
+ s->samplerate = samplerate;
+ s->blocksize = blocksize;
+ s->source_output = new_fvec(blocksize);
+ s->source_output_multi = new_fmat(4, blocksize);
+ s->source = NULL;
+ s->playing = 0;
+ return s;
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri )
+{
+ if (o->source) del_aubio_source(o->source);
+
+ if (o->uri) AUBIO_FREE(o->uri);
+ o->uri = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX));
+ strncpy(o->uri, uri, strnlen(uri, PATH_MAX));
+
+ o->source = new_aubio_source(uri, o->samplerate, o->blocksize);
+ if (o->source) return 0;
+ AUBIO_ERR("sampler: failed loading %s", uri);
+ return 1;
+}
+
+void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output)
+{
+ uint_t read = 0, i;
+ if (o->playing) {
+ aubio_source_do (o->source, o->source_output, &read);
+ for (i = 0; i < output->length; i++) {
+ output->data[i] += o->source_output->data[i];
+ }
+ if (read < o->blocksize) o->playing = 0;
+ }
+ if (input && input != output) {
+ for (i = 0; i < output->length; i++) {
+ output->data[i] += input->data[i];
+ }
+ }
+}
+
+void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output)
+{
+ uint_t read = 0, i, j;
+ if (o->playing) {
+ aubio_source_do_multi (o->source, o->source_output_multi, &read);
+ for (i = 0; i < output->height; i++) {
+ for (j = 0; j < output->length; j++) {
+ output->data[i][j] += o->source_output_multi->data[i][j];
+ }
+ }
+ if ( read < o->blocksize ) o->playing = 0;
+ }
+ if (input && input != output) {
+ for (i = 0; i < output->height; i++) {
+ for (j = 0; j < output->length; j++) {
+ output->data[i][j] += input->data[i][j];
+ }
+ }
+ }
+}
+
+uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o )
+{
+ return o->playing;
+}
+
+uint_t aubio_sampler_set_playing ( aubio_sampler_t * o, uint_t playing )
+{
+ o->playing = (playing == 1) ? 1 : 0;
+ return 0;
+}
+
+uint_t aubio_sampler_play ( aubio_sampler_t * o )
+{
+ aubio_source_seek (o->source, 0);
+ return aubio_sampler_set_playing (o, 1);
+}
+
+uint_t aubio_sampler_stop ( aubio_sampler_t * o )
+{
+ return aubio_sampler_set_playing (o, 0);
+}
+
+void del_aubio_sampler( aubio_sampler_t * o )
+{
+ if (o->source) {
+ del_aubio_source(o->source);
+ }
+ if (o->uri) AUBIO_FREE(o->uri);
+ del_fvec(o->source_output);
+ del_fmat(o->source_output_multi);
+ AUBIO_FREE(o);
+}
diff --git a/src/synth/sampler.h b/src/synth/sampler.h
new file mode 100644
index 0000000..fb1304f
--- /dev/null
+++ b/src/synth/sampler.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_SAMPLER_H
+#define AUBIO_SAMPLER_H
+
+/** \file
+
+ Load and play sound files.
+
+ This file loads a sample and gets ready to play it.
+
+ The `_do` function adds the new samples to the input, and write the result as
+ the output.
+
+ \example synth/test-sampler.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sampler object */
+typedef struct _aubio_sampler_t aubio_sampler_t;
+
+/** create new sampler object
+
+ \param samplerate the sampling rate of the new sampler
+ \param hop_size the block size of the new sampler
+
+ \return the newly created ::aubio_sampler_t
+
+*/
+aubio_sampler_t * new_aubio_sampler(uint_t samplerate, uint_t hop_size);
+
+/** load source in sampler
+
+ \param o sampler, created by new_aubio_sampler()
+ \param uri the uri of the source to load
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri );
+
+/** process sampler function
+
+ \param o sampler, created by new_aubio_sampler()
+ \param input input of the sampler, to be added to the output
+ \param output output of the sampler
+
+This function adds the new samples from the playing source to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output);
+
+/** process sampler function, multiple channels
+
+ \param o sampler, created by new_aubio_sampler()
+ \param input input of the sampler, to be added to the output
+ \param output output of the sampler
+
+This function adds the new samples from the playing source to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output);
+
+/** get current playing state
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if not playing, 1 if playing
+
+*/
+uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o );
+
+/** set current playing state
+
+ \param o sampler, created by new_aubio_sampler()
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_set_playing ( aubio_sampler_t * o, uint_t playing );
+
+/** play sample from start
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_play ( aubio_sampler_t * o );
+
+/** stop sample
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_stop ( aubio_sampler_t * o );
+
+/** destroy ::aubio_sampler_t object
+
+ \param o sampler, created by new_aubio_sampler()
+
+*/
+void del_aubio_sampler( aubio_sampler_t * o );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SAMPLER_H */
diff --git a/src/synth/wavetable.c b/src/synth/wavetable.c
new file mode 100644
index 0000000..830ffd7
--- /dev/null
+++ b/src/synth/wavetable.c
@@ -0,0 +1,194 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "utils/parameter.h"
+#include "synth/wavetable.h"
+
+#define WAVETABLE_LEN 4096
+
+struct _aubio_wavetable_t {
+ uint_t samplerate;
+ uint_t blocksize;
+ uint_t wavetable_length;
+ fvec_t *wavetable;
+ uint_t playing;
+ smpl_t last_pos;
+
+ aubio_parameter_t *freq;
+ aubio_parameter_t *amp;
+};
+
+aubio_wavetable_t *new_aubio_wavetable(uint_t samplerate, uint_t blocksize)
+{
+ uint_t i = 0;
+ aubio_wavetable_t *s = AUBIO_NEW(aubio_wavetable_t);
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERR("Can not create wavetable with samplerate %d\n", samplerate);
+ goto beach;
+ }
+ s->samplerate = samplerate;
+ s->blocksize = blocksize;
+ s->wavetable_length = WAVETABLE_LEN;
+ s->wavetable = new_fvec(s->wavetable_length + 3);
+ for (i = 0; i < s->wavetable_length; i++) {
+ s->wavetable->data[i] = SIN(TWO_PI * i / (smpl_t) s->wavetable_length );
+ }
+ s->wavetable->data[s->wavetable_length] = s->wavetable->data[0];
+ s->wavetable->data[s->wavetable_length + 1] = s->wavetable->data[1];
+ s->wavetable->data[s->wavetable_length + 2] = s->wavetable->data[2];
+ s->playing = 0;
+ s->last_pos = 0.;
+ s->freq = new_aubio_parameter( 0., s->samplerate / 2., 10 );
+ s->amp = new_aubio_parameter( 0., 1., 100 );
+ return s;
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+static smpl_t interp_2(const fvec_t *input, smpl_t pos) {
+ uint_t idx = (uint_t)FLOOR(pos);
+ smpl_t frac = pos - (smpl_t)idx;
+ smpl_t a = input->data[idx];
+ smpl_t b = input->data[idx + 1];
+ return a + frac * ( b - a );
+}
+
+void aubio_wavetable_do ( aubio_wavetable_t * s, const fvec_t * input, fvec_t * output)
+{
+ uint_t i;
+ if (s->playing) {
+ smpl_t pos = s->last_pos;
+ for (i = 0; i < output->length; i++) {
+ smpl_t inc = aubio_parameter_get_next_value( s->freq );
+ inc *= (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
+ pos += inc;
+ while (pos > s->wavetable_length) {
+ pos -= s->wavetable_length;
+ }
+ output->data[i] = aubio_parameter_get_next_value ( s->amp );
+ output->data[i] *= interp_2(s->wavetable, pos);
+ }
+ s->last_pos = pos;
+ } else {
+ for (i = 0; i < output->length; i++) {
+ aubio_parameter_get_next_value ( s->freq );
+ aubio_parameter_get_next_value ( s->amp );
+ }
+ fvec_zeros (output);
+ }
+ // add input to output if needed
+ if (input && input != output) {
+ for (i = 0; i < output->length; i++) {
+ output->data[i] += input->data[i];
+ }
+ }
+}
+
+void aubio_wavetable_do_multi ( aubio_wavetable_t * s, const fmat_t * input, fmat_t * output)
+{
+ uint_t i, j;
+ if (s->playing) {
+ smpl_t pos = s->last_pos;
+ for (j = 0; j < output->length; j++) {
+ smpl_t inc = aubio_parameter_get_next_value( s->freq );
+ smpl_t amp = aubio_parameter_get_next_value ( s->amp );
+ inc *= (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
+ pos += inc;
+ while (pos > s->wavetable_length) {
+ pos -= s->wavetable_length;
+ }
+ for (i = 0; i < output->height; i++) {
+ output->data[i][j] = amp * interp_2(s->wavetable, pos);
+ }
+ }
+ s->last_pos = pos;
+ } else {
+ for (j = 0; j < output->length; j++) {
+ aubio_parameter_get_next_value ( s->freq );
+ aubio_parameter_get_next_value ( s->amp );
+ }
+ fmat_zeros (output);
+ }
+ // add output to input if needed
+ if (input && input != output) {
+ for (i = 0; i < output->height; i++) {
+ for (j = 0; j < output->length; j++) {
+ output->data[i][j] += input->data[i][j];
+ }
+ }
+ }
+}
+
+uint_t aubio_wavetable_get_playing ( const aubio_wavetable_t * s )
+{
+ return s->playing;
+}
+
+uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * s, uint_t playing )
+{
+ s->playing = (playing == 1) ? 1 : 0;
+ return 0;
+}
+
+uint_t aubio_wavetable_play ( aubio_wavetable_t * s )
+{
+ aubio_wavetable_set_amp (s, 0.7);
+ return aubio_wavetable_set_playing (s, 1);
+}
+
+uint_t aubio_wavetable_stop ( aubio_wavetable_t * s )
+{
+ //aubio_wavetable_set_freq (s, 0.);
+ aubio_wavetable_set_amp (s, 0.);
+ //s->last_pos = 0;
+ return aubio_wavetable_set_playing (s, 1);
+}
+
+uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
+{
+ return aubio_parameter_set_target_value ( s->freq, freq );
+}
+
+smpl_t aubio_wavetable_get_freq ( const aubio_wavetable_t * s) {
+ return aubio_parameter_get_current_value ( s->freq);
+}
+
+uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * s, smpl_t amp )
+{
+ return aubio_parameter_set_target_value ( s->amp, amp );
+}
+
+smpl_t aubio_wavetable_get_amp ( const aubio_wavetable_t * s) {
+ return aubio_parameter_get_current_value ( s->amp );
+}
+
+void del_aubio_wavetable( aubio_wavetable_t * s )
+{
+ del_aubio_parameter(s->freq);
+ del_aubio_parameter(s->amp);
+ del_fvec(s->wavetable);
+ AUBIO_FREE(s);
+}
diff --git a/src/synth/wavetable.h b/src/synth/wavetable.h
new file mode 100644
index 0000000..b333575
--- /dev/null
+++ b/src/synth/wavetable.h
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_WAVETABLE_H
+#define AUBIO_WAVETABLE_H
+
+/** \file
+
+ Wavetable synthesis.
+
+ This file creates a wavetable and plays it at different frequency.
+
+ The `_do` function adds the new samples to the input, and write the result as
+ the output.
+
+ \example synth/test-wavetable.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** wavetable object */
+typedef struct _aubio_wavetable_t aubio_wavetable_t;
+
+/** create new wavetable object
+
+ \param samplerate the sampling rate of the new wavetable
+ \param hop_size the block size of the new wavetable
+
+ \return the newly created aubio_wavetable_t
+
+*/
+aubio_wavetable_t * new_aubio_wavetable(uint_t samplerate, uint_t hop_size);
+
+/** load source in wavetable
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param uri the uri of the source to load
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_wavetable_load( aubio_wavetable_t * o, const char_t * uri );
+
+/** process wavetable function
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing wavetable to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do ( aubio_wavetable_t * o, const fvec_t * input, fvec_t * output);
+
+/** process wavetable function, multiple channels
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing wavetable to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do_multi ( aubio_wavetable_t * o, const fmat_t * input, fmat_t * output);
+
+/** get current playing state
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if not playing, 1 if playing
+
+*/
+uint_t aubio_wavetable_get_playing ( const aubio_wavetable_t * o );
+
+/** set current playing state
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * o, uint_t playing );
+
+/** play sample from start
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_play ( aubio_wavetable_t * o );
+
+/** stop wavetable
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_stop ( aubio_wavetable_t * o );
+
+/** set wavetable frequency
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param freq new frequency value for the wavetable
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * o, smpl_t freq );
+
+/** get wavetable frequency
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return current frequency, in Hz
+
+*/
+smpl_t aubio_wavetable_get_freq ( const aubio_wavetable_t * o);
+
+/** set wavetable amplitude
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param amp new amplitude value for the wavetable
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * o, smpl_t amp );
+
+/** get wavetable amplitude
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return current amplitude
+
+*/
+smpl_t aubio_wavetable_get_amp ( const aubio_wavetable_t * o);
+
+/** destroy aubio_wavetable_t object
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+*/
+void del_aubio_wavetable( aubio_wavetable_t * o );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_WAVETABLE_H */
diff --git a/src/tempo/beattracking.c b/src/tempo/beattracking.c
new file mode 100644
index 0000000..6031fe2
--- /dev/null
+++ b/src/tempo/beattracking.c
@@ -0,0 +1,443 @@
+/*
+ Copyright (C) 2005-2009 Matthew Davies and Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "tempo/beattracking.h"
+
+/** define to 1 to print out tracking difficulties */
+#define AUBIO_BEAT_WARNINGS 0
+
+uint_t fvec_gettimesig (fvec_t * acf, uint_t acflen, uint_t gp);
+void aubio_beattracking_checkstate (aubio_beattracking_t * bt);
+
+struct _aubio_beattracking_t
+{
+ uint_t hop_size; /** length of one tempo detection function sample, in audio samples */
+ uint_t samplerate; /** samplerate of the original signal */
+ fvec_t *rwv; /** rayleigh weighting for beat period in general model */
+ fvec_t *dfwv; /** exponential weighting for beat alignment in general model */
+ fvec_t *gwv; /** gaussian weighting for beat period in context dependant model */
+ fvec_t *phwv; /** gaussian weighting for beat alignment in context dependant model */
+ fvec_t *dfrev; /** reversed onset detection function */
+ fvec_t *acf; /** vector for autocorrelation function (of current detection function frame) */
+ fvec_t *acfout; /** store result of passing acf through s.i.c.f.b. */
+ fvec_t *phout;
+ uint_t timesig; /** time signature of input, set to zero until context dependent model activated */
+ uint_t step;
+ uint_t rayparam; /** Rayleigh parameter */
+ smpl_t lastbeat;
+ sint_t counter;
+ uint_t flagstep;
+ smpl_t g_var;
+ smpl_t gp;
+ smpl_t bp;
+ smpl_t rp;
+ smpl_t rp1;
+ smpl_t rp2;
+};
+
+aubio_beattracking_t *
+new_aubio_beattracking (uint_t winlen, uint_t hop_size, uint_t samplerate)
+{
+
+ aubio_beattracking_t *p = AUBIO_NEW (aubio_beattracking_t);
+ uint_t i = 0;
+ /* default value for rayleigh weighting - sets preferred tempo to 120bpm */
+ smpl_t rayparam = 60. * samplerate / 120. / hop_size;
+ smpl_t dfwvnorm = EXP ((LOG (2.0) / rayparam) * (winlen + 2));
+ /* length over which beat period is found [128] */
+ uint_t laglen = winlen / 4;
+ /* step increment - both in detection function samples -i.e. 11.6ms or
+ * 1 onset frame [128] */
+ uint_t step = winlen / 4; /* 1.5 seconds */
+
+ p->hop_size = hop_size;
+ p->samplerate = samplerate;
+ p->lastbeat = 0;
+ p->counter = 0;
+ p->flagstep = 0;
+ p->g_var = 3.901; // constthresh empirically derived!
+ p->rp = 1;
+ p->gp = 0;
+
+ p->rayparam = rayparam;
+ p->step = step;
+ p->rwv = new_fvec (laglen);
+ p->gwv = new_fvec (laglen);
+ p->dfwv = new_fvec (winlen);
+ p->dfrev = new_fvec (winlen);
+ p->acf = new_fvec (winlen);
+ p->acfout = new_fvec (laglen);
+ p->phwv = new_fvec (2 * laglen);
+ p->phout = new_fvec (winlen);
+
+ p->timesig = 0;
+
+ /* exponential weighting, dfwv = 0.5 when i = 43 */
+ for (i = 0; i < winlen; i++) {
+ p->dfwv->data[i] = (EXP ((LOG (2.0) / rayparam) * (i + 1)))
+ / dfwvnorm;
+ }
+
+ for (i = 0; i < (laglen); i++) {
+ p->rwv->data[i] = ((smpl_t) (i + 1.) / SQR ((smpl_t) rayparam)) *
+ EXP ((-SQR ((smpl_t) (i + 1.)) / (2. * SQR ((smpl_t) rayparam))));
+ }
+
+ return p;
+
+}
+
+void
+del_aubio_beattracking (aubio_beattracking_t * p)
+{
+ del_fvec (p->rwv);
+ del_fvec (p->gwv);
+ del_fvec (p->dfwv);
+ del_fvec (p->dfrev);
+ del_fvec (p->acf);
+ del_fvec (p->acfout);
+ del_fvec (p->phwv);
+ del_fvec (p->phout);
+ AUBIO_FREE (p);
+}
+
+
+void
+aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframe,
+ fvec_t * output)
+{
+
+ uint_t i, k;
+ uint_t step = bt->step;
+ uint_t laglen = bt->rwv->length;
+ uint_t winlen = bt->dfwv->length;
+ uint_t maxindex = 0;
+ //number of harmonics in shift invariant comb filterbank
+ uint_t numelem = 4;
+
+ smpl_t phase; // beat alignment (step - lastbeat)
+ smpl_t beat; // beat position
+ smpl_t bp; // beat period
+ uint_t a, b; // used to build shift invariant comb filterbank
+ uint_t kmax; // number of elements used to find beat phase
+
+ /* copy dfframe, apply detection function weighting, and revert */
+ fvec_copy (dfframe, bt->dfrev);
+ fvec_weight (bt->dfrev, bt->dfwv);
+ fvec_rev (bt->dfrev);
+
+ /* compute autocorrelation function */
+ aubio_autocorr (dfframe, bt->acf);
+
+ /* if timesig is unknown, use metrically unbiased version of filterbank */
+ if (!bt->timesig) {
+ numelem = 4;
+ } else {
+ numelem = bt->timesig;
+ }
+
+ /* first and last output values are left intentionally as zero */
+ fvec_zeros (bt->acfout);
+
+ /* compute shift invariant comb filterbank */
+ for (i = 1; i < laglen - 1; i++) {
+ for (a = 1; a <= numelem; a++) {
+ for (b = 1; b < 2 * a; b++) {
+ bt->acfout->data[i] += bt->acf->data[i * a + b - 1]
+ * 1. / (2. * a - 1.);
+ }
+ }
+ }
+ /* apply Rayleigh weight */
+ fvec_weight (bt->acfout, bt->rwv);
+
+ /* find non-zero Rayleigh period */
+ maxindex = fvec_max_elem (bt->acfout);
+ if (maxindex > 0 && maxindex < bt->acfout->length - 1) {
+ bt->rp = fvec_quadratic_peak_pos (bt->acfout, maxindex);
+ } else {
+ bt->rp = bt->rayparam;
+ }
+
+ /* activate biased filterbank */
+ aubio_beattracking_checkstate (bt);
+#if 0 // debug metronome mode
+ bt->bp = 36.9142;
+#endif
+ bp = bt->bp;
+ /* end of biased filterbank */
+
+ if (bp == 0) {
+ fvec_zeros(output);
+ return;
+ }
+
+ /* deliberate integer operation, could be set to 3 max eventually */
+ kmax = FLOOR (winlen / bp);
+
+ /* initialize output */
+ fvec_zeros (bt->phout);
+ for (i = 0; i < bp; i++) {
+ for (k = 0; k < kmax; k++) {
+ bt->phout->data[i] += bt->dfrev->data[i + (uint_t) ROUND (bp * k)];
+ }
+ }
+ fvec_weight (bt->phout, bt->phwv);
+
+ /* find Rayleigh period */
+ maxindex = fvec_max_elem (bt->phout);
+ if (maxindex >= winlen - 1) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("no idea what this groove's phase is\n");
+#endif /* AUBIO_BEAT_WARNINGS */
+ phase = step - bt->lastbeat;
+ } else {
+ phase = fvec_quadratic_peak_pos (bt->phout, maxindex);
+ }
+ /* take back one frame delay */
+ phase += 1.;
+#if 0 // debug metronome mode
+ phase = step - bt->lastbeat;
+#endif
+
+ /* reset output */
+ fvec_zeros (output);
+
+ i = 1;
+ beat = bp - phase;
+
+ // AUBIO_DBG ("bp: %f, phase: %f, lastbeat: %f, step: %d, winlen: %d\n",
+ // bp, phase, bt->lastbeat, step, winlen);
+
+ /* the next beat will be earlier than 60% of the tempo period
+ skip this one */
+ if ( ( step - bt->lastbeat - phase ) < -0.40 * bp ) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("back off-beat error, skipping this beat\n");
+#endif /* AUBIO_BEAT_WARNINGS */
+ beat += bp;
+ }
+
+ /* start counting the beats */
+ while (beat + bp < 0) {
+ beat += bp;
+ }
+
+ if (beat >= 0) {
+ //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat);
+ output->data[i] = beat;
+ i++;
+ }
+
+ while (beat + bp <= step) {
+ beat += bp;
+ //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat);
+ output->data[i] = beat;
+ i++;
+ }
+
+ bt->lastbeat = beat;
+ /* store the number of beats in this frame as the first element */
+ output->data[0] = i;
+}
+
+uint_t
+fvec_gettimesig (fvec_t * acf, uint_t acflen, uint_t gp)
+{
+ sint_t k = 0;
+ smpl_t three_energy = 0., four_energy = 0.;
+ if (gp < 2) return 4;
+ if (acflen > 6 * gp + 2) {
+ for (k = -2; k < 2; k++) {
+ three_energy += acf->data[3 * gp + k];
+ four_energy += acf->data[4 * gp + k];
+ }
+ } else {
+ /*Expanded to be more accurate in time sig estimation */
+ for (k = -2; k < 2; k++) {
+ three_energy += acf->data[3 * gp + k] + acf->data[6 * gp + k];
+ four_energy += acf->data[4 * gp + k] + acf->data[2 * gp + k];
+ }
+ }
+ return (three_energy > four_energy) ? 3 : 4;
+}
+
+void
+aubio_beattracking_checkstate (aubio_beattracking_t * bt)
+{
+ uint_t i, j, a, b;
+ uint_t flagconst = 0;
+ sint_t counter = bt->counter;
+ uint_t flagstep = bt->flagstep;
+ smpl_t gp = bt->gp;
+ smpl_t bp = bt->bp;
+ smpl_t rp = bt->rp;
+ smpl_t rp1 = bt->rp1;
+ smpl_t rp2 = bt->rp2;
+ uint_t laglen = bt->rwv->length;
+ uint_t acflen = bt->acf->length;
+ uint_t step = bt->step;
+ fvec_t *acf = bt->acf;
+ fvec_t *acfout = bt->acfout;
+
+ if (gp) {
+ // compute shift invariant comb filterbank
+ fvec_zeros (acfout);
+ for (i = 1; i < laglen - 1; i++) {
+ for (a = 1; a <= bt->timesig; a++) {
+ for (b = 1; b < 2 * a; b++) {
+ acfout->data[i] += acf->data[i * a + b - 1];
+ }
+ }
+ }
+ // since gp is set, gwv has been computed in previous checkstate
+ fvec_weight (acfout, bt->gwv);
+ gp = fvec_quadratic_peak_pos (acfout, fvec_max_elem (acfout));
+ } else {
+ //still only using general model
+ gp = 0;
+ }
+
+ //now look for step change - i.e. a difference between gp and rp that
+ // is greater than 2*constthresh - always true in first case, since gp = 0
+ if (counter == 0) {
+ if (ABS (gp - rp) > 2. * bt->g_var) {
+ flagstep = 1; // have observed step change.
+ counter = 3; // setup 3 frame counter
+ } else {
+ flagstep = 0;
+ }
+ }
+ //i.e. 3rd frame after flagstep initially set
+ if (counter == 1 && flagstep == 1) {
+ //check for consistency between previous beatperiod values
+ if (ABS (2 * rp - rp1 - rp2) < bt->g_var) {
+ //if true, can activate context dependent model
+ flagconst = 1;
+ counter = 0; // reset counter and flagstep
+ } else {
+ //if not consistent, then don't flag consistency!
+ flagconst = 0;
+ counter = 2; // let it look next time
+ }
+ } else if (counter > 0) {
+ //if counter doesn't = 1,
+ counter = counter - 1;
+ }
+
+ rp2 = rp1;
+ rp1 = rp;
+
+ if (flagconst) {
+ /* first run of new hypothesis */
+ gp = rp;
+ bt->timesig = fvec_gettimesig (acf, acflen, gp);
+ for (j = 0; j < laglen; j++)
+ bt->gwv->data[j] =
+ EXP (-.5 * SQR ((smpl_t) (j + 1. - gp)) / SQR (bt->g_var));
+ flagconst = 0;
+ bp = gp;
+ /* flat phase weighting */
+ fvec_ones (bt->phwv);
+ } else if (bt->timesig) {
+ /* context dependant model */
+ bp = gp;
+ /* gaussian phase weighting */
+ if (step > bt->lastbeat) {
+ for (j = 0; j < 2 * laglen; j++) {
+ bt->phwv->data[j] =
+ EXP (-.5 * SQR ((smpl_t) (1. + j - step +
+ bt->lastbeat)) / (bp / 8.));
+ }
+ } else {
+ //AUBIO_DBG("NOT using phase weighting as step is %d and lastbeat %d \n",
+ // step,bt->lastbeat);
+ fvec_ones (bt->phwv);
+ }
+ } else {
+ /* initial state */
+ bp = rp;
+ /* flat phase weighting */
+ fvec_ones (bt->phwv);
+ }
+
+ /* do some further checks on the final bp value */
+
+ /* if tempo is > 206 bpm, half it */
+ while (0 < bp && bp < 25) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("doubling from %f (%f bpm) to %f (%f bpm)\n",
+ bp, 60.*44100./512./bp, bp/2., 60.*44100./512./bp/2. );
+ //AUBIO_DBG("warning, halving the tempo from %f\n", 60.*samplerate/hopsize/bp);
+#endif /* AUBIO_BEAT_WARNINGS */
+ bp = bp * 2;
+ }
+
+ //AUBIO_DBG("tempo:\t%3.5f bpm | ", 5168./bp);
+
+ /* smoothing */
+ //bp = (uint_t) (0.8 * (smpl_t)bp + 0.2 * (smpl_t)bp2);
+ //AUBIO_DBG("tempo:\t%3.5f bpm smoothed | bp2 %d | bp %d | ", 5168./bp, bp2, bp);
+ //bp2 = bp;
+ //AUBIO_DBG("time signature: %d \n", bt->timesig);
+ bt->counter = counter;
+ bt->flagstep = flagstep;
+ bt->gp = gp;
+ bt->bp = bp;
+ bt->rp1 = rp1;
+ bt->rp2 = rp2;
+}
+
+smpl_t
+aubio_beattracking_get_period (const aubio_beattracking_t * bt)
+{
+ return bt->hop_size * bt->bp;
+}
+
+smpl_t
+aubio_beattracking_get_period_s (const aubio_beattracking_t * bt)
+{
+ return aubio_beattracking_get_period(bt) / (smpl_t) bt->samplerate;
+}
+
+smpl_t
+aubio_beattracking_get_bpm (const aubio_beattracking_t * bt)
+{
+ if (bt->bp != 0) {
+ return 60. / aubio_beattracking_get_period_s(bt);
+ } else {
+ return 0.;
+ }
+}
+
+smpl_t
+aubio_beattracking_get_confidence (const aubio_beattracking_t * bt)
+{
+ if (bt->gp) {
+ smpl_t acf_sum = fvec_sum(bt->acfout);
+ if (acf_sum != 0.) {
+ return fvec_quadratic_peak_mag (bt->acfout, bt->gp) / acf_sum;
+ }
+ }
+ return 0.;
+}
diff --git a/src/tempo/beattracking.h b/src/tempo/beattracking.h
new file mode 100644
index 0000000..bc57de8
--- /dev/null
+++ b/src/tempo/beattracking.h
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2003-2015 Matthew Davies and Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Beat tracking using a context dependant model
+
+ This file implements the causal beat tracking algorithm designed by Matthew
+ Davies and described in the following articles:
+
+ Matthew E. P. Davies and Mark D. Plumbley. Causal tempo tracking of audio.
+ In Proceedings of the International Symposium on Music Information Retrieval
+ (ISMIR), pages 164­169, Barcelona, Spain, 2004.
+
+ Matthew E. P. Davies, Paul Brossier, and Mark D. Plumbley. Beat tracking
+ towards automatic musical accompaniment. In Proceedings of the Audio
+ Engeeniring Society 118th Convention, Barcelona, Spain, May 2005.
+
+ \example tempo/test-beattracking.c
+
+*/
+#ifndef AUBIO_BEATTRACKING_H
+#define AUBIO_BEATTRACKING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** beat tracking object */
+typedef struct _aubio_beattracking_t aubio_beattracking_t;
+
+/** create beat tracking object
+
+ \param winlen length of the onset detection window
+ \param hop_size number of onset detection samples [512]
+ \param samplerate samplerate of the input signal
+
+*/
+aubio_beattracking_t * new_aubio_beattracking(uint_t winlen, uint_t hop_size,
+ uint_t samplerate);
+
+/** track the beat
+
+ \param bt beat tracking object
+ \param dfframes current input detection function frame, smoothed by
+ adaptive median threshold.
+ \param out stored detected beat locations
+
+*/
+void aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframes,
+ fvec_t * out);
+
+/** get current beat period in samples
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in samples, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_beattracking_get_period (const aubio_beattracking_t * bt);
+
+/** get current beat period in seconds
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in seconds, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_beattracking_get_period_s (const aubio_beattracking_t * bt);
+
+/** get current tempo in bpm
+
+ \param bt beat tracking object
+
+ Returns the currently observed tempo, in beats per minutes, or 0 if no
+ consistent value is found.
+
+*/
+smpl_t aubio_beattracking_get_bpm(const aubio_beattracking_t * bt);
+
+/** get current tempo confidence
+
+ \param bt beat tracking object
+
+ Returns the confidence with which the tempo has been observed, 0 if no
+ consistent value is found.
+
+*/
+smpl_t aubio_beattracking_get_confidence(const aubio_beattracking_t * bt);
+
+/** delete beat tracking object
+
+ \param p beat tracking object
+
+*/
+void del_aubio_beattracking(aubio_beattracking_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_BEATTRACKING_H */
diff --git a/src/tempo/tempo.c b/src/tempo/tempo.c
new file mode 100644
index 0000000..80c89e9
--- /dev/null
+++ b/src/tempo/tempo.c
@@ -0,0 +1,291 @@
+/*
+ Copyright (C) 2006-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+#include "tempo/beattracking.h"
+#include "spectral/phasevoc.h"
+#include "onset/peakpicker.h"
+#include "mathutils.h"
+#include "tempo/tempo.h"
+
+/* structure to store object state */
+struct _aubio_tempo_t {
+ aubio_specdesc_t * od; /** onset detection */
+ aubio_pvoc_t * pv; /** phase vocoder */
+ aubio_peakpicker_t * pp; /** peak picker */
+ aubio_beattracking_t * bt; /** beat tracking */
+ cvec_t * fftgrain; /** spectral frame */
+ fvec_t * of; /** onset detection function value */
+ fvec_t * dfframe; /** peak picked detection function buffer */
+ fvec_t * out; /** beat tactus candidates */
+ fvec_t * onset; /** onset results */
+ smpl_t silence; /** silence parameter */
+ smpl_t threshold; /** peak picking threshold */
+ sint_t blockpos; /** current position in dfframe */
+ uint_t winlen; /** dfframe bufsize */
+ uint_t step; /** dfframe hopsize */
+ uint_t samplerate; /** sampling rate of the signal */
+ uint_t hop_size; /** get hop_size */
+ uint_t total_frames; /** total frames since beginning */
+ uint_t last_beat; /** time of latest detected beat, in samples */
+ sint_t delay; /** delay to remove to last beat, in samples */
+ uint_t last_tatum; /** time of latest detected tatum, in samples */
+ uint_t tatum_signature; /** number of tatum between each beats */
+};
+
+/* execute tempo detection function on iput buffer */
+void aubio_tempo_do(aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo)
+{
+ uint_t i;
+ uint_t winlen = o->winlen;
+ uint_t step = o->step;
+ fvec_t * thresholded;
+ aubio_pvoc_do (o->pv, input, o->fftgrain);
+ aubio_specdesc_do (o->od, o->fftgrain, o->of);
+ /*if (usedoubled) {
+ aubio_specdesc_do(o2,fftgrain, onset2);
+ onset->data[0] *= onset2->data[0];
+ }*/
+ /* execute every overlap_size*step */
+ if (o->blockpos == (signed)step -1 ) {
+ /* check dfframe */
+ aubio_beattracking_do(o->bt,o->dfframe,o->out);
+ /* rotate dfframe */
+ for (i = 0 ; i < winlen - step; i++ )
+ o->dfframe->data[i] = o->dfframe->data[i+step];
+ for (i = winlen - step ; i < winlen; i++ )
+ o->dfframe->data[i] = 0.;
+ o->blockpos = -1;
+ }
+ o->blockpos++;
+ aubio_peakpicker_do (o->pp, o->of, o->onset);
+ // store onset detection function in second sample of vector
+ //tempo->data[1] = o->onset->data[0];
+ thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
+ o->dfframe->data[winlen - step + o->blockpos] = thresholded->data[0];
+ /* end of second level loop */
+ tempo->data[0] = 0; /* reset tactus */
+ //i=0;
+ for (i = 1; i < o->out->data[0]; i++ ) {
+ /* if current frame is a predicted tactus */
+ if (o->blockpos == FLOOR(o->out->data[i])) {
+ tempo->data[0] = o->out->data[i] - FLOOR(o->out->data[i]); /* set tactus */
+ /* test for silence */
+ if (aubio_silence_detection(input, o->silence)==1) {
+ tempo->data[0] = 0; // unset beat if silent
+ }
+ o->last_beat = o->total_frames + (uint_t)ROUND(tempo->data[0] * o->hop_size);
+ o->last_tatum = o->last_beat;
+ }
+ }
+ o->total_frames += o->hop_size;
+ return;
+}
+
+uint_t aubio_tempo_get_last (aubio_tempo_t *o)
+{
+ return o->last_beat + o->delay;
+}
+
+smpl_t aubio_tempo_get_last_s (aubio_tempo_t *o)
+{
+ return aubio_tempo_get_last (o) / (smpl_t) (o->samplerate);
+}
+
+smpl_t aubio_tempo_get_last_ms (aubio_tempo_t *o)
+{
+ return aubio_tempo_get_last_s (o) * 1000.;
+}
+
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay) {
+ o->delay = delay;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay) {
+ o->delay = delay * o->samplerate;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay) {
+ o->delay = 1000. * delay * o->samplerate;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tempo_get_delay(aubio_tempo_t * o) {
+ return o->delay;
+}
+
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o) {
+ return o->delay / (smpl_t)(o->samplerate);
+}
+
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o) {
+ return o->delay / (smpl_t)(o->samplerate) / 1000.;
+}
+
+uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence) {
+ o->silence = silence;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_tempo_get_silence(aubio_tempo_t * o) {
+ return o->silence;
+}
+
+uint_t aubio_tempo_set_threshold(aubio_tempo_t * o, smpl_t threshold) {
+ o->threshold = threshold;
+ aubio_peakpicker_set_threshold(o->pp, o->threshold);
+ return AUBIO_OK;
+}
+
+smpl_t aubio_tempo_get_threshold(aubio_tempo_t * o) {
+ return o->threshold;
+}
+
+/* Allocate memory for an tempo detection */
+aubio_tempo_t * new_aubio_tempo (const char_t * tempo_mode,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+ aubio_tempo_t * o = AUBIO_NEW(aubio_tempo_t);
+ char_t specdesc_func[20];
+ o->samplerate = samplerate;
+ // check parameters are valid
+ if ((sint_t)hop_size < 1) {
+ AUBIO_ERR("tempo: got hop size %d, but can not be < 1\n", hop_size);
+ goto beach;
+ } else if ((sint_t)buf_size < 2) {
+ AUBIO_ERR("tempo: got window size %d, but can not be < 2\n", buf_size);
+ goto beach;
+ } else if (buf_size < hop_size) {
+ AUBIO_ERR("tempo: hop size (%d) is larger than window size (%d)\n", buf_size, hop_size);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("tempo: samplerate (%d) can not be < 1\n", samplerate);
+ goto beach;
+ }
+
+ /* length of observations, worth about 6 seconds */
+ o->winlen = aubio_next_power_of_two(5.8 * samplerate / hop_size);
+ if (o->winlen < 4) o->winlen = 4;
+ o->step = o->winlen/4;
+ o->blockpos = 0;
+ o->threshold = 0.3;
+ o->silence = -90.;
+ o->total_frames = 0;
+ o->last_beat = 0;
+ o->delay = 0;
+ o->hop_size = hop_size;
+ o->dfframe = new_fvec(o->winlen);
+ o->fftgrain = new_cvec(buf_size);
+ o->out = new_fvec(o->step);
+ o->pv = new_aubio_pvoc(buf_size, hop_size);
+ o->pp = new_aubio_peakpicker();
+ aubio_peakpicker_set_threshold (o->pp, o->threshold);
+ if ( strcmp(tempo_mode, "default") == 0 ) {
+ strcpy(specdesc_func, "specflux");
+ } else {
+ strcpy(specdesc_func, tempo_mode);
+ }
+ o->od = new_aubio_specdesc(specdesc_func,buf_size);
+ o->of = new_fvec(1);
+ o->bt = new_aubio_beattracking(o->winlen, o->hop_size, o->samplerate);
+ o->onset = new_fvec(1);
+ /*if (usedoubled) {
+ o2 = new_aubio_specdesc(type_onset2,buffer_size);
+ onset2 = new_fvec(1);
+ }*/
+ o->last_tatum = 0;
+ o->tatum_signature = 4;
+ return o;
+
+beach:
+ AUBIO_FREE(o);
+ return NULL;
+}
+
+smpl_t aubio_tempo_get_bpm(aubio_tempo_t *o) {
+ return aubio_beattracking_get_bpm(o->bt);
+}
+
+smpl_t aubio_tempo_get_period (aubio_tempo_t *o)
+{
+ return aubio_beattracking_get_period (o->bt);
+}
+
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t *o)
+{
+ return aubio_beattracking_get_period_s (o->bt);
+}
+
+smpl_t aubio_tempo_get_confidence(aubio_tempo_t *o) {
+ return aubio_beattracking_get_confidence(o->bt);
+}
+
+uint_t aubio_tempo_was_tatum (aubio_tempo_t *o)
+{
+ uint_t last_tatum_distance = o->total_frames - o->last_tatum;
+ smpl_t beat_period = aubio_tempo_get_period(o);
+ smpl_t tatum_period = beat_period / o->tatum_signature;
+ if (last_tatum_distance < o->hop_size) {
+ o->last_tatum = o->last_beat;
+ return 2;
+ }
+ else if (last_tatum_distance > tatum_period) {
+ if ( last_tatum_distance + o->hop_size > beat_period ) {
+ // next beat is too close, pass
+ return 0;
+ }
+ o->last_tatum = o->total_frames;
+ return 1;
+ }
+ return 0;
+}
+
+smpl_t aubio_tempo_get_last_tatum (aubio_tempo_t *o) {
+ return (smpl_t)o->last_tatum - o->delay;
+}
+
+uint_t aubio_tempo_set_tatum_signature (aubio_tempo_t *o, uint_t signature) {
+ if (signature < 1 || signature > 64) {
+ return AUBIO_FAIL;
+ } else {
+ o->tatum_signature = signature;
+ return AUBIO_OK;
+ }
+}
+
+void del_aubio_tempo (aubio_tempo_t *o)
+{
+ del_aubio_specdesc(o->od);
+ del_aubio_beattracking(o->bt);
+ del_aubio_peakpicker(o->pp);
+ del_aubio_pvoc(o->pv);
+ del_fvec(o->out);
+ del_fvec(o->of);
+ del_cvec(o->fftgrain);
+ del_fvec(o->dfframe);
+ del_fvec(o->onset);
+ AUBIO_FREE(o);
+ return;
+}
diff --git a/src/tempo/tempo.h b/src/tempo/tempo.h
new file mode 100644
index 0000000..13637f9
--- /dev/null
+++ b/src/tempo/tempo.h
@@ -0,0 +1,255 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Tempo detection object
+
+ This object stores all the memory required for tempo detection algorithm
+ and returns the estimated beat locations.
+
+ \example tempo/test-tempo.c
+ \example examples/aubiotrack.c
+
+*/
+
+#ifndef AUBIO_TEMPO_H
+#define AUBIO_TEMPO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** tempo detection structure */
+typedef struct _aubio_tempo_t aubio_tempo_t;
+
+/** create tempo detection object
+
+ \param method beat tracking method, unused for now (use "default")
+ \param buf_size length of FFT
+ \param hop_size number of frames between two consecutive runs
+ \param samplerate sampling rate of the signal to analyze
+
+ \return newly created ::aubio_tempo_t if successful, `NULL` otherwise
+
+*/
+aubio_tempo_t * new_aubio_tempo (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** execute tempo detection
+
+ \param o beat tracking object
+ \param input new samples
+ \param tempo output beats
+
+*/
+void aubio_tempo_do (aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo);
+
+/** get the time of the latest beat detected, in samples
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+uint_t aubio_tempo_get_last (aubio_tempo_t *o);
+
+/** get the time of the latest beat detected, in seconds
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+smpl_t aubio_tempo_get_last_s (aubio_tempo_t *o);
+
+/** get the time of the latest beat detected, in milliseconds
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+smpl_t aubio_tempo_get_last_ms (aubio_tempo_t *o);
+
+/** set tempo detection silence threshold
+
+ \param o beat tracking object
+ \param silence new silence threshold, in dB
+
+ \return `0` if successful, non-zero otherwise
+
+*/
+uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence);
+
+/** get tempo detection silence threshold
+
+ \param o tempo detection object as returned by new_aubio_tempo()
+
+ \return current silence threshold
+
+*/
+smpl_t aubio_tempo_get_silence(aubio_tempo_t * o);
+
+/** set tempo detection peak picking threshold
+
+ \param o beat tracking object
+ \param threshold new threshold
+
+ \return `0` if successful, non-zero otherwise
+
+*/
+uint_t aubio_tempo_set_threshold(aubio_tempo_t * o, smpl_t threshold);
+
+/** get tempo peak picking threshold
+
+ \param o tempo detection object as returned by new_aubio_tempo()
+
+ \return current tempo detection threshold
+
+*/
+smpl_t aubio_tempo_get_threshold(aubio_tempo_t * o);
+
+/** get current beat period in samples
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in samples, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_tempo_get_period (aubio_tempo_t * bt);
+
+/** get current beat period in seconds
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in seconds, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t * bt);
+
+/** get current tempo
+
+ \param o beat tracking object
+
+ \return the currently observed tempo, or `0` if no consistent value is found
+
+*/
+smpl_t aubio_tempo_get_bpm(aubio_tempo_t * o);
+
+/** get current tempo confidence
+
+ \param o beat tracking object
+
+ \return confidence with which the tempo has been observed, `0` if no
+ consistent value is found.
+
+*/
+smpl_t aubio_tempo_get_confidence(aubio_tempo_t * o);
+
+/** set number of tatum per beat
+
+ \param o beat tracking object
+ \param signature number of tatum per beat (between 1 and 64)
+
+*/
+uint_t aubio_tempo_set_tatum_signature(aubio_tempo_t *o, uint_t signature);
+
+/** check whether a tatum was detected in the current frame
+
+ \param o beat tracking object
+
+ \return 2 if a beat was detected, 1 if a tatum was detected, 0 otherwise
+
+*/
+uint_t aubio_tempo_was_tatum(aubio_tempo_t *o);
+
+/** get position of last_tatum, in samples
+
+ \param o beat tracking object
+
+*/
+smpl_t aubio_tempo_get_last_tatum(aubio_tempo_t *o);
+
+/** get current delay
+
+ \param o beat tracking object
+
+ \return current delay, in samples
+
+ */
+uint_t aubio_tempo_get_delay(aubio_tempo_t * o);
+
+/** get current delay in seconds
+
+ \param o beat tracking object
+
+ \return current delay, in seconds
+
+ */
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o);
+
+/** get current delay in ms
+
+ \param o beat tracking object
+
+ \return current delay, in milliseconds
+
+ */
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o);
+
+/** set current delay
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in samples
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay);
+
+/** set current delay in seconds
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in seconds
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay);
+
+/** set current delay
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in samples
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay);
+
+/** delete tempo detection object
+
+ \param o beat tracking object
+
+*/
+void del_aubio_tempo(aubio_tempo_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TEMPO_H */
diff --git a/src/temporal/a_weighting.c b/src/temporal/a_weighting.c
new file mode 100644
index 0000000..f19f566
--- /dev/null
+++ b/src/temporal/a_weighting.c
@@ -0,0 +1,262 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/a_weighting.h"
+
+uint_t
+aubio_filter_set_a_weighting (aubio_filter_t * f, uint_t samplerate)
+{
+ uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
+
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERROR("aubio_filter: failed setting A-weighting with samplerate %d\n", samplerate);
+ return AUBIO_FAIL;
+ }
+ if (f == NULL) {
+ AUBIO_ERROR("aubio_filter: failed setting A-weighting with filter NULL\n");
+ return AUBIO_FAIL;
+ }
+
+ order = aubio_filter_get_order (f);
+ if (order != 7) {
+ AUBIO_ERROR ("aubio_filter: order of A-weighting filter must be 7, not %d\n", order);
+ return 1;
+ }
+
+ aubio_filter_set_samplerate (f, samplerate);
+ bs = aubio_filter_get_feedforward (f);
+ as = aubio_filter_get_feedback (f);
+ b = bs->data, a = as->data;
+
+ /* select coefficients according to sampling frequency */
+ switch (samplerate) {
+
+ case 8000:
+ b[0] = 6.306209468238731519207362907764036208391189575195312500e-01;
+ b[1] = -1.261241893647746525886077506584115326404571533203125000e+00;
+ b[2] = -6.306209468238730408984338282607495784759521484375000000e-01;
+ b[3] = 2.522483787295493051772155013168230652809143066406250000e+00;
+ b[4] = -6.306209468238730408984338282607495784759521484375000000e-01;
+ b[5] = -1.261241893647746525886077506584115326404571533203125000e+00;
+ b[6] = 6.306209468238731519207362907764036208391189575195312500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.128467193009123015201566886389628052711486816406250000e+00;
+ a[2] = 2.948668980101234460278192273108288645744323730468750000e-01;
+ a[3] = 1.824183830735050637628091863007284700870513916015625000e+00;
+ a[4] = -8.056628943119792385374466903158463537693023681640625000e-01;
+ a[5] = -3.947497982842933517133587884018197655677795410156250000e-01;
+ a[6] = 2.098548546080332977137317129745497368276119232177734375e-01;
+ break;
+
+ case 11025:
+ b[0] = 6.014684165832374640459079273568931967020034790039062500e-01;
+ b[1] = -1.202936833166475150136420779745094478130340576171875000e+00;
+ b[2] = -6.014684165832373530236054648412391543388366699218750000e-01;
+ b[3] = 2.405873666332950300272841559490188956260681152343750000e+00;
+ b[4] = -6.014684165832373530236054648412391543388366699218750000e-01;
+ b[5] = -1.202936833166475150136420779745094478130340576171875000e+00;
+ b[6] = 6.014684165832374640459079273568931967020034790039062500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.463578747722854345170162559952586889266967773437500000e+00;
+ a[2] = 1.096799662705210121060872552334330976009368896484375000e+00;
+ a[3] = 1.381222210556041218865175324026495218276977539062500000e+00;
+ a[4] = -1.013875696476876031582037285261321812868118286132812500e+00;
+ a[5] = -1.839132734476921215982514468123554252088069915771484375e-01;
+ a[6] = 1.833526393172056623281918064094497822225093841552734375e-01;
+ break;
+
+ case 16000:
+ b[0] = 5.314898298235570806014038680586963891983032226562500000e-01;
+ b[1] = -1.062979659647114161202807736117392778396606445312500000e+00;
+ b[2] = -5.314898298235570806014038680586963891983032226562500000e-01;
+ b[3] = 2.125959319294228322405615472234785556793212890625000000e+00;
+ b[4] = -5.314898298235570806014038680586963891983032226562500000e-01;
+ b[5] = -1.062979659647114161202807736117392778396606445312500000e+00;
+ b[6] = 5.314898298235570806014038680586963891983032226562500000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.867832572992162987191022693878039717674255371093750000e+00;
+ a[2] = 2.221144410202312347024644623161293566226959228515625000e+00;
+ a[3] = 4.552683347886614662058946123579517006874084472656250000e-01;
+ a[4] = -9.833868636162828025248927588108927011489868164062500000e-01;
+ a[5] = 5.592994142413361402521587706360151059925556182861328125e-02;
+ a[6] = 1.188781038285612462468421313133148942142724990844726562e-01;
+ break;
+
+ case 22050:
+ b[0] = 4.492998504299193784916610638902056962251663208007812500e-01;
+ b[1] = -8.985997008598388680056245902960654348134994506835937500e-01;
+ b[2] = -4.492998504299192674693586013745516538619995117187500000e-01;
+ b[3] = 1.797199401719677958055854105623438954353332519531250000e+00;
+ b[4] = -4.492998504299192674693586013745516538619995117187500000e-01;
+ b[5] = -8.985997008598388680056245902960654348134994506835937500e-01;
+ b[6] = 4.492998504299193784916610638902056962251663208007812500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.229078805225074955131958631682209670543670654296875000e+00;
+ a[2] = 3.354494881236033787530459449044428765773773193359375000e+00;
+ a[3] = -7.317843680657351024265722116979304701089859008789062500e-01;
+ a[4] = -6.271627581807257545420952737913466989994049072265625000e-01;
+ a[5] = 1.772142005020879151899748649157118052244186401367187500e-01;
+ a[6] = 5.631716697383508385410522123493137769401073455810546875e-02;
+ break;
+
+ case 24000:
+ b[0] = 4.256263892891054001488271296693710610270500183105468750e-01;
+ b[1] = -8.512527785782106892753517968230880796909332275390625000e-01;
+ b[2] = -4.256263892891054556599783609271980822086334228515625000e-01;
+ b[3] = 1.702505557156421378550703593646176159381866455078125000e+00;
+ b[4] = -4.256263892891054556599783609271980822086334228515625000e-01;
+ b[5] = -8.512527785782106892753517968230880796909332275390625000e-01;
+ b[6] = 4.256263892891054001488271296693710610270500183105468750e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.325996004241962733516402295208536088466644287109375000e+00;
+ a[2] = 3.677161079286316969216841243905946612358093261718750000e+00;
+ a[3] = -1.106476076828482035807610373012721538543701171875000000e+00;
+ a[4] = -4.726706734908718843257702246773988008499145507812500000e-01;
+ a[5] = 1.861941760230954034938122276798821985721588134765625000e-01;
+ a[6] = 4.178771337829546850262119050967157818377017974853515625e-02;
+ break;
+
+ case 32000:
+ b[0] = 3.434583386824304196416335344110848382115364074707031250e-01;
+ b[1] = -6.869166773648609503055695313378237187862396240234375000e-01;
+ b[2] = -3.434583386824303641304823031532578170299530029296875000e-01;
+ b[3] = 1.373833354729721900611139062675647437572479248046875000e+00;
+ b[4] = -3.434583386824303641304823031532578170299530029296875000e-01;
+ b[5] = -6.869166773648609503055695313378237187862396240234375000e-01;
+ b[6] = 3.434583386824304196416335344110848382115364074707031250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.656446043233668063976438133977353572845458984375000000e+00;
+ a[2] = 4.831468450652579349480220116674900054931640625000000000e+00;
+ a[3] = -2.557597496581567764195597192156128585338592529296875000e+00;
+ a[4] = 2.533680394205302666144064005493419244885444641113281250e-01;
+ a[5] = 1.224430322452567110325105659285327419638633728027343750e-01;
+ a[6] = 6.764072168342137418572956875095769646577537059783935547e-03;
+ break;
+
+ case 44100:
+ b[0] = 2.557411252042575133813784304948057979345321655273437500e-01;
+ b[1] = -5.114822504085150267627568609896115958690643310546875000e-01;
+ b[2] = -2.557411252042575133813784304948057979345321655273437500e-01;
+ b[3] = 1.022964500817030053525513721979223191738128662109375000e+00;
+ b[4] = -2.557411252042575133813784304948057979345321655273437500e-01;
+ b[5] = -5.114822504085150267627568609896115958690643310546875000e-01;
+ b[6] = 2.557411252042575133813784304948057979345321655273437500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.019576181115832369528106937650591135025024414062500000e+00;
+ a[2] = 6.189406442920693862674852425698190927505493164062500000e+00;
+ a[3] = -4.453198903544116404873420833609998226165771484375000000e+00;
+ a[4] = 1.420842949621876627475103305187076330184936523437500000e+00;
+ a[5] = -1.418254738303044160119270600262098014354705810546875000e-01;
+ a[6] = 4.351177233495117681327801761881346465088427066802978516e-03;
+ break;
+
+ case 48000:
+ b[0] = 2.343017922995132285013397677175817079842090606689453125e-01;
+ b[1] = -4.686035845990265125138307666929904371500015258789062500e-01;
+ b[2] = -2.343017922995132007457641520886681973934173583984375000e-01;
+ b[3] = 9.372071691980530250276615333859808743000030517578125000e-01;
+ b[4] = -2.343017922995132007457641520886681973934173583984375000e-01;
+ b[5] = -4.686035845990265125138307666929904371500015258789062500e-01;
+ b[6] = 2.343017922995132285013397677175817079842090606689453125e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.113043408775872045168853219365701079368591308593750000e+00;
+ a[2] = 6.553121752655050258340452273841947317123413085937500000e+00;
+ a[3] = -4.990849294163385074796224216697737574577331542968750000e+00;
+ a[4] = 1.785737302937575599059982778271660208702087402343750000e+00;
+ a[5] = -2.461905953194876706113802811159985139966011047363281250e-01;
+ a[6] = 1.122425003323123879339640041052916785702109336853027344e-02;
+ break;
+
+ case 88200:
+ b[0] = 1.118876366882113199130444058937428053468465805053710938e-01;
+ b[1] = -2.237752733764226120705131961585721001029014587402343750e-01;
+ b[2] = -1.118876366882113337908322137081995606422424316406250000e-01;
+ b[3] = 4.475505467528452241410263923171442002058029174804687500e-01;
+ b[4] = -1.118876366882113337908322137081995606422424316406250000e-01;
+ b[5] = -2.237752733764226120705131961585721001029014587402343750e-01;
+ b[6] = 1.118876366882113199130444058937428053468465805053710938e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.726938565651158441482948546763509511947631835937500000e+00;
+ a[2] = 9.076897983832765248735086061060428619384765625000000000e+00;
+ a[3] = -9.014855113464800950850985827855765819549560546875000000e+00;
+ a[4] = 4.852772261031594425162438710685819387435913085937500000e+00;
+ a[5] = -1.333877820398965186043938047077972441911697387695312500e+00;
+ a[6] = 1.460012549591642450064199465487035922706127166748046875e-01;
+ break;
+
+ case 96000:
+ b[0] = 9.951898975972744976203898659150581806898117065429687500e-02;
+ b[1] = -1.990379795194548995240779731830116361379623413085937500e-01;
+ b[2] = -9.951898975972744976203898659150581806898117065429687500e-02;
+ b[3] = 3.980759590389097990481559463660232722759246826171875000e-01;
+ b[4] = -9.951898975972744976203898659150581806898117065429687500e-02;
+ b[5] = -1.990379795194548995240779731830116361379623413085937500e-01;
+ b[6] = 9.951898975972744976203898659150581806898117065429687500e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.802203044225376693532325589330866932868957519531250000e+00;
+ a[2] = 9.401807218627226347962277941405773162841796875000000000e+00;
+ a[3] = -9.566143943569164420637207513209432363510131835937500000e+00;
+ a[4] = 5.309775930392619081032989925006404519081115722656250000e+00;
+ a[5] = -1.517333360452622237346531619550660252571105957031250000e+00;
+ a[6] = 1.740971994228911745583587844521389342844486236572265625e-01;
+ break;
+
+ case 192000:
+ b[0] = 3.433213424548713782469278044118254911154508590698242188e-02;
+ b[1] = -6.866426849097426177159775306790834292769432067871093750e-02;
+ b[2] = -3.433213424548714476358668434841092675924301147460937500e-02;
+ b[3] = 1.373285369819485235431955061358166858553886413574218750e-01;
+ b[4] = -3.433213424548714476358668434841092675924301147460937500e-02;
+ b[5] = -6.866426849097426177159775306790834292769432067871093750e-02;
+ b[6] = 3.433213424548713782469278044118254911154508590698242188e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -5.305923689674640009172890131594613194465637207031250000e+00;
+ a[2] = 1.165952437466175695135461864992976188659667968750000000e+01;
+ a[3] = -1.357560092700591525272102444432675838470458984375000000e+01;
+ a[4] = 8.828906932824192921316353022120893001556396484375000000e+00;
+ a[5] = -3.039490120988216581565666274400427937507629394531250000e+00;
+ a[6] = 4.325834301870381537469256727490574121475219726562500000e-01;
+ break;
+
+ default:
+ AUBIO_ERROR ("sampling rate of A-weighting filter is %d, should be one of\
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 192000.\n", samplerate);
+ return 1;
+
+ }
+
+ return 0;
+}
+
+aubio_filter_t *
+new_aubio_filter_a_weighting (uint_t samplerate)
+{
+ aubio_filter_t *f = new_aubio_filter (7);
+ if (aubio_filter_set_a_weighting(f,samplerate) != AUBIO_OK) {
+ del_aubio_filter(f);
+ return NULL;
+ }
+ return f;
+}
diff --git a/src/temporal/a_weighting.h b/src/temporal/a_weighting.h
new file mode 100644
index 0000000..49dd4d5
--- /dev/null
+++ b/src/temporal/a_weighting.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FILTER_A_DESIGN_H
+#define AUBIO_FILTER_A_DESIGN_H
+
+/** \file
+
+ A-weighting filter coefficients
+
+ This file creates an A-weighting digital filter, which reduces low and high
+ frequencies and enhance the middle ones to reflect the ability of the human
+ hearing.
+
+ The implementation is based on the following standard:
+
+ - IEC/CD 1672: Electroacoustics-Sound Level Meters, IEC, Geneva, Nov. 1996,
+ for A- and C-weighting filters.
+
+ See also:
+
+ - <a href="http://en.wikipedia.org/wiki/A-weighting">A-Weighting on
+ Wikipedia</a>
+ - <a href="http://en.wikipedia.org/wiki/Weighting_filter">Weighting filter on
+ Wikipedia</a>
+ - <a href="http://www.mathworks.com/matlabcentral/fileexchange/69">Christophe
+ Couvreur's 'octave' toolbox</a>
+
+ The coefficients in this file have been computed using Christophe Couvreur's
+ scripts in octave 3.0 (debian package 1:3.0.5-6+b2 with octave-signal
+ 1.0.9-1+b1 on i386), with <pre> [b, a] = adsign(1/Fs) </pre> for various
+ sampling frequencies (8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, and 192000 Hz).
+
+ The sampling frequency should normally be higher than 20kHz, but most common
+ file sampling rates have been included for completeness.
+
+ \example temporal/test-a_weighting.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create new A-design filter
+
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+ \return a new filter object
+
+*/
+aubio_filter_t *new_aubio_filter_a_weighting (uint_t samplerate);
+
+/** set feedback and feedforward coefficients of a A-weighting filter
+
+ \param f filter object to get coefficients from
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+*/
+uint_t aubio_filter_set_a_weighting (aubio_filter_t * f, uint_t samplerate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_A_DESIGN_H */
diff --git a/src/temporal/biquad.c b/src/temporal/biquad.c
new file mode 100644
index 0000000..6a03aa6
--- /dev/null
+++ b/src/temporal/biquad.c
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+
+uint_t
+aubio_filter_set_biquad (aubio_filter_t * f, lsmp_t b0, lsmp_t b1, lsmp_t b2,
+ lsmp_t a1, lsmp_t a2)
+{
+ uint_t order = aubio_filter_get_order (f);
+ lvec_t *bs = aubio_filter_get_feedforward (f);
+ lvec_t *as = aubio_filter_get_feedback (f);
+
+ if (order != 3) {
+ AUBIO_ERROR ("order of biquad filter must be 3, not %d\n", order);
+ return AUBIO_FAIL;
+ }
+ bs->data[0] = b0;
+ bs->data[1] = b1;
+ bs->data[2] = b2;
+ as->data[0] = 1.;
+ as->data[1] = a1;
+ as->data[1] = a2;
+ return AUBIO_OK;
+}
+
+aubio_filter_t *
+new_aubio_filter_biquad (lsmp_t b0, lsmp_t b1, lsmp_t b2, lsmp_t a1, lsmp_t a2)
+{
+ aubio_filter_t *f = new_aubio_filter (3);
+ aubio_filter_set_biquad (f, b0, b1, b2, a1, a2);
+ return f;
+}
diff --git a/src/temporal/biquad.h b/src/temporal/biquad.h
new file mode 100644
index 0000000..1d19d94
--- /dev/null
+++ b/src/temporal/biquad.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FILTER_BIQUAD_H
+#define AUBIO_FILTER_BIQUAD_H
+
+/** \file
+
+ Second order Infinite Impulse Response filter
+
+ This file implements a normalised biquad filter (second order IIR):
+
+ \f$ y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] - a_1 y[n-1] - a_2 y[n-2] \f$
+
+ The filtfilt version runs the filter twice, forward and backward, to
+ compensate the phase shifting of the forward operation.
+
+ See also <a href="http://en.wikipedia.org/wiki/Digital_biquad_filter">Digital
+ biquad filter</a> on wikipedia.
+
+ \example temporal/test-biquad.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** set coefficients of a biquad filter
+
+ \param f filter object as returned by new_aubio_filter()
+ \param b0 forward filter coefficient
+ \param b1 forward filter coefficient
+ \param b2 forward filter coefficient
+ \param a1 feedback filter coefficient
+ \param a2 feedback filter coefficient
+
+*/
+uint_t aubio_filter_set_biquad (aubio_filter_t * f, lsmp_t b0, lsmp_t b1,
+ lsmp_t b2, lsmp_t a1, lsmp_t a2);
+
+/** create biquad filter with `b0`, `b1`, `b2`, `a1`, `a2` coeffs
+
+ \param b0 forward filter coefficient
+ \param b1 forward filter coefficient
+ \param b2 forward filter coefficient
+ \param a1 feedback filter coefficient
+ \param a2 feedback filter coefficient
+
+*/
+aubio_filter_t *new_aubio_filter_biquad (lsmp_t b0, lsmp_t b1, lsmp_t b2,
+ lsmp_t a1, lsmp_t a2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_BIQUAD_H */
diff --git a/src/temporal/c_weighting.c b/src/temporal/c_weighting.c
new file mode 100644
index 0000000..91ada71
--- /dev/null
+++ b/src/temporal/c_weighting.c
@@ -0,0 +1,217 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/c_weighting.h"
+
+uint_t
+aubio_filter_set_c_weighting (aubio_filter_t * f, uint_t samplerate)
+{
+ uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
+
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERROR("aubio_filter: failed setting C-weighting with samplerate %d\n", samplerate);
+ return AUBIO_FAIL;
+ }
+ if (f == NULL) {
+ AUBIO_ERROR("aubio_filter: failed setting C-weighting with filter NULL\n");
+ return AUBIO_FAIL;
+ }
+
+ order = aubio_filter_get_order (f);
+ if ( order != 5 ) {
+ AUBIO_ERROR ("aubio_filter: order of C-weighting filter must be 5, not %d\n", order);
+ return 1;
+ }
+
+ aubio_filter_set_samplerate (f, samplerate);
+ bs = aubio_filter_get_feedforward (f);
+ as = aubio_filter_get_feedback (f);
+ b = bs->data, a = as->data;
+
+ /* select coefficients according to sampling frequency */
+ switch (samplerate) {
+
+ case 8000:
+ b[0] = 6.782173932405135552414776611840352416038513183593750000e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.356434786481027110482955322368070483207702636718750000e+00;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 6.782173932405135552414776611840352416038513183593750000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -6.589092811505605773447769024642184376716613769531250000e-01;
+ a[2] = -1.179445664897062595599663836765103042125701904296875000e+00;
+ a[3] = 4.243329729632123736848825501510873436927795410156250000e-01;
+ a[4] = 4.147270002091348328754349950031610205769538879394531250e-01;
+ break;
+
+ case 11025:
+ b[0] = 6.002357155402652244546857218665536493062973022460937500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.200471431080530448909371443733107298612594604492187500e+00;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 6.002357155402652244546857218665536493062973022460937500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -8.705602141280316397242700077185872942209243774414062500e-01;
+ a[2] = -9.037199507150940336330791069485712796449661254882812500e-01;
+ a[3] = 4.758433040929530011275971901341108605265617370605468750e-01;
+ a[4] = 2.987653956523212417373258631414500996470451354980468750e-01;
+ break;
+
+ case 16000:
+ b[0] = 4.971057193673903418229542694461997598409652709960937500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -9.942114387347806836459085388923995196819305419921875000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 4.971057193673903418229542694461997598409652709960937500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.162322939286873690889478893950581550598144531250000000e+00;
+ a[2] = -4.771961355734982701548574368644040077924728393554687500e-01;
+ a[3] = 4.736145114694704227886745684372726827859878540039062500e-01;
+ a[4] = 1.660337524309875301131711466950946487486362457275390625e-01;
+ break;
+
+ case 22050:
+ b[0] = 4.033381299002754549754001800465630367398262023925781250e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -8.066762598005509099508003600931260734796524047851562500e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 4.033381299002754549754001800465630367398262023925781250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.449545371157945350404361306573264300823211669921875000e+00;
+ a[2] = -1.030104190885922088583015465701464563608169555664062500e-02;
+ a[3] = 3.881857047554073680828423675848171114921569824218750000e-01;
+ a[4] = 7.171589940116777917022972133054281584918498992919921875e-02;
+ break;
+
+ case 24000:
+ b[0] = 3.786678621924967069745093795063439756631851196289062500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -7.573357243849934139490187590126879513263702392578125000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 3.786678621924967069745093795063439756631851196289062500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.529945307555420797029910318087786436080932617187500000e+00;
+ a[2] = 1.283553182116208835061854642844991758465766906738281250e-01;
+ a[3] = 3.494608072385725350272878131363540887832641601562500000e-01;
+ a[4] = 5.217291949300089520802359288609295617789030075073242188e-02;
+ break;
+
+ case 32000:
+ b[0] = 2.977986488230693340462096330156782642006874084472656250e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -5.955972976461386680924192660313565284013748168945312500e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.977986488230693340462096330156782642006874084472656250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.812455387128179218336754274787381291389465332031250000e+00;
+ a[2] = 6.425013281155662614452239722595550119876861572265625000e-01;
+ a[3] = 1.619857574578579817448087396769551560282707214355468750e-01;
+ a[4] = 7.987649713547682189807019881300220731645822525024414062e-03;
+ break;
+
+ case 44100:
+ b[0] = 2.170085619492190254220531642204150557518005371093750000e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -4.340171238984380508441063284408301115036010742187500000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.170085619492190254220531642204150557518005371093750000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.134674963687040794013682898366823792457580566406250000e+00;
+ a[2] = 1.279333533236062692139967111870646476745605468750000000e+00;
+ a[3] = -1.495598460893957093453821016737492755055427551269531250e-01;
+ a[4] = 4.908700174624683852664386307651511742733418941497802734e-03;
+ break;
+
+ case 48000:
+ b[0] = 1.978871200263932761398422144338837824761867523193359375e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -3.957742400527865522796844288677675649523735046386718750e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 1.978871200263932761398422144338837824761867523193359375e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.219172914052801814932536217384040355682373046875000000e+00;
+ a[2] = 1.455135878947171557129536267893854528665542602539062500e+00;
+ a[3] = -2.484960738877830532800317087094299495220184326171875000e-01;
+ a[4] = 1.253882314727246607977129144728678511455655097961425781e-02;
+ break;
+
+ case 88200:
+ b[0] = 9.221909851156021020734954163344809785485267639160156250e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.844381970231204204146990832668961957097053527832031250e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 9.221909851156021020734954163344809785485267639160156250e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.785795902923448696952846148633398115634918212890625000e+00;
+ a[2] = 2.727736758747444145711824603495188057422637939453125000e+00;
+ a[3] = -1.097007502819661528548067508381791412830352783203125000e+00;
+ a[4] = 1.550674356752141103132913713125162757933139801025390625e-01;
+ break;
+
+ case 96000:
+ b[0] = 8.182864044979756834585771230194950476288795471191406250e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.636572808995951366917154246038990095257759094238281250e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 8.182864044979756834585771230194950476288795471191406250e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.856378516857566829401093855267390608787536621093750000e+00;
+ a[2] = 2.897640237559524045707348705036565661430358886718750000e+00;
+ a[3] = -1.225265958339703198376469117647502571344375610351562500e+00;
+ a[4] = 1.840048283551226071530493300087982788681983947753906250e-01;
+ break;
+
+ case 192000:
+ b[0] = 2.784755468532278815940728122768632601946592330932617188e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -5.569510937064557631881456245537265203893184661865234375e-02;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.784755468532278815940728122768632601946592330932617188e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.333298856144166322224009491037577390670776367187500000e+00;
+ a[2] = 4.111467536240339448738723149290308356285095214843750000e+00;
+ a[3] = -2.222889041651291641699117462849244475364685058593750000e+00;
+ a[4] = 4.447204118126878991112960193277103826403617858886718750e-01;
+ break;
+
+ default:
+ AUBIO_ERROR ( "sampling rate of C-weighting filter is %d, should be one of\
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 192000.\n",
+ samplerate );
+ return 1;
+
+ }
+
+ return 0;
+}
+
+aubio_filter_t * new_aubio_filter_c_weighting (uint_t samplerate) {
+ aubio_filter_t * f = new_aubio_filter(5);
+ if (aubio_filter_set_c_weighting(f,samplerate) != AUBIO_OK) {
+ del_aubio_filter(f);
+ return NULL;
+ }
+ return f;
+}
diff --git a/src/temporal/c_weighting.h b/src/temporal/c_weighting.h
new file mode 100644
index 0000000..d87f61f
--- /dev/null
+++ b/src/temporal/c_weighting.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FILTER_C_DESIGN_H
+#define AUBIO_FILTER_C_DESIGN_H
+
+/** \file
+
+ C-weighting filter coefficients
+
+ This file creates a C-weighting digital filter, which reduces low and high
+ frequencies and enhance the middle ones to reflect the ability of the human
+ hearing.
+
+ The implementation is based on the following standard:
+
+ - IEC/CD 1672: Electroacoustics-Sound Level Meters, IEC, Geneva, Nov. 1996,
+ for A- and C-weighting filters.
+
+ See also:
+
+ - <a href="http://en.wikipedia.org/wiki/A-weighting">A-Weighting on
+ Wikipedia</a>
+ - <a href="http://en.wikipedia.org/wiki/Weighting_filter">Weighting filter on
+ Wikipedia</a>
+ - <a href="http://www.mathworks.com/matlabcentral/fileexchange/69">Christophe
+ Couvreur's 'octave' toolbox</a>
+
+ The coefficients in this file have been computed using Christophe Couvreur's
+ scripts in octave 3.0 (debian package 1:3.0.5-6+b2 with octave-signal
+ 1.0.9-1+b1 on i386), with <pre> [b, a] = cdsign(1/Fs) </pre> for various
+ sampling frequencies (8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, and 192000 Hz).
+
+ The sampling frequency should normally be higher than 20kHz, but most common
+ file sampling rates have been included for completeness.
+
+ \example temporal/test-c_weighting.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create new C-design filter
+
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+ \return a new filter object
+
+*/
+aubio_filter_t *new_aubio_filter_c_weighting (uint_t samplerate);
+
+/** set feedback and feedforward coefficients of a C-weighting filter
+
+ \param f filter object to get coefficients from
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+*/
+uint_t aubio_filter_set_c_weighting (aubio_filter_t * f, uint_t samplerate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_C_DESIGN_H */
diff --git a/src/temporal/filter.c b/src/temporal/filter.c
new file mode 100644
index 0000000..776d2e6
--- /dev/null
+++ b/src/temporal/filter.c
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+/* Requires lsmp_t to be long or double. float will NOT give reliable
+ * results */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "mathutils.h"
+#include "temporal/filter.h"
+
+struct _aubio_filter_t
+{
+ uint_t order;
+ uint_t samplerate;
+ lvec_t *a;
+ lvec_t *b;
+ lvec_t *y;
+ lvec_t *x;
+};
+
+void
+aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out)
+{
+ fvec_copy (in, out);
+ aubio_filter_do (f, out);
+}
+
+void
+aubio_filter_do (aubio_filter_t * f, fvec_t * in)
+{
+ uint_t j, l, order = f->order;
+ lsmp_t *x = f->x->data;
+ lsmp_t *y = f->y->data;
+ lsmp_t *a = f->a->data;
+ lsmp_t *b = f->b->data;
+
+ for (j = 0; j < in->length; j++) {
+ /* new input */
+ x[0] = KILL_DENORMAL (in->data[j]);
+ y[0] = b[0] * x[0];
+ for (l = 1; l < order; l++) {
+ y[0] += b[l] * x[l];
+ y[0] -= a[l] * y[l];
+ }
+ /* new output */
+ in->data[j] = y[0];
+ /* store for next sample */
+ for (l = order - 1; l > 0; l--) {
+ x[l] = x[l - 1];
+ y[l] = y[l - 1];
+ }
+ }
+}
+
+/* The rough way: reset memory of filter between each run to avoid end effects. */
+void
+aubio_filter_do_filtfilt (aubio_filter_t * f, fvec_t * in, fvec_t * tmp)
+{
+ uint_t j;
+ uint_t length = in->length;
+ /* apply filtering */
+ aubio_filter_do (f, in);
+ aubio_filter_do_reset (f);
+ /* mirror */
+ for (j = 0; j < length; j++)
+ tmp->data[length - j - 1] = in->data[j];
+ /* apply filtering on mirrored */
+ aubio_filter_do (f, tmp);
+ aubio_filter_do_reset (f);
+ /* invert back */
+ for (j = 0; j < length; j++)
+ in->data[j] = tmp->data[length - j - 1];
+}
+
+lvec_t *
+aubio_filter_get_feedback (const aubio_filter_t * f)
+{
+ return f->a;
+}
+
+lvec_t *
+aubio_filter_get_feedforward (const aubio_filter_t * f)
+{
+ return f->b;
+}
+
+uint_t
+aubio_filter_get_order (const aubio_filter_t * f)
+{
+ return f->order;
+}
+
+uint_t
+aubio_filter_get_samplerate (const aubio_filter_t * f)
+{
+ return f->samplerate;
+}
+
+uint_t
+aubio_filter_set_samplerate (aubio_filter_t * f, uint_t samplerate)
+{
+ f->samplerate = samplerate;
+ return AUBIO_OK;
+}
+
+void
+aubio_filter_do_reset (aubio_filter_t * f)
+{
+ lvec_zeros (f->x);
+ lvec_zeros (f->y);
+}
+
+aubio_filter_t *
+new_aubio_filter (uint_t order)
+{
+ aubio_filter_t *f = AUBIO_NEW (aubio_filter_t);
+ if ((sint_t)order < 1) {
+ AUBIO_FREE(f);
+ return NULL;
+ }
+ f->x = new_lvec (order);
+ f->y = new_lvec (order);
+ f->a = new_lvec (order);
+ f->b = new_lvec (order);
+ /* by default, samplerate is not set */
+ f->samplerate = 0;
+ f->order = order;
+ /* set default to identity */
+ f->a->data[0] = 1.;
+ f->b->data[0] = 1.;
+ return f;
+}
+
+void
+del_aubio_filter (aubio_filter_t * f)
+{
+ del_lvec (f->a);
+ del_lvec (f->b);
+ del_lvec (f->x);
+ del_lvec (f->y);
+ AUBIO_FREE (f);
+ return;
+}
diff --git a/src/temporal/filter.h b/src/temporal/filter.h
new file mode 100644
index 0000000..b8b678e
--- /dev/null
+++ b/src/temporal/filter.h
@@ -0,0 +1,176 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_FILTER_H
+#define AUBIO_FILTER_H
+
+/** \file
+
+ Digital filter
+
+ This object stores a digital filter of order \f$n\f$.
+ It contains the following data:
+ - \f$ n*1 b_i \f$ feedforward coefficients
+ - \f$ n*1 a_i \f$ feedback coefficients
+ - \f$ n*c x_i \f$ input signal
+ - \f$ n*c y_i \f$ output signal
+
+ For convenience, the samplerate of the input signal is also stored in the
+ object.
+
+ Feedforward and feedback parameters can be modified using
+ aubio_filter_get_feedback() and aubio_filter_get_feedforward().
+
+ The function aubio_filter_do_outplace() computes the following output signal
+ \f$ y[n] \f$ from the input signal \f$ x[n] \f$:
+
+ \f{eqnarray*}{
+ y[n] = b_0 x[n] & + & b_1 x[n-1] + b_2 x[n-2] + ... + b_P x[n-P] \\
+ & - & a_1 y[n-1] - a_2 y[n-2] - ... - a_P y[n-P] \\
+ \f}
+
+ The function aubio_filter_do() executes the same computation but modifies
+ directly the input signal (in-place).
+
+ The function aubio_filter_do_filtfilt() version runs the filter twice, first
+ forward then backward, to compensate with the phase shifting of the forward
+ operation.
+
+ Some convenience functions are provided:
+ - new_aubio_filter_a_weighting() and aubio_filter_set_a_weighting(),
+ - new_aubio_filter_c_weighting() and aubio_filter_set_c_weighting().
+ - new_aubio_filter_biquad() and aubio_filter_set_biquad().
+
+ \example temporal/test-filter.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Digital filter
+
+*/
+typedef struct _aubio_filter_t aubio_filter_t;
+
+/** filter input vector (in-place)
+
+ \param f filter object as returned by new_aubio_filter()
+ \param in input vector to filter
+
+*/
+void aubio_filter_do (aubio_filter_t * f, fvec_t * in);
+
+/** filter input vector (out-of-place)
+
+ \param f filter object as returned by new_aubio_filter()
+ \param in input vector to filter
+ \param out output vector to store filtered input
+
+*/
+void aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out);
+
+/** filter input vector forward and backward
+
+ \param f ::aubio_filter_t object as returned by new_aubio_filter()
+ \param in ::fvec_t input vector to filter
+ \param tmp memory space to use for computation
+
+*/
+void aubio_filter_do_filtfilt (aubio_filter_t * f, fvec_t * in, fvec_t * tmp);
+
+/** returns a pointer to feedback coefficients \f$ a_i \f$
+
+ \param f filter object to get parameters from
+
+ \return a pointer to the \f$ a_0 ... a_i ... a_P \f$ coefficients
+
+*/
+lvec_t *aubio_filter_get_feedback (const aubio_filter_t * f);
+
+/** returns a pointer to feedforward coefficients \f$ b_i \f$
+
+ \param f filter object to get coefficients from
+
+ \return a pointer to the \f$ b_0 ... b_i ... b_P \f$ coefficients
+
+*/
+lvec_t *aubio_filter_get_feedforward (const aubio_filter_t * f);
+
+/** get order of the filter
+
+ \param f filter to get order from
+
+ \return the order of the filter
+
+*/
+uint_t aubio_filter_get_order (const aubio_filter_t * f);
+
+/** get sampling rate of the filter
+
+ \param f filter to get sampling rate from
+
+ \return the sampling rate of the filter, in Hz
+
+*/
+uint_t aubio_filter_get_samplerate (const aubio_filter_t * f);
+
+/** get sampling rate of the filter
+
+ \param f filter to get sampling rate from
+ \param samplerate sample rate to set the filter to
+
+ \return the sampling rate of the filter, in Hz
+
+*/
+uint_t aubio_filter_set_samplerate (aubio_filter_t * f, uint_t samplerate);
+
+/** reset filter memory
+
+ \param f filter object as returned by new_aubio_filter()
+
+*/
+void aubio_filter_do_reset (aubio_filter_t * f);
+
+/** create new filter object
+
+ This function creates a new ::aubio_filter_t object, given the order of the
+ filter.
+
+ \param order order of the filter (number of coefficients)
+
+ \return the newly created filter object
+
+*/
+aubio_filter_t *new_aubio_filter (uint_t order);
+
+/** delete a filter object
+
+ \param f filter object to delete
+
+*/
+void del_aubio_filter (aubio_filter_t * f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_H */
diff --git a/src/temporal/resampler.c b/src/temporal/resampler.c
new file mode 100644
index 0000000..2c9d2fd
--- /dev/null
+++ b/src/temporal/resampler.c
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "temporal/resampler.h"
+
+#ifdef HAVE_SAMPLERATE
+
+#include <samplerate.h> /* from libsamplerate */
+
+struct _aubio_resampler_t
+{
+ SRC_DATA *proc;
+ SRC_STATE *stat;
+ smpl_t ratio;
+ uint_t type;
+};
+
+aubio_resampler_t *
+new_aubio_resampler (smpl_t ratio, uint_t type)
+{
+ aubio_resampler_t *s = AUBIO_NEW (aubio_resampler_t);
+ int error = 0;
+ s->stat = src_new (type, 1, &error); /* only one channel */
+ if (error) {
+ AUBIO_ERR ("Failed creating resampler: %s\n", src_strerror (error));
+ del_aubio_resampler(s);
+ return NULL;
+ }
+ s->proc = AUBIO_NEW (SRC_DATA);
+ s->ratio = ratio;
+ return s;
+}
+
+void
+del_aubio_resampler (aubio_resampler_t * s)
+{
+ if (s->stat) src_delete (s->stat);
+ AUBIO_FREE (s->proc);
+ AUBIO_FREE (s);
+}
+
+void
+aubio_resampler_do (aubio_resampler_t * s, const fvec_t * input, fvec_t * output)
+{
+ s->proc->input_frames = input->length;
+ s->proc->output_frames = output->length;
+ s->proc->src_ratio = (double) s->ratio;
+ /* make SRC_PROC data point to input outputs */
+ s->proc->data_in = (float *) input->data;
+ s->proc->data_out = (float *) output->data;
+ /* do resampling */
+ src_process (s->stat, s->proc);
+}
+
+#else
+struct _aubio_resampler_t
+{
+ void *dummy;
+};
+
+aubio_resampler_t *
+new_aubio_resampler (smpl_t ratio UNUSED, uint_t type UNUSED)
+{
+ AUBIO_ERR ("aubio was not compiled with libsamplerate\n");
+ return NULL;
+}
+
+void
+del_aubio_resampler (aubio_resampler_t * s UNUSED)
+{
+}
+
+void
+aubio_resampler_do (aubio_resampler_t * s UNUSED, const fvec_t * input UNUSED, fvec_t * output UNUSED)
+{
+}
+#endif /* HAVE_SAMPLERATE */
diff --git a/src/temporal/resampler.h b/src/temporal/resampler.h
new file mode 100644
index 0000000..7528e8a
--- /dev/null
+++ b/src/temporal/resampler.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_RESAMPLER_H
+#define AUBIO_RESAMPLER_H
+
+/** \file
+
+ Resampling object
+
+ This object resamples an input vector into an output vector using
+ libsamplerate. See http://www.mega-nerd.com/SRC/
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** resampler object */
+typedef struct _aubio_resampler_t aubio_resampler_t;
+
+/** create resampler object
+
+ \param ratio output_sample_rate / input_sample_rate
+ \param type libsamplerate resampling type, see http://www.mega-nerd.com/SRC/api_misc.html#Converters
+
+*/
+aubio_resampler_t *new_aubio_resampler (smpl_t ratio, uint_t type);
+
+/** delete resampler object */
+void del_aubio_resampler (aubio_resampler_t * s);
+
+/** resample input in output
+
+ \param s resampler object
+ \param input input buffer of size N
+ \param output output buffer of size N*ratio
+
+*/
+void aubio_resampler_do (aubio_resampler_t * s, const fvec_t * input,
+ fvec_t * output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_RESAMPLER_H */
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..57df2e0
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_TYPES_H
+#define AUBIO_TYPES_H
+
+/** \file
+
+ Definition of data types used in aubio
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HAVE_AUBIO_DOUBLE
+/** defined to 1 if aubio is compiled in double precision */
+#define HAVE_AUBIO_DOUBLE 0
+#endif
+
+/** short sample format (32 or 64 bits) */
+#if !HAVE_AUBIO_DOUBLE
+typedef float smpl_t;
+/** print format for sample in single precision */
+#define AUBIO_SMPL_FMT "%f"
+#else
+typedef double smpl_t;
+/** print format for double in single precision */
+#define AUBIO_SMPL_FMT "%lf"
+#endif
+/** long sample format (64 bits or more) */
+#if !HAVE_AUBIO_DOUBLE
+typedef double lsmp_t;
+/** print format for sample in double precision */
+#define AUBIO_LSMP_FMT "%lf"
+#else
+typedef long double lsmp_t;
+/** print format for double in double precision */
+#define AUBIO_LSMP_FMT "%Lf"
+#endif
+/** unsigned integer */
+typedef unsigned int uint_t;
+/** signed integer */
+typedef int sint_t;
+/** character */
+typedef char char_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TYPES_H */
diff --git a/src/utils/hist.c b/src/utils/hist.c
new file mode 100644
index 0000000..9b5ab10
--- /dev/null
+++ b/src/utils/hist.c
@@ -0,0 +1,147 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "utils/scale.h"
+#include "mathutils.h" //fvec_min fvec_max
+#include "utils/hist.h"
+
+/********
+ * Object Structure
+ */
+
+struct _aubio_hist_t {
+ fvec_t * hist;
+ uint_t nelems;
+ fvec_t * cent;
+ aubio_scale_t *scaler;
+};
+
+/**
+ * Object creation/deletion calls
+ */
+aubio_hist_t * new_aubio_hist (smpl_t flow, smpl_t fhig, uint_t nelems){
+ aubio_hist_t * s = AUBIO_NEW(aubio_hist_t);
+ smpl_t step = (fhig-flow)/(smpl_t)(nelems);
+ smpl_t accum = step;
+ uint_t i;
+ s->nelems = nelems;
+ s->hist = new_fvec(nelems);
+ s->cent = new_fvec(nelems);
+
+ /* use scale to map flow/fhig -> 0/nelems */
+ s->scaler = new_aubio_scale(flow,fhig,0,nelems);
+ /* calculate centers now once */
+ s->cent->data[0] = flow + 0.5 * step;
+ for (i=1; i < s->nelems; i++, accum+=step )
+ s->cent->data[i] = s->cent->data[0] + accum;
+
+ return s;
+}
+
+void del_aubio_hist(aubio_hist_t *s) {
+ del_fvec(s->hist);
+ del_fvec(s->cent);
+ del_aubio_scale(s->scaler);
+ AUBIO_FREE(s);
+}
+
+/***
+ * do it
+ */
+void aubio_hist_do (aubio_hist_t *s, fvec_t *input) {
+ uint_t j;
+ sint_t tmp = 0;
+ aubio_scale_do(s->scaler, input);
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (j=0; j < input->length; j++)
+ {
+ tmp = (sint_t)FLOOR(input->data[j]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems)) {
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+void aubio_hist_do_notnull (aubio_hist_t *s, fvec_t *input) {
+ uint_t j;
+ sint_t tmp = 0;
+ aubio_scale_do(s->scaler, input);
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (j=0; j < input->length; j++) {
+ if (input->data[j] != 0) {
+ tmp = (sint_t)FLOOR(input->data[j]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+
+void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input) {
+ uint_t i;
+ sint_t tmp = 0;
+ smpl_t ilow = fvec_min(input);
+ smpl_t ihig = fvec_max(input);
+ smpl_t step = (ihig-ilow)/(smpl_t)(s->nelems);
+
+ /* readapt */
+ aubio_scale_set_limits (s->scaler, ilow, ihig, 0, s->nelems);
+
+ /* recalculate centers */
+ s->cent->data[0] = ilow + 0.5f * step;
+ for (i=1; i < s->nelems; i++)
+ s->cent->data[i] = s->cent->data[0] + i * step;
+
+ /* scale */
+ aubio_scale_do(s->scaler, input);
+
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (i=0; i < input->length; i++) {
+ if (input->data[i] != 0) {
+ tmp = (sint_t)FLOOR(input->data[i]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+void aubio_hist_weight (aubio_hist_t *s) {
+ uint_t j;
+ for (j=0; j < s->nelems; j++) {
+ s->hist->data[j] *= s->cent->data[j];
+ }
+}
+
+smpl_t aubio_hist_mean (const aubio_hist_t *s) {
+ uint_t j;
+ smpl_t tmp = 0.0;
+ for (j=0; j < s->nelems; j++)
+ tmp += s->hist->data[j];
+ return tmp/(smpl_t)(s->nelems);
+}
+
diff --git a/src/utils/hist.h b/src/utils/hist.h
new file mode 100644
index 0000000..d39091a
--- /dev/null
+++ b/src/utils/hist.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file
+ *
+ * Histogram function
+ *
+ * Big hacks to implement an histogram
+ */
+
+#ifndef AUBIO_HIST_H
+#define AUBIO_HIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** histogram object */
+typedef struct _aubio_hist_t aubio_hist_t;
+
+/** histogram creation
+
+ \param flow minimum input
+ \param fhig maximum input
+ \param nelems number of histogram columns
+
+*/
+aubio_hist_t * new_aubio_hist(smpl_t flow, smpl_t fhig, uint_t nelems);
+/** histogram deletion */
+void del_aubio_hist(aubio_hist_t *s);
+/** compute the histogram */
+void aubio_hist_do(aubio_hist_t *s, fvec_t * input);
+/** compute the histogram ignoring null elements */
+void aubio_hist_do_notnull(aubio_hist_t *s, fvec_t * input);
+/** compute the mean of the histogram */
+smpl_t aubio_hist_mean(const aubio_hist_t *s);
+/** weight the histogram */
+void aubio_hist_weight(aubio_hist_t *s);
+/** compute dynamic histogram for non-null elements */
+void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_HIST_H */
diff --git a/src/utils/parameter.c b/src/utils/parameter.c
new file mode 100644
index 0000000..f8a8b45
--- /dev/null
+++ b/src/utils/parameter.c
@@ -0,0 +1,142 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "parameter.h"
+
+#define AUBIO_PARAM_MAX_STEPS 2000
+#define AUBIO_PARAM_MIN_STEPS 1
+
+struct _aubio_parameter_t {
+ smpl_t current_value;
+ smpl_t target_value;
+ smpl_t increment;
+
+ smpl_t max_value;
+ smpl_t min_value;
+
+ uint_t steps;
+};
+
+aubio_parameter_t * new_aubio_parameter (smpl_t min_value, smpl_t max_value, uint_t steps )
+{
+ aubio_parameter_t * param = AUBIO_NEW(aubio_parameter_t);
+
+ param->min_value = min_value;
+ param->max_value = max_value;
+ param->steps = steps;
+
+ param->current_value = param->min_value;
+ param->target_value = param->current_value;
+ param->increment = 0.;
+
+ return param;
+}
+
+uint_t aubio_parameter_set_target_value ( aubio_parameter_t * param, smpl_t value )
+{
+ uint_t err = AUBIO_OK;
+ if (value < param->min_value ) {
+ param->target_value = param->min_value;
+ err = AUBIO_FAIL;
+ } else if ( value > param->max_value ) {
+ param->target_value = param->max_value;
+ err = AUBIO_FAIL;
+ } else {
+ param->target_value = value;
+ }
+ param->increment = ( param->target_value - param->current_value ) / param->steps;
+ return err;
+}
+
+uint_t aubio_parameter_set_current_value ( aubio_parameter_t * param, smpl_t value )
+{
+ uint_t err = AUBIO_OK;
+ if (value < param->min_value ) {
+ param->current_value = param->min_value;
+ err = AUBIO_FAIL;
+ } else if ( value > param->max_value ) {
+ param->current_value = param->max_value;
+ err = AUBIO_FAIL;
+ } else {
+ param->current_value = value;
+ }
+ param->target_value = param->current_value;
+ param->increment = 0;
+ return err;
+}
+
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * s )
+{
+ return s->current_value;
+}
+
+smpl_t aubio_parameter_get_next_value ( aubio_parameter_t * s )
+{
+ if ( ABS(s->current_value - s->target_value) > ABS(s->increment) ) {
+ s->current_value += s->increment;
+ } else {
+ s->current_value = s->target_value;
+ }
+ return s->current_value;
+}
+
+uint_t aubio_parameter_set_steps ( aubio_parameter_t * param, uint_t steps )
+{
+ if (steps < AUBIO_PARAM_MIN_STEPS || steps > AUBIO_PARAM_MAX_STEPS) {
+ return AUBIO_FAIL;
+ }
+ param->steps = steps;
+ param->increment = ( param->target_value - param->current_value ) / param->steps;
+ return AUBIO_OK;
+}
+
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param )
+{
+ return param->steps;
+}
+
+uint_t aubio_parameter_set_min_value ( aubio_parameter_t * param, smpl_t min_value )
+{
+ param->min_value = min_value;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param )
+{
+ return param->min_value;
+}
+
+uint_t aubio_parameter_set_max_value ( aubio_parameter_t * param, smpl_t max_value )
+{
+ param->max_value = max_value;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param )
+{
+ return param->max_value;
+}
+
+void del_aubio_parameter ( aubio_parameter_t * param )
+{
+ AUBIO_FREE(param);
+}
diff --git a/src/utils/parameter.h b/src/utils/parameter.h
new file mode 100644
index 0000000..9649eb8
--- /dev/null
+++ b/src/utils/parameter.h
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_PARAMETER_H
+#define AUBIO_PARAMETER_H
+
+/** \file
+
+ Parameter with linear interpolation
+
+ This object manages a parameter, with minimum and maximum values, and a
+ number of steps to compute linear interpolation between two values.
+
+ \example utils/test-parameter.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** parameter object */
+typedef struct _aubio_parameter_t aubio_parameter_t;
+
+/** create new parameter object
+
+ \param min_value the minimum value of the new parameter
+ \param max_value the maximum value of the new parameter
+ \param steps the number of steps to interpolate from the old value to the target value
+
+ \return the newly created ::aubio_parameter_t
+
+*/
+aubio_parameter_t * new_aubio_parameter(smpl_t min_value, smpl_t max_value, uint_t steps);
+
+/** set target value of the parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param value new target value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_target_value ( aubio_parameter_t * param, smpl_t value );
+
+/** get next parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return new interpolated parameter value
+
+*/
+smpl_t aubio_parameter_get_next_value ( aubio_parameter_t * param );
+
+/** get current parameter value, without interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return current value
+
+*/
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * param );
+
+/** set current parameter value, skipping interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param value new parameter value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_current_value ( aubio_parameter_t * param, smpl_t value );
+
+/** set number of steps used for interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param steps new number of steps
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_steps ( aubio_parameter_t * param, uint_t steps );
+
+/** get number of steps of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return number of steps
+
+*/
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param);
+
+/** set minimum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param min_value new minimum value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_min_value ( aubio_parameter_t * param, smpl_t min_value );
+
+/** get minimum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return minimum value
+
+*/
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param );
+
+/** set maximum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param max_value new maximum value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_max_value ( aubio_parameter_t * param, smpl_t max_value );
+
+/** get maximum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return maximum value
+
+*/
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param );
+
+/** destroy ::aubio_parameter_t object
+
+ \param param parameter, created by ::new_aubio_parameter
+
+*/
+void del_aubio_parameter( aubio_parameter_t * param );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PARAMETER_H */
diff --git a/src/utils/scale.c b/src/utils/scale.c
new file mode 100644
index 0000000..3bd116c
--- /dev/null
+++ b/src/utils/scale.c
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "utils/scale.h"
+
+struct _aubio_scale_t {
+ smpl_t ilow;
+ smpl_t ihig;
+ smpl_t olow;
+ smpl_t ohig;
+
+ smpl_t scaler;
+ smpl_t irange;
+
+ /* not implemented yet : type in/out data
+ bool inint;
+ bool outint;
+ */
+};
+
+aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig) {
+ aubio_scale_t * s = AUBIO_NEW(aubio_scale_t);
+ aubio_scale_set_limits (s, ilow, ihig, olow, ohig);
+ return s;
+}
+
+void del_aubio_scale(aubio_scale_t *s) {
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_scale_set_limits (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig) {
+ smpl_t inputrange = ihig - ilow;
+ smpl_t outputrange= ohig - olow;
+ s->ilow = ilow;
+ s->ihig = ihig;
+ s->olow = olow;
+ s->ohig = ohig;
+ if (inputrange == 0) {
+ s->scaler = 0.0;
+ } else {
+ s->scaler = outputrange/inputrange;
+ if (inputrange < 0) {
+ inputrange = inputrange * -1.0f;
+ }
+ }
+ return AUBIO_OK;
+}
+
+void aubio_scale_do (aubio_scale_t *s, fvec_t *input)
+{
+ uint_t j;
+ for (j=0; j < input->length; j++){
+ input->data[j] -= s->ilow;
+ input->data[j] *= s->scaler;
+ input->data[j] += s->olow;
+ }
+}
+
diff --git a/src/utils/scale.h b/src/utils/scale.h
new file mode 100644
index 0000000..da31114
--- /dev/null
+++ b/src/utils/scale.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Vector scaling function
+
+ This object, inspired from the scale object in FTS, the jMax engine, scales
+ the values of a vector according to an affine function defined as follow:
+
+ \f$ y = (x - ilow)*(ohig-olow)/(ihig-ilow) + olow \f$
+
+*/
+#ifndef AUBIO_SCALE_H
+#define AUBIO_SCALE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** scale object */
+typedef struct _aubio_scale_t aubio_scale_t;
+
+/** create a scale object
+
+ \param flow lower value of output function
+ \param fhig higher value of output function
+ \param ilow lower value of input function
+ \param ihig higher value of output function
+
+*/
+aubio_scale_t * new_aubio_scale(smpl_t flow, smpl_t fhig,
+ smpl_t ilow, smpl_t ihig);
+/** delete a scale object
+
+ \param s scale object as returned by new_aubio_scale
+
+*/
+void del_aubio_scale(aubio_scale_t *s);
+/** scale input vector
+
+ \param s scale object as returned by new_aubio_scale
+ \param input vector to scale
+
+*/
+void aubio_scale_do(aubio_scale_t *s, fvec_t * input);
+/** modify scale parameters after object creation
+
+ \param s scale object as returned by new_aubio_scale
+ \param olow lower value of output function
+ \param ohig higher value of output function
+ \param ilow lower value of input function
+ \param ihig higher value of output function
+
+*/
+uint_t aubio_scale_set_limits (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SCALE_H */
diff --git a/src/utils/windll.c b/src/utils/windll.c
new file mode 100644
index 0000000..7c11af6
--- /dev/null
+++ b/src/utils/windll.c
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file
+
+ Windows dll entry point.
+
+*/
+
+#include "config.h"
+
+#ifdef HAVE_WIN_HACKS
+
+#ifndef __GNUC__ // do not include msvc headers when using gcc/mingw32
+
+// latest version
+#include <SDKDDKVer.h>
+// for earlier versions, include WinSDKVer.h and set _WIN32_WINNT macro
+
+#endif /* __GNUC__ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "aubio.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+#endif
diff --git a/src/vecutils.c b/src/vecutils.c
new file mode 100644
index 0000000..8e49f96
--- /dev/null
+++ b/src/vecutils.c
@@ -0,0 +1,37 @@
+#include "config.h"
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "vecutils.h"
+
+#define AUBIO_OP(OPNAME, OP, TYPE, OBJ) \
+void TYPE ## _ ## OPNAME (TYPE ## _t *o) \
+{ \
+ uint_t j; \
+ for (j = 0; j < o->length; j++) { \
+ o->OBJ[j] = OP (o->OBJ[j]); \
+ } \
+}
+
+#define AUBIO_OP_C(OPNAME, OP) \
+ AUBIO_OP(OPNAME, OP, fvec, data)
+
+AUBIO_OP_C(exp, EXP)
+AUBIO_OP_C(cos, COS)
+AUBIO_OP_C(sin, SIN)
+AUBIO_OP_C(abs, ABS)
+AUBIO_OP_C(sqrt, SQRT)
+AUBIO_OP_C(log10, SAFE_LOG10)
+AUBIO_OP_C(log, SAFE_LOG)
+AUBIO_OP_C(floor, FLOOR)
+AUBIO_OP_C(ceil, CEIL)
+AUBIO_OP_C(round, ROUND)
+
+void fvec_pow (fvec_t *s, smpl_t power)
+{
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ s->data[j] = POW(s->data[j], power);
+ }
+}
diff --git a/src/vecutils.h b/src/vecutils.h
new file mode 100644
index 0000000..f0ed96e
--- /dev/null
+++ b/src/vecutils.h
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2009-2015 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** \file
+
+ Utility functions for ::fvec_t
+
+ */
+
+#ifndef AUBIO_VECUTILS_H
+#define AUBIO_VECUTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** compute \f$e^x\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_exp (fvec_t *s);
+
+/** compute \f$cos(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_cos (fvec_t *s);
+
+/** compute \f$sin(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_sin (fvec_t *s);
+
+/** compute the \f$abs(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_abs (fvec_t *s);
+
+/** compute the \f$sqrt(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_sqrt (fvec_t *s);
+
+/** compute the \f$log10(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_log10 (fvec_t *s);
+
+/** compute the \f$log(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_log (fvec_t *s);
+
+/** compute the \f$floor(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_floor (fvec_t *s);
+
+/** compute the \f$ceil(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_ceil (fvec_t *s);
+
+/** compute the \f$round(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_round (fvec_t *s);
+
+/** raise each vector elements to the power pow
+
+ \param s vector to modify
+ \param pow power to raise to
+
+*/
+void fvec_pow (fvec_t *s, smpl_t pow);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_VECUTILS_H */
diff --git a/src/wscript_build b/src/wscript_build
new file mode 100644
index 0000000..f2bd2ba
--- /dev/null
+++ b/src/wscript_build
@@ -0,0 +1,41 @@
+# vim:set syntax=python:
+
+uselib = []
+uselib += ['M']
+uselib += ['FFTW3', 'FFTW3F']
+uselib += ['SAMPLERATE']
+uselib += ['SNDFILE']
+uselib += ['AVCODEC']
+uselib += ['AVFORMAT']
+uselib += ['AVRESAMPLE']
+uselib += ['AVUTIL']
+uselib += ['BLAS']
+
+source = ctx.path.ant_glob('*.c **/*.c')
+
+ctx(features = 'c',
+ source = source,
+ includes = ['.'],
+ use = uselib,
+ target = 'lib_objects')
+
+# build libaubio.so (cshlib) and/or libaubio.a (cstlib)
+if ctx.env['DEST_OS'] in ['ios', 'iosimulator']:
+ build_features = ['cstlib', 'cshlib']
+elif ctx.env['DEST_OS'] in ['win32', 'win64']:
+ build_features = ['cstlib', 'cshlib']
+elif ctx.env['DEST_OS'] in ['emscripten']:
+ build_features = ['cstlib']
+else: #linux, darwin, android, mingw, ...
+ build_features = ['cstlib', 'cshlib']
+
+for target in build_features:
+ ctx(features = 'c ' + target,
+ use = uselib + ['lib_objects'],
+ target = 'aubio',
+ vnum = ctx.env['LIB_VERSION'])
+
+# install headers, except _priv.h ones
+ctx.install_files('${PREFIX}/include/aubio/',
+ ctx.path.ant_glob('**/*.h', excl = ['**_priv.h', 'config.h']),
+ relative_trick=True)
diff --git a/tests/src/io/test-sink-multi.c b/tests/src/io/test-sink-multi.c
new file mode 100644
index 0000000..3f44787
--- /dev/null
+++ b/tests/src/io/test-sink-multi.c
@@ -0,0 +1,73 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0;
+ uint_t channels = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) channels = atoi(argv[4]);
+ if ( argc >= 6 ) hop_size = atoi(argv[5]);
+ if ( argc >= 7 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+ if (channels == 0 ) channels = aubio_source_get_channels(i);
+
+ fmat_t *mat = new_fmat(channels, hop_size);
+ if (!mat) { err = 1; goto beach_fmat; }
+
+ aubio_sink_t *o = new_aubio_sink(sink_path, 0);
+ if (!o) { err = 1; goto beach_sink; }
+ err = aubio_sink_preset_samplerate(o, samplerate);
+ if (err) { goto beach; }
+ err = aubio_sink_preset_channels(o, channels);
+ if (err) { goto beach; }
+
+ do {
+ aubio_source_do_multi(i, mat, &read);
+ aubio_sink_do_multi(o, mat, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz in %d channels (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, channels, n_frames / hop_size,
+ source_path, sink_path);
+ PRINT_MSG("wrote %s with %dHz in %d channels\n", sink_path,
+ aubio_sink_get_samplerate(o),
+ aubio_sink_get_channels(o) );
+
+beach:
+ del_aubio_sink(o);
+beach_sink:
+ del_fmat(mat);
+beach_fmat:
+ del_aubio_source(i);
+beach_source:
+ return err;
+}
diff --git a/tests/src/io/test-sink.c b/tests/src/io/test-sink.c
new file mode 100644
index 0000000..2f04177
--- /dev/null
+++ b/tests/src/io/test-sink.c
@@ -0,0 +1,58 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) hop_size = atoi(argv[4]);
+ if ( argc >= 6 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ fvec_t *vec = new_fvec(hop_size);
+ if (!vec) { err = 1; goto beach_fvec; }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+ aubio_sink_t *o = new_aubio_sink(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ do {
+ aubio_source_do(i, vec, &read);
+ aubio_sink_do(o, vec, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path, sink_path);
+
+ del_aubio_sink(o);
+beach_sink:
+ del_aubio_source(i);
+beach_source:
+ del_fvec(vec);
+beach_fvec:
+ return err;
+}
diff --git a/tests/src/io/test-sink_apple_audio-multi.c b/tests/src/io/test-sink_apple_audio-multi.c
new file mode 100644
index 0000000..fc06d5e
--- /dev/null
+++ b/tests/src/io/test-sink_apple_audio-multi.c
@@ -0,0 +1,78 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_SINK_APPLE_AUDIO
+ uint_t samplerate = 0;
+ uint_t channels = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) channels = atoi(argv[4]);
+ if ( argc >= 6 ) hop_size = atoi(argv[5]);
+ if ( argc >= 7 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+ if (channels == 0 ) channels = aubio_source_get_channels(i);
+
+ fmat_t *mat = new_fmat(channels, hop_size);
+ if (!mat) { err = 1; goto beach_fmat; }
+
+ aubio_sink_apple_audio_t *o = new_aubio_sink_apple_audio(sink_path, 0);
+ if (!o) { err = 1; goto beach_sink; }
+ err = aubio_sink_apple_audio_preset_samplerate(o, samplerate);
+ if (err) { goto beach; }
+ err = aubio_sink_apple_audio_preset_channels(o, channels);
+ if (err) { goto beach; }
+
+ do {
+ aubio_source_do_multi(i, mat, &read);
+ aubio_sink_apple_audio_do_multi(o, mat, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz in %d channels (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, channels, n_frames / hop_size,
+ source_path, sink_path);
+ PRINT_MSG("wrote %s with %dHz in %d channels\n", sink_path,
+ aubio_sink_apple_audio_get_samplerate(o),
+ aubio_sink_apple_audio_get_channels(o) );
+
+beach:
+ del_aubio_sink_apple_audio(o);
+beach_sink:
+ del_fmat(mat);
+beach_fmat:
+ del_aubio_source(i);
+beach_source:
+#else /* HAVE_SINK_APPLE_AUDIO */
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_sink_apple_audio\n");
+#endif /* HAVE_SINK_APPLE_AUDIO */
+ return err;
+}
diff --git a/tests/src/io/test-sink_apple_audio.c b/tests/src/io/test-sink_apple_audio.c
new file mode 100644
index 0000000..86d1769
--- /dev/null
+++ b/tests/src/io/test-sink_apple_audio.c
@@ -0,0 +1,67 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_SINK_APPLE_AUDIO
+ uint_t samplerate = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) hop_size = atoi(argv[4]);
+ if ( argc >= 6 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ fvec_t *vec = new_fvec(hop_size);
+ if (!vec) { err = 1; goto beach_fvec; }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+ aubio_sink_apple_audio_t *o = new_aubio_sink_apple_audio(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ do {
+ aubio_source_do(i, vec, &read);
+ aubio_sink_apple_audio_do(o, vec, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path, sink_path);
+
+ del_aubio_sink_apple_audio(o);
+beach_sink:
+ del_aubio_source(i);
+beach_source:
+ del_fvec(vec);
+beach_fvec:
+#else /* HAVE_SINK_APPLE_AUDIO */
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_apple_audio\n");
+#endif /* HAVE_SINK_APPLE_AUDIO */
+ return err;
+}
diff --git a/tests/src/io/test-sink_sndfile-multi.c b/tests/src/io/test-sink_sndfile-multi.c
new file mode 100644
index 0000000..4dcc690
--- /dev/null
+++ b/tests/src/io/test-sink_sndfile-multi.c
@@ -0,0 +1,79 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "config.h"
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_SNDFILE
+ uint_t samplerate = 0;
+ uint_t channels = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) channels = atoi(argv[4]);
+ if ( argc >= 6 ) hop_size = atoi(argv[5]);
+ if ( argc >= 7 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+ if (channels == 0 ) channels = aubio_source_get_channels(i);
+
+ fmat_t *mat = new_fmat(channels, hop_size);
+ if (!mat) { err = 1; goto beach_fmat; }
+
+ aubio_sink_sndfile_t *o = new_aubio_sink_sndfile(sink_path, 0);
+ if (!o) { err = 1; goto beach_sink; }
+ err = aubio_sink_sndfile_preset_samplerate(o, samplerate);
+ if (err) { goto beach; }
+ err = aubio_sink_sndfile_preset_channels(o, channels);
+ if (err) { goto beach; }
+
+ do {
+ aubio_source_do_multi(i, mat, &read);
+ aubio_sink_sndfile_do_multi(o, mat, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz in %d channels (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, channels, n_frames / hop_size,
+ source_path, sink_path);
+ PRINT_MSG("wrote %s with %dHz in %d channels\n", sink_path,
+ aubio_sink_sndfile_get_samplerate(o),
+ aubio_sink_sndfile_get_channels(o) );
+
+beach:
+ del_aubio_sink_sndfile(o);
+beach_sink:
+ del_fmat(mat);
+beach_fmat:
+ del_aubio_source(i);
+beach_source:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_sink_sndfile\n");
+#endif /* HAVE_SNDFILE */
+ return err;
+}
diff --git a/tests/src/io/test-sink_sndfile.c b/tests/src/io/test-sink_sndfile.c
new file mode 100644
index 0000000..7812229
--- /dev/null
+++ b/tests/src/io/test-sink_sndfile.c
@@ -0,0 +1,68 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "config.h"
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_SNDFILE
+ uint_t samplerate = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) hop_size = atoi(argv[4]);
+ if ( argc >= 6 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ fvec_t *vec = new_fvec(hop_size);
+ if (!vec) { err = 1; goto beach_fvec; }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+ aubio_sink_sndfile_t *o = new_aubio_sink_sndfile(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ do {
+ aubio_source_do(i, vec, &read);
+ aubio_sink_sndfile_do(o, vec, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path, sink_path);
+
+ del_aubio_sink_sndfile(o);
+beach_sink:
+ del_aubio_source(i);
+beach_source:
+ del_fvec(vec);
+beach_fvec:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_sndfile\n");
+#endif /* HAVE_SNDFILE */
+ return err;
+}
diff --git a/tests/src/io/test-sink_wavwrite-multi.c b/tests/src/io/test-sink_wavwrite-multi.c
new file mode 100644
index 0000000..c80e2c0
--- /dev/null
+++ b/tests/src/io/test-sink_wavwrite-multi.c
@@ -0,0 +1,78 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [channels] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_WAVWRITE
+ uint_t samplerate = 0;
+ uint_t channels = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) channels = atoi(argv[4]);
+ if ( argc >= 6 ) hop_size = atoi(argv[5]);
+ if ( argc >= 7 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+ if (channels == 0 ) channels = aubio_source_get_channels(i);
+
+ fmat_t *mat = new_fmat(channels, hop_size);
+ if (!mat) { err = 1; goto beach_fmat; }
+
+ aubio_sink_wavwrite_t *o = new_aubio_sink_wavwrite(sink_path, 0);
+ if (!o) { err = 1; goto beach_sink; }
+ err = aubio_sink_wavwrite_preset_samplerate(o, samplerate);
+ if (err) { goto beach; }
+ err = aubio_sink_wavwrite_preset_channels(o, channels);
+ if (err) { goto beach; }
+
+ do {
+ aubio_source_do_multi(i, mat, &read);
+ aubio_sink_wavwrite_do_multi(o, mat, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz in %d channels (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, channels, n_frames / hop_size,
+ source_path, sink_path);
+ PRINT_MSG("wrote %s with %dHz in %d channels\n", sink_path,
+ aubio_sink_wavwrite_get_samplerate(o),
+ aubio_sink_wavwrite_get_channels(o) );
+
+beach:
+ del_aubio_sink_wavwrite(o);
+beach_sink:
+ del_fmat(mat);
+beach_fmat:
+ del_aubio_source(i);
+beach_source:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_sink_wavwrite\n");
+#endif /* HAVE_WAVWRITE */
+ return err;
+}
diff --git a/tests/src/io/test-sink_wavwrite.c b/tests/src/io/test-sink_wavwrite.c
new file mode 100644
index 0000000..2e758e3
--- /dev/null
+++ b/tests/src/io/test-sink_wavwrite.c
@@ -0,0 +1,67 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> [samplerate] [hop_size]\n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_WAVWRITE
+ uint_t samplerate = 0;
+ uint_t hop_size = 512;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+
+ if ( argc >= 4 ) samplerate = atoi(argv[3]);
+ if ( argc >= 5 ) hop_size = atoi(argv[4]);
+ if ( argc >= 6 ) {
+ err = 2;
+ PRINT_ERR("too many arguments\n");
+ return err;
+ }
+
+ fvec_t *vec = new_fvec(hop_size);
+ if (!vec) { err = 1; goto beach_fvec; }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+ aubio_sink_wavwrite_t *o = new_aubio_sink_wavwrite(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ do {
+ aubio_source_do(i, vec, &read);
+ aubio_sink_wavwrite_do(o, vec, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path, sink_path);
+
+ del_aubio_sink_wavwrite(o);
+beach_sink:
+ del_aubio_source(i);
+beach_source:
+ del_fvec(vec);
+beach_fvec:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_sink_wavwrite\n");
+#endif /* HAVE_WAVWRITE */
+ return err;
+}
diff --git a/tests/src/io/test-source.c b/tests/src/io/test-source.c
new file mode 100644
index 0000000..a1f17ae
--- /dev/null
+++ b/tests/src/io/test-source.c
@@ -0,0 +1,59 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+
+ aubio_source_t* s =
+ new_aubio_source(source_path, samplerate, hop_size);
+ if (!s) { err = 1; goto beach; }
+ fvec_t *vec = new_fvec(hop_size);
+
+ uint_t n_frames_expected = aubio_source_get_duration(s);
+
+ samplerate = aubio_source_get_samplerate(s);
+
+ do {
+ aubio_source_do(s, vec, &read);
+ fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+ n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+ source_path);
+
+ // close the file (optional)
+ aubio_source_close(s);
+ // test closing the file a second time
+ aubio_source_close(s);
+
+ del_fvec (vec);
+ del_aubio_source (s);
+beach:
+ return err;
+}
diff --git a/tests/src/io/test-source_apple_audio.c b/tests/src/io/test-source_apple_audio.c
new file mode 100644
index 0000000..92d0e54
--- /dev/null
+++ b/tests/src/io/test-source_apple_audio.c
@@ -0,0 +1,63 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_source instead
+// see src/io/source.h and tests/src/source/test-source.c
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.aif at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.mp3 at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.mp3 0 4096 \n", argv[0]);
+ return err;
+ }
+
+#if HAVE_SOURCE_APPLE_AUDIO
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+
+ aubio_source_apple_audio_t * s =
+ new_aubio_source_apple_audio(source_path, samplerate, hop_size);
+ if (!s) { err = 1; goto beach; }
+ fvec_t *vec = new_fvec(hop_size);
+
+ uint_t n_frames_expected = aubio_source_apple_audio_get_duration(s);
+
+ samplerate = aubio_source_apple_audio_get_samplerate(s);
+
+ do {
+ aubio_source_apple_audio_do(s, vec, &read);
+ fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+ n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+ source_path);
+
+ del_fvec (vec);
+ del_aubio_source_apple_audio (s);
+beach:
+#else /* HAVE_SOURCE_APPLE_AUDIO */
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_apple_audio\n");
+#endif /* HAVE_SOURCE_APPLE_AUDIO */
+ return err;
+}
diff --git a/tests/src/io/test-source_avcodec.c b/tests/src/io/test-source_avcodec.c
new file mode 100644
index 0000000..dc23d76
--- /dev/null
+++ b/tests/src/io/test-source_avcodec.c
@@ -0,0 +1,63 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_source instead
+// see src/io/source.h and tests/src/source/test-source.c
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_LIBAV
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+
+ aubio_source_avcodec_t * s =
+ new_aubio_source_avcodec(source_path, samplerate, hop_size);
+ if (!s) { err = 1; goto beach; }
+ fvec_t *vec = new_fvec(hop_size);
+
+ uint_t n_frames_expected = aubio_source_avcodec_get_duration(s);
+
+ samplerate = aubio_source_avcodec_get_samplerate(s);
+
+ do {
+ aubio_source_avcodec_do(s, vec, &read);
+ fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+ n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+ source_path);
+
+ del_fvec (vec);
+ del_aubio_source_avcodec (s);
+beach:
+#else /* HAVE_LIBAV */
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_avcodec\n");
+#endif /* HAVE_LIBAV */
+ return err;
+}
diff --git a/tests/src/io/test-source_multi.c b/tests/src/io/test-source_multi.c
new file mode 100644
index 0000000..b3b4683
--- /dev/null
+++ b/tests/src/io/test-source_multi.c
@@ -0,0 +1,57 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+ if (argc < 2) {
+ err = -2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 256 frames blocks, mono\n");
+ PRINT_MSG(" %s file.wav 0 4096 1\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ uint_t n_channels = 0;
+ if ( argc >= 3 ) samplerate = atoi(argv[2]);
+ if ( argc >= 4 ) hop_size = atoi(argv[3]);
+ if ( argc >= 5 ) n_channels = atoi(argv[4]);
+
+ char_t *source_path = argv[1];
+
+ aubio_source_t* s = new_aubio_source(source_path, samplerate, hop_size);
+ if (!s) { err = -1; goto beach; }
+
+ if ( samplerate == 0 ) samplerate = aubio_source_get_samplerate(s);
+
+ if ( n_channels == 0 ) n_channels = aubio_source_get_channels(s);
+
+ fmat_t *mat = new_fmat(n_channels, hop_size);
+
+ do {
+ aubio_source_do_multi (s, mat, &read);
+ fmat_print (mat);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames in %d channels at %dHz (%d blocks) from %s\n",
+ n_frames, n_channels, samplerate, n_frames / hop_size, source_path);
+
+ del_fmat (mat);
+ del_aubio_source (s);
+beach:
+
+ return err;
+}
diff --git a/tests/src/io/test-source_seek.c b/tests/src/io/test-source_seek.c
new file mode 100644
index 0000000..773aefe
--- /dev/null
+++ b/tests/src/io/test-source_seek.c
@@ -0,0 +1,92 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ uint_t old_n_frames_1 = 0, old_n_frames_2 = 0, old_n_frames_3 = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+ fvec_t *vec = new_fvec(hop_size);
+
+ aubio_source_t* s = new_aubio_source(source_path, samplerate, hop_size);
+ if (!s) { err = 1; goto beach; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(s);
+
+ do {
+ aubio_source_do(s, vec, &read);
+ //fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %.2fs, %d frames at %dHz (%d blocks) from %s\n",
+ n_frames * 1. / samplerate,
+ n_frames, samplerate,
+ n_frames / hop_size, source_path);
+
+ old_n_frames_1 = n_frames;
+
+ aubio_source_seek (s, 0);
+
+ n_frames = 0;
+ do {
+ aubio_source_do(s, vec, &read);
+ //fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %.2fs, %d frames at %dHz (%d blocks) from %s\n",
+ n_frames * 1. / samplerate,
+ n_frames, samplerate,
+ n_frames / hop_size, source_path);
+
+ old_n_frames_2 = n_frames;
+
+ aubio_source_seek (s, old_n_frames_1 / 2);
+
+ n_frames = 0;
+ do {
+ aubio_source_do(s, vec, &read);
+ //fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %.2fs, %d frames at %dHz (%d blocks) from %s\n",
+ n_frames * 1. / samplerate,
+ n_frames, samplerate,
+ n_frames / hop_size, source_path);
+
+ old_n_frames_3 = n_frames;
+
+ del_aubio_source (s);
+beach:
+ del_fvec (vec);
+
+ // check that we got exactly the same number of frames
+ assert ( old_n_frames_2 == old_n_frames_1 );
+ // check that we got about half the frames, with 3 decimals
+ assert ( roundf(1.e3 * old_n_frames_1 / old_n_frames_3) / 1.e3 == 2.);
+ return err;
+}
diff --git a/tests/src/io/test-source_sndfile.c b/tests/src/io/test-source_sndfile.c
new file mode 100644
index 0000000..6dfff59
--- /dev/null
+++ b/tests/src/io/test-source_sndfile.c
@@ -0,0 +1,63 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_source instead
+// see src/io/source.h and tests/src/source/test-source.c
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_SNDFILE
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+
+ aubio_source_sndfile_t * s =
+ new_aubio_source_sndfile(source_path, samplerate, hop_size);
+ if (!s) { err = 1; goto beach; }
+ fvec_t *vec = new_fvec(hop_size);
+
+ uint_t n_frames_expected = aubio_source_sndfile_get_duration(s);
+
+ samplerate = aubio_source_sndfile_get_samplerate(s);
+
+ do {
+ aubio_source_sndfile_do(s, vec, &read);
+ fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+ n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+ source_path);
+
+ del_fvec (vec);
+ del_aubio_source_sndfile (s);
+beach:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_sndfile\n");
+#endif /* HAVE_SNDFILE */
+ return err;
+}
diff --git a/tests/src/io/test-source_wavread.c b/tests/src/io/test-source_wavread.c
new file mode 100644
index 0000000..23511ca
--- /dev/null
+++ b/tests/src/io/test-source_wavread.c
@@ -0,0 +1,64 @@
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+// this file uses the unstable aubio api, please use aubio_source instead
+// see src/io/source.h and tests/src/source/test-source.c
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ PRINT_MSG("examples:\n");
+ PRINT_MSG(" - read file.wav at original samplerate\n");
+ PRINT_MSG(" %s file.wav\n", argv[0]);
+ PRINT_MSG(" - read file.wav at 32000Hz\n");
+ PRINT_MSG(" %s file.aif 32000\n", argv[0]);
+ PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n");
+ PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]);
+ return err;
+ }
+
+#ifdef HAVE_WAVREAD
+ uint_t samplerate = 0;
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+
+
+ aubio_source_wavread_t * s =
+ new_aubio_source_wavread(source_path, samplerate, hop_size);
+
+ if (!s) { err = 1; goto beach; }
+ fvec_t *vec = new_fvec(hop_size);
+
+ uint_t n_frames_expected = aubio_source_wavread_get_duration(s);
+
+ samplerate = aubio_source_wavread_get_samplerate(s);
+
+ do {
+ aubio_source_wavread_do(s, vec, &read);
+ fvec_print (vec);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames (expected %d) at %dHz (%d blocks) from %s\n",
+ n_frames, n_frames_expected, samplerate, n_frames / hop_size,
+ source_path);
+
+ del_fvec (vec);
+ del_aubio_source_wavread (s);
+beach:
+#else
+ err = 3;
+ PRINT_ERR("aubio was not compiled with aubio_source_wavread\n");
+#endif /* HAVE_WAVREAD */
+ return err;
+}
diff --git a/tests/src/onset/test-onset.c b/tests/src/onset/test-onset.c
new file mode 100644
index 0000000..d1476b0
--- /dev/null
+++ b/tests/src/onset/test-onset.c
@@ -0,0 +1,62 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [hop_size]\n", argv[0]);
+ return err;
+ }
+ uint_t samplerate = 0;
+ uint_t win_s = 1024; // window size
+ uint_t hop_size = win_s / 4;
+ uint_t n_frames = 0, read = 0;
+ if ( argc == 3 ) samplerate = atoi(argv[2]);
+ if ( argc == 4 ) hop_size = atoi(argv[3]);
+
+ char_t *source_path = argv[1];
+ aubio_source_t * source = new_aubio_source(source_path, samplerate, hop_size);
+ if (!source) { err = 1; goto beach; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(source);
+
+ // create some vectors
+ fvec_t * in = new_fvec (hop_size); // input audio buffer
+ fvec_t * out = new_fvec (2); // output position
+
+ // create onset object
+ aubio_onset_t * o = new_aubio_onset("default", win_s, hop_size, samplerate);
+
+ do {
+ // put some fresh data in input vector
+ aubio_source_do(source, in, &read);
+ // execute onset
+ aubio_onset_do(o,in,out);
+ // do something with the onsets
+ if (out->data[0] != 0) {
+ PRINT_MSG("onset at %.3fms, %.3fs, frame %d\n",
+ aubio_onset_get_last_ms(o), aubio_onset_get_last_s(o),
+ aubio_onset_get_last(o));
+ }
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %.2fs, %d frames at %dHz (%d blocks) from %s\n",
+ n_frames * 1. / samplerate,
+ n_frames, samplerate,
+ n_frames / hop_size, source_path);
+
+ // clean up memory
+ del_aubio_source(source);
+ del_aubio_onset(o);
+ del_fvec(in);
+ del_fvec(out);
+beach:
+ aubio_cleanup();
+
+ return err;
+}
diff --git a/tests/src/onset/test-peakpicker.c b/tests/src/onset/test-peakpicker.c
new file mode 100644
index 0000000..e86232d
--- /dev/null
+++ b/tests/src/onset/test-peakpicker.c
@@ -0,0 +1,23 @@
+#define AUBIO_UNSTABLE 1
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 1024; // window size
+ fvec_t * in = new_fvec (win_s); // input buffer
+ fvec_t * out = new_fvec (1); // input buffer
+ aubio_peakpicker_t * o = new_aubio_peakpicker();
+ aubio_peakpicker_set_threshold (o, 0.3);
+
+ aubio_peakpicker_do(o, in, out);
+ aubio_peakpicker_do(o, in, out);
+ aubio_peakpicker_do(o, in, out);
+ aubio_peakpicker_do(o, in, out);
+
+ del_aubio_peakpicker(o);
+ del_fvec(out);
+ del_fvec(in);
+ return 0;
+}
+
diff --git a/tests/src/pitch/test-pitch.c b/tests/src/pitch/test-pitch.c
new file mode 100644
index 0000000..1509870
--- /dev/null
+++ b/tests/src/pitch/test-pitch.c
@@ -0,0 +1,34 @@
+#include <aubio.h>
+
+int main (void)
+{
+ // 1. allocate some memory
+ uint_t n = 0; // frame counter
+ uint_t win_s = 1024; // window size
+ uint_t hop_s = win_s / 4; // hop size
+ uint_t samplerate = 44100; // samplerate
+ // create some vectors
+ fvec_t *input = new_fvec (hop_s); // input buffer
+ fvec_t *out = new_fvec (1); // output candidates
+ // create pitch object
+ aubio_pitch_t *o = new_aubio_pitch ("default", win_s, hop_s, samplerate);
+
+ // 2. do something with it
+ while (n < 100) {
+ // get `hop_s` new samples into `input`
+ // ...
+ // exectute pitch
+ aubio_pitch_do (o, input, out);
+ // do something with output candidates
+ // ...
+ n++;
+ };
+
+ // 3. clean up memory
+ del_aubio_pitch (o);
+ del_fvec (out);
+ del_fvec (input);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/pitch/test-pitchfcomb.c b/tests/src/pitch/test-pitchfcomb.c
new file mode 100644
index 0000000..718537b
--- /dev/null
+++ b/tests/src/pitch/test-pitchfcomb.c
@@ -0,0 +1,29 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t i = 0;
+ uint_t win_s = 1024; // window size
+ uint_t hop_s = win_s/4; // hop size
+ // create some vectors
+ fvec_t * in = new_fvec (hop_s); // input buffer
+ fvec_t * out = new_fvec (1); // output candidates
+ // create pitch object
+ aubio_pitchfcomb_t * o = new_aubio_pitchfcomb ( win_s, hop_s);
+
+ while (i < 10) {
+ aubio_pitchfcomb_do (o,in, out);
+ i++;
+ };
+
+ del_aubio_pitchfcomb(o);
+ del_fvec(out);
+ del_fvec(in);
+ aubio_cleanup();
+ return 0;
+}
diff --git a/tests/src/pitch/test-pitchmcomb.c b/tests/src/pitch/test-pitchmcomb.c
new file mode 100644
index 0000000..9e8483b
--- /dev/null
+++ b/tests/src/pitch/test-pitchmcomb.c
@@ -0,0 +1,32 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ uint_t hop_s = win_s/4; // hop size
+ // create some vectors
+ cvec_t * in_cvec = new_cvec (win_s); // input fftgrain
+ fvec_t * out_cands = new_fvec (1); // pitch candidate
+ // create pitch object
+ aubio_pitchmcomb_t * mcomb = new_aubio_pitchmcomb(win_s, hop_s);
+
+ while ( n-- ) {
+ aubio_pitchmcomb_do (mcomb, in_cvec, out_cands);
+ // fvec_print(out_cands);
+ };
+
+ // clean up before exiting
+ del_aubio_pitchmcomb(mcomb);
+ del_cvec(in_cvec);
+ del_fvec(out_cands);
+
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/pitch/test-pitchschmitt.c b/tests/src/pitch/test-pitchschmitt.c
new file mode 100644
index 0000000..bae7f81
--- /dev/null
+++ b/tests/src/pitch/test-pitchschmitt.c
@@ -0,0 +1,29 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ // create some vectors
+ fvec_t * in = new_fvec (win_s); // input buffer
+ fvec_t * out = new_fvec (1); // input buffer
+ // create pitch object
+ aubio_pitchschmitt_t * o = new_aubio_pitchschmitt(win_s);
+
+ while ( n-- ) {
+ aubio_pitchschmitt_do (o,in, out);
+ };
+
+ del_aubio_pitchschmitt(o);
+ del_fvec(in);
+ del_fvec(out);
+ aubio_cleanup();
+
+ return 0;
+}
+
diff --git a/tests/src/pitch/test-pitchspecacf.c b/tests/src/pitch/test-pitchspecacf.c
new file mode 100644
index 0000000..5a4fa23
--- /dev/null
+++ b/tests/src/pitch/test-pitchspecacf.c
@@ -0,0 +1,29 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ // create some vectors
+ fvec_t * in = new_fvec (win_s); // input buffer
+ fvec_t * out = new_fvec (1); // input buffer
+ // create pitch object
+ aubio_pitchspecacf_t * o = new_aubio_pitchspecacf(win_s);
+
+ while ( n-- ) {
+ aubio_pitchspecacf_do(o,in, out);
+ };
+
+ del_aubio_pitchspecacf(o);
+ del_fvec(in);
+ del_fvec(out);
+ aubio_cleanup();
+
+ return 0;
+}
+
diff --git a/tests/src/pitch/test-pitchyin.c b/tests/src/pitch/test-pitchyin.c
new file mode 100644
index 0000000..9b45c55
--- /dev/null
+++ b/tests/src/pitch/test-pitchyin.c
@@ -0,0 +1,30 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ // create some vectors
+ fvec_t * input_signal = new_fvec (win_s); // input signal
+ fvec_t * output_cands = new_fvec (1); // output candidates
+ // create pitch object
+ aubio_pitchyin_t *p = new_aubio_pitchyin (win_s);
+
+ while ( n-- ) {
+ aubio_pitchyin_do (p, input_signal, output_cands);
+ };
+
+ fvec_print(output_cands);
+
+ del_fvec(input_signal);
+ del_fvec(output_cands);
+ del_aubio_pitchyin(p);
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/pitch/test-pitchyinfft.c b/tests/src/pitch/test-pitchyinfft.c
new file mode 100644
index 0000000..ee1ece8
--- /dev/null
+++ b/tests/src/pitch/test-pitchyinfft.c
@@ -0,0 +1,31 @@
+#define AUBIO_UNSTABLE 1
+
+// this file uses the unstable aubio api, please use aubio_pitch instead
+// see src/pitch/pitch.h and tests/src/pitch/test-pitch.c
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ // create some vectors
+ fvec_t * in = new_fvec (win_s); // input buffer
+ fvec_t * out = new_fvec (1); // output candidates
+ // create pitch object
+ aubio_pitchyinfft_t *p = new_aubio_pitchyinfft(44100, win_s);
+ aubio_pitchyinfft_set_tolerance (p, 0.2);
+
+ while ( n-- ) {
+ aubio_pitchyinfft_do (p, in,out);
+ };
+
+ fvec_print(out);
+
+ del_fvec(in);
+ del_fvec(out);
+ del_aubio_pitchyinfft(p);
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-fft.c b/tests/src/spectral/test-fft.c
new file mode 100644
index 0000000..72db530
--- /dev/null
+++ b/tests/src/spectral/test-fft.c
@@ -0,0 +1,48 @@
+#include <aubio.h>
+
+int main (void)
+{
+ int return_code = 0;
+ uint_t i, n_iters = 100; // number of iterations
+ uint_t win_s = 500; // window size
+ fvec_t * in = new_fvec (win_s); // input buffer
+ cvec_t * fftgrain = new_cvec (win_s); // fft norm and phase
+ fvec_t * out = new_fvec (win_s); // output buffer
+ // create fft object
+ aubio_fft_t * fft = new_aubio_fft(win_s);
+
+ if (!fft) {
+ return_code = 1;
+ goto beach;
+ }
+
+ // fill input with some data
+ in->data[0] = 1;
+ in->data[1] = 2;
+ in->data[2] = 3;
+ in->data[3] = 4;
+ in->data[4] = 5;
+ in->data[5] = 6;
+ in->data[6] = 5;
+ in->data[7] = 6;
+ //fvec_print(in);
+
+ for (i = 0; i < n_iters; i++) {
+ // execute stft
+ aubio_fft_do (fft,in,fftgrain);
+ cvec_print(fftgrain);
+
+ // execute inverse fourier transform
+ aubio_fft_rdo(fft,fftgrain,out);
+ }
+
+ // cleam up
+ //fvec_print(out);
+ del_aubio_fft(fft);
+beach:
+ del_fvec(in);
+ del_cvec(fftgrain);
+ del_fvec(out);
+ aubio_cleanup();
+ return return_code;
+}
diff --git a/tests/src/spectral/test-filterbank.c b/tests/src/spectral/test-filterbank.c
new file mode 100644
index 0000000..543226d
--- /dev/null
+++ b/tests/src/spectral/test-filterbank.c
@@ -0,0 +1,39 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 1024; // window size
+ uint_t n_filters = 13; // number of filters
+
+ cvec_t *in_spec = new_cvec (win_s); // input vector of samples
+ fvec_t *out_filters = new_fvec (n_filters); // per-band outputs
+
+ // create filterbank object
+ aubio_filterbank_t *o = new_aubio_filterbank (n_filters, win_s);
+
+ // apply filterbank ten times
+ uint_t n = 10;
+ while (n) {
+ aubio_filterbank_do (o, in_spec, out_filters);
+ n--;
+ }
+
+ // print out filterbank coeffs
+ fmat_t *coeffs; // pointer to the coefficients
+ coeffs = aubio_filterbank_get_coeffs (o);
+ fmat_print (coeffs);
+
+ aubio_filterbank_set_coeffs (o, coeffs);
+ coeffs = aubio_filterbank_get_coeffs (o);
+ fmat_print (coeffs);
+
+ //fvec_print (out_filters);
+
+ // clean up
+ del_aubio_filterbank (o);
+ del_cvec (in_spec);
+ del_fvec (out_filters);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-filterbank_mel.c b/tests/src/spectral/test-filterbank_mel.c
new file mode 100644
index 0000000..0a0c670
--- /dev/null
+++ b/tests/src/spectral/test-filterbank_mel.c
@@ -0,0 +1,38 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t samplerate = 16000; // samplerate of signal to filter
+ uint_t win_s = 512; // fft size
+ uint_t n_filters = 40; // number of filters
+
+ cvec_t *in_spec = new_cvec (win_s); // input vector of samples
+ fvec_t *out_filters = new_fvec (n_filters); // per-band outputs
+
+ // create filterbank object
+ aubio_filterbank_t *o = new_aubio_filterbank (n_filters, win_s);
+
+ // assign Mel-frequency coefficients
+ aubio_filterbank_set_mel_coeffs_slaney (o, samplerate);
+
+ // apply filterbank ten times
+ uint_t n = 10;
+ while (n) {
+ aubio_filterbank_do (o, in_spec, out_filters);
+ n--;
+ }
+
+ // print out filter coefficients
+ fmat_t *coeffs; // pointer to the coefficients
+ coeffs = aubio_filterbank_get_coeffs (o);
+ fmat_print (coeffs);
+
+ //fvec_print (out_filters);
+
+ del_aubio_filterbank (o);
+ del_cvec (in_spec);
+ del_fvec (out_filters);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-mfcc.c b/tests/src/spectral/test-mfcc.c
new file mode 100644
index 0000000..23f8c64
--- /dev/null
+++ b/tests/src/spectral/test-mfcc.c
@@ -0,0 +1,30 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 512; // fft size
+ uint_t n_filters = 40; // number of filters
+ uint_t n_coefs = 13; // number of coefficients
+ smpl_t samplerate = 16000.; // samplerate
+ cvec_t *in = new_cvec (win_s); // input buffer
+ fvec_t *out = new_fvec (n_coefs); // output coefficients
+
+ // create mfcc object
+ aubio_mfcc_t *o = new_aubio_mfcc (win_s, n_filters, n_coefs, samplerate);
+
+ cvec_norm_set_all (in, 1.);
+ aubio_mfcc_do (o, in, out);
+ fvec_print (out);
+
+ cvec_norm_set_all (in, .5);
+ aubio_mfcc_do (o, in, out);
+ fvec_print (out);
+
+ // clean up
+ del_aubio_mfcc (o);
+ del_cvec (in);
+ del_fvec (out);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-phasevoc.c b/tests/src/spectral/test-phasevoc.c
new file mode 100644
index 0000000..e43b881
--- /dev/null
+++ b/tests/src/spectral/test-phasevoc.c
@@ -0,0 +1,47 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 6; // compute n times
+ uint_t win_s = 32; // window size
+ uint_t hop_s = win_s / 4; // hop size
+
+ fvec_t * in = new_fvec (hop_s); // input buffer
+ cvec_t * fftgrain = new_cvec (win_s); // fft norm and phase
+ fvec_t * out = new_fvec (hop_s); // output buffer
+
+ // allocate fft and other memory space
+ aubio_pvoc_t * pv = new_aubio_pvoc(win_s,hop_s);
+
+ // fill input with some data
+ fvec_set_all (in, 1.);
+ fvec_print (in);
+
+ while ( n-- ) {
+ // get some fresh input data
+ // ..
+
+ // execute phase vocoder
+ aubio_pvoc_do (pv,in,fftgrain);
+
+ // do something with fftgrain
+ // ...
+ cvec_print (fftgrain);
+
+ // optionnaly rebuild the signa
+ aubio_pvoc_rdo(pv,fftgrain,out);
+
+ // and do something with the result
+ // ...
+ fvec_print (out);
+ }
+
+ // clean up
+ del_fvec(in);
+ del_cvec(fftgrain);
+ del_fvec(out);
+ del_aubio_pvoc(pv);
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-specdesc.c b/tests/src/spectral/test-specdesc.c
new file mode 100644
index 0000000..f890e59
--- /dev/null
+++ b/tests/src/spectral/test-specdesc.c
@@ -0,0 +1,44 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 1024; // window size
+ cvec_t *in = new_cvec (win_s); // input buffer
+ fvec_t *out = new_fvec (1); // output spectral descriptor
+
+ aubio_specdesc_t *o;
+
+ o = new_aubio_specdesc ("energy", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("energy", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("hfc", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("complex", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("phase", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("kl", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ o = new_aubio_specdesc ("mkl", win_s);
+ aubio_specdesc_do (o, in, out);
+ del_aubio_specdesc (o);
+
+ del_cvec (in);
+ del_fvec (out);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/spectral/test-tss.c b/tests/src/spectral/test-tss.c
new file mode 100644
index 0000000..0e18b20
--- /dev/null
+++ b/tests/src/spectral/test-tss.c
@@ -0,0 +1,52 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 10; // compute n times
+ uint_t win_s = 1024; // window size
+ uint_t hop_s = 256; // hop size
+
+ // create some vectors
+ fvec_t * in = new_fvec (hop_s); // input buffer
+ cvec_t * fftgrain = new_cvec (win_s); // fft norm and phase
+ cvec_t * cstead = new_cvec (win_s); // fft norm and phase
+ cvec_t * ctrans = new_cvec (win_s); // fft norm and phase
+ fvec_t * stead = new_fvec (hop_s); // output buffer
+ fvec_t * trans = new_fvec (hop_s); // output buffer
+
+ // create phase vocoder for analysis of input signal
+ aubio_pvoc_t * pv = new_aubio_pvoc (win_s,hop_s);
+ // create transient/steady-state separation object
+ aubio_tss_t * tss = new_aubio_tss(win_s,hop_s);
+ // create phase vocoder objects for synthesis of output signals
+ aubio_pvoc_t * pvt = new_aubio_pvoc(win_s,hop_s);
+ aubio_pvoc_t * pvs = new_aubio_pvoc(win_s,hop_s);
+
+ /* execute stft */
+ while ( n-- ) {
+ // fftgrain = pv(in)
+ aubio_pvoc_do (pv, in, fftgrain);
+ // ctrans, cstead = tss (fftgrain)
+ aubio_tss_do (tss, fftgrain, ctrans, cstead);
+ // stead = pvt_inverse (cstead)
+ // trans = pvt_inverse (ctrans)
+ aubio_pvoc_rdo (pvt, cstead, stead);
+ aubio_pvoc_rdo (pvs, ctrans, trans);
+ }
+
+ del_aubio_pvoc(pv);
+ del_aubio_pvoc(pvt);
+ del_aubio_pvoc(pvs);
+ del_aubio_tss(tss);
+
+ del_fvec(in);
+ del_cvec(fftgrain);
+ del_cvec(cstead);
+ del_cvec(ctrans);
+ del_fvec(stead);
+ del_fvec(trans);
+
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/synth/test-sampler.c b/tests/src/synth/test-sampler.c
new file mode 100644
index 0000000..0f3bfa7
--- /dev/null
+++ b/tests/src/synth/test-sampler.c
@@ -0,0 +1,59 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 4) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <input_path> <output_path> <sample_path> [samplerate]\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 0; // default is the samplerate of input_path
+ uint_t hop_size = 256;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+ char_t *sample_path = argv[3];
+ if ( argc == 5 ) samplerate = atoi(argv[4]);
+
+ fvec_t *vec = new_fvec(hop_size);
+ aubio_source_t *source = new_aubio_source(source_path, samplerate, hop_size);
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(source);
+ aubio_sink_t *sink = new_aubio_sink(sink_path, samplerate);
+
+ aubio_sampler_t * sampler = new_aubio_sampler (samplerate, hop_size);
+
+ aubio_sampler_load (sampler, sample_path);
+
+ do {
+ aubio_source_do(source, vec, &read);
+ if (n_frames / hop_size == 10) {
+ aubio_sampler_play ( sampler );
+ }
+ if (n_frames / hop_size == 40) {
+ aubio_sampler_play ( sampler );
+ }
+ if (n_frames / hop_size == 70) {
+ aubio_sampler_play ( sampler );
+ }
+ if (n_frames > 10.0 * samplerate) {
+ aubio_sampler_stop ( sampler );
+ }
+ aubio_sampler_do (sampler, vec, vec);
+ aubio_sink_do(sink, vec, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ del_aubio_sampler(sampler);
+ del_aubio_source(source);
+ del_aubio_sink(sink);
+ del_fvec(vec);
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/synth/test-wavetable.c b/tests/src/synth/test-wavetable.c
new file mode 100644
index 0000000..f569277
--- /dev/null
+++ b/tests/src/synth/test-wavetable.c
@@ -0,0 +1,68 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <output_path> [freq] [samplerate]\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 44100; // default is the samplerate of input_path
+ uint_t hop_size = 256;
+ smpl_t freq = 440.;
+
+ char_t *sink_path = argv[1];
+ if ( argc == 4 ) samplerate = atoi(argv[3]);
+ if ( argc == 3 ) freq = atof(argv[2]);
+
+ fvec_t *vec = new_fvec(hop_size);
+ aubio_sink_t *sink = new_aubio_sink(sink_path, samplerate);
+
+ aubio_wavetable_t * wavetable = new_aubio_wavetable (samplerate, hop_size);
+
+ // 2 seconds duration, in samples
+ uint_t duration = 2 * samplerate;
+
+ uint_t n_frames = 0;
+ uint_t write = 0;
+
+ aubio_wavetable_play (wavetable);
+ aubio_wavetable_set_freq ( wavetable, freq );
+
+ uint_t region = 0;
+
+ do {
+ if ( n_frames > duration / 3 && region < 1) {
+ aubio_wavetable_stop (wavetable);
+ region++;
+ }
+ if ( n_frames > 2 * duration / 3 && region < 2) {
+ aubio_wavetable_play (wavetable);
+ aubio_wavetable_set_freq ( wavetable, freq / 2.);
+ region++;
+ }
+ if (duration - n_frames < hop_size * 2 ) {
+ aubio_wavetable_stop( wavetable );
+ }
+ if (duration - n_frames < hop_size ) {
+ write = duration - n_frames;
+ } else {
+ write = hop_size;
+ }
+ aubio_wavetable_do (wavetable, vec, vec);
+ aubio_sink_do(sink, vec, write);
+ n_frames += hop_size;
+ } while ( n_frames <= duration );
+
+ del_aubio_wavetable (wavetable);
+ del_aubio_sink(sink);
+ del_fvec(vec);
+ aubio_cleanup();
+
+ return 0;
+}
diff --git a/tests/src/tempo/test-beattracking.c b/tests/src/tempo/test-beattracking.c
new file mode 100644
index 0000000..323e493
--- /dev/null
+++ b/tests/src/tempo/test-beattracking.c
@@ -0,0 +1,40 @@
+#define AUBIO_UNSTABLE 1
+
+#include <aubio.h>
+#include <stdio.h>
+
+int main (void)
+{
+ uint_t i = 0;
+ uint_t win_s = 1024; // window size
+ fvec_t * in = new_fvec (win_s); // input buffer
+ fvec_t * out = new_fvec (win_s / 4); // output beat position
+
+ // create beattracking object
+ aubio_beattracking_t * tempo = new_aubio_beattracking(win_s, 256, 44100);
+
+ smpl_t bpm, confidence;
+
+ while (i < 10) {
+ // put some fresh data in feature vector
+ // ...
+
+ aubio_beattracking_do(tempo,in,out);
+ // do something with the beats
+ // ...
+
+ // get bpm and confidence
+ bpm = aubio_beattracking_get_bpm(tempo);
+ confidence = aubio_beattracking_get_confidence(tempo);
+ fprintf(stderr, "found bpm %f with confidence %f\n", bpm, confidence);
+ i++;
+ };
+
+ del_aubio_beattracking(tempo);
+ del_fvec(in);
+ del_fvec(out);
+ aubio_cleanup();
+
+ return 0;
+}
+
diff --git a/tests/src/tempo/test-tempo.c b/tests/src/tempo/test-tempo.c
new file mode 100644
index 0000000..7a87832
--- /dev/null
+++ b/tests/src/tempo/test-tempo.c
@@ -0,0 +1,63 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ uint_t err = 0;
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("read a wave file as a mono vector\n");
+ PRINT_MSG("usage: %s <source_path> [samplerate] [win_size] [hop_size]\n", argv[0]);
+ return err;
+ }
+ uint_t samplerate = 0;
+ if ( argc >= 3 ) samplerate = atoi(argv[2]);
+ uint_t win_size = 1024; // window size
+ if ( argc >= 4 ) win_size = atoi(argv[3]);
+ uint_t hop_size = win_size / 4;
+ if ( argc >= 5 ) hop_size = atoi(argv[4]);
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ aubio_source_t * source = new_aubio_source(source_path, samplerate, hop_size);
+ if (!source) { err = 1; goto beach; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(source);
+
+ // create some vectors
+ fvec_t * in = new_fvec (hop_size); // input audio buffer
+ fvec_t * out = new_fvec (1); // output position
+
+ // create tempo object
+ aubio_tempo_t * o = new_aubio_tempo("default", win_size, hop_size, samplerate);
+
+ do {
+ // put some fresh data in input vector
+ aubio_source_do(source, in, &read);
+ // execute tempo
+ aubio_tempo_do(o,in,out);
+ // do something with the beats
+ if (out->data[0] != 0) {
+ PRINT_MSG("beat at %.3fms, %.3fs, frame %d, %.2fbpm with confidence %.2f\n",
+ aubio_tempo_get_last_ms(o), aubio_tempo_get_last_s(o),
+ aubio_tempo_get_last(o), aubio_tempo_get_bpm(o), aubio_tempo_get_confidence(o));
+ }
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %.2fs, %d frames at %dHz (%d blocks) from %s\n",
+ n_frames * 1. / samplerate,
+ n_frames, samplerate,
+ n_frames / hop_size, source_path);
+
+ // clean up memory
+ del_aubio_tempo(o);
+ del_fvec(in);
+ del_fvec(out);
+ del_aubio_source(source);
+beach:
+ aubio_cleanup();
+
+ return err;
+}
diff --git a/tests/src/temporal/test-a_weighting.c b/tests/src/temporal/test-a_weighting.c
new file mode 100644
index 0000000..4030a0d
--- /dev/null
+++ b/tests/src/temporal/test-a_weighting.c
@@ -0,0 +1,43 @@
+#include <aubio.h>
+
+int main (void)
+{
+
+ aubio_filter_t * f;
+
+ uint_t rates[] = { 8000, 16000, 22050, 44100, 96000, 192000};
+ uint_t nrates = 6;
+ uint_t samplerate, i = 0;
+
+ for ( samplerate = rates[i]; i < nrates ; i++ ) {
+ f = new_aubio_filter_a_weighting (samplerate);
+ del_aubio_filter (f);
+
+ f = new_aubio_filter (7);
+ aubio_filter_set_a_weighting (f, samplerate);
+ del_aubio_filter (f);
+ }
+
+ // samplerate unknown
+ f = new_aubio_filter_a_weighting (4200);
+ if (!f) {
+ //PRINT_MSG ("failed creating A-weighting filter with samplerate=4200Hz\n");
+ }
+
+ // order to small
+ f = new_aubio_filter (2);
+ if (aubio_filter_set_a_weighting (f, samplerate) != 0) {
+ //PRINT_MSG ("failed setting filter to A-weighting\n");
+ }
+ del_aubio_filter (f);
+
+ // order to big
+ f = new_aubio_filter (12);
+ if (aubio_filter_set_a_weighting (f, samplerate) != 0) {
+ //PRINT_MSG ("failed setting filter to A-weighting\n");
+ }
+ del_aubio_filter (f);
+
+ return 0;
+}
+
diff --git a/tests/src/temporal/test-biquad.c b/tests/src/temporal/test-biquad.c
new file mode 100644
index 0000000..8317b06
--- /dev/null
+++ b/tests/src/temporal/test-biquad.c
@@ -0,0 +1,32 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 64; // window size
+
+ // create biquad filter with `b0`, `b1`, `b2`, `a1`, `a2`
+ aubio_filter_t * o = new_aubio_filter_biquad(0.3,0.2,0.1,0.2,0.3);
+
+ fvec_t * in_vec = new_fvec (win_s); // input buffer
+ fvec_t * tmp_vec = new_fvec (win_s); // temporary buffer
+ fvec_t * out_vec = new_fvec (win_s); // output buffer
+
+ uint_t times = 100;
+ while ( times-- ) {
+ // copy to out, then filter out
+ aubio_filter_do_outplace(o, in_vec, out_vec);
+ // in-place filtering
+ aubio_filter_do(o, in_vec);
+ // in-place filtering
+ aubio_filter_do_filtfilt(o, in_vec, out_vec);
+ fvec_print(in_vec);
+ }
+
+ // memory clean-up, one for each new
+ del_aubio_filter(o);
+ del_fvec(in_vec);
+ del_fvec(tmp_vec);
+ del_fvec(out_vec);
+
+ return 0;
+}
diff --git a/tests/src/temporal/test-c_weighting.c b/tests/src/temporal/test-c_weighting.c
new file mode 100644
index 0000000..84380c9
--- /dev/null
+++ b/tests/src/temporal/test-c_weighting.c
@@ -0,0 +1,42 @@
+#include <aubio.h>
+
+int main (void)
+{
+ aubio_filter_t * f;
+
+ uint_t rates[] = { 8000, 16000, 22050, 44100, 96000, 192000};
+ uint_t nrates = 6;
+ uint_t samplerate, i = 0;
+
+ for ( samplerate = rates[i]; i < nrates ; i++ ) {
+ f = new_aubio_filter_c_weighting (samplerate);
+ del_aubio_filter (f);
+
+ f = new_aubio_filter (5);
+ aubio_filter_set_c_weighting (f, samplerate);
+ del_aubio_filter (f);
+ }
+
+ // samplerate unknown
+ f = new_aubio_filter_c_weighting (4200);
+ if (!f) {
+ //PRINT_WRN ("failed creating C-weighting filter with samplerate=4200Hz");
+ }
+
+ // order to small
+ f = new_aubio_filter (2);
+ if (aubio_filter_set_c_weighting (f, samplerate) != 0) {
+ //PRINT_WRN ("failed setting filter to C-weighting");
+ }
+ del_aubio_filter (f);
+
+ // order to big
+ f = new_aubio_filter (12);
+ if (aubio_filter_set_c_weighting (f, samplerate) != 0) {
+ //PRINT_WRN ("failed setting filter to C-weighting");
+ }
+ del_aubio_filter (f);
+
+ return 0;
+}
+
diff --git a/tests/src/temporal/test-filter.c b/tests/src/temporal/test-filter.c
new file mode 100644
index 0000000..260d81b
--- /dev/null
+++ b/tests/src/temporal/test-filter.c
@@ -0,0 +1,35 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 16; // window size
+ uint_t impulse_at = win_s / 2;
+ fvec_t *in = new_fvec (win_s); // input buffer
+ fvec_t *out = new_fvec (win_s); // input buffer
+
+ aubio_filter_t *o = new_aubio_filter_c_weighting (44100);
+ in->data[impulse_at] = 0.5;
+ fvec_print (in);
+ aubio_filter_do (o, in);
+ fvec_print (in);
+ del_aubio_filter (o);
+
+ o = new_aubio_filter_a_weighting (32000);
+ in->data[impulse_at] = 0.5;
+ fvec_print (in);
+ aubio_filter_do_outplace (o, in, out);
+ fvec_print (out);
+
+ aubio_filter_set_a_weighting (o, 32000);
+ in->data[impulse_at] = 0.5;
+ fvec_print (in);
+ aubio_filter_do_filtfilt (o, in, out);
+ fvec_print (out);
+
+ del_fvec (in);
+ del_fvec (out);
+ del_aubio_filter (o);
+ aubio_cleanup ();
+
+ return 0;
+}
diff --git a/tests/src/temporal/test-resampler.c b/tests/src/temporal/test-resampler.c
new file mode 100644
index 0000000..ee818e1
--- /dev/null
+++ b/tests/src/temporal/test-resampler.c
@@ -0,0 +1,22 @@
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t win_s = 1024; // window size
+ smpl_t ratio = 0.5;
+ fvec_t *in = new_fvec (win_s); // input buffer
+ fvec_t *out = new_fvec ((uint_t) (win_s * ratio)); // output buffer
+ aubio_resampler_t *o = new_aubio_resampler (0.5, 0);
+ uint_t i = 0;
+
+ while (i < 10) {
+ aubio_resampler_do (o, in, out);
+ i++;
+ };
+
+ del_aubio_resampler (o);
+ del_fvec (in);
+ del_fvec (out);
+
+ return 0;
+}
diff --git a/tests/src/test-cvec.c b/tests/src/test-cvec.c
new file mode 100644
index 0000000..c1e6bca
--- /dev/null
+++ b/tests/src/test-cvec.c
@@ -0,0 +1,48 @@
+#include "aubio.h"
+#include "utils_tests.h"
+
+int main (void)
+{
+ uint_t i, window_size = 16; // window size
+ cvec_t * complex_vector = new_cvec (window_size); // input buffer
+ uint_t rand_times = 4;
+
+ utils_init_random();
+
+ while (rand_times -- ) {
+ // fill with random phas and norm
+ for ( i = 0; i < complex_vector->length; i++ ) {
+ complex_vector->norm[i] = ( 2. / RAND_MAX * random() - 1. );
+ complex_vector->phas[i] = ( 2. / RAND_MAX * random() - 1. ) * M_PI;
+ }
+ // print the vector
+ cvec_print(complex_vector);
+ }
+
+ // set all vector elements to `0`
+ cvec_norm_zeros(complex_vector);
+ for ( i = 0; i < complex_vector->length; i++ ) {
+ assert( complex_vector->norm[i] == 0. );
+ // assert( complex_vector->phas[i] == 0 );
+ }
+ cvec_print(complex_vector);
+
+ // set all vector elements to `1`
+ cvec_norm_ones(complex_vector);
+ for ( i = 0; i < complex_vector->length; i++ ) {
+ assert( complex_vector->norm[i] == 1. );
+ // assert( complex_vector->phas[i] == 0 );
+ }
+ cvec_print(complex_vector);
+
+ cvec_zeros(complex_vector);
+ cvec_phas_zeros(complex_vector);
+ cvec_norm_zeros(complex_vector);
+ cvec_norm_ones(complex_vector);
+ cvec_phas_ones(complex_vector);
+ cvec_copy(complex_vector, complex_vector);
+
+ // destroy it
+ del_cvec(complex_vector);
+ return 0;
+}
diff --git a/tests/src/test-delnull.c b/tests/src/test-delnull.c
new file mode 100644
index 0000000..bb24509
--- /dev/null
+++ b/tests/src/test-delnull.c
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include "aubio.h"
+
+// When creating an aubio object, the user should check whether the object is
+// set NULL, indicating the creation failed and the object was not allocated.
+
+int main (void)
+{
+ uint_t return_code = 0;
+ fvec_t *f = new_fvec(-12);
+ cvec_t *c = new_cvec(-12);
+ lvec_t *l = new_lvec(-12);
+ aubio_fft_t *fft = new_aubio_fft(-12);
+ if (f != NULL) {
+ return_code = 1;
+ } else if (c != NULL) {
+ return_code = 2;
+ } else if (l != NULL) {
+ return_code = 3;
+ } else if (fft != NULL) {
+ return_code = 3;
+ }
+ return return_code;
+}
diff --git a/tests/src/test-fmat.c b/tests/src/test-fmat.c
new file mode 100644
index 0000000..218c027
--- /dev/null
+++ b/tests/src/test-fmat.c
@@ -0,0 +1,30 @@
+#include "aubio.h"
+#include "utils_tests.h"
+
+// create a new matrix and fill it with i * 1. + j * .1, where i is the row,
+// and j the column.
+
+int main (void)
+{
+ uint_t height = 3, length = 9, i, j;
+ // create fmat_t object
+ fmat_t * mat = new_fmat (height, length);
+ for ( i = 0; i < mat->height; i++ ) {
+ for ( j = 0; j < mat->length; j++ ) {
+ // all elements are already initialized to 0.
+ assert(mat->data[i][j] == 0);
+ // setting element of row i, column j
+ mat->data[i][j] = i * 1. + j *.1;
+ }
+ }
+ fvec_t channel_onstack;
+ fvec_t *channel = &channel_onstack;
+ fmat_get_channel(mat, 1, channel);
+ fvec_print (channel);
+ // print out matrix
+ fmat_print(mat);
+ // destroy it
+ del_fmat(mat);
+ return 0;
+}
+
diff --git a/tests/src/test-fvec.c b/tests/src/test-fvec.c
new file mode 100644
index 0000000..c53e396
--- /dev/null
+++ b/tests/src/test-fvec.c
@@ -0,0 +1,43 @@
+#include "aubio.h"
+#include "utils_tests.h"
+
+int main (void)
+{
+ uint_t vec_size = 10, i;
+ fvec_t * vec = new_fvec (vec_size);
+
+ // vec->length matches requested size
+ assert(vec->length == vec_size);
+
+ // all elements are initialized to `0.`
+ for ( i = 0; i < vec->length; i++ ) {
+ assert(vec->data[i] == 0.);
+ }
+
+ // all elements can be set to `0.`
+ fvec_zeros(vec);
+ for ( i = 0; i < vec->length; i++ ) {
+ assert(vec->data[i] == 0.);
+ }
+ fvec_print(vec);
+
+ // all elements can be set to `1.`
+ fvec_ones(vec);
+ for ( i = 0; i < vec->length; i++ ) {
+ assert(vec->data[i] == 1.);
+ }
+ fvec_print(vec);
+
+ // each element can be accessed directly
+ for ( i = 0; i < vec->length; i++ ) {
+ vec->data[i] = i;
+ assert(vec->data[i] == i);
+ }
+ fvec_print(vec);
+
+ // now destroys the vector
+ del_fvec(vec);
+
+ return 0;
+}
+
diff --git a/tests/src/test-lvec.c b/tests/src/test-lvec.c
new file mode 100644
index 0000000..17b5fc6
--- /dev/null
+++ b/tests/src/test-lvec.c
@@ -0,0 +1,18 @@
+#include "aubio.h"
+#include "utils_tests.h"
+
+int main (void)
+{
+ uint_t win_s = 32; // window size
+ lvec_t * sp = new_lvec (win_s); // input buffer
+ lvec_set_sample (sp, 2./3., 0);
+ PRINT_MSG(AUBIO_LSMP_FMT "\n", lvec_get_sample (sp, 0));
+ lvec_print (sp);
+ lvec_ones (sp);
+ lvec_print (sp);
+ lvec_set_all (sp, 3./5.);
+ lvec_print (sp);
+ del_lvec(sp);
+ return 0;
+}
+
diff --git a/tests/src/test-mathutils-window.c b/tests/src/test-mathutils-window.c
new file mode 100644
index 0000000..4b45e7f
--- /dev/null
+++ b/tests/src/test-mathutils-window.c
@@ -0,0 +1,31 @@
+#include "aubio.h"
+#include "utils_tests.h"
+
+int main (void)
+{
+ uint_t length = 0;
+ uint_t n_length = 4, n_types = 10, i, t;
+ uint_t lengths[4] = { 8, 10, 15, 16 };
+ char *method = "default";
+ char *window_types[10] = { "default",
+ "rectangle", "hamming", "hanning", "hanningz",
+ "blackman", "blackman_harris", "gaussian", "welch", "parzen"};
+
+ for ( t = 0; t < n_types; t ++ ) {
+ for ( i = 0; i < n_length; i++)
+ {
+ length = lengths[i];
+ method = window_types[t];
+
+ fvec_t * window = new_aubio_window(method, length);
+
+ fvec_set_window(window, method);
+ fprintf(stdout, "length: %d, method: %s, window:, ", length, method);
+ fvec_print(window);
+
+ del_fvec(window);
+ }
+ }
+ return 0;
+}
+
diff --git a/tests/src/test-mathutils.c b/tests/src/test-mathutils.c
new file mode 100644
index 0000000..0a6eedf
--- /dev/null
+++ b/tests/src/test-mathutils.c
@@ -0,0 +1,120 @@
+#define AUBIO_UNSTABLE 1
+#include "aubio.h"
+#include "utils_tests.h"
+
+int test_next_power_of_two (void);
+int test_miditofreq (void);
+int test_freqtomidi (void);
+int test_aubio_window (void);
+
+int test_next_power_of_two (void)
+{
+ uint_t a, b;
+ a = 15; b = aubio_next_power_of_two(a); assert(b == 16);
+ fprintf(stdout, "aubio_next_power_of_two(%d) = %d\n", a, b);
+
+ a = 17; b = aubio_next_power_of_two(a); assert(b == 32);
+ fprintf(stdout, "aubio_next_power_of_two(%d) = %d\n", a, b);
+
+ a = 31; b = aubio_next_power_of_two(a); assert(b == 32);
+ fprintf(stdout, "aubio_next_power_of_two(%d) = %d\n", a, b);
+
+ a = 32; b = aubio_next_power_of_two(a); assert(b == 32);
+ fprintf(stdout, "aubio_next_power_of_two(%d) = %d\n", a, b);
+
+ a = 33; b = aubio_next_power_of_two(a); assert(b == 64);
+ fprintf(stdout, "aubio_next_power_of_two(%d) = %d\n", a, b);
+
+ return 0;
+}
+
+int test_miditofreq (void)
+{
+ smpl_t a, b;
+ fprintf(stdout, "b = aubio_miditofreq(a): [");
+ for ( a = -123.; a < 400.; a += 20. ) {
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ }
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = -69.5;
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = -169.5;
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = 140.;
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = 0;
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = 8.2e10;
+ b = aubio_miditofreq(a);
+ fprintf(stdout, "(%.2f, %.2f), ", a, b);
+ a = -5.e10;
+ fprintf(stdout, "(%.2f, %.2f)", a, b);
+ fprintf(stdout, "]\n");
+ return 0;
+}
+
+int test_freqtomidi (void)
+{
+ smpl_t midi, freq;
+ fprintf(stdout, "b = aubio_freqtomidi(a): [");
+ for ( freq = 0.; freq < 30000.; freq += 440. ) {
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ }
+ freq = 69.5;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = -69.5;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = -169.5;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = 140.;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = 0;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = 8.2e10;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f), ", freq, midi);
+ freq = -5.;
+ midi = aubio_freqtomidi(freq);
+ fprintf(stdout, "(%.2f, %.2f)]\n", freq, midi);
+ return 0;
+}
+
+int test_aubio_window (void)
+{
+ uint_t window_size = 16;
+ fvec_t * window = new_aubio_window("default", window_size);
+ del_fvec(window);
+
+ window = new_fvec(window_size);
+ fvec_set_window(window, "rectangle");
+ fvec_print(window);
+
+ window_size /= 2.;
+ window = new_aubio_window("triangle", window_size);
+ fvec_print(window);
+ del_fvec(window);
+
+ window = new_aubio_window("rectangle", 16);
+ del_fvec (window);
+ return 0;
+}
+
+int main (void)
+{
+ test_next_power_of_two();
+ test_miditofreq();
+ test_freqtomidi();
+ return 0;
+}
diff --git a/tests/src/utils/test-hist.c b/tests/src/utils/test-hist.c
new file mode 100644
index 0000000..ee3bc9b
--- /dev/null
+++ b/tests/src/utils/test-hist.c
@@ -0,0 +1,30 @@
+#define AUBIO_UNSTABLE 1
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t length;
+ for (length = 1; length < 10; length ++ ) {
+ aubio_hist_t *o = new_aubio_hist(0, 1, length);
+ fvec_t *t = new_aubio_window("hanning", length);
+ aubio_hist_do(o,t);
+ fvec_print(t);
+ aubio_hist_do_notnull(o,t);
+ fvec_print(t);
+ aubio_hist_dyn_notnull(o,t);
+ fvec_print(t);
+ del_fvec(t);
+ t = new_aubio_window("hanningz", length);
+ aubio_hist_do(o,t);
+ fvec_print(t);
+ aubio_hist_do_notnull(o,t);
+ fvec_print(t);
+ aubio_hist_dyn_notnull(o,t);
+ fvec_print(t);
+ del_aubio_hist(o);
+ del_fvec(t);
+ }
+ return 0;
+}
+
diff --git a/tests/src/utils/test-parameter.c b/tests/src/utils/test-parameter.c
new file mode 100644
index 0000000..073d9c3
--- /dev/null
+++ b/tests/src/utils/test-parameter.c
@@ -0,0 +1,70 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+void get_some_steps ( aubio_parameter_t * param );
+
+void get_some_steps ( aubio_parameter_t * param )
+{
+ uint_t i = 0;
+ uint_t steps = aubio_parameter_get_steps ( param );
+
+ PRINT_MSG("next steps (%d) values:", steps );
+ for (i = 0; i < steps; i ++ ) {
+ PRINT_MSG(" %f", aubio_parameter_get_next_value (param) );
+ }
+ PRINT_MSG("\n");
+
+ PRINT_MSG("next 3 values:");
+ for (i = 0; i < 3; i ++ ) {
+ PRINT_MSG(" %f", aubio_parameter_get_next_value (param) );
+ }
+ PRINT_MSG("\n");
+
+}
+
+int main (void)
+{
+ smpl_t max_value = 100.;
+ smpl_t min_value = 0.;
+ uint_t steps = 10;
+
+ aubio_parameter_t * param = new_aubio_parameter ( min_value, max_value, steps );
+
+ PRINT_MSG("initial value: %f, steps: %d\n", aubio_parameter_get_current_value
+ (param) , aubio_parameter_get_steps (param) );
+
+ PRINT_MSG("target: max_value / 2\n");
+ aubio_parameter_set_target_value ( param, max_value );
+ get_some_steps ( param );
+
+ PRINT_MSG("target: max_value / 2\n");
+ aubio_parameter_set_target_value ( param, max_value / 2 );
+ get_some_steps ( param );
+
+ PRINT_MSG("target: max_value * 2\n");
+ aubio_parameter_set_target_value ( param, max_value * 2);
+ get_some_steps ( param );
+
+ PRINT_MSG("steps: 1, target: -max\n");
+ aubio_parameter_set_steps ( param, 1);
+ aubio_parameter_set_target_value ( param, - max_value);
+ get_some_steps ( param );
+
+ PRINT_MSG("steps: 30, current value: max, target: min\n");
+ aubio_parameter_set_current_value ( param, max_value );
+ aubio_parameter_set_target_value ( param, min_value );
+ aubio_parameter_set_steps ( param, 7 );
+ get_some_steps ( param );
+
+ PRINT_MSG("steps: 30, max value: max * 2, min value: -max, current value: -max, target: max\n");
+ aubio_parameter_set_min_value ( param, - max_value );
+ aubio_parameter_set_max_value ( param, 2. * max_value );
+ aubio_parameter_set_current_value ( param, - max_value );
+ aubio_parameter_set_target_value ( param, max_value );
+ aubio_parameter_set_steps ( param, 10 );
+ get_some_steps ( param );
+
+ del_aubio_parameter (param);
+
+ return 0;
+}
diff --git a/tests/src/utils/test-scale.c b/tests/src/utils/test-scale.c
new file mode 100644
index 0000000..df1f0d8
--- /dev/null
+++ b/tests/src/utils/test-scale.c
@@ -0,0 +1,22 @@
+#define AUBIO_UNSTABLE 1
+
+#include <aubio.h>
+
+int main (void)
+{
+ uint_t n = 0;
+ uint_t win_s = 1024; // window size
+ fvec_t * in = new_fvec (win_s); // input buffer
+ aubio_scale_t * o = new_aubio_scale(0,1,2,3);
+ aubio_scale_set_limits (o,0,1,2,3);
+
+ while (n < 1000) {
+ aubio_scale_do(o,in);
+ n++;
+ };
+
+ del_aubio_scale(o);
+ del_fvec(in);
+
+ return 0;
+}
diff --git a/tests/utils_tests.h b/tests/utils_tests.h
new file mode 100644
index 0000000..97d5297
--- /dev/null
+++ b/tests/utils_tests.h
@@ -0,0 +1,53 @@
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include "config.h"
+
+#ifdef HAVE_C99_VARARGS_MACROS
+#define PRINT_ERR(...) fprintf(stderr, "AUBIO-TESTS ERROR: " __VA_ARGS__)
+#define PRINT_MSG(...) fprintf(stdout, __VA_ARGS__)
+#define PRINT_DBG(...) fprintf(stderr, __VA_ARGS__)
+#define PRINT_WRN(...) fprintf(stderr, "AUBIO-TESTS WARNING: " __VA_ARGS__)
+#else
+#define PRINT_ERR(format, args...) fprintf(stderr, "AUBIO-TESTS ERROR: " format , ##args)
+#define PRINT_MSG(format, args...) fprintf(stdout, format , ##args)
+#define PRINT_DBG(format, args...) fprintf(stderr, format , ##args)
+#define PRINT_WRN(format, args...) fprintf(stderr, "AUBIO-TESTS WARNING: " format, ##args)
+#endif
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+#ifndef RAND_MAX
+#define RAND_MAX 32767
+#endif
+
+// are we on windows ? or are we using -std=c99 ?
+#if defined(HAVE_WIN_HACKS) || defined(__STRICT_ANSI__)
+// http://en.wikipedia.org/wiki/Linear_congruential_generator
+// no srandom/random on win32
+
+uint_t srandom_seed = 1029;
+
+void srandom(uint_t new_seed) {
+ srandom_seed = new_seed;
+}
+
+uint_t random(void) {
+ srandom_seed = 1664525 * srandom_seed + 1013904223;
+ return srandom_seed;
+}
+#endif
+
+void utils_init_random (void);
+
+void utils_init_random (void) {
+ time_t now = time(0);
+ struct tm *tm_struct = localtime(&now);
+ int seed = tm_struct->tm_sec;
+ //PRINT_WRN("current seed: %d\n", seed);
+ srandom (seed);
+}
diff --git a/tests/wscript_build b/tests/wscript_build
new file mode 100644
index 0000000..45e83b8
--- /dev/null
+++ b/tests/wscript_build
@@ -0,0 +1,19 @@
+# vim:set syntax=python:
+
+import os.path
+
+uselib = ['aubio']
+
+includes = ['../src', '.']
+programs_sources = ctx.path.ant_glob('src/**/*.c')
+
+for source_file in programs_sources:
+ target = os.path.basename(os.path.splitext(str(source_file))[0])
+ bld(features = 'c cprogram test',
+ source = source_file,
+ target = target,
+ includes = includes,
+ use = uselib,
+ install_path = None,
+ defines = 'AUBIO_UNSTABLE_API=1',
+ )
diff --git a/waf b/waf
new file mode 100755
index 0000000..c5bd07d
--- /dev/null
+++ b/waf
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+# encoding: ISO8859-1
+# Thomas Nagy, 2005-2016
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys, inspect
+
+VERSION="1.8.22"
+REVISION="596301b77b6d6efab064109ecd67cd79"
+GIT="129ec0cfe7dc9d2880e085fab2a449c651ac8285"
+INSTALL=''
+C1='#.'
+C2='#,'
+C3='#&'
+cwd = os.getcwd()
+join = os.path.join
+
+
+WAF='waf'
+def b(x):
+ return x
+if sys.hexversion>0x300000f:
+ WAF='waf3'
+ def b(x):
+ return x.encode()
+
+def err(m):
+ print(('\033[91mError: %s\033[0m' % m))
+ sys.exit(1)
+
+def unpack_wafdir(dir, src):
+ f = open(src,'rb')
+ c = 'corrupt archive (%d)'
+ while 1:
+ line = f.readline()
+ if not line: err('run waf-light from a folder containing waflib')
+ if line == b('#==>\n'):
+ txt = f.readline()
+ if not txt: err(c % 1)
+ if f.readline() != b('#<==\n'): err(c % 2)
+ break
+ if not txt: err(c % 3)
+ txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00'))
+
+ import shutil, tarfile
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ try:
+ for x in ('Tools', 'extras'):
+ os.makedirs(join(dir, 'waflib', x))
+ except OSError:
+ err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)
+
+ os.chdir(dir)
+ tmp = 't.bz2'
+ t = open(tmp,'wb')
+ try: t.write(txt)
+ finally: t.close()
+
+ try:
+ t = tarfile.open(tmp)
+ except:
+ try:
+ os.system('bunzip2 t.bz2')
+ t = tarfile.open('t')
+ tmp = 't'
+ except:
+ os.chdir(cwd)
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ err("Waf cannot be unpacked, check that bzip2 support is present")
+
+ try:
+ for x in t: t.extract(x)
+ finally:
+ t.close()
+
+ for x in ('Tools', 'extras'):
+ os.chmod(join('waflib',x), 493)
+
+ if sys.hexversion<0x300000f:
+ sys.path = [join(dir, 'waflib')] + sys.path
+ import fixpy2
+ fixpy2.fixdir(dir)
+
+ os.remove(tmp)
+ os.chdir(cwd)
+
+ try: dir = unicode(dir, 'mbcs')
+ except: pass
+ try:
+ from ctypes import windll
+ windll.kernel32.SetFileAttributesW(dir, 2)
+ except:
+ pass
+
+def test(dir):
+ try:
+ os.stat(join(dir, 'waflib'))
+ return os.path.abspath(dir)
+ except OSError:
+ pass
+
+def find_lib():
+ src = os.path.abspath(inspect.getfile(inspect.getmodule(err)))
+ base, name = os.path.split(src)
+
+ #devs use $WAFDIR
+ w=test(os.environ.get('WAFDIR', ''))
+ if w: return w
+
+ #waf-light
+ if name.endswith('waf-light'):
+ w = test(base)
+ if w: return w
+ err('waf-light requires waflib -> export WAFDIR=/folder')
+
+ dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
+ for i in (INSTALL,'/usr','/usr/local','/opt'):
+ w = test(i + '/lib/' + dirname)
+ if w: return w
+
+ #waf-local
+ dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
+ w = test(dir)
+ if w: return w
+
+ #unpack
+ unpack_wafdir(dir, src)
+ return dir
+
+wafdir = find_lib()
+sys.path.insert(0, wafdir)
+
+if __name__ == '__main__':
+
+ from waflib import Scripting
+ Scripting.waf_entry_point(cwd, VERSION, wafdir)
+
diff --git a/waflib/Build.py b/waflib/Build.py
new file mode 100644
index 0000000..f24ce07
--- /dev/null
+++ b/waflib/Build.py
@@ -0,0 +1,759 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,sys,errno,re,shutil,stat
+try:
+ import cPickle
+except ImportError:
+ import pickle as cPickle
+from waflib import Runner,TaskGen,Utils,ConfigSet,Task,Logs,Options,Context,Errors
+import waflib.Node
+CACHE_DIR='c4che'
+CACHE_SUFFIX='_cache.py'
+INSTALL=1337
+UNINSTALL=-1337
+SAVED_ATTRS='root node_deps raw_deps task_sigs'.split()
+CFG_FILES='cfg_files'
+POST_AT_ONCE=0
+POST_LAZY=1
+POST_BOTH=2
+PROTOCOL=-1
+if sys.platform=='cli':
+ PROTOCOL=0
+class BuildContext(Context.Context):
+ '''executes the build'''
+ cmd='build'
+ variant=''
+ def __init__(self,**kw):
+ super(BuildContext,self).__init__(**kw)
+ self.is_install=0
+ self.top_dir=kw.get('top_dir',Context.top_dir)
+ self.run_dir=kw.get('run_dir',Context.run_dir)
+ self.post_mode=POST_AT_ONCE
+ self.out_dir=kw.get('out_dir',Context.out_dir)
+ self.cache_dir=kw.get('cache_dir',None)
+ if not self.cache_dir:
+ self.cache_dir=os.path.join(self.out_dir,CACHE_DIR)
+ self.all_envs={}
+ self.task_sigs={}
+ self.node_deps={}
+ self.raw_deps={}
+ self.cache_dir_contents={}
+ self.task_gen_cache_names={}
+ self.launch_dir=Context.launch_dir
+ self.jobs=Options.options.jobs
+ self.targets=Options.options.targets
+ self.keep=Options.options.keep
+ self.progress_bar=Options.options.progress_bar
+ self.deps_man=Utils.defaultdict(list)
+ self.current_group=0
+ self.groups=[]
+ self.group_names={}
+ def get_variant_dir(self):
+ if not self.variant:
+ return self.out_dir
+ return os.path.join(self.out_dir,self.variant)
+ variant_dir=property(get_variant_dir,None)
+ def __call__(self,*k,**kw):
+ kw['bld']=self
+ ret=TaskGen.task_gen(*k,**kw)
+ self.task_gen_cache_names={}
+ self.add_to_group(ret,group=kw.get('group',None))
+ return ret
+ def rule(self,*k,**kw):
+ def f(rule):
+ ret=self(*k,**kw)
+ ret.rule=rule
+ return ret
+ return f
+ def __copy__(self):
+ raise Errors.WafError('build contexts are not supposed to be copied')
+ def install_files(self,*k,**kw):
+ pass
+ def install_as(self,*k,**kw):
+ pass
+ def symlink_as(self,*k,**kw):
+ pass
+ def load_envs(self):
+ node=self.root.find_node(self.cache_dir)
+ if not node:
+ raise Errors.WafError('The project was not configured: run "waf configure" first!')
+ lst=node.ant_glob('**/*%s'%CACHE_SUFFIX,quiet=True)
+ if not lst:
+ raise Errors.WafError('The cache directory is empty: reconfigure the project')
+ for x in lst:
+ name=x.path_from(node).replace(CACHE_SUFFIX,'').replace('\\','/')
+ env=ConfigSet.ConfigSet(x.abspath())
+ self.all_envs[name]=env
+ for f in env[CFG_FILES]:
+ newnode=self.root.find_resource(f)
+ try:
+ h=Utils.h_file(newnode.abspath())
+ except(IOError,AttributeError):
+ Logs.error('cannot find %r'%f)
+ h=Utils.SIG_NIL
+ newnode.sig=h
+ def init_dirs(self):
+ if not(os.path.isabs(self.top_dir)and os.path.isabs(self.out_dir)):
+ raise Errors.WafError('The project was not configured: run "waf configure" first!')
+ self.path=self.srcnode=self.root.find_dir(self.top_dir)
+ self.bldnode=self.root.make_node(self.variant_dir)
+ self.bldnode.mkdir()
+ def execute(self):
+ self.restore()
+ if not self.all_envs:
+ self.load_envs()
+ self.execute_build()
+ def execute_build(self):
+ Logs.info("Waf: Entering directory `%s'"%self.variant_dir)
+ self.recurse([self.run_dir])
+ self.pre_build()
+ self.timer=Utils.Timer()
+ try:
+ self.compile()
+ finally:
+ if self.progress_bar==1 and sys.stderr.isatty():
+ c=len(self.returned_tasks)or 1
+ m=self.progress_line(c,c,Logs.colors.BLUE,Logs.colors.NORMAL)
+ Logs.info(m,extra={'stream':sys.stderr,'c1':Logs.colors.cursor_off,'c2':Logs.colors.cursor_on})
+ Logs.info("Waf: Leaving directory `%s'"%self.variant_dir)
+ self.post_build()
+ def restore(self):
+ try:
+ env=ConfigSet.ConfigSet(os.path.join(self.cache_dir,'build.config.py'))
+ except EnvironmentError:
+ pass
+ else:
+ if env['version']<Context.HEXVERSION:
+ raise Errors.WafError('Version mismatch! reconfigure the project')
+ for t in env['tools']:
+ self.setup(**t)
+ dbfn=os.path.join(self.variant_dir,Context.DBFILE)
+ try:
+ data=Utils.readf(dbfn,'rb')
+ except(IOError,EOFError):
+ Logs.debug('build: Could not load the build cache %s (missing)'%dbfn)
+ else:
+ try:
+ waflib.Node.pickle_lock.acquire()
+ waflib.Node.Nod3=self.node_class
+ try:
+ data=cPickle.loads(data)
+ except Exception ,e:
+ Logs.debug('build: Could not pickle the build cache %s: %r'%(dbfn,e))
+ else:
+ for x in SAVED_ATTRS:
+ setattr(self,x,data[x])
+ finally:
+ waflib.Node.pickle_lock.release()
+ self.init_dirs()
+ def store(self):
+ data={}
+ for x in SAVED_ATTRS:
+ data[x]=getattr(self,x)
+ db=os.path.join(self.variant_dir,Context.DBFILE)
+ try:
+ waflib.Node.pickle_lock.acquire()
+ waflib.Node.Nod3=self.node_class
+ x=cPickle.dumps(data,PROTOCOL)
+ finally:
+ waflib.Node.pickle_lock.release()
+ Utils.writef(db+'.tmp',x,m='wb')
+ try:
+ st=os.stat(db)
+ os.remove(db)
+ if not Utils.is_win32:
+ os.chown(db+'.tmp',st.st_uid,st.st_gid)
+ except(AttributeError,OSError):
+ pass
+ os.rename(db+'.tmp',db)
+ def compile(self):
+ Logs.debug('build: compile()')
+ self.producer=Runner.Parallel(self,self.jobs)
+ self.producer.biter=self.get_build_iterator()
+ self.returned_tasks=[]
+ try:
+ self.producer.start()
+ except KeyboardInterrupt:
+ self.store()
+ raise
+ else:
+ if self.producer.dirty:
+ self.store()
+ if self.producer.error:
+ raise Errors.BuildError(self.producer.error)
+ def setup(self,tool,tooldir=None,funs=None):
+ if isinstance(tool,list):
+ for i in tool:self.setup(i,tooldir)
+ return
+ module=Context.load_tool(tool,tooldir)
+ if hasattr(module,"setup"):module.setup(self)
+ def get_env(self):
+ try:
+ return self.all_envs[self.variant]
+ except KeyError:
+ return self.all_envs['']
+ def set_env(self,val):
+ self.all_envs[self.variant]=val
+ env=property(get_env,set_env)
+ def add_manual_dependency(self,path,value):
+ if path is None:
+ raise ValueError('Invalid input')
+ if isinstance(path,waflib.Node.Node):
+ node=path
+ elif os.path.isabs(path):
+ node=self.root.find_resource(path)
+ else:
+ node=self.path.find_resource(path)
+ if isinstance(value,list):
+ self.deps_man[id(node)].extend(value)
+ else:
+ self.deps_man[id(node)].append(value)
+ def launch_node(self):
+ try:
+ return self.p_ln
+ except AttributeError:
+ self.p_ln=self.root.find_dir(self.launch_dir)
+ return self.p_ln
+ def hash_env_vars(self,env,vars_lst):
+ if not env.table:
+ env=env.parent
+ if not env:
+ return Utils.SIG_NIL
+ idx=str(id(env))+str(vars_lst)
+ try:
+ cache=self.cache_env
+ except AttributeError:
+ cache=self.cache_env={}
+ else:
+ try:
+ return self.cache_env[idx]
+ except KeyError:
+ pass
+ lst=[env[a]for a in vars_lst]
+ ret=Utils.h_list(lst)
+ Logs.debug('envhash: %s %r',Utils.to_hex(ret),lst)
+ cache[idx]=ret
+ return ret
+ def get_tgen_by_name(self,name):
+ cache=self.task_gen_cache_names
+ if not cache:
+ for g in self.groups:
+ for tg in g:
+ try:
+ cache[tg.name]=tg
+ except AttributeError:
+ pass
+ try:
+ return cache[name]
+ except KeyError:
+ raise Errors.WafError('Could not find a task generator for the name %r'%name)
+ def progress_line(self,state,total,col1,col2):
+ if not sys.stderr.isatty():
+ return''
+ n=len(str(total))
+ Utils.rot_idx+=1
+ ind=Utils.rot_chr[Utils.rot_idx%4]
+ pc=(100.*state)/total
+ eta=str(self.timer)
+ fs="[%%%dd/%%%dd][%%s%%2d%%%%%%s][%s]["%(n,n,ind)
+ left=fs%(state,total,col1,pc,col2)
+ right='][%s%s%s]'%(col1,eta,col2)
+ cols=Logs.get_term_cols()-len(left)-len(right)+2*len(col1)+2*len(col2)
+ if cols<7:cols=7
+ ratio=((cols*state)//total)-1
+ bar=('='*ratio+'>').ljust(cols)
+ msg=Logs.indicator%(left,bar,right)
+ return msg
+ def declare_chain(self,*k,**kw):
+ return TaskGen.declare_chain(*k,**kw)
+ def pre_build(self):
+ for m in getattr(self,'pre_funs',[]):
+ m(self)
+ def post_build(self):
+ for m in getattr(self,'post_funs',[]):
+ m(self)
+ def add_pre_fun(self,meth):
+ try:
+ self.pre_funs.append(meth)
+ except AttributeError:
+ self.pre_funs=[meth]
+ def add_post_fun(self,meth):
+ try:
+ self.post_funs.append(meth)
+ except AttributeError:
+ self.post_funs=[meth]
+ def get_group(self,x):
+ if not self.groups:
+ self.add_group()
+ if x is None:
+ return self.groups[self.current_group]
+ if x in self.group_names:
+ return self.group_names[x]
+ return self.groups[x]
+ def add_to_group(self,tgen,group=None):
+ assert(isinstance(tgen,TaskGen.task_gen)or isinstance(tgen,Task.TaskBase))
+ tgen.bld=self
+ self.get_group(group).append(tgen)
+ def get_group_name(self,g):
+ if not isinstance(g,list):
+ g=self.groups[g]
+ for x in self.group_names:
+ if id(self.group_names[x])==id(g):
+ return x
+ return''
+ def get_group_idx(self,tg):
+ se=id(tg)
+ for i in range(len(self.groups)):
+ for t in self.groups[i]:
+ if id(t)==se:
+ return i
+ return None
+ def add_group(self,name=None,move=True):
+ if name and name in self.group_names:
+ Logs.error('add_group: name %s already present'%name)
+ g=[]
+ self.group_names[name]=g
+ self.groups.append(g)
+ if move:
+ self.current_group=len(self.groups)-1
+ def set_group(self,idx):
+ if isinstance(idx,str):
+ g=self.group_names[idx]
+ for i in range(len(self.groups)):
+ if id(g)==id(self.groups[i]):
+ self.current_group=i
+ break
+ else:
+ self.current_group=idx
+ def total(self):
+ total=0
+ for group in self.groups:
+ for tg in group:
+ try:
+ total+=len(tg.tasks)
+ except AttributeError:
+ total+=1
+ return total
+ def get_targets(self):
+ to_post=[]
+ min_grp=0
+ for name in self.targets.split(','):
+ tg=self.get_tgen_by_name(name)
+ m=self.get_group_idx(tg)
+ if m>min_grp:
+ min_grp=m
+ to_post=[tg]
+ elif m==min_grp:
+ to_post.append(tg)
+ return(min_grp,to_post)
+ def get_all_task_gen(self):
+ lst=[]
+ for g in self.groups:
+ lst.extend(g)
+ return lst
+ def post_group(self):
+ if self.targets=='*':
+ for tg in self.groups[self.cur]:
+ try:
+ f=tg.post
+ except AttributeError:
+ pass
+ else:
+ f()
+ elif self.targets:
+ if self.cur<self._min_grp:
+ for tg in self.groups[self.cur]:
+ try:
+ f=tg.post
+ except AttributeError:
+ pass
+ else:
+ f()
+ else:
+ for tg in self._exact_tg:
+ tg.post()
+ else:
+ ln=self.launch_node()
+ if ln.is_child_of(self.bldnode):
+ Logs.warn('Building from the build directory, forcing --targets=*')
+ ln=self.srcnode
+ elif not ln.is_child_of(self.srcnode):
+ Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)'%(ln.abspath(),self.srcnode.abspath()))
+ ln=self.srcnode
+ for tg in self.groups[self.cur]:
+ try:
+ f=tg.post
+ except AttributeError:
+ pass
+ else:
+ if tg.path.is_child_of(ln):
+ f()
+ def get_tasks_group(self,idx):
+ tasks=[]
+ for tg in self.groups[idx]:
+ try:
+ tasks.extend(tg.tasks)
+ except AttributeError:
+ tasks.append(tg)
+ return tasks
+ def get_build_iterator(self):
+ self.cur=0
+ if self.targets and self.targets!='*':
+ (self._min_grp,self._exact_tg)=self.get_targets()
+ global lazy_post
+ if self.post_mode!=POST_LAZY:
+ while self.cur<len(self.groups):
+ self.post_group()
+ self.cur+=1
+ self.cur=0
+ while self.cur<len(self.groups):
+ if self.post_mode!=POST_AT_ONCE:
+ self.post_group()
+ tasks=self.get_tasks_group(self.cur)
+ Task.set_file_constraints(tasks)
+ Task.set_precedence_constraints(tasks)
+ self.cur_tasks=tasks
+ self.cur+=1
+ if not tasks:
+ continue
+ yield tasks
+ while 1:
+ yield[]
+class inst(Task.Task):
+ color='CYAN'
+ def uid(self):
+ lst=[self.dest,self.path]+self.source
+ return Utils.h_list(repr(lst))
+ def post(self):
+ buf=[]
+ for x in self.source:
+ if isinstance(x,waflib.Node.Node):
+ y=x
+ else:
+ y=self.path.find_resource(x)
+ if not y:
+ if os.path.isabs(x):
+ y=self.bld.root.make_node(x)
+ else:
+ y=self.path.make_node(x)
+ buf.append(y)
+ self.inputs=buf
+ def runnable_status(self):
+ ret=super(inst,self).runnable_status()
+ if ret==Task.SKIP_ME:
+ return Task.RUN_ME
+ return ret
+ def __str__(self):
+ return''
+ def run(self):
+ return self.generator.exec_task()
+ def get_install_path(self,destdir=True):
+ dest=Utils.subst_vars(self.dest,self.env)
+ dest=dest.replace('/',os.sep)
+ if destdir and Options.options.destdir:
+ dest=os.path.join(Options.options.destdir,os.path.splitdrive(dest)[1].lstrip(os.sep))
+ return dest
+ def exec_install_files(self):
+ destpath=self.get_install_path()
+ if not destpath:
+ raise Errors.WafError('unknown installation path %r'%self.generator)
+ for x,y in zip(self.source,self.inputs):
+ if self.relative_trick:
+ destfile=os.path.join(destpath,y.path_from(self.path))
+ else:
+ destfile=os.path.join(destpath,y.name)
+ self.generator.bld.do_install(y.abspath(),destfile,chmod=self.chmod,tsk=self)
+ def exec_install_as(self):
+ destfile=self.get_install_path()
+ self.generator.bld.do_install(self.inputs[0].abspath(),destfile,chmod=self.chmod,tsk=self)
+ def exec_symlink_as(self):
+ destfile=self.get_install_path()
+ src=self.link
+ if self.relative_trick:
+ src=os.path.relpath(src,os.path.dirname(destfile))
+ self.generator.bld.do_link(src,destfile,tsk=self)
+class InstallContext(BuildContext):
+ '''installs the targets on the system'''
+ cmd='install'
+ def __init__(self,**kw):
+ super(InstallContext,self).__init__(**kw)
+ self.uninstall=[]
+ self.is_install=INSTALL
+ def copy_fun(self,src,tgt,**kw):
+ if Utils.is_win32 and len(tgt)>259 and not tgt.startswith('\\\\?\\'):
+ tgt='\\\\?\\'+tgt
+ shutil.copy2(src,tgt)
+ os.chmod(tgt,kw.get('chmod',Utils.O644))
+ def do_install(self,src,tgt,**kw):
+ d,_=os.path.split(tgt)
+ if not d:
+ raise Errors.WafError('Invalid installation given %r->%r'%(src,tgt))
+ Utils.check_dir(d)
+ srclbl=src.replace(self.srcnode.abspath()+os.sep,'')
+ if not Options.options.force:
+ try:
+ st1=os.stat(tgt)
+ st2=os.stat(src)
+ except OSError:
+ pass
+ else:
+ if st1.st_mtime+2>=st2.st_mtime and st1.st_size==st2.st_size:
+ if not self.progress_bar:
+ Logs.info('- install %s (from %s)'%(tgt,srclbl))
+ return False
+ if not self.progress_bar:
+ Logs.info('+ install %s (from %s)'%(tgt,srclbl))
+ try:
+ os.chmod(tgt,Utils.O644|stat.S_IMODE(os.stat(tgt).st_mode))
+ except EnvironmentError:
+ pass
+ try:
+ os.remove(tgt)
+ except OSError:
+ pass
+ try:
+ self.copy_fun(src,tgt,**kw)
+ except IOError:
+ try:
+ os.stat(src)
+ except EnvironmentError:
+ Logs.error('File %r does not exist'%src)
+ raise Errors.WafError('Could not install the file %r'%tgt)
+ def do_link(self,src,tgt,**kw):
+ d,_=os.path.split(tgt)
+ Utils.check_dir(d)
+ link=False
+ if not os.path.islink(tgt):
+ link=True
+ elif os.readlink(tgt)!=src:
+ link=True
+ if link:
+ try:os.remove(tgt)
+ except OSError:pass
+ if not self.progress_bar:
+ Logs.info('+ symlink %s (to %s)'%(tgt,src))
+ os.symlink(src,tgt)
+ else:
+ if not self.progress_bar:
+ Logs.info('- symlink %s (to %s)'%(tgt,src))
+ def run_task_now(self,tsk,postpone):
+ tsk.post()
+ if not postpone:
+ if tsk.runnable_status()==Task.ASK_LATER:
+ raise self.WafError('cannot post the task %r'%tsk)
+ tsk.run()
+ tsk.hasrun=True
+ def install_files(self,dest,files,env=None,chmod=Utils.O644,relative_trick=False,cwd=None,add=True,postpone=True,task=None):
+ assert(dest)
+ tsk=inst(env=env or self.env)
+ tsk.bld=self
+ tsk.path=cwd or self.path
+ tsk.chmod=chmod
+ tsk.task=task
+ if isinstance(files,waflib.Node.Node):
+ tsk.source=[files]
+ else:
+ tsk.source=Utils.to_list(files)
+ tsk.dest=dest
+ tsk.exec_task=tsk.exec_install_files
+ tsk.relative_trick=relative_trick
+ if add:self.add_to_group(tsk)
+ self.run_task_now(tsk,postpone)
+ return tsk
+ def install_as(self,dest,srcfile,env=None,chmod=Utils.O644,cwd=None,add=True,postpone=True,task=None):
+ assert(dest)
+ tsk=inst(env=env or self.env)
+ tsk.bld=self
+ tsk.path=cwd or self.path
+ tsk.chmod=chmod
+ tsk.source=[srcfile]
+ tsk.task=task
+ tsk.dest=dest
+ tsk.exec_task=tsk.exec_install_as
+ if add:self.add_to_group(tsk)
+ self.run_task_now(tsk,postpone)
+ return tsk
+ def symlink_as(self,dest,src,env=None,cwd=None,add=True,postpone=True,relative_trick=False,task=None):
+ if Utils.is_win32:
+ return
+ assert(dest)
+ tsk=inst(env=env or self.env)
+ tsk.bld=self
+ tsk.dest=dest
+ tsk.path=cwd or self.path
+ tsk.source=[]
+ tsk.task=task
+ tsk.link=src
+ tsk.relative_trick=relative_trick
+ tsk.exec_task=tsk.exec_symlink_as
+ if add:self.add_to_group(tsk)
+ self.run_task_now(tsk,postpone)
+ return tsk
+class UninstallContext(InstallContext):
+ '''removes the targets installed'''
+ cmd='uninstall'
+ def __init__(self,**kw):
+ super(UninstallContext,self).__init__(**kw)
+ self.is_install=UNINSTALL
+ def rm_empty_dirs(self,tgt):
+ while tgt:
+ tgt=os.path.dirname(tgt)
+ try:
+ os.rmdir(tgt)
+ except OSError:
+ break
+ def do_install(self,src,tgt,**kw):
+ if not self.progress_bar:
+ Logs.info('- remove %s'%tgt)
+ self.uninstall.append(tgt)
+ try:
+ os.remove(tgt)
+ except OSError ,e:
+ if e.errno!=errno.ENOENT:
+ if not getattr(self,'uninstall_error',None):
+ self.uninstall_error=True
+ Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)')
+ if Logs.verbose>1:
+ Logs.warn('Could not remove %s (error code %r)'%(e.filename,e.errno))
+ self.rm_empty_dirs(tgt)
+ def do_link(self,src,tgt,**kw):
+ try:
+ if not self.progress_bar:
+ Logs.info('- remove %s'%tgt)
+ os.remove(tgt)
+ except OSError:
+ pass
+ self.rm_empty_dirs(tgt)
+ def execute(self):
+ try:
+ def runnable_status(self):
+ return Task.SKIP_ME
+ setattr(Task.Task,'runnable_status_back',Task.Task.runnable_status)
+ setattr(Task.Task,'runnable_status',runnable_status)
+ super(UninstallContext,self).execute()
+ finally:
+ setattr(Task.Task,'runnable_status',Task.Task.runnable_status_back)
+class CleanContext(BuildContext):
+ '''cleans the project'''
+ cmd='clean'
+ def execute(self):
+ self.restore()
+ if not self.all_envs:
+ self.load_envs()
+ self.recurse([self.run_dir])
+ try:
+ self.clean()
+ finally:
+ self.store()
+ def clean(self):
+ Logs.debug('build: clean called')
+ if self.bldnode!=self.srcnode:
+ lst=[]
+ for e in self.all_envs.values():
+ lst.extend(self.root.find_or_declare(f)for f in e[CFG_FILES])
+ for n in self.bldnode.ant_glob('**/*',excl='.lock* *conf_check_*/** config.log c4che/*',quiet=True):
+ if n in lst:
+ continue
+ n.delete()
+ self.root.children={}
+ for v in'node_deps task_sigs raw_deps'.split():
+ setattr(self,v,{})
+class ListContext(BuildContext):
+ '''lists the targets to execute'''
+ cmd='list'
+ def execute(self):
+ self.restore()
+ if not self.all_envs:
+ self.load_envs()
+ self.recurse([self.run_dir])
+ self.pre_build()
+ self.timer=Utils.Timer()
+ for g in self.groups:
+ for tg in g:
+ try:
+ f=tg.post
+ except AttributeError:
+ pass
+ else:
+ f()
+ try:
+ self.get_tgen_by_name('')
+ except Exception:
+ pass
+ lst=list(self.task_gen_cache_names.keys())
+ lst.sort()
+ for k in lst:
+ Logs.pprint('GREEN',k)
+class StepContext(BuildContext):
+ '''executes tasks in a step-by-step fashion, for debugging'''
+ cmd='step'
+ def __init__(self,**kw):
+ super(StepContext,self).__init__(**kw)
+ self.files=Options.options.files
+ def compile(self):
+ if not self.files:
+ Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"')
+ BuildContext.compile(self)
+ return
+ targets=None
+ if self.targets and self.targets!='*':
+ targets=self.targets.split(',')
+ for g in self.groups:
+ for tg in g:
+ if targets and tg.name not in targets:
+ continue
+ try:
+ f=tg.post
+ except AttributeError:
+ pass
+ else:
+ f()
+ for pat in self.files.split(','):
+ matcher=self.get_matcher(pat)
+ for tg in g:
+ if isinstance(tg,Task.TaskBase):
+ lst=[tg]
+ else:
+ lst=tg.tasks
+ for tsk in lst:
+ do_exec=False
+ for node in getattr(tsk,'inputs',[]):
+ if matcher(node,output=False):
+ do_exec=True
+ break
+ for node in getattr(tsk,'outputs',[]):
+ if matcher(node,output=True):
+ do_exec=True
+ break
+ if do_exec:
+ ret=tsk.run()
+ Logs.info('%s -> exit %r'%(str(tsk),ret))
+ def get_matcher(self,pat):
+ inn=True
+ out=True
+ if pat.startswith('in:'):
+ out=False
+ pat=pat.replace('in:','')
+ elif pat.startswith('out:'):
+ inn=False
+ pat=pat.replace('out:','')
+ anode=self.root.find_node(pat)
+ pattern=None
+ if not anode:
+ if not pat.startswith('^'):
+ pat='^.+?%s'%pat
+ if not pat.endswith('$'):
+ pat='%s$'%pat
+ pattern=re.compile(pat)
+ def match(node,output):
+ if output==True and not out:
+ return False
+ if output==False and not inn:
+ return False
+ if anode:
+ return anode==node
+ else:
+ return pattern.match(node.abspath())
+ return match
diff --git a/waflib/ConfigSet.py b/waflib/ConfigSet.py
new file mode 100644
index 0000000..19f8321
--- /dev/null
+++ b/waflib/ConfigSet.py
@@ -0,0 +1,155 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import copy,re,os
+from waflib import Logs,Utils
+re_imp=re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$',re.M)
+class ConfigSet(object):
+ __slots__=('table','parent')
+ def __init__(self,filename=None):
+ self.table={}
+ if filename:
+ self.load(filename)
+ def __contains__(self,key):
+ if key in self.table:return True
+ try:return self.parent.__contains__(key)
+ except AttributeError:return False
+ def keys(self):
+ keys=set()
+ cur=self
+ while cur:
+ keys.update(cur.table.keys())
+ cur=getattr(cur,'parent',None)
+ keys=list(keys)
+ keys.sort()
+ return keys
+ def __str__(self):
+ return"\n".join(["%r %r"%(x,self.__getitem__(x))for x in self.keys()])
+ def __getitem__(self,key):
+ try:
+ while 1:
+ x=self.table.get(key,None)
+ if not x is None:
+ return x
+ self=self.parent
+ except AttributeError:
+ return[]
+ def __setitem__(self,key,value):
+ self.table[key]=value
+ def __delitem__(self,key):
+ self[key]=[]
+ def __getattr__(self,name):
+ if name in self.__slots__:
+ return object.__getattr__(self,name)
+ else:
+ return self[name]
+ def __setattr__(self,name,value):
+ if name in self.__slots__:
+ object.__setattr__(self,name,value)
+ else:
+ self[name]=value
+ def __delattr__(self,name):
+ if name in self.__slots__:
+ object.__delattr__(self,name)
+ else:
+ del self[name]
+ def derive(self):
+ newenv=ConfigSet()
+ newenv.parent=self
+ return newenv
+ def detach(self):
+ tbl=self.get_merged_dict()
+ try:
+ delattr(self,'parent')
+ except AttributeError:
+ pass
+ else:
+ keys=tbl.keys()
+ for x in keys:
+ tbl[x]=copy.deepcopy(tbl[x])
+ self.table=tbl
+ return self
+ def get_flat(self,key):
+ s=self[key]
+ if isinstance(s,str):return s
+ return' '.join(s)
+ def _get_list_value_for_modification(self,key):
+ try:
+ value=self.table[key]
+ except KeyError:
+ try:value=self.parent[key]
+ except AttributeError:value=[]
+ if isinstance(value,list):
+ value=value[:]
+ else:
+ value=[value]
+ else:
+ if not isinstance(value,list):
+ value=[value]
+ self.table[key]=value
+ return value
+ def append_value(self,var,val):
+ if isinstance(val,str):
+ val=[val]
+ current_value=self._get_list_value_for_modification(var)
+ current_value.extend(val)
+ def prepend_value(self,var,val):
+ if isinstance(val,str):
+ val=[val]
+ self.table[var]=val+self._get_list_value_for_modification(var)
+ def append_unique(self,var,val):
+ if isinstance(val,str):
+ val=[val]
+ current_value=self._get_list_value_for_modification(var)
+ for x in val:
+ if x not in current_value:
+ current_value.append(x)
+ def get_merged_dict(self):
+ table_list=[]
+ env=self
+ while 1:
+ table_list.insert(0,env.table)
+ try:env=env.parent
+ except AttributeError:break
+ merged_table={}
+ for table in table_list:
+ merged_table.update(table)
+ return merged_table
+ def store(self,filename):
+ try:
+ os.makedirs(os.path.split(filename)[0])
+ except OSError:
+ pass
+ buf=[]
+ merged_table=self.get_merged_dict()
+ keys=list(merged_table.keys())
+ keys.sort()
+ try:
+ fun=ascii
+ except NameError:
+ fun=repr
+ for k in keys:
+ if k!='undo_stack':
+ buf.append('%s = %s\n'%(k,fun(merged_table[k])))
+ Utils.writef(filename,''.join(buf))
+ def load(self,filename):
+ tbl=self.table
+ code=Utils.readf(filename,m='rU')
+ for m in re_imp.finditer(code):
+ g=m.group
+ tbl[g(2)]=eval(g(3))
+ Logs.debug('env: %s'%str(self.table))
+ def update(self,d):
+ for k,v in d.items():
+ self[k]=v
+ def stash(self):
+ orig=self.table
+ tbl=self.table=self.table.copy()
+ for x in tbl.keys():
+ tbl[x]=copy.deepcopy(tbl[x])
+ self.undo_stack=self.undo_stack+[orig]
+ def commit(self):
+ self.undo_stack.pop(-1)
+ def revert(self):
+ self.table=self.undo_stack.pop(-1)
diff --git a/waflib/Configure.py b/waflib/Configure.py
new file mode 100644
index 0000000..97ce134
--- /dev/null
+++ b/waflib/Configure.py
@@ -0,0 +1,379 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,shlex,sys,time,re,shutil
+from waflib import ConfigSet,Utils,Options,Logs,Context,Build,Errors
+BREAK='break'
+CONTINUE='continue'
+WAF_CONFIG_LOG='config.log'
+autoconfig=False
+conf_template='''# project %(app)s configured on %(now)s by
+# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)
+# using %(args)s
+#'''
+class ConfigurationContext(Context.Context):
+ '''configures the project'''
+ cmd='configure'
+ error_handlers=[]
+ def __init__(self,**kw):
+ super(ConfigurationContext,self).__init__(**kw)
+ self.environ=dict(os.environ)
+ self.all_envs={}
+ self.top_dir=None
+ self.out_dir=None
+ self.tools=[]
+ self.hash=0
+ self.files=[]
+ self.tool_cache=[]
+ self.setenv('')
+ def setenv(self,name,env=None):
+ if name not in self.all_envs or env:
+ if not env:
+ env=ConfigSet.ConfigSet()
+ self.prepare_env(env)
+ else:
+ env=env.derive()
+ self.all_envs[name]=env
+ self.variant=name
+ def get_env(self):
+ return self.all_envs[self.variant]
+ def set_env(self,val):
+ self.all_envs[self.variant]=val
+ env=property(get_env,set_env)
+ def init_dirs(self):
+ top=self.top_dir
+ if not top:
+ top=Options.options.top
+ if not top:
+ top=getattr(Context.g_module,Context.TOP,None)
+ if not top:
+ top=self.path.abspath()
+ top=os.path.abspath(top)
+ self.srcnode=(os.path.isabs(top)and self.root or self.path).find_dir(top)
+ assert(self.srcnode)
+ out=self.out_dir
+ if not out:
+ out=Options.options.out
+ if not out:
+ out=getattr(Context.g_module,Context.OUT,None)
+ if not out:
+ out=Options.lockfile.replace('.lock-waf_%s_'%sys.platform,'').replace('.lock-waf','')
+ out=os.path.realpath(out)
+ self.bldnode=(os.path.isabs(out)and self.root or self.path).make_node(out)
+ self.bldnode.mkdir()
+ if not os.path.isdir(self.bldnode.abspath()):
+ conf.fatal('Could not create the build directory %s'%self.bldnode.abspath())
+ def execute(self):
+ self.init_dirs()
+ self.cachedir=self.bldnode.make_node(Build.CACHE_DIR)
+ self.cachedir.mkdir()
+ path=os.path.join(self.bldnode.abspath(),WAF_CONFIG_LOG)
+ self.logger=Logs.make_logger(path,'cfg')
+ app=getattr(Context.g_module,'APPNAME','')
+ if app:
+ ver=getattr(Context.g_module,'VERSION','')
+ if ver:
+ app="%s (%s)"%(app,ver)
+ params={'now':time.ctime(),'pyver':sys.hexversion,'systype':sys.platform,'args':" ".join(sys.argv),'wafver':Context.WAFVERSION,'abi':Context.ABI,'app':app}
+ self.to_log(conf_template%params)
+ self.msg('Setting top to',self.srcnode.abspath())
+ self.msg('Setting out to',self.bldnode.abspath())
+ if id(self.srcnode)==id(self.bldnode):
+ Logs.warn('Setting top == out (remember to use "update_outputs")')
+ elif id(self.path)!=id(self.srcnode):
+ if self.srcnode.is_child_of(self.path):
+ Logs.warn('Are you certain that you do not want to set top="." ?')
+ super(ConfigurationContext,self).execute()
+ self.store()
+ Context.top_dir=self.srcnode.abspath()
+ Context.out_dir=self.bldnode.abspath()
+ env=ConfigSet.ConfigSet()
+ env['argv']=sys.argv
+ env['options']=Options.options.__dict__
+ env.run_dir=Context.run_dir
+ env.top_dir=Context.top_dir
+ env.out_dir=Context.out_dir
+ env['hash']=self.hash
+ env['files']=self.files
+ env['environ']=dict(self.environ)
+ if not self.env.NO_LOCK_IN_RUN and not getattr(Options.options,'no_lock_in_run'):
+ env.store(os.path.join(Context.run_dir,Options.lockfile))
+ if not self.env.NO_LOCK_IN_TOP and not getattr(Options.options,'no_lock_in_top'):
+ env.store(os.path.join(Context.top_dir,Options.lockfile))
+ if not self.env.NO_LOCK_IN_OUT and not getattr(Options.options,'no_lock_in_out'):
+ env.store(os.path.join(Context.out_dir,Options.lockfile))
+ def prepare_env(self,env):
+ if not env.PREFIX:
+ if Options.options.prefix or Utils.is_win32:
+ env.PREFIX=Utils.sane_path(Options.options.prefix)
+ else:
+ env.PREFIX=''
+ if not env.BINDIR:
+ if Options.options.bindir:
+ env.BINDIR=Utils.sane_path(Options.options.bindir)
+ else:
+ env.BINDIR=Utils.subst_vars('${PREFIX}/bin',env)
+ if not env.LIBDIR:
+ if Options.options.libdir:
+ env.LIBDIR=Utils.sane_path(Options.options.libdir)
+ else:
+ env.LIBDIR=Utils.subst_vars('${PREFIX}/lib%s'%Utils.lib64(),env)
+ def store(self):
+ n=self.cachedir.make_node('build.config.py')
+ n.write('version = 0x%x\ntools = %r\n'%(Context.HEXVERSION,self.tools))
+ if not self.all_envs:
+ self.fatal('nothing to store in the configuration context!')
+ for key in self.all_envs:
+ tmpenv=self.all_envs[key]
+ tmpenv.store(os.path.join(self.cachedir.abspath(),key+Build.CACHE_SUFFIX))
+ def load(self,input,tooldir=None,funs=None,with_sys_path=True):
+ tools=Utils.to_list(input)
+ if tooldir:tooldir=Utils.to_list(tooldir)
+ for tool in tools:
+ mag=(tool,id(self.env),tooldir,funs)
+ if mag in self.tool_cache:
+ self.to_log('(tool %s is already loaded, skipping)'%tool)
+ continue
+ self.tool_cache.append(mag)
+ module=None
+ try:
+ module=Context.load_tool(tool,tooldir,ctx=self,with_sys_path=with_sys_path)
+ except ImportError ,e:
+ self.fatal('Could not load the Waf tool %r from %r\n%s'%(tool,sys.path,e))
+ except Exception ,e:
+ self.to_log('imp %r (%r & %r)'%(tool,tooldir,funs))
+ self.to_log(Utils.ex_stack())
+ raise
+ if funs is not None:
+ self.eval_rules(funs)
+ else:
+ func=getattr(module,'configure',None)
+ if func:
+ if type(func)is type(Utils.readf):func(self)
+ else:self.eval_rules(func)
+ self.tools.append({'tool':tool,'tooldir':tooldir,'funs':funs})
+ def post_recurse(self,node):
+ super(ConfigurationContext,self).post_recurse(node)
+ self.hash=Utils.h_list((self.hash,node.read('rb')))
+ self.files.append(node.abspath())
+ def eval_rules(self,rules):
+ self.rules=Utils.to_list(rules)
+ for x in self.rules:
+ f=getattr(self,x)
+ if not f:self.fatal("No such method '%s'."%x)
+ try:
+ f()
+ except Exception ,e:
+ ret=self.err_handler(x,e)
+ if ret==BREAK:
+ break
+ elif ret==CONTINUE:
+ continue
+ else:
+ raise
+ def err_handler(self,fun,error):
+ pass
+def conf(f):
+ def fun(*k,**kw):
+ mandatory=True
+ if'mandatory'in kw:
+ mandatory=kw['mandatory']
+ del kw['mandatory']
+ try:
+ return f(*k,**kw)
+ except Errors.ConfigurationError:
+ if mandatory:
+ raise
+ fun.__name__=f.__name__
+ setattr(ConfigurationContext,f.__name__,fun)
+ setattr(Build.BuildContext,f.__name__,fun)
+ return f
+@conf
+def add_os_flags(self,var,dest=None,dup=True):
+ try:
+ flags=shlex.split(self.environ[var])
+ except KeyError:
+ return
+ if dup or''.join(flags)not in''.join(Utils.to_list(self.env[dest or var])):
+ self.env.append_value(dest or var,flags)
+@conf
+def cmd_to_list(self,cmd):
+ if isinstance(cmd,str)and cmd.find(' '):
+ try:
+ os.stat(cmd)
+ except OSError:
+ return shlex.split(cmd)
+ else:
+ return[cmd]
+ return cmd
+@conf
+def check_waf_version(self,mini='1.7.99',maxi='1.9.0',**kw):
+ self.start_msg('Checking for waf version in %s-%s'%(str(mini),str(maxi)),**kw)
+ ver=Context.HEXVERSION
+ if Utils.num2ver(mini)>ver:
+ self.fatal('waf version should be at least %r (%r found)'%(Utils.num2ver(mini),ver))
+ if Utils.num2ver(maxi)<ver:
+ self.fatal('waf version should be at most %r (%r found)'%(Utils.num2ver(maxi),ver))
+ self.end_msg('ok',**kw)
+@conf
+def find_file(self,filename,path_list=[]):
+ for n in Utils.to_list(filename):
+ for d in Utils.to_list(path_list):
+ p=os.path.expanduser(os.path.join(d,n))
+ if os.path.exists(p):
+ return p
+ self.fatal('Could not find %r'%filename)
+@conf
+def find_program(self,filename,**kw):
+ exts=kw.get('exts',Utils.is_win32 and'.exe,.com,.bat,.cmd'or',.sh,.pl,.py')
+ environ=kw.get('environ',getattr(self,'environ',os.environ))
+ ret=''
+ filename=Utils.to_list(filename)
+ msg=kw.get('msg',', '.join(filename))
+ var=kw.get('var','')
+ if not var:
+ var=re.sub(r'[-.]','_',filename[0].upper())
+ path_list=kw.get('path_list','')
+ if path_list:
+ path_list=Utils.to_list(path_list)
+ else:
+ path_list=environ.get('PATH','').split(os.pathsep)
+ if var in environ:
+ filename=environ[var]
+ if os.path.isfile(filename):
+ ret=[filename]
+ else:
+ ret=self.cmd_to_list(filename)
+ elif self.env[var]:
+ ret=self.env[var]
+ ret=self.cmd_to_list(ret)
+ else:
+ if not ret:
+ ret=self.find_binary(filename,exts.split(','),path_list)
+ if not ret and Utils.winreg:
+ ret=Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER,filename)
+ if not ret and Utils.winreg:
+ ret=Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE,filename)
+ ret=self.cmd_to_list(ret)
+ if ret:
+ if len(ret)==1:
+ retmsg=ret[0]
+ else:
+ retmsg=ret
+ else:
+ retmsg=False
+ self.msg("Checking for program '%s'"%msg,retmsg,**kw)
+ if not kw.get('quiet',None):
+ self.to_log('find program=%r paths=%r var=%r -> %r'%(filename,path_list,var,ret))
+ if not ret:
+ self.fatal(kw.get('errmsg','')or'Could not find the program %r'%filename)
+ interpreter=kw.get('interpreter',None)
+ if interpreter is None:
+ if not Utils.check_exe(ret[0],env=environ):
+ self.fatal('Program %r is not executable'%ret)
+ self.env[var]=ret
+ else:
+ self.env[var]=self.env[interpreter]+ret
+ return ret
+@conf
+def find_binary(self,filenames,exts,paths):
+ for f in filenames:
+ for ext in exts:
+ exe_name=f+ext
+ if os.path.isabs(exe_name):
+ if os.path.isfile(exe_name):
+ return exe_name
+ else:
+ for path in paths:
+ x=os.path.expanduser(os.path.join(path,exe_name))
+ if os.path.isfile(x):
+ return x
+ return None
+@conf
+def run_build(self,*k,**kw):
+ lst=[str(v)for(p,v)in kw.items()if p!='env']
+ h=Utils.h_list(lst)
+ dir=self.bldnode.abspath()+os.sep+(not Utils.is_win32 and'.'or'')+'conf_check_'+Utils.to_hex(h)
+ try:
+ os.makedirs(dir)
+ except OSError:
+ pass
+ try:
+ os.stat(dir)
+ except OSError:
+ self.fatal('cannot use the configuration test folder %r'%dir)
+ cachemode=getattr(Options.options,'confcache',None)
+ if cachemode==1:
+ try:
+ proj=ConfigSet.ConfigSet(os.path.join(dir,'cache_run_build'))
+ except OSError:
+ pass
+ except IOError:
+ pass
+ else:
+ ret=proj['cache_run_build']
+ if isinstance(ret,str)and ret.startswith('Test does not build'):
+ self.fatal(ret)
+ return ret
+ bdir=os.path.join(dir,'testbuild')
+ if not os.path.exists(bdir):
+ os.makedirs(bdir)
+ self.test_bld=bld=Build.BuildContext(top_dir=dir,out_dir=bdir)
+ bld.init_dirs()
+ bld.progress_bar=0
+ bld.targets='*'
+ bld.logger=self.logger
+ bld.all_envs.update(self.all_envs)
+ bld.env=kw['env']
+ bld.kw=kw
+ bld.conf=self
+ kw['build_fun'](bld)
+ ret=-1
+ try:
+ try:
+ bld.compile()
+ except Errors.WafError:
+ ret='Test does not build: %s'%Utils.ex_stack()
+ self.fatal(ret)
+ else:
+ ret=getattr(bld,'retval',0)
+ finally:
+ if cachemode==1:
+ proj=ConfigSet.ConfigSet()
+ proj['cache_run_build']=ret
+ proj.store(os.path.join(dir,'cache_run_build'))
+ else:
+ shutil.rmtree(dir)
+ return ret
+@conf
+def ret_msg(self,msg,args):
+ if isinstance(msg,str):
+ return msg
+ return msg(args)
+@conf
+def test(self,*k,**kw):
+ if not'env'in kw:
+ kw['env']=self.env.derive()
+ if kw.get('validate',None):
+ kw['validate'](kw)
+ self.start_msg(kw['msg'],**kw)
+ ret=None
+ try:
+ ret=self.run_build(*k,**kw)
+ except self.errors.ConfigurationError:
+ self.end_msg(kw['errmsg'],'YELLOW',**kw)
+ if Logs.verbose>1:
+ raise
+ else:
+ self.fatal('The configuration failed')
+ else:
+ kw['success']=ret
+ if kw.get('post_check',None):
+ ret=kw['post_check'](kw)
+ if ret:
+ self.end_msg(kw['errmsg'],'YELLOW',**kw)
+ self.fatal('The configuration failed %r'%ret)
+ else:
+ self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw)
+ return ret
diff --git a/waflib/Context.py b/waflib/Context.py
new file mode 100644
index 0000000..55422f3
--- /dev/null
+++ b/waflib/Context.py
@@ -0,0 +1,394 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,imp,sys
+from waflib import Utils,Errors,Logs
+import waflib.Node
+HEXVERSION=0x1081600
+WAFVERSION="1.8.22"
+WAFREVISION="17d4d4faa52c454eb3580e482df69b2a80e19fa7"
+ABI=98
+DBFILE='.wafpickle-%s-%d-%d'%(sys.platform,sys.hexversion,ABI)
+APPNAME='APPNAME'
+VERSION='VERSION'
+TOP='top'
+OUT='out'
+WSCRIPT_FILE='wscript'
+launch_dir=''
+run_dir=''
+top_dir=''
+out_dir=''
+waf_dir=''
+local_repo=''
+remote_repo='https://raw.githubusercontent.com/waf-project/waf/master/'
+remote_locs=['waflib/extras','waflib/Tools']
+g_module=None
+STDOUT=1
+STDERR=-1
+BOTH=0
+classes=[]
+def create_context(cmd_name,*k,**kw):
+ global classes
+ for x in classes:
+ if x.cmd==cmd_name:
+ return x(*k,**kw)
+ ctx=Context(*k,**kw)
+ ctx.fun=cmd_name
+ return ctx
+class store_context(type):
+ def __init__(cls,name,bases,dict):
+ super(store_context,cls).__init__(name,bases,dict)
+ name=cls.__name__
+ if name=='ctx'or name=='Context':
+ return
+ try:
+ cls.cmd
+ except AttributeError:
+ raise Errors.WafError('Missing command for the context class %r (cmd)'%name)
+ if not getattr(cls,'fun',None):
+ cls.fun=cls.cmd
+ global classes
+ classes.insert(0,cls)
+ctx=store_context('ctx',(object,),{})
+class Context(ctx):
+ errors=Errors
+ tools={}
+ def __init__(self,**kw):
+ try:
+ rd=kw['run_dir']
+ except KeyError:
+ global run_dir
+ rd=run_dir
+ self.node_class=type("Nod3",(waflib.Node.Node,),{})
+ self.node_class.__module__="waflib.Node"
+ self.node_class.ctx=self
+ self.root=self.node_class('',None)
+ self.cur_script=None
+ self.path=self.root.find_dir(rd)
+ self.stack_path=[]
+ self.exec_dict={'ctx':self,'conf':self,'bld':self,'opt':self}
+ self.logger=None
+ def __hash__(self):
+ return id(self)
+ def finalize(self):
+ try:
+ logger=self.logger
+ except AttributeError:
+ pass
+ else:
+ Logs.free_logger(logger)
+ delattr(self,'logger')
+ def load(self,tool_list,*k,**kw):
+ tools=Utils.to_list(tool_list)
+ path=Utils.to_list(kw.get('tooldir',''))
+ with_sys_path=kw.get('with_sys_path',True)
+ for t in tools:
+ module=load_tool(t,path,with_sys_path=with_sys_path)
+ fun=getattr(module,kw.get('name',self.fun),None)
+ if fun:
+ fun(self)
+ def execute(self):
+ global g_module
+ self.recurse([os.path.dirname(g_module.root_path)])
+ def pre_recurse(self,node):
+ self.stack_path.append(self.cur_script)
+ self.cur_script=node
+ self.path=node.parent
+ def post_recurse(self,node):
+ self.cur_script=self.stack_path.pop()
+ if self.cur_script:
+ self.path=self.cur_script.parent
+ def recurse(self,dirs,name=None,mandatory=True,once=True,encoding=None):
+ try:
+ cache=self.recurse_cache
+ except AttributeError:
+ cache=self.recurse_cache={}
+ for d in Utils.to_list(dirs):
+ if not os.path.isabs(d):
+ d=os.path.join(self.path.abspath(),d)
+ WSCRIPT=os.path.join(d,WSCRIPT_FILE)
+ WSCRIPT_FUN=WSCRIPT+'_'+(name or self.fun)
+ node=self.root.find_node(WSCRIPT_FUN)
+ if node and(not once or node not in cache):
+ cache[node]=True
+ self.pre_recurse(node)
+ try:
+ function_code=node.read('rU',encoding)
+ exec(compile(function_code,node.abspath(),'exec'),self.exec_dict)
+ finally:
+ self.post_recurse(node)
+ elif not node:
+ node=self.root.find_node(WSCRIPT)
+ tup=(node,name or self.fun)
+ if node and(not once or tup not in cache):
+ cache[tup]=True
+ self.pre_recurse(node)
+ try:
+ wscript_module=load_module(node.abspath(),encoding=encoding)
+ user_function=getattr(wscript_module,(name or self.fun),None)
+ if not user_function:
+ if not mandatory:
+ continue
+ raise Errors.WafError('No function %s defined in %s'%(name or self.fun,node.abspath()))
+ user_function(self)
+ finally:
+ self.post_recurse(node)
+ elif not node:
+ if not mandatory:
+ continue
+ try:
+ os.listdir(d)
+ except OSError:
+ raise Errors.WafError('Cannot read the folder %r'%d)
+ raise Errors.WafError('No wscript file in directory %s'%d)
+ def exec_command(self,cmd,**kw):
+ subprocess=Utils.subprocess
+ kw['shell']=isinstance(cmd,str)
+ Logs.debug('runner: %r'%(cmd,))
+ Logs.debug('runner_env: kw=%s'%kw)
+ if self.logger:
+ self.logger.info(cmd)
+ if'stdout'not in kw:
+ kw['stdout']=subprocess.PIPE
+ if'stderr'not in kw:
+ kw['stderr']=subprocess.PIPE
+ if Logs.verbose and not kw['shell']and not Utils.check_exe(cmd[0]):
+ raise Errors.WafError("Program %s not found!"%cmd[0])
+ wargs={}
+ if'timeout'in kw:
+ if kw['timeout']is not None:
+ wargs['timeout']=kw['timeout']
+ del kw['timeout']
+ if'input'in kw:
+ if kw['input']:
+ wargs['input']=kw['input']
+ kw['stdin']=subprocess.PIPE
+ del kw['input']
+ try:
+ if kw['stdout']or kw['stderr']:
+ p=subprocess.Popen(cmd,**kw)
+ (out,err)=p.communicate(**wargs)
+ ret=p.returncode
+ else:
+ out,err=(None,None)
+ ret=subprocess.Popen(cmd,**kw).wait(**wargs)
+ except Exception ,e:
+ raise Errors.WafError('Execution failure: %s'%str(e),ex=e)
+ if out:
+ if not isinstance(out,str):
+ out=out.decode(sys.stdout.encoding or'iso8859-1')
+ if self.logger:
+ self.logger.debug('out: %s'%out)
+ else:
+ Logs.info(out,extra={'stream':sys.stdout,'c1':''})
+ if err:
+ if not isinstance(err,str):
+ err=err.decode(sys.stdout.encoding or'iso8859-1')
+ if self.logger:
+ self.logger.error('err: %s'%err)
+ else:
+ Logs.info(err,extra={'stream':sys.stderr,'c1':''})
+ return ret
+ def cmd_and_log(self,cmd,**kw):
+ subprocess=Utils.subprocess
+ kw['shell']=isinstance(cmd,str)
+ Logs.debug('runner: %r'%(cmd,))
+ if'quiet'in kw:
+ quiet=kw['quiet']
+ del kw['quiet']
+ else:
+ quiet=None
+ if'output'in kw:
+ to_ret=kw['output']
+ del kw['output']
+ else:
+ to_ret=STDOUT
+ if Logs.verbose and not kw['shell']and not Utils.check_exe(cmd[0]):
+ raise Errors.WafError("Program %s not found!"%cmd[0])
+ kw['stdout']=kw['stderr']=subprocess.PIPE
+ if quiet is None:
+ self.to_log(cmd)
+ wargs={}
+ if'timeout'in kw:
+ if kw['timeout']is not None:
+ wargs['timeout']=kw['timeout']
+ del kw['timeout']
+ if'input'in kw:
+ if kw['input']:
+ wargs['input']=kw['input']
+ kw['stdin']=subprocess.PIPE
+ del kw['input']
+ try:
+ p=subprocess.Popen(cmd,**kw)
+ (out,err)=p.communicate(**wargs)
+ except Exception ,e:
+ raise Errors.WafError('Execution failure: %s'%str(e),ex=e)
+ if not isinstance(out,str):
+ out=out.decode(sys.stdout.encoding or'iso8859-1')
+ if not isinstance(err,str):
+ err=err.decode(sys.stdout.encoding or'iso8859-1')
+ if out and quiet!=STDOUT and quiet!=BOTH:
+ self.to_log('out: %s'%out)
+ if err and quiet!=STDERR and quiet!=BOTH:
+ self.to_log('err: %s'%err)
+ if p.returncode:
+ e=Errors.WafError('Command %r returned %r'%(cmd,p.returncode))
+ e.returncode=p.returncode
+ e.stderr=err
+ e.stdout=out
+ raise e
+ if to_ret==BOTH:
+ return(out,err)
+ elif to_ret==STDERR:
+ return err
+ return out
+ def fatal(self,msg,ex=None):
+ if self.logger:
+ self.logger.info('from %s: %s'%(self.path.abspath(),msg))
+ try:
+ msg='%s\n(complete log in %s)'%(msg,self.logger.handlers[0].baseFilename)
+ except Exception:
+ pass
+ raise self.errors.ConfigurationError(msg,ex=ex)
+ def to_log(self,msg):
+ if not msg:
+ return
+ if self.logger:
+ self.logger.info(msg)
+ else:
+ sys.stderr.write(str(msg))
+ sys.stderr.flush()
+ def msg(self,*k,**kw):
+ try:
+ msg=kw['msg']
+ except KeyError:
+ msg=k[0]
+ self.start_msg(msg,**kw)
+ try:
+ result=kw['result']
+ except KeyError:
+ result=k[1]
+ color=kw.get('color',None)
+ if not isinstance(color,str):
+ color=result and'GREEN'or'YELLOW'
+ self.end_msg(result,color,**kw)
+ def start_msg(self,*k,**kw):
+ if kw.get('quiet',None):
+ return
+ msg=kw.get('msg',None)or k[0]
+ try:
+ if self.in_msg:
+ self.in_msg+=1
+ return
+ except AttributeError:
+ self.in_msg=0
+ self.in_msg+=1
+ try:
+ self.line_just=max(self.line_just,len(msg))
+ except AttributeError:
+ self.line_just=max(40,len(msg))
+ for x in(self.line_just*'-',msg):
+ self.to_log(x)
+ Logs.pprint('NORMAL',"%s :"%msg.ljust(self.line_just),sep='')
+ def end_msg(self,*k,**kw):
+ if kw.get('quiet',None):
+ return
+ self.in_msg-=1
+ if self.in_msg:
+ return
+ result=kw.get('result',None)or k[0]
+ defcolor='GREEN'
+ if result==True:
+ msg='ok'
+ elif result==False:
+ msg='not found'
+ defcolor='YELLOW'
+ else:
+ msg=str(result)
+ self.to_log(msg)
+ try:
+ color=kw['color']
+ except KeyError:
+ if len(k)>1 and k[1]in Logs.colors_lst:
+ color=k[1]
+ else:
+ color=defcolor
+ Logs.pprint(color,msg)
+ def load_special_tools(self,var,ban=[]):
+ global waf_dir
+ if os.path.isdir(waf_dir):
+ lst=self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var)
+ for x in lst:
+ if not x.name in ban:
+ load_tool(x.name.replace('.py',''))
+ else:
+ from zipfile import PyZipFile
+ waflibs=PyZipFile(waf_dir)
+ lst=waflibs.namelist()
+ for x in lst:
+ if not re.match("waflib/extras/%s"%var.replace("*",".*"),var):
+ continue
+ f=os.path.basename(x)
+ doban=False
+ for b in ban:
+ r=b.replace("*",".*")
+ if re.match(r,f):
+ doban=True
+ if not doban:
+ f=f.replace('.py','')
+ load_tool(f)
+cache_modules={}
+def load_module(path,encoding=None):
+ try:
+ return cache_modules[path]
+ except KeyError:
+ pass
+ module=imp.new_module(WSCRIPT_FILE)
+ try:
+ code=Utils.readf(path,m='rU',encoding=encoding)
+ except EnvironmentError:
+ raise Errors.WafError('Could not read the file %r'%path)
+ module_dir=os.path.dirname(path)
+ sys.path.insert(0,module_dir)
+ try:exec(compile(code,path,'exec'),module.__dict__)
+ finally:sys.path.remove(module_dir)
+ cache_modules[path]=module
+ return module
+def load_tool(tool,tooldir=None,ctx=None,with_sys_path=True):
+ if tool=='java':
+ tool='javaw'
+ else:
+ tool=tool.replace('++','xx')
+ origSysPath=sys.path
+ if not with_sys_path:sys.path=[]
+ try:
+ if tooldir:
+ assert isinstance(tooldir,list)
+ sys.path=tooldir+sys.path
+ try:
+ __import__(tool)
+ finally:
+ for d in tooldir:
+ sys.path.remove(d)
+ ret=sys.modules[tool]
+ Context.tools[tool]=ret
+ return ret
+ else:
+ if not with_sys_path:sys.path.insert(0,waf_dir)
+ try:
+ for x in('waflib.Tools.%s','waflib.extras.%s','waflib.%s','%s'):
+ try:
+ __import__(x%tool)
+ break
+ except ImportError:
+ x=None
+ if x is None:
+ __import__(tool)
+ finally:
+ if not with_sys_path:sys.path.remove(waf_dir)
+ ret=sys.modules[x%tool]
+ Context.tools[tool]=ret
+ return ret
+ finally:
+ if not with_sys_path:sys.path+=origSysPath
diff --git a/waflib/Errors.py b/waflib/Errors.py
new file mode 100644
index 0000000..3d98c8d
--- /dev/null
+++ b/waflib/Errors.py
@@ -0,0 +1,37 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import traceback,sys
+class WafError(Exception):
+ def __init__(self,msg='',ex=None):
+ self.msg=msg
+ assert not isinstance(msg,Exception)
+ self.stack=[]
+ if ex:
+ if not msg:
+ self.msg=str(ex)
+ if isinstance(ex,WafError):
+ self.stack=ex.stack
+ else:
+ self.stack=traceback.extract_tb(sys.exc_info()[2])
+ self.stack+=traceback.extract_stack()[:-1]
+ self.verbose_msg=''.join(traceback.format_list(self.stack))
+ def __str__(self):
+ return str(self.msg)
+class BuildError(WafError):
+ def __init__(self,error_tasks=[]):
+ self.tasks=error_tasks
+ WafError.__init__(self,self.format_error())
+ def format_error(self):
+ lst=['Build failed']
+ for tsk in self.tasks:
+ txt=tsk.format_error()
+ if txt:lst.append(txt)
+ return'\n'.join(lst)
+class ConfigurationError(WafError):
+ pass
+class TaskRescan(WafError):
+ pass
+class TaskNotReady(WafError):
+ pass
diff --git a/waflib/Logs.py b/waflib/Logs.py
new file mode 100644
index 0000000..06ac7dd
--- /dev/null
+++ b/waflib/Logs.py
@@ -0,0 +1,199 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,traceback,sys
+from waflib import Utils,ansiterm
+if not os.environ.get('NOSYNC',False):
+ if sys.stdout.isatty()and id(sys.stdout)==id(sys.__stdout__):
+ sys.stdout=ansiterm.AnsiTerm(sys.stdout)
+ if sys.stderr.isatty()and id(sys.stderr)==id(sys.__stderr__):
+ sys.stderr=ansiterm.AnsiTerm(sys.stderr)
+import logging
+LOG_FORMAT=os.environ.get('WAF_LOG_FORMAT','%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s')
+HOUR_FORMAT=os.environ.get('WAF_HOUR_FORMAT','%H:%M:%S')
+zones=''
+verbose=0
+colors_lst={'USE':True,'BOLD':'\x1b[01;1m','RED':'\x1b[01;31m','GREEN':'\x1b[32m','YELLOW':'\x1b[33m','PINK':'\x1b[35m','BLUE':'\x1b[01;34m','CYAN':'\x1b[36m','GREY':'\x1b[37m','NORMAL':'\x1b[0m','cursor_on':'\x1b[?25h','cursor_off':'\x1b[?25l',}
+indicator='\r\x1b[K%s%s%s'
+try:
+ unicode
+except NameError:
+ unicode=None
+def enable_colors(use):
+ if use==1:
+ if not(sys.stderr.isatty()or sys.stdout.isatty()):
+ use=0
+ if Utils.is_win32 and os.name!='java':
+ term=os.environ.get('TERM','')
+ else:
+ term=os.environ.get('TERM','dumb')
+ if term in('dumb','emacs'):
+ use=0
+ if use>=1:
+ os.environ['TERM']='vt100'
+ colors_lst['USE']=use
+try:
+ get_term_cols=ansiterm.get_term_cols
+except AttributeError:
+ def get_term_cols():
+ return 80
+get_term_cols.__doc__="""
+ Get the console width in characters.
+
+ :return: the number of characters per line
+ :rtype: int
+ """
+def get_color(cl):
+ if not colors_lst['USE']:return''
+ return colors_lst.get(cl,'')
+class color_dict(object):
+ def __getattr__(self,a):
+ return get_color(a)
+ def __call__(self,a):
+ return get_color(a)
+colors=color_dict()
+re_log=re.compile(r'(\w+): (.*)',re.M)
+class log_filter(logging.Filter):
+ def __init__(self,name=None):
+ pass
+ def filter(self,rec):
+ rec.zone=rec.module
+ if rec.levelno>=logging.INFO:
+ return True
+ m=re_log.match(rec.msg)
+ if m:
+ rec.zone=m.group(1)
+ rec.msg=m.group(2)
+ if zones:
+ return getattr(rec,'zone','')in zones or'*'in zones
+ elif not verbose>2:
+ return False
+ return True
+class log_handler(logging.StreamHandler):
+ def emit(self,record):
+ try:
+ try:
+ self.stream=record.stream
+ except AttributeError:
+ if record.levelno>=logging.WARNING:
+ record.stream=self.stream=sys.stderr
+ else:
+ record.stream=self.stream=sys.stdout
+ self.emit_override(record)
+ self.flush()
+ except(KeyboardInterrupt,SystemExit):
+ raise
+ except:
+ self.handleError(record)
+ def emit_override(self,record,**kw):
+ self.terminator=getattr(record,'terminator','\n')
+ stream=self.stream
+ if unicode:
+ msg=self.formatter.format(record)
+ fs='%s'+self.terminator
+ try:
+ if(isinstance(msg,unicode)and getattr(stream,'encoding',None)):
+ fs=fs.decode(stream.encoding)
+ try:
+ stream.write(fs%msg)
+ except UnicodeEncodeError:
+ stream.write((fs%msg).encode(stream.encoding))
+ else:
+ stream.write(fs%msg)
+ except UnicodeError:
+ stream.write((fs%msg).encode('utf-8'))
+ else:
+ logging.StreamHandler.emit(self,record)
+class formatter(logging.Formatter):
+ def __init__(self):
+ logging.Formatter.__init__(self,LOG_FORMAT,HOUR_FORMAT)
+ def format(self,rec):
+ try:
+ msg=rec.msg.decode('utf-8')
+ except Exception:
+ msg=rec.msg
+ use=colors_lst['USE']
+ if(use==1 and rec.stream.isatty())or use==2:
+ c1=getattr(rec,'c1',None)
+ if c1 is None:
+ c1=''
+ if rec.levelno>=logging.ERROR:
+ c1=colors.RED
+ elif rec.levelno>=logging.WARNING:
+ c1=colors.YELLOW
+ elif rec.levelno>=logging.INFO:
+ c1=colors.GREEN
+ c2=getattr(rec,'c2',colors.NORMAL)
+ msg='%s%s%s'%(c1,msg,c2)
+ else:
+ msg=re.sub(r'\r(?!\n)|\x1B\[(K|.*?(m|h|l))','',msg)
+ if rec.levelno>=logging.INFO:
+ return msg
+ rec.msg=msg
+ rec.c1=colors.PINK
+ rec.c2=colors.NORMAL
+ return logging.Formatter.format(self,rec)
+log=None
+def debug(*k,**kw):
+ if verbose:
+ k=list(k)
+ k[0]=k[0].replace('\n',' ')
+ global log
+ log.debug(*k,**kw)
+def error(*k,**kw):
+ global log
+ log.error(*k,**kw)
+ if verbose>2:
+ st=traceback.extract_stack()
+ if st:
+ st=st[:-1]
+ buf=[]
+ for filename,lineno,name,line in st:
+ buf.append(' File "%s", line %d, in %s'%(filename,lineno,name))
+ if line:
+ buf.append(' %s'%line.strip())
+ if buf:log.error("\n".join(buf))
+def warn(*k,**kw):
+ global log
+ log.warn(*k,**kw)
+def info(*k,**kw):
+ global log
+ log.info(*k,**kw)
+def init_log():
+ global log
+ log=logging.getLogger('waflib')
+ log.handlers=[]
+ log.filters=[]
+ hdlr=log_handler()
+ hdlr.setFormatter(formatter())
+ log.addHandler(hdlr)
+ log.addFilter(log_filter())
+ log.setLevel(logging.DEBUG)
+def make_logger(path,name):
+ logger=logging.getLogger(name)
+ hdlr=logging.FileHandler(path,'w')
+ formatter=logging.Formatter('%(message)s')
+ hdlr.setFormatter(formatter)
+ logger.addHandler(hdlr)
+ logger.setLevel(logging.DEBUG)
+ return logger
+def make_mem_logger(name,to_log,size=8192):
+ from logging.handlers import MemoryHandler
+ logger=logging.getLogger(name)
+ hdlr=MemoryHandler(size,target=to_log)
+ formatter=logging.Formatter('%(message)s')
+ hdlr.setFormatter(formatter)
+ logger.addHandler(hdlr)
+ logger.memhandler=hdlr
+ logger.setLevel(logging.DEBUG)
+ return logger
+def free_logger(logger):
+ try:
+ for x in logger.handlers:
+ x.close()
+ logger.removeHandler(x)
+ except Exception:
+ pass
+def pprint(col,msg,label='',sep='\n'):
+ info("%s%s%s %s"%(colors(col),msg,colors.NORMAL,label),extra={'terminator':sep})
diff --git a/waflib/Node.py b/waflib/Node.py
new file mode 100644
index 0000000..85e3910
--- /dev/null
+++ b/waflib/Node.py
@@ -0,0 +1,491 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,sys,shutil
+from waflib import Utils,Errors
+exclude_regs='''
+**/*~
+**/#*#
+**/.#*
+**/%*%
+**/._*
+**/CVS
+**/CVS/**
+**/.cvsignore
+**/SCCS
+**/SCCS/**
+**/vssver.scc
+**/.svn
+**/.svn/**
+**/BitKeeper
+**/.git
+**/.git/**
+**/.gitignore
+**/.bzr
+**/.bzrignore
+**/.bzr/**
+**/.hg
+**/.hg/**
+**/_MTN
+**/_MTN/**
+**/.arch-ids
+**/{arch}
+**/_darcs
+**/_darcs/**
+**/.intlcache
+**/.DS_Store'''
+split_path=Utils.split_path
+split_path_unix=Utils.split_path_unix
+split_path_cygwin=Utils.split_path_cygwin
+split_path_win32=Utils.split_path_win32
+class Node(object):
+ dict_class=dict
+ __slots__=('name','sig','children','parent','cache_abspath','cache_isdir','cache_sig')
+ def __init__(self,name,parent):
+ self.name=name
+ self.parent=parent
+ if parent:
+ if name in parent.children:
+ raise Errors.WafError('node %s exists in the parent files %r already'%(name,parent))
+ parent.children[name]=self
+ def __setstate__(self,data):
+ self.name=data[0]
+ self.parent=data[1]
+ if data[2]is not None:
+ self.children=self.dict_class(data[2])
+ if data[3]is not None:
+ self.sig=data[3]
+ def __getstate__(self):
+ return(self.name,self.parent,getattr(self,'children',None),getattr(self,'sig',None))
+ def __str__(self):
+ return self.name
+ def __repr__(self):
+ return self.abspath()
+ def __hash__(self):
+ return id(self)
+ def __eq__(self,node):
+ return id(self)==id(node)
+ def __copy__(self):
+ raise Errors.WafError('nodes are not supposed to be copied')
+ def read(self,flags='r',encoding='ISO8859-1'):
+ return Utils.readf(self.abspath(),flags,encoding)
+ def write(self,data,flags='w',encoding='ISO8859-1'):
+ Utils.writef(self.abspath(),data,flags,encoding)
+ def read_json(self,convert=True,encoding='utf-8'):
+ import json
+ object_pairs_hook=None
+ if convert and sys.hexversion<0x3000000:
+ try:
+ _type=unicode
+ except NameError:
+ _type=str
+ def convert(value):
+ if isinstance(value,list):
+ return[convert(element)for element in value]
+ elif isinstance(value,_type):
+ return str(value)
+ else:
+ return value
+ def object_pairs(pairs):
+ return dict((str(pair[0]),convert(pair[1]))for pair in pairs)
+ object_pairs_hook=object_pairs
+ return json.loads(self.read(encoding=encoding),object_pairs_hook=object_pairs_hook)
+ def write_json(self,data,pretty=True):
+ import json
+ indent=2
+ separators=(',',': ')
+ sort_keys=pretty
+ newline=os.linesep
+ if not pretty:
+ indent=None
+ separators=(',',':')
+ newline=''
+ output=json.dumps(data,indent=indent,separators=separators,sort_keys=sort_keys)+newline
+ self.write(output,encoding='utf-8')
+ def chmod(self,val):
+ os.chmod(self.abspath(),val)
+ def delete(self):
+ try:
+ try:
+ if hasattr(self,'children'):
+ shutil.rmtree(self.abspath())
+ else:
+ os.remove(self.abspath())
+ except OSError ,e:
+ if os.path.exists(self.abspath()):
+ raise e
+ finally:
+ self.evict()
+ def evict(self):
+ del self.parent.children[self.name]
+ def suffix(self):
+ k=max(0,self.name.rfind('.'))
+ return self.name[k:]
+ def height(self):
+ d=self
+ val=-1
+ while d:
+ d=d.parent
+ val+=1
+ return val
+ def listdir(self):
+ lst=Utils.listdir(self.abspath())
+ lst.sort()
+ return lst
+ def mkdir(self):
+ if getattr(self,'cache_isdir',None):
+ return
+ try:
+ self.parent.mkdir()
+ except OSError:
+ pass
+ if self.name:
+ try:
+ os.makedirs(self.abspath())
+ except OSError:
+ pass
+ if not os.path.isdir(self.abspath()):
+ raise Errors.WafError('Could not create the directory %s'%self.abspath())
+ try:
+ self.children
+ except AttributeError:
+ self.children=self.dict_class()
+ self.cache_isdir=True
+ def find_node(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ cur=self
+ for x in lst:
+ if x=='..':
+ cur=cur.parent or cur
+ continue
+ try:
+ ch=cur.children
+ except AttributeError:
+ cur.children=self.dict_class()
+ else:
+ try:
+ cur=ch[x]
+ continue
+ except KeyError:
+ pass
+ cur=self.__class__(x,cur)
+ try:
+ os.stat(cur.abspath())
+ except OSError:
+ cur.evict()
+ return None
+ ret=cur
+ try:
+ os.stat(ret.abspath())
+ except OSError:
+ ret.evict()
+ return None
+ try:
+ while not getattr(cur.parent,'cache_isdir',None):
+ cur=cur.parent
+ cur.cache_isdir=True
+ except AttributeError:
+ pass
+ return ret
+ def make_node(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ cur=self
+ for x in lst:
+ if x=='..':
+ cur=cur.parent or cur
+ continue
+ if getattr(cur,'children',{}):
+ if x in cur.children:
+ cur=cur.children[x]
+ continue
+ else:
+ cur.children=self.dict_class()
+ cur=self.__class__(x,cur)
+ return cur
+ def search_node(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ cur=self
+ for x in lst:
+ if x=='..':
+ cur=cur.parent or cur
+ else:
+ try:
+ cur=cur.children[x]
+ except(AttributeError,KeyError):
+ return None
+ return cur
+ def path_from(self,node):
+ c1=self
+ c2=node
+ c1h=c1.height()
+ c2h=c2.height()
+ lst=[]
+ up=0
+ while c1h>c2h:
+ lst.append(c1.name)
+ c1=c1.parent
+ c1h-=1
+ while c2h>c1h:
+ up+=1
+ c2=c2.parent
+ c2h-=1
+ while id(c1)!=id(c2):
+ lst.append(c1.name)
+ up+=1
+ c1=c1.parent
+ c2=c2.parent
+ if c1.parent:
+ for i in range(up):
+ lst.append('..')
+ else:
+ if lst and not Utils.is_win32:
+ lst.append('')
+ lst.reverse()
+ return os.sep.join(lst)or'.'
+ def abspath(self):
+ try:
+ return self.cache_abspath
+ except AttributeError:
+ pass
+ if not self.parent:
+ val=os.sep
+ elif not self.parent.name:
+ val=os.sep+self.name
+ else:
+ val=self.parent.abspath()+os.sep+self.name
+ self.cache_abspath=val
+ return val
+ if Utils.is_win32:
+ def abspath(self):
+ try:
+ return self.cache_abspath
+ except AttributeError:
+ pass
+ if not self.parent:
+ val=''
+ elif not self.parent.name:
+ val=self.name+os.sep
+ else:
+ val=self.parent.abspath().rstrip(os.sep)+os.sep+self.name
+ self.cache_abspath=val
+ return val
+ def is_child_of(self,node):
+ p=self
+ diff=self.height()-node.height()
+ while diff>0:
+ diff-=1
+ p=p.parent
+ return id(p)==id(node)
+ def ant_iter(self,accept=None,maxdepth=25,pats=[],dir=False,src=True,remove=True):
+ dircont=self.listdir()
+ dircont.sort()
+ try:
+ lst=set(self.children.keys())
+ except AttributeError:
+ self.children=self.dict_class()
+ else:
+ if remove:
+ for x in lst-set(dircont):
+ self.children[x].evict()
+ for name in dircont:
+ npats=accept(name,pats)
+ if npats and npats[0]:
+ accepted=[]in npats[0]
+ node=self.make_node([name])
+ isdir=os.path.isdir(node.abspath())
+ if accepted:
+ if isdir:
+ if dir:
+ yield node
+ else:
+ if src:
+ yield node
+ if getattr(node,'cache_isdir',None)or isdir:
+ node.cache_isdir=True
+ if maxdepth:
+ for k in node.ant_iter(accept=accept,maxdepth=maxdepth-1,pats=npats,dir=dir,src=src,remove=remove):
+ yield k
+ raise StopIteration
+ def ant_glob(self,*k,**kw):
+ src=kw.get('src',True)
+ dir=kw.get('dir',False)
+ excl=kw.get('excl',exclude_regs)
+ incl=k and k[0]or kw.get('incl','**')
+ reflags=kw.get('ignorecase',0)and re.I
+ def to_pat(s):
+ lst=Utils.to_list(s)
+ ret=[]
+ for x in lst:
+ x=x.replace('\\','/').replace('//','/')
+ if x.endswith('/'):
+ x+='**'
+ lst2=x.split('/')
+ accu=[]
+ for k in lst2:
+ if k=='**':
+ accu.append(k)
+ else:
+ k=k.replace('.','[.]').replace('*','.*').replace('?','.').replace('+','\\+')
+ k='^%s$'%k
+ try:
+ accu.append(re.compile(k,flags=reflags))
+ except Exception ,e:
+ raise Errors.WafError("Invalid pattern: %s"%k,e)
+ ret.append(accu)
+ return ret
+ def filtre(name,nn):
+ ret=[]
+ for lst in nn:
+ if not lst:
+ pass
+ elif lst[0]=='**':
+ ret.append(lst)
+ if len(lst)>1:
+ if lst[1].match(name):
+ ret.append(lst[2:])
+ else:
+ ret.append([])
+ elif lst[0].match(name):
+ ret.append(lst[1:])
+ return ret
+ def accept(name,pats):
+ nacc=filtre(name,pats[0])
+ nrej=filtre(name,pats[1])
+ if[]in nrej:
+ nacc=[]
+ return[nacc,nrej]
+ ret=[x for x in self.ant_iter(accept=accept,pats=[to_pat(incl),to_pat(excl)],maxdepth=kw.get('maxdepth',25),dir=dir,src=src,remove=kw.get('remove',True))]
+ if kw.get('flat',False):
+ return' '.join([x.path_from(self)for x in ret])
+ return ret
+ def is_src(self):
+ cur=self
+ x=id(self.ctx.srcnode)
+ y=id(self.ctx.bldnode)
+ while cur.parent:
+ if id(cur)==y:
+ return False
+ if id(cur)==x:
+ return True
+ cur=cur.parent
+ return False
+ def is_bld(self):
+ cur=self
+ y=id(self.ctx.bldnode)
+ while cur.parent:
+ if id(cur)==y:
+ return True
+ cur=cur.parent
+ return False
+ def get_src(self):
+ cur=self
+ x=id(self.ctx.srcnode)
+ y=id(self.ctx.bldnode)
+ lst=[]
+ while cur.parent:
+ if id(cur)==y:
+ lst.reverse()
+ return self.ctx.srcnode.make_node(lst)
+ if id(cur)==x:
+ return self
+ lst.append(cur.name)
+ cur=cur.parent
+ return self
+ def get_bld(self):
+ cur=self
+ x=id(self.ctx.srcnode)
+ y=id(self.ctx.bldnode)
+ lst=[]
+ while cur.parent:
+ if id(cur)==y:
+ return self
+ if id(cur)==x:
+ lst.reverse()
+ return self.ctx.bldnode.make_node(lst)
+ lst.append(cur.name)
+ cur=cur.parent
+ lst.reverse()
+ if lst and Utils.is_win32 and len(lst[0])==2 and lst[0].endswith(':'):
+ lst[0]=lst[0][0]
+ return self.ctx.bldnode.make_node(['__root__']+lst)
+ def find_resource(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ node=self.get_bld().search_node(lst)
+ if not node:
+ self=self.get_src()
+ node=self.find_node(lst)
+ if node:
+ if os.path.isdir(node.abspath()):
+ return None
+ return node
+ def find_or_declare(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ node=self.get_bld().search_node(lst)
+ if node:
+ if not os.path.isfile(node.abspath()):
+ node.sig=None
+ node.parent.mkdir()
+ return node
+ self=self.get_src()
+ node=self.find_node(lst)
+ if node:
+ if not os.path.isfile(node.abspath()):
+ node.sig=None
+ node.parent.mkdir()
+ return node
+ node=self.get_bld().make_node(lst)
+ node.parent.mkdir()
+ return node
+ def find_dir(self,lst):
+ if isinstance(lst,str):
+ lst=[x for x in split_path(lst)if x and x!='.']
+ node=self.find_node(lst)
+ try:
+ if not os.path.isdir(node.abspath()):
+ return None
+ except(OSError,AttributeError):
+ return None
+ return node
+ def change_ext(self,ext,ext_in=None):
+ name=self.name
+ if ext_in is None:
+ k=name.rfind('.')
+ if k>=0:
+ name=name[:k]+ext
+ else:
+ name=name+ext
+ else:
+ name=name[:-len(ext_in)]+ext
+ return self.parent.find_or_declare([name])
+ def bldpath(self):
+ return self.path_from(self.ctx.bldnode)
+ def srcpath(self):
+ return self.path_from(self.ctx.srcnode)
+ def relpath(self):
+ cur=self
+ x=id(self.ctx.bldnode)
+ while cur.parent:
+ if id(cur)==x:
+ return self.bldpath()
+ cur=cur.parent
+ return self.srcpath()
+ def bld_dir(self):
+ return self.parent.bldpath()
+ def get_bld_sig(self):
+ try:
+ return self.cache_sig
+ except AttributeError:
+ pass
+ if not self.is_bld()or self.ctx.bldnode is self.ctx.srcnode:
+ self.sig=Utils.h_file(self.abspath())
+ self.cache_sig=ret=self.sig
+ return ret
+pickle_lock=Utils.threading.Lock()
+class Nod3(Node):
+ pass
diff --git a/waflib/Options.py b/waflib/Options.py
new file mode 100644
index 0000000..5101f5f
--- /dev/null
+++ b/waflib/Options.py
@@ -0,0 +1,147 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,tempfile,optparse,sys,re
+from waflib import Logs,Utils,Context
+cmds='distclean configure build install clean uninstall check dist distcheck'.split()
+options={}
+commands=[]
+envvars=[]
+lockfile=os.environ.get('WAFLOCK','.lock-waf_%s_build'%sys.platform)
+platform=Utils.unversioned_sys_platform()
+class opt_parser(optparse.OptionParser):
+ def __init__(self,ctx):
+ optparse.OptionParser.__init__(self,conflict_handler="resolve",version='waf %s (%s)'%(Context.WAFVERSION,Context.WAFREVISION))
+ self.formatter.width=Logs.get_term_cols()
+ self.ctx=ctx
+ def print_usage(self,file=None):
+ return self.print_help(file)
+ def get_usage(self):
+ cmds_str={}
+ for cls in Context.classes:
+ if not cls.cmd or cls.cmd=='options'or cls.cmd.startswith('_'):
+ continue
+ s=cls.__doc__ or''
+ cmds_str[cls.cmd]=s
+ if Context.g_module:
+ for(k,v)in Context.g_module.__dict__.items():
+ if k in('options','init','shutdown'):
+ continue
+ if type(v)is type(Context.create_context):
+ if v.__doc__ and not k.startswith('_'):
+ cmds_str[k]=v.__doc__
+ just=0
+ for k in cmds_str:
+ just=max(just,len(k))
+ lst=[' %s: %s'%(k.ljust(just),v)for(k,v)in cmds_str.items()]
+ lst.sort()
+ ret='\n'.join(lst)
+ return'''waf [commands] [options]
+
+Main commands (example: ./waf build -j4)
+%s
+'''%ret
+class OptionsContext(Context.Context):
+ cmd='options'
+ fun='options'
+ def __init__(self,**kw):
+ super(OptionsContext,self).__init__(**kw)
+ self.parser=opt_parser(self)
+ self.option_groups={}
+ jobs=self.jobs()
+ p=self.add_option
+ color=os.environ.get('NOCOLOR','')and'no'or'auto'
+ p('-c','--color',dest='colors',default=color,action='store',help='whether to use colors (yes/no/auto) [default: auto]',choices=('yes','no','auto'))
+ p('-j','--jobs',dest='jobs',default=jobs,type='int',help='amount of parallel jobs (%r)'%jobs)
+ p('-k','--keep',dest='keep',default=0,action='count',help='continue despite errors (-kk to try harder)')
+ p('-v','--verbose',dest='verbose',default=0,action='count',help='verbosity level -v -vv or -vvv [default: 0]')
+ p('--zones',dest='zones',default='',action='store',help='debugging zones (task_gen, deps, tasks, etc)')
+ gr=self.add_option_group('Configuration options')
+ self.option_groups['configure options']=gr
+ gr.add_option('-o','--out',action='store',default='',help='build dir for the project',dest='out')
+ gr.add_option('-t','--top',action='store',default='',help='src dir for the project',dest='top')
+ gr.add_option('--no-lock-in-run',action='store_true',default='',help=optparse.SUPPRESS_HELP,dest='no_lock_in_run')
+ gr.add_option('--no-lock-in-out',action='store_true',default='',help=optparse.SUPPRESS_HELP,dest='no_lock_in_out')
+ gr.add_option('--no-lock-in-top',action='store_true',default='',help=optparse.SUPPRESS_HELP,dest='no_lock_in_top')
+ default_prefix=getattr(Context.g_module,'default_prefix',os.environ.get('PREFIX'))
+ if not default_prefix:
+ if platform=='win32':
+ d=tempfile.gettempdir()
+ default_prefix=d[0].upper()+d[1:]
+ else:
+ default_prefix='/usr/local/'
+ gr.add_option('--prefix',dest='prefix',default=default_prefix,help='installation prefix [default: %r]'%default_prefix)
+ gr.add_option('--bindir',dest='bindir',help='bindir')
+ gr.add_option('--libdir',dest='libdir',help='libdir')
+ gr=self.add_option_group('Build and installation options')
+ self.option_groups['build and install options']=gr
+ gr.add_option('-p','--progress',dest='progress_bar',default=0,action='count',help='-p: progress bar; -pp: ide output')
+ gr.add_option('--targets',dest='targets',default='',action='store',help='task generators, e.g. "target1,target2"')
+ gr=self.add_option_group('Step options')
+ self.option_groups['step options']=gr
+ gr.add_option('--files',dest='files',default='',action='store',help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
+ default_destdir=os.environ.get('DESTDIR','')
+ gr=self.add_option_group('Installation and uninstallation options')
+ self.option_groups['install/uninstall options']=gr
+ gr.add_option('--destdir',help='installation root [default: %r]'%default_destdir,default=default_destdir,dest='destdir')
+ gr.add_option('-f','--force',dest='force',default=False,action='store_true',help='force file installation')
+ gr.add_option('--distcheck-args',metavar='ARGS',help='arguments to pass to distcheck',default=None,action='store')
+ def jobs(self):
+ count=int(os.environ.get('JOBS',0))
+ if count<1:
+ if'NUMBER_OF_PROCESSORS'in os.environ:
+ count=int(os.environ.get('NUMBER_OF_PROCESSORS',1))
+ else:
+ if hasattr(os,'sysconf_names'):
+ if'SC_NPROCESSORS_ONLN'in os.sysconf_names:
+ count=int(os.sysconf('SC_NPROCESSORS_ONLN'))
+ elif'SC_NPROCESSORS_CONF'in os.sysconf_names:
+ count=int(os.sysconf('SC_NPROCESSORS_CONF'))
+ if not count and os.name not in('nt','java'):
+ try:
+ tmp=self.cmd_and_log(['sysctl','-n','hw.ncpu'],quiet=0)
+ except Exception:
+ pass
+ else:
+ if re.match('^[0-9]+$',tmp):
+ count=int(tmp)
+ if count<1:
+ count=1
+ elif count>1024:
+ count=1024
+ return count
+ def add_option(self,*k,**kw):
+ return self.parser.add_option(*k,**kw)
+ def add_option_group(self,*k,**kw):
+ try:
+ gr=self.option_groups[k[0]]
+ except KeyError:
+ gr=self.parser.add_option_group(*k,**kw)
+ self.option_groups[k[0]]=gr
+ return gr
+ def get_option_group(self,opt_str):
+ try:
+ return self.option_groups[opt_str]
+ except KeyError:
+ for group in self.parser.option_groups:
+ if group.title==opt_str:
+ return group
+ return None
+ def parse_args(self,_args=None):
+ global options,commands,envvars
+ (options,leftover_args)=self.parser.parse_args(args=_args)
+ for arg in leftover_args:
+ if'='in arg:
+ envvars.append(arg)
+ else:
+ commands.append(arg)
+ if options.destdir:
+ options.destdir=Utils.sane_path(options.destdir)
+ if options.verbose>=1:
+ self.load('errcheck')
+ colors={'yes':2,'auto':1,'no':0}[options.colors]
+ Logs.enable_colors(colors)
+ def execute(self):
+ super(OptionsContext,self).execute()
+ self.parse_args()
diff --git a/waflib/Runner.py b/waflib/Runner.py
new file mode 100644
index 0000000..c22503e
--- /dev/null
+++ b/waflib/Runner.py
@@ -0,0 +1,207 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import random,atexit
+try:
+ from queue import Queue
+except ImportError:
+ from Queue import Queue
+from waflib import Utils,Task,Errors,Logs
+GAP=10
+class TaskConsumer(Utils.threading.Thread):
+ def __init__(self):
+ Utils.threading.Thread.__init__(self)
+ self.ready=Queue()
+ self.setDaemon(1)
+ self.start()
+ def run(self):
+ try:
+ self.loop()
+ except Exception:
+ pass
+ def loop(self):
+ while 1:
+ tsk=self.ready.get()
+ if not isinstance(tsk,Task.TaskBase):
+ tsk(self)
+ else:
+ tsk.process()
+pool=Queue()
+def get_pool():
+ try:
+ return pool.get(False)
+ except Exception:
+ return TaskConsumer()
+def put_pool(x):
+ pool.put(x)
+def _free_resources():
+ global pool
+ lst=[]
+ while pool.qsize():
+ lst.append(pool.get())
+ for x in lst:
+ x.ready.put(None)
+ for x in lst:
+ x.join()
+ pool=None
+atexit.register(_free_resources)
+class Parallel(object):
+ def __init__(self,bld,j=2):
+ self.numjobs=j
+ self.bld=bld
+ self.outstanding=[]
+ self.frozen=[]
+ self.out=Queue(0)
+ self.count=0
+ self.processed=1
+ self.stop=False
+ self.error=[]
+ self.biter=None
+ self.dirty=False
+ def get_next_task(self):
+ if not self.outstanding:
+ return None
+ return self.outstanding.pop(0)
+ def postpone(self,tsk):
+ if random.randint(0,1):
+ self.frozen.insert(0,tsk)
+ else:
+ self.frozen.append(tsk)
+ def refill_task_list(self):
+ while self.count>self.numjobs*GAP:
+ self.get_out()
+ while not self.outstanding:
+ if self.count:
+ self.get_out()
+ elif self.frozen:
+ try:
+ cond=self.deadlock==self.processed
+ except AttributeError:
+ pass
+ else:
+ if cond:
+ msg='check the build order for the tasks'
+ for tsk in self.frozen:
+ if not tsk.run_after:
+ msg='check the methods runnable_status'
+ break
+ lst=[]
+ for tsk in self.frozen:
+ lst.append('%s\t-> %r'%(repr(tsk),[id(x)for x in tsk.run_after]))
+ raise Errors.WafError('Deadlock detected: %s%s'%(msg,''.join(lst)))
+ self.deadlock=self.processed
+ if self.frozen:
+ self.outstanding+=self.frozen
+ self.frozen=[]
+ elif not self.count:
+ self.outstanding.extend(self.biter.next())
+ self.total=self.bld.total()
+ break
+ def add_more_tasks(self,tsk):
+ if getattr(tsk,'more_tasks',None):
+ self.outstanding+=tsk.more_tasks
+ self.total+=len(tsk.more_tasks)
+ def get_out(self):
+ tsk=self.out.get()
+ if not self.stop:
+ self.add_more_tasks(tsk)
+ self.count-=1
+ self.dirty=True
+ return tsk
+ def add_task(self,tsk):
+ try:
+ self.pool
+ except AttributeError:
+ self.init_task_pool()
+ self.ready.put(tsk)
+ def init_task_pool(self):
+ pool=self.pool=[get_pool()for i in range(self.numjobs)]
+ self.ready=Queue(0)
+ def setq(consumer):
+ consumer.ready=self.ready
+ for x in pool:
+ x.ready.put(setq)
+ return pool
+ def free_task_pool(self):
+ def setq(consumer):
+ consumer.ready=Queue(0)
+ self.out.put(self)
+ try:
+ pool=self.pool
+ except AttributeError:
+ pass
+ else:
+ for x in pool:
+ self.ready.put(setq)
+ for x in pool:
+ self.get_out()
+ for x in pool:
+ put_pool(x)
+ self.pool=[]
+ def skip(self,tsk):
+ tsk.hasrun=Task.SKIPPED
+ def error_handler(self,tsk):
+ if hasattr(tsk,'scan')and hasattr(tsk,'uid'):
+ key=(tsk.uid(),'imp')
+ try:
+ del self.bld.task_sigs[key]
+ except KeyError:
+ pass
+ if not self.bld.keep:
+ self.stop=True
+ self.error.append(tsk)
+ def task_status(self,tsk):
+ try:
+ return tsk.runnable_status()
+ except Exception:
+ self.processed+=1
+ tsk.err_msg=Utils.ex_stack()
+ if not self.stop and self.bld.keep:
+ self.skip(tsk)
+ if self.bld.keep==1:
+ if Logs.verbose>1 or not self.error:
+ self.error.append(tsk)
+ self.stop=True
+ else:
+ if Logs.verbose>1:
+ self.error.append(tsk)
+ return Task.EXCEPTION
+ tsk.hasrun=Task.EXCEPTION
+ self.error_handler(tsk)
+ return Task.EXCEPTION
+ def start(self):
+ self.total=self.bld.total()
+ while not self.stop:
+ self.refill_task_list()
+ tsk=self.get_next_task()
+ if not tsk:
+ if self.count:
+ continue
+ else:
+ break
+ if tsk.hasrun:
+ self.processed+=1
+ continue
+ if self.stop:
+ break
+ st=self.task_status(tsk)
+ if st==Task.RUN_ME:
+ tsk.position=(self.processed,self.total)
+ self.count+=1
+ tsk.master=self
+ self.processed+=1
+ if self.numjobs==1:
+ tsk.process()
+ else:
+ self.add_task(tsk)
+ if st==Task.ASK_LATER:
+ self.postpone(tsk)
+ elif st==Task.SKIP_ME:
+ self.processed+=1
+ self.skip(tsk)
+ self.add_more_tasks(tsk)
+ while self.error and self.count:
+ self.get_out()
+ assert(self.count==0 or self.stop)
+ self.free_task_pool()
diff --git a/waflib/Scripting.py b/waflib/Scripting.py
new file mode 100644
index 0000000..7798bb0
--- /dev/null
+++ b/waflib/Scripting.py
@@ -0,0 +1,418 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,shlex,shutil,traceback,errno,sys,stat
+from waflib import Utils,Configure,Logs,Options,ConfigSet,Context,Errors,Build,Node
+build_dir_override=None
+no_climb_commands=['configure']
+default_cmd="build"
+def waf_entry_point(current_directory,version,wafdir):
+ Logs.init_log()
+ if Context.WAFVERSION!=version:
+ Logs.error('Waf script %r and library %r do not match (directory %r)'%(version,Context.WAFVERSION,wafdir))
+ sys.exit(1)
+ if'--version'in sys.argv:
+ Context.run_dir=current_directory
+ ctx=Context.create_context('options')
+ ctx.curdir=current_directory
+ ctx.parse_args()
+ sys.exit(0)
+ if len(sys.argv)>1:
+ potential_wscript=os.path.join(current_directory,sys.argv[1])
+ if os.path.basename(potential_wscript)=='wscript'and os.path.isfile(potential_wscript):
+ current_directory=os.path.normpath(os.path.dirname(potential_wscript))
+ sys.argv.pop(1)
+ Context.waf_dir=wafdir
+ Context.launch_dir=current_directory
+ no_climb=os.environ.get('NOCLIMB',None)
+ if not no_climb:
+ for k in no_climb_commands:
+ for y in sys.argv:
+ if y.startswith(k):
+ no_climb=True
+ break
+ for i,x in enumerate(sys.argv):
+ if x.startswith('--top='):
+ Context.run_dir=Context.top_dir=Utils.sane_path(x[6:])
+ sys.argv[i]='--top='+Context.run_dir
+ if x.startswith('--out='):
+ Context.out_dir=Utils.sane_path(x[6:])
+ sys.argv[i]='--out='+Context.out_dir
+ cur=current_directory
+ while cur and not Context.top_dir:
+ try:
+ lst=os.listdir(cur)
+ except OSError:
+ lst=[]
+ Logs.error('Directory %r is unreadable!'%cur)
+ if Options.lockfile in lst:
+ env=ConfigSet.ConfigSet()
+ try:
+ env.load(os.path.join(cur,Options.lockfile))
+ ino=os.stat(cur)[stat.ST_INO]
+ except Exception:
+ pass
+ else:
+ for x in(env.run_dir,env.top_dir,env.out_dir):
+ if Utils.is_win32:
+ if cur==x:
+ load=True
+ break
+ else:
+ try:
+ ino2=os.stat(x)[stat.ST_INO]
+ except OSError:
+ pass
+ else:
+ if ino==ino2:
+ load=True
+ break
+ else:
+ Logs.warn('invalid lock file in %s'%cur)
+ load=False
+ if load:
+ Context.run_dir=env.run_dir
+ Context.top_dir=env.top_dir
+ Context.out_dir=env.out_dir
+ break
+ if not Context.run_dir:
+ if Context.WSCRIPT_FILE in lst:
+ Context.run_dir=cur
+ next=os.path.dirname(cur)
+ if next==cur:
+ break
+ cur=next
+ if no_climb:
+ break
+ if not Context.run_dir:
+ if'-h'in sys.argv or'--help'in sys.argv:
+ Logs.warn('No wscript file found: the help message may be incomplete')
+ Context.run_dir=current_directory
+ ctx=Context.create_context('options')
+ ctx.curdir=current_directory
+ ctx.parse_args()
+ sys.exit(0)
+ Logs.error('Waf: Run from a directory containing a file named %r'%Context.WSCRIPT_FILE)
+ sys.exit(1)
+ try:
+ os.chdir(Context.run_dir)
+ except OSError:
+ Logs.error('Waf: The folder %r is unreadable'%Context.run_dir)
+ sys.exit(1)
+ try:
+ set_main_module(os.path.normpath(os.path.join(Context.run_dir,Context.WSCRIPT_FILE)))
+ except Errors.WafError ,e:
+ Logs.pprint('RED',e.verbose_msg)
+ Logs.error(str(e))
+ sys.exit(1)
+ except Exception ,e:
+ Logs.error('Waf: The wscript in %r is unreadable'%Context.run_dir,e)
+ traceback.print_exc(file=sys.stdout)
+ sys.exit(2)
+ try:
+ run_commands()
+ except Errors.WafError ,e:
+ if Logs.verbose>1:
+ Logs.pprint('RED',e.verbose_msg)
+ Logs.error(e.msg)
+ sys.exit(1)
+ except SystemExit:
+ raise
+ except Exception ,e:
+ traceback.print_exc(file=sys.stdout)
+ sys.exit(2)
+ except KeyboardInterrupt:
+ Logs.pprint('RED','Interrupted')
+ sys.exit(68)
+def set_main_module(file_path):
+ Context.g_module=Context.load_module(file_path)
+ Context.g_module.root_path=file_path
+ def set_def(obj):
+ name=obj.__name__
+ if not name in Context.g_module.__dict__:
+ setattr(Context.g_module,name,obj)
+ for k in(update,dist,distclean,distcheck):
+ set_def(k)
+ if not'init'in Context.g_module.__dict__:
+ Context.g_module.init=Utils.nada
+ if not'shutdown'in Context.g_module.__dict__:
+ Context.g_module.shutdown=Utils.nada
+ if not'options'in Context.g_module.__dict__:
+ Context.g_module.options=Utils.nada
+def parse_options():
+ Context.create_context('options').execute()
+ for var in Options.envvars:
+ (name,value)=var.split('=',1)
+ os.environ[name.strip()]=value
+ if not Options.commands:
+ Options.commands=[default_cmd]
+ Options.commands=[x for x in Options.commands if x!='options']
+ Logs.verbose=Options.options.verbose
+ if Options.options.zones:
+ Logs.zones=Options.options.zones.split(',')
+ if not Logs.verbose:
+ Logs.verbose=1
+ elif Logs.verbose>0:
+ Logs.zones=['runner']
+ if Logs.verbose>2:
+ Logs.zones=['*']
+def run_command(cmd_name):
+ ctx=Context.create_context(cmd_name)
+ ctx.log_timer=Utils.Timer()
+ ctx.options=Options.options
+ ctx.cmd=cmd_name
+ try:
+ ctx.execute()
+ finally:
+ ctx.finalize()
+ return ctx
+def run_commands():
+ parse_options()
+ run_command('init')
+ while Options.commands:
+ cmd_name=Options.commands.pop(0)
+ ctx=run_command(cmd_name)
+ Logs.info('%r finished successfully (%s)'%(cmd_name,str(ctx.log_timer)))
+ run_command('shutdown')
+def _can_distclean(name):
+ for k in'.o .moc .exe'.split():
+ if name.endswith(k):
+ return True
+ return False
+def distclean_dir(dirname):
+ for(root,dirs,files)in os.walk(dirname):
+ for f in files:
+ if _can_distclean(f):
+ fname=os.path.join(root,f)
+ try:
+ os.remove(fname)
+ except OSError:
+ Logs.warn('Could not remove %r'%fname)
+ for x in(Context.DBFILE,'config.log'):
+ try:
+ os.remove(x)
+ except OSError:
+ pass
+ try:
+ shutil.rmtree('c4che')
+ except OSError:
+ pass
+def distclean(ctx):
+ '''removes the build directory'''
+ lst=os.listdir('.')
+ for f in lst:
+ if f==Options.lockfile:
+ try:
+ proj=ConfigSet.ConfigSet(f)
+ except IOError:
+ Logs.warn('Could not read %r'%f)
+ continue
+ if proj['out_dir']!=proj['top_dir']:
+ try:
+ shutil.rmtree(proj['out_dir'])
+ except IOError:
+ pass
+ except OSError ,e:
+ if e.errno!=errno.ENOENT:
+ Logs.warn('Could not remove %r'%proj['out_dir'])
+ else:
+ distclean_dir(proj['out_dir'])
+ for k in(proj['out_dir'],proj['top_dir'],proj['run_dir']):
+ p=os.path.join(k,Options.lockfile)
+ try:
+ os.remove(p)
+ except OSError ,e:
+ if e.errno!=errno.ENOENT:
+ Logs.warn('Could not remove %r'%p)
+ if not Options.commands:
+ for x in'.waf-1. waf-1. .waf3-1. waf3-1.'.split():
+ if f.startswith(x):
+ shutil.rmtree(f,ignore_errors=True)
+class Dist(Context.Context):
+ '''creates an archive containing the project source code'''
+ cmd='dist'
+ fun='dist'
+ algo='tar.bz2'
+ ext_algo={}
+ def execute(self):
+ self.recurse([os.path.dirname(Context.g_module.root_path)])
+ self.archive()
+ def archive(self):
+ import tarfile
+ arch_name=self.get_arch_name()
+ try:
+ self.base_path
+ except AttributeError:
+ self.base_path=self.path
+ node=self.base_path.make_node(arch_name)
+ try:
+ node.delete()
+ except OSError:
+ pass
+ files=self.get_files()
+ if self.algo.startswith('tar.'):
+ tar=tarfile.open(arch_name,'w:'+self.algo.replace('tar.',''))
+ for x in files:
+ self.add_tar_file(x,tar)
+ tar.close()
+ elif self.algo=='zip':
+ import zipfile
+ zip=zipfile.ZipFile(arch_name,'w',compression=zipfile.ZIP_DEFLATED)
+ for x in files:
+ archive_name=self.get_base_name()+'/'+x.path_from(self.base_path)
+ zip.write(x.abspath(),archive_name,zipfile.ZIP_DEFLATED)
+ zip.close()
+ else:
+ self.fatal('Valid algo types are tar.bz2, tar.gz, tar.xz or zip')
+ try:
+ from hashlib import sha1 as sha
+ except ImportError:
+ from sha import sha
+ try:
+ digest=" (sha=%r)"%sha(node.read()).hexdigest()
+ except Exception:
+ digest=''
+ Logs.info('New archive created: %s%s'%(self.arch_name,digest))
+ def get_tar_path(self,node):
+ return node.abspath()
+ def add_tar_file(self,x,tar):
+ p=self.get_tar_path(x)
+ tinfo=tar.gettarinfo(name=p,arcname=self.get_tar_prefix()+'/'+x.path_from(self.base_path))
+ tinfo.uid=0
+ tinfo.gid=0
+ tinfo.uname='root'
+ tinfo.gname='root'
+ fu=None
+ try:
+ fu=open(p,'rb')
+ tar.addfile(tinfo,fileobj=fu)
+ finally:
+ if fu:
+ fu.close()
+ def get_tar_prefix(self):
+ try:
+ return self.tar_prefix
+ except AttributeError:
+ return self.get_base_name()
+ def get_arch_name(self):
+ try:
+ self.arch_name
+ except AttributeError:
+ self.arch_name=self.get_base_name()+'.'+self.ext_algo.get(self.algo,self.algo)
+ return self.arch_name
+ def get_base_name(self):
+ try:
+ self.base_name
+ except AttributeError:
+ appname=getattr(Context.g_module,Context.APPNAME,'noname')
+ version=getattr(Context.g_module,Context.VERSION,'1.0')
+ self.base_name=appname+'-'+version
+ return self.base_name
+ def get_excl(self):
+ try:
+ return self.excl
+ except AttributeError:
+ self.excl=Node.exclude_regs+' **/waf-1.8.* **/.waf-1.8* **/waf3-1.8.* **/.waf3-1.8* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*'
+ if Context.out_dir:
+ nd=self.root.find_node(Context.out_dir)
+ if nd:
+ self.excl+=' '+nd.path_from(self.base_path)
+ return self.excl
+ def get_files(self):
+ try:
+ files=self.files
+ except AttributeError:
+ files=self.base_path.ant_glob('**/*',excl=self.get_excl())
+ return files
+def dist(ctx):
+ '''makes a tarball for redistributing the sources'''
+ pass
+class DistCheck(Dist):
+ fun='distcheck'
+ cmd='distcheck'
+ def execute(self):
+ self.recurse([os.path.dirname(Context.g_module.root_path)])
+ self.archive()
+ self.check()
+ def check(self):
+ import tempfile,tarfile
+ t=None
+ try:
+ t=tarfile.open(self.get_arch_name())
+ for x in t:
+ t.extract(x)
+ finally:
+ if t:
+ t.close()
+ cfg=[]
+ if Options.options.distcheck_args:
+ cfg=shlex.split(Options.options.distcheck_args)
+ else:
+ cfg=[x for x in sys.argv if x.startswith('-')]
+ instdir=tempfile.mkdtemp('.inst',self.get_base_name())
+ ret=Utils.subprocess.Popen([sys.executable,sys.argv[0],'configure','install','uninstall','--destdir='+instdir]+cfg,cwd=self.get_base_name()).wait()
+ if ret:
+ raise Errors.WafError('distcheck failed with code %i'%ret)
+ if os.path.exists(instdir):
+ raise Errors.WafError('distcheck succeeded, but files were left in %s'%instdir)
+ shutil.rmtree(self.get_base_name())
+def distcheck(ctx):
+ '''checks if the project compiles (tarball from 'dist')'''
+ pass
+def update(ctx):
+ lst=Options.options.files
+ if lst:
+ lst=lst.split(',')
+ else:
+ path=os.path.join(Context.waf_dir,'waflib','extras')
+ lst=[x for x in Utils.listdir(path)if x.endswith('.py')]
+ for x in lst:
+ tool=x.replace('.py','')
+ if not tool:
+ continue
+ try:
+ dl=Configure.download_tool
+ except AttributeError:
+ ctx.fatal('The command "update" is dangerous; include the tool "use_config" in your project!')
+ try:
+ dl(tool,force=True,ctx=ctx)
+ except Errors.WafError:
+ Logs.error('Could not find the tool %r in the remote repository'%x)
+ else:
+ Logs.warn('Updated %r'%tool)
+def autoconfigure(execute_method):
+ def execute(self):
+ if not Configure.autoconfig:
+ return execute_method(self)
+ env=ConfigSet.ConfigSet()
+ do_config=False
+ try:
+ env.load(os.path.join(Context.top_dir,Options.lockfile))
+ except Exception:
+ Logs.warn('Configuring the project')
+ do_config=True
+ else:
+ if env.run_dir!=Context.run_dir:
+ do_config=True
+ else:
+ h=0
+ for f in env['files']:
+ h=Utils.h_list((h,Utils.readf(f,'rb')))
+ do_config=h!=env.hash
+ if do_config:
+ cmd=env['config_cmd']or'configure'
+ if Configure.autoconfig=='clobber':
+ tmp=Options.options.__dict__
+ Options.options.__dict__=env.options
+ try:
+ run_command(cmd)
+ finally:
+ Options.options.__dict__=tmp
+ else:
+ run_command(cmd)
+ run_command(self.cmd)
+ else:
+ return execute_method(self)
+ return execute
+Build.BuildContext.execute=autoconfigure(Build.BuildContext.execute)
diff --git a/waflib/Task.py b/waflib/Task.py
new file mode 100644
index 0000000..6070f68
--- /dev/null
+++ b/waflib/Task.py
@@ -0,0 +1,692 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,sys
+from waflib import Utils,Logs,Errors
+NOT_RUN=0
+MISSING=1
+CRASHED=2
+EXCEPTION=3
+SKIPPED=8
+SUCCESS=9
+ASK_LATER=-1
+SKIP_ME=-2
+RUN_ME=-3
+COMPILE_TEMPLATE_SHELL='''
+def f(tsk):
+ env = tsk.env
+ gen = tsk.generator
+ bld = gen.bld
+ cwdx = getattr(bld, 'cwdx', bld.bldnode) # TODO single cwd value in waf 1.9
+ wd = getattr(tsk, 'cwd', None)
+ p = env.get_flat
+ tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s
+ return tsk.exec_command(cmd, cwd=wd, env=env.env or None)
+'''
+COMPILE_TEMPLATE_NOSHELL='''
+def f(tsk):
+ env = tsk.env
+ gen = tsk.generator
+ bld = gen.bld
+ cwdx = getattr(bld, 'cwdx', bld.bldnode) # TODO single cwd value in waf 1.9
+ wd = getattr(tsk, 'cwd', None)
+ def to_list(xx):
+ if isinstance(xx, str): return [xx]
+ return xx
+ tsk.last_cmd = lst = []
+ %s
+ lst = [x for x in lst if x]
+ return tsk.exec_command(lst, cwd=wd, env=env.env or None)
+'''
+classes={}
+class store_task_type(type):
+ def __init__(cls,name,bases,dict):
+ super(store_task_type,cls).__init__(name,bases,dict)
+ name=cls.__name__
+ if name.endswith('_task'):
+ name=name.replace('_task','')
+ if name!='evil'and name!='TaskBase':
+ global classes
+ if getattr(cls,'run_str',None):
+ (f,dvars)=compile_fun(cls.run_str,cls.shell)
+ cls.hcode=Utils.h_cmd(cls.run_str)
+ cls.orig_run_str=cls.run_str
+ cls.run_str=None
+ cls.run=f
+ cls.vars=list(set(cls.vars+dvars))
+ cls.vars.sort()
+ elif getattr(cls,'run',None)and not'hcode'in cls.__dict__:
+ cls.hcode=Utils.h_cmd(cls.run)
+ getattr(cls,'register',classes)[name]=cls
+evil=store_task_type('evil',(object,),{})
+class TaskBase(evil):
+ color='GREEN'
+ ext_in=[]
+ ext_out=[]
+ before=[]
+ after=[]
+ hcode=''
+ def __init__(self,*k,**kw):
+ self.hasrun=NOT_RUN
+ try:
+ self.generator=kw['generator']
+ except KeyError:
+ self.generator=self
+ def __repr__(self):
+ return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,'fun','')))
+ def __str__(self):
+ if hasattr(self,'fun'):
+ return self.fun.__name__
+ return self.__class__.__name__
+ def __hash__(self):
+ return id(self)
+ def keyword(self):
+ if hasattr(self,'fun'):
+ return'Function'
+ return'Processing'
+ def exec_command(self,cmd,**kw):
+ bld=self.generator.bld
+ try:
+ if not kw.get('cwd',None):
+ kw['cwd']=bld.cwd
+ except AttributeError:
+ bld.cwd=kw['cwd']=bld.variant_dir
+ return bld.exec_command(cmd,**kw)
+ def runnable_status(self):
+ return RUN_ME
+ def process(self):
+ m=self.master
+ if m.stop:
+ m.out.put(self)
+ return
+ try:
+ del self.generator.bld.task_sigs[self.uid()]
+ except KeyError:
+ pass
+ try:
+ self.generator.bld.returned_tasks.append(self)
+ self.log_display(self.generator.bld)
+ ret=self.run()
+ except Exception:
+ self.err_msg=Utils.ex_stack()
+ self.hasrun=EXCEPTION
+ m.error_handler(self)
+ m.out.put(self)
+ return
+ if ret:
+ self.err_code=ret
+ self.hasrun=CRASHED
+ else:
+ try:
+ self.post_run()
+ except Errors.WafError:
+ pass
+ except Exception:
+ self.err_msg=Utils.ex_stack()
+ self.hasrun=EXCEPTION
+ else:
+ self.hasrun=SUCCESS
+ if self.hasrun!=SUCCESS:
+ m.error_handler(self)
+ m.out.put(self)
+ def run(self):
+ if hasattr(self,'fun'):
+ return self.fun(self)
+ return 0
+ def post_run(self):
+ pass
+ def log_display(self,bld):
+ if self.generator.bld.progress_bar==3:
+ return
+ s=self.display()
+ if s:
+ if bld.logger:
+ logger=bld.logger
+ else:
+ logger=Logs
+ if self.generator.bld.progress_bar==1:
+ c1=Logs.colors.cursor_off
+ c2=Logs.colors.cursor_on
+ logger.info(s,extra={'stream':sys.stderr,'terminator':'','c1':c1,'c2':c2})
+ else:
+ logger.info(s,extra={'terminator':'','c1':'','c2':''})
+ def display(self):
+ col1=Logs.colors(self.color)
+ col2=Logs.colors.NORMAL
+ master=self.master
+ def cur():
+ tmp=-1
+ if hasattr(master,'ready'):
+ tmp-=master.ready.qsize()
+ return master.processed+tmp
+ if self.generator.bld.progress_bar==1:
+ return self.generator.bld.progress_line(cur(),master.total,col1,col2)
+ if self.generator.bld.progress_bar==2:
+ ela=str(self.generator.bld.timer)
+ try:
+ ins=','.join([n.name for n in self.inputs])
+ except AttributeError:
+ ins=''
+ try:
+ outs=','.join([n.name for n in self.outputs])
+ except AttributeError:
+ outs=''
+ return'|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n'%(master.total,cur(),ins,outs,ela)
+ s=str(self)
+ if not s:
+ return None
+ total=master.total
+ n=len(str(total))
+ fs='[%%%dd/%%%dd] %%s%%s%%s%%s\n'%(n,n)
+ kw=self.keyword()
+ if kw:
+ kw+=' '
+ return fs%(cur(),total,kw,col1,s,col2)
+ def attr(self,att,default=None):
+ ret=getattr(self,att,self)
+ if ret is self:return getattr(self.__class__,att,default)
+ return ret
+ def hash_constraints(self):
+ cls=self.__class__
+ tup=(str(cls.before),str(cls.after),str(cls.ext_in),str(cls.ext_out),cls.__name__,cls.hcode)
+ h=hash(tup)
+ return h
+ def format_error(self):
+ msg=getattr(self,'last_cmd','')
+ name=getattr(self.generator,'name','')
+ if getattr(self,"err_msg",None):
+ return self.err_msg
+ elif not self.hasrun:
+ return'task in %r was not executed for some reason: %r'%(name,self)
+ elif self.hasrun==CRASHED:
+ try:
+ return' -> task in %r failed (exit status %r): %r\n%r'%(name,self.err_code,self,msg)
+ except AttributeError:
+ return' -> task in %r failed: %r\n%r'%(name,self,msg)
+ elif self.hasrun==MISSING:
+ return' -> missing files in %r: %r\n%r'%(name,self,msg)
+ else:
+ return'invalid status for task in %r: %r'%(name,self.hasrun)
+ def colon(self,var1,var2):
+ tmp=self.env[var1]
+ if not tmp:
+ return[]
+ if isinstance(var2,str):
+ it=self.env[var2]
+ else:
+ it=var2
+ if isinstance(tmp,str):
+ return[tmp%x for x in it]
+ else:
+ lst=[]
+ for y in it:
+ lst.extend(tmp)
+ lst.append(y)
+ return lst
+class Task(TaskBase):
+ vars=[]
+ shell=False
+ def __init__(self,*k,**kw):
+ TaskBase.__init__(self,*k,**kw)
+ self.env=kw['env']
+ self.inputs=[]
+ self.outputs=[]
+ self.dep_nodes=[]
+ self.run_after=set([])
+ def __str__(self):
+ name=self.__class__.__name__
+ if self.outputs:
+ if(name.endswith('lib')or name.endswith('program'))or not self.inputs:
+ node=self.outputs[0]
+ return node.path_from(node.ctx.launch_node())
+ if not(self.inputs or self.outputs):
+ return self.__class__.__name__
+ if len(self.inputs)==1:
+ node=self.inputs[0]
+ return node.path_from(node.ctx.launch_node())
+ src_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.inputs])
+ tgt_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.outputs])
+ if self.outputs:sep=' -> '
+ else:sep=''
+ return'%s: %s%s%s'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str)
+ def keyword(self):
+ name=self.__class__.__name__
+ if name.endswith('lib')or name.endswith('program'):
+ return'Linking'
+ if len(self.inputs)==1 and len(self.outputs)==1:
+ return'Compiling'
+ if not self.inputs:
+ if self.outputs:
+ return'Creating'
+ else:
+ return'Running'
+ return'Processing'
+ def __repr__(self):
+ try:
+ ins=",".join([x.name for x in self.inputs])
+ outs=",".join([x.name for x in self.outputs])
+ except AttributeError:
+ ins=",".join([str(x)for x in self.inputs])
+ outs=",".join([str(x)for x in self.outputs])
+ return"".join(['\n\t{task %r: '%id(self),self.__class__.__name__," ",ins," -> ",outs,'}'])
+ def uid(self):
+ try:
+ return self.uid_
+ except AttributeError:
+ m=Utils.md5()
+ up=m.update
+ up(self.__class__.__name__)
+ for x in self.inputs+self.outputs:
+ up(x.abspath())
+ self.uid_=m.digest()
+ return self.uid_
+ def set_inputs(self,inp):
+ if isinstance(inp,list):self.inputs+=inp
+ else:self.inputs.append(inp)
+ def set_outputs(self,out):
+ if isinstance(out,list):self.outputs+=out
+ else:self.outputs.append(out)
+ def set_run_after(self,task):
+ assert isinstance(task,TaskBase)
+ self.run_after.add(task)
+ def signature(self):
+ try:return self.cache_sig
+ except AttributeError:pass
+ self.m=Utils.md5()
+ self.m.update(self.hcode)
+ self.sig_explicit_deps()
+ self.sig_vars()
+ if self.scan:
+ try:
+ self.sig_implicit_deps()
+ except Errors.TaskRescan:
+ return self.signature()
+ ret=self.cache_sig=self.m.digest()
+ return ret
+ def runnable_status(self):
+ for t in self.run_after:
+ if not t.hasrun:
+ return ASK_LATER
+ bld=self.generator.bld
+ try:
+ new_sig=self.signature()
+ except Errors.TaskNotReady:
+ return ASK_LATER
+ key=self.uid()
+ try:
+ prev_sig=bld.task_sigs[key]
+ except KeyError:
+ Logs.debug("task: task %r must run as it was never run before or the task code changed"%self)
+ return RUN_ME
+ for node in self.outputs:
+ try:
+ if node.sig!=new_sig:
+ return RUN_ME
+ except AttributeError:
+ Logs.debug("task: task %r must run as the output nodes do not exist"%self)
+ return RUN_ME
+ if new_sig!=prev_sig:
+ return RUN_ME
+ return SKIP_ME
+ def post_run(self):
+ bld=self.generator.bld
+ sig=self.signature()
+ for node in self.outputs:
+ try:
+ os.stat(node.abspath())
+ except OSError:
+ self.hasrun=MISSING
+ self.err_msg='-> missing file: %r'%node.abspath()
+ raise Errors.WafError(self.err_msg)
+ node.sig=node.cache_sig=sig
+ bld.task_sigs[self.uid()]=self.cache_sig
+ def sig_explicit_deps(self):
+ bld=self.generator.bld
+ upd=self.m.update
+ for x in self.inputs+self.dep_nodes:
+ try:
+ upd(x.get_bld_sig())
+ except(AttributeError,TypeError):
+ raise Errors.WafError('Missing node signature for %r (required by %r)'%(x,self))
+ if bld.deps_man:
+ additional_deps=bld.deps_man
+ for x in self.inputs+self.outputs:
+ try:
+ d=additional_deps[id(x)]
+ except KeyError:
+ continue
+ for v in d:
+ if isinstance(v,bld.root.__class__):
+ try:
+ v=v.get_bld_sig()
+ except AttributeError:
+ raise Errors.WafError('Missing node signature for %r (required by %r)'%(v,self))
+ elif hasattr(v,'__call__'):
+ v=v()
+ upd(v)
+ return self.m.digest()
+ def sig_vars(self):
+ bld=self.generator.bld
+ env=self.env
+ upd=self.m.update
+ act_sig=bld.hash_env_vars(env,self.__class__.vars)
+ upd(act_sig)
+ dep_vars=getattr(self,'dep_vars',None)
+ if dep_vars:
+ upd(bld.hash_env_vars(env,dep_vars))
+ return self.m.digest()
+ scan=None
+ def sig_implicit_deps(self):
+ bld=self.generator.bld
+ key=self.uid()
+ prev=bld.task_sigs.get((key,'imp'),[])
+ if prev:
+ try:
+ if prev==self.compute_sig_implicit_deps():
+ return prev
+ except Errors.TaskNotReady:
+ raise
+ except EnvironmentError:
+ for x in bld.node_deps.get(self.uid(),[]):
+ if not x.is_bld():
+ try:
+ os.stat(x.abspath())
+ except OSError:
+ try:
+ del x.parent.children[x.name]
+ except KeyError:
+ pass
+ del bld.task_sigs[(key,'imp')]
+ raise Errors.TaskRescan('rescan')
+ (nodes,names)=self.scan()
+ if Logs.verbose:
+ Logs.debug('deps: scanner for %s returned %s %s'%(str(self),str(nodes),str(names)))
+ bld.node_deps[key]=nodes
+ bld.raw_deps[key]=names
+ self.are_implicit_nodes_ready()
+ try:
+ bld.task_sigs[(key,'imp')]=sig=self.compute_sig_implicit_deps()
+ except Exception:
+ if Logs.verbose:
+ for k in bld.node_deps.get(self.uid(),[]):
+ try:
+ k.get_bld_sig()
+ except Exception:
+ Logs.warn('Missing signature for node %r (may cause rebuilds)'%k)
+ else:
+ return sig
+ def compute_sig_implicit_deps(self):
+ upd=self.m.update
+ bld=self.generator.bld
+ self.are_implicit_nodes_ready()
+ for k in bld.node_deps.get(self.uid(),[]):
+ upd(k.get_bld_sig())
+ return self.m.digest()
+ def are_implicit_nodes_ready(self):
+ bld=self.generator.bld
+ try:
+ cache=bld.dct_implicit_nodes
+ except AttributeError:
+ bld.dct_implicit_nodes=cache={}
+ try:
+ dct=cache[bld.cur]
+ except KeyError:
+ dct=cache[bld.cur]={}
+ for tsk in bld.cur_tasks:
+ for x in tsk.outputs:
+ dct[x]=tsk
+ modified=False
+ for x in bld.node_deps.get(self.uid(),[]):
+ if x in dct:
+ self.run_after.add(dct[x])
+ modified=True
+ if modified:
+ for tsk in self.run_after:
+ if not tsk.hasrun:
+ raise Errors.TaskNotReady('not ready')
+if sys.hexversion>0x3000000:
+ def uid(self):
+ try:
+ return self.uid_
+ except AttributeError:
+ m=Utils.md5()
+ up=m.update
+ up(self.__class__.__name__.encode('iso8859-1','xmlcharrefreplace'))
+ for x in self.inputs+self.outputs:
+ up(x.abspath().encode('iso8859-1','xmlcharrefreplace'))
+ self.uid_=m.digest()
+ return self.uid_
+ uid.__doc__=Task.uid.__doc__
+ Task.uid=uid
+def is_before(t1,t2):
+ to_list=Utils.to_list
+ for k in to_list(t2.ext_in):
+ if k in to_list(t1.ext_out):
+ return 1
+ if t1.__class__.__name__ in to_list(t2.after):
+ return 1
+ if t2.__class__.__name__ in to_list(t1.before):
+ return 1
+ return 0
+def set_file_constraints(tasks):
+ ins=Utils.defaultdict(set)
+ outs=Utils.defaultdict(set)
+ for x in tasks:
+ for a in getattr(x,'inputs',[])+getattr(x,'dep_nodes',[]):
+ ins[id(a)].add(x)
+ for a in getattr(x,'outputs',[]):
+ outs[id(a)].add(x)
+ links=set(ins.keys()).intersection(outs.keys())
+ for k in links:
+ for a in ins[k]:
+ a.run_after.update(outs[k])
+def set_precedence_constraints(tasks):
+ cstr_groups=Utils.defaultdict(list)
+ for x in tasks:
+ h=x.hash_constraints()
+ cstr_groups[h].append(x)
+ keys=list(cstr_groups.keys())
+ maxi=len(keys)
+ for i in range(maxi):
+ t1=cstr_groups[keys[i]][0]
+ for j in range(i+1,maxi):
+ t2=cstr_groups[keys[j]][0]
+ if is_before(t1,t2):
+ a=i
+ b=j
+ elif is_before(t2,t1):
+ a=j
+ b=i
+ else:
+ continue
+ aval=set(cstr_groups[keys[a]])
+ for x in cstr_groups[keys[b]]:
+ x.run_after.update(aval)
+def funex(c):
+ dc={}
+ exec(c,dc)
+ return dc['f']
+re_novar=re.compile(r"^(SRC|TGT)\W+.*?$")
+reg_act=re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})",re.M)
+def compile_fun_shell(line):
+ extr=[]
+ def repl(match):
+ g=match.group
+ if g('dollar'):return"$"
+ elif g('backslash'):return'\\\\'
+ elif g('subst'):extr.append((g('var'),g('code')));return"%s"
+ return None
+ line=reg_act.sub(repl,line)or line
+ parm=[]
+ dvars=[]
+ app=parm.append
+ for(var,meth)in extr:
+ if var=='SRC':
+ if meth:app('tsk.inputs%s'%meth)
+ else:app('" ".join([a.path_from(cwdx) for a in tsk.inputs])')
+ elif var=='TGT':
+ if meth:app('tsk.outputs%s'%meth)
+ else:app('" ".join([a.path_from(cwdx) for a in tsk.outputs])')
+ elif meth:
+ if meth.startswith(':'):
+ if var not in dvars:
+ dvars.append(var)
+ m=meth[1:]
+ if m=='SRC':
+ m='[a.path_from(cwdx) for a in tsk.inputs]'
+ elif m=='TGT':
+ m='[a.path_from(cwdx) for a in tsk.outputs]'
+ elif re_novar.match(m):
+ m='[tsk.inputs%s]'%m[3:]
+ elif re_novar.match(m):
+ m='[tsk.outputs%s]'%m[3:]
+ elif m[:3]not in('tsk','gen','bld'):
+ dvars.append(meth[1:])
+ m='%r'%m
+ app('" ".join(tsk.colon(%r, %s))'%(var,m))
+ else:
+ app('%s%s'%(var,meth))
+ else:
+ if var not in dvars:
+ dvars.append(var)
+ app("p('%s')"%var)
+ if parm:parm="%% (%s) "%(',\n\t\t'.join(parm))
+ else:parm=''
+ c=COMPILE_TEMPLATE_SHELL%(line,parm)
+ Logs.debug('action: %s'%c.strip().splitlines())
+ return(funex(c),dvars)
+def compile_fun_noshell(line):
+ extr=[]
+ def repl(match):
+ g=match.group
+ if g('dollar'):return"$"
+ elif g('backslash'):return'\\'
+ elif g('subst'):extr.append((g('var'),g('code')));return"<<|@|>>"
+ return None
+ line2=reg_act.sub(repl,line)
+ params=line2.split('<<|@|>>')
+ assert(extr)
+ buf=[]
+ dvars=[]
+ app=buf.append
+ for x in range(len(extr)):
+ params[x]=params[x].strip()
+ if params[x]:
+ app("lst.extend(%r)"%params[x].split())
+ (var,meth)=extr[x]
+ if var=='SRC':
+ if meth:app('lst.append(tsk.inputs%s)'%meth)
+ else:app("lst.extend([a.path_from(cwdx) for a in tsk.inputs])")
+ elif var=='TGT':
+ if meth:app('lst.append(tsk.outputs%s)'%meth)
+ else:app("lst.extend([a.path_from(cwdx) for a in tsk.outputs])")
+ elif meth:
+ if meth.startswith(':'):
+ if not var in dvars:
+ dvars.append(var)
+ m=meth[1:]
+ if m=='SRC':
+ m='[a.path_from(cwdx) for a in tsk.inputs]'
+ elif m=='TGT':
+ m='[a.path_from(cwdx) for a in tsk.outputs]'
+ elif re_novar.match(m):
+ m='[tsk.inputs%s]'%m[3:]
+ elif re_novar.match(m):
+ m='[tsk.outputs%s]'%m[3:]
+ elif m[:3]not in('tsk','gen','bld'):
+ dvars.append(m)
+ m='%r'%m
+ app('lst.extend(tsk.colon(%r, %s))'%(var,m))
+ else:
+ app('lst.extend(gen.to_list(%s%s))'%(var,meth))
+ else:
+ app('lst.extend(to_list(env[%r]))'%var)
+ if not var in dvars:
+ dvars.append(var)
+ if extr:
+ if params[-1]:
+ app("lst.extend(%r)"%params[-1].split())
+ fun=COMPILE_TEMPLATE_NOSHELL%"\n\t".join(buf)
+ Logs.debug('action: %s'%fun.strip().splitlines())
+ return(funex(fun),dvars)
+def compile_fun(line,shell=False):
+ if isinstance(line,str):
+ if line.find('<')>0 or line.find('>')>0 or line.find('&&')>0:
+ shell=True
+ else:
+ dvars_lst=[]
+ funs_lst=[]
+ for x in line:
+ if isinstance(x,str):
+ fun,dvars=compile_fun(x,shell)
+ dvars_lst+=dvars
+ funs_lst.append(fun)
+ else:
+ funs_lst.append(x)
+ def composed_fun(task):
+ for x in funs_lst:
+ ret=x(task)
+ if ret:
+ return ret
+ return None
+ return composed_fun,dvars
+ if shell:
+ return compile_fun_shell(line)
+ else:
+ return compile_fun_noshell(line)
+def task_factory(name,func=None,vars=None,color='GREEN',ext_in=[],ext_out=[],before=[],after=[],shell=False,scan=None):
+ params={'vars':vars or[],'color':color,'name':name,'ext_in':Utils.to_list(ext_in),'ext_out':Utils.to_list(ext_out),'before':Utils.to_list(before),'after':Utils.to_list(after),'shell':shell,'scan':scan,}
+ if isinstance(func,str)or isinstance(func,tuple):
+ params['run_str']=func
+ else:
+ params['run']=func
+ cls=type(Task)(name,(Task,),params)
+ global classes
+ classes[name]=cls
+ return cls
+def always_run(cls):
+ old=cls.runnable_status
+ def always(self):
+ ret=old(self)
+ if ret==SKIP_ME:
+ ret=RUN_ME
+ return ret
+ cls.runnable_status=always
+ return cls
+def update_outputs(cls):
+ old_post_run=cls.post_run
+ def post_run(self):
+ old_post_run(self)
+ for node in self.outputs:
+ node.sig=node.cache_sig=Utils.h_file(node.abspath())
+ self.generator.bld.task_sigs[node.abspath()]=self.uid()
+ cls.post_run=post_run
+ old_runnable_status=cls.runnable_status
+ def runnable_status(self):
+ status=old_runnable_status(self)
+ if status!=RUN_ME:
+ return status
+ try:
+ bld=self.generator.bld
+ prev_sig=bld.task_sigs[self.uid()]
+ if prev_sig==self.signature():
+ for x in self.outputs:
+ if not x.is_child_of(bld.bldnode):
+ x.sig=Utils.h_file(x.abspath())
+ if not x.sig or bld.task_sigs[x.abspath()]!=self.uid():
+ return RUN_ME
+ return SKIP_ME
+ except OSError:
+ pass
+ except IOError:
+ pass
+ except KeyError:
+ pass
+ except IndexError:
+ pass
+ except AttributeError:
+ pass
+ return RUN_ME
+ cls.runnable_status=runnable_status
+ return cls
diff --git a/waflib/TaskGen.py b/waflib/TaskGen.py
new file mode 100644
index 0000000..046f1f9
--- /dev/null
+++ b/waflib/TaskGen.py
@@ -0,0 +1,434 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import copy,re,os
+from waflib import Task,Utils,Logs,Errors,ConfigSet,Node
+feats=Utils.defaultdict(set)
+HEADER_EXTS=['.h','.hpp','.hxx','.hh']
+class task_gen(object):
+ mappings=Utils.ordered_iter_dict()
+ prec=Utils.defaultdict(list)
+ def __init__(self,*k,**kw):
+ self.source=''
+ self.target=''
+ self.meths=[]
+ self.prec=Utils.defaultdict(list)
+ self.mappings={}
+ self.features=[]
+ self.tasks=[]
+ if not'bld'in kw:
+ self.env=ConfigSet.ConfigSet()
+ self.idx=0
+ self.path=None
+ else:
+ self.bld=kw['bld']
+ self.env=self.bld.env.derive()
+ self.path=self.bld.path
+ try:
+ self.idx=self.bld.idx[id(self.path)]=self.bld.idx.get(id(self.path),0)+1
+ except AttributeError:
+ self.bld.idx={}
+ self.idx=self.bld.idx[id(self.path)]=1
+ for key,val in kw.items():
+ setattr(self,key,val)
+ def __str__(self):
+ return"<task_gen %r declared in %s>"%(self.name,self.path.abspath())
+ def __repr__(self):
+ lst=[]
+ for x in self.__dict__.keys():
+ if x not in('env','bld','compiled_tasks','tasks'):
+ lst.append("%s=%s"%(x,repr(getattr(self,x))))
+ return"bld(%s) in %s"%(", ".join(lst),self.path.abspath())
+ def get_name(self):
+ try:
+ return self._name
+ except AttributeError:
+ if isinstance(self.target,list):
+ lst=[str(x)for x in self.target]
+ name=self._name=','.join(lst)
+ else:
+ name=self._name=str(self.target)
+ return name
+ def set_name(self,name):
+ self._name=name
+ name=property(get_name,set_name)
+ def to_list(self,val):
+ if isinstance(val,str):return val.split()
+ else:return val
+ def post(self):
+ if getattr(self,'posted',None):
+ return False
+ self.posted=True
+ keys=set(self.meths)
+ self.features=Utils.to_list(self.features)
+ for x in self.features+['*']:
+ st=feats[x]
+ if not st:
+ if not x in Task.classes:
+ Logs.warn('feature %r does not exist - bind at least one method to it'%x)
+ keys.update(list(st))
+ prec={}
+ prec_tbl=self.prec or task_gen.prec
+ for x in prec_tbl:
+ if x in keys:
+ prec[x]=prec_tbl[x]
+ tmp=[]
+ for a in keys:
+ for x in prec.values():
+ if a in x:break
+ else:
+ tmp.append(a)
+ tmp.sort()
+ out=[]
+ while tmp:
+ e=tmp.pop()
+ if e in keys:out.append(e)
+ try:
+ nlst=prec[e]
+ except KeyError:
+ pass
+ else:
+ del prec[e]
+ for x in nlst:
+ for y in prec:
+ if x in prec[y]:
+ break
+ else:
+ tmp.append(x)
+ if prec:
+ txt='\n'.join(['- %s after %s'%(k,repr(v))for k,v in prec.items()])
+ raise Errors.WafError('Cycle detected in the method execution\n%s'%txt)
+ out.reverse()
+ self.meths=out
+ Logs.debug('task_gen: posting %s %d'%(self,id(self)))
+ for x in out:
+ try:
+ v=getattr(self,x)
+ except AttributeError:
+ raise Errors.WafError('%r is not a valid task generator method'%x)
+ Logs.debug('task_gen: -> %s (%d)'%(x,id(self)))
+ v()
+ Logs.debug('task_gen: posted %s'%self.name)
+ return True
+ def get_hook(self,node):
+ name=node.name
+ if self.mappings:
+ for k in self.mappings:
+ if name.endswith(k):
+ return self.mappings[k]
+ for k in task_gen.mappings:
+ if name.endswith(k):
+ return task_gen.mappings[k]
+ raise Errors.WafError("File %r has no mapping in %r (have you forgotten to load a waf tool?)"%(node,task_gen.mappings.keys()))
+ def create_task(self,name,src=None,tgt=None,**kw):
+ task=Task.classes[name](env=self.env.derive(),generator=self)
+ if src:
+ task.set_inputs(src)
+ if tgt:
+ task.set_outputs(tgt)
+ task.__dict__.update(kw)
+ self.tasks.append(task)
+ return task
+ def clone(self,env):
+ newobj=self.bld()
+ for x in self.__dict__:
+ if x in('env','bld'):
+ continue
+ elif x in('path','features'):
+ setattr(newobj,x,getattr(self,x))
+ else:
+ setattr(newobj,x,copy.copy(getattr(self,x)))
+ newobj.posted=False
+ if isinstance(env,str):
+ newobj.env=self.bld.all_envs[env].derive()
+ else:
+ newobj.env=env.derive()
+ return newobj
+def declare_chain(name='',rule=None,reentrant=None,color='BLUE',ext_in=[],ext_out=[],before=[],after=[],decider=None,scan=None,install_path=None,shell=False):
+ ext_in=Utils.to_list(ext_in)
+ ext_out=Utils.to_list(ext_out)
+ if not name:
+ name=rule
+ cls=Task.task_factory(name,rule,color=color,ext_in=ext_in,ext_out=ext_out,before=before,after=after,scan=scan,shell=shell)
+ def x_file(self,node):
+ ext=decider and decider(self,node)or cls.ext_out
+ if ext_in:
+ _ext_in=ext_in[0]
+ tsk=self.create_task(name,node)
+ cnt=0
+ keys=set(self.mappings.keys())|set(self.__class__.mappings.keys())
+ for x in ext:
+ k=node.change_ext(x,ext_in=_ext_in)
+ tsk.outputs.append(k)
+ if reentrant!=None:
+ if cnt<int(reentrant):
+ self.source.append(k)
+ else:
+ for y in keys:
+ if k.name.endswith(y):
+ self.source.append(k)
+ break
+ cnt+=1
+ if install_path:
+ self.bld.install_files(install_path,tsk.outputs)
+ return tsk
+ for x in cls.ext_in:
+ task_gen.mappings[x]=x_file
+ return x_file
+def taskgen_method(func):
+ setattr(task_gen,func.__name__,func)
+ return func
+def feature(*k):
+ def deco(func):
+ setattr(task_gen,func.__name__,func)
+ for name in k:
+ feats[name].update([func.__name__])
+ return func
+ return deco
+def before_method(*k):
+ def deco(func):
+ setattr(task_gen,func.__name__,func)
+ for fun_name in k:
+ if not func.__name__ in task_gen.prec[fun_name]:
+ task_gen.prec[fun_name].append(func.__name__)
+ return func
+ return deco
+before=before_method
+def after_method(*k):
+ def deco(func):
+ setattr(task_gen,func.__name__,func)
+ for fun_name in k:
+ if not fun_name in task_gen.prec[func.__name__]:
+ task_gen.prec[func.__name__].append(fun_name)
+ return func
+ return deco
+after=after_method
+def extension(*k):
+ def deco(func):
+ setattr(task_gen,func.__name__,func)
+ for x in k:
+ task_gen.mappings[x]=func
+ return func
+ return deco
+@taskgen_method
+def to_nodes(self,lst,path=None):
+ tmp=[]
+ path=path or self.path
+ find=path.find_resource
+ if isinstance(lst,Node.Node):
+ lst=[lst]
+ for x in Utils.to_list(lst):
+ if isinstance(x,str):
+ node=find(x)
+ else:
+ node=x
+ if not node:
+ raise Errors.WafError("source not found: %r in %r"%(x,self))
+ tmp.append(node)
+ return tmp
+@feature('*')
+def process_source(self):
+ self.source=self.to_nodes(getattr(self,'source',[]))
+ for node in self.source:
+ self.get_hook(node)(self,node)
+@feature('*')
+@before_method('process_source')
+def process_rule(self):
+ if not getattr(self,'rule',None):
+ return
+ name=str(getattr(self,'name',None)or self.target or getattr(self.rule,'__name__',self.rule))
+ try:
+ cache=self.bld.cache_rule_attr
+ except AttributeError:
+ cache=self.bld.cache_rule_attr={}
+ cls=None
+ if getattr(self,'cache_rule','True'):
+ try:
+ cls=cache[(name,self.rule)]
+ except KeyError:
+ pass
+ if not cls:
+ rule=self.rule
+ if hasattr(self,'chmod'):
+ def chmod_fun(tsk):
+ for x in tsk.outputs:
+ os.chmod(x.abspath(),self.chmod)
+ rule=(self.rule,chmod_fun)
+ cls=Task.task_factory(name,rule,getattr(self,'vars',[]),shell=getattr(self,'shell',True),color=getattr(self,'color','BLUE'),scan=getattr(self,'scan',None))
+ if getattr(self,'scan',None):
+ cls.scan=self.scan
+ elif getattr(self,'deps',None):
+ def scan(self):
+ nodes=[]
+ for x in self.generator.to_list(getattr(self.generator,'deps',None)):
+ node=self.generator.path.find_resource(x)
+ if not node:
+ self.generator.bld.fatal('Could not find %r (was it declared?)'%x)
+ nodes.append(node)
+ return[nodes,[]]
+ cls.scan=scan
+ if getattr(self,'update_outputs',None):
+ Task.update_outputs(cls)
+ if getattr(self,'always',None):
+ Task.always_run(cls)
+ for x in('after','before','ext_in','ext_out'):
+ setattr(cls,x,getattr(self,x,[]))
+ if getattr(self,'cache_rule','True'):
+ cache[(name,self.rule)]=cls
+ if getattr(self,'cls_str',None):
+ setattr(cls,'__str__',self.cls_str)
+ if getattr(self,'cls_keyword',None):
+ setattr(cls,'keyword',self.cls_keyword)
+ tsk=self.create_task(name)
+ if getattr(self,'target',None):
+ if isinstance(self.target,str):
+ self.target=self.target.split()
+ if not isinstance(self.target,list):
+ self.target=[self.target]
+ for x in self.target:
+ if isinstance(x,str):
+ tsk.outputs.append(self.path.find_or_declare(x))
+ else:
+ x.parent.mkdir()
+ tsk.outputs.append(x)
+ if getattr(self,'install_path',None):
+ self.bld.install_files(self.install_path,tsk.outputs,chmod=getattr(self,'chmod',Utils.O644))
+ if getattr(self,'source',None):
+ tsk.inputs=self.to_nodes(self.source)
+ self.source=[]
+ if getattr(self,'cwd',None):
+ tsk.cwd=self.cwd
+@feature('seq')
+def sequence_order(self):
+ if self.meths and self.meths[-1]!='sequence_order':
+ self.meths.append('sequence_order')
+ return
+ if getattr(self,'seq_start',None):
+ return
+ if getattr(self.bld,'prev',None):
+ self.bld.prev.post()
+ for x in self.bld.prev.tasks:
+ for y in self.tasks:
+ y.set_run_after(x)
+ self.bld.prev=self
+re_m4=re.compile('@(\w+)@',re.M)
+class subst_pc(Task.Task):
+ def force_permissions(self):
+ if getattr(self.generator,'chmod',None):
+ for x in self.outputs:
+ os.chmod(x.abspath(),self.generator.chmod)
+ def run(self):
+ if getattr(self.generator,'is_copy',None):
+ for i,x in enumerate(self.outputs):
+ x.write(self.inputs[i].read('rb'),'wb')
+ self.force_permissions()
+ return None
+ if getattr(self.generator,'fun',None):
+ ret=self.generator.fun(self)
+ if not ret:
+ self.force_permissions()
+ return ret
+ code=self.inputs[0].read(encoding=getattr(self.generator,'encoding','ISO8859-1'))
+ if getattr(self.generator,'subst_fun',None):
+ code=self.generator.subst_fun(self,code)
+ if code is not None:
+ self.outputs[0].write(code,encoding=getattr(self.generator,'encoding','ISO8859-1'))
+ self.force_permissions()
+ return None
+ code=code.replace('%','%%')
+ lst=[]
+ def repl(match):
+ g=match.group
+ if g(1):
+ lst.append(g(1))
+ return"%%(%s)s"%g(1)
+ return''
+ global re_m4
+ code=getattr(self.generator,'re_m4',re_m4).sub(repl,code)
+ try:
+ d=self.generator.dct
+ except AttributeError:
+ d={}
+ for x in lst:
+ tmp=getattr(self.generator,x,'')or self.env[x]or self.env[x.upper()]
+ try:
+ tmp=''.join(tmp)
+ except TypeError:
+ tmp=str(tmp)
+ d[x]=tmp
+ code=code%d
+ self.outputs[0].write(code,encoding=getattr(self.generator,'encoding','ISO8859-1'))
+ self.generator.bld.raw_deps[self.uid()]=self.dep_vars=lst
+ try:delattr(self,'cache_sig')
+ except AttributeError:pass
+ self.force_permissions()
+ def sig_vars(self):
+ bld=self.generator.bld
+ env=self.env
+ upd=self.m.update
+ if getattr(self.generator,'fun',None):
+ upd(Utils.h_fun(self.generator.fun))
+ if getattr(self.generator,'subst_fun',None):
+ upd(Utils.h_fun(self.generator.subst_fun))
+ vars=self.generator.bld.raw_deps.get(self.uid(),[])
+ act_sig=bld.hash_env_vars(env,vars)
+ upd(act_sig)
+ lst=[getattr(self.generator,x,'')for x in vars]
+ upd(Utils.h_list(lst))
+ return self.m.digest()
+@extension('.pc.in')
+def add_pcfile(self,node):
+ tsk=self.create_task('subst_pc',node,node.change_ext('.pc','.pc.in'))
+ self.bld.install_files(getattr(self,'install_path','${LIBDIR}/pkgconfig/'),tsk.outputs)
+class subst(subst_pc):
+ pass
+@feature('subst')
+@before_method('process_source','process_rule')
+def process_subst(self):
+ src=Utils.to_list(getattr(self,'source',[]))
+ if isinstance(src,Node.Node):
+ src=[src]
+ tgt=Utils.to_list(getattr(self,'target',[]))
+ if isinstance(tgt,Node.Node):
+ tgt=[tgt]
+ if len(src)!=len(tgt):
+ raise Errors.WafError('invalid number of source/target for %r'%self)
+ for x,y in zip(src,tgt):
+ if not x or not y:
+ raise Errors.WafError('null source or target for %r'%self)
+ a,b=None,None
+ if isinstance(x,str)and isinstance(y,str)and x==y:
+ a=self.path.find_node(x)
+ b=self.path.get_bld().make_node(y)
+ if not os.path.isfile(b.abspath()):
+ b.sig=None
+ b.parent.mkdir()
+ else:
+ if isinstance(x,str):
+ a=self.path.find_resource(x)
+ elif isinstance(x,Node.Node):
+ a=x
+ if isinstance(y,str):
+ b=self.path.find_or_declare(y)
+ elif isinstance(y,Node.Node):
+ b=y
+ if not a:
+ raise Errors.WafError('could not find %r for %r'%(x,self))
+ has_constraints=False
+ tsk=self.create_task('subst',a,b)
+ for k in('after','before','ext_in','ext_out'):
+ val=getattr(self,k,None)
+ if val:
+ has_constraints=True
+ setattr(tsk,k,val)
+ if not has_constraints:
+ global HEADER_EXTS
+ for xt in HEADER_EXTS:
+ if b.name.endswith(xt):
+ tsk.before=[k for k in('c','cxx')if k in Task.classes]
+ break
+ inst_to=getattr(self,'install_path',None)
+ if inst_to:
+ self.bld.install_files(inst_to,b,chmod=getattr(self,'chmod',Utils.O644))
+ self.source=[]
diff --git a/waflib/Tools/__init__.py b/waflib/Tools/__init__.py
new file mode 100644
index 0000000..55e850d
--- /dev/null
+++ b/waflib/Tools/__init__.py
@@ -0,0 +1,4 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
diff --git a/waflib/Tools/ar.py b/waflib/Tools/ar.py
new file mode 100644
index 0000000..5921ce1
--- /dev/null
+++ b/waflib/Tools/ar.py
@@ -0,0 +1,13 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Configure import conf
+@conf
+def find_ar(conf):
+ conf.load('ar')
+def configure(conf):
+ conf.find_program('ar',var='AR')
+ conf.add_os_flags('ARFLAGS')
+ if not conf.env.ARFLAGS:
+ conf.env.ARFLAGS=['rcs']
diff --git a/waflib/Tools/asm.py b/waflib/Tools/asm.py
new file mode 100644
index 0000000..3f1e135
--- /dev/null
+++ b/waflib/Tools/asm.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Task
+import waflib.Task
+from waflib.Tools.ccroot import link_task,stlink_task
+from waflib.TaskGen import extension
+class asm(Task.Task):
+ color='BLUE'
+ run_str='${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}'
+@extension('.s','.S','.asm','.ASM','.spp','.SPP')
+def asm_hook(self,node):
+ return self.create_compiled_task('asm',node)
+class asmprogram(link_task):
+ run_str='${ASLINK} ${ASLINKFLAGS} ${ASLNK_TGT_F}${TGT} ${ASLNK_SRC_F}${SRC}'
+ ext_out=['.bin']
+ inst_to='${BINDIR}'
+class asmshlib(asmprogram):
+ inst_to='${LIBDIR}'
+class asmstlib(stlink_task):
+ pass
+def configure(conf):
+ conf.env['ASMPATH_ST']='-I%s'
diff --git a/waflib/Tools/bison.py b/waflib/Tools/bison.py
new file mode 100644
index 0000000..c85c8d6
--- /dev/null
+++ b/waflib/Tools/bison.py
@@ -0,0 +1,28 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Task
+from waflib.TaskGen import extension
+class bison(Task.Task):
+ color='BLUE'
+ run_str='${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}'
+ ext_out=['.h']
+@extension('.y','.yc','.yy')
+def big_bison(self,node):
+ has_h='-d'in self.env['BISONFLAGS']
+ outs=[]
+ if node.name.endswith('.yc'):
+ outs.append(node.change_ext('.tab.cc'))
+ if has_h:
+ outs.append(node.change_ext('.tab.hh'))
+ else:
+ outs.append(node.change_ext('.tab.c'))
+ if has_h:
+ outs.append(node.change_ext('.tab.h'))
+ tsk=self.create_task('bison',node,outs)
+ tsk.cwd=node.parent.get_bld().abspath()
+ self.source.append(outs[0])
+def configure(conf):
+ conf.find_program('bison',var='BISON')
+ conf.env.BISONFLAGS=['-d']
diff --git a/waflib/Tools/c.py b/waflib/Tools/c.py
new file mode 100644
index 0000000..e3e7665
--- /dev/null
+++ b/waflib/Tools/c.py
@@ -0,0 +1,26 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import TaskGen,Task
+from waflib.Tools import c_preproc
+from waflib.Tools.ccroot import link_task,stlink_task
+@TaskGen.extension('.c')
+def c_hook(self,node):
+ if not self.env.CC and self.env.CXX:
+ return self.create_compiled_task('cxx',node)
+ return self.create_compiled_task('c',node)
+class c(Task.Task):
+ run_str='${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath()}'
+ vars=['CCDEPS']
+ ext_in=['.h']
+ scan=c_preproc.scan
+class cprogram(link_task):
+ run_str='${LINK_CC} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LDFLAGS}'
+ ext_out=['.bin']
+ vars=['LINKDEPS']
+ inst_to='${BINDIR}'
+class cshlib(cprogram):
+ inst_to='${LIBDIR}'
+class cstlib(stlink_task):
+ pass
diff --git a/waflib/Tools/c_aliases.py b/waflib/Tools/c_aliases.py
new file mode 100644
index 0000000..e947f0d
--- /dev/null
+++ b/waflib/Tools/c_aliases.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Utils,Errors
+from waflib.Configure import conf
+def get_extensions(lst):
+ ret=[]
+ for x in Utils.to_list(lst):
+ try:
+ if not isinstance(x,str):
+ x=x.name
+ ret.append(x[x.rfind('.')+1:])
+ except Exception:
+ pass
+ return ret
+def sniff_features(**kw):
+ exts=get_extensions(kw['source'])
+ type=kw['_type']
+ feats=[]
+ for x in'cxx cpp c++ cc C'.split():
+ if x in exts:
+ feats.append('cxx')
+ break
+ if'c'in exts or'vala'in exts or'gs'in exts:
+ feats.append('c')
+ for x in'f f90 F F90 for FOR'.split():
+ if x in exts:
+ feats.append('fc')
+ break
+ if'd'in exts:
+ feats.append('d')
+ if'java'in exts:
+ feats.append('java')
+ return'java'
+ if type in('program','shlib','stlib'):
+ will_link=False
+ for x in feats:
+ if x in('cxx','d','fc','c'):
+ feats.append(x+type)
+ will_link=True
+ if not will_link and not kw.get('features',[]):
+ raise Errors.WafError('Cannot link from %r, try passing eg: features="c cprogram"?'%kw)
+ return feats
+def set_features(kw,_type):
+ kw['_type']=_type
+ kw['features']=Utils.to_list(kw.get('features',[]))+Utils.to_list(sniff_features(**kw))
+@conf
+def program(bld,*k,**kw):
+ set_features(kw,'program')
+ return bld(*k,**kw)
+@conf
+def shlib(bld,*k,**kw):
+ set_features(kw,'shlib')
+ return bld(*k,**kw)
+@conf
+def stlib(bld,*k,**kw):
+ set_features(kw,'stlib')
+ return bld(*k,**kw)
+@conf
+def objects(bld,*k,**kw):
+ set_features(kw,'objects')
+ return bld(*k,**kw)
diff --git a/waflib/Tools/c_config.py b/waflib/Tools/c_config.py
new file mode 100644
index 0000000..5f4e308
--- /dev/null
+++ b/waflib/Tools/c_config.py
@@ -0,0 +1,765 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,shlex
+from waflib import Build,Utils,Task,Options,Logs,Errors,Runner
+from waflib.TaskGen import after_method,feature
+from waflib.Configure import conf
+WAF_CONFIG_H='config.h'
+DEFKEYS='define_key'
+INCKEYS='include_key'
+cfg_ver={'atleast-version':'>=','exact-version':'==','max-version':'<=',}
+SNIP_FUNCTION='''
+int main(int argc, char **argv) {
+ void (*p)();
+ (void)argc; (void)argv;
+ p=(void(*)())(%s);
+ return !p;
+}
+'''
+SNIP_TYPE='''
+int main(int argc, char **argv) {
+ (void)argc; (void)argv;
+ if ((%(type_name)s *) 0) return 0;
+ if (sizeof (%(type_name)s)) return 0;
+ return 1;
+}
+'''
+SNIP_EMPTY_PROGRAM='''
+int main(int argc, char **argv) {
+ (void)argc; (void)argv;
+ return 0;
+}
+'''
+SNIP_FIELD='''
+int main(int argc, char **argv) {
+ char *off;
+ (void)argc; (void)argv;
+ off = (char*) &((%(type_name)s*)0)->%(field_name)s;
+ return (size_t) off < sizeof(%(type_name)s);
+}
+'''
+MACRO_TO_DESTOS={'__linux__':'linux','__GNU__':'gnu','__FreeBSD__':'freebsd','__NetBSD__':'netbsd','__OpenBSD__':'openbsd','__sun':'sunos','__hpux':'hpux','__sgi':'irix','_AIX':'aix','__CYGWIN__':'cygwin','__MSYS__':'cygwin','_UWIN':'uwin','_WIN64':'win32','_WIN32':'win32','__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__':'darwin','__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__':'darwin','__QNX__':'qnx','__native_client__':'nacl'}
+MACRO_TO_DEST_CPU={'__x86_64__':'x86_64','__amd64__':'x86_64','__i386__':'x86','__ia64__':'ia','__mips__':'mips','__sparc__':'sparc','__alpha__':'alpha','__aarch64__':'aarch64','__thumb__':'thumb','__arm__':'arm','__hppa__':'hppa','__powerpc__':'powerpc','__ppc__':'powerpc','__convex__':'convex','__m68k__':'m68k','__s390x__':'s390x','__s390__':'s390','__sh__':'sh','__xtensa__':'xtensa',}
+@conf
+def parse_flags(self,line,uselib_store,env=None,force_static=False,posix=None):
+ assert(isinstance(line,str))
+ env=env or self.env
+ if posix is None:
+ posix=True
+ if'\\'in line:
+ posix=('\\ 'in line)or('\\\\'in line)
+ lex=shlex.shlex(line,posix=posix)
+ lex.whitespace_split=True
+ lex.commenters=''
+ lst=list(lex)
+ app=env.append_value
+ appu=env.append_unique
+ uselib=uselib_store
+ static=False
+ while lst:
+ x=lst.pop(0)
+ st=x[:2]
+ ot=x[2:]
+ if st=='-I'or st=='/I':
+ if not ot:ot=lst.pop(0)
+ appu('INCLUDES_'+uselib,[ot])
+ elif st=='-i':
+ tmp=[x,lst.pop(0)]
+ app('CFLAGS',tmp)
+ app('CXXFLAGS',tmp)
+ elif st=='-D'or(env.CXX_NAME=='msvc'and st=='/D'):
+ if not ot:ot=lst.pop(0)
+ app('DEFINES_'+uselib,[ot])
+ elif st=='-l':
+ if not ot:ot=lst.pop(0)
+ prefix=(force_static or static)and'STLIB_'or'LIB_'
+ appu(prefix+uselib,[ot])
+ elif st=='-L':
+ if not ot:ot=lst.pop(0)
+ prefix=(force_static or static)and'STLIBPATH_'or'LIBPATH_'
+ appu(prefix+uselib,[ot])
+ elif x.startswith('/LIBPATH:'):
+ prefix=(force_static or static)and'STLIBPATH_'or'LIBPATH_'
+ appu(prefix+uselib,[x.replace('/LIBPATH:','')])
+ elif x.startswith('-std='):
+ if'++'in x:
+ app('CXXFLAGS_'+uselib,[x])
+ else:
+ app('CFLAGS_'+uselib,[x])
+ elif x=='-pthread'or x.startswith('+'):
+ app('CFLAGS_'+uselib,[x])
+ app('CXXFLAGS_'+uselib,[x])
+ app('LINKFLAGS_'+uselib,[x])
+ elif x=='-framework':
+ appu('FRAMEWORK_'+uselib,[lst.pop(0)])
+ elif x.startswith('-F'):
+ appu('FRAMEWORKPATH_'+uselib,[x[2:]])
+ elif x=='-Wl,-rpath'or x=='-Wl,-R':
+ app('RPATH_'+uselib,lst.pop(0).lstrip('-Wl,'))
+ elif x.startswith('-Wl,-R,'):
+ app('RPATH_'+uselib,x[7:])
+ elif x.startswith('-Wl,-R'):
+ app('RPATH_'+uselib,x[6:])
+ elif x.startswith('-Wl,-rpath,'):
+ app('RPATH_'+uselib,x[11:])
+ elif x=='-Wl,-Bstatic'or x=='-Bstatic':
+ static=True
+ elif x=='-Wl,-Bdynamic'or x=='-Bdynamic':
+ static=False
+ elif x.startswith('-Wl'):
+ app('LINKFLAGS_'+uselib,[x])
+ elif x.startswith('-m')or x.startswith('-f')or x.startswith('-dynamic'):
+ app('CFLAGS_'+uselib,[x])
+ app('CXXFLAGS_'+uselib,[x])
+ elif x.startswith('-bundle'):
+ app('LINKFLAGS_'+uselib,[x])
+ elif x.startswith('-undefined')or x.startswith('-Xlinker'):
+ arg=lst.pop(0)
+ app('LINKFLAGS_'+uselib,[x,arg])
+ elif x.startswith('-arch')or x.startswith('-isysroot'):
+ tmp=[x,lst.pop(0)]
+ app('CFLAGS_'+uselib,tmp)
+ app('CXXFLAGS_'+uselib,tmp)
+ app('LINKFLAGS_'+uselib,tmp)
+ elif x.endswith('.a')or x.endswith('.so')or x.endswith('.dylib')or x.endswith('.lib'):
+ appu('LINKFLAGS_'+uselib,[x])
+@conf
+def validate_cfg(self,kw):
+ if not'path'in kw:
+ if not self.env.PKGCONFIG:
+ self.find_program('pkg-config',var='PKGCONFIG')
+ kw['path']=self.env.PKGCONFIG
+ if'atleast_pkgconfig_version'in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for pkg-config version >= %r'%kw['atleast_pkgconfig_version']
+ return
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ if not'errmsg'in kw:
+ kw['errmsg']='not found'
+ if'modversion'in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for %r version'%kw['modversion']
+ return
+ for x in cfg_ver.keys():
+ y=x.replace('-','_')
+ if y in kw:
+ if not'package'in kw:
+ raise ValueError('%s requires a package'%x)
+ if not'msg'in kw:
+ kw['msg']='Checking for %r %s %s'%(kw['package'],cfg_ver[x],kw[y])
+ return
+ if not'define_name'in kw:
+ pkgname=kw.get('uselib_store',kw['package'].upper())
+ kw['define_name']=self.have_define(pkgname)
+ if not'uselib_store'in kw:
+ self.undefine(kw['define_name'])
+ if not'msg'in kw:
+ kw['msg']='Checking for %r'%(kw['package']or kw['path'])
+@conf
+def exec_cfg(self,kw):
+ path=Utils.to_list(kw['path'])
+ env=self.env.env or None
+ def define_it():
+ pkgname=kw.get('uselib_store',kw['package'].upper())
+ if kw.get('global_define'):
+ self.define(self.have_define(kw['package']),1,False)
+ else:
+ self.env.append_unique('DEFINES_%s'%pkgname,"%s=1"%self.have_define(pkgname))
+ self.env[self.have_define(pkgname)]=1
+ if'atleast_pkgconfig_version'in kw:
+ cmd=path+['--atleast-pkgconfig-version=%s'%kw['atleast_pkgconfig_version']]
+ self.cmd_and_log(cmd,env=env)
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ return
+ for x in cfg_ver:
+ y=x.replace('-','_')
+ if y in kw:
+ self.cmd_and_log(path+['--%s=%s'%(x,kw[y]),kw['package']],env=env)
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ define_it()
+ break
+ if'modversion'in kw:
+ version=self.cmd_and_log(path+['--modversion',kw['modversion']],env=env).strip()
+ self.define('%s_VERSION'%Utils.quote_define_name(kw.get('uselib_store',kw['modversion'])),version)
+ return version
+ lst=[]+path
+ defi=kw.get('define_variable',None)
+ if not defi:
+ defi=self.env.PKG_CONFIG_DEFINES or{}
+ for key,val in defi.items():
+ lst.append('--define-variable=%s=%s'%(key,val))
+ static=kw.get('force_static',False)
+ if'args'in kw:
+ args=Utils.to_list(kw['args'])
+ if'--static'in args or'--static-libs'in args:
+ static=True
+ lst+=args
+ lst.extend(Utils.to_list(kw['package']))
+ if'variables'in kw:
+ v_env=kw.get('env',self.env)
+ uselib=kw.get('uselib_store',kw['package'].upper())
+ vars=Utils.to_list(kw['variables'])
+ for v in vars:
+ val=self.cmd_and_log(lst+['--variable='+v],env=env).strip()
+ var='%s_%s'%(uselib,v)
+ v_env[var]=val
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ return
+ ret=self.cmd_and_log(lst,env=env)
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ define_it()
+ self.parse_flags(ret,kw.get('uselib_store',kw['package'].upper()),kw.get('env',self.env),force_static=static,posix=kw.get('posix',None))
+ return ret
+@conf
+def check_cfg(self,*k,**kw):
+ if k:
+ lst=k[0].split()
+ kw['package']=lst[0]
+ kw['args']=' '.join(lst[1:])
+ self.validate_cfg(kw)
+ if'msg'in kw:
+ self.start_msg(kw['msg'],**kw)
+ ret=None
+ try:
+ ret=self.exec_cfg(kw)
+ except self.errors.WafError:
+ if'errmsg'in kw:
+ self.end_msg(kw['errmsg'],'YELLOW',**kw)
+ if Logs.verbose>1:
+ raise
+ else:
+ self.fatal('The configuration failed')
+ else:
+ if not ret:
+ ret=True
+ kw['success']=ret
+ if'okmsg'in kw:
+ self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw)
+ return ret
+def build_fun(bld):
+ if bld.kw['compile_filename']:
+ node=bld.srcnode.make_node(bld.kw['compile_filename'])
+ node.write(bld.kw['code'])
+ o=bld(features=bld.kw['features'],source=bld.kw['compile_filename'],target='testprog')
+ for k,v in bld.kw.items():
+ setattr(o,k,v)
+ if not bld.kw.get('quiet',None):
+ bld.conf.to_log("==>\n%s\n<=="%bld.kw['code'])
+@conf
+def validate_c(self,kw):
+ if not'build_fun'in kw:
+ kw['build_fun']=build_fun
+ if not'env'in kw:
+ kw['env']=self.env.derive()
+ env=kw['env']
+ if not'compiler'in kw and not'features'in kw:
+ kw['compiler']='c'
+ if env['CXX_NAME']and Task.classes.get('cxx',None):
+ kw['compiler']='cxx'
+ if not self.env['CXX']:
+ self.fatal('a c++ compiler is required')
+ else:
+ if not self.env['CC']:
+ self.fatal('a c compiler is required')
+ if not'compile_mode'in kw:
+ kw['compile_mode']='c'
+ if'cxx'in Utils.to_list(kw.get('features',[]))or kw.get('compiler','')=='cxx':
+ kw['compile_mode']='cxx'
+ if not'type'in kw:
+ kw['type']='cprogram'
+ if not'features'in kw:
+ if not'header_name'in kw or kw.get('link_header_test',True):
+ kw['features']=[kw['compile_mode'],kw['type']]
+ else:
+ kw['features']=[kw['compile_mode']]
+ else:
+ kw['features']=Utils.to_list(kw['features'])
+ if not'compile_filename'in kw:
+ kw['compile_filename']='test.c'+((kw['compile_mode']=='cxx')and'pp'or'')
+ def to_header(dct):
+ if'header_name'in dct:
+ dct=Utils.to_list(dct['header_name'])
+ return''.join(['#include <%s>\n'%x for x in dct])
+ return''
+ if'framework_name'in kw:
+ fwkname=kw['framework_name']
+ if not'uselib_store'in kw:
+ kw['uselib_store']=fwkname.upper()
+ if not kw.get('no_header',False):
+ if not'header_name'in kw:
+ kw['header_name']=[]
+ fwk='%s/%s.h'%(fwkname,fwkname)
+ if kw.get('remove_dot_h',None):
+ fwk=fwk[:-2]
+ kw['header_name']=Utils.to_list(kw['header_name'])+[fwk]
+ kw['msg']='Checking for framework %s'%fwkname
+ kw['framework']=fwkname
+ if'function_name'in kw:
+ fu=kw['function_name']
+ if not'msg'in kw:
+ kw['msg']='Checking for function %s'%fu
+ kw['code']=to_header(kw)+SNIP_FUNCTION%fu
+ if not'uselib_store'in kw:
+ kw['uselib_store']=fu.upper()
+ if not'define_name'in kw:
+ kw['define_name']=self.have_define(fu)
+ elif'type_name'in kw:
+ tu=kw['type_name']
+ if not'header_name'in kw:
+ kw['header_name']='stdint.h'
+ if'field_name'in kw:
+ field=kw['field_name']
+ kw['code']=to_header(kw)+SNIP_FIELD%{'type_name':tu,'field_name':field}
+ if not'msg'in kw:
+ kw['msg']='Checking for field %s in %s'%(field,tu)
+ if not'define_name'in kw:
+ kw['define_name']=self.have_define((tu+'_'+field).upper())
+ else:
+ kw['code']=to_header(kw)+SNIP_TYPE%{'type_name':tu}
+ if not'msg'in kw:
+ kw['msg']='Checking for type %s'%tu
+ if not'define_name'in kw:
+ kw['define_name']=self.have_define(tu.upper())
+ elif'header_name'in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for header %s'%kw['header_name']
+ l=Utils.to_list(kw['header_name'])
+ assert len(l)>0,'list of headers in header_name is empty'
+ kw['code']=to_header(kw)+SNIP_EMPTY_PROGRAM
+ if not'uselib_store'in kw:
+ kw['uselib_store']=l[0].upper()
+ if not'define_name'in kw:
+ kw['define_name']=self.have_define(l[0])
+ if'lib'in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for library %s'%kw['lib']
+ if not'uselib_store'in kw:
+ kw['uselib_store']=kw['lib'].upper()
+ if'stlib'in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for static library %s'%kw['stlib']
+ if not'uselib_store'in kw:
+ kw['uselib_store']=kw['stlib'].upper()
+ if'fragment'in kw:
+ kw['code']=kw['fragment']
+ if not'msg'in kw:
+ kw['msg']='Checking for code snippet'
+ if not'errmsg'in kw:
+ kw['errmsg']='no'
+ for(flagsname,flagstype)in(('cxxflags','compiler'),('cflags','compiler'),('linkflags','linker')):
+ if flagsname in kw:
+ if not'msg'in kw:
+ kw['msg']='Checking for %s flags %s'%(flagstype,kw[flagsname])
+ if not'errmsg'in kw:
+ kw['errmsg']='no'
+ if not'execute'in kw:
+ kw['execute']=False
+ if kw['execute']:
+ kw['features'].append('test_exec')
+ kw['chmod']=493
+ if not'errmsg'in kw:
+ kw['errmsg']='not found'
+ if not'okmsg'in kw:
+ kw['okmsg']='yes'
+ if not'code'in kw:
+ kw['code']=SNIP_EMPTY_PROGRAM
+ if self.env[INCKEYS]:
+ kw['code']='\n'.join(['#include <%s>'%x for x in self.env[INCKEYS]])+'\n'+kw['code']
+ if kw.get('merge_config_header',False)or env.merge_config_header:
+ kw['code']='%s\n\n%s'%(self.get_config_header(),kw['code'])
+ env.DEFINES=[]
+ if not kw.get('success'):kw['success']=None
+ if'define_name'in kw:
+ self.undefine(kw['define_name'])
+ if not'msg'in kw:
+ self.fatal('missing "msg" in conf.check(...)')
+@conf
+def post_check(self,*k,**kw):
+ is_success=0
+ if kw['execute']:
+ if kw['success']is not None:
+ if kw.get('define_ret',False):
+ is_success=kw['success']
+ else:
+ is_success=(kw['success']==0)
+ else:
+ is_success=(kw['success']==0)
+ if'define_name'in kw:
+ comment=kw.get('comment','')
+ define_name=kw['define_name']
+ if'header_name'in kw or'function_name'in kw or'type_name'in kw or'fragment'in kw:
+ if kw['execute']and kw.get('define_ret',None)and isinstance(is_success,str):
+ self.define(define_name,is_success,quote=kw.get('quote',1),comment=comment)
+ else:
+ self.define_cond(define_name,is_success,comment=comment)
+ else:
+ self.define_cond(define_name,is_success,comment=comment)
+ if kw.get('global_define',None):
+ self.env[kw['define_name']]=is_success
+ if'header_name'in kw:
+ if kw.get('auto_add_header_name',False):
+ self.env.append_value(INCKEYS,Utils.to_list(kw['header_name']))
+ if is_success and'uselib_store'in kw:
+ from waflib.Tools import ccroot
+ _vars=set([])
+ for x in kw['features']:
+ if x in ccroot.USELIB_VARS:
+ _vars|=ccroot.USELIB_VARS[x]
+ for k in _vars:
+ lk=k.lower()
+ if lk in kw:
+ val=kw[lk]
+ if isinstance(val,str):
+ val=val.rstrip(os.path.sep)
+ self.env.append_unique(k+'_'+kw['uselib_store'],Utils.to_list(val))
+ return is_success
+@conf
+def check(self,*k,**kw):
+ self.validate_c(kw)
+ self.start_msg(kw['msg'],**kw)
+ ret=None
+ try:
+ ret=self.run_build(*k,**kw)
+ except self.errors.ConfigurationError:
+ self.end_msg(kw['errmsg'],'YELLOW',**kw)
+ if Logs.verbose>1:
+ raise
+ else:
+ self.fatal('The configuration failed')
+ else:
+ kw['success']=ret
+ ret=self.post_check(*k,**kw)
+ if not ret:
+ self.end_msg(kw['errmsg'],'YELLOW',**kw)
+ self.fatal('The configuration failed %r'%ret)
+ else:
+ self.end_msg(self.ret_msg(kw['okmsg'],kw),**kw)
+ return ret
+class test_exec(Task.Task):
+ color='PINK'
+ def run(self):
+ if getattr(self.generator,'rpath',None):
+ if getattr(self.generator,'define_ret',False):
+ self.generator.bld.retval=self.generator.bld.cmd_and_log([self.inputs[0].abspath()])
+ else:
+ self.generator.bld.retval=self.generator.bld.exec_command([self.inputs[0].abspath()])
+ else:
+ env=self.env.env or{}
+ env.update(dict(os.environ))
+ for var in('LD_LIBRARY_PATH','DYLD_LIBRARY_PATH','PATH'):
+ env[var]=self.inputs[0].parent.abspath()+os.path.pathsep+env.get(var,'')
+ if getattr(self.generator,'define_ret',False):
+ self.generator.bld.retval=self.generator.bld.cmd_and_log([self.inputs[0].abspath()],env=env)
+ else:
+ self.generator.bld.retval=self.generator.bld.exec_command([self.inputs[0].abspath()],env=env)
+@feature('test_exec')
+@after_method('apply_link')
+def test_exec_fun(self):
+ self.create_task('test_exec',self.link_task.outputs[0])
+@conf
+def check_cxx(self,*k,**kw):
+ kw['compiler']='cxx'
+ return self.check(*k,**kw)
+@conf
+def check_cc(self,*k,**kw):
+ kw['compiler']='c'
+ return self.check(*k,**kw)
+@conf
+def set_define_comment(self,key,comment):
+ coms=self.env.DEFINE_COMMENTS
+ if not coms:
+ coms=self.env.DEFINE_COMMENTS={}
+ coms[key]=comment or''
+@conf
+def get_define_comment(self,key):
+ coms=self.env.DEFINE_COMMENTS or{}
+ return coms.get(key,'')
+@conf
+def define(self,key,val,quote=True,comment=''):
+ assert key and isinstance(key,str)
+ if val is True:
+ val=1
+ elif val in(False,None):
+ val=0
+ if isinstance(val,int)or isinstance(val,float):
+ s='%s=%s'
+ else:
+ s=quote and'%s="%s"'or'%s=%s'
+ app=s%(key,str(val))
+ ban=key+'='
+ lst=self.env['DEFINES']
+ for x in lst:
+ if x.startswith(ban):
+ lst[lst.index(x)]=app
+ break
+ else:
+ self.env.append_value('DEFINES',app)
+ self.env.append_unique(DEFKEYS,key)
+ self.set_define_comment(key,comment)
+@conf
+def undefine(self,key,comment=''):
+ assert key and isinstance(key,str)
+ ban=key+'='
+ lst=[x for x in self.env['DEFINES']if not x.startswith(ban)]
+ self.env['DEFINES']=lst
+ self.env.append_unique(DEFKEYS,key)
+ self.set_define_comment(key,comment)
+@conf
+def define_cond(self,key,val,comment=''):
+ assert key and isinstance(key,str)
+ if val:
+ self.define(key,1,comment=comment)
+ else:
+ self.undefine(key,comment=comment)
+@conf
+def is_defined(self,key):
+ assert key and isinstance(key,str)
+ ban=key+'='
+ for x in self.env['DEFINES']:
+ if x.startswith(ban):
+ return True
+ return False
+@conf
+def get_define(self,key):
+ assert key and isinstance(key,str)
+ ban=key+'='
+ for x in self.env['DEFINES']:
+ if x.startswith(ban):
+ return x[len(ban):]
+ return None
+@conf
+def have_define(self,key):
+ return(self.env.HAVE_PAT or'HAVE_%s')%Utils.quote_define_name(key)
+@conf
+def write_config_header(self,configfile='',guard='',top=False,defines=True,headers=False,remove=True,define_prefix=''):
+ if not configfile:configfile=WAF_CONFIG_H
+ waf_guard=guard or'W_%s_WAF'%Utils.quote_define_name(configfile)
+ node=top and self.bldnode or self.path.get_bld()
+ node=node.make_node(configfile)
+ node.parent.mkdir()
+ lst=['/* WARNING! All changes made to this file will be lost! */\n']
+ lst.append('#ifndef %s\n#define %s\n'%(waf_guard,waf_guard))
+ lst.append(self.get_config_header(defines,headers,define_prefix=define_prefix))
+ lst.append('\n#endif /* %s */\n'%waf_guard)
+ node.write('\n'.join(lst))
+ self.env.append_unique(Build.CFG_FILES,[node.abspath()])
+ if remove:
+ for key in self.env[DEFKEYS]:
+ self.undefine(key)
+ self.env[DEFKEYS]=[]
+@conf
+def get_config_header(self,defines=True,headers=False,define_prefix=''):
+ lst=[]
+ if self.env.WAF_CONFIG_H_PRELUDE:
+ lst.append(self.env.WAF_CONFIG_H_PRELUDE)
+ if headers:
+ for x in self.env[INCKEYS]:
+ lst.append('#include <%s>'%x)
+ if defines:
+ tbl={}
+ for k in self.env['DEFINES']:
+ a,_,b=k.partition('=')
+ tbl[a]=b
+ for k in self.env[DEFKEYS]:
+ caption=self.get_define_comment(k)
+ if caption:
+ caption=' /* %s */'%caption
+ try:
+ txt='#define %s%s %s%s'%(define_prefix,k,tbl[k],caption)
+ except KeyError:
+ txt='/* #undef %s%s */%s'%(define_prefix,k,caption)
+ lst.append(txt)
+ return"\n".join(lst)
+@conf
+def cc_add_flags(conf):
+ conf.add_os_flags('CPPFLAGS',dup=False)
+ conf.add_os_flags('CFLAGS',dup=False)
+@conf
+def cxx_add_flags(conf):
+ conf.add_os_flags('CPPFLAGS',dup=False)
+ conf.add_os_flags('CXXFLAGS',dup=False)
+@conf
+def link_add_flags(conf):
+ conf.add_os_flags('LINKFLAGS',dup=False)
+ conf.add_os_flags('LDFLAGS',dup=False)
+@conf
+def cc_load_tools(conf):
+ if not conf.env.DEST_OS:
+ conf.env.DEST_OS=Utils.unversioned_sys_platform()
+ conf.load('c')
+@conf
+def cxx_load_tools(conf):
+ if not conf.env.DEST_OS:
+ conf.env.DEST_OS=Utils.unversioned_sys_platform()
+ conf.load('cxx')
+@conf
+def get_cc_version(conf,cc,gcc=False,icc=False,clang=False):
+ cmd=cc+['-dM','-E','-']
+ env=conf.env.env or None
+ try:
+ out,err=conf.cmd_and_log(cmd,output=0,input='\n',env=env)
+ except Exception:
+ conf.fatal('Could not determine the compiler version %r'%cmd)
+ if gcc:
+ if out.find('__INTEL_COMPILER')>=0:
+ conf.fatal('The intel compiler pretends to be gcc')
+ if out.find('__GNUC__')<0 and out.find('__clang__')<0:
+ conf.fatal('Could not determine the compiler type')
+ if icc and out.find('__INTEL_COMPILER')<0:
+ conf.fatal('Not icc/icpc')
+ if clang and out.find('__clang__')<0:
+ conf.fatal('Not clang/clang++')
+ if not clang and out.find('__clang__')>=0:
+ conf.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure')
+ k={}
+ if icc or gcc or clang:
+ out=out.splitlines()
+ for line in out:
+ lst=shlex.split(line)
+ if len(lst)>2:
+ key=lst[1]
+ val=lst[2]
+ k[key]=val
+ def isD(var):
+ return var in k
+ if not conf.env.DEST_OS:
+ conf.env.DEST_OS=''
+ for i in MACRO_TO_DESTOS:
+ if isD(i):
+ conf.env.DEST_OS=MACRO_TO_DESTOS[i]
+ break
+ else:
+ if isD('__APPLE__')and isD('__MACH__'):
+ conf.env.DEST_OS='darwin'
+ elif isD('__unix__'):
+ conf.env.DEST_OS='generic'
+ if isD('__ELF__'):
+ conf.env.DEST_BINFMT='elf'
+ elif isD('__WINNT__')or isD('__CYGWIN__')or isD('_WIN32'):
+ conf.env.DEST_BINFMT='pe'
+ conf.env.LIBDIR=conf.env.BINDIR
+ elif isD('__APPLE__'):
+ conf.env.DEST_BINFMT='mac-o'
+ if not conf.env.DEST_BINFMT:
+ conf.env.DEST_BINFMT=Utils.destos_to_binfmt(conf.env.DEST_OS)
+ for i in MACRO_TO_DEST_CPU:
+ if isD(i):
+ conf.env.DEST_CPU=MACRO_TO_DEST_CPU[i]
+ break
+ Logs.debug('ccroot: dest platform: '+' '.join([conf.env[x]or'?'for x in('DEST_OS','DEST_BINFMT','DEST_CPU')]))
+ if icc:
+ ver=k['__INTEL_COMPILER']
+ conf.env['CC_VERSION']=(ver[:-2],ver[-2],ver[-1])
+ else:
+ if isD('__clang__')and isD('__clang_major__'):
+ conf.env['CC_VERSION']=(k['__clang_major__'],k['__clang_minor__'],k['__clang_patchlevel__'])
+ else:
+ conf.env['CC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k.get('__GNUC_PATCHLEVEL__','0'))
+ return k
+@conf
+def get_xlc_version(conf,cc):
+ cmd=cc+['-qversion']
+ try:
+ out,err=conf.cmd_and_log(cmd,output=0)
+ except Errors.WafError:
+ conf.fatal('Could not find xlc %r'%cmd)
+ for v in(r"IBM XL C/C\+\+.* V(?P<major>\d*)\.(?P<minor>\d*)",):
+ version_re=re.compile(v,re.I).search
+ match=version_re(out or err)
+ if match:
+ k=match.groupdict()
+ conf.env['CC_VERSION']=(k['major'],k['minor'])
+ break
+ else:
+ conf.fatal('Could not determine the XLC version.')
+@conf
+def get_suncc_version(conf,cc):
+ cmd=cc+['-V']
+ try:
+ out,err=conf.cmd_and_log(cmd,output=0)
+ except Errors.WafError ,e:
+ if not(hasattr(e,'returncode')and hasattr(e,'stdout')and hasattr(e,'stderr')):
+ conf.fatal('Could not find suncc %r'%cmd)
+ out=e.stdout
+ err=e.stderr
+ version=(out or err)
+ version=version.splitlines()[0]
+ version_re=re.compile(r'cc: (studio.*?|\s+)?(sun\s+(c\+\+|c)|(WorkShop\s+Compilers))?\s+(?P<major>\d*)\.(?P<minor>\d*)',re.I).search
+ match=version_re(version)
+ if match:
+ k=match.groupdict()
+ conf.env['CC_VERSION']=(k['major'],k['minor'])
+ else:
+ conf.fatal('Could not determine the suncc version.')
+@conf
+def add_as_needed(self):
+ if self.env.DEST_BINFMT=='elf'and'gcc'in(self.env.CXX_NAME,self.env.CC_NAME):
+ self.env.append_unique('LINKFLAGS','-Wl,--as-needed')
+class cfgtask(Task.TaskBase):
+ def display(self):
+ return''
+ def runnable_status(self):
+ return Task.RUN_ME
+ def uid(self):
+ return Utils.SIG_NIL
+ def run(self):
+ conf=self.conf
+ bld=Build.BuildContext(top_dir=conf.srcnode.abspath(),out_dir=conf.bldnode.abspath())
+ bld.env=conf.env
+ bld.init_dirs()
+ bld.in_msg=1
+ bld.logger=self.logger
+ try:
+ bld.check(**self.args)
+ except Exception:
+ return 1
+@conf
+def multicheck(self,*k,**kw):
+ self.start_msg(kw.get('msg','Executing %d configuration tests'%len(k)),**kw)
+ class par(object):
+ def __init__(self):
+ self.keep=False
+ self.returned_tasks=[]
+ self.task_sigs={}
+ self.progress_bar=0
+ def total(self):
+ return len(tasks)
+ def to_log(self,*k,**kw):
+ return
+ bld=par()
+ tasks=[]
+ for dct in k:
+ x=cfgtask(bld=bld)
+ tasks.append(x)
+ x.args=dct
+ x.bld=bld
+ x.conf=self
+ x.args=dct
+ x.logger=Logs.make_mem_logger(str(id(x)),self.logger)
+ def it():
+ yield tasks
+ while 1:
+ yield[]
+ p=Runner.Parallel(bld,Options.options.jobs)
+ p.biter=it()
+ p.start()
+ for x in tasks:
+ x.logger.memhandler.flush()
+ if p.error:
+ for x in p.error:
+ if getattr(x,'err_msg',None):
+ self.to_log(x.err_msg)
+ self.end_msg('fail',color='RED')
+ raise Errors.WafError('There is an error in the library, read config.log for more information')
+ for x in tasks:
+ if x.hasrun!=Task.SUCCESS:
+ self.end_msg(kw.get('errmsg','no'),color='YELLOW',**kw)
+ self.fatal(kw.get('fatalmsg',None)or'One of the tests has failed, read config.log for more information')
+ self.end_msg('ok',**kw)
diff --git a/waflib/Tools/c_osx.py b/waflib/Tools/c_osx.py
new file mode 100644
index 0000000..8cb4bce
--- /dev/null
+++ b/waflib/Tools/c_osx.py
@@ -0,0 +1,137 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,shutil,platform
+from waflib import Task,Utils,Errors
+from waflib.TaskGen import taskgen_method,feature,after_method,before_method
+app_info='''
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Created by Waf</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>NOTE</key>
+ <string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>
+ <key>CFBundleExecutable</key>
+ <string>{app_name}</string>
+</dict>
+</plist>
+'''
+@feature('c','cxx')
+def set_macosx_deployment_target(self):
+ if self.env['MACOSX_DEPLOYMENT_TARGET']:
+ os.environ['MACOSX_DEPLOYMENT_TARGET']=self.env['MACOSX_DEPLOYMENT_TARGET']
+ elif'MACOSX_DEPLOYMENT_TARGET'not in os.environ:
+ if Utils.unversioned_sys_platform()=='darwin':
+ os.environ['MACOSX_DEPLOYMENT_TARGET']='.'.join(platform.mac_ver()[0].split('.')[:2])
+@taskgen_method
+def create_bundle_dirs(self,name,out):
+ dir=out.parent.find_or_declare(name)
+ dir.mkdir()
+ macos=dir.find_or_declare(['Contents','MacOS'])
+ macos.mkdir()
+ return dir
+def bundle_name_for_output(out):
+ name=out.name
+ k=name.rfind('.')
+ if k>=0:
+ name=name[:k]+'.app'
+ else:
+ name=name+'.app'
+ return name
+@feature('cprogram','cxxprogram')
+@after_method('apply_link')
+def create_task_macapp(self):
+ if self.env['MACAPP']or getattr(self,'mac_app',False):
+ out=self.link_task.outputs[0]
+ name=bundle_name_for_output(out)
+ dir=self.create_bundle_dirs(name,out)
+ n1=dir.find_or_declare(['Contents','MacOS',out.name])
+ self.apptask=self.create_task('macapp',self.link_task.outputs,n1)
+ inst_to=getattr(self,'install_path','/Applications')+'/%s/Contents/MacOS/'%name
+ self.bld.install_files(inst_to,n1,chmod=Utils.O755)
+ if getattr(self,'mac_files',None):
+ mac_files_root=getattr(self,'mac_files_root',None)
+ if isinstance(mac_files_root,str):
+ mac_files_root=self.path.find_node(mac_files_root)
+ if not mac_files_root:
+ self.bld.fatal('Invalid mac_files_root %r'%self.mac_files_root)
+ res_dir=n1.parent.parent.make_node('Resources')
+ inst_to=getattr(self,'install_path','/Applications')+'/%s/Resources'%name
+ for node in self.to_nodes(self.mac_files):
+ relpath=node.path_from(mac_files_root or node.parent)
+ self.create_task('macapp',node,res_dir.make_node(relpath))
+ self.bld.install_as(os.path.join(inst_to,relpath),node)
+ if getattr(self,'mac_resources',None):
+ res_dir=n1.parent.parent.make_node('Resources')
+ inst_to=getattr(self,'install_path','/Applications')+'/%s/Resources'%name
+ for x in self.to_list(self.mac_resources):
+ node=self.path.find_node(x)
+ if not node:
+ raise Errors.WafError('Missing mac_resource %r in %r'%(x,self))
+ parent=node.parent
+ if os.path.isdir(node.abspath()):
+ nodes=node.ant_glob('**')
+ else:
+ nodes=[node]
+ for node in nodes:
+ rel=node.path_from(parent)
+ self.create_task('macapp',node,res_dir.make_node(rel))
+ self.bld.install_as(inst_to+'/%s'%rel,node)
+ if getattr(self.bld,'is_install',None):
+ self.install_task.hasrun=Task.SKIP_ME
+@feature('cprogram','cxxprogram')
+@after_method('apply_link')
+def create_task_macplist(self):
+ if self.env['MACAPP']or getattr(self,'mac_app',False):
+ out=self.link_task.outputs[0]
+ name=bundle_name_for_output(out)
+ dir=self.create_bundle_dirs(name,out)
+ n1=dir.find_or_declare(['Contents','Info.plist'])
+ self.plisttask=plisttask=self.create_task('macplist',[],n1)
+ plisttask.context={'app_name':self.link_task.outputs[0].name,'env':self.env}
+ plist_ctx=getattr(self,'plist_context',None)
+ if(plist_ctx):
+ plisttask.context.update(plist_ctx)
+ if getattr(self,'mac_plist',False):
+ node=self.path.find_resource(self.mac_plist)
+ if node:
+ plisttask.inputs.append(node)
+ else:
+ plisttask.code=self.mac_plist
+ else:
+ plisttask.code=app_info
+ inst_to=getattr(self,'install_path','/Applications')+'/%s/Contents/'%name
+ self.bld.install_files(inst_to,n1)
+@feature('cshlib','cxxshlib')
+@before_method('apply_link','propagate_uselib_vars')
+def apply_bundle(self):
+ if self.env['MACBUNDLE']or getattr(self,'mac_bundle',False):
+ self.env['LINKFLAGS_cshlib']=self.env['LINKFLAGS_cxxshlib']=[]
+ self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['macbundle_PATTERN']
+ use=self.use=self.to_list(getattr(self,'use',[]))
+ if not'MACBUNDLE'in use:
+ use.append('MACBUNDLE')
+app_dirs=['Contents','Contents/MacOS','Contents/Resources']
+class macapp(Task.Task):
+ color='PINK'
+ def run(self):
+ self.outputs[0].parent.mkdir()
+ shutil.copy2(self.inputs[0].srcpath(),self.outputs[0].abspath())
+class macplist(Task.Task):
+ color='PINK'
+ ext_in=['.bin']
+ def run(self):
+ if getattr(self,'code',None):
+ txt=self.code
+ else:
+ txt=self.inputs[0].read()
+ context=getattr(self,'context',{})
+ txt=txt.format(**context)
+ self.outputs[0].write(txt)
diff --git a/waflib/Tools/c_preproc.py b/waflib/Tools/c_preproc.py
new file mode 100644
index 0000000..846ca07
--- /dev/null
+++ b/waflib/Tools/c_preproc.py
@@ -0,0 +1,611 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re,string,traceback
+from waflib import Logs,Utils,Errors
+from waflib.Logs import debug,error
+class PreprocError(Errors.WafError):
+ pass
+POPFILE='-'
+recursion_limit=150
+go_absolute=False
+standard_includes=['/usr/include']
+if Utils.is_win32:
+ standard_includes=[]
+use_trigraphs=0
+strict_quotes=0
+g_optrans={'not':'!','not_eq':'!','and':'&&','and_eq':'&=','or':'||','or_eq':'|=','xor':'^','xor_eq':'^=','bitand':'&','bitor':'|','compl':'~',}
+re_lines=re.compile('^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$',re.IGNORECASE|re.MULTILINE)
+re_mac=re.compile("^[a-zA-Z_]\w*")
+re_fun=re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]')
+re_pragma_once=re.compile('^\s*once\s*',re.IGNORECASE)
+re_nl=re.compile('\\\\\r*\n',re.MULTILINE)
+re_cpp=re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',re.DOTALL|re.MULTILINE)
+trig_def=[('??'+a,b)for a,b in zip("=-/!'()<>",r'#~\|^[]{}')]
+chr_esc={'0':0,'a':7,'b':8,'t':9,'n':10,'f':11,'v':12,'r':13,'\\':92,"'":39}
+NUM='i'
+OP='O'
+IDENT='T'
+STR='s'
+CHAR='c'
+tok_types=[NUM,STR,IDENT,OP]
+exp_types=[r"""0[xX](?P<hex>[a-fA-F0-9]+)(?P<qual1>[uUlL]*)|L*?'(?P<char>(\\.|[^\\'])+)'|(?P<n1>\d+)[Ee](?P<exp0>[+-]*?\d+)(?P<float0>[fFlL]*)|(?P<n2>\d*\.\d+)([Ee](?P<exp1>[+-]*?\d+))?(?P<float1>[fFlL]*)|(?P<n4>\d+\.\d*)([Ee](?P<exp2>[+-]*?\d+))?(?P<float2>[fFlL]*)|(?P<oct>0*)(?P<n0>\d+)(?P<qual2>[uUlL]*)""",r'L?"([^"\\]|\\.)*"',r'[a-zA-Z_]\w*',r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]',]
+re_clexer=re.compile('|'.join(["(?P<%s>%s)"%(name,part)for name,part in zip(tok_types,exp_types)]),re.M)
+accepted='a'
+ignored='i'
+undefined='u'
+skipped='s'
+def repl(m):
+ s=m.group(0)
+ if s.startswith('/'):
+ return' '
+ return s
+def filter_comments(filename):
+ code=Utils.readf(filename)
+ if use_trigraphs:
+ for(a,b)in trig_def:code=code.split(a).join(b)
+ code=re_nl.sub('',code)
+ code=re_cpp.sub(repl,code)
+ return[(m.group(2),m.group(3))for m in re.finditer(re_lines,code)]
+prec={}
+ops=['* / %','+ -','<< >>','< <= >= >','== !=','& | ^','&& ||',',']
+for x in range(len(ops)):
+ syms=ops[x]
+ for u in syms.split():
+ prec[u]=x
+def trimquotes(s):
+ if not s:return''
+ s=s.rstrip()
+ if s[0]=="'"and s[-1]=="'":return s[1:-1]
+ return s
+def reduce_nums(val_1,val_2,val_op):
+ try:a=0+val_1
+ except TypeError:a=int(val_1)
+ try:b=0+val_2
+ except TypeError:b=int(val_2)
+ d=val_op
+ if d=='%':c=a%b
+ elif d=='+':c=a+b
+ elif d=='-':c=a-b
+ elif d=='*':c=a*b
+ elif d=='/':c=a/b
+ elif d=='^':c=a^b
+ elif d=='==':c=int(a==b)
+ elif d=='|'or d=='bitor':c=a|b
+ elif d=='||'or d=='or':c=int(a or b)
+ elif d=='&'or d=='bitand':c=a&b
+ elif d=='&&'or d=='and':c=int(a and b)
+ elif d=='!='or d=='not_eq':c=int(a!=b)
+ elif d=='^'or d=='xor':c=int(a^b)
+ elif d=='<=':c=int(a<=b)
+ elif d=='<':c=int(a<b)
+ elif d=='>':c=int(a>b)
+ elif d=='>=':c=int(a>=b)
+ elif d=='<<':c=a<<b
+ elif d=='>>':c=a>>b
+ else:c=0
+ return c
+def get_num(lst):
+ if not lst:raise PreprocError("empty list for get_num")
+ (p,v)=lst[0]
+ if p==OP:
+ if v=='(':
+ count_par=1
+ i=1
+ while i<len(lst):
+ (p,v)=lst[i]
+ if p==OP:
+ if v==')':
+ count_par-=1
+ if count_par==0:
+ break
+ elif v=='(':
+ count_par+=1
+ i+=1
+ else:
+ raise PreprocError("rparen expected %r"%lst)
+ (num,_)=get_term(lst[1:i])
+ return(num,lst[i+1:])
+ elif v=='+':
+ return get_num(lst[1:])
+ elif v=='-':
+ num,lst=get_num(lst[1:])
+ return(reduce_nums('-1',num,'*'),lst)
+ elif v=='!':
+ num,lst=get_num(lst[1:])
+ return(int(not int(num)),lst)
+ elif v=='~':
+ num,lst=get_num(lst[1:])
+ return(~int(num),lst)
+ else:
+ raise PreprocError("Invalid op token %r for get_num"%lst)
+ elif p==NUM:
+ return v,lst[1:]
+ elif p==IDENT:
+ return 0,lst[1:]
+ else:
+ raise PreprocError("Invalid token %r for get_num"%lst)
+def get_term(lst):
+ if not lst:raise PreprocError("empty list for get_term")
+ num,lst=get_num(lst)
+ if not lst:
+ return(num,[])
+ (p,v)=lst[0]
+ if p==OP:
+ if v==',':
+ return get_term(lst[1:])
+ elif v=='?':
+ count_par=0
+ i=1
+ while i<len(lst):
+ (p,v)=lst[i]
+ if p==OP:
+ if v==')':
+ count_par-=1
+ elif v=='(':
+ count_par+=1
+ elif v==':':
+ if count_par==0:
+ break
+ i+=1
+ else:
+ raise PreprocError("rparen expected %r"%lst)
+ if int(num):
+ return get_term(lst[1:i])
+ else:
+ return get_term(lst[i+1:])
+ else:
+ num2,lst=get_num(lst[1:])
+ if not lst:
+ num2=reduce_nums(num,num2,v)
+ return get_term([(NUM,num2)]+lst)
+ p2,v2=lst[0]
+ if p2!=OP:
+ raise PreprocError("op expected %r"%lst)
+ if prec[v2]>=prec[v]:
+ num2=reduce_nums(num,num2,v)
+ return get_term([(NUM,num2)]+lst)
+ else:
+ num3,lst=get_num(lst[1:])
+ num3=reduce_nums(num2,num3,v2)
+ return get_term([(NUM,num),(p,v),(NUM,num3)]+lst)
+ raise PreprocError("cannot reduce %r"%lst)
+def reduce_eval(lst):
+ num,lst=get_term(lst)
+ return(NUM,num)
+def stringize(lst):
+ lst=[str(v2)for(p2,v2)in lst]
+ return"".join(lst)
+def paste_tokens(t1,t2):
+ p1=None
+ if t1[0]==OP and t2[0]==OP:
+ p1=OP
+ elif t1[0]==IDENT and(t2[0]==IDENT or t2[0]==NUM):
+ p1=IDENT
+ elif t1[0]==NUM and t2[0]==NUM:
+ p1=NUM
+ if not p1:
+ raise PreprocError('tokens do not make a valid paste %r and %r'%(t1,t2))
+ return(p1,t1[1]+t2[1])
+def reduce_tokens(lst,defs,ban=[]):
+ i=0
+ while i<len(lst):
+ (p,v)=lst[i]
+ if p==IDENT and v=="defined":
+ del lst[i]
+ if i<len(lst):
+ (p2,v2)=lst[i]
+ if p2==IDENT:
+ if v2 in defs:
+ lst[i]=(NUM,1)
+ else:
+ lst[i]=(NUM,0)
+ elif p2==OP and v2=='(':
+ del lst[i]
+ (p2,v2)=lst[i]
+ del lst[i]
+ if v2 in defs:
+ lst[i]=(NUM,1)
+ else:
+ lst[i]=(NUM,0)
+ else:
+ raise PreprocError("Invalid define expression %r"%lst)
+ elif p==IDENT and v in defs:
+ if isinstance(defs[v],str):
+ a,b=extract_macro(defs[v])
+ defs[v]=b
+ macro_def=defs[v]
+ to_add=macro_def[1]
+ if isinstance(macro_def[0],list):
+ del lst[i]
+ accu=to_add[:]
+ reduce_tokens(accu,defs,ban+[v])
+ for x in range(len(accu)):
+ lst.insert(i,accu[x])
+ i+=1
+ else:
+ args=[]
+ del lst[i]
+ if i>=len(lst):
+ raise PreprocError("expected '(' after %r (got nothing)"%v)
+ (p2,v2)=lst[i]
+ if p2!=OP or v2!='(':
+ raise PreprocError("expected '(' after %r"%v)
+ del lst[i]
+ one_param=[]
+ count_paren=0
+ while i<len(lst):
+ p2,v2=lst[i]
+ del lst[i]
+ if p2==OP and count_paren==0:
+ if v2=='(':
+ one_param.append((p2,v2))
+ count_paren+=1
+ elif v2==')':
+ if one_param:args.append(one_param)
+ break
+ elif v2==',':
+ if not one_param:raise PreprocError("empty param in funcall %s"%v)
+ args.append(one_param)
+ one_param=[]
+ else:
+ one_param.append((p2,v2))
+ else:
+ one_param.append((p2,v2))
+ if v2=='(':count_paren+=1
+ elif v2==')':count_paren-=1
+ else:
+ raise PreprocError('malformed macro')
+ accu=[]
+ arg_table=macro_def[0]
+ j=0
+ while j<len(to_add):
+ (p2,v2)=to_add[j]
+ if p2==OP and v2=='#':
+ if j+1<len(to_add)and to_add[j+1][0]==IDENT and to_add[j+1][1]in arg_table:
+ toks=args[arg_table[to_add[j+1][1]]]
+ accu.append((STR,stringize(toks)))
+ j+=1
+ else:
+ accu.append((p2,v2))
+ elif p2==OP and v2=='##':
+ if accu and j+1<len(to_add):
+ t1=accu[-1]
+ if to_add[j+1][0]==IDENT and to_add[j+1][1]in arg_table:
+ toks=args[arg_table[to_add[j+1][1]]]
+ if toks:
+ accu[-1]=paste_tokens(t1,toks[0])
+ accu.extend(toks[1:])
+ else:
+ accu.append((p2,v2))
+ accu.extend(toks)
+ elif to_add[j+1][0]==IDENT and to_add[j+1][1]=='__VA_ARGS__':
+ va_toks=[]
+ st=len(macro_def[0])
+ pt=len(args)
+ for x in args[pt-st+1:]:
+ va_toks.extend(x)
+ va_toks.append((OP,','))
+ if va_toks:va_toks.pop()
+ if len(accu)>1:
+ (p3,v3)=accu[-1]
+ (p4,v4)=accu[-2]
+ if v3=='##':
+ accu.pop()
+ if v4==','and pt<st:
+ accu.pop()
+ accu+=va_toks
+ else:
+ accu[-1]=paste_tokens(t1,to_add[j+1])
+ j+=1
+ else:
+ accu.append((p2,v2))
+ elif p2==IDENT and v2 in arg_table:
+ toks=args[arg_table[v2]]
+ reduce_tokens(toks,defs,ban+[v])
+ accu.extend(toks)
+ else:
+ accu.append((p2,v2))
+ j+=1
+ reduce_tokens(accu,defs,ban+[v])
+ for x in range(len(accu)-1,-1,-1):
+ lst.insert(i,accu[x])
+ i+=1
+def eval_macro(lst,defs):
+ reduce_tokens(lst,defs,[])
+ if not lst:raise PreprocError("missing tokens to evaluate")
+ (p,v)=reduce_eval(lst)
+ return int(v)!=0
+def extract_macro(txt):
+ t=tokenize(txt)
+ if re_fun.search(txt):
+ p,name=t[0]
+ p,v=t[1]
+ if p!=OP:raise PreprocError("expected open parenthesis")
+ i=1
+ pindex=0
+ params={}
+ prev='('
+ while 1:
+ i+=1
+ p,v=t[i]
+ if prev=='(':
+ if p==IDENT:
+ params[v]=pindex
+ pindex+=1
+ prev=p
+ elif p==OP and v==')':
+ break
+ else:
+ raise PreprocError("unexpected token (3)")
+ elif prev==IDENT:
+ if p==OP and v==',':
+ prev=v
+ elif p==OP and v==')':
+ break
+ else:
+ raise PreprocError("comma or ... expected")
+ elif prev==',':
+ if p==IDENT:
+ params[v]=pindex
+ pindex+=1
+ prev=p
+ elif p==OP and v=='...':
+ raise PreprocError("not implemented (1)")
+ else:
+ raise PreprocError("comma or ... expected (2)")
+ elif prev=='...':
+ raise PreprocError("not implemented (2)")
+ else:
+ raise PreprocError("unexpected else")
+ return(name,[params,t[i+1:]])
+ else:
+ (p,v)=t[0]
+ if len(t)>1:
+ return(v,[[],t[1:]])
+ else:
+ return(v,[[],[('T','')]])
+re_include=re.compile('^\s*(<(?P<a>.*)>|"(?P<b>.*)")')
+def extract_include(txt,defs):
+ m=re_include.search(txt)
+ if m:
+ if m.group('a'):return'<',m.group('a')
+ if m.group('b'):return'"',m.group('b')
+ toks=tokenize(txt)
+ reduce_tokens(toks,defs,['waf_include'])
+ if not toks:
+ raise PreprocError("could not parse include %s"%txt)
+ if len(toks)==1:
+ if toks[0][0]==STR:
+ return'"',toks[0][1]
+ else:
+ if toks[0][1]=='<'and toks[-1][1]=='>':
+ ret='<',stringize(toks).lstrip('<').rstrip('>')
+ return ret
+ raise PreprocError("could not parse include %s."%txt)
+def parse_char(txt):
+ if not txt:raise PreprocError("attempted to parse a null char")
+ if txt[0]!='\\':
+ return ord(txt)
+ c=txt[1]
+ if c=='x':
+ if len(txt)==4 and txt[3]in string.hexdigits:return int(txt[2:],16)
+ return int(txt[2:],16)
+ elif c.isdigit():
+ if c=='0'and len(txt)==2:return 0
+ for i in 3,2,1:
+ if len(txt)>i and txt[1:1+i].isdigit():
+ return(1+i,int(txt[1:1+i],8))
+ else:
+ try:return chr_esc[c]
+ except KeyError:raise PreprocError("could not parse char literal '%s'"%txt)
+def tokenize(s):
+ return tokenize_private(s)[:]
+@Utils.run_once
+def tokenize_private(s):
+ ret=[]
+ for match in re_clexer.finditer(s):
+ m=match.group
+ for name in tok_types:
+ v=m(name)
+ if v:
+ if name==IDENT:
+ try:
+ g_optrans[v]
+ name=OP
+ except KeyError:
+ if v.lower()=="true":
+ v=1
+ name=NUM
+ elif v.lower()=="false":
+ v=0
+ name=NUM
+ elif name==NUM:
+ if m('oct'):v=int(v,8)
+ elif m('hex'):v=int(m('hex'),16)
+ elif m('n0'):v=m('n0')
+ else:
+ v=m('char')
+ if v:v=parse_char(v)
+ else:v=m('n2')or m('n4')
+ elif name==OP:
+ if v=='%:':v='#'
+ elif v=='%:%:':v='##'
+ elif name==STR:
+ v=v[1:-1]
+ ret.append((name,v))
+ break
+ return ret
+@Utils.run_once
+def define_name(line):
+ return re_mac.match(line).group(0)
+class c_parser(object):
+ def __init__(self,nodepaths=None,defines=None):
+ self.lines=[]
+ if defines is None:
+ self.defs={}
+ else:
+ self.defs=dict(defines)
+ self.state=[]
+ self.count_files=0
+ self.currentnode_stack=[]
+ self.nodepaths=nodepaths or[]
+ self.nodes=[]
+ self.names=[]
+ self.curfile=''
+ self.ban_includes=set([])
+ def cached_find_resource(self,node,filename):
+ try:
+ nd=node.ctx.cache_nd
+ except AttributeError:
+ nd=node.ctx.cache_nd={}
+ tup=(node,filename)
+ try:
+ return nd[tup]
+ except KeyError:
+ ret=node.find_resource(filename)
+ if ret:
+ if getattr(ret,'children',None):
+ ret=None
+ elif ret.is_child_of(node.ctx.bldnode):
+ tmp=node.ctx.srcnode.search_node(ret.path_from(node.ctx.bldnode))
+ if tmp and getattr(tmp,'children',None):
+ ret=None
+ nd[tup]=ret
+ return ret
+ def tryfind(self,filename):
+ if filename.endswith('.moc'):
+ self.names.append(filename)
+ return None
+ self.curfile=filename
+ found=self.cached_find_resource(self.currentnode_stack[-1],filename)
+ for n in self.nodepaths:
+ if found:
+ break
+ found=self.cached_find_resource(n,filename)
+ if found and not found in self.ban_includes:
+ self.nodes.append(found)
+ self.addlines(found)
+ else:
+ if not filename in self.names:
+ self.names.append(filename)
+ return found
+ def addlines(self,node):
+ self.currentnode_stack.append(node.parent)
+ filepath=node.abspath()
+ self.count_files+=1
+ if self.count_files>recursion_limit:
+ raise PreprocError("recursion limit exceeded")
+ pc=self.parse_cache
+ debug('preproc: reading file %r',filepath)
+ try:
+ lns=pc[filepath]
+ except KeyError:
+ pass
+ else:
+ self.lines.extend(lns)
+ return
+ try:
+ lines=filter_comments(filepath)
+ lines.append((POPFILE,''))
+ lines.reverse()
+ pc[filepath]=lines
+ self.lines.extend(lines)
+ except IOError:
+ raise PreprocError("could not read the file %s"%filepath)
+ except Exception:
+ if Logs.verbose>0:
+ error("parsing %s failed"%filepath)
+ traceback.print_exc()
+ def start(self,node,env):
+ debug('preproc: scanning %s (in %s)',node.name,node.parent.name)
+ bld=node.ctx
+ try:
+ self.parse_cache=bld.parse_cache
+ except AttributeError:
+ self.parse_cache=bld.parse_cache={}
+ self.current_file=node
+ self.addlines(node)
+ if env['DEFINES']:
+ try:
+ lst=['%s %s'%(x[0],trimquotes('='.join(x[1:])))for x in[y.split('=')for y in env['DEFINES']]]
+ lst.reverse()
+ self.lines.extend([('define',x)for x in lst])
+ except AttributeError:
+ pass
+ while self.lines:
+ (token,line)=self.lines.pop()
+ if token==POPFILE:
+ self.count_files-=1
+ self.currentnode_stack.pop()
+ continue
+ try:
+ ve=Logs.verbose
+ if ve:debug('preproc: line is %s - %s state is %s',token,line,self.state)
+ state=self.state
+ if token[:2]=='if':
+ state.append(undefined)
+ elif token=='endif':
+ state.pop()
+ if token[0]!='e':
+ if skipped in self.state or ignored in self.state:
+ continue
+ if token=='if':
+ ret=eval_macro(tokenize(line),self.defs)
+ if ret:state[-1]=accepted
+ else:state[-1]=ignored
+ elif token=='ifdef':
+ m=re_mac.match(line)
+ if m and m.group(0)in self.defs:state[-1]=accepted
+ else:state[-1]=ignored
+ elif token=='ifndef':
+ m=re_mac.match(line)
+ if m and m.group(0)in self.defs:state[-1]=ignored
+ else:state[-1]=accepted
+ elif token=='include'or token=='import':
+ (kind,inc)=extract_include(line,self.defs)
+ if ve:debug('preproc: include found %s (%s) ',inc,kind)
+ if kind=='"'or not strict_quotes:
+ self.current_file=self.tryfind(inc)
+ if token=='import':
+ self.ban_includes.add(self.current_file)
+ elif token=='elif':
+ if state[-1]==accepted:
+ state[-1]=skipped
+ elif state[-1]==ignored:
+ if eval_macro(tokenize(line),self.defs):
+ state[-1]=accepted
+ elif token=='else':
+ if state[-1]==accepted:state[-1]=skipped
+ elif state[-1]==ignored:state[-1]=accepted
+ elif token=='define':
+ try:
+ self.defs[define_name(line)]=line
+ except Exception:
+ raise PreprocError("Invalid define line %s"%line)
+ elif token=='undef':
+ m=re_mac.match(line)
+ if m and m.group(0)in self.defs:
+ self.defs.__delitem__(m.group(0))
+ elif token=='pragma':
+ if re_pragma_once.match(line.lower()):
+ self.ban_includes.add(self.current_file)
+ except Exception ,e:
+ if Logs.verbose:
+ debug('preproc: line parsing failed (%s): %s %s',e,line,Utils.ex_stack())
+def scan(task):
+ global go_absolute
+ try:
+ incn=task.generator.includes_nodes
+ except AttributeError:
+ raise Errors.WafError('%r is missing a feature such as "c", "cxx" or "includes": '%task.generator)
+ if go_absolute:
+ nodepaths=incn+[task.generator.bld.root.find_dir(x)for x in standard_includes]
+ else:
+ nodepaths=[x for x in incn if x.is_child_of(x.ctx.srcnode)or x.is_child_of(x.ctx.bldnode)]
+ tmp=c_parser(nodepaths)
+ tmp.start(task.inputs[0],task.env)
+ if Logs.verbose:
+ debug('deps: deps for %r: %r; unresolved %r'%(task.inputs,tmp.nodes,tmp.names))
+ return(tmp.nodes,tmp.names)
diff --git a/waflib/Tools/c_tests.py b/waflib/Tools/c_tests.py
new file mode 100644
index 0000000..7791f23
--- /dev/null
+++ b/waflib/Tools/c_tests.py
@@ -0,0 +1,152 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Task
+from waflib.Configure import conf
+from waflib.TaskGen import feature,before_method,after_method
+LIB_CODE='''
+#ifdef _MSC_VER
+#define testEXPORT __declspec(dllexport)
+#else
+#define testEXPORT
+#endif
+testEXPORT int lib_func(void) { return 9; }
+'''
+MAIN_CODE='''
+#ifdef _MSC_VER
+#define testEXPORT __declspec(dllimport)
+#else
+#define testEXPORT
+#endif
+testEXPORT int lib_func(void);
+int main(int argc, char **argv) {
+ (void)argc; (void)argv;
+ return !(lib_func() == 9);
+}
+'''
+@feature('link_lib_test')
+@before_method('process_source')
+def link_lib_test_fun(self):
+ def write_test_file(task):
+ task.outputs[0].write(task.generator.code)
+ rpath=[]
+ if getattr(self,'add_rpath',False):
+ rpath=[self.bld.path.get_bld().abspath()]
+ mode=self.mode
+ m='%s %s'%(mode,mode)
+ ex=self.test_exec and'test_exec'or''
+ bld=self.bld
+ bld(rule=write_test_file,target='test.'+mode,code=LIB_CODE)
+ bld(rule=write_test_file,target='main.'+mode,code=MAIN_CODE)
+ bld(features='%sshlib'%m,source='test.'+mode,target='test')
+ bld(features='%sprogram %s'%(m,ex),source='main.'+mode,target='app',use='test',rpath=rpath)
+@conf
+def check_library(self,mode=None,test_exec=True):
+ if not mode:
+ mode='c'
+ if self.env.CXX:
+ mode='cxx'
+ self.check(compile_filename=[],features='link_lib_test',msg='Checking for libraries',mode=mode,test_exec=test_exec,)
+INLINE_CODE='''
+typedef int foo_t;
+static %s foo_t static_foo () {return 0; }
+%s foo_t foo () {
+ return 0;
+}
+'''
+INLINE_VALUES=['inline','__inline__','__inline']
+@conf
+def check_inline(self,**kw):
+ self.start_msg('Checking for inline')
+ if not'define_name'in kw:
+ kw['define_name']='INLINE_MACRO'
+ if not'features'in kw:
+ if self.env.CXX:
+ kw['features']=['cxx']
+ else:
+ kw['features']=['c']
+ for x in INLINE_VALUES:
+ kw['fragment']=INLINE_CODE%(x,x)
+ try:
+ self.check(**kw)
+ except self.errors.ConfigurationError:
+ continue
+ else:
+ self.end_msg(x)
+ if x!='inline':
+ self.define('inline',x,quote=False)
+ return x
+ self.fatal('could not use inline functions')
+LARGE_FRAGMENT='''#include <unistd.h>
+int main(int argc, char **argv) {
+ (void)argc; (void)argv;
+ return !(sizeof(off_t) >= 8);
+}
+'''
+@conf
+def check_large_file(self,**kw):
+ if not'define_name'in kw:
+ kw['define_name']='HAVE_LARGEFILE'
+ if not'execute'in kw:
+ kw['execute']=True
+ if not'features'in kw:
+ if self.env.CXX:
+ kw['features']=['cxx','cxxprogram']
+ else:
+ kw['features']=['c','cprogram']
+ kw['fragment']=LARGE_FRAGMENT
+ kw['msg']='Checking for large file support'
+ ret=True
+ try:
+ if self.env.DEST_BINFMT!='pe':
+ ret=self.check(**kw)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ if ret:
+ return True
+ kw['msg']='Checking for -D_FILE_OFFSET_BITS=64'
+ kw['defines']=['_FILE_OFFSET_BITS=64']
+ try:
+ ret=self.check(**kw)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ self.define('_FILE_OFFSET_BITS',64)
+ return ret
+ self.fatal('There is no support for large files')
+ENDIAN_FRAGMENT='''
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+}
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+}
+extern int foo;
+'''
+class grep_for_endianness(Task.Task):
+ color='PINK'
+ def run(self):
+ txt=self.inputs[0].read(flags='rb').decode('iso8859-1')
+ if txt.find('LiTTleEnDian')>-1:
+ self.generator.tmp.append('little')
+ elif txt.find('BIGenDianSyS')>-1:
+ self.generator.tmp.append('big')
+ else:
+ return-1
+@feature('grep_for_endianness')
+@after_method('process_source')
+def grep_for_endianness_fun(self):
+ self.create_task('grep_for_endianness',self.compiled_tasks[0].outputs[0])
+@conf
+def check_endianness(self):
+ tmp=[]
+ def check_msg(self):
+ return tmp[0]
+ self.check(fragment=ENDIAN_FRAGMENT,features='c grep_for_endianness',msg="Checking for endianness",define='ENDIANNESS',tmp=tmp,okmsg=check_msg)
+ return tmp[0]
diff --git a/waflib/Tools/ccroot.py b/waflib/Tools/ccroot.py
new file mode 100644
index 0000000..498a0ab
--- /dev/null
+++ b/waflib/Tools/ccroot.py
@@ -0,0 +1,447 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re
+from waflib import Task,Utils,Node,Errors
+from waflib.TaskGen import after_method,before_method,feature,taskgen_method,extension
+from waflib.Tools import c_aliases,c_preproc,c_config,c_osx,c_tests
+from waflib.Configure import conf
+SYSTEM_LIB_PATHS=['/usr/lib64','/usr/lib','/usr/local/lib64','/usr/local/lib']
+USELIB_VARS=Utils.defaultdict(set)
+USELIB_VARS['c']=set(['INCLUDES','FRAMEWORKPATH','DEFINES','CPPFLAGS','CCDEPS','CFLAGS','ARCH'])
+USELIB_VARS['cxx']=set(['INCLUDES','FRAMEWORKPATH','DEFINES','CPPFLAGS','CXXDEPS','CXXFLAGS','ARCH'])
+USELIB_VARS['d']=set(['INCLUDES','DFLAGS'])
+USELIB_VARS['includes']=set(['INCLUDES','FRAMEWORKPATH','ARCH'])
+USELIB_VARS['cprogram']=USELIB_VARS['cxxprogram']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS','FRAMEWORK','FRAMEWORKPATH','ARCH','LDFLAGS'])
+USELIB_VARS['cshlib']=USELIB_VARS['cxxshlib']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS','FRAMEWORK','FRAMEWORKPATH','ARCH','LDFLAGS'])
+USELIB_VARS['cstlib']=USELIB_VARS['cxxstlib']=set(['ARFLAGS','LINKDEPS'])
+USELIB_VARS['dprogram']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS'])
+USELIB_VARS['dshlib']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS'])
+USELIB_VARS['dstlib']=set(['ARFLAGS','LINKDEPS'])
+USELIB_VARS['asm']=set(['ASFLAGS'])
+@taskgen_method
+def create_compiled_task(self,name,node):
+ out='%s.%d.o'%(node.name,self.idx)
+ task=self.create_task(name,node,node.parent.find_or_declare(out))
+ try:
+ self.compiled_tasks.append(task)
+ except AttributeError:
+ self.compiled_tasks=[task]
+ return task
+@taskgen_method
+def to_incnodes(self,inlst):
+ lst=[]
+ seen=set([])
+ for x in self.to_list(inlst):
+ if x in seen or not x:
+ continue
+ seen.add(x)
+ if isinstance(x,Node.Node):
+ lst.append(x)
+ else:
+ if os.path.isabs(x):
+ lst.append(self.bld.root.make_node(x)or x)
+ else:
+ if x[0]=='#':
+ p=self.bld.bldnode.make_node(x[1:])
+ v=self.bld.srcnode.make_node(x[1:])
+ else:
+ p=self.path.get_bld().make_node(x)
+ v=self.path.make_node(x)
+ if p.is_child_of(self.bld.bldnode):
+ p.mkdir()
+ lst.append(p)
+ lst.append(v)
+ return lst
+@feature('c','cxx','d','asm','fc','includes')
+@after_method('propagate_uselib_vars','process_source')
+def apply_incpaths(self):
+ lst=self.to_incnodes(self.to_list(getattr(self,'includes',[]))+self.env['INCLUDES'])
+ self.includes_nodes=lst
+ self.env['INCPATHS']=[x.abspath()for x in lst]
+class link_task(Task.Task):
+ color='YELLOW'
+ inst_to=None
+ chmod=Utils.O755
+ def add_target(self,target):
+ if isinstance(target,str):
+ pattern=self.env[self.__class__.__name__+'_PATTERN']
+ if not pattern:
+ pattern='%s'
+ folder,name=os.path.split(target)
+ if self.__class__.__name__.find('shlib')>0 and getattr(self.generator,'vnum',None):
+ nums=self.generator.vnum.split('.')
+ if self.env.DEST_BINFMT=='pe':
+ name=name+'-'+nums[0]
+ elif self.env.DEST_OS=='openbsd':
+ pattern='%s.%s'%(pattern,nums[0])
+ if len(nums)>=2:
+ pattern+='.%s'%nums[1]
+ if folder:
+ tmp=folder+os.sep+pattern%name
+ else:
+ tmp=pattern%name
+ target=self.generator.path.find_or_declare(tmp)
+ self.set_outputs(target)
+class stlink_task(link_task):
+ run_str='${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
+ chmod=Utils.O644
+def rm_tgt(cls):
+ old=cls.run
+ def wrap(self):
+ try:os.remove(self.outputs[0].abspath())
+ except OSError:pass
+ return old(self)
+ setattr(cls,'run',wrap)
+rm_tgt(stlink_task)
+@feature('c','cxx','d','fc','asm')
+@after_method('process_source')
+def apply_link(self):
+ for x in self.features:
+ if x=='cprogram'and'cxx'in self.features:
+ x='cxxprogram'
+ elif x=='cshlib'and'cxx'in self.features:
+ x='cxxshlib'
+ if x in Task.classes:
+ if issubclass(Task.classes[x],link_task):
+ link=x
+ break
+ else:
+ return
+ objs=[t.outputs[0]for t in getattr(self,'compiled_tasks',[])]
+ self.link_task=self.create_task(link,objs)
+ self.link_task.add_target(self.target)
+ try:
+ inst_to=self.install_path
+ except AttributeError:
+ inst_to=self.link_task.__class__.inst_to
+ if inst_to:
+ self.install_task=self.bld.install_files(inst_to,self.link_task.outputs[:],env=self.env,chmod=self.link_task.chmod,task=self.link_task)
+@taskgen_method
+def use_rec(self,name,**kw):
+ if name in self.tmp_use_not or name in self.tmp_use_seen:
+ return
+ try:
+ y=self.bld.get_tgen_by_name(name)
+ except Errors.WafError:
+ self.uselib.append(name)
+ self.tmp_use_not.add(name)
+ return
+ self.tmp_use_seen.append(name)
+ y.post()
+ y.tmp_use_objects=objects=kw.get('objects',True)
+ y.tmp_use_stlib=stlib=kw.get('stlib',True)
+ try:
+ link_task=y.link_task
+ except AttributeError:
+ y.tmp_use_var=''
+ else:
+ objects=False
+ if not isinstance(link_task,stlink_task):
+ stlib=False
+ y.tmp_use_var='LIB'
+ else:
+ y.tmp_use_var='STLIB'
+ p=self.tmp_use_prec
+ for x in self.to_list(getattr(y,'use',[])):
+ if self.env["STLIB_"+x]:
+ continue
+ try:
+ p[x].append(name)
+ except KeyError:
+ p[x]=[name]
+ self.use_rec(x,objects=objects,stlib=stlib)
+@feature('c','cxx','d','use','fc')
+@before_method('apply_incpaths','propagate_uselib_vars')
+@after_method('apply_link','process_source')
+def process_use(self):
+ use_not=self.tmp_use_not=set([])
+ self.tmp_use_seen=[]
+ use_prec=self.tmp_use_prec={}
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ self.includes=self.to_list(getattr(self,'includes',[]))
+ names=self.to_list(getattr(self,'use',[]))
+ for x in names:
+ self.use_rec(x)
+ for x in use_not:
+ if x in use_prec:
+ del use_prec[x]
+ out=[]
+ tmp=[]
+ for x in self.tmp_use_seen:
+ for k in use_prec.values():
+ if x in k:
+ break
+ else:
+ tmp.append(x)
+ while tmp:
+ e=tmp.pop()
+ out.append(e)
+ try:
+ nlst=use_prec[e]
+ except KeyError:
+ pass
+ else:
+ del use_prec[e]
+ for x in nlst:
+ for y in use_prec:
+ if x in use_prec[y]:
+ break
+ else:
+ tmp.append(x)
+ if use_prec:
+ raise Errors.WafError('Cycle detected in the use processing %r'%use_prec)
+ out.reverse()
+ link_task=getattr(self,'link_task',None)
+ for x in out:
+ y=self.bld.get_tgen_by_name(x)
+ var=y.tmp_use_var
+ if var and link_task:
+ if var=='LIB'or y.tmp_use_stlib or x in names:
+ self.env.append_value(var,[y.target[y.target.rfind(os.sep)+1:]])
+ self.link_task.dep_nodes.extend(y.link_task.outputs)
+ tmp_path=y.link_task.outputs[0].parent.path_from(self.bld.bldnode)
+ self.env.append_unique(var+'PATH',[tmp_path])
+ else:
+ if y.tmp_use_objects:
+ self.add_objects_from_tgen(y)
+ if getattr(y,'export_includes',None):
+ self.includes.extend(y.to_incnodes(y.export_includes))
+ if getattr(y,'export_defines',None):
+ self.env.append_value('DEFINES',self.to_list(y.export_defines))
+ for x in names:
+ try:
+ y=self.bld.get_tgen_by_name(x)
+ except Errors.WafError:
+ if not self.env['STLIB_'+x]and not x in self.uselib:
+ self.uselib.append(x)
+ else:
+ for k in self.to_list(getattr(y,'use',[])):
+ if not self.env['STLIB_'+k]and not k in self.uselib:
+ self.uselib.append(k)
+@taskgen_method
+def accept_node_to_link(self,node):
+ return not node.name.endswith('.pdb')
+@taskgen_method
+def add_objects_from_tgen(self,tg):
+ try:
+ link_task=self.link_task
+ except AttributeError:
+ pass
+ else:
+ for tsk in getattr(tg,'compiled_tasks',[]):
+ for x in tsk.outputs:
+ if self.accept_node_to_link(x):
+ link_task.inputs.append(x)
+@taskgen_method
+def get_uselib_vars(self):
+ _vars=set([])
+ for x in self.features:
+ if x in USELIB_VARS:
+ _vars|=USELIB_VARS[x]
+ return _vars
+@feature('c','cxx','d','fc','javac','cs','uselib','asm')
+@after_method('process_use')
+def propagate_uselib_vars(self):
+ _vars=self.get_uselib_vars()
+ env=self.env
+ app=env.append_value
+ feature_uselib=self.features+self.to_list(getattr(self,'uselib',[]))
+ for var in _vars:
+ y=var.lower()
+ val=getattr(self,y,[])
+ if val:
+ app(var,self.to_list(val))
+ for x in feature_uselib:
+ val=env['%s_%s'%(var,x)]
+ if val:
+ app(var,val)
+@feature('cshlib','cxxshlib','fcshlib')
+@after_method('apply_link')
+def apply_implib(self):
+ if not self.env.DEST_BINFMT=='pe':
+ return
+ dll=self.link_task.outputs[0]
+ if isinstance(self.target,Node.Node):
+ name=self.target.name
+ else:
+ name=os.path.split(self.target)[1]
+ implib=self.env['implib_PATTERN']%name
+ implib=dll.parent.find_or_declare(implib)
+ self.env.append_value('LINKFLAGS',self.env['IMPLIB_ST']%implib.bldpath())
+ self.link_task.outputs.append(implib)
+ if getattr(self,'defs',None)and self.env.DEST_BINFMT=='pe':
+ node=self.path.find_resource(self.defs)
+ if not node:
+ raise Errors.WafError('invalid def file %r'%self.defs)
+ if'msvc'in(self.env.CC_NAME,self.env.CXX_NAME):
+ self.env.append_value('LINKFLAGS','/def:%s'%node.path_from(self.bld.bldnode))
+ self.link_task.dep_nodes.append(node)
+ else:
+ self.link_task.inputs.append(node)
+ if getattr(self,'install_task',None):
+ try:
+ inst_to=self.install_path_implib
+ except AttributeError:
+ try:
+ inst_to=self.install_path
+ except AttributeError:
+ inst_to='${IMPLIBDIR}'
+ self.install_task.dest='${BINDIR}'
+ if not self.env.IMPLIBDIR:
+ self.env.IMPLIBDIR=self.env.LIBDIR
+ self.implib_install_task=self.bld.install_files(inst_to,implib,env=self.env,chmod=self.link_task.chmod,task=self.link_task)
+re_vnum=re.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)){0,2}?$')
+@feature('cshlib','cxxshlib','dshlib','fcshlib','vnum')
+@after_method('apply_link','propagate_uselib_vars')
+def apply_vnum(self):
+ if not getattr(self,'vnum','')or os.name!='posix'or self.env.DEST_BINFMT not in('elf','mac-o'):
+ return
+ link=self.link_task
+ if not re_vnum.match(self.vnum):
+ raise Errors.WafError('Invalid vnum %r for target %r'%(self.vnum,getattr(self,'name',self)))
+ nums=self.vnum.split('.')
+ node=link.outputs[0]
+ cnum=getattr(self,'cnum',str(nums[0]))
+ cnums=cnum.split('.')
+ if len(cnums)>len(nums)or nums[0:len(cnums)]!=cnums:
+ raise Errors.WafError('invalid compatibility version %s'%cnum)
+ libname=node.name
+ if libname.endswith('.dylib'):
+ name3=libname.replace('.dylib','.%s.dylib'%self.vnum)
+ name2=libname.replace('.dylib','.%s.dylib'%cnum)
+ else:
+ name3=libname+'.'+self.vnum
+ name2=libname+'.'+cnum
+ if self.env.SONAME_ST:
+ v=self.env.SONAME_ST%name2
+ self.env.append_value('LINKFLAGS',v.split())
+ if self.env.DEST_OS!='openbsd':
+ outs=[node.parent.find_or_declare(name3)]
+ if name2!=name3:
+ outs.append(node.parent.find_or_declare(name2))
+ self.create_task('vnum',node,outs)
+ if getattr(self,'install_task',None):
+ self.install_task.hasrun=Task.SKIP_ME
+ bld=self.bld
+ path=self.install_task.dest
+ if self.env.DEST_OS=='openbsd':
+ libname=self.link_task.outputs[0].name
+ t1=bld.install_as('%s%s%s'%(path,os.sep,libname),node,env=self.env,chmod=self.link_task.chmod)
+ self.vnum_install_task=(t1,)
+ else:
+ t1=bld.install_as(path+os.sep+name3,node,env=self.env,chmod=self.link_task.chmod)
+ t3=bld.symlink_as(path+os.sep+libname,name3)
+ if name2!=name3:
+ t2=bld.symlink_as(path+os.sep+name2,name3)
+ self.vnum_install_task=(t1,t2,t3)
+ else:
+ self.vnum_install_task=(t1,t3)
+ if'-dynamiclib'in self.env['LINKFLAGS']:
+ try:
+ inst_to=self.install_path
+ except AttributeError:
+ inst_to=self.link_task.__class__.inst_to
+ if inst_to:
+ p=Utils.subst_vars(inst_to,self.env)
+ path=os.path.join(p,name2)
+ self.env.append_value('LINKFLAGS',['-install_name',path])
+ self.env.append_value('LINKFLAGS','-Wl,-compatibility_version,%s'%cnum)
+ self.env.append_value('LINKFLAGS','-Wl,-current_version,%s'%self.vnum)
+class vnum(Task.Task):
+ color='CYAN'
+ quient=True
+ ext_in=['.bin']
+ def keyword(self):
+ return'Symlinking'
+ def run(self):
+ for x in self.outputs:
+ path=x.abspath()
+ try:
+ os.remove(path)
+ except OSError:
+ pass
+ try:
+ os.symlink(self.inputs[0].name,path)
+ except OSError:
+ return 1
+class fake_shlib(link_task):
+ def runnable_status(self):
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ for x in self.outputs:
+ x.sig=Utils.h_file(x.abspath())
+ return Task.SKIP_ME
+class fake_stlib(stlink_task):
+ def runnable_status(self):
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ for x in self.outputs:
+ x.sig=Utils.h_file(x.abspath())
+ return Task.SKIP_ME
+@conf
+def read_shlib(self,name,paths=[],export_includes=[],export_defines=[]):
+ return self(name=name,features='fake_lib',lib_paths=paths,lib_type='shlib',export_includes=export_includes,export_defines=export_defines)
+@conf
+def read_stlib(self,name,paths=[],export_includes=[],export_defines=[]):
+ return self(name=name,features='fake_lib',lib_paths=paths,lib_type='stlib',export_includes=export_includes,export_defines=export_defines)
+lib_patterns={'shlib':['lib%s.so','%s.so','lib%s.dylib','lib%s.dll','%s.dll'],'stlib':['lib%s.a','%s.a','lib%s.dll','%s.dll','lib%s.lib','%s.lib'],}
+@feature('fake_lib')
+def process_lib(self):
+ node=None
+ names=[x%self.name for x in lib_patterns[self.lib_type]]
+ for x in self.lib_paths+[self.path]+SYSTEM_LIB_PATHS:
+ if not isinstance(x,Node.Node):
+ x=self.bld.root.find_node(x)or self.path.find_node(x)
+ if not x:
+ continue
+ for y in names:
+ node=x.find_node(y)
+ if node:
+ node.sig=Utils.h_file(node.abspath())
+ break
+ else:
+ continue
+ break
+ else:
+ raise Errors.WafError('could not find library %r'%self.name)
+ self.link_task=self.create_task('fake_%s'%self.lib_type,[],[node])
+ self.target=self.name
+class fake_o(Task.Task):
+ def runnable_status(self):
+ return Task.SKIP_ME
+@extension('.o','.obj')
+def add_those_o_files(self,node):
+ tsk=self.create_task('fake_o',[],node)
+ try:
+ self.compiled_tasks.append(tsk)
+ except AttributeError:
+ self.compiled_tasks=[tsk]
+@feature('fake_obj')
+@before_method('process_source')
+def process_objs(self):
+ for node in self.to_nodes(self.source):
+ self.add_those_o_files(node)
+ self.source=[]
+@conf
+def read_object(self,obj):
+ if not isinstance(obj,self.path.__class__):
+ obj=self.path.find_resource(obj)
+ return self(features='fake_obj',source=obj,name=obj.name)
+@feature('cxxprogram','cprogram')
+@after_method('apply_link','process_use')
+def set_full_paths_hpux(self):
+ if self.env.DEST_OS!='hp-ux':
+ return
+ base=self.bld.bldnode.abspath()
+ for var in['LIBPATH','STLIBPATH']:
+ lst=[]
+ for x in self.env[var]:
+ if x.startswith('/'):
+ lst.append(x)
+ else:
+ lst.append(os.path.normpath(os.path.join(base,x)))
+ self.env[var]=lst
diff --git a/waflib/Tools/clang.py b/waflib/Tools/clang.py
new file mode 100644
index 0000000..9379f5a
--- /dev/null
+++ b/waflib/Tools/clang.py
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar,gcc
+from waflib.Configure import conf
+@conf
+def find_clang(conf):
+ cc=conf.find_program('clang',var='CC')
+ conf.get_cc_version(cc,clang=True)
+ conf.env.CC_NAME='clang'
+def configure(conf):
+ conf.find_clang()
+ conf.find_program(['llvm-ar','ar'],var='AR')
+ conf.find_ar()
+ conf.gcc_common_flags()
+ conf.gcc_modifier_platform()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/clangxx.py b/waflib/Tools/clangxx.py
new file mode 100644
index 0000000..fc97135
--- /dev/null
+++ b/waflib/Tools/clangxx.py
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar,gxx
+from waflib.Configure import conf
+@conf
+def find_clangxx(conf):
+ cxx=conf.find_program('clang++',var='CXX')
+ conf.get_cc_version(cxx,clang=True)
+ conf.env.CXX_NAME='clang'
+def configure(conf):
+ conf.find_clangxx()
+ conf.find_program(['llvm-ar','ar'],var='AR')
+ conf.find_ar()
+ conf.gxx_common_flags()
+ conf.gxx_modifier_platform()
+ conf.cxx_load_tools()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/compiler_c.py b/waflib/Tools/compiler_c.py
new file mode 100644
index 0000000..3d7f34e
--- /dev/null
+++ b/waflib/Tools/compiler_c.py
@@ -0,0 +1,40 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib.Tools import ccroot
+from waflib import Utils
+from waflib.Logs import debug
+c_compiler={'win32':['msvc','gcc','clang'],'cygwin':['gcc'],'darwin':['clang','gcc'],'aix':['xlc','gcc','clang'],'linux':['gcc','clang','icc'],'sunos':['suncc','gcc'],'irix':['gcc','irixcc'],'hpux':['gcc'],'osf1V':['gcc'],'gnu':['gcc','clang'],'java':['gcc','msvc','clang','icc'],'default':['gcc','clang'],}
+def default_compilers():
+ build_platform=Utils.unversioned_sys_platform()
+ possible_compiler_list=c_compiler.get(build_platform,c_compiler['default'])
+ return' '.join(possible_compiler_list)
+def configure(conf):
+ try:test_for_compiler=conf.options.check_c_compiler or default_compilers()
+ except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_c')")
+ for compiler in re.split('[ ,]+',test_for_compiler):
+ conf.env.stash()
+ conf.start_msg('Checking for %r (C compiler)'%compiler)
+ try:
+ conf.load(compiler)
+ except conf.errors.ConfigurationError ,e:
+ conf.env.revert()
+ conf.end_msg(False)
+ debug('compiler_c: %r'%e)
+ else:
+ if conf.env['CC']:
+ conf.end_msg(conf.env.get_flat('CC'))
+ conf.env['COMPILER_CC']=compiler
+ break
+ conf.end_msg(False)
+ else:
+ conf.fatal('could not configure a C compiler!')
+def options(opt):
+ test_for_compiler=default_compilers()
+ opt.load_special_tools('c_*.py',ban=['c_dumbpreproc.py'])
+ cc_compiler_opts=opt.add_option_group('Configuration options')
+ cc_compiler_opts.add_option('--check-c-compiler',default=None,help='list of C compilers to try [%s]'%test_for_compiler,dest="check_c_compiler")
+ for x in test_for_compiler.split():
+ opt.load('%s'%x)
diff --git a/waflib/Tools/compiler_cxx.py b/waflib/Tools/compiler_cxx.py
new file mode 100644
index 0000000..eb5d8da
--- /dev/null
+++ b/waflib/Tools/compiler_cxx.py
@@ -0,0 +1,40 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib.Tools import ccroot
+from waflib import Utils
+from waflib.Logs import debug
+cxx_compiler={'win32':['msvc','g++','clang++'],'cygwin':['g++'],'darwin':['clang++','g++'],'aix':['xlc++','g++','clang++'],'linux':['g++','clang++','icpc'],'sunos':['sunc++','g++'],'irix':['g++'],'hpux':['g++'],'osf1V':['g++'],'gnu':['g++','clang++'],'java':['g++','msvc','clang++','icpc'],'default':['g++','clang++']}
+def default_compilers():
+ build_platform=Utils.unversioned_sys_platform()
+ possible_compiler_list=cxx_compiler.get(build_platform,cxx_compiler['default'])
+ return' '.join(possible_compiler_list)
+def configure(conf):
+ try:test_for_compiler=conf.options.check_cxx_compiler or default_compilers()
+ except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_cxx')")
+ for compiler in re.split('[ ,]+',test_for_compiler):
+ conf.env.stash()
+ conf.start_msg('Checking for %r (C++ compiler)'%compiler)
+ try:
+ conf.load(compiler)
+ except conf.errors.ConfigurationError ,e:
+ conf.env.revert()
+ conf.end_msg(False)
+ debug('compiler_cxx: %r'%e)
+ else:
+ if conf.env['CXX']:
+ conf.end_msg(conf.env.get_flat('CXX'))
+ conf.env['COMPILER_CXX']=compiler
+ break
+ conf.end_msg(False)
+ else:
+ conf.fatal('could not configure a C++ compiler!')
+def options(opt):
+ test_for_compiler=default_compilers()
+ opt.load_special_tools('cxx_*.py')
+ cxx_compiler_opts=opt.add_option_group('Configuration options')
+ cxx_compiler_opts.add_option('--check-cxx-compiler',default=None,help='list of C++ compilers to try [%s]'%test_for_compiler,dest="check_cxx_compiler")
+ for x in test_for_compiler.split():
+ opt.load('%s'%x)
diff --git a/waflib/Tools/compiler_d.py b/waflib/Tools/compiler_d.py
new file mode 100644
index 0000000..0d81675
--- /dev/null
+++ b/waflib/Tools/compiler_d.py
@@ -0,0 +1,37 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils,Logs
+d_compiler={'default':['gdc','dmd','ldc2']}
+def default_compilers():
+ build_platform=Utils.unversioned_sys_platform()
+ possible_compiler_list=d_compiler.get(build_platform,d_compiler['default'])
+ return' '.join(possible_compiler_list)
+def configure(conf):
+ try:test_for_compiler=conf.options.check_d_compiler or default_compilers()
+ except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_d')")
+ for compiler in re.split('[ ,]+',test_for_compiler):
+ conf.env.stash()
+ conf.start_msg('Checking for %r (D compiler)'%compiler)
+ try:
+ conf.load(compiler)
+ except conf.errors.ConfigurationError ,e:
+ conf.env.revert()
+ conf.end_msg(False)
+ Logs.debug('compiler_d: %r'%e)
+ else:
+ if conf.env.D:
+ conf.end_msg(conf.env.get_flat('D'))
+ conf.env['COMPILER_D']=compiler
+ break
+ conf.end_msg(False)
+ else:
+ conf.fatal('could not configure a D compiler!')
+def options(opt):
+ test_for_compiler=default_compilers()
+ d_compiler_opts=opt.add_option_group('Configuration options')
+ d_compiler_opts.add_option('--check-d-compiler',default=None,help='list of D compilers to try [%s]'%test_for_compiler,dest='check_d_compiler')
+ for x in test_for_compiler.split():
+ opt.load('%s'%x)
diff --git a/waflib/Tools/compiler_fc.py b/waflib/Tools/compiler_fc.py
new file mode 100644
index 0000000..2cdeeb4
--- /dev/null
+++ b/waflib/Tools/compiler_fc.py
@@ -0,0 +1,39 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils,Logs
+from waflib.Tools import fc
+fc_compiler={'win32':['gfortran','ifort'],'darwin':['gfortran','g95','ifort'],'linux':['gfortran','g95','ifort'],'java':['gfortran','g95','ifort'],'default':['gfortran'],'aix':['gfortran']}
+def default_compilers():
+ build_platform=Utils.unversioned_sys_platform()
+ possible_compiler_list=fc_compiler.get(build_platform,fc_compiler['default'])
+ return' '.join(possible_compiler_list)
+def configure(conf):
+ try:test_for_compiler=conf.options.check_fortran_compiler or default_compilers()
+ except AttributeError:conf.fatal("Add options(opt): opt.load('compiler_fc')")
+ for compiler in re.split('[ ,]+',test_for_compiler):
+ conf.env.stash()
+ conf.start_msg('Checking for %r (Fortran compiler)'%compiler)
+ try:
+ conf.load(compiler)
+ except conf.errors.ConfigurationError ,e:
+ conf.env.revert()
+ conf.end_msg(False)
+ Logs.debug('compiler_fortran: %r'%e)
+ else:
+ if conf.env['FC']:
+ conf.end_msg(conf.env.get_flat('FC'))
+ conf.env.COMPILER_FORTRAN=compiler
+ break
+ conf.end_msg(False)
+ else:
+ conf.fatal('could not configure a Fortran compiler!')
+def options(opt):
+ test_for_compiler=default_compilers()
+ opt.load_special_tools('fc_*.py')
+ fortran_compiler_opts=opt.add_option_group('Configuration options')
+ fortran_compiler_opts.add_option('--check-fortran-compiler',default=None,help='list of Fortran compiler to try [%s]'%test_for_compiler,dest="check_fortran_compiler")
+ for x in test_for_compiler.split():
+ opt.load('%s'%x)
diff --git a/waflib/Tools/cs.py b/waflib/Tools/cs.py
new file mode 100644
index 0000000..8f1589a
--- /dev/null
+++ b/waflib/Tools/cs.py
@@ -0,0 +1,132 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Utils,Task,Options,Errors
+from waflib.TaskGen import before_method,after_method,feature
+from waflib.Tools import ccroot
+from waflib.Configure import conf
+import os,tempfile
+ccroot.USELIB_VARS['cs']=set(['CSFLAGS','ASSEMBLIES','RESOURCES'])
+ccroot.lib_patterns['csshlib']=['%s']
+@feature('cs')
+@before_method('process_source')
+def apply_cs(self):
+ cs_nodes=[]
+ no_nodes=[]
+ for x in self.to_nodes(self.source):
+ if x.name.endswith('.cs'):
+ cs_nodes.append(x)
+ else:
+ no_nodes.append(x)
+ self.source=no_nodes
+ bintype=getattr(self,'bintype',self.gen.endswith('.dll')and'library'or'exe')
+ self.cs_task=tsk=self.create_task('mcs',cs_nodes,self.path.find_or_declare(self.gen))
+ tsk.env.CSTYPE='/target:%s'%bintype
+ tsk.env.OUT='/out:%s'%tsk.outputs[0].abspath()
+ self.env.append_value('CSFLAGS','/platform:%s'%getattr(self,'platform','anycpu'))
+ inst_to=getattr(self,'install_path',bintype=='exe'and'${BINDIR}'or'${LIBDIR}')
+ if inst_to:
+ mod=getattr(self,'chmod',bintype=='exe'and Utils.O755 or Utils.O644)
+ self.install_task=self.bld.install_files(inst_to,self.cs_task.outputs[:],env=self.env,chmod=mod)
+@feature('cs')
+@after_method('apply_cs')
+def use_cs(self):
+ names=self.to_list(getattr(self,'use',[]))
+ get=self.bld.get_tgen_by_name
+ for x in names:
+ try:
+ y=get(x)
+ except Errors.WafError:
+ self.env.append_value('CSFLAGS','/reference:%s'%x)
+ continue
+ y.post()
+ tsk=getattr(y,'cs_task',None)or getattr(y,'link_task',None)
+ if not tsk:
+ self.bld.fatal('cs task has no link task for use %r'%self)
+ self.cs_task.dep_nodes.extend(tsk.outputs)
+ self.cs_task.set_run_after(tsk)
+ self.env.append_value('CSFLAGS','/reference:%s'%tsk.outputs[0].abspath())
+@feature('cs')
+@after_method('apply_cs','use_cs')
+def debug_cs(self):
+ csdebug=getattr(self,'csdebug',self.env.CSDEBUG)
+ if not csdebug:
+ return
+ node=self.cs_task.outputs[0]
+ if self.env.CS_NAME=='mono':
+ out=node.parent.find_or_declare(node.name+'.mdb')
+ else:
+ out=node.change_ext('.pdb')
+ self.cs_task.outputs.append(out)
+ try:
+ self.install_task.source.append(out)
+ except AttributeError:
+ pass
+ if csdebug=='pdbonly':
+ val=['/debug+','/debug:pdbonly']
+ elif csdebug=='full':
+ val=['/debug+','/debug:full']
+ else:
+ val=['/debug-']
+ self.env.append_value('CSFLAGS',val)
+class mcs(Task.Task):
+ color='YELLOW'
+ run_str='${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'
+ def exec_command(self,cmd,**kw):
+ bld=self.generator.bld
+ try:
+ if not kw.get('cwd',None):
+ kw['cwd']=bld.cwd
+ except AttributeError:
+ bld.cwd=kw['cwd']=bld.variant_dir
+ try:
+ tmp=None
+ if isinstance(cmd,list)and len(' '.join(cmd))>=8192:
+ program=cmd[0]
+ cmd=[self.quote_response_command(x)for x in cmd]
+ (fd,tmp)=tempfile.mkstemp()
+ os.write(fd,'\r\n'.join(i.replace('\\','\\\\')for i in cmd[1:]))
+ os.close(fd)
+ cmd=[program,'@'+tmp]
+ ret=self.generator.bld.exec_command(cmd,**kw)
+ finally:
+ if tmp:
+ try:
+ os.remove(tmp)
+ except OSError:
+ pass
+ return ret
+ def quote_response_command(self,flag):
+ if flag.lower()=='/noconfig':
+ return''
+ if flag.find(' ')>-1:
+ for x in('/r:','/reference:','/resource:','/lib:','/out:'):
+ if flag.startswith(x):
+ flag='%s"%s"'%(x,'","'.join(flag[len(x):].split(',')))
+ break
+ else:
+ flag='"%s"'%flag
+ return flag
+def configure(conf):
+ csc=getattr(Options.options,'cscbinary',None)
+ if csc:
+ conf.env.MCS=csc
+ conf.find_program(['csc','mcs','gmcs'],var='MCS')
+ conf.env.ASS_ST='/r:%s'
+ conf.env.RES_ST='/resource:%s'
+ conf.env.CS_NAME='csc'
+ if str(conf.env.MCS).lower().find('mcs')>-1:
+ conf.env.CS_NAME='mono'
+def options(opt):
+ opt.add_option('--with-csc-binary',type='string',dest='cscbinary')
+class fake_csshlib(Task.Task):
+ color='YELLOW'
+ inst_to=None
+ def runnable_status(self):
+ for x in self.outputs:
+ x.sig=Utils.h_file(x.abspath())
+ return Task.SKIP_ME
+@conf
+def read_csshlib(self,name,paths=[]):
+ return self(name=name,features='fake_lib',lib_paths=paths,lib_type='csshlib')
diff --git a/waflib/Tools/cxx.py b/waflib/Tools/cxx.py
new file mode 100644
index 0000000..6f039e9
--- /dev/null
+++ b/waflib/Tools/cxx.py
@@ -0,0 +1,26 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import TaskGen,Task
+from waflib.Tools import c_preproc
+from waflib.Tools.ccroot import link_task,stlink_task
+@TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')
+def cxx_hook(self,node):
+ return self.create_compiled_task('cxx',node)
+if not'.c'in TaskGen.task_gen.mappings:
+ TaskGen.task_gen.mappings['.c']=TaskGen.task_gen.mappings['.cpp']
+class cxx(Task.Task):
+ run_str='${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT[0].abspath()}'
+ vars=['CXXDEPS']
+ ext_in=['.h']
+ scan=c_preproc.scan
+class cxxprogram(link_task):
+ run_str='${LINK_CXX} ${LINKFLAGS} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LDFLAGS}'
+ vars=['LINKDEPS']
+ ext_out=['.bin']
+ inst_to='${BINDIR}'
+class cxxshlib(cxxprogram):
+ inst_to='${LIBDIR}'
+class cxxstlib(stlink_task):
+ pass
diff --git a/waflib/Tools/d.py b/waflib/Tools/d.py
new file mode 100644
index 0000000..e8c98f0
--- /dev/null
+++ b/waflib/Tools/d.py
@@ -0,0 +1,54 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Utils,Task,Errors
+from waflib.TaskGen import taskgen_method,feature,extension
+from waflib.Tools import d_scan,d_config
+from waflib.Tools.ccroot import link_task,stlink_task
+class d(Task.Task):
+ color='GREEN'
+ run_str='${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F:SRC} ${D_TGT_F:TGT}'
+ scan=d_scan.scan
+class d_with_header(d):
+ run_str='${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F:tgt.outputs[1].bldpath()} ${D_SRC_F:SRC} ${D_TGT_F:tgt.outputs[0].bldpath()}'
+class d_header(Task.Task):
+ color='BLUE'
+ run_str='${D} ${D_HEADER} ${SRC}'
+class dprogram(link_task):
+ run_str='${D_LINKER} ${LINKFLAGS} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F:TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${DLIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB}'
+ inst_to='${BINDIR}'
+class dshlib(dprogram):
+ inst_to='${LIBDIR}'
+class dstlib(stlink_task):
+ pass
+@extension('.d','.di','.D')
+def d_hook(self,node):
+ ext=Utils.destos_to_binfmt(self.env.DEST_OS)=='pe'and'obj'or'o'
+ out='%s.%d.%s'%(node.name,self.idx,ext)
+ def create_compiled_task(self,name,node):
+ task=self.create_task(name,node,node.parent.find_or_declare(out))
+ try:
+ self.compiled_tasks.append(task)
+ except AttributeError:
+ self.compiled_tasks=[task]
+ return task
+ if getattr(self,'generate_headers',None):
+ tsk=create_compiled_task(self,'d_with_header',node)
+ tsk.outputs.append(node.change_ext(self.env['DHEADER_ext']))
+ else:
+ tsk=create_compiled_task(self,'d',node)
+ return tsk
+@taskgen_method
+def generate_header(self,filename):
+ try:
+ self.header_lst.append([filename,self.install_path])
+ except AttributeError:
+ self.header_lst=[[filename,self.install_path]]
+@feature('d')
+def process_header(self):
+ for i in getattr(self,'header_lst',[]):
+ node=self.path.find_resource(i[0])
+ if not node:
+ raise Errors.WafError('file %r not found on d obj'%i[0])
+ self.create_task('d_header',node,node.change_ext('.di'))
diff --git a/waflib/Tools/d_config.py b/waflib/Tools/d_config.py
new file mode 100644
index 0000000..71b7b6e
--- /dev/null
+++ b/waflib/Tools/d_config.py
@@ -0,0 +1,52 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Utils
+from waflib.Configure import conf
+@conf
+def d_platform_flags(self):
+ v=self.env
+ if not v.DEST_OS:
+ v.DEST_OS=Utils.unversioned_sys_platform()
+ binfmt=Utils.destos_to_binfmt(self.env.DEST_OS)
+ if binfmt=='pe':
+ v['dprogram_PATTERN']='%s.exe'
+ v['dshlib_PATTERN']='lib%s.dll'
+ v['dstlib_PATTERN']='lib%s.a'
+ elif binfmt=='mac-o':
+ v['dprogram_PATTERN']='%s'
+ v['dshlib_PATTERN']='lib%s.dylib'
+ v['dstlib_PATTERN']='lib%s.a'
+ else:
+ v['dprogram_PATTERN']='%s'
+ v['dshlib_PATTERN']='lib%s.so'
+ v['dstlib_PATTERN']='lib%s.a'
+DLIB='''
+version(D_Version2) {
+ import std.stdio;
+ int main() {
+ writefln("phobos2");
+ return 0;
+ }
+} else {
+ version(Tango) {
+ import tango.stdc.stdio;
+ int main() {
+ printf("tango");
+ return 0;
+ }
+ } else {
+ import std.stdio;
+ int main() {
+ writefln("phobos1");
+ return 0;
+ }
+ }
+}
+'''
+@conf
+def check_dlibrary(self,execute=True):
+ ret=self.check_cc(features='d dprogram',fragment=DLIB,compile_filename='test.d',execute=execute,define_ret=True)
+ if execute:
+ self.env.DLIBRARY=ret.strip()
diff --git a/waflib/Tools/d_scan.py b/waflib/Tools/d_scan.py
new file mode 100644
index 0000000..47f9196
--- /dev/null
+++ b/waflib/Tools/d_scan.py
@@ -0,0 +1,133 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils,Logs
+def filter_comments(filename):
+ txt=Utils.readf(filename)
+ i=0
+ buf=[]
+ max=len(txt)
+ begin=0
+ while i<max:
+ c=txt[i]
+ if c=='"'or c=="'":
+ buf.append(txt[begin:i])
+ delim=c
+ i+=1
+ while i<max:
+ c=txt[i]
+ if c==delim:break
+ elif c=='\\':
+ i+=1
+ i+=1
+ i+=1
+ begin=i
+ elif c=='/':
+ buf.append(txt[begin:i])
+ i+=1
+ if i==max:break
+ c=txt[i]
+ if c=='+':
+ i+=1
+ nesting=1
+ c=None
+ while i<max:
+ prev=c
+ c=txt[i]
+ if prev=='/'and c=='+':
+ nesting+=1
+ c=None
+ elif prev=='+'and c=='/':
+ nesting-=1
+ if nesting==0:break
+ c=None
+ i+=1
+ elif c=='*':
+ i+=1
+ c=None
+ while i<max:
+ prev=c
+ c=txt[i]
+ if prev=='*'and c=='/':break
+ i+=1
+ elif c=='/':
+ i+=1
+ while i<max and txt[i]!='\n':
+ i+=1
+ else:
+ begin=i-1
+ continue
+ i+=1
+ begin=i
+ buf.append(' ')
+ else:
+ i+=1
+ buf.append(txt[begin:])
+ return buf
+class d_parser(object):
+ def __init__(self,env,incpaths):
+ self.allnames=[]
+ self.re_module=re.compile("module\s+([^;]+)")
+ self.re_import=re.compile("import\s+([^;]+)")
+ self.re_import_bindings=re.compile("([^:]+):(.*)")
+ self.re_import_alias=re.compile("[^=]+=(.+)")
+ self.env=env
+ self.nodes=[]
+ self.names=[]
+ self.incpaths=incpaths
+ def tryfind(self,filename):
+ found=0
+ for n in self.incpaths:
+ found=n.find_resource(filename.replace('.','/')+'.d')
+ if found:
+ self.nodes.append(found)
+ self.waiting.append(found)
+ break
+ if not found:
+ if not filename in self.names:
+ self.names.append(filename)
+ def get_strings(self,code):
+ self.module=''
+ lst=[]
+ mod_name=self.re_module.search(code)
+ if mod_name:
+ self.module=re.sub('\s+','',mod_name.group(1))
+ import_iterator=self.re_import.finditer(code)
+ if import_iterator:
+ for import_match in import_iterator:
+ import_match_str=re.sub('\s+','',import_match.group(1))
+ bindings_match=self.re_import_bindings.match(import_match_str)
+ if bindings_match:
+ import_match_str=bindings_match.group(1)
+ matches=import_match_str.split(',')
+ for match in matches:
+ alias_match=self.re_import_alias.match(match)
+ if alias_match:
+ match=alias_match.group(1)
+ lst.append(match)
+ return lst
+ def start(self,node):
+ self.waiting=[node]
+ while self.waiting:
+ nd=self.waiting.pop(0)
+ self.iter(nd)
+ def iter(self,node):
+ path=node.abspath()
+ code="".join(filter_comments(path))
+ names=self.get_strings(code)
+ for x in names:
+ if x in self.allnames:continue
+ self.allnames.append(x)
+ self.tryfind(x)
+def scan(self):
+ env=self.env
+ gruik=d_parser(env,self.generator.includes_nodes)
+ node=self.inputs[0]
+ gruik.start(node)
+ nodes=gruik.nodes
+ names=gruik.names
+ if Logs.verbose:
+ Logs.debug('deps: deps for %s: %r; unresolved %r'%(str(node),nodes,names))
+ return(nodes,names)
diff --git a/waflib/Tools/dbus.py b/waflib/Tools/dbus.py
new file mode 100644
index 0000000..9ce00d1
--- /dev/null
+++ b/waflib/Tools/dbus.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Task,Errors
+from waflib.TaskGen import taskgen_method,before_method
+@taskgen_method
+def add_dbus_file(self,filename,prefix,mode):
+ if not hasattr(self,'dbus_lst'):
+ self.dbus_lst=[]
+ if not'process_dbus'in self.meths:
+ self.meths.append('process_dbus')
+ self.dbus_lst.append([filename,prefix,mode])
+@before_method('apply_core')
+def process_dbus(self):
+ for filename,prefix,mode in getattr(self,'dbus_lst',[]):
+ node=self.path.find_resource(filename)
+ if not node:
+ raise Errors.WafError('file not found '+filename)
+ tsk=self.create_task('dbus_binding_tool',node,node.change_ext('.h'))
+ tsk.env.DBUS_BINDING_TOOL_PREFIX=prefix
+ tsk.env.DBUS_BINDING_TOOL_MODE=mode
+class dbus_binding_tool(Task.Task):
+ color='BLUE'
+ ext_out=['.h']
+ run_str='${DBUS_BINDING_TOOL} --prefix=${DBUS_BINDING_TOOL_PREFIX} --mode=${DBUS_BINDING_TOOL_MODE} --output=${TGT} ${SRC}'
+ shell=True
+def configure(conf):
+ conf.find_program('dbus-binding-tool',var='DBUS_BINDING_TOOL')
diff --git a/waflib/Tools/dmd.py b/waflib/Tools/dmd.py
new file mode 100644
index 0000000..59aab6d
--- /dev/null
+++ b/waflib/Tools/dmd.py
@@ -0,0 +1,51 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import sys
+from waflib.Tools import ar,d
+from waflib.Configure import conf
+@conf
+def find_dmd(conf):
+ conf.find_program(['dmd','dmd2','ldc'],var='D')
+ out=conf.cmd_and_log(conf.env.D+['--help'])
+ if out.find("D Compiler v")==-1:
+ out=conf.cmd_and_log(conf.env.D+['-version'])
+ if out.find("based on DMD v1.")==-1:
+ conf.fatal("detected compiler is not dmd/ldc")
+@conf
+def common_flags_ldc(conf):
+ v=conf.env
+ v['DFLAGS']=['-d-version=Posix']
+ v['LINKFLAGS']=[]
+ v['DFLAGS_dshlib']=['-relocation-model=pic']
+@conf
+def common_flags_dmd(conf):
+ v=conf.env
+ v['D_SRC_F']=['-c']
+ v['D_TGT_F']='-of%s'
+ v['D_LINKER']=v['D']
+ v['DLNK_SRC_F']=''
+ v['DLNK_TGT_F']='-of%s'
+ v['DINC_ST']='-I%s'
+ v['DSHLIB_MARKER']=v['DSTLIB_MARKER']=''
+ v['DSTLIB_ST']=v['DSHLIB_ST']='-L-l%s'
+ v['DSTLIBPATH_ST']=v['DLIBPATH_ST']='-L-L%s'
+ v['LINKFLAGS_dprogram']=['-quiet']
+ v['DFLAGS_dshlib']=['-fPIC']
+ v['LINKFLAGS_dshlib']=['-L-shared']
+ v['DHEADER_ext']='.di'
+ v.DFLAGS_d_with_header=['-H','-Hf']
+ v['D_HDR_F']='%s'
+def configure(conf):
+ conf.find_dmd()
+ if sys.platform=='win32':
+ out=conf.cmd_and_log(conf.env.D+['--help'])
+ if out.find("D Compiler v2.")>-1:
+ conf.fatal('dmd2 on Windows is not supported, use gdc or ldc2 instead')
+ conf.load('ar')
+ conf.load('d')
+ conf.common_flags_dmd()
+ conf.d_platform_flags()
+ if str(conf.env.D).find('ldc')>-1:
+ conf.common_flags_ldc()
diff --git a/waflib/Tools/errcheck.py b/waflib/Tools/errcheck.py
new file mode 100644
index 0000000..421dfa6
--- /dev/null
+++ b/waflib/Tools/errcheck.py
@@ -0,0 +1,163 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+typos={'feature':'features','sources':'source','targets':'target','include':'includes','export_include':'export_includes','define':'defines','importpath':'includes','installpath':'install_path','iscopy':'is_copy',}
+meths_typos=['__call__','program','shlib','stlib','objects']
+import sys
+from waflib import Logs,Build,Node,Task,TaskGen,ConfigSet,Errors,Utils
+import waflib.Tools.ccroot
+def check_same_targets(self):
+ mp=Utils.defaultdict(list)
+ uids={}
+ def check_task(tsk):
+ if not isinstance(tsk,Task.Task):
+ return
+ for node in tsk.outputs:
+ mp[node].append(tsk)
+ try:
+ uids[tsk.uid()].append(tsk)
+ except KeyError:
+ uids[tsk.uid()]=[tsk]
+ for g in self.groups:
+ for tg in g:
+ try:
+ for tsk in tg.tasks:
+ check_task(tsk)
+ except AttributeError:
+ check_task(tg)
+ dupe=False
+ for(k,v)in mp.items():
+ if len(v)>1:
+ dupe=True
+ msg='* Node %r is created more than once%s. The task generators are:'%(k,Logs.verbose==1 and" (full message on 'waf -v -v')"or"")
+ Logs.error(msg)
+ for x in v:
+ if Logs.verbose>1:
+ Logs.error(' %d. %r'%(1+v.index(x),x.generator))
+ else:
+ Logs.error(' %d. %r in %r'%(1+v.index(x),x.generator.name,getattr(x.generator,'path',None)))
+ if not dupe:
+ for(k,v)in uids.items():
+ if len(v)>1:
+ Logs.error('* Several tasks use the same identifier. Please check the information on\n https://waf.io/apidocs/Task.html?highlight=uid#waflib.Task.Task.uid')
+ for tsk in v:
+ Logs.error(' - object %r (%r) defined in %r'%(tsk.__class__.__name__,tsk,tsk.generator))
+def check_invalid_constraints(self):
+ feat=set([])
+ for x in list(TaskGen.feats.values()):
+ feat.union(set(x))
+ for(x,y)in TaskGen.task_gen.prec.items():
+ feat.add(x)
+ feat.union(set(y))
+ ext=set([])
+ for x in TaskGen.task_gen.mappings.values():
+ ext.add(x.__name__)
+ invalid=ext&feat
+ if invalid:
+ Logs.error('The methods %r have invalid annotations: @extension <-> @feature/@before_method/@after_method'%list(invalid))
+ for cls in list(Task.classes.values()):
+ if sys.hexversion>0x3000000 and issubclass(cls,Task.Task)and isinstance(cls.hcode,str):
+ raise Errors.WafError('Class %r has hcode value %r of type <str>, expecting <bytes> (use Utils.h_cmd() ?)'%(cls,cls.hcode))
+ for x in('before','after'):
+ for y in Utils.to_list(getattr(cls,x,[])):
+ if not Task.classes.get(y,None):
+ Logs.error('Erroneous order constraint %r=%r on task class %r'%(x,y,cls.__name__))
+ if getattr(cls,'rule',None):
+ Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")'%cls.__name__)
+def replace(m):
+ oldcall=getattr(Build.BuildContext,m)
+ def call(self,*k,**kw):
+ ret=oldcall(self,*k,**kw)
+ for x in typos:
+ if x in kw:
+ if x=='iscopy'and'subst'in getattr(self,'features',''):
+ continue
+ Logs.error('Fix the typo %r -> %r on %r'%(x,typos[x],ret))
+ return ret
+ setattr(Build.BuildContext,m,call)
+def enhance_lib():
+ for m in meths_typos:
+ replace(m)
+ def ant_glob(self,*k,**kw):
+ if k:
+ lst=Utils.to_list(k[0])
+ for pat in lst:
+ if'..'in pat.split('/'):
+ Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'"%k[0])
+ if kw.get('remove',True):
+ try:
+ if self.is_child_of(self.ctx.bldnode)and not kw.get('quiet',False):
+ Logs.error('Using ant_glob on the build folder (%r) is dangerous (quiet=True to disable this warning)'%self)
+ except AttributeError:
+ pass
+ return self.old_ant_glob(*k,**kw)
+ Node.Node.old_ant_glob=Node.Node.ant_glob
+ Node.Node.ant_glob=ant_glob
+ old=Task.is_before
+ def is_before(t1,t2):
+ ret=old(t1,t2)
+ if ret and old(t2,t1):
+ Logs.error('Contradictory order constraints in classes %r %r'%(t1,t2))
+ return ret
+ Task.is_before=is_before
+ def check_err_features(self):
+ lst=self.to_list(self.features)
+ if'shlib'in lst:
+ Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')
+ for x in('c','cxx','d','fc'):
+ if not x in lst and lst and lst[0]in[x+y for y in('program','shlib','stlib')]:
+ Logs.error('%r features is probably missing %r'%(self,x))
+ TaskGen.feature('*')(check_err_features)
+ def check_err_order(self):
+ if not hasattr(self,'rule')and not'subst'in Utils.to_list(self.features):
+ for x in('before','after','ext_in','ext_out'):
+ if hasattr(self,x):
+ Logs.warn('Erroneous order constraint %r on non-rule based task generator %r'%(x,self))
+ else:
+ for x in('before','after'):
+ for y in self.to_list(getattr(self,x,[])):
+ if not Task.classes.get(y,None):
+ Logs.error('Erroneous order constraint %s=%r on %r (no such class)'%(x,y,self))
+ TaskGen.feature('*')(check_err_order)
+ def check_compile(self):
+ check_invalid_constraints(self)
+ try:
+ ret=self.orig_compile()
+ finally:
+ check_same_targets(self)
+ return ret
+ Build.BuildContext.orig_compile=Build.BuildContext.compile
+ Build.BuildContext.compile=check_compile
+ def use_rec(self,name,**kw):
+ try:
+ y=self.bld.get_tgen_by_name(name)
+ except Errors.WafError:
+ pass
+ else:
+ idx=self.bld.get_group_idx(self)
+ odx=self.bld.get_group_idx(y)
+ if odx>idx:
+ msg="Invalid 'use' across build groups:"
+ if Logs.verbose>1:
+ msg+='\n target %r\n uses:\n %r'%(self,y)
+ else:
+ msg+=" %r uses %r (try 'waf -v -v' for the full error)"%(self.name,name)
+ raise Errors.WafError(msg)
+ self.orig_use_rec(name,**kw)
+ TaskGen.task_gen.orig_use_rec=TaskGen.task_gen.use_rec
+ TaskGen.task_gen.use_rec=use_rec
+ def getattri(self,name,default=None):
+ if name=='append'or name=='add':
+ raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')
+ elif name=='prepend':
+ raise Errors.WafError('env.prepend does not exist: use env.prepend_value')
+ if name in self.__slots__:
+ return object.__getattr__(self,name,default)
+ else:
+ return self[name]
+ ConfigSet.ConfigSet.__getattr__=getattri
+def options(opt):
+ enhance_lib()
+def configure(conf):
+ pass
diff --git a/waflib/Tools/fc.py b/waflib/Tools/fc.py
new file mode 100644
index 0000000..bc9f0b0
--- /dev/null
+++ b/waflib/Tools/fc.py
@@ -0,0 +1,115 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib import Utils,Task,Logs
+from waflib.Tools import ccroot,fc_config,fc_scan
+from waflib.TaskGen import feature,extension
+from waflib.Configure import conf
+ccroot.USELIB_VARS['fc']=set(['FCFLAGS','DEFINES','INCLUDES'])
+ccroot.USELIB_VARS['fcprogram_test']=ccroot.USELIB_VARS['fcprogram']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS'])
+ccroot.USELIB_VARS['fcshlib']=set(['LIB','STLIB','LIBPATH','STLIBPATH','LINKFLAGS','RPATH','LINKDEPS'])
+ccroot.USELIB_VARS['fcstlib']=set(['ARFLAGS','LINKDEPS'])
+@feature('fcprogram','fcshlib','fcstlib','fcprogram_test')
+def dummy(self):
+ pass
+@extension('.f','.f90','.F','.F90','.for','.FOR')
+def fc_hook(self,node):
+ return self.create_compiled_task('fc',node)
+@conf
+def modfile(conf,name):
+ return{'lower':name.lower()+'.mod','lower.MOD':name.upper()+'.MOD','UPPER.mod':name.upper()+'.mod','UPPER':name.upper()+'.MOD'}[conf.env.FC_MOD_CAPITALIZATION or'lower']
+def get_fortran_tasks(tsk):
+ bld=tsk.generator.bld
+ tasks=bld.get_tasks_group(bld.get_group_idx(tsk.generator))
+ return[x for x in tasks if isinstance(x,fc)and not getattr(x,'nomod',None)and not getattr(x,'mod_fortran_done',None)]
+class fc(Task.Task):
+ color='GREEN'
+ run_str='${FC} ${FCFLAGS} ${FCINCPATH_ST:INCPATHS} ${FCDEFINES_ST:DEFINES} ${_FCMODOUTFLAGS} ${FC_TGT_F}${TGT[0].abspath()} ${FC_SRC_F}${SRC[0].abspath()}'
+ vars=["FORTRANMODPATHFLAG"]
+ def scan(self):
+ tmp=fc_scan.fortran_parser(self.generator.includes_nodes)
+ tmp.task=self
+ tmp.start(self.inputs[0])
+ if Logs.verbose:
+ Logs.debug('deps: deps for %r: %r; unresolved %r'%(self.inputs,tmp.nodes,tmp.names))
+ return(tmp.nodes,tmp.names)
+ def runnable_status(self):
+ if getattr(self,'mod_fortran_done',None):
+ return super(fc,self).runnable_status()
+ bld=self.generator.bld
+ lst=get_fortran_tasks(self)
+ for tsk in lst:
+ tsk.mod_fortran_done=True
+ for tsk in lst:
+ ret=tsk.runnable_status()
+ if ret==Task.ASK_LATER:
+ for x in lst:
+ x.mod_fortran_done=None
+ return Task.ASK_LATER
+ ins=Utils.defaultdict(set)
+ outs=Utils.defaultdict(set)
+ for tsk in lst:
+ key=tsk.uid()
+ for x in bld.raw_deps[key]:
+ if x.startswith('MOD@'):
+ name=bld.modfile(x.replace('MOD@',''))
+ node=bld.srcnode.find_or_declare(name)
+ if not getattr(node,'sig',None):
+ node.sig=Utils.SIG_NIL
+ tsk.set_outputs(node)
+ outs[id(node)].add(tsk)
+ for tsk in lst:
+ key=tsk.uid()
+ for x in bld.raw_deps[key]:
+ if x.startswith('USE@'):
+ name=bld.modfile(x.replace('USE@',''))
+ node=bld.srcnode.find_resource(name)
+ if node and node not in tsk.outputs:
+ if not node in bld.node_deps[key]:
+ bld.node_deps[key].append(node)
+ ins[id(node)].add(tsk)
+ for k in ins.keys():
+ for a in ins[k]:
+ a.run_after.update(outs[k])
+ tmp=[]
+ for t in outs[k]:
+ tmp.extend(t.outputs)
+ a.dep_nodes.extend(tmp)
+ a.dep_nodes.sort(key=lambda x:x.abspath())
+ for tsk in lst:
+ try:
+ delattr(tsk,'cache_sig')
+ except AttributeError:
+ pass
+ return super(fc,self).runnable_status()
+class fcprogram(ccroot.link_task):
+ color='YELLOW'
+ run_str='${FC} ${LINKFLAGS} ${FCLNK_SRC_F}${SRC} ${FCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FCSTLIB_MARKER} ${FCSTLIBPATH_ST:STLIBPATH} ${FCSTLIB_ST:STLIB} ${FCSHLIB_MARKER} ${FCLIBPATH_ST:LIBPATH} ${FCLIB_ST:LIB} ${LDFLAGS}'
+ inst_to='${BINDIR}'
+class fcshlib(fcprogram):
+ inst_to='${LIBDIR}'
+class fcprogram_test(fcprogram):
+ def runnable_status(self):
+ ret=super(fcprogram_test,self).runnable_status()
+ if ret==Task.SKIP_ME:
+ ret=Task.RUN_ME
+ return ret
+ def exec_command(self,cmd,**kw):
+ bld=self.generator.bld
+ kw['shell']=isinstance(cmd,str)
+ kw['stdout']=kw['stderr']=Utils.subprocess.PIPE
+ kw['cwd']=bld.variant_dir
+ bld.out=bld.err=''
+ bld.to_log('command: %s\n'%cmd)
+ kw['output']=0
+ try:
+ (bld.out,bld.err)=bld.cmd_and_log(cmd,**kw)
+ except Exception:
+ return-1
+ if bld.out:
+ bld.to_log("out: %s\n"%bld.out)
+ if bld.err:
+ bld.to_log("err: %s\n"%bld.err)
+class fcstlib(ccroot.stlink_task):
+ pass
diff --git a/waflib/Tools/fc_config.py b/waflib/Tools/fc_config.py
new file mode 100644
index 0000000..f57ae90
--- /dev/null
+++ b/waflib/Tools/fc_config.py
@@ -0,0 +1,286 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re,os,sys,shlex
+from waflib.Configure import conf
+from waflib.TaskGen import feature,before_method
+FC_FRAGMENT=' program main\n end program main\n'
+FC_FRAGMENT2=' PROGRAM MAIN\n END\n'
+@conf
+def fc_flags(conf):
+ v=conf.env
+ v['FC_SRC_F']=[]
+ v['FC_TGT_F']=['-c','-o']
+ v['FCINCPATH_ST']='-I%s'
+ v['FCDEFINES_ST']='-D%s'
+ if not v['LINK_FC']:v['LINK_FC']=v['FC']
+ v['FCLNK_SRC_F']=[]
+ v['FCLNK_TGT_F']=['-o']
+ v['FCFLAGS_fcshlib']=['-fpic']
+ v['LINKFLAGS_fcshlib']=['-shared']
+ v['fcshlib_PATTERN']='lib%s.so'
+ v['fcstlib_PATTERN']='lib%s.a'
+ v['FCLIB_ST']='-l%s'
+ v['FCLIBPATH_ST']='-L%s'
+ v['FCSTLIB_ST']='-l%s'
+ v['FCSTLIBPATH_ST']='-L%s'
+ v['FCSTLIB_MARKER']='-Wl,-Bstatic'
+ v['FCSHLIB_MARKER']='-Wl,-Bdynamic'
+ v['SONAME_ST']='-Wl,-h,%s'
+@conf
+def fc_add_flags(conf):
+ conf.add_os_flags('FCFLAGS',dup=False)
+ conf.add_os_flags('LINKFLAGS',dup=False)
+ conf.add_os_flags('LDFLAGS',dup=False)
+@conf
+def check_fortran(self,*k,**kw):
+ self.check_cc(fragment=FC_FRAGMENT,compile_filename='test.f',features='fc fcprogram',msg='Compiling a simple fortran app')
+@conf
+def check_fc(self,*k,**kw):
+ kw['compiler']='fc'
+ if not'compile_mode'in kw:
+ kw['compile_mode']='fc'
+ if not'type'in kw:
+ kw['type']='fcprogram'
+ if not'compile_filename'in kw:
+ kw['compile_filename']='test.f90'
+ if not'code'in kw:
+ kw['code']=FC_FRAGMENT
+ return self.check(*k,**kw)
+@conf
+def fortran_modifier_darwin(conf):
+ v=conf.env
+ v['FCFLAGS_fcshlib']=['-fPIC']
+ v['LINKFLAGS_fcshlib']=['-dynamiclib']
+ v['fcshlib_PATTERN']='lib%s.dylib'
+ v['FRAMEWORKPATH_ST']='-F%s'
+ v['FRAMEWORK_ST']='-framework %s'
+ v['LINKFLAGS_fcstlib']=[]
+ v['FCSHLIB_MARKER']=''
+ v['FCSTLIB_MARKER']=''
+ v['SONAME_ST']=''
+@conf
+def fortran_modifier_win32(conf):
+ v=conf.env
+ v['fcprogram_PATTERN']=v['fcprogram_test_PATTERN']='%s.exe'
+ v['fcshlib_PATTERN']='%s.dll'
+ v['implib_PATTERN']='lib%s.dll.a'
+ v['IMPLIB_ST']='-Wl,--out-implib,%s'
+ v['FCFLAGS_fcshlib']=[]
+ v.append_value('FCFLAGS_fcshlib',['-DDLL_EXPORT'])
+ v.append_value('LINKFLAGS',['-Wl,--enable-auto-import'])
+@conf
+def fortran_modifier_cygwin(conf):
+ fortran_modifier_win32(conf)
+ v=conf.env
+ v['fcshlib_PATTERN']='cyg%s.dll'
+ v.append_value('LINKFLAGS_fcshlib',['-Wl,--enable-auto-image-base'])
+ v['FCFLAGS_fcshlib']=[]
+@conf
+def check_fortran_dummy_main(self,*k,**kw):
+ if not self.env.CC:
+ self.fatal('A c compiler is required for check_fortran_dummy_main')
+ lst=['MAIN__','__MAIN','_MAIN','MAIN_','MAIN']
+ lst.extend([m.lower()for m in lst])
+ lst.append('')
+ self.start_msg('Detecting whether we need a dummy main')
+ for main in lst:
+ kw['fortran_main']=main
+ try:
+ self.check_cc(fragment='int %s() { return 0; }\n'%(main or'test'),features='c fcprogram',mandatory=True)
+ if not main:
+ self.env.FC_MAIN=-1
+ self.end_msg('no')
+ else:
+ self.env.FC_MAIN=main
+ self.end_msg('yes %s'%main)
+ break
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ self.end_msg('not found')
+ self.fatal('could not detect whether fortran requires a dummy main, see the config.log')
+GCC_DRIVER_LINE=re.compile('^Driving:')
+POSIX_STATIC_EXT=re.compile('\S+\.a')
+POSIX_LIB_FLAGS=re.compile('-l\S+')
+@conf
+def is_link_verbose(self,txt):
+ assert isinstance(txt,str)
+ for line in txt.splitlines():
+ if not GCC_DRIVER_LINE.search(line):
+ if POSIX_STATIC_EXT.search(line)or POSIX_LIB_FLAGS.search(line):
+ return True
+ return False
+@conf
+def check_fortran_verbose_flag(self,*k,**kw):
+ self.start_msg('fortran link verbose flag')
+ for x in('-v','--verbose','-verbose','-V'):
+ try:
+ self.check_cc(features='fc fcprogram_test',fragment=FC_FRAGMENT2,compile_filename='test.f',linkflags=[x],mandatory=True)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ if self.is_link_verbose(self.test_bld.err)or self.is_link_verbose(self.test_bld.out):
+ self.end_msg(x)
+ break
+ else:
+ self.end_msg('failure')
+ self.fatal('Could not obtain the fortran link verbose flag (see config.log)')
+ self.env.FC_VERBOSE_FLAG=x
+ return x
+LINKFLAGS_IGNORED=[r'-lang*',r'-lcrt[a-zA-Z0-9\.]*\.o',r'-lc$',r'-lSystem',r'-libmil',r'-LIST:*',r'-LNO:*']
+if os.name=='nt':
+ LINKFLAGS_IGNORED.extend([r'-lfrt*',r'-luser32',r'-lkernel32',r'-ladvapi32',r'-lmsvcrt',r'-lshell32',r'-lmingw',r'-lmoldname'])
+else:
+ LINKFLAGS_IGNORED.append(r'-lgcc*')
+RLINKFLAGS_IGNORED=[re.compile(f)for f in LINKFLAGS_IGNORED]
+def _match_ignore(line):
+ for i in RLINKFLAGS_IGNORED:
+ if i.match(line):
+ return True
+ return False
+def parse_fortran_link(lines):
+ final_flags=[]
+ for line in lines:
+ if not GCC_DRIVER_LINE.match(line):
+ _parse_flink_line(line,final_flags)
+ return final_flags
+SPACE_OPTS=re.compile('^-[LRuYz]$')
+NOSPACE_OPTS=re.compile('^-[RL]')
+def _parse_flink_token(lexer,token,tmp_flags):
+ if _match_ignore(token):
+ pass
+ elif token.startswith('-lkernel32')and sys.platform=='cygwin':
+ tmp_flags.append(token)
+ elif SPACE_OPTS.match(token):
+ t=lexer.get_token()
+ if t.startswith('P,'):
+ t=t[2:]
+ for opt in t.split(os.pathsep):
+ tmp_flags.append('-L%s'%opt)
+ elif NOSPACE_OPTS.match(token):
+ tmp_flags.append(token)
+ elif POSIX_LIB_FLAGS.match(token):
+ tmp_flags.append(token)
+ else:
+ pass
+ t=lexer.get_token()
+ return t
+def _parse_flink_line(line,final_flags):
+ lexer=shlex.shlex(line,posix=True)
+ lexer.whitespace_split=True
+ t=lexer.get_token()
+ tmp_flags=[]
+ while t:
+ t=_parse_flink_token(lexer,t,tmp_flags)
+ final_flags.extend(tmp_flags)
+ return final_flags
+@conf
+def check_fortran_clib(self,autoadd=True,*k,**kw):
+ if not self.env.FC_VERBOSE_FLAG:
+ self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?')
+ self.start_msg('Getting fortran runtime link flags')
+ try:
+ self.check_cc(fragment=FC_FRAGMENT2,compile_filename='test.f',features='fc fcprogram_test',linkflags=[self.env.FC_VERBOSE_FLAG])
+ except Exception:
+ self.end_msg(False)
+ if kw.get('mandatory',True):
+ conf.fatal('Could not find the c library flags')
+ else:
+ out=self.test_bld.err
+ flags=parse_fortran_link(out.splitlines())
+ self.end_msg('ok (%s)'%' '.join(flags))
+ self.env.LINKFLAGS_CLIB=flags
+ return flags
+ return[]
+def getoutput(conf,cmd,stdin=False):
+ from waflib import Errors
+ if conf.env.env:
+ env=conf.env.env
+ else:
+ env=dict(os.environ)
+ env['LANG']='C'
+ input=stdin and'\n'or None
+ try:
+ out,err=conf.cmd_and_log(cmd,env=env,output=0,input=input)
+ except Errors.WafError ,e:
+ if not(hasattr(e,'stderr')and hasattr(e,'stdout')):
+ raise e
+ else:
+ out=e.stdout
+ err=e.stderr
+ except Exception:
+ conf.fatal('could not determine the compiler version %r'%cmd)
+ return(out,err)
+ROUTINES_CODE="""\
+ subroutine foobar()
+ return
+ end
+ subroutine foo_bar()
+ return
+ end
+"""
+MAIN_CODE="""
+void %(dummy_func_nounder)s(void);
+void %(dummy_func_under)s(void);
+int %(main_func_name)s() {
+ %(dummy_func_nounder)s();
+ %(dummy_func_under)s();
+ return 0;
+}
+"""
+@feature('link_main_routines_func')
+@before_method('process_source')
+def link_main_routines_tg_method(self):
+ def write_test_file(task):
+ task.outputs[0].write(task.generator.code)
+ bld=self.bld
+ bld(rule=write_test_file,target='main.c',code=MAIN_CODE%self.__dict__)
+ bld(rule=write_test_file,target='test.f',code=ROUTINES_CODE)
+ bld(features='fc fcstlib',source='test.f',target='test')
+ bld(features='c fcprogram',source='main.c',target='app',use='test')
+def mangling_schemes():
+ for u in('_',''):
+ for du in('','_'):
+ for c in("lower","upper"):
+ yield(u,du,c)
+def mangle_name(u,du,c,name):
+ return getattr(name,c)()+u+(name.find('_')!=-1 and du or'')
+@conf
+def check_fortran_mangling(self,*k,**kw):
+ if not self.env.CC:
+ self.fatal('A c compiler is required for link_main_routines')
+ if not self.env.FC:
+ self.fatal('A fortran compiler is required for link_main_routines')
+ if not self.env.FC_MAIN:
+ self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)')
+ self.start_msg('Getting fortran mangling scheme')
+ for(u,du,c)in mangling_schemes():
+ try:
+ self.check_cc(compile_filename=[],features='link_main_routines_func',msg='nomsg',errmsg='nomsg',mandatory=True,dummy_func_nounder=mangle_name(u,du,c,"foobar"),dummy_func_under=mangle_name(u,du,c,"foo_bar"),main_func_name=self.env.FC_MAIN)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ self.end_msg("ok ('%s', '%s', '%s-case')"%(u,du,c))
+ self.env.FORTRAN_MANGLING=(u,du,c)
+ break
+ else:
+ self.end_msg(False)
+ self.fatal('mangler not found')
+ return(u,du,c)
+@feature('pyext')
+@before_method('propagate_uselib_vars','apply_link')
+def set_lib_pat(self):
+ self.env['fcshlib_PATTERN']=self.env['pyext_PATTERN']
+@conf
+def detect_openmp(self):
+ for x in('-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp'):
+ try:
+ self.check_fc(msg='Checking for OpenMP flag %s'%x,fragment='program main\n call omp_get_num_threads()\nend program main',fcflags=x,linkflags=x,uselib_store='OPENMP')
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ break
+ else:
+ self.fatal('Could not find OpenMP')
diff --git a/waflib/Tools/fc_scan.py b/waflib/Tools/fc_scan.py
new file mode 100644
index 0000000..c07a22d
--- /dev/null
+++ b/waflib/Tools/fc_scan.py
@@ -0,0 +1,64 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+INC_REGEX="""(?:^|['">]\s*;)\s*(?:|#\s*)INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
+USE_REGEX="""(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
+MOD_REGEX="""(?:^|;)\s*MODULE(?!\s*PROCEDURE)(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
+re_inc=re.compile(INC_REGEX,re.I)
+re_use=re.compile(USE_REGEX,re.I)
+re_mod=re.compile(MOD_REGEX,re.I)
+class fortran_parser(object):
+ def __init__(self,incpaths):
+ self.seen=[]
+ self.nodes=[]
+ self.names=[]
+ self.incpaths=incpaths
+ def find_deps(self,node):
+ txt=node.read()
+ incs=[]
+ uses=[]
+ mods=[]
+ for line in txt.splitlines():
+ m=re_inc.search(line)
+ if m:
+ incs.append(m.group(1))
+ m=re_use.search(line)
+ if m:
+ uses.append(m.group(1))
+ m=re_mod.search(line)
+ if m:
+ mods.append(m.group(1))
+ return(incs,uses,mods)
+ def start(self,node):
+ self.waiting=[node]
+ while self.waiting:
+ nd=self.waiting.pop(0)
+ self.iter(nd)
+ def iter(self,node):
+ incs,uses,mods=self.find_deps(node)
+ for x in incs:
+ if x in self.seen:
+ continue
+ self.seen.append(x)
+ self.tryfind_header(x)
+ for x in uses:
+ name="USE@%s"%x
+ if not name in self.names:
+ self.names.append(name)
+ for x in mods:
+ name="MOD@%s"%x
+ if not name in self.names:
+ self.names.append(name)
+ def tryfind_header(self,filename):
+ found=None
+ for n in self.incpaths:
+ found=n.find_resource(filename)
+ if found:
+ self.nodes.append(found)
+ self.waiting.append(found)
+ break
+ if not found:
+ if not filename in self.names:
+ self.names.append(filename)
diff --git a/waflib/Tools/flex.py b/waflib/Tools/flex.py
new file mode 100644
index 0000000..7a04074
--- /dev/null
+++ b/waflib/Tools/flex.py
@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import waflib.TaskGen,os,re
+def decide_ext(self,node):
+ if'cxx'in self.features:
+ return['.lex.cc']
+ return['.lex.c']
+def flexfun(tsk):
+ env=tsk.env
+ bld=tsk.generator.bld
+ wd=bld.variant_dir
+ def to_list(xx):
+ if isinstance(xx,str):return[xx]
+ return xx
+ tsk.last_cmd=lst=[]
+ lst.extend(to_list(env['FLEX']))
+ lst.extend(to_list(env['FLEXFLAGS']))
+ inputs=[a.path_from(bld.bldnode)for a in tsk.inputs]
+ if env.FLEX_MSYS:
+ inputs=[x.replace(os.sep,'/')for x in inputs]
+ lst.extend(inputs)
+ lst=[x for x in lst if x]
+ txt=bld.cmd_and_log(lst,cwd=wd,env=env.env or None,quiet=0)
+ tsk.outputs[0].write(txt.replace('\r\n','\n').replace('\r','\n'))
+waflib.TaskGen.declare_chain(name='flex',rule=flexfun,ext_in='.l',decider=decide_ext,)
+def configure(conf):
+ conf.find_program('flex',var='FLEX')
+ conf.env.FLEXFLAGS=['-t']
+ if re.search(r"\\msys\\[0-9.]+\\bin\\flex.exe$",conf.env.FLEX[0]):
+ conf.env.FLEX_MSYS=True
diff --git a/waflib/Tools/g95.py b/waflib/Tools/g95.py
new file mode 100644
index 0000000..6524e1c
--- /dev/null
+++ b/waflib/Tools/g95.py
@@ -0,0 +1,54 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan,ar
+from waflib.Configure import conf
+@conf
+def find_g95(conf):
+ fc=conf.find_program('g95',var='FC')
+ conf.get_g95_version(fc)
+ conf.env.FC_NAME='G95'
+@conf
+def g95_flags(conf):
+ v=conf.env
+ v['FCFLAGS_fcshlib']=['-fPIC']
+ v['FORTRANMODFLAG']=['-fmod=','']
+ v['FCFLAGS_DEBUG']=['-Werror']
+@conf
+def g95_modifier_win32(conf):
+ fc_config.fortran_modifier_win32(conf)
+@conf
+def g95_modifier_cygwin(conf):
+ fc_config.fortran_modifier_cygwin(conf)
+@conf
+def g95_modifier_darwin(conf):
+ fc_config.fortran_modifier_darwin(conf)
+@conf
+def g95_modifier_platform(conf):
+ dest_os=conf.env['DEST_OS']or Utils.unversioned_sys_platform()
+ g95_modifier_func=getattr(conf,'g95_modifier_'+dest_os,None)
+ if g95_modifier_func:
+ g95_modifier_func()
+@conf
+def get_g95_version(conf,fc):
+ version_re=re.compile(r"g95\s*(?P<major>\d*)\.(?P<minor>\d*)").search
+ cmd=fc+['--version']
+ out,err=fc_config.getoutput(conf,cmd,stdin=False)
+ if out:
+ match=version_re(out)
+ else:
+ match=version_re(err)
+ if not match:
+ conf.fatal('cannot determine g95 version')
+ k=match.groupdict()
+ conf.env['FC_VERSION']=(k['major'],k['minor'])
+def configure(conf):
+ conf.find_g95()
+ conf.find_ar()
+ conf.fc_flags()
+ conf.fc_add_flags()
+ conf.g95_flags()
+ conf.g95_modifier_platform()
diff --git a/waflib/Tools/gas.py b/waflib/Tools/gas.py
new file mode 100644
index 0000000..4817c23
--- /dev/null
+++ b/waflib/Tools/gas.py
@@ -0,0 +1,12 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import waflib.Tools.asm
+from waflib.Tools import ar
+def configure(conf):
+ conf.find_program(['gas','gcc'],var='AS')
+ conf.env.AS_TGT_F=['-c','-o']
+ conf.env.ASLNK_TGT_F=['-o']
+ conf.find_ar()
+ conf.load('asm')
diff --git a/waflib/Tools/gcc.py b/waflib/Tools/gcc.py
new file mode 100644
index 0000000..a3c7720
--- /dev/null
+++ b/waflib/Tools/gcc.py
@@ -0,0 +1,102 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_gcc(conf):
+ cc=conf.find_program(['gcc','cc'],var='CC')
+ conf.get_cc_version(cc,gcc=True)
+ conf.env.CC_NAME='gcc'
+@conf
+def gcc_common_flags(conf):
+ v=conf.env
+ v['CC_SRC_F']=[]
+ v['CC_TGT_F']=['-c','-o']
+ if not v['LINK_CC']:v['LINK_CC']=v['CC']
+ v['CCLNK_SRC_F']=[]
+ v['CCLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['RPATH_ST']='-Wl,-rpath,%s'
+ v['SONAME_ST']='-Wl,-h,%s'
+ v['SHLIB_MARKER']='-Wl,-Bdynamic'
+ v['STLIB_MARKER']='-Wl,-Bstatic'
+ v['cprogram_PATTERN']='%s'
+ v['CFLAGS_cshlib']=['-fPIC']
+ v['LINKFLAGS_cshlib']=['-shared']
+ v['cshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cstlib']=['-Wl,-Bstatic']
+ v['cstlib_PATTERN']='lib%s.a'
+ v['LINKFLAGS_MACBUNDLE']=['-bundle','-undefined','dynamic_lookup']
+ v['CFLAGS_MACBUNDLE']=['-fPIC']
+ v['macbundle_PATTERN']='%s.bundle'
+@conf
+def gcc_modifier_win32(conf):
+ v=conf.env
+ v['cprogram_PATTERN']='%s.exe'
+ v['cshlib_PATTERN']='%s.dll'
+ v['implib_PATTERN']='lib%s.dll.a'
+ v['IMPLIB_ST']='-Wl,--out-implib,%s'
+ v['CFLAGS_cshlib']=[]
+ v.append_value('LINKFLAGS',['-Wl,--enable-auto-import'])
+@conf
+def gcc_modifier_cygwin(conf):
+ gcc_modifier_win32(conf)
+ v=conf.env
+ v['cshlib_PATTERN']='cyg%s.dll'
+ v.append_value('LINKFLAGS_cshlib',['-Wl,--enable-auto-image-base'])
+ v['CFLAGS_cshlib']=[]
+@conf
+def gcc_modifier_darwin(conf):
+ v=conf.env
+ v['CFLAGS_cshlib']=['-fPIC']
+ v['LINKFLAGS_cshlib']=['-dynamiclib']
+ v['cshlib_PATTERN']='lib%s.dylib'
+ v['FRAMEWORKPATH_ST']='-F%s'
+ v['FRAMEWORK_ST']=['-framework']
+ v['ARCH_ST']=['-arch']
+ v['LINKFLAGS_cstlib']=[]
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['SONAME_ST']=[]
+@conf
+def gcc_modifier_aix(conf):
+ v=conf.env
+ v['LINKFLAGS_cprogram']=['-Wl,-brtl']
+ v['LINKFLAGS_cshlib']=['-shared','-Wl,-brtl,-bexpfull']
+ v['SHLIB_MARKER']=[]
+@conf
+def gcc_modifier_hpux(conf):
+ v=conf.env
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['CFLAGS_cshlib']=['-fPIC','-DPIC']
+ v['cshlib_PATTERN']='lib%s.sl'
+@conf
+def gcc_modifier_openbsd(conf):
+ conf.env.SONAME_ST=[]
+@conf
+def gcc_modifier_osf1V(conf):
+ v=conf.env
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['SONAME_ST']=[]
+@conf
+def gcc_modifier_platform(conf):
+ gcc_modifier_func=getattr(conf,'gcc_modifier_'+conf.env.DEST_OS,None)
+ if gcc_modifier_func:
+ gcc_modifier_func()
+def configure(conf):
+ conf.find_gcc()
+ conf.find_ar()
+ conf.gcc_common_flags()
+ conf.gcc_modifier_platform()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/gdc.py b/waflib/Tools/gdc.py
new file mode 100644
index 0000000..acfea4a
--- /dev/null
+++ b/waflib/Tools/gdc.py
@@ -0,0 +1,35 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ar,d
+from waflib.Configure import conf
+@conf
+def find_gdc(conf):
+ conf.find_program('gdc',var='D')
+ out=conf.cmd_and_log(conf.env.D+['--version'])
+ if out.find("gdc")==-1:
+ conf.fatal("detected compiler is not gdc")
+@conf
+def common_flags_gdc(conf):
+ v=conf.env
+ v['DFLAGS']=[]
+ v['D_SRC_F']=['-c']
+ v['D_TGT_F']='-o%s'
+ v['D_LINKER']=v['D']
+ v['DLNK_SRC_F']=''
+ v['DLNK_TGT_F']='-o%s'
+ v['DINC_ST']='-I%s'
+ v['DSHLIB_MARKER']=v['DSTLIB_MARKER']=''
+ v['DSTLIB_ST']=v['DSHLIB_ST']='-l%s'
+ v['DSTLIBPATH_ST']=v['DLIBPATH_ST']='-L%s'
+ v['LINKFLAGS_dshlib']=['-shared']
+ v['DHEADER_ext']='.di'
+ v.DFLAGS_d_with_header='-fintfc'
+ v['D_HDR_F']='-fintfc-file=%s'
+def configure(conf):
+ conf.find_gdc()
+ conf.load('ar')
+ conf.load('d')
+ conf.common_flags_gdc()
+ conf.d_platform_flags()
diff --git a/waflib/Tools/gfortran.py b/waflib/Tools/gfortran.py
new file mode 100644
index 0000000..a0ea00b
--- /dev/null
+++ b/waflib/Tools/gfortran.py
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan,ar
+from waflib.Configure import conf
+@conf
+def find_gfortran(conf):
+ fc=conf.find_program(['gfortran','g77'],var='FC')
+ conf.get_gfortran_version(fc)
+ conf.env.FC_NAME='GFORTRAN'
+@conf
+def gfortran_flags(conf):
+ v=conf.env
+ v['FCFLAGS_fcshlib']=['-fPIC']
+ v['FORTRANMODFLAG']=['-J','']
+ v['FCFLAGS_DEBUG']=['-Werror']
+@conf
+def gfortran_modifier_win32(conf):
+ fc_config.fortran_modifier_win32(conf)
+@conf
+def gfortran_modifier_cygwin(conf):
+ fc_config.fortran_modifier_cygwin(conf)
+@conf
+def gfortran_modifier_darwin(conf):
+ fc_config.fortran_modifier_darwin(conf)
+@conf
+def gfortran_modifier_platform(conf):
+ dest_os=conf.env['DEST_OS']or Utils.unversioned_sys_platform()
+ gfortran_modifier_func=getattr(conf,'gfortran_modifier_'+dest_os,None)
+ if gfortran_modifier_func:
+ gfortran_modifier_func()
+@conf
+def get_gfortran_version(conf,fc):
+ version_re=re.compile(r"GNU\s*Fortran",re.I).search
+ cmd=fc+['--version']
+ out,err=fc_config.getoutput(conf,cmd,stdin=False)
+ if out:match=version_re(out)
+ else:match=version_re(err)
+ if not match:
+ conf.fatal('Could not determine the compiler type')
+ cmd=fc+['-dM','-E','-']
+ out,err=fc_config.getoutput(conf,cmd,stdin=True)
+ if out.find('__GNUC__')<0:
+ conf.fatal('Could not determine the compiler type')
+ k={}
+ out=out.splitlines()
+ import shlex
+ for line in out:
+ lst=shlex.split(line)
+ if len(lst)>2:
+ key=lst[1]
+ val=lst[2]
+ k[key]=val
+ def isD(var):
+ return var in k
+ def isT(var):
+ return var in k and k[var]!='0'
+ conf.env['FC_VERSION']=(k['__GNUC__'],k['__GNUC_MINOR__'],k['__GNUC_PATCHLEVEL__'])
+def configure(conf):
+ conf.find_gfortran()
+ conf.find_ar()
+ conf.fc_flags()
+ conf.fc_add_flags()
+ conf.gfortran_flags()
+ conf.gfortran_modifier_platform()
diff --git a/waflib/Tools/glib2.py b/waflib/Tools/glib2.py
new file mode 100644
index 0000000..47ee823
--- /dev/null
+++ b/waflib/Tools/glib2.py
@@ -0,0 +1,234 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+from waflib import Context,Task,Utils,Options,Errors,Logs
+from waflib.TaskGen import taskgen_method,before_method,feature,extension
+from waflib.Configure import conf
+@taskgen_method
+def add_marshal_file(self,filename,prefix):
+ if not hasattr(self,'marshal_list'):
+ self.marshal_list=[]
+ self.meths.append('process_marshal')
+ self.marshal_list.append((filename,prefix))
+@before_method('process_source')
+def process_marshal(self):
+ for f,prefix in getattr(self,'marshal_list',[]):
+ node=self.path.find_resource(f)
+ if not node:
+ raise Errors.WafError('file not found %r'%f)
+ h_node=node.change_ext('.h')
+ c_node=node.change_ext('.c')
+ task=self.create_task('glib_genmarshal',node,[h_node,c_node])
+ task.env.GLIB_GENMARSHAL_PREFIX=prefix
+ self.source=self.to_nodes(getattr(self,'source',[]))
+ self.source.append(c_node)
+class glib_genmarshal(Task.Task):
+ def run(self):
+ bld=self.inputs[0].__class__.ctx
+ get=self.env.get_flat
+ cmd1="%s %s --prefix=%s --header > %s"%(get('GLIB_GENMARSHAL'),self.inputs[0].srcpath(),get('GLIB_GENMARSHAL_PREFIX'),self.outputs[0].abspath())
+ ret=bld.exec_command(cmd1)
+ if ret:return ret
+ c='''#include "%s"\n'''%self.outputs[0].name
+ self.outputs[1].write(c)
+ cmd2="%s %s --prefix=%s --body >> %s"%(get('GLIB_GENMARSHAL'),self.inputs[0].srcpath(),get('GLIB_GENMARSHAL_PREFIX'),self.outputs[1].abspath())
+ return bld.exec_command(cmd2)
+ vars=['GLIB_GENMARSHAL_PREFIX','GLIB_GENMARSHAL']
+ color='BLUE'
+ ext_out=['.h']
+@taskgen_method
+def add_enums_from_template(self,source='',target='',template='',comments=''):
+ if not hasattr(self,'enums_list'):
+ self.enums_list=[]
+ self.meths.append('process_enums')
+ self.enums_list.append({'source':source,'target':target,'template':template,'file-head':'','file-prod':'','file-tail':'','enum-prod':'','value-head':'','value-prod':'','value-tail':'','comments':comments})
+@taskgen_method
+def add_enums(self,source='',target='',file_head='',file_prod='',file_tail='',enum_prod='',value_head='',value_prod='',value_tail='',comments=''):
+ if not hasattr(self,'enums_list'):
+ self.enums_list=[]
+ self.meths.append('process_enums')
+ self.enums_list.append({'source':source,'template':'','target':target,'file-head':file_head,'file-prod':file_prod,'file-tail':file_tail,'enum-prod':enum_prod,'value-head':value_head,'value-prod':value_prod,'value-tail':value_tail,'comments':comments})
+@before_method('process_source')
+def process_enums(self):
+ for enum in getattr(self,'enums_list',[]):
+ task=self.create_task('glib_mkenums')
+ env=task.env
+ inputs=[]
+ source_list=self.to_list(enum['source'])
+ if not source_list:
+ raise Errors.WafError('missing source '+str(enum))
+ source_list=[self.path.find_resource(k)for k in source_list]
+ inputs+=source_list
+ env['GLIB_MKENUMS_SOURCE']=[k.abspath()for k in source_list]
+ if not enum['target']:
+ raise Errors.WafError('missing target '+str(enum))
+ tgt_node=self.path.find_or_declare(enum['target'])
+ if tgt_node.name.endswith('.c'):
+ self.source.append(tgt_node)
+ env['GLIB_MKENUMS_TARGET']=tgt_node.abspath()
+ options=[]
+ if enum['template']:
+ template_node=self.path.find_resource(enum['template'])
+ options.append('--template %s'%(template_node.abspath()))
+ inputs.append(template_node)
+ params={'file-head':'--fhead','file-prod':'--fprod','file-tail':'--ftail','enum-prod':'--eprod','value-head':'--vhead','value-prod':'--vprod','value-tail':'--vtail','comments':'--comments'}
+ for param,option in params.items():
+ if enum[param]:
+ options.append('%s %r'%(option,enum[param]))
+ env['GLIB_MKENUMS_OPTIONS']=' '.join(options)
+ task.set_inputs(inputs)
+ task.set_outputs(tgt_node)
+class glib_mkenums(Task.Task):
+ run_str='${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}'
+ color='PINK'
+ ext_out=['.h']
+@taskgen_method
+def add_settings_schemas(self,filename_list):
+ if not hasattr(self,'settings_schema_files'):
+ self.settings_schema_files=[]
+ if not isinstance(filename_list,list):
+ filename_list=[filename_list]
+ self.settings_schema_files.extend(filename_list)
+@taskgen_method
+def add_settings_enums(self,namespace,filename_list):
+ if hasattr(self,'settings_enum_namespace'):
+ raise Errors.WafError("Tried to add gsettings enums to '%s' more than once"%self.name)
+ self.settings_enum_namespace=namespace
+ if type(filename_list)!='list':
+ filename_list=[filename_list]
+ self.settings_enum_files=filename_list
+@feature('glib2')
+def process_settings(self):
+ enums_tgt_node=[]
+ install_files=[]
+ settings_schema_files=getattr(self,'settings_schema_files',[])
+ if settings_schema_files and not self.env['GLIB_COMPILE_SCHEMAS']:
+ raise Errors.WafError("Unable to process GSettings schemas - glib-compile-schemas was not found during configure")
+ if hasattr(self,'settings_enum_files'):
+ enums_task=self.create_task('glib_mkenums')
+ source_list=self.settings_enum_files
+ source_list=[self.path.find_resource(k)for k in source_list]
+ enums_task.set_inputs(source_list)
+ enums_task.env['GLIB_MKENUMS_SOURCE']=[k.abspath()for k in source_list]
+ target=self.settings_enum_namespace+'.enums.xml'
+ tgt_node=self.path.find_or_declare(target)
+ enums_task.set_outputs(tgt_node)
+ enums_task.env['GLIB_MKENUMS_TARGET']=tgt_node.abspath()
+ enums_tgt_node=[tgt_node]
+ install_files.append(tgt_node)
+ options='--comments "<!-- @comment@ -->" --fhead "<schemalist>" --vhead " <@type@ id=\\"%s.@EnumName@\\">" --vprod " <value nick=\\"@valuenick@\\" value=\\"@valuenum@\\"/>" --vtail " </@type@>" --ftail "</schemalist>" '%(self.settings_enum_namespace)
+ enums_task.env['GLIB_MKENUMS_OPTIONS']=options
+ for schema in settings_schema_files:
+ schema_task=self.create_task('glib_validate_schema')
+ schema_node=self.path.find_resource(schema)
+ if not schema_node:
+ raise Errors.WafError("Cannot find the schema file '%s'"%schema)
+ install_files.append(schema_node)
+ source_list=enums_tgt_node+[schema_node]
+ schema_task.set_inputs(source_list)
+ schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS']=[("--schema-file="+k.abspath())for k in source_list]
+ target_node=schema_node.change_ext('.xml.valid')
+ schema_task.set_outputs(target_node)
+ schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT']=target_node.abspath()
+ def compile_schemas_callback(bld):
+ if not bld.is_install:return
+ Logs.pprint('YELLOW','Updating GSettings schema cache')
+ command=Utils.subst_vars("${GLIB_COMPILE_SCHEMAS} ${GSETTINGSSCHEMADIR}",bld.env)
+ self.bld.exec_command(command)
+ if self.bld.is_install:
+ if not self.env['GSETTINGSSCHEMADIR']:
+ raise Errors.WafError('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)')
+ if install_files:
+ self.bld.install_files(self.env['GSETTINGSSCHEMADIR'],install_files)
+ if not hasattr(self.bld,'_compile_schemas_registered'):
+ self.bld.add_post_fun(compile_schemas_callback)
+ self.bld._compile_schemas_registered=True
+class glib_validate_schema(Task.Task):
+ run_str='rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}'
+ color='PINK'
+@extension('.gresource.xml')
+def process_gresource_source(self,node):
+ if not self.env['GLIB_COMPILE_RESOURCES']:
+ raise Errors.WafError("Unable to process GResource file - glib-compile-resources was not found during configure")
+ if'gresource'in self.features:
+ return
+ h_node=node.change_ext('_xml.h')
+ c_node=node.change_ext('_xml.c')
+ self.create_task('glib_gresource_source',node,[h_node,c_node])
+ self.source.append(c_node)
+@feature('gresource')
+def process_gresource_bundle(self):
+ for i in self.to_list(self.source):
+ node=self.path.find_resource(i)
+ task=self.create_task('glib_gresource_bundle',node,node.change_ext(''))
+ inst_to=getattr(self,'install_path',None)
+ if inst_to:
+ self.bld.install_files(inst_to,task.outputs)
+class glib_gresource_base(Task.Task):
+ color='BLUE'
+ base_cmd='${GLIB_COMPILE_RESOURCES} --sourcedir=${SRC[0].parent.srcpath()} --sourcedir=${SRC[0].bld_dir()}'
+ def scan(self):
+ bld=self.generator.bld
+ kw={}
+ try:
+ if not kw.get('cwd',None):
+ kw['cwd']=bld.cwd
+ except AttributeError:
+ bld.cwd=kw['cwd']=bld.variant_dir
+ kw['quiet']=Context.BOTH
+ cmd=Utils.subst_vars('${GLIB_COMPILE_RESOURCES} --sourcedir=%s --sourcedir=%s --generate-dependencies %s'%(self.inputs[0].parent.srcpath(),self.inputs[0].bld_dir(),self.inputs[0].bldpath()),self.env)
+ output=bld.cmd_and_log(cmd,**kw)
+ nodes=[]
+ names=[]
+ for dep in output.splitlines():
+ if dep:
+ node=bld.bldnode.find_node(dep)
+ if node:
+ nodes.append(node)
+ else:
+ names.append(dep)
+ return(nodes,names)
+class glib_gresource_source(glib_gresource_base):
+ vars=['GLIB_COMPILE_RESOURCES']
+ fun_h=Task.compile_fun_shell(glib_gresource_base.base_cmd+' --target=${TGT[0].abspath()} --generate-header ${SRC}')
+ fun_c=Task.compile_fun_shell(glib_gresource_base.base_cmd+' --target=${TGT[1].abspath()} --generate-source ${SRC}')
+ ext_out=['.h']
+ def run(self):
+ return self.fun_h[0](self)or self.fun_c[0](self)
+class glib_gresource_bundle(glib_gresource_base):
+ run_str=glib_gresource_base.base_cmd+' --target=${TGT} ${SRC}'
+ shell=True
+@conf
+def find_glib_genmarshal(conf):
+ conf.find_program('glib-genmarshal',var='GLIB_GENMARSHAL')
+@conf
+def find_glib_mkenums(conf):
+ if not conf.env.PERL:
+ conf.find_program('perl',var='PERL')
+ conf.find_program('glib-mkenums',interpreter='PERL',var='GLIB_MKENUMS')
+@conf
+def find_glib_compile_schemas(conf):
+ conf.find_program('glib-compile-schemas',var='GLIB_COMPILE_SCHEMAS')
+ def getstr(varname):
+ return getattr(Options.options,varname,getattr(conf.env,varname,''))
+ gsettingsschemadir=getstr('GSETTINGSSCHEMADIR')
+ if not gsettingsschemadir:
+ datadir=getstr('DATADIR')
+ if not datadir:
+ prefix=conf.env['PREFIX']
+ datadir=os.path.join(prefix,'share')
+ gsettingsschemadir=os.path.join(datadir,'glib-2.0','schemas')
+ conf.env['GSETTINGSSCHEMADIR']=gsettingsschemadir
+@conf
+def find_glib_compile_resources(conf):
+ conf.find_program('glib-compile-resources',var='GLIB_COMPILE_RESOURCES')
+def configure(conf):
+ conf.find_glib_genmarshal()
+ conf.find_glib_mkenums()
+ conf.find_glib_compile_schemas(mandatory=False)
+ conf.find_glib_compile_resources(mandatory=False)
+def options(opt):
+ gr=opt.add_option_group('Installation directories')
+ gr.add_option('--gsettingsschemadir',help='GSettings schema location [DATADIR/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR')
diff --git a/waflib/Tools/gnu_dirs.py b/waflib/Tools/gnu_dirs.py
new file mode 100644
index 0000000..21a6288
--- /dev/null
+++ b/waflib/Tools/gnu_dirs.py
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re
+from waflib import Utils,Options,Context
+gnuopts='''
+bindir, user commands, ${EXEC_PREFIX}/bin
+sbindir, system binaries, ${EXEC_PREFIX}/sbin
+libexecdir, program-specific binaries, ${EXEC_PREFIX}/libexec
+sysconfdir, host-specific configuration, ${PREFIX}/etc
+sharedstatedir, architecture-independent variable data, ${PREFIX}/com
+localstatedir, variable data, ${PREFIX}/var
+libdir, object code libraries, ${EXEC_PREFIX}/lib%s
+includedir, header files, ${PREFIX}/include
+oldincludedir, header files for non-GCC compilers, /usr/include
+datarootdir, architecture-independent data root, ${PREFIX}/share
+datadir, architecture-independent data, ${DATAROOTDIR}
+infodir, GNU "info" documentation, ${DATAROOTDIR}/info
+localedir, locale-dependent data, ${DATAROOTDIR}/locale
+mandir, manual pages, ${DATAROOTDIR}/man
+docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE}
+htmldir, HTML documentation, ${DOCDIR}
+dvidir, DVI documentation, ${DOCDIR}
+pdfdir, PDF documentation, ${DOCDIR}
+psdir, PostScript documentation, ${DOCDIR}
+'''%Utils.lib64()
+_options=[x.split(', ')for x in gnuopts.splitlines()if x]
+def configure(conf):
+ def get_param(varname,default):
+ return getattr(Options.options,varname,'')or default
+ env=conf.env
+ env.LIBDIR=env.BINDIR=[]
+ env.EXEC_PREFIX=get_param('EXEC_PREFIX',env.PREFIX)
+ env.PACKAGE=getattr(Context.g_module,'APPNAME',None)or env.PACKAGE
+ complete=False
+ iter=0
+ while not complete and iter<len(_options)+1:
+ iter+=1
+ complete=True
+ for name,help,default in _options:
+ name=name.upper()
+ if not env[name]:
+ try:
+ env[name]=Utils.subst_vars(get_param(name,default).replace('/',os.sep),env)
+ except TypeError:
+ complete=False
+ if not complete:
+ lst=[x for x,_,_ in _options if not env[x.upper()]]
+ raise conf.errors.WafError('Variable substitution failure %r'%lst)
+def options(opt):
+ inst_dir=opt.add_option_group('Installation prefix','By default, "waf install" will put the files in\
+ "/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\
+ than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"')
+ for k in('--prefix','--destdir'):
+ option=opt.parser.get_option(k)
+ if option:
+ opt.parser.remove_option(k)
+ inst_dir.add_option(option)
+ inst_dir.add_option('--exec-prefix',help='installation prefix for binaries [PREFIX]',default='',dest='EXEC_PREFIX')
+ dirs_options=opt.add_option_group('Installation directories')
+ for name,help,default in _options:
+ option_name='--'+name
+ str_default=default
+ str_help='%s [%s]'%(help,re.sub(r'\$\{([^}]+)\}',r'\1',str_default))
+ dirs_options.add_option(option_name,help=str_help,default='',dest=name.upper())
diff --git a/waflib/Tools/gxx.py b/waflib/Tools/gxx.py
new file mode 100644
index 0000000..332c953
--- /dev/null
+++ b/waflib/Tools/gxx.py
@@ -0,0 +1,102 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_gxx(conf):
+ cxx=conf.find_program(['g++','c++'],var='CXX')
+ conf.get_cc_version(cxx,gcc=True)
+ conf.env.CXX_NAME='gcc'
+@conf
+def gxx_common_flags(conf):
+ v=conf.env
+ v['CXX_SRC_F']=[]
+ v['CXX_TGT_F']=['-c','-o']
+ if not v['LINK_CXX']:v['LINK_CXX']=v['CXX']
+ v['CXXLNK_SRC_F']=[]
+ v['CXXLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['RPATH_ST']='-Wl,-rpath,%s'
+ v['SONAME_ST']='-Wl,-h,%s'
+ v['SHLIB_MARKER']='-Wl,-Bdynamic'
+ v['STLIB_MARKER']='-Wl,-Bstatic'
+ v['cxxprogram_PATTERN']='%s'
+ v['CXXFLAGS_cxxshlib']=['-fPIC']
+ v['LINKFLAGS_cxxshlib']=['-shared']
+ v['cxxshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cxxstlib']=['-Wl,-Bstatic']
+ v['cxxstlib_PATTERN']='lib%s.a'
+ v['LINKFLAGS_MACBUNDLE']=['-bundle','-undefined','dynamic_lookup']
+ v['CXXFLAGS_MACBUNDLE']=['-fPIC']
+ v['macbundle_PATTERN']='%s.bundle'
+@conf
+def gxx_modifier_win32(conf):
+ v=conf.env
+ v['cxxprogram_PATTERN']='%s.exe'
+ v['cxxshlib_PATTERN']='%s.dll'
+ v['implib_PATTERN']='lib%s.dll.a'
+ v['IMPLIB_ST']='-Wl,--out-implib,%s'
+ v['CXXFLAGS_cxxshlib']=[]
+ v.append_value('LINKFLAGS',['-Wl,--enable-auto-import'])
+@conf
+def gxx_modifier_cygwin(conf):
+ gxx_modifier_win32(conf)
+ v=conf.env
+ v['cxxshlib_PATTERN']='cyg%s.dll'
+ v.append_value('LINKFLAGS_cxxshlib',['-Wl,--enable-auto-image-base'])
+ v['CXXFLAGS_cxxshlib']=[]
+@conf
+def gxx_modifier_darwin(conf):
+ v=conf.env
+ v['CXXFLAGS_cxxshlib']=['-fPIC']
+ v['LINKFLAGS_cxxshlib']=['-dynamiclib']
+ v['cxxshlib_PATTERN']='lib%s.dylib'
+ v['FRAMEWORKPATH_ST']='-F%s'
+ v['FRAMEWORK_ST']=['-framework']
+ v['ARCH_ST']=['-arch']
+ v['LINKFLAGS_cxxstlib']=[]
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['SONAME_ST']=[]
+@conf
+def gxx_modifier_aix(conf):
+ v=conf.env
+ v['LINKFLAGS_cxxprogram']=['-Wl,-brtl']
+ v['LINKFLAGS_cxxshlib']=['-shared','-Wl,-brtl,-bexpfull']
+ v['SHLIB_MARKER']=[]
+@conf
+def gxx_modifier_hpux(conf):
+ v=conf.env
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['CFLAGS_cxxshlib']=['-fPIC','-DPIC']
+ v['cxxshlib_PATTERN']='lib%s.sl'
+@conf
+def gxx_modifier_openbsd(conf):
+ conf.env.SONAME_ST=[]
+@conf
+def gcc_modifier_osf1V(conf):
+ v=conf.env
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['SONAME_ST']=[]
+@conf
+def gxx_modifier_platform(conf):
+ gxx_modifier_func=getattr(conf,'gxx_modifier_'+conf.env.DEST_OS,None)
+ if gxx_modifier_func:
+ gxx_modifier_func()
+def configure(conf):
+ conf.find_gxx()
+ conf.find_ar()
+ conf.gxx_common_flags()
+ conf.gxx_modifier_platform()
+ conf.cxx_load_tools()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/icc.py b/waflib/Tools/icc.py
new file mode 100644
index 0000000..9b7aa03
--- /dev/null
+++ b/waflib/Tools/icc.py
@@ -0,0 +1,22 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import sys
+from waflib.Tools import ccroot,ar,gcc
+from waflib.Configure import conf
+@conf
+def find_icc(conf):
+ if sys.platform=='cygwin':
+ conf.fatal('The Intel compiler does not work on Cygwin')
+ cc=conf.find_program(['icc','ICL'],var='CC')
+ conf.get_cc_version(cc,icc=True)
+ conf.env.CC_NAME='icc'
+def configure(conf):
+ conf.find_icc()
+ conf.find_ar()
+ conf.gcc_common_flags()
+ conf.gcc_modifier_platform()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/icpc.py b/waflib/Tools/icpc.py
new file mode 100644
index 0000000..1e9b6cc
--- /dev/null
+++ b/waflib/Tools/icpc.py
@@ -0,0 +1,22 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import sys
+from waflib.Tools import ccroot,ar,gxx
+from waflib.Configure import conf
+@conf
+def find_icpc(conf):
+ if sys.platform=='cygwin':
+ conf.fatal('The Intel compiler does not work on Cygwin')
+ cxx=conf.find_program('icpc',var='CXX')
+ conf.get_cc_version(cxx,icc=True)
+ conf.env.CXX_NAME='icc'
+def configure(conf):
+ conf.find_icpc()
+ conf.find_ar()
+ conf.gxx_common_flags()
+ conf.gxx_modifier_platform()
+ conf.cxx_load_tools()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/ifort.py b/waflib/Tools/ifort.py
new file mode 100644
index 0000000..41fa604
--- /dev/null
+++ b/waflib/Tools/ifort.py
@@ -0,0 +1,433 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan,ar
+from waflib.Configure import conf
+@conf
+def find_ifort(conf):
+ fc=conf.find_program('ifort',var='FC')
+ conf.get_ifort_version(fc)
+ conf.env.FC_NAME='IFORT'
+@conf
+def ifort_modifier_win32(self):
+ v=self.env
+ v.IFORT_WIN32=True
+ v.FCSTLIB_MARKER=''
+ v.FCSHLIB_MARKER=''
+ v.FCLIB_ST=v.FCSTLIB_ST='%s.lib'
+ v.FCLIBPATH_ST=v.STLIBPATH_ST='/LIBPATH:%s'
+ v.FCINCPATH_ST='/I%s'
+ v.FCDEFINES_ST='/D%s'
+ v.fcprogram_PATTERN=v.fcprogram_test_PATTERN='%s.exe'
+ v.fcshlib_PATTERN='%s.dll'
+ v.fcstlib_PATTERN=v.implib_PATTERN='%s.lib'
+ v.FCLNK_TGT_F='/out:'
+ v.FC_TGT_F=['/c','/o','']
+ v.FCFLAGS_fcshlib=''
+ v.LINKFLAGS_fcshlib='/DLL'
+ v.AR_TGT_F='/out:'
+ v.IMPLIB_ST='/IMPLIB:%s'
+ v.append_value('LINKFLAGS','/subsystem:console')
+ if v.IFORT_MANIFEST:
+ v.append_value('LINKFLAGS',['/MANIFEST'])
+@conf
+def ifort_modifier_darwin(conf):
+ fc_config.fortran_modifier_darwin(conf)
+@conf
+def ifort_modifier_platform(conf):
+ dest_os=conf.env.DEST_OS or Utils.unversioned_sys_platform()
+ ifort_modifier_func=getattr(conf,'ifort_modifier_'+dest_os,None)
+ if ifort_modifier_func:
+ ifort_modifier_func()
+@conf
+def get_ifort_version(conf,fc):
+ version_re=re.compile(r"\bIntel\b.*\bVersion\s*(?P<major>\d*)\.(?P<minor>\d*)",re.I).search
+ if Utils.is_win32:
+ cmd=fc
+ else:
+ cmd=fc+['-logo']
+ out,err=fc_config.getoutput(conf,cmd,stdin=False)
+ match=version_re(out)or version_re(err)
+ if not match:
+ conf.fatal('cannot determine ifort version.')
+ k=match.groupdict()
+ conf.env['FC_VERSION']=(k['major'],k['minor'])
+def configure(conf):
+ if Utils.is_win32:
+ compiler,version,path,includes,libdirs,arch=conf.detect_ifort(True)
+ v=conf.env
+ v.DEST_CPU=arch
+ v.PATH=path
+ v.INCLUDES=includes
+ v.LIBPATH=libdirs
+ v.MSVC_COMPILER=compiler
+ try:
+ v.MSVC_VERSION=float(version)
+ except Exception:
+ raise
+ v.MSVC_VERSION=float(version[:-3])
+ conf.find_ifort_win32()
+ conf.ifort_modifier_win32()
+ else:
+ conf.find_ifort()
+ conf.find_program('xiar',var='AR')
+ conf.find_ar()
+ conf.fc_flags()
+ conf.fc_add_flags()
+ conf.ifort_modifier_platform()
+import os,sys,re,tempfile
+from waflib import Task,Logs,Options,Errors
+from waflib.Logs import debug,warn
+from waflib.TaskGen import after_method,feature
+from waflib.Configure import conf
+from waflib.Tools import ccroot,ar,winres
+all_ifort_platforms=[('intel64','amd64'),('em64t','amd64'),('ia32','x86'),('Itanium','ia64')]
+@conf
+def gather_ifort_versions(conf,versions):
+ version_pattern=re.compile('^...?.?\....?.?')
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Compilers\\Fortran')
+ except WindowsError:
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Compilers\\Fortran')
+ except WindowsError:
+ return
+ index=0
+ while 1:
+ try:
+ version=Utils.winreg.EnumKey(all_versions,index)
+ except WindowsError:
+ break
+ index=index+1
+ if not version_pattern.match(version):
+ continue
+ targets=[]
+ for target,arch in all_ifort_platforms:
+ try:
+ if target=='intel64':targetDir='EM64T_NATIVE'
+ else:targetDir=target
+ Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)
+ icl_version=Utils.winreg.OpenKey(all_versions,version)
+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
+ batch_file=os.path.join(path,'bin','iclvars.bat')
+ if os.path.isfile(batch_file):
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ pass
+ for target,arch in all_ifort_platforms:
+ try:
+ icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+target)
+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
+ batch_file=os.path.join(path,'bin','iclvars.bat')
+ if os.path.isfile(batch_file):
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ continue
+ major=version[0:2]
+ versions.append(('intel '+major,targets))
+def setup_ifort(conf,versions,arch=False):
+ platforms=Utils.to_list(conf.env['MSVC_TARGETS'])or[i for i,j in all_ifort_platforms]
+ desired_versions=conf.env['MSVC_VERSIONS']or[v for v,_ in versions][::-1]
+ versiondict=dict(versions)
+ for version in desired_versions:
+ try:
+ targets=dict(versiondict[version])
+ for target in platforms:
+ try:
+ try:
+ realtarget,(p1,p2,p3)=targets[target]
+ except conf.errors.ConfigurationError:
+ del(targets[target])
+ else:
+ compiler,revision=version.rsplit(' ',1)
+ if arch:
+ return compiler,revision,p1,p2,p3,realtarget
+ else:
+ return compiler,revision,p1,p2,p3
+ except KeyError:
+ continue
+ except KeyError:
+ continue
+ conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_ifort)')
+@conf
+def get_ifort_version_win32(conf,compiler,version,target,vcvars):
+ try:
+ conf.msvc_cnt+=1
+ except AttributeError:
+ conf.msvc_cnt=1
+ batfile=conf.bldnode.make_node('waf-print-msvc-%d.bat'%conf.msvc_cnt)
+ batfile.write("""@echo off
+set INCLUDE=
+set LIB=
+call "%s" %s
+echo PATH=%%PATH%%
+echo INCLUDE=%%INCLUDE%%
+echo LIB=%%LIB%%;%%LIBPATH%%
+"""%(vcvars,target))
+ sout=conf.cmd_and_log(['cmd.exe','/E:on','/V:on','/C',batfile.abspath()])
+ batfile.delete()
+ lines=sout.splitlines()
+ if not lines[0]:
+ lines.pop(0)
+ MSVC_PATH=MSVC_INCDIR=MSVC_LIBDIR=None
+ for line in lines:
+ if line.startswith('PATH='):
+ path=line[5:]
+ MSVC_PATH=path.split(';')
+ elif line.startswith('INCLUDE='):
+ MSVC_INCDIR=[i for i in line[8:].split(';')if i]
+ elif line.startswith('LIB='):
+ MSVC_LIBDIR=[i for i in line[4:].split(';')if i]
+ if None in(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR):
+ conf.fatal('msvc: Could not find a valid architecture for building (get_ifort_version_win32)')
+ env=dict(os.environ)
+ env.update(PATH=path)
+ compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
+ fc=conf.find_program(compiler_name,path_list=MSVC_PATH)
+ if'CL'in env:
+ del(env['CL'])
+ try:
+ try:
+ conf.cmd_and_log(fc+['/help'],env=env)
+ except UnicodeError:
+ st=Utils.ex_stack()
+ if conf.logger:
+ conf.logger.error(st)
+ conf.fatal('msvc: Unicode error - check the code page?')
+ except Exception ,e:
+ debug('msvc: get_ifort_version: %r %r %r -> failure %s'%(compiler,version,target,str(e)))
+ conf.fatal('msvc: cannot run the compiler in get_ifort_version (run with -v to display errors)')
+ else:
+ debug('msvc: get_ifort_version: %r %r %r -> OK',compiler,version,target)
+ finally:
+ conf.env[compiler_name]=''
+ return(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR)
+def get_compiler_env(conf,compiler,version,bat_target,bat,select=None):
+ lazy=getattr(Options.options,'msvc_lazy',True)
+ if conf.env.MSVC_LAZY_AUTODETECT is False:
+ lazy=False
+ def msvc_thunk():
+ vs=conf.get_ifort_version_win32(compiler,version,bat_target,bat)
+ if select:
+ return select(vs)
+ else:
+ return vs
+ return lazytup(msvc_thunk,lazy,([],[],[]))
+class lazytup(object):
+ def __init__(self,fn,lazy=True,default=None):
+ self.fn=fn
+ self.default=default
+ if not lazy:
+ self.evaluate()
+ def __len__(self):
+ self.evaluate()
+ return len(self.value)
+ def __iter__(self):
+ self.evaluate()
+ for i,v in enumerate(self.value):
+ yield v
+ def __getitem__(self,i):
+ self.evaluate()
+ return self.value[i]
+ def __repr__(self):
+ if hasattr(self,'value'):
+ return repr(self.value)
+ elif self.default:
+ return repr(self.default)
+ else:
+ self.evaluate()
+ return repr(self.value)
+ def evaluate(self):
+ if hasattr(self,'value'):
+ return
+ self.value=self.fn()
+@conf
+def get_ifort_versions(conf,eval_and_save=True):
+ if conf.env['IFORT_INSTALLED_VERSIONS']:
+ return conf.env['IFORT_INSTALLED_VERSIONS']
+ lst=[]
+ conf.gather_ifort_versions(lst)
+ if eval_and_save:
+ def checked_target(t):
+ target,(arch,paths)=t
+ try:
+ paths.evaluate()
+ except conf.errors.ConfigurationError:
+ return None
+ else:
+ return t
+ lst=[(version,list(filter(checked_target,targets)))for version,targets in lst]
+ conf.env['IFORT_INSTALLED_VERSIONS']=lst
+ return lst
+@conf
+def detect_ifort(conf,arch=False):
+ versions=get_ifort_versions(conf,False)
+ return setup_ifort(conf,versions,arch)
+def _get_prog_names(conf,compiler):
+ if compiler=='intel':
+ compiler_name='ifort'
+ linker_name='XILINK'
+ lib_name='XILIB'
+ else:
+ compiler_name='CL'
+ linker_name='LINK'
+ lib_name='LIB'
+ return compiler_name,linker_name,lib_name
+@conf
+def find_ifort_win32(conf):
+ v=conf.env
+ path=v['PATH']
+ compiler=v['MSVC_COMPILER']
+ version=v['MSVC_VERSION']
+ compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
+ v.IFORT_MANIFEST=(compiler=='intel'and version>=11)
+ fc=conf.find_program(compiler_name,var='FC',path_list=path)
+ env=dict(conf.environ)
+ if path:env.update(PATH=';'.join(path))
+ if not conf.cmd_and_log(fc+['/nologo','/help'],env=env):
+ conf.fatal('not intel fortran compiler could not be identified')
+ v['FC_NAME']='IFORT'
+ if not v['LINK_FC']:
+ conf.find_program(linker_name,var='LINK_FC',path_list=path,mandatory=True)
+ if not v['AR']:
+ conf.find_program(lib_name,path_list=path,var='AR',mandatory=True)
+ v['ARFLAGS']=['/NOLOGO']
+ if v.IFORT_MANIFEST:
+ conf.find_program('MT',path_list=path,var='MT')
+ v['MTFLAGS']=['/NOLOGO']
+ try:
+ conf.load('winres')
+ except Errors.WafError:
+ warn('Resource compiler not found. Compiling resource file is disabled')
+@after_method('apply_link')
+@feature('fc')
+def apply_flags_ifort(self):
+ if not self.env.IFORT_WIN32 or not getattr(self,'link_task',None):
+ return
+ is_static=isinstance(self.link_task,ccroot.stlink_task)
+ subsystem=getattr(self,'subsystem','')
+ if subsystem:
+ subsystem='/subsystem:%s'%subsystem
+ flags=is_static and'ARFLAGS'or'LINKFLAGS'
+ self.env.append_value(flags,subsystem)
+ if not is_static:
+ for f in self.env.LINKFLAGS:
+ d=f.lower()
+ if d[1:]=='debug':
+ pdbnode=self.link_task.outputs[0].change_ext('.pdb')
+ self.link_task.outputs.append(pdbnode)
+ if getattr(self,'install_task',None):
+ self.pdb_install_task=self.bld.install_files(self.install_task.dest,pdbnode,env=self.env)
+ break
+@feature('fcprogram','fcshlib','fcprogram_test')
+@after_method('apply_link')
+def apply_manifest_ifort(self):
+ if self.env.IFORT_WIN32 and getattr(self,'link_task',None):
+ self.link_task.env.FC=self.env.LINK_FC
+ if self.env.IFORT_WIN32 and self.env.IFORT_MANIFEST and getattr(self,'link_task',None):
+ out_node=self.link_task.outputs[0]
+ man_node=out_node.parent.find_or_declare(out_node.name+'.manifest')
+ self.link_task.outputs.append(man_node)
+ self.link_task.do_manifest=True
+def exec_mf(self):
+ env=self.env
+ mtool=env['MT']
+ if not mtool:
+ return 0
+ self.do_manifest=False
+ outfile=self.outputs[0].abspath()
+ manifest=None
+ for out_node in self.outputs:
+ if out_node.name.endswith('.manifest'):
+ manifest=out_node.abspath()
+ break
+ if manifest is None:
+ return 0
+ mode=''
+ if'fcprogram'in self.generator.features or'fcprogram_test'in self.generator.features:
+ mode='1'
+ elif'fcshlib'in self.generator.features:
+ mode='2'
+ debug('msvc: embedding manifest in mode %r'%mode)
+ lst=[]+mtool
+ lst.extend(Utils.to_list(env['MTFLAGS']))
+ lst.extend(['-manifest',manifest])
+ lst.append('-outputresource:%s;%s'%(outfile,mode))
+ return self.exec_command(lst)
+def quote_response_command(self,flag):
+ if flag.find(' ')>-1:
+ for x in('/LIBPATH:','/IMPLIB:','/OUT:','/I'):
+ if flag.startswith(x):
+ flag='%s"%s"'%(x,flag[len(x):])
+ break
+ else:
+ flag='"%s"'%flag
+ return flag
+def exec_response_command(self,cmd,**kw):
+ try:
+ tmp=None
+ if sys.platform.startswith('win')and isinstance(cmd,list)and len(' '.join(cmd))>=8192:
+ program=cmd[0]
+ cmd=[self.quote_response_command(x)for x in cmd]
+ (fd,tmp)=tempfile.mkstemp()
+ os.write(fd,'\r\n'.join(i.replace('\\','\\\\')for i in cmd[1:]))
+ os.close(fd)
+ cmd=[program,'@'+tmp]
+ ret=super(self.__class__,self).exec_command(cmd,**kw)
+ finally:
+ if tmp:
+ try:
+ os.remove(tmp)
+ except OSError:
+ pass
+ return ret
+def exec_command_ifort(self,*k,**kw):
+ if isinstance(k[0],list):
+ lst=[]
+ carry=''
+ for a in k[0]:
+ if a=='/Fo'or a=='/doc'or a[-1]==':':
+ carry=a
+ else:
+ lst.append(carry+a)
+ carry=''
+ k=[lst]
+ if self.env['PATH']:
+ env=dict(self.env.env or os.environ)
+ env.update(PATH=';'.join(self.env['PATH']))
+ kw['env']=env
+ if not'cwd'in kw:
+ kw['cwd']=self.generator.bld.variant_dir
+ ret=self.exec_response_command(k[0],**kw)
+ if not ret and getattr(self,'do_manifest',None):
+ ret=self.exec_mf()
+ return ret
+def wrap_class(class_name):
+ cls=Task.classes.get(class_name,None)
+ if not cls:
+ return None
+ derived_class=type(class_name,(cls,),{})
+ def exec_command(self,*k,**kw):
+ if self.env.IFORT_WIN32:
+ return self.exec_command_ifort(*k,**kw)
+ else:
+ return super(derived_class,self).exec_command(*k,**kw)
+ derived_class.exec_command=exec_command
+ derived_class.exec_response_command=exec_response_command
+ derived_class.quote_response_command=quote_response_command
+ derived_class.exec_command_ifort=exec_command_ifort
+ derived_class.exec_mf=exec_mf
+ if hasattr(cls,'hcode'):
+ derived_class.hcode=cls.hcode
+ return derived_class
+for k in'fc fcprogram fcprogram_test fcshlib fcstlib'.split():
+ wrap_class(k)
diff --git a/waflib/Tools/intltool.py b/waflib/Tools/intltool.py
new file mode 100644
index 0000000..c751e26
--- /dev/null
+++ b/waflib/Tools/intltool.py
@@ -0,0 +1,97 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re
+from waflib import Context,Task,Utils,Logs
+import waflib.Tools.ccroot
+from waflib.TaskGen import feature,before_method,taskgen_method
+from waflib.Logs import error
+from waflib.Configure import conf
+_style_flags={'ba':'-b','desktop':'-d','keys':'-k','quoted':'--quoted-style','quotedxml':'--quotedxml-style','rfc822deb':'-r','schemas':'-s','xml':'-x',}
+@taskgen_method
+def ensure_localedir(self):
+ if not self.env.LOCALEDIR:
+ if self.env.DATAROOTDIR:
+ self.env.LOCALEDIR=os.path.join(self.env.DATAROOTDIR,'locale')
+ else:
+ self.env.LOCALEDIR=os.path.join(self.env.PREFIX,'share','locale')
+@before_method('process_source')
+@feature('intltool_in')
+def apply_intltool_in_f(self):
+ try:self.meths.remove('process_source')
+ except ValueError:pass
+ self.ensure_localedir()
+ podir=getattr(self,'podir','.')
+ podirnode=self.path.find_dir(podir)
+ if not podirnode:
+ error("could not find the podir %r"%podir)
+ return
+ cache=getattr(self,'intlcache','.intlcache')
+ self.env.INTLCACHE=[os.path.join(str(self.path.get_bld()),podir,cache)]
+ self.env.INTLPODIR=podirnode.bldpath()
+ self.env.append_value('INTLFLAGS',getattr(self,'flags',self.env.INTLFLAGS_DEFAULT))
+ if'-c'in self.env.INTLFLAGS:
+ self.bld.fatal('Redundant -c flag in intltool task %r'%self)
+ style=getattr(self,'style',None)
+ if style:
+ try:
+ style_flag=_style_flags[style]
+ except KeyError:
+ self.bld.fatal('intltool_in style "%s" is not valid'%style)
+ self.env.append_unique('INTLFLAGS',[style_flag])
+ for i in self.to_list(self.source):
+ node=self.path.find_resource(i)
+ task=self.create_task('intltool',node,node.change_ext(''))
+ inst=getattr(self,'install_path',None)
+ if inst:
+ self.bld.install_files(inst,task.outputs)
+@feature('intltool_po')
+def apply_intltool_po(self):
+ try:self.meths.remove('process_source')
+ except ValueError:pass
+ self.ensure_localedir()
+ appname=getattr(self,'appname',getattr(Context.g_module,Context.APPNAME,'set_your_app_name'))
+ podir=getattr(self,'podir','.')
+ inst=getattr(self,'install_path','${LOCALEDIR}')
+ linguas=self.path.find_node(os.path.join(podir,'LINGUAS'))
+ if linguas:
+ file=open(linguas.abspath())
+ langs=[]
+ for line in file.readlines():
+ if not line.startswith('#'):
+ langs+=line.split()
+ file.close()
+ re_linguas=re.compile('[-a-zA-Z_@.]+')
+ for lang in langs:
+ if re_linguas.match(lang):
+ node=self.path.find_resource(os.path.join(podir,re_linguas.match(lang).group()+'.po'))
+ task=self.create_task('po',node,node.change_ext('.mo'))
+ if inst:
+ filename=task.outputs[0].name
+ (langname,ext)=os.path.splitext(filename)
+ inst_file=inst+os.sep+langname+os.sep+'LC_MESSAGES'+os.sep+appname+'.mo'
+ self.bld.install_as(inst_file,task.outputs[0],chmod=getattr(self,'chmod',Utils.O644),env=task.env)
+ else:
+ Logs.pprint('RED',"Error no LINGUAS file found in po directory")
+class po(Task.Task):
+ run_str='${MSGFMT} -o ${TGT} ${SRC}'
+ color='BLUE'
+class intltool(Task.Task):
+ run_str='${INTLTOOL} ${INTLFLAGS} ${INTLCACHE_ST:INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}'
+ color='BLUE'
+@conf
+def find_msgfmt(conf):
+ conf.find_program('msgfmt',var='MSGFMT')
+@conf
+def find_intltool_merge(conf):
+ if not conf.env.PERL:
+ conf.find_program('perl',var='PERL')
+ conf.env.INTLCACHE_ST='--cache=%s'
+ conf.env.INTLFLAGS_DEFAULT=['-q','-u']
+ conf.find_program('intltool-merge',interpreter='PERL',var='INTLTOOL')
+def configure(conf):
+ conf.find_msgfmt()
+ conf.find_intltool_merge()
+ if conf.env.CC or conf.env.CXX:
+ conf.check(header_name='locale.h')
diff --git a/waflib/Tools/irixcc.py b/waflib/Tools/irixcc.py
new file mode 100644
index 0000000..74a36cf
--- /dev/null
+++ b/waflib/Tools/irixcc.py
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_irixcc(conf):
+ v=conf.env
+ cc=None
+ if v['CC']:cc=v['CC']
+ elif'CC'in conf.environ:cc=conf.environ['CC']
+ if not cc:cc=conf.find_program('cc',var='CC')
+ if not cc:conf.fatal('irixcc was not found')
+ try:
+ conf.cmd_and_log(cc+['-version'])
+ except Exception:
+ conf.fatal('%r -version could not be executed'%cc)
+ v['CC']=cc
+ v['CC_NAME']='irix'
+@conf
+def irixcc_common_flags(conf):
+ v=conf.env
+ v['CC_SRC_F']=''
+ v['CC_TGT_F']=['-c','-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ if not v['LINK_CC']:v['LINK_CC']=v['CC']
+ v['CCLNK_SRC_F']=''
+ v['CCLNK_TGT_F']=['-o']
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['cprogram_PATTERN']='%s'
+ v['cshlib_PATTERN']='lib%s.so'
+ v['cstlib_PATTERN']='lib%s.a'
+def configure(conf):
+ conf.find_irixcc()
+ conf.find_cpp()
+ conf.find_ar()
+ conf.irixcc_common_flags()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/javaw.py b/waflib/Tools/javaw.py
new file mode 100644
index 0000000..585cce7
--- /dev/null
+++ b/waflib/Tools/javaw.py
@@ -0,0 +1,319 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,tempfile,shutil
+from waflib import Task,Utils,Errors,Node,Logs
+from waflib.Configure import conf
+from waflib.TaskGen import feature,before_method,after_method
+from waflib.Tools import ccroot
+ccroot.USELIB_VARS['javac']=set(['CLASSPATH','JAVACFLAGS'])
+SOURCE_RE='**/*.java'
+JAR_RE='**/*'
+class_check_source='''
+public class Test {
+ public static void main(String[] argv) {
+ Class lib;
+ if (argv.length < 1) {
+ System.err.println("Missing argument");
+ System.exit(77);
+ }
+ try {
+ lib = Class.forName(argv[0]);
+ } catch (ClassNotFoundException e) {
+ System.err.println("ClassNotFoundException");
+ System.exit(1);
+ }
+ lib = null;
+ System.exit(0);
+ }
+}
+'''
+@feature('javac')
+@before_method('process_source')
+def apply_java(self):
+ Utils.def_attrs(self,jarname='',classpath='',sourcepath='.',srcdir='.',jar_mf_attributes={},jar_mf_classpath=[])
+ outdir=getattr(self,'outdir',None)
+ if outdir:
+ if not isinstance(outdir,Node.Node):
+ outdir=self.path.get_bld().make_node(self.outdir)
+ else:
+ outdir=self.path.get_bld()
+ outdir.mkdir()
+ self.outdir=outdir
+ self.env['OUTDIR']=outdir.abspath()
+ self.javac_task=tsk=self.create_task('javac')
+ tmp=[]
+ srcdir=getattr(self,'srcdir','')
+ if isinstance(srcdir,Node.Node):
+ srcdir=[srcdir]
+ for x in Utils.to_list(srcdir):
+ if isinstance(x,Node.Node):
+ y=x
+ else:
+ y=self.path.find_dir(x)
+ if not y:
+ self.bld.fatal('Could not find the folder %s from %s'%(x,self.path))
+ tmp.append(y)
+ tsk.srcdir=tmp
+ if getattr(self,'compat',None):
+ tsk.env.append_value('JAVACFLAGS',['-source',self.compat])
+ if hasattr(self,'sourcepath'):
+ fold=[isinstance(x,Node.Node)and x or self.path.find_dir(x)for x in self.to_list(self.sourcepath)]
+ names=os.pathsep.join([x.srcpath()for x in fold])
+ else:
+ names=[x.srcpath()for x in tsk.srcdir]
+ if names:
+ tsk.env.append_value('JAVACFLAGS',['-sourcepath',names])
+@feature('javac')
+@after_method('apply_java')
+def use_javac_files(self):
+ lst=[]
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ names=self.to_list(getattr(self,'use',[]))
+ get=self.bld.get_tgen_by_name
+ for x in names:
+ try:
+ y=get(x)
+ except Exception:
+ self.uselib.append(x)
+ else:
+ y.post()
+ if hasattr(y,'jar_task'):
+ lst.append(y.jar_task.outputs[0].abspath())
+ self.javac_task.set_run_after(y.jar_task)
+ else:
+ for tsk in y.tasks:
+ self.javac_task.set_run_after(tsk)
+ if lst:
+ self.env.append_value('CLASSPATH',lst)
+@feature('javac')
+@after_method('apply_java','propagate_uselib_vars','use_javac_files')
+def set_classpath(self):
+ self.env.append_value('CLASSPATH',getattr(self,'classpath',[]))
+ for x in self.tasks:
+ x.env.CLASSPATH=os.pathsep.join(self.env.CLASSPATH)+os.pathsep
+@feature('jar')
+@after_method('apply_java','use_javac_files')
+@before_method('process_source')
+def jar_files(self):
+ destfile=getattr(self,'destfile','test.jar')
+ jaropts=getattr(self,'jaropts',[])
+ manifest=getattr(self,'manifest',None)
+ basedir=getattr(self,'basedir',None)
+ if basedir:
+ if not isinstance(self.basedir,Node.Node):
+ basedir=self.path.get_bld().make_node(basedir)
+ else:
+ basedir=self.path.get_bld()
+ if not basedir:
+ self.bld.fatal('Could not find the basedir %r for %r'%(self.basedir,self))
+ self.jar_task=tsk=self.create_task('jar_create')
+ if manifest:
+ jarcreate=getattr(self,'jarcreate','cfm')
+ if not isinstance(manifest,Node.Node):
+ node=self.path.find_or_declare(manifest)
+ else:
+ node=manifest
+ tsk.dep_nodes.append(node)
+ jaropts.insert(0,node.abspath())
+ else:
+ jarcreate=getattr(self,'jarcreate','cf')
+ if not isinstance(destfile,Node.Node):
+ destfile=self.path.find_or_declare(destfile)
+ if not destfile:
+ self.bld.fatal('invalid destfile %r for %r'%(destfile,self))
+ tsk.set_outputs(destfile)
+ tsk.basedir=basedir
+ jaropts.append('-C')
+ jaropts.append(basedir.bldpath())
+ jaropts.append('.')
+ tsk.env['JAROPTS']=jaropts
+ tsk.env['JARCREATE']=jarcreate
+ if getattr(self,'javac_task',None):
+ tsk.set_run_after(self.javac_task)
+@feature('jar')
+@after_method('jar_files')
+def use_jar_files(self):
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ names=self.to_list(getattr(self,'use',[]))
+ get=self.bld.get_tgen_by_name
+ for x in names:
+ try:
+ y=get(x)
+ except Exception:
+ self.uselib.append(x)
+ else:
+ y.post()
+ self.jar_task.run_after.update(y.tasks)
+class jar_create(Task.Task):
+ color='GREEN'
+ run_str='${JAR} ${JARCREATE} ${TGT} ${JAROPTS}'
+ def runnable_status(self):
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ if not self.inputs:
+ global JAR_RE
+ try:
+ self.inputs=[x for x in self.basedir.ant_glob(JAR_RE,remove=False)if id(x)!=id(self.outputs[0])]
+ except Exception:
+ raise Errors.WafError('Could not find the basedir %r for %r'%(self.basedir,self))
+ return super(jar_create,self).runnable_status()
+class javac(Task.Task):
+ color='BLUE'
+ vars=['CLASSPATH','JAVACFLAGS','JAVAC','OUTDIR']
+ def uid(self):
+ lst=[self.__class__.__name__,self.generator.outdir.abspath()]
+ for x in self.srcdir:
+ lst.append(x.abspath())
+ return Utils.h_list(lst)
+ def runnable_status(self):
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ if not self.inputs:
+ global SOURCE_RE
+ self.inputs=[]
+ for x in self.srcdir:
+ self.inputs.extend(x.ant_glob(SOURCE_RE,remove=False))
+ return super(javac,self).runnable_status()
+ def run(self):
+ env=self.env
+ gen=self.generator
+ bld=gen.bld
+ wd=bld.bldnode.abspath()
+ def to_list(xx):
+ if isinstance(xx,str):return[xx]
+ return xx
+ cmd=[]
+ cmd.extend(to_list(env['JAVAC']))
+ cmd.extend(['-classpath'])
+ cmd.extend(to_list(env['CLASSPATH']))
+ cmd.extend(['-d'])
+ cmd.extend(to_list(env['OUTDIR']))
+ cmd.extend(to_list(env['JAVACFLAGS']))
+ files=[a.path_from(bld.bldnode)for a in self.inputs]
+ tmp=None
+ try:
+ if len(str(files))+len(str(cmd))>8192:
+ (fd,tmp)=tempfile.mkstemp(dir=bld.bldnode.abspath())
+ try:
+ os.write(fd,'\n'.join(files))
+ finally:
+ if tmp:
+ os.close(fd)
+ if Logs.verbose:
+ Logs.debug('runner: %r'%(cmd+files))
+ cmd.append('@'+tmp)
+ else:
+ cmd+=files
+ ret=self.exec_command(cmd,cwd=wd,env=env.env or None)
+ finally:
+ if tmp:
+ os.remove(tmp)
+ return ret
+ def post_run(self):
+ for n in self.generator.outdir.ant_glob('**/*.class'):
+ n.sig=Utils.h_file(n.abspath())
+ self.generator.bld.task_sigs[self.uid()]=self.cache_sig
+@feature('javadoc')
+@after_method('process_rule')
+def create_javadoc(self):
+ tsk=self.create_task('javadoc')
+ tsk.classpath=getattr(self,'classpath',[])
+ self.javadoc_package=Utils.to_list(self.javadoc_package)
+ if not isinstance(self.javadoc_output,Node.Node):
+ self.javadoc_output=self.bld.path.find_or_declare(self.javadoc_output)
+class javadoc(Task.Task):
+ color='BLUE'
+ def __str__(self):
+ return'%s: %s -> %s\n'%(self.__class__.__name__,self.generator.srcdir,self.generator.javadoc_output)
+ def run(self):
+ env=self.env
+ bld=self.generator.bld
+ wd=bld.bldnode.abspath()
+ srcpath=self.generator.path.abspath()+os.sep+self.generator.srcdir
+ srcpath+=os.pathsep
+ srcpath+=self.generator.path.get_bld().abspath()+os.sep+self.generator.srcdir
+ classpath=env.CLASSPATH
+ classpath+=os.pathsep
+ classpath+=os.pathsep.join(self.classpath)
+ classpath="".join(classpath)
+ self.last_cmd=lst=[]
+ lst.extend(Utils.to_list(env['JAVADOC']))
+ lst.extend(['-d',self.generator.javadoc_output.abspath()])
+ lst.extend(['-sourcepath',srcpath])
+ lst.extend(['-classpath',classpath])
+ lst.extend(['-subpackages'])
+ lst.extend(self.generator.javadoc_package)
+ lst=[x for x in lst if x]
+ self.generator.bld.cmd_and_log(lst,cwd=wd,env=env.env or None,quiet=0)
+ def post_run(self):
+ nodes=self.generator.javadoc_output.ant_glob('**')
+ for x in nodes:
+ x.sig=Utils.h_file(x.abspath())
+ self.generator.bld.task_sigs[self.uid()]=self.cache_sig
+def configure(self):
+ java_path=self.environ['PATH'].split(os.pathsep)
+ v=self.env
+ if'JAVA_HOME'in self.environ:
+ java_path=[os.path.join(self.environ['JAVA_HOME'],'bin')]+java_path
+ self.env['JAVA_HOME']=[self.environ['JAVA_HOME']]
+ for x in'javac java jar javadoc'.split():
+ self.find_program(x,var=x.upper(),path_list=java_path)
+ if'CLASSPATH'in self.environ:
+ v['CLASSPATH']=self.environ['CLASSPATH']
+ if not v['JAR']:self.fatal('jar is required for making java packages')
+ if not v['JAVAC']:self.fatal('javac is required for compiling java classes')
+ v['JARCREATE']='cf'
+ v['JAVACFLAGS']=[]
+@conf
+def check_java_class(self,classname,with_classpath=None):
+ javatestdir='.waf-javatest'
+ classpath=javatestdir
+ if self.env['CLASSPATH']:
+ classpath+=os.pathsep+self.env['CLASSPATH']
+ if isinstance(with_classpath,str):
+ classpath+=os.pathsep+with_classpath
+ shutil.rmtree(javatestdir,True)
+ os.mkdir(javatestdir)
+ Utils.writef(os.path.join(javatestdir,'Test.java'),class_check_source)
+ self.exec_command(self.env['JAVAC']+[os.path.join(javatestdir,'Test.java')],shell=False)
+ cmd=self.env['JAVA']+['-cp',classpath,'Test',classname]
+ self.to_log("%s\n"%str(cmd))
+ found=self.exec_command(cmd,shell=False)
+ self.msg('Checking for java class %s'%classname,not found)
+ shutil.rmtree(javatestdir,True)
+ return found
+@conf
+def check_jni_headers(conf):
+ if not conf.env.CC_NAME and not conf.env.CXX_NAME:
+ conf.fatal('load a compiler first (gcc, g++, ..)')
+ if not conf.env.JAVA_HOME:
+ conf.fatal('set JAVA_HOME in the system environment')
+ javaHome=conf.env['JAVA_HOME'][0]
+ dir=conf.root.find_dir(conf.env.JAVA_HOME[0]+'/include')
+ if dir is None:
+ dir=conf.root.find_dir(conf.env.JAVA_HOME[0]+'/../Headers')
+ if dir is None:
+ conf.fatal('JAVA_HOME does not seem to be set properly')
+ f=dir.ant_glob('**/(jni|jni_md).h')
+ incDirs=[x.parent.abspath()for x in f]
+ dir=conf.root.find_dir(conf.env.JAVA_HOME[0])
+ f=dir.ant_glob('**/*jvm.(so|dll|dylib)')
+ libDirs=[x.parent.abspath()for x in f]or[javaHome]
+ f=dir.ant_glob('**/*jvm.(lib)')
+ if f:
+ libDirs=[[x,y.parent.abspath()]for x in libDirs for y in f]
+ if conf.env.DEST_OS=='freebsd':
+ conf.env.append_unique('LINKFLAGS_JAVA','-pthread')
+ for d in libDirs:
+ try:
+ conf.check(header_name='jni.h',define_name='HAVE_JNI_H',lib='jvm',libpath=d,includes=incDirs,uselib_store='JAVA',uselib='JAVA')
+ except Exception:
+ pass
+ else:
+ break
+ else:
+ conf.fatal('could not find lib jvm in %r (see config.log)'%libDirs)
diff --git a/waflib/Tools/kde4.py b/waflib/Tools/kde4.py
new file mode 100644
index 0000000..3e90377
--- /dev/null
+++ b/waflib/Tools/kde4.py
@@ -0,0 +1,48 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re
+from waflib import Task,Utils
+from waflib.TaskGen import feature
+@feature('msgfmt')
+def apply_msgfmt(self):
+ for lang in self.to_list(self.langs):
+ node=self.path.find_resource(lang+'.po')
+ task=self.create_task('msgfmt',node,node.change_ext('.mo'))
+ langname=lang.split('/')
+ langname=langname[-1]
+ inst=getattr(self,'install_path','${KDE4_LOCALE_INSTALL_DIR}')
+ self.bld.install_as(inst+os.sep+langname+os.sep+'LC_MESSAGES'+os.sep+getattr(self,'appname','set_your_appname')+'.mo',task.outputs[0],chmod=getattr(self,'chmod',Utils.O644))
+class msgfmt(Task.Task):
+ color='BLUE'
+ run_str='${MSGFMT} ${SRC} -o ${TGT}'
+def configure(self):
+ kdeconfig=self.find_program('kde4-config')
+ prefix=self.cmd_and_log(kdeconfig+['--prefix']).strip()
+ fname='%s/share/apps/cmake/modules/KDELibsDependencies.cmake'%prefix
+ try:os.stat(fname)
+ except OSError:
+ fname='%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake'%prefix
+ try:os.stat(fname)
+ except OSError:self.fatal('could not open %s'%fname)
+ try:
+ txt=Utils.readf(fname)
+ except EnvironmentError:
+ self.fatal('could not read %s'%fname)
+ txt=txt.replace('\\\n','\n')
+ fu=re.compile('#(.*)\n')
+ txt=fu.sub('',txt)
+ setregexp=re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)')
+ found=setregexp.findall(txt)
+ for(_,key,val)in found:
+ self.env[key]=val
+ self.env['LIB_KDECORE']=['kdecore']
+ self.env['LIB_KDEUI']=['kdeui']
+ self.env['LIB_KIO']=['kio']
+ self.env['LIB_KHTML']=['khtml']
+ self.env['LIB_KPARTS']=['kparts']
+ self.env['LIBPATH_KDECORE']=[os.path.join(self.env.KDE4_LIB_INSTALL_DIR,'kde4','devel'),self.env.KDE4_LIB_INSTALL_DIR]
+ self.env['INCLUDES_KDECORE']=[self.env['KDE4_INCLUDE_INSTALL_DIR']]
+ self.env.append_value('INCLUDES_KDECORE',[self.env['KDE4_INCLUDE_INSTALL_DIR']+os.sep+'KDE'])
+ self.find_program('msgfmt',var='MSGFMT')
diff --git a/waflib/Tools/ldc2.py b/waflib/Tools/ldc2.py
new file mode 100644
index 0000000..75162e4
--- /dev/null
+++ b/waflib/Tools/ldc2.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ar,d
+from waflib.Configure import conf
+@conf
+def find_ldc2(conf):
+ conf.find_program(['ldc2'],var='D')
+ out=conf.cmd_and_log(conf.env.D+['-version'])
+ if out.find("based on DMD v2.")==-1:
+ conf.fatal("detected compiler is not ldc2")
+@conf
+def common_flags_ldc2(conf):
+ v=conf.env
+ v['D_SRC_F']=['-c']
+ v['D_TGT_F']='-of%s'
+ v['D_LINKER']=v['D']
+ v['DLNK_SRC_F']=''
+ v['DLNK_TGT_F']='-of%s'
+ v['DINC_ST']='-I%s'
+ v['DSHLIB_MARKER']=v['DSTLIB_MARKER']=''
+ v['DSTLIB_ST']=v['DSHLIB_ST']='-L-l%s'
+ v['DSTLIBPATH_ST']=v['DLIBPATH_ST']='-L-L%s'
+ v['LINKFLAGS_dshlib']=['-L-shared']
+ v['DHEADER_ext']='.di'
+ v['DFLAGS_d_with_header']=['-H','-Hf']
+ v['D_HDR_F']='%s'
+ v['LINKFLAGS']=[]
+ v['DFLAGS_dshlib']=['-relocation-model=pic']
+def configure(conf):
+ conf.find_ldc2()
+ conf.load('ar')
+ conf.load('d')
+ conf.common_flags_ldc2()
+ conf.d_platform_flags()
diff --git a/waflib/Tools/lua.py b/waflib/Tools/lua.py
new file mode 100644
index 0000000..b801d5f
--- /dev/null
+++ b/waflib/Tools/lua.py
@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.TaskGen import extension
+from waflib import Task
+@extension('.lua')
+def add_lua(self,node):
+ tsk=self.create_task('luac',node,node.change_ext('.luac'))
+ inst_to=getattr(self,'install_path',self.env.LUADIR and'${LUADIR}'or None)
+ if inst_to:
+ self.bld.install_files(inst_to,tsk.outputs)
+ return tsk
+class luac(Task.Task):
+ run_str='${LUAC} -s -o ${TGT} ${SRC}'
+ color='PINK'
+def configure(conf):
+ conf.find_program('luac',var='LUAC')
diff --git a/waflib/Tools/msvc.py b/waflib/Tools/msvc.py
new file mode 100644
index 0000000..919c825
--- /dev/null
+++ b/waflib/Tools/msvc.py
@@ -0,0 +1,809 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,sys,re,tempfile
+from waflib import Utils,Task,Logs,Options,Errors
+from waflib.Logs import debug,warn
+from waflib.TaskGen import after_method,feature
+from waflib.Configure import conf
+from waflib.Tools import ccroot,c,cxx,ar,winres
+g_msvc_systemlibs='''
+aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
+cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
+credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
+ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
+faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
+gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
+kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
+mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
+msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
+netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
+odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
+osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
+ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
+rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
+shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
+traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
+version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm
+wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
+'''.split()
+all_msvc_platforms=[('x64','amd64'),('x86','x86'),('ia64','ia64'),('x86_amd64','amd64'),('x86_ia64','ia64'),('x86_arm','arm'),('amd64_x86','x86'),('amd64_arm','arm')]
+all_wince_platforms=[('armv4','arm'),('armv4i','arm'),('mipsii','mips'),('mipsii_fp','mips'),('mipsiv','mips'),('mipsiv_fp','mips'),('sh4','sh'),('x86','cex86')]
+all_icl_platforms=[('intel64','amd64'),('em64t','amd64'),('ia32','x86'),('Itanium','ia64')]
+def options(opt):
+ opt.add_option('--msvc_version',type='string',help='msvc version, eg: "msvc 10.0,msvc 9.0"',default='')
+ opt.add_option('--msvc_targets',type='string',help='msvc targets, eg: "x64,arm"',default='')
+ opt.add_option('--msvc_lazy_autodetect',action='store_true',help='lazily check msvc target environments')
+def setup_msvc(conf,versions,arch=False):
+ platforms=getattr(Options.options,'msvc_targets','').split(',')
+ if platforms==['']:
+ platforms=Utils.to_list(conf.env['MSVC_TARGETS'])or[i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
+ desired_versions=getattr(Options.options,'msvc_version','').split(',')
+ if desired_versions==['']:
+ desired_versions=conf.env['MSVC_VERSIONS']or[v for v,_ in versions][::-1]
+ versiondict=dict(versions)
+ for version in desired_versions:
+ try:
+ targets=dict(versiondict[version])
+ for target in platforms:
+ try:
+ try:
+ realtarget,(p1,p2,p3)=targets[target]
+ except conf.errors.ConfigurationError:
+ del(targets[target])
+ else:
+ compiler,revision=version.rsplit(' ',1)
+ if arch:
+ return compiler,revision,p1,p2,p3,realtarget
+ else:
+ return compiler,revision,p1,p2,p3
+ except KeyError:continue
+ except KeyError:continue
+ conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')
+@conf
+def get_msvc_version(conf,compiler,version,target,vcvars):
+ debug('msvc: get_msvc_version: %r %r %r',compiler,version,target)
+ try:
+ conf.msvc_cnt+=1
+ except AttributeError:
+ conf.msvc_cnt=1
+ batfile=conf.bldnode.make_node('waf-print-msvc-%d.bat'%conf.msvc_cnt)
+ batfile.write("""@echo off
+set INCLUDE=
+set LIB=
+call "%s" %s
+echo PATH=%%PATH%%
+echo INCLUDE=%%INCLUDE%%
+echo LIB=%%LIB%%;%%LIBPATH%%
+"""%(vcvars,target))
+ sout=conf.cmd_and_log(['cmd.exe','/E:on','/V:on','/C',batfile.abspath()])
+ lines=sout.splitlines()
+ if not lines[0]:
+ lines.pop(0)
+ MSVC_PATH=MSVC_INCDIR=MSVC_LIBDIR=None
+ for line in lines:
+ if line.startswith('PATH='):
+ path=line[5:]
+ MSVC_PATH=path.split(';')
+ elif line.startswith('INCLUDE='):
+ MSVC_INCDIR=[i for i in line[8:].split(';')if i]
+ elif line.startswith('LIB='):
+ MSVC_LIBDIR=[i for i in line[4:].split(';')if i]
+ if None in(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR):
+ conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)')
+ env=dict(os.environ)
+ env.update(PATH=path)
+ compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
+ cxx=conf.find_program(compiler_name,path_list=MSVC_PATH)
+ if'CL'in env:
+ del(env['CL'])
+ try:
+ try:
+ conf.cmd_and_log(cxx+['/help'],env=env)
+ except UnicodeError:
+ st=Utils.ex_stack()
+ if conf.logger:
+ conf.logger.error(st)
+ conf.fatal('msvc: Unicode error - check the code page?')
+ except Exception ,e:
+ debug('msvc: get_msvc_version: %r %r %r -> failure %s'%(compiler,version,target,str(e)))
+ conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
+ else:
+ debug('msvc: get_msvc_version: %r %r %r -> OK',compiler,version,target)
+ finally:
+ conf.env[compiler_name]=''
+ return(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR)
+@conf
+def gather_wsdk_versions(conf,versions):
+ version_pattern=re.compile('^v..?.?\...?.?')
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
+ except WindowsError:
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
+ except WindowsError:
+ return
+ index=0
+ while 1:
+ try:
+ version=Utils.winreg.EnumKey(all_versions,index)
+ except WindowsError:
+ break
+ index=index+1
+ if not version_pattern.match(version):
+ continue
+ try:
+ msvc_version=Utils.winreg.OpenKey(all_versions,version)
+ path,type=Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')
+ except WindowsError:
+ continue
+ if path and os.path.isfile(os.path.join(path,'bin','SetEnv.cmd')):
+ targets=[]
+ for target,arch in all_msvc_platforms:
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'wsdk',version,'/'+target,os.path.join(path,'bin','SetEnv.cmd')))))
+ except conf.errors.ConfigurationError:
+ pass
+ versions.append(('wsdk '+version[1:],targets))
+def gather_wince_supported_platforms():
+ supported_wince_platforms=[]
+ try:
+ ce_sdk=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
+ except WindowsError:
+ try:
+ ce_sdk=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
+ except WindowsError:
+ ce_sdk=''
+ if not ce_sdk:
+ return supported_wince_platforms
+ ce_index=0
+ while 1:
+ try:
+ sdk_device=Utils.winreg.EnumKey(ce_sdk,ce_index)
+ except WindowsError:
+ break
+ ce_index=ce_index+1
+ sdk=Utils.winreg.OpenKey(ce_sdk,sdk_device)
+ try:
+ path,type=Utils.winreg.QueryValueEx(sdk,'SDKRootDir')
+ except WindowsError:
+ try:
+ path,type=Utils.winreg.QueryValueEx(sdk,'SDKInformation')
+ path,xml=os.path.split(path)
+ except WindowsError:
+ continue
+ path=str(path)
+ path,device=os.path.split(path)
+ if not device:
+ path,device=os.path.split(path)
+ platforms=[]
+ for arch,compiler in all_wince_platforms:
+ if os.path.isdir(os.path.join(path,device,'Lib',arch)):
+ platforms.append((arch,compiler,os.path.join(path,device,'Include',arch),os.path.join(path,device,'Lib',arch)))
+ if platforms:
+ supported_wince_platforms.append((device,platforms))
+ return supported_wince_platforms
+def gather_msvc_detected_versions():
+ version_pattern=re.compile('^(\d\d?\.\d\d?)(Exp)?$')
+ detected_versions=[]
+ for vcver,vcvar in(('VCExpress','Exp'),('VisualStudio','')):
+ try:
+ prefix='SOFTWARE\\Wow6432node\\Microsoft\\'+vcver
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,prefix)
+ except WindowsError:
+ try:
+ prefix='SOFTWARE\\Microsoft\\'+vcver
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,prefix)
+ except WindowsError:
+ continue
+ index=0
+ while 1:
+ try:
+ version=Utils.winreg.EnumKey(all_versions,index)
+ except WindowsError:
+ break
+ index=index+1
+ match=version_pattern.match(version)
+ if not match:
+ continue
+ else:
+ versionnumber=float(match.group(1))
+ detected_versions.append((versionnumber,version+vcvar,prefix+"\\"+version))
+ def fun(tup):
+ return tup[0]
+ detected_versions.sort(key=fun)
+ return detected_versions
+def get_compiler_env(conf,compiler,version,bat_target,bat,select=None):
+ lazy=getattr(Options.options,'msvc_lazy_autodetect',False)or conf.env['MSVC_LAZY_AUTODETECT']
+ def msvc_thunk():
+ vs=conf.get_msvc_version(compiler,version,bat_target,bat)
+ if select:
+ return select(vs)
+ else:
+ return vs
+ return lazytup(msvc_thunk,lazy,([],[],[]))
+class lazytup(object):
+ def __init__(self,fn,lazy=True,default=None):
+ self.fn=fn
+ self.default=default
+ if not lazy:
+ self.evaluate()
+ def __len__(self):
+ self.evaluate()
+ return len(self.value)
+ def __iter__(self):
+ self.evaluate()
+ for i,v in enumerate(self.value):
+ yield v
+ def __getitem__(self,i):
+ self.evaluate()
+ return self.value[i]
+ def __repr__(self):
+ if hasattr(self,'value'):
+ return repr(self.value)
+ elif self.default:
+ return repr(self.default)
+ else:
+ self.evaluate()
+ return repr(self.value)
+ def evaluate(self):
+ if hasattr(self,'value'):
+ return
+ self.value=self.fn()
+@conf
+def gather_msvc_targets(conf,versions,version,vc_path):
+ targets=[]
+ if os.path.isfile(os.path.join(vc_path,'vcvarsall.bat')):
+ for target,realtarget in all_msvc_platforms[::-1]:
+ try:
+ targets.append((target,(realtarget,get_compiler_env(conf,'msvc',version,target,os.path.join(vc_path,'vcvarsall.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
+ elif os.path.isfile(os.path.join(vc_path,'Common7','Tools','vsvars32.bat')):
+ try:
+ targets.append(('x86',('x86',get_compiler_env(conf,'msvc',version,'x86',os.path.join(vc_path,'Common7','Tools','vsvars32.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
+ elif os.path.isfile(os.path.join(vc_path,'Bin','vcvars32.bat')):
+ try:
+ targets.append(('x86',('x86',get_compiler_env(conf,'msvc',version,'',os.path.join(vc_path,'Bin','vcvars32.bat')))))
+ except conf.errors.ConfigurationError:
+ pass
+ if targets:
+ versions.append(('msvc '+version,targets))
+@conf
+def gather_wince_targets(conf,versions,version,vc_path,vsvars,supported_platforms):
+ for device,platforms in supported_platforms:
+ cetargets=[]
+ for platform,compiler,include,lib in platforms:
+ winCEpath=os.path.join(vc_path,'ce')
+ if not os.path.isdir(winCEpath):
+ continue
+ if os.path.isdir(os.path.join(winCEpath,'lib',platform)):
+ bindirs=[os.path.join(winCEpath,'bin',compiler),os.path.join(winCEpath,'bin','x86_'+compiler)]
+ incdirs=[os.path.join(winCEpath,'include'),os.path.join(winCEpath,'atlmfc','include'),include]
+ libdirs=[os.path.join(winCEpath,'lib',platform),os.path.join(winCEpath,'atlmfc','lib',platform),lib]
+ def combine_common(compiler_env):
+ (common_bindirs,_1,_2)=compiler_env
+ return(bindirs+common_bindirs,incdirs,libdirs)
+ try:
+ cetargets.append((platform,(platform,get_compiler_env(conf,'msvc',version,'x86',vsvars,combine_common))))
+ except conf.errors.ConfigurationError:
+ continue
+ if cetargets:
+ versions.append((device+' '+version,cetargets))
+@conf
+def gather_winphone_targets(conf,versions,version,vc_path,vsvars):
+ targets=[]
+ for target,realtarget in all_msvc_platforms[::-1]:
+ try:
+ targets.append((target,(realtarget,get_compiler_env(conf,'winphone',version,target,vsvars))))
+ except conf.errors.ConfigurationError:
+ pass
+ if targets:
+ versions.append(('winphone '+version,targets))
+@conf
+def gather_msvc_versions(conf,versions):
+ vc_paths=[]
+ for(v,version,reg)in gather_msvc_detected_versions():
+ try:
+ try:
+ msvc_version=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,reg+"\\Setup\\VC")
+ except WindowsError:
+ msvc_version=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,reg+"\\Setup\\Microsoft Visual C++")
+ path,type=Utils.winreg.QueryValueEx(msvc_version,'ProductDir')
+ vc_paths.append((version,os.path.abspath(str(path))))
+ except WindowsError:
+ continue
+ wince_supported_platforms=gather_wince_supported_platforms()
+ for version,vc_path in vc_paths:
+ vs_path=os.path.dirname(vc_path)
+ vsvars=os.path.join(vs_path,'Common7','Tools','vsvars32.bat')
+ if wince_supported_platforms and os.path.isfile(vsvars):
+ conf.gather_wince_targets(versions,version,vc_path,vsvars,wince_supported_platforms)
+ for version,vc_path in vc_paths:
+ vs_path=os.path.dirname(vc_path)
+ vsvars=os.path.join(vs_path,'VC','WPSDK','WP80','vcvarsphoneall.bat')
+ if os.path.isfile(vsvars):
+ conf.gather_winphone_targets(versions,'8.0',vc_path,vsvars)
+ break
+ for version,vc_path in vc_paths:
+ vs_path=os.path.dirname(vc_path)
+ conf.gather_msvc_targets(versions,version,vc_path)
+@conf
+def gather_icl_versions(conf,versions):
+ version_pattern=re.compile('^...?.?\....?.?')
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
+ except WindowsError:
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Compilers\\C++')
+ except WindowsError:
+ return
+ index=0
+ while 1:
+ try:
+ version=Utils.winreg.EnumKey(all_versions,index)
+ except WindowsError:
+ break
+ index=index+1
+ if not version_pattern.match(version):
+ continue
+ targets=[]
+ for target,arch in all_icl_platforms:
+ try:
+ if target=='intel64':targetDir='EM64T_NATIVE'
+ else:targetDir=target
+ Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)
+ icl_version=Utils.winreg.OpenKey(all_versions,version)
+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
+ batch_file=os.path.join(path,'bin','iclvars.bat')
+ if os.path.isfile(batch_file):
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ pass
+ for target,arch in all_icl_platforms:
+ try:
+ icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+target)
+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
+ batch_file=os.path.join(path,'bin','iclvars.bat')
+ if os.path.isfile(batch_file):
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ except WindowsError:
+ continue
+ major=version[0:2]
+ versions.append(('intel '+major,targets))
+@conf
+def gather_intel_composer_versions(conf,versions):
+ version_pattern=re.compile('^...?.?\...?.?.?')
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Suites')
+ except WindowsError:
+ try:
+ all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Suites')
+ except WindowsError:
+ return
+ index=0
+ while 1:
+ try:
+ version=Utils.winreg.EnumKey(all_versions,index)
+ except WindowsError:
+ break
+ index=index+1
+ if not version_pattern.match(version):
+ continue
+ targets=[]
+ for target,arch in all_icl_platforms:
+ try:
+ if target=='intel64':targetDir='EM64T_NATIVE'
+ else:targetDir=target
+ try:
+ defaults=Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir)
+ except WindowsError:
+ if targetDir=='EM64T_NATIVE':
+ defaults=Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T')
+ else:
+ raise WindowsError
+ uid,type=Utils.winreg.QueryValueEx(defaults,'SubKey')
+ Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir)
+ icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++')
+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
+ batch_file=os.path.join(path,'bin','iclvars.bat')
+ if os.path.isfile(batch_file):
+ try:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
+ pass
+ compilervars_warning_attr='_compilervars_warning_key'
+ if version[0:2]=='13'and getattr(conf,compilervars_warning_attr,True):
+ setattr(conf,compilervars_warning_attr,False)
+ patch_url='http://software.intel.com/en-us/forums/topic/328487'
+ compilervars_arch=os.path.join(path,'bin','compilervars_arch.bat')
+ for vscomntool in('VS110COMNTOOLS','VS100COMNTOOLS'):
+ if vscomntool in os.environ:
+ vs_express_path=os.environ[vscomntool]+r'..\IDE\VSWinExpress.exe'
+ dev_env_path=os.environ[vscomntool]+r'..\IDE\devenv.exe'
+ if(r'if exist "%VS110COMNTOOLS%..\IDE\VSWinExpress.exe"'in Utils.readf(compilervars_arch)and not os.path.exists(vs_express_path)and not os.path.exists(dev_env_path)):
+ Logs.warn(('The Intel compilervar_arch.bat only checks for one Visual Studio SKU ''(VSWinExpress.exe) but it does not seem to be installed at %r. ''The intel command line set up will fail to configure unless the file %r''is patched. See: %s')%(vs_express_path,compilervars_arch,patch_url))
+ except WindowsError:
+ pass
+ major=version[0:2]
+ versions.append(('intel '+major,targets))
+@conf
+def get_msvc_versions(conf,eval_and_save=True):
+ if conf.env['MSVC_INSTALLED_VERSIONS']:
+ return conf.env['MSVC_INSTALLED_VERSIONS']
+ lst=[]
+ conf.gather_icl_versions(lst)
+ conf.gather_intel_composer_versions(lst)
+ conf.gather_wsdk_versions(lst)
+ conf.gather_msvc_versions(lst)
+ if eval_and_save:
+ def checked_target(t):
+ target,(arch,paths)=t
+ try:
+ paths.evaluate()
+ except conf.errors.ConfigurationError:
+ return None
+ else:
+ return t
+ lst=[(version,list(filter(checked_target,targets)))for version,targets in lst]
+ conf.env['MSVC_INSTALLED_VERSIONS']=lst
+ return lst
+@conf
+def print_all_msvc_detected(conf):
+ for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:
+ Logs.info(version)
+ for target,l in targets:
+ Logs.info("\t"+target)
+@conf
+def detect_msvc(conf,arch=False):
+ lazy_detect=getattr(Options.options,'msvc_lazy_autodetect',False)or conf.env['MSVC_LAZY_AUTODETECT']
+ versions=get_msvc_versions(conf,not lazy_detect)
+ return setup_msvc(conf,versions,arch)
+@conf
+def find_lt_names_msvc(self,libname,is_static=False):
+ lt_names=['lib%s.la'%libname,'%s.la'%libname,]
+ for path in self.env['LIBPATH']:
+ for la in lt_names:
+ laf=os.path.join(path,la)
+ dll=None
+ if os.path.exists(laf):
+ ltdict=Utils.read_la_file(laf)
+ lt_libdir=None
+ if ltdict.get('libdir',''):
+ lt_libdir=ltdict['libdir']
+ if not is_static and ltdict.get('library_names',''):
+ dllnames=ltdict['library_names'].split()
+ dll=dllnames[0].lower()
+ dll=re.sub('\.dll$','',dll)
+ return(lt_libdir,dll,False)
+ elif ltdict.get('old_library',''):
+ olib=ltdict['old_library']
+ if os.path.exists(os.path.join(path,olib)):
+ return(path,olib,True)
+ elif lt_libdir!=''and os.path.exists(os.path.join(lt_libdir,olib)):
+ return(lt_libdir,olib,True)
+ else:
+ return(None,olib,True)
+ else:
+ raise self.errors.WafError('invalid libtool object file: %s'%laf)
+ return(None,None,None)
+@conf
+def libname_msvc(self,libname,is_static=False):
+ lib=libname.lower()
+ lib=re.sub('\.lib$','',lib)
+ if lib in g_msvc_systemlibs:
+ return lib
+ lib=re.sub('^lib','',lib)
+ if lib=='m':
+ return None
+ (lt_path,lt_libname,lt_static)=self.find_lt_names_msvc(lib,is_static)
+ if lt_path!=None and lt_libname!=None:
+ if lt_static==True:
+ return os.path.join(lt_path,lt_libname)
+ if lt_path!=None:
+ _libpaths=[lt_path]+self.env['LIBPATH']
+ else:
+ _libpaths=self.env['LIBPATH']
+ static_libs=['lib%ss.lib'%lib,'lib%s.lib'%lib,'%ss.lib'%lib,'%s.lib'%lib,]
+ dynamic_libs=['lib%s.dll.lib'%lib,'lib%s.dll.a'%lib,'%s.dll.lib'%lib,'%s.dll.a'%lib,'lib%s_d.lib'%lib,'%s_d.lib'%lib,'%s.lib'%lib,]
+ libnames=static_libs
+ if not is_static:
+ libnames=dynamic_libs+static_libs
+ for path in _libpaths:
+ for libn in libnames:
+ if os.path.exists(os.path.join(path,libn)):
+ debug('msvc: lib found: %s'%os.path.join(path,libn))
+ return re.sub('\.lib$','',libn)
+ self.fatal("The library %r could not be found"%libname)
+ return re.sub('\.lib$','',libname)
+@conf
+def check_lib_msvc(self,libname,is_static=False,uselib_store=None):
+ libn=self.libname_msvc(libname,is_static)
+ if not uselib_store:
+ uselib_store=libname.upper()
+ if False and is_static:
+ self.env['STLIB_'+uselib_store]=[libn]
+ else:
+ self.env['LIB_'+uselib_store]=[libn]
+@conf
+def check_libs_msvc(self,libnames,is_static=False):
+ for libname in Utils.to_list(libnames):
+ self.check_lib_msvc(libname,is_static)
+def configure(conf):
+ conf.autodetect(True)
+ conf.find_msvc()
+ conf.msvc_common_flags()
+ conf.cc_load_tools()
+ conf.cxx_load_tools()
+ conf.cc_add_flags()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
+ conf.visual_studio_add_flags()
+@conf
+def no_autodetect(conf):
+ conf.env.NO_MSVC_DETECT=1
+ configure(conf)
+@conf
+def autodetect(conf,arch=False):
+ v=conf.env
+ if v.NO_MSVC_DETECT:
+ return
+ if arch:
+ compiler,version,path,includes,libdirs,arch=conf.detect_msvc(True)
+ v['DEST_CPU']=arch
+ else:
+ compiler,version,path,includes,libdirs=conf.detect_msvc()
+ v['PATH']=path
+ v['INCLUDES']=includes
+ v['LIBPATH']=libdirs
+ v['MSVC_COMPILER']=compiler
+ try:
+ v['MSVC_VERSION']=float(version)
+ except Exception:
+ v['MSVC_VERSION']=float(version[:-3])
+def _get_prog_names(conf,compiler):
+ if compiler=='intel':
+ compiler_name='ICL'
+ linker_name='XILINK'
+ lib_name='XILIB'
+ else:
+ compiler_name='CL'
+ linker_name='LINK'
+ lib_name='LIB'
+ return compiler_name,linker_name,lib_name
+@conf
+def find_msvc(conf):
+ if sys.platform=='cygwin':
+ conf.fatal('MSVC module does not work under cygwin Python!')
+ v=conf.env
+ path=v['PATH']
+ compiler=v['MSVC_COMPILER']
+ version=v['MSVC_VERSION']
+ compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
+ v.MSVC_MANIFEST=(compiler=='msvc'and version>=8)or(compiler=='wsdk'and version>=6)or(compiler=='intel'and version>=11)
+ cxx=conf.find_program(compiler_name,var='CXX',path_list=path)
+ env=dict(conf.environ)
+ if path:env.update(PATH=';'.join(path))
+ if not conf.cmd_and_log(cxx+['/nologo','/help'],env=env):
+ conf.fatal('the msvc compiler could not be identified')
+ v['CC']=v['CXX']=cxx
+ v['CC_NAME']=v['CXX_NAME']='msvc'
+ if not v['LINK_CXX']:
+ link=conf.find_program(linker_name,path_list=path)
+ if link:v['LINK_CXX']=link
+ else:conf.fatal('%s was not found (linker)'%linker_name)
+ v['LINK']=link
+ if not v['LINK_CC']:
+ v['LINK_CC']=v['LINK_CXX']
+ if not v['AR']:
+ stliblink=conf.find_program(lib_name,path_list=path,var='AR')
+ if not stliblink:return
+ v['ARFLAGS']=['/NOLOGO']
+ if v.MSVC_MANIFEST:
+ conf.find_program('MT',path_list=path,var='MT')
+ v['MTFLAGS']=['/NOLOGO']
+ try:
+ conf.load('winres')
+ except Errors.WafError:
+ warn('Resource compiler not found. Compiling resource file is disabled')
+@conf
+def visual_studio_add_flags(self):
+ v=self.env
+ try:v.prepend_value('INCLUDES',[x for x in self.environ['INCLUDE'].split(';')if x])
+ except Exception:pass
+ try:v.prepend_value('LIBPATH',[x for x in self.environ['LIB'].split(';')if x])
+ except Exception:pass
+@conf
+def msvc_common_flags(conf):
+ v=conf.env
+ v['DEST_BINFMT']='pe'
+ v.append_value('CFLAGS',['/nologo'])
+ v.append_value('CXXFLAGS',['/nologo'])
+ v['DEFINES_ST']='/D%s'
+ v['CC_SRC_F']=''
+ v['CC_TGT_F']=['/c','/Fo']
+ v['CXX_SRC_F']=''
+ v['CXX_TGT_F']=['/c','/Fo']
+ if(v.MSVC_COMPILER=='msvc'and v.MSVC_VERSION>=8)or(v.MSVC_COMPILER=='wsdk'and v.MSVC_VERSION>=6):
+ v['CC_TGT_F']=['/FC']+v['CC_TGT_F']
+ v['CXX_TGT_F']=['/FC']+v['CXX_TGT_F']
+ v['CPPPATH_ST']='/I%s'
+ v['AR_TGT_F']=v['CCLNK_TGT_F']=v['CXXLNK_TGT_F']='/OUT:'
+ v['CFLAGS_CONSOLE']=v['CXXFLAGS_CONSOLE']=['/SUBSYSTEM:CONSOLE']
+ v['CFLAGS_NATIVE']=v['CXXFLAGS_NATIVE']=['/SUBSYSTEM:NATIVE']
+ v['CFLAGS_POSIX']=v['CXXFLAGS_POSIX']=['/SUBSYSTEM:POSIX']
+ v['CFLAGS_WINDOWS']=v['CXXFLAGS_WINDOWS']=['/SUBSYSTEM:WINDOWS']
+ v['CFLAGS_WINDOWSCE']=v['CXXFLAGS_WINDOWSCE']=['/SUBSYSTEM:WINDOWSCE']
+ v['CFLAGS_CRT_MULTITHREADED']=v['CXXFLAGS_CRT_MULTITHREADED']=['/MT']
+ v['CFLAGS_CRT_MULTITHREADED_DLL']=v['CXXFLAGS_CRT_MULTITHREADED_DLL']=['/MD']
+ v['CFLAGS_CRT_MULTITHREADED_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DBG']=['/MTd']
+ v['CFLAGS_CRT_MULTITHREADED_DLL_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG']=['/MDd']
+ v['LIB_ST']='%s.lib'
+ v['LIBPATH_ST']='/LIBPATH:%s'
+ v['STLIB_ST']='%s.lib'
+ v['STLIBPATH_ST']='/LIBPATH:%s'
+ v.append_value('LINKFLAGS',['/NOLOGO'])
+ if v['MSVC_MANIFEST']:
+ v.append_value('LINKFLAGS',['/MANIFEST'])
+ v['CFLAGS_cshlib']=[]
+ v['CXXFLAGS_cxxshlib']=[]
+ v['LINKFLAGS_cshlib']=v['LINKFLAGS_cxxshlib']=['/DLL']
+ v['cshlib_PATTERN']=v['cxxshlib_PATTERN']='%s.dll'
+ v['implib_PATTERN']='%s.lib'
+ v['IMPLIB_ST']='/IMPLIB:%s'
+ v['LINKFLAGS_cstlib']=[]
+ v['cstlib_PATTERN']=v['cxxstlib_PATTERN']='%s.lib'
+ v['cprogram_PATTERN']=v['cxxprogram_PATTERN']='%s.exe'
+@after_method('apply_link')
+@feature('c','cxx')
+def apply_flags_msvc(self):
+ if self.env.CC_NAME!='msvc'or not getattr(self,'link_task',None):
+ return
+ is_static=isinstance(self.link_task,ccroot.stlink_task)
+ subsystem=getattr(self,'subsystem','')
+ if subsystem:
+ subsystem='/subsystem:%s'%subsystem
+ flags=is_static and'ARFLAGS'or'LINKFLAGS'
+ self.env.append_value(flags,subsystem)
+ if not is_static:
+ for f in self.env.LINKFLAGS:
+ d=f.lower()
+ if d[1:]=='debug':
+ pdbnode=self.link_task.outputs[0].change_ext('.pdb')
+ self.link_task.outputs.append(pdbnode)
+ if getattr(self,'install_task',None):
+ self.pdb_install_task=self.bld.install_files(self.install_task.dest,pdbnode,env=self.env)
+ break
+@feature('cprogram','cshlib','cxxprogram','cxxshlib')
+@after_method('apply_link')
+def apply_manifest(self):
+ if self.env.CC_NAME=='msvc'and self.env.MSVC_MANIFEST and getattr(self,'link_task',None):
+ out_node=self.link_task.outputs[0]
+ man_node=out_node.parent.find_or_declare(out_node.name+'.manifest')
+ self.link_task.outputs.append(man_node)
+ self.link_task.do_manifest=True
+def exec_mf(self):
+ env=self.env
+ mtool=env['MT']
+ if not mtool:
+ return 0
+ self.do_manifest=False
+ outfile=self.outputs[0].abspath()
+ manifest=None
+ for out_node in self.outputs:
+ if out_node.name.endswith('.manifest'):
+ manifest=out_node.abspath()
+ break
+ if manifest is None:
+ return 0
+ mode=''
+ if'cprogram'in self.generator.features or'cxxprogram'in self.generator.features:
+ mode='1'
+ elif'cshlib'in self.generator.features or'cxxshlib'in self.generator.features:
+ mode='2'
+ debug('msvc: embedding manifest in mode %r'%mode)
+ lst=[]+mtool
+ lst.extend(Utils.to_list(env['MTFLAGS']))
+ lst.extend(['-manifest',manifest])
+ lst.append('-outputresource:%s;%s'%(outfile,mode))
+ return self.exec_command(lst)
+def quote_response_command(self,flag):
+ if flag.find(' ')>-1:
+ for x in('/LIBPATH:','/IMPLIB:','/OUT:','/I'):
+ if flag.startswith(x):
+ flag='%s"%s"'%(x,flag[len(x):])
+ break
+ else:
+ flag='"%s"'%flag
+ return flag
+def exec_response_command(self,cmd,**kw):
+ try:
+ tmp=None
+ if sys.platform.startswith('win')and isinstance(cmd,list)and len(' '.join(cmd))>=8192:
+ program=cmd[0]
+ cmd=[self.quote_response_command(x)for x in cmd]
+ (fd,tmp)=tempfile.mkstemp()
+ os.write(fd,'\r\n'.join(i.replace('\\','\\\\')for i in cmd[1:]))
+ os.close(fd)
+ cmd=[program,'@'+tmp]
+ ret=self.generator.bld.exec_command(cmd,**kw)
+ finally:
+ if tmp:
+ try:
+ os.remove(tmp)
+ except OSError:
+ pass
+ return ret
+def exec_command_msvc(self,*k,**kw):
+ if isinstance(k[0],list):
+ lst=[]
+ carry=''
+ for a in k[0]:
+ if a=='/Fo'or a=='/doc'or a[-1]==':':
+ carry=a
+ else:
+ lst.append(carry+a)
+ carry=''
+ k=[lst]
+ if self.env['PATH']:
+ env=dict(self.env.env or os.environ)
+ env.update(PATH=';'.join(self.env['PATH']))
+ kw['env']=env
+ bld=self.generator.bld
+ try:
+ if not kw.get('cwd',None):
+ kw['cwd']=bld.cwd
+ except AttributeError:
+ bld.cwd=kw['cwd']=bld.variant_dir
+ ret=self.exec_response_command(k[0],**kw)
+ if not ret and getattr(self,'do_manifest',None):
+ ret=self.exec_mf()
+ return ret
+def wrap_class(class_name):
+ cls=Task.classes.get(class_name,None)
+ if not cls:
+ return None
+ derived_class=type(class_name,(cls,),{})
+ def exec_command(self,*k,**kw):
+ if self.env['CC_NAME']=='msvc':
+ return self.exec_command_msvc(*k,**kw)
+ else:
+ return super(derived_class,self).exec_command(*k,**kw)
+ derived_class.exec_command=exec_command
+ derived_class.exec_response_command=exec_response_command
+ derived_class.quote_response_command=quote_response_command
+ derived_class.exec_command_msvc=exec_command_msvc
+ derived_class.exec_mf=exec_mf
+ if hasattr(cls,'hcode'):
+ derived_class.hcode=cls.hcode
+ return derived_class
+for k in'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():
+ wrap_class(k)
+def make_winapp(self,family):
+ append=self.env.append_unique
+ append('DEFINES','WINAPI_FAMILY=%s'%family)
+ append('CXXFLAGS','/ZW')
+ append('CXXFLAGS','/TP')
+ for lib_path in self.env.LIBPATH:
+ append('CXXFLAGS','/AI%s'%lib_path)
+@feature('winphoneapp')
+@after_method('process_use')
+@after_method('propagate_uselib_vars')
+def make_winphone_app(self):
+ make_winapp(self,'WINAPI_FAMILY_PHONE_APP')
+ conf.env.append_unique('LINKFLAGS','/NODEFAULTLIB:ole32.lib')
+ conf.env.append_unique('LINKFLAGS','PhoneAppModelHost.lib')
+@feature('winapp')
+@after_method('process_use')
+@after_method('propagate_uselib_vars')
+def make_windows_app(self):
+ make_winapp(self,'WINAPI_FAMILY_DESKTOP_APP')
diff --git a/waflib/Tools/nasm.py b/waflib/Tools/nasm.py
new file mode 100644
index 0000000..a107298
--- /dev/null
+++ b/waflib/Tools/nasm.py
@@ -0,0 +1,16 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+import waflib.Tools.asm
+from waflib.TaskGen import feature
+@feature('asm')
+def apply_nasm_vars(self):
+ self.env.append_value('ASFLAGS',self.to_list(getattr(self,'nasm_flags',[])))
+def configure(conf):
+ conf.find_program(['nasm','yasm'],var='AS')
+ conf.env.AS_TGT_F=['-o']
+ conf.env.ASLNK_TGT_F=['-o']
+ conf.load('asm')
+ conf.env.ASMPATH_ST='-I%s'+os.sep
diff --git a/waflib/Tools/perl.py b/waflib/Tools/perl.py
new file mode 100644
index 0000000..47506d8
--- /dev/null
+++ b/waflib/Tools/perl.py
@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+from waflib import Task,Options,Utils
+from waflib.Configure import conf
+from waflib.TaskGen import extension,feature,before_method
+@before_method('apply_incpaths','apply_link','propagate_uselib_vars')
+@feature('perlext')
+def init_perlext(self):
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ if not'PERLEXT'in self.uselib:self.uselib.append('PERLEXT')
+ self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['perlext_PATTERN']
+@extension('.xs')
+def xsubpp_file(self,node):
+ outnode=node.change_ext('.c')
+ self.create_task('xsubpp',node,outnode)
+ self.source.append(outnode)
+class xsubpp(Task.Task):
+ run_str='${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}'
+ color='BLUE'
+ ext_out=['.h']
+@conf
+def check_perl_version(self,minver=None):
+ res=True
+ if minver:
+ cver='.'.join(map(str,minver))
+ else:
+ cver=''
+ self.start_msg('Checking for minimum perl version %s'%cver)
+ perl=Utils.to_list(getattr(Options.options,'perlbinary',None))
+ if not perl:
+ perl=self.find_program('perl',var='PERL')
+ if not perl:
+ self.end_msg("Perl not found",color="YELLOW")
+ return False
+ self.env['PERL']=perl
+ version=self.cmd_and_log(self.env.PERL+["-e",'printf \"%vd\", $^V'])
+ if not version:
+ res=False
+ version="Unknown"
+ elif not minver is None:
+ ver=tuple(map(int,version.split(".")))
+ if ver<minver:
+ res=False
+ self.end_msg(version,color=res and"GREEN"or"YELLOW")
+ return res
+@conf
+def check_perl_module(self,module):
+ cmd=self.env.PERL+['-e','use %s'%module]
+ self.start_msg('perl module %s'%module)
+ try:
+ r=self.cmd_and_log(cmd)
+ except Exception:
+ self.end_msg(False)
+ return None
+ self.end_msg(r or True)
+ return r
+@conf
+def check_perl_ext_devel(self):
+ env=self.env
+ perl=env.PERL
+ if not perl:
+ self.fatal('find perl first')
+ def cmd_perl_config(s):
+ return perl+['-MConfig','-e','print \"%s\"'%s]
+ def cfg_str(cfg):
+ return self.cmd_and_log(cmd_perl_config(cfg))
+ def cfg_lst(cfg):
+ return Utils.to_list(cfg_str(cfg))
+ def find_xsubpp():
+ for var in('privlib','vendorlib'):
+ xsubpp=cfg_lst('$Config{%s}/ExtUtils/xsubpp$Config{exe_ext}'%var)
+ if xsubpp and os.path.isfile(xsubpp[0]):
+ return xsubpp
+ return self.find_program('xsubpp')
+ env['LINKFLAGS_PERLEXT']=cfg_lst('$Config{lddlflags}')
+ env['INCLUDES_PERLEXT']=cfg_lst('$Config{archlib}/CORE')
+ env['CFLAGS_PERLEXT']=cfg_lst('$Config{ccflags} $Config{cccdlflags}')
+ env['EXTUTILS_TYPEMAP']=cfg_lst('$Config{privlib}/ExtUtils/typemap')
+ env['XSUBPP']=find_xsubpp()
+ if not getattr(Options.options,'perlarchdir',None):
+ env['ARCHDIR_PERL']=cfg_str('$Config{sitearch}')
+ else:
+ env['ARCHDIR_PERL']=getattr(Options.options,'perlarchdir')
+ env['perlext_PATTERN']='%s.'+cfg_str('$Config{dlext}')
+def options(opt):
+ opt.add_option('--with-perl-binary',type='string',dest='perlbinary',help='Specify alternate perl binary',default=None)
+ opt.add_option('--with-perl-archdir',type='string',dest='perlarchdir',help='Specify directory where to install arch specific files',default=None)
diff --git a/waflib/Tools/python.py b/waflib/Tools/python.py
new file mode 100644
index 0000000..17c054e
--- /dev/null
+++ b/waflib/Tools/python.py
@@ -0,0 +1,399 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,sys
+from waflib import Utils,Options,Errors,Logs,Task,Node
+from waflib.TaskGen import extension,before_method,after_method,feature
+from waflib.Configure import conf
+FRAG='''
+#include <Python.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void Py_Initialize(void);
+ void Py_Finalize(void);
+#ifdef __cplusplus
+}
+#endif
+int main(int argc, char **argv)
+{
+ (void)argc; (void)argv;
+ Py_Initialize();
+ Py_Finalize();
+ return 0;
+}
+'''
+INST='''
+import sys, py_compile
+py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3], True)
+'''
+DISTUTILS_IMP=['from distutils.sysconfig import get_config_var, get_python_lib']
+@before_method('process_source')
+@feature('py')
+def feature_py(self):
+ self.install_path=getattr(self,'install_path','${PYTHONDIR}')
+ install_from=getattr(self,'install_from',None)
+ if install_from and not isinstance(install_from,Node.Node):
+ install_from=self.path.find_dir(install_from)
+ self.install_from=install_from
+ ver=self.env.PYTHON_VERSION
+ if not ver:
+ self.bld.fatal('Installing python files requires PYTHON_VERSION, try conf.check_python_version')
+ if int(ver.replace('.',''))>31:
+ self.install_32=True
+@extension('.py')
+def process_py(self,node):
+ assert(getattr(self,'install_path')),'add features="py"'
+ if self.install_path:
+ if self.install_from:
+ self.bld.install_files(self.install_path,[node],cwd=self.install_from,relative_trick=True)
+ else:
+ self.bld.install_files(self.install_path,[node],relative_trick=True)
+ lst=[]
+ if self.env.PYC:
+ lst.append('pyc')
+ if self.env.PYO:
+ lst.append('pyo')
+ if self.install_path:
+ if self.install_from:
+ pyd=Utils.subst_vars("%s/%s"%(self.install_path,node.path_from(self.install_from)),self.env)
+ else:
+ pyd=Utils.subst_vars("%s/%s"%(self.install_path,node.path_from(self.path)),self.env)
+ else:
+ pyd=node.abspath()
+ for ext in lst:
+ if self.env.PYTAG:
+ name=node.name[:-3]
+ pyobj=node.parent.get_bld().make_node('__pycache__').make_node("%s.%s.%s"%(name,self.env.PYTAG,ext))
+ pyobj.parent.mkdir()
+ else:
+ pyobj=node.change_ext(".%s"%ext)
+ tsk=self.create_task(ext,node,pyobj)
+ tsk.pyd=pyd
+ if self.install_path:
+ self.bld.install_files(os.path.dirname(pyd),pyobj,cwd=node.parent.get_bld(),relative_trick=True)
+class pyc(Task.Task):
+ color='PINK'
+ def run(self):
+ cmd=[Utils.subst_vars('${PYTHON}',self.env),'-c',INST,self.inputs[0].abspath(),self.outputs[0].abspath(),self.pyd]
+ ret=self.generator.bld.exec_command(cmd)
+ return ret
+class pyo(Task.Task):
+ color='PINK'
+ def run(self):
+ cmd=[Utils.subst_vars('${PYTHON}',self.env),Utils.subst_vars('${PYFLAGS_OPT}',self.env),'-c',INST,self.inputs[0].abspath(),self.outputs[0].abspath(),self.pyd]
+ ret=self.generator.bld.exec_command(cmd)
+ return ret
+@feature('pyext')
+@before_method('propagate_uselib_vars','apply_link')
+@after_method('apply_bundle')
+def init_pyext(self):
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ if not'PYEXT'in self.uselib:
+ self.uselib.append('PYEXT')
+ self.env.cshlib_PATTERN=self.env.cxxshlib_PATTERN=self.env.macbundle_PATTERN=self.env.pyext_PATTERN
+ self.env.fcshlib_PATTERN=self.env.dshlib_PATTERN=self.env.pyext_PATTERN
+ try:
+ if not self.install_path:
+ return
+ except AttributeError:
+ self.install_path='${PYTHONARCHDIR}'
+@feature('pyext')
+@before_method('apply_link','apply_bundle')
+def set_bundle(self):
+ if Utils.unversioned_sys_platform()=='darwin':
+ self.mac_bundle=True
+@before_method('propagate_uselib_vars')
+@feature('pyembed')
+def init_pyembed(self):
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ if not'PYEMBED'in self.uselib:
+ self.uselib.append('PYEMBED')
+@conf
+def get_python_variables(self,variables,imports=None):
+ if not imports:
+ try:
+ imports=self.python_imports
+ except AttributeError:
+ imports=DISTUTILS_IMP
+ program=list(imports)
+ program.append('')
+ for v in variables:
+ program.append("print(repr(%s))"%v)
+ os_env=dict(os.environ)
+ try:
+ del os_env['MACOSX_DEPLOYMENT_TARGET']
+ except KeyError:
+ pass
+ try:
+ out=self.cmd_and_log(self.env.PYTHON+['-c','\n'.join(program)],env=os_env)
+ except Errors.WafError:
+ self.fatal('The distutils module is unusable: install "python-devel"?')
+ self.to_log(out)
+ return_values=[]
+ for s in out.splitlines():
+ s=s.strip()
+ if not s:
+ continue
+ if s=='None':
+ return_values.append(None)
+ elif(s[0]=="'"and s[-1]=="'")or(s[0]=='"'and s[-1]=='"'):
+ return_values.append(eval(s))
+ elif s[0].isdigit():
+ return_values.append(int(s))
+ else:break
+ return return_values
+@conf
+def test_pyembed(self,mode,msg='Testing pyembed configuration'):
+ self.check(header_name='Python.h',define_name='HAVE_PYEMBED',msg=msg,fragment=FRAG,errmsg='Could not build a python embedded interpreter',features='%s %sprogram pyembed'%(mode,mode))
+@conf
+def test_pyext(self,mode,msg='Testing pyext configuration'):
+ self.check(header_name='Python.h',define_name='HAVE_PYEXT',msg=msg,fragment=FRAG,errmsg='Could not build python extensions',features='%s %sshlib pyext'%(mode,mode))
+@conf
+def python_cross_compile(self,features='pyembed pyext'):
+ features=Utils.to_list(features)
+ if not('PYTHON_LDFLAGS'in self.environ or'PYTHON_PYEXT_LDFLAGS'in self.environ or'PYTHON_PYEMBED_LDFLAGS'in self.environ):
+ return False
+ for x in'PYTHON_VERSION PYTAG pyext_PATTERN'.split():
+ if not x in self.environ:
+ self.fatal('Please set %s in the os environment'%x)
+ else:
+ self.env[x]=self.environ[x]
+ xx=self.env.CXX_NAME and'cxx'or'c'
+ if'pyext'in features:
+ flags=self.environ.get('PYTHON_PYEXT_LDFLAGS',self.environ.get('PYTHON_LDFLAGS',None))
+ if flags is None:
+ self.fatal('No flags provided through PYTHON_PYEXT_LDFLAGS as required')
+ else:
+ self.parse_flags(flags,'PYEXT')
+ self.test_pyext(xx)
+ if'pyembed'in features:
+ flags=self.environ.get('PYTHON_PYEMBED_LDFLAGS',self.environ.get('PYTHON_LDFLAGS',None))
+ if flags is None:
+ self.fatal('No flags provided through PYTHON_PYEMBED_LDFLAGS as required')
+ else:
+ self.parse_flags(flags,'PYEMBED')
+ self.test_pyembed(xx)
+ return True
+@conf
+def check_python_headers(conf,features='pyembed pyext'):
+ features=Utils.to_list(features)
+ assert('pyembed'in features)or('pyext'in features),"check_python_headers features must include 'pyembed' and/or 'pyext'"
+ env=conf.env
+ if not env['CC_NAME']and not env['CXX_NAME']:
+ conf.fatal('load a compiler first (gcc, g++, ..)')
+ if conf.python_cross_compile(features):
+ return
+ if not env['PYTHON_VERSION']:
+ conf.check_python_version()
+ pybin=env.PYTHON
+ if not pybin:
+ conf.fatal('Could not find the python executable')
+ v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split()
+ try:
+ lst=conf.get_python_variables(["get_config_var('%s') or ''"%x for x in v])
+ except RuntimeError:
+ conf.fatal("Python development headers not found (-v for details).")
+ vals=['%s = %r'%(x,y)for(x,y)in zip(v,lst)]
+ conf.to_log("Configuration returned from %r:\n%s\n"%(pybin,'\n'.join(vals)))
+ dct=dict(zip(v,lst))
+ x='MACOSX_DEPLOYMENT_TARGET'
+ if dct[x]:
+ env[x]=conf.environ[x]=dct[x]
+ env['pyext_PATTERN']='%s'+dct['SO']
+ num='.'.join(env['PYTHON_VERSION'].split('.')[:2])
+ conf.find_program([''.join(pybin)+'-config','python%s-config'%num,'python-config-%s'%num,'python%sm-config'%num],var='PYTHON_CONFIG',msg="python-config",mandatory=False)
+ if env.PYTHON_CONFIG:
+ all_flags=[['--cflags','--libs','--ldflags']]
+ if sys.hexversion<0x2070000:
+ all_flags=[[k]for k in all_flags[0]]
+ xx=env.CXX_NAME and'cxx'or'c'
+ if'pyembed'in features:
+ for flags in all_flags:
+ conf.check_cfg(msg='Asking python-config for pyembed %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=flags)
+ try:
+ conf.test_pyembed(xx)
+ except conf.errors.ConfigurationError:
+ if dct['Py_ENABLE_SHARED']and dct['LIBDIR']:
+ env.append_unique('LIBPATH_PYEMBED',[dct['LIBDIR']])
+ conf.test_pyembed(xx)
+ else:
+ raise
+ if'pyext'in features:
+ for flags in all_flags:
+ conf.check_cfg(msg='Asking python-config for pyext %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEXT',args=flags)
+ try:
+ conf.test_pyext(xx)
+ except conf.errors.ConfigurationError:
+ if dct['Py_ENABLE_SHARED']and dct['LIBDIR']:
+ env.append_unique('LIBPATH_PYEXT',[dct['LIBDIR']])
+ conf.test_pyext(xx)
+ else:
+ raise
+ conf.define('HAVE_PYTHON_H',1)
+ return
+ all_flags=dct['LDFLAGS']+' '+dct['CFLAGS']
+ conf.parse_flags(all_flags,'PYEMBED')
+ all_flags=dct['LDFLAGS']+' '+dct['LDSHARED']+' '+dct['CFLAGS']
+ conf.parse_flags(all_flags,'PYEXT')
+ result=None
+ if not dct["LDVERSION"]:
+ dct["LDVERSION"]=env['PYTHON_VERSION']
+ for name in('python'+dct['LDVERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')):
+ if not result and env['LIBPATH_PYEMBED']:
+ path=env['LIBPATH_PYEMBED']
+ conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path)
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBPATH_PYEMBED'%name)
+ if not result and dct['LIBDIR']:
+ path=[dct['LIBDIR']]
+ conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n"%path)
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBDIR'%name)
+ if not result and dct['LIBPL']:
+ path=[dct['LIBPL']]
+ conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in python_LIBPL'%name)
+ if not result:
+ path=[os.path.join(dct['prefix'],"libs")]
+ conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
+ result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in $prefix/libs'%name)
+ if result:
+ break
+ if result:
+ env['LIBPATH_PYEMBED']=path
+ env.append_value('LIB_PYEMBED',[name])
+ else:
+ conf.to_log("\n\n### LIB NOT FOUND\n")
+ if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
+ env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED']
+ env['LIB_PYEXT']=env['LIB_PYEMBED']
+ conf.to_log("Include path for Python extensions (found via distutils module): %r\n"%(dct['INCLUDEPY'],))
+ env['INCLUDES_PYEXT']=[dct['INCLUDEPY']]
+ env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']]
+ if env['CC_NAME']=='gcc':
+ env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing'])
+ env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing'])
+ if env['CXX_NAME']=='gcc':
+ env.append_value('CXXFLAGS_PYEMBED',['-fno-strict-aliasing'])
+ env.append_value('CXXFLAGS_PYEXT',['-fno-strict-aliasing'])
+ if env.CC_NAME=="msvc":
+ from distutils.msvccompiler import MSVCCompiler
+ dist_compiler=MSVCCompiler()
+ dist_compiler.initialize()
+ env.append_value('CFLAGS_PYEXT',dist_compiler.compile_options)
+ env.append_value('CXXFLAGS_PYEXT',dist_compiler.compile_options)
+ env.append_value('LINKFLAGS_PYEXT',dist_compiler.ldflags_shared)
+ conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg='Distutils not installed? Broken python installation? Get python-config now!')
+@conf
+def check_python_version(conf,minver=None):
+ assert minver is None or isinstance(minver,tuple)
+ pybin=conf.env['PYTHON']
+ if not pybin:
+ conf.fatal('could not find the python executable')
+ cmd=pybin+['-c','import sys\nfor x in sys.version_info: print(str(x))']
+ Logs.debug('python: Running python command %r'%cmd)
+ lines=conf.cmd_and_log(cmd).split()
+ assert len(lines)==5,"found %i lines, expected 5: %r"%(len(lines),lines)
+ pyver_tuple=(int(lines[0]),int(lines[1]),int(lines[2]),lines[3],int(lines[4]))
+ result=(minver is None)or(pyver_tuple>=minver)
+ if result:
+ pyver='.'.join([str(x)for x in pyver_tuple[:2]])
+ conf.env['PYTHON_VERSION']=pyver
+ if'PYTHONDIR'in conf.env:
+ pydir=conf.env['PYTHONDIR']
+ elif'PYTHONDIR'in conf.environ:
+ pydir=conf.environ['PYTHONDIR']
+ else:
+ if Utils.is_win32:
+ (python_LIBDEST,pydir)=conf.get_python_variables(["get_config_var('LIBDEST') or ''","get_python_lib(standard_lib=0) or ''"])
+ else:
+ python_LIBDEST=None
+ (pydir,)=conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''"%conf.env.PREFIX])
+ if python_LIBDEST is None:
+ if conf.env['LIBDIR']:
+ python_LIBDEST=os.path.join(conf.env['LIBDIR'],"python"+pyver)
+ else:
+ python_LIBDEST=os.path.join(conf.env['PREFIX'],"lib","python"+pyver)
+ if'PYTHONARCHDIR'in conf.env:
+ pyarchdir=conf.env['PYTHONARCHDIR']
+ elif'PYTHONARCHDIR'in conf.environ:
+ pyarchdir=conf.environ['PYTHONARCHDIR']
+ else:
+ (pyarchdir,)=conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''"%conf.env.PREFIX])
+ if not pyarchdir:
+ pyarchdir=pydir
+ if hasattr(conf,'define'):
+ conf.define('PYTHONDIR',pydir)
+ conf.define('PYTHONARCHDIR',pyarchdir)
+ conf.env['PYTHONDIR']=pydir
+ conf.env['PYTHONARCHDIR']=pyarchdir
+ pyver_full='.'.join(map(str,pyver_tuple[:3]))
+ if minver is None:
+ conf.msg('Checking for python version',pyver_full)
+ else:
+ minver_str='.'.join(map(str,minver))
+ conf.msg('Checking for python version >= %s'%(minver_str,),pyver_full,color=result and'GREEN'or'YELLOW')
+ if not result:
+ conf.fatal('The python version is too old, expecting %r'%(minver,))
+PYTHON_MODULE_TEMPLATE='''
+import %s as current_module
+version = getattr(current_module, '__version__', None)
+if version is not None:
+ print(str(version))
+else:
+ print('unknown version')
+'''
+@conf
+def check_python_module(conf,module_name,condition=''):
+ msg="Checking for python module '%s'"%module_name
+ if condition:
+ msg='%s (%s)'%(msg,condition)
+ conf.start_msg(msg)
+ try:
+ ret=conf.cmd_and_log(conf.env['PYTHON']+['-c',PYTHON_MODULE_TEMPLATE%module_name])
+ except Exception:
+ conf.end_msg(False)
+ conf.fatal('Could not find the python module %r'%module_name)
+ ret=ret.strip()
+ if condition:
+ conf.end_msg(ret)
+ if ret=='unknown version':
+ conf.fatal('Could not check the %s version'%module_name)
+ from distutils.version import LooseVersion
+ def num(*k):
+ if isinstance(k[0],int):
+ return LooseVersion('.'.join([str(x)for x in k]))
+ else:
+ return LooseVersion(k[0])
+ d={'num':num,'ver':LooseVersion(ret)}
+ ev=eval(condition,{},d)
+ if not ev:
+ conf.fatal('The %s version does not satisfy the requirements'%module_name)
+ else:
+ if ret=='unknown version':
+ conf.end_msg(True)
+ else:
+ conf.end_msg(ret)
+def configure(conf):
+ v=conf.env
+ v['PYTHON']=Options.options.python or os.environ.get('PYTHON',sys.executable)
+ if Options.options.pythondir:
+ v['PYTHONDIR']=Options.options.pythondir
+ if Options.options.pythonarchdir:
+ v['PYTHONARCHDIR']=Options.options.pythonarchdir
+ conf.find_program('python',var='PYTHON')
+ v['PYFLAGS']=''
+ v['PYFLAGS_OPT']='-O'
+ v['PYC']=getattr(Options.options,'pyc',1)
+ v['PYO']=getattr(Options.options,'pyo',1)
+ try:
+ v.PYTAG=conf.cmd_and_log(conf.env.PYTHON+['-c',"import imp;print(imp.get_tag())"]).strip()
+ except Errors.WafError:
+ pass
+def options(opt):
+ pyopt=opt.add_option_group("Python Options")
+ pyopt.add_option('--nopyc',dest='pyc',action='store_false',default=1,help='Do not install bytecode compiled .pyc files (configuration) [Default:install]')
+ pyopt.add_option('--nopyo',dest='pyo',action='store_false',default=1,help='Do not install optimised compiled .pyo files (configuration) [Default:install]')
+ pyopt.add_option('--python',dest="python",help='python binary to be used [Default: %s]'%sys.executable)
+ pyopt.add_option('--pythondir',dest='pythondir',help='Installation path for python modules (py, platform-independent .py and .pyc files)')
+ pyopt.add_option('--pythonarchdir',dest='pythonarchdir',help='Installation path for python extension (pyext, platform-dependent .so or .dylib files)')
diff --git a/waflib/Tools/qt4.py b/waflib/Tools/qt4.py
new file mode 100644
index 0000000..896c5b4
--- /dev/null
+++ b/waflib/Tools/qt4.py
@@ -0,0 +1,442 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+try:
+ from xml.sax import make_parser
+ from xml.sax.handler import ContentHandler
+except ImportError:
+ has_xml=False
+ ContentHandler=object
+else:
+ has_xml=True
+import os,sys
+from waflib.Tools import cxx
+from waflib import Task,Utils,Options,Errors,Context
+from waflib.TaskGen import feature,after_method,extension
+from waflib.Configure import conf
+from waflib import Logs
+MOC_H=['.h','.hpp','.hxx','.hh']
+EXT_RCC=['.qrc']
+EXT_UI=['.ui']
+EXT_QT4=['.cpp','.cc','.cxx','.C']
+QT4_LIBS="QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative QtDesigner"
+class qxx(Task.classes['cxx']):
+ def __init__(self,*k,**kw):
+ Task.Task.__init__(self,*k,**kw)
+ self.moc_done=0
+ def runnable_status(self):
+ if self.moc_done:
+ return Task.Task.runnable_status(self)
+ else:
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ self.add_moc_tasks()
+ return Task.Task.runnable_status(self)
+ def create_moc_task(self,h_node,m_node):
+ try:
+ moc_cache=self.generator.bld.moc_cache
+ except AttributeError:
+ moc_cache=self.generator.bld.moc_cache={}
+ try:
+ return moc_cache[h_node]
+ except KeyError:
+ tsk=moc_cache[h_node]=Task.classes['moc'](env=self.env,generator=self.generator)
+ tsk.set_inputs(h_node)
+ tsk.set_outputs(m_node)
+ if self.generator:
+ self.generator.tasks.append(tsk)
+ gen=self.generator.bld.producer
+ gen.outstanding.insert(0,tsk)
+ gen.total+=1
+ return tsk
+ def moc_h_ext(self):
+ ext=[]
+ try:
+ ext=Options.options.qt_header_ext.split()
+ except AttributeError:
+ pass
+ if not ext:
+ ext=MOC_H
+ return ext
+ def add_moc_tasks(self):
+ node=self.inputs[0]
+ bld=self.generator.bld
+ try:
+ self.signature()
+ except KeyError:
+ pass
+ else:
+ delattr(self,'cache_sig')
+ include_nodes=[node.parent]+self.generator.includes_nodes
+ moctasks=[]
+ mocfiles=set([])
+ for d in bld.raw_deps.get(self.uid(),[]):
+ if not d.endswith('.moc'):
+ continue
+ if d in mocfiles:
+ continue
+ mocfiles.add(d)
+ h_node=None
+ base2=d[:-4]
+ for x in include_nodes:
+ for e in self.moc_h_ext():
+ h_node=x.find_node(base2+e)
+ if h_node:
+ break
+ if h_node:
+ m_node=h_node.change_ext('.moc')
+ break
+ else:
+ for k in EXT_QT4:
+ if base2.endswith(k):
+ for x in include_nodes:
+ h_node=x.find_node(base2)
+ if h_node:
+ break
+ if h_node:
+ m_node=h_node.change_ext(k+'.moc')
+ break
+ if not h_node:
+ raise Errors.WafError('No source found for %r which is a moc file'%d)
+ task=self.create_moc_task(h_node,m_node)
+ moctasks.append(task)
+ self.run_after.update(set(moctasks))
+ self.moc_done=1
+class trans_update(Task.Task):
+ run_str='${QT_LUPDATE} ${SRC} -ts ${TGT}'
+ color='BLUE'
+Task.update_outputs(trans_update)
+class XMLHandler(ContentHandler):
+ def __init__(self):
+ self.buf=[]
+ self.files=[]
+ def startElement(self,name,attrs):
+ if name=='file':
+ self.buf=[]
+ def endElement(self,name):
+ if name=='file':
+ self.files.append(str(''.join(self.buf)))
+ def characters(self,cars):
+ self.buf.append(cars)
+@extension(*EXT_RCC)
+def create_rcc_task(self,node):
+ rcnode=node.change_ext('_rc.cpp')
+ self.create_task('rcc',node,rcnode)
+ cpptask=self.create_task('cxx',rcnode,rcnode.change_ext('.o'))
+ try:
+ self.compiled_tasks.append(cpptask)
+ except AttributeError:
+ self.compiled_tasks=[cpptask]
+ return cpptask
+@extension(*EXT_UI)
+def create_uic_task(self,node):
+ uictask=self.create_task('ui4',node)
+ uictask.outputs=[self.path.find_or_declare(self.env['ui_PATTERN']%node.name[:-3])]
+@extension('.ts')
+def add_lang(self,node):
+ self.lang=self.to_list(getattr(self,'lang',[]))+[node]
+@feature('qt4')
+@after_method('apply_link')
+def apply_qt4(self):
+ if getattr(self,'lang',None):
+ qmtasks=[]
+ for x in self.to_list(self.lang):
+ if isinstance(x,str):
+ x=self.path.find_resource(x+'.ts')
+ qmtasks.append(self.create_task('ts2qm',x,x.change_ext('.qm')))
+ if getattr(self,'update',None)and Options.options.trans_qt4:
+ cxxnodes=[a.inputs[0]for a in self.compiled_tasks]+[a.inputs[0]for a in self.tasks if getattr(a,'inputs',None)and a.inputs[0].name.endswith('.ui')]
+ for x in qmtasks:
+ self.create_task('trans_update',cxxnodes,x.inputs)
+ if getattr(self,'langname',None):
+ qmnodes=[x.outputs[0]for x in qmtasks]
+ rcnode=self.langname
+ if isinstance(rcnode,str):
+ rcnode=self.path.find_or_declare(rcnode+'.qrc')
+ t=self.create_task('qm2rcc',qmnodes,rcnode)
+ k=create_rcc_task(self,t.outputs[0])
+ self.link_task.inputs.append(k.outputs[0])
+ lst=[]
+ for flag in self.to_list(self.env['CXXFLAGS']):
+ if len(flag)<2:continue
+ f=flag[0:2]
+ if f in('-D','-I','/D','/I'):
+ if(f[0]=='/'):
+ lst.append('-'+flag[1:])
+ else:
+ lst.append(flag)
+ self.env.append_value('MOC_FLAGS',lst)
+@extension(*EXT_QT4)
+def cxx_hook(self,node):
+ return self.create_compiled_task('qxx',node)
+class rcc(Task.Task):
+ color='BLUE'
+ run_str='${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
+ ext_out=['.h']
+ def rcname(self):
+ return os.path.splitext(self.inputs[0].name)[0]
+ def scan(self):
+ if not has_xml:
+ Logs.error('no xml support was found, the rcc dependencies will be incomplete!')
+ return([],[])
+ parser=make_parser()
+ curHandler=XMLHandler()
+ parser.setContentHandler(curHandler)
+ fi=open(self.inputs[0].abspath(),'r')
+ try:
+ parser.parse(fi)
+ finally:
+ fi.close()
+ nodes=[]
+ names=[]
+ root=self.inputs[0].parent
+ for x in curHandler.files:
+ nd=root.find_resource(x)
+ if nd:nodes.append(nd)
+ else:names.append(x)
+ return(nodes,names)
+class moc(Task.Task):
+ color='BLUE'
+ run_str='${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
+ def keyword(self):
+ return"Creating"
+ def __str__(self):
+ return self.outputs[0].path_from(self.generator.bld.launch_node())
+class ui4(Task.Task):
+ color='BLUE'
+ run_str='${QT_UIC} ${SRC} -o ${TGT}'
+ ext_out=['.h']
+class ts2qm(Task.Task):
+ color='BLUE'
+ run_str='${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
+class qm2rcc(Task.Task):
+ color='BLUE'
+ after='ts2qm'
+ def run(self):
+ txt='\n'.join(['<file>%s</file>'%k.path_from(self.outputs[0].parent)for k in self.inputs])
+ code='<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>'%txt
+ self.outputs[0].write(code)
+def configure(self):
+ self.find_qt4_binaries()
+ self.set_qt4_libs_to_check()
+ self.set_qt4_defines()
+ self.find_qt4_libraries()
+ self.add_qt4_rpath()
+ self.simplify_qt4_libs()
+@conf
+def find_qt4_binaries(self):
+ env=self.env
+ opt=Options.options
+ qtdir=getattr(opt,'qtdir','')
+ qtbin=getattr(opt,'qtbin','')
+ paths=[]
+ if qtdir:
+ qtbin=os.path.join(qtdir,'bin')
+ if not qtdir:
+ qtdir=os.environ.get('QT4_ROOT','')
+ qtbin=os.environ.get('QT4_BIN',None)or os.path.join(qtdir,'bin')
+ if qtbin:
+ paths=[qtbin]
+ if not qtdir:
+ paths=os.environ.get('PATH','').split(os.pathsep)
+ paths.append('/usr/share/qt4/bin/')
+ try:
+ lst=Utils.listdir('/usr/local/Trolltech/')
+ except OSError:
+ pass
+ else:
+ if lst:
+ lst.sort()
+ lst.reverse()
+ qtdir='/usr/local/Trolltech/%s/'%lst[0]
+ qtbin=os.path.join(qtdir,'bin')
+ paths.append(qtbin)
+ cand=None
+ prev_ver=['4','0','0']
+ for qmk in('qmake-qt4','qmake4','qmake'):
+ try:
+ qmake=self.find_program(qmk,path_list=paths)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ try:
+ version=self.cmd_and_log(qmake+['-query','QT_VERSION']).strip()
+ except self.errors.WafError:
+ pass
+ else:
+ if version:
+ new_ver=version.split('.')
+ if new_ver>prev_ver:
+ cand=qmake
+ prev_ver=new_ver
+ if cand:
+ self.env.QMAKE=cand
+ else:
+ self.fatal('Could not find qmake for qt4')
+ qtbin=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_BINS']).strip()+os.sep
+ def find_bin(lst,var):
+ if var in env:
+ return
+ for f in lst:
+ try:
+ ret=self.find_program(f,path_list=paths)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ env[var]=ret
+ break
+ find_bin(['uic-qt3','uic3'],'QT_UIC3')
+ find_bin(['uic-qt4','uic'],'QT_UIC')
+ if not env.QT_UIC:
+ self.fatal('cannot find the uic compiler for qt4')
+ self.start_msg('Checking for uic version')
+ uicver=self.cmd_and_log(env.QT_UIC+["-version"],output=Context.BOTH)
+ uicver=''.join(uicver).strip()
+ uicver=uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt','')
+ self.end_msg(uicver)
+ if uicver.find(' 3.')!=-1:
+ self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
+ find_bin(['moc-qt4','moc'],'QT_MOC')
+ find_bin(['rcc-qt4','rcc'],'QT_RCC')
+ find_bin(['lrelease-qt4','lrelease'],'QT_LRELEASE')
+ find_bin(['lupdate-qt4','lupdate'],'QT_LUPDATE')
+ env['UIC3_ST']='%s -o %s'
+ env['UIC_ST']='%s -o %s'
+ env['MOC_ST']='-o'
+ env['ui_PATTERN']='ui_%s.h'
+ env['QT_LRELEASE_FLAGS']=['-silent']
+ env.MOCCPPPATH_ST='-I%s'
+ env.MOCDEFINES_ST='-D%s'
+@conf
+def find_qt4_libraries(self):
+ qtlibs=getattr(Options.options,'qtlibs',None)or os.environ.get("QT4_LIBDIR",None)
+ if not qtlibs:
+ try:
+ qtlibs=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_LIBS']).strip()
+ except Errors.WafError:
+ qtdir=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_PREFIX']).strip()+os.sep
+ qtlibs=os.path.join(qtdir,'lib')
+ self.msg('Found the Qt4 libraries in',qtlibs)
+ qtincludes=os.environ.get("QT4_INCLUDES",None)or self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_HEADERS']).strip()
+ env=self.env
+ if not'PKG_CONFIG_PATH'in os.environ:
+ os.environ['PKG_CONFIG_PATH']='%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib'%(qtlibs,qtlibs)
+ try:
+ if os.environ.get("QT4_XCOMPILE",None):
+ raise self.errors.ConfigurationError()
+ self.check_cfg(atleast_pkgconfig_version='0.1')
+ except self.errors.ConfigurationError:
+ for i in self.qt4_vars:
+ uselib=i.upper()
+ if Utils.unversioned_sys_platform()=="darwin":
+ frameworkName=i+".framework"
+ qtDynamicLib=os.path.join(qtlibs,frameworkName,i)
+ if os.path.exists(qtDynamicLib):
+ env.append_unique('FRAMEWORK_'+uselib,i)
+ self.msg('Checking for %s'%i,qtDynamicLib,'GREEN')
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtlibs,frameworkName,'Headers'))
+ elif env.DEST_OS!="win32":
+ qtDynamicLib=os.path.join(qtlibs,"lib"+i+".so")
+ qtStaticLib=os.path.join(qtlibs,"lib"+i+".a")
+ if os.path.exists(qtDynamicLib):
+ env.append_unique('LIB_'+uselib,i)
+ self.msg('Checking for %s'%i,qtDynamicLib,'GREEN')
+ elif os.path.exists(qtStaticLib):
+ env.append_unique('LIB_'+uselib,i)
+ self.msg('Checking for %s'%i,qtStaticLib,'GREEN')
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i))
+ else:
+ for k in("lib%s.a","lib%s4.a","%s.lib","%s4.lib"):
+ lib=os.path.join(qtlibs,k%i)
+ if os.path.exists(lib):
+ env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')])
+ self.msg('Checking for %s'%i,lib,'GREEN')
+ break
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i))
+ uselib=i.upper()+"_debug"
+ for k in("lib%sd.a","lib%sd4.a","%sd.lib","%sd4.lib"):
+ lib=os.path.join(qtlibs,k%i)
+ if os.path.exists(lib):
+ env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')])
+ self.msg('Checking for %s'%i,lib,'GREEN')
+ break
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i))
+ else:
+ for i in self.qt4_vars_debug+self.qt4_vars:
+ self.check_cfg(package=i,args='--cflags --libs',mandatory=False)
+@conf
+def simplify_qt4_libs(self):
+ env=self.env
+ def process_lib(vars_,coreval):
+ for d in vars_:
+ var=d.upper()
+ if var=='QTCORE':
+ continue
+ value=env['LIBPATH_'+var]
+ if value:
+ core=env[coreval]
+ accu=[]
+ for lib in value:
+ if lib in core:
+ continue
+ accu.append(lib)
+ env['LIBPATH_'+var]=accu
+ process_lib(self.qt4_vars,'LIBPATH_QTCORE')
+ process_lib(self.qt4_vars_debug,'LIBPATH_QTCORE_DEBUG')
+@conf
+def add_qt4_rpath(self):
+ env=self.env
+ if getattr(Options.options,'want_rpath',False):
+ def process_rpath(vars_,coreval):
+ for d in vars_:
+ var=d.upper()
+ value=env['LIBPATH_'+var]
+ if value:
+ core=env[coreval]
+ accu=[]
+ for lib in value:
+ if var!='QTCORE':
+ if lib in core:
+ continue
+ accu.append('-Wl,--rpath='+lib)
+ env['RPATH_'+var]=accu
+ process_rpath(self.qt4_vars,'LIBPATH_QTCORE')
+ process_rpath(self.qt4_vars_debug,'LIBPATH_QTCORE_DEBUG')
+@conf
+def set_qt4_libs_to_check(self):
+ if not hasattr(self,'qt4_vars'):
+ self.qt4_vars=QT4_LIBS
+ self.qt4_vars=Utils.to_list(self.qt4_vars)
+ if not hasattr(self,'qt4_vars_debug'):
+ self.qt4_vars_debug=[a+'_debug'for a in self.qt4_vars]
+ self.qt4_vars_debug=Utils.to_list(self.qt4_vars_debug)
+@conf
+def set_qt4_defines(self):
+ if sys.platform!='win32':
+ return
+ for x in self.qt4_vars:
+ y=x[2:].upper()
+ self.env.append_unique('DEFINES_%s'%x.upper(),'QT_%s_LIB'%y)
+ self.env.append_unique('DEFINES_%s_DEBUG'%x.upper(),'QT_%s_LIB'%y)
+def options(opt):
+ opt.add_option('--want-rpath',action='store_true',default=False,dest='want_rpath',help='enable the rpath for qt libraries')
+ opt.add_option('--header-ext',type='string',default='',help='header extension for moc files',dest='qt_header_ext')
+ for i in'qtdir qtbin qtlibs'.split():
+ opt.add_option('--'+i,type='string',default='',dest=i)
+ opt.add_option('--translate',action="store_true",help="collect translation strings",dest="trans_qt4",default=False)
diff --git a/waflib/Tools/qt5.py b/waflib/Tools/qt5.py
new file mode 100644
index 0000000..f69c79d
--- /dev/null
+++ b/waflib/Tools/qt5.py
@@ -0,0 +1,489 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+try:
+ from xml.sax import make_parser
+ from xml.sax.handler import ContentHandler
+except ImportError:
+ has_xml=False
+ ContentHandler=object
+else:
+ has_xml=True
+import os,sys
+from waflib.Tools import cxx
+from waflib import Task,Utils,Options,Errors,Context
+from waflib.TaskGen import feature,after_method,extension
+from waflib.Configure import conf
+from waflib import Logs
+MOC_H=['.h','.hpp','.hxx','.hh']
+EXT_RCC=['.qrc']
+EXT_UI=['.ui']
+EXT_QT5=['.cpp','.cc','.cxx','.C']
+QT5_LIBS='''
+qtmain
+Qt5Bluetooth
+Qt5CLucene
+Qt5Concurrent
+Qt5Core
+Qt5DBus
+Qt5Declarative
+Qt5DesignerComponents
+Qt5Designer
+Qt5Gui
+Qt5Help
+Qt5MultimediaQuick_p
+Qt5Multimedia
+Qt5MultimediaWidgets
+Qt5Network
+Qt5Nfc
+Qt5OpenGL
+Qt5Positioning
+Qt5PrintSupport
+Qt5Qml
+Qt5QuickParticles
+Qt5Quick
+Qt5QuickTest
+Qt5Script
+Qt5ScriptTools
+Qt5Sensors
+Qt5SerialPort
+Qt5Sql
+Qt5Svg
+Qt5Test
+Qt5WebKit
+Qt5WebKitWidgets
+Qt5Widgets
+Qt5WinExtras
+Qt5X11Extras
+Qt5XmlPatterns
+Qt5Xml'''
+class qxx(Task.classes['cxx']):
+ def __init__(self,*k,**kw):
+ Task.Task.__init__(self,*k,**kw)
+ self.moc_done=0
+ def runnable_status(self):
+ if self.moc_done:
+ return Task.Task.runnable_status(self)
+ else:
+ for t in self.run_after:
+ if not t.hasrun:
+ return Task.ASK_LATER
+ self.add_moc_tasks()
+ return Task.Task.runnable_status(self)
+ def create_moc_task(self,h_node,m_node):
+ try:
+ moc_cache=self.generator.bld.moc_cache
+ except AttributeError:
+ moc_cache=self.generator.bld.moc_cache={}
+ try:
+ return moc_cache[h_node]
+ except KeyError:
+ tsk=moc_cache[h_node]=Task.classes['moc'](env=self.env,generator=self.generator)
+ tsk.set_inputs(h_node)
+ tsk.set_outputs(m_node)
+ if self.generator:
+ self.generator.tasks.append(tsk)
+ gen=self.generator.bld.producer
+ gen.outstanding.insert(0,tsk)
+ gen.total+=1
+ return tsk
+ else:
+ delattr(self,'cache_sig')
+ def moc_h_ext(self):
+ ext=[]
+ try:
+ ext=Options.options.qt_header_ext.split()
+ except AttributeError:
+ pass
+ if not ext:
+ ext=MOC_H
+ return ext
+ def add_moc_tasks(self):
+ node=self.inputs[0]
+ bld=self.generator.bld
+ try:
+ self.signature()
+ except KeyError:
+ pass
+ else:
+ delattr(self,'cache_sig')
+ include_nodes=[node.parent]+self.generator.includes_nodes
+ moctasks=[]
+ mocfiles=set([])
+ for d in bld.raw_deps.get(self.uid(),[]):
+ if not d.endswith('.moc'):
+ continue
+ if d in mocfiles:
+ continue
+ mocfiles.add(d)
+ h_node=None
+ base2=d[:-4]
+ for x in include_nodes:
+ for e in self.moc_h_ext():
+ h_node=x.find_node(base2+e)
+ if h_node:
+ break
+ if h_node:
+ m_node=h_node.change_ext('.moc')
+ break
+ else:
+ for k in EXT_QT5:
+ if base2.endswith(k):
+ for x in include_nodes:
+ h_node=x.find_node(base2)
+ if h_node:
+ break
+ if h_node:
+ m_node=h_node.change_ext(k+'.moc')
+ break
+ if not h_node:
+ raise Errors.WafError('No source found for %r which is a moc file'%d)
+ task=self.create_moc_task(h_node,m_node)
+ moctasks.append(task)
+ self.run_after.update(set(moctasks))
+ self.moc_done=1
+class trans_update(Task.Task):
+ run_str='${QT_LUPDATE} ${SRC} -ts ${TGT}'
+ color='BLUE'
+Task.update_outputs(trans_update)
+class XMLHandler(ContentHandler):
+ def __init__(self):
+ self.buf=[]
+ self.files=[]
+ def startElement(self,name,attrs):
+ if name=='file':
+ self.buf=[]
+ def endElement(self,name):
+ if name=='file':
+ self.files.append(str(''.join(self.buf)))
+ def characters(self,cars):
+ self.buf.append(cars)
+@extension(*EXT_RCC)
+def create_rcc_task(self,node):
+ rcnode=node.change_ext('_rc.cpp')
+ self.create_task('rcc',node,rcnode)
+ cpptask=self.create_task('cxx',rcnode,rcnode.change_ext('.o'))
+ try:
+ self.compiled_tasks.append(cpptask)
+ except AttributeError:
+ self.compiled_tasks=[cpptask]
+ return cpptask
+@extension(*EXT_UI)
+def create_uic_task(self,node):
+ uictask=self.create_task('ui5',node)
+ uictask.outputs=[self.path.find_or_declare(self.env['ui_PATTERN']%node.name[:-3])]
+@extension('.ts')
+def add_lang(self,node):
+ self.lang=self.to_list(getattr(self,'lang',[]))+[node]
+@feature('qt5')
+@after_method('apply_link')
+def apply_qt5(self):
+ if getattr(self,'lang',None):
+ qmtasks=[]
+ for x in self.to_list(self.lang):
+ if isinstance(x,str):
+ x=self.path.find_resource(x+'.ts')
+ qmtasks.append(self.create_task('ts2qm',x,x.change_ext('.qm')))
+ if getattr(self,'update',None)and Options.options.trans_qt5:
+ cxxnodes=[a.inputs[0]for a in self.compiled_tasks]+[a.inputs[0]for a in self.tasks if getattr(a,'inputs',None)and a.inputs[0].name.endswith('.ui')]
+ for x in qmtasks:
+ self.create_task('trans_update',cxxnodes,x.inputs)
+ if getattr(self,'langname',None):
+ qmnodes=[x.outputs[0]for x in qmtasks]
+ rcnode=self.langname
+ if isinstance(rcnode,str):
+ rcnode=self.path.find_or_declare(rcnode+'.qrc')
+ t=self.create_task('qm2rcc',qmnodes,rcnode)
+ k=create_rcc_task(self,t.outputs[0])
+ self.link_task.inputs.append(k.outputs[0])
+ lst=[]
+ for flag in self.to_list(self.env['CXXFLAGS']):
+ if len(flag)<2:continue
+ f=flag[0:2]
+ if f in('-D','-I','/D','/I'):
+ if(f[0]=='/'):
+ lst.append('-'+flag[1:])
+ else:
+ lst.append(flag)
+ self.env.append_value('MOC_FLAGS',lst)
+@extension(*EXT_QT5)
+def cxx_hook(self,node):
+ return self.create_compiled_task('qxx',node)
+class rcc(Task.Task):
+ color='BLUE'
+ run_str='${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
+ ext_out=['.h']
+ def rcname(self):
+ return os.path.splitext(self.inputs[0].name)[0]
+ def scan(self):
+ if not has_xml:
+ Logs.error('no xml support was found, the rcc dependencies will be incomplete!')
+ return([],[])
+ parser=make_parser()
+ curHandler=XMLHandler()
+ parser.setContentHandler(curHandler)
+ fi=open(self.inputs[0].abspath(),'r')
+ try:
+ parser.parse(fi)
+ finally:
+ fi.close()
+ nodes=[]
+ names=[]
+ root=self.inputs[0].parent
+ for x in curHandler.files:
+ nd=root.find_resource(x)
+ if nd:nodes.append(nd)
+ else:names.append(x)
+ return(nodes,names)
+class moc(Task.Task):
+ color='BLUE'
+ run_str='${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
+class ui5(Task.Task):
+ color='BLUE'
+ run_str='${QT_UIC} ${SRC} -o ${TGT}'
+ ext_out=['.h']
+class ts2qm(Task.Task):
+ color='BLUE'
+ run_str='${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
+class qm2rcc(Task.Task):
+ color='BLUE'
+ after='ts2qm'
+ def run(self):
+ txt='\n'.join(['<file>%s</file>'%k.path_from(self.outputs[0].parent)for k in self.inputs])
+ code='<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>'%txt
+ self.outputs[0].write(code)
+def configure(self):
+ self.find_qt5_binaries()
+ self.set_qt5_libs_to_check()
+ self.set_qt5_defines()
+ self.find_qt5_libraries()
+ self.add_qt5_rpath()
+ self.simplify_qt5_libs()
+@conf
+def find_qt5_binaries(self):
+ env=self.env
+ opt=Options.options
+ qtdir=getattr(opt,'qtdir','')
+ qtbin=getattr(opt,'qtbin','')
+ paths=[]
+ if qtdir:
+ qtbin=os.path.join(qtdir,'bin')
+ if not qtdir:
+ qtdir=os.environ.get('QT5_ROOT','')
+ qtbin=os.environ.get('QT5_BIN',None)or os.path.join(qtdir,'bin')
+ if qtbin:
+ paths=[qtbin]
+ if not qtdir:
+ paths=os.environ.get('PATH','').split(os.pathsep)
+ paths.append('/usr/share/qt5/bin/')
+ try:
+ lst=Utils.listdir('/usr/local/Trolltech/')
+ except OSError:
+ pass
+ else:
+ if lst:
+ lst.sort()
+ lst.reverse()
+ qtdir='/usr/local/Trolltech/%s/'%lst[0]
+ qtbin=os.path.join(qtdir,'bin')
+ paths.append(qtbin)
+ cand=None
+ prev_ver=['5','0','0']
+ for qmk in('qmake-qt5','qmake5','qmake'):
+ try:
+ qmake=self.find_program(qmk,path_list=paths)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ try:
+ version=self.cmd_and_log(qmake+['-query','QT_VERSION']).strip()
+ except self.errors.WafError:
+ pass
+ else:
+ if version:
+ new_ver=version.split('.')
+ if new_ver>prev_ver:
+ cand=qmake
+ prev_ver=new_ver
+ if not cand:
+ try:
+ self.find_program('qtchooser')
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ cmd=self.env.QTCHOOSER+['-qt=5','-run-tool=qmake']
+ try:
+ version=self.cmd_and_log(cmd+['-query','QT_VERSION'])
+ except self.errors.WafError:
+ pass
+ else:
+ cand=cmd
+ if cand:
+ self.env.QMAKE=cand
+ else:
+ self.fatal('Could not find qmake for qt5')
+ self.env.QT_INSTALL_BINS=qtbin=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_BINS']).strip()+os.sep
+ paths.insert(0,qtbin)
+ def find_bin(lst,var):
+ if var in env:
+ return
+ for f in lst:
+ try:
+ ret=self.find_program(f,path_list=paths)
+ except self.errors.ConfigurationError:
+ pass
+ else:
+ env[var]=ret
+ break
+ find_bin(['uic-qt5','uic'],'QT_UIC')
+ if not env.QT_UIC:
+ self.fatal('cannot find the uic compiler for qt5')
+ self.start_msg('Checking for uic version')
+ uicver=self.cmd_and_log(env.QT_UIC+['-version'],output=Context.BOTH)
+ uicver=''.join(uicver).strip()
+ uicver=uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt','')
+ self.end_msg(uicver)
+ if uicver.find(' 3.')!=-1 or uicver.find(' 4.')!=-1:
+ self.fatal('this uic compiler is for qt3 or qt5, add uic for qt5 to your path')
+ find_bin(['moc-qt5','moc'],'QT_MOC')
+ find_bin(['rcc-qt5','rcc'],'QT_RCC')
+ find_bin(['lrelease-qt5','lrelease'],'QT_LRELEASE')
+ find_bin(['lupdate-qt5','lupdate'],'QT_LUPDATE')
+ env['UIC_ST']='%s -o %s'
+ env['MOC_ST']='-o'
+ env['ui_PATTERN']='ui_%s.h'
+ env['QT_LRELEASE_FLAGS']=['-silent']
+ env.MOCCPPPATH_ST='-I%s'
+ env.MOCDEFINES_ST='-D%s'
+@conf
+def find_qt5_libraries(self):
+ qtlibs=getattr(Options.options,'qtlibs',None)or os.environ.get("QT5_LIBDIR",None)
+ if not qtlibs:
+ try:
+ qtlibs=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_LIBS']).strip()
+ except Errors.WafError:
+ qtdir=self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_PREFIX']).strip()+os.sep
+ qtlibs=os.path.join(qtdir,'lib')
+ self.msg('Found the Qt5 libraries in',qtlibs)
+ qtincludes=os.environ.get("QT5_INCLUDES",None)or self.cmd_and_log(self.env.QMAKE+['-query','QT_INSTALL_HEADERS']).strip()
+ env=self.env
+ if not'PKG_CONFIG_PATH'in os.environ:
+ os.environ['PKG_CONFIG_PATH']='%s:%s/pkgconfig:/usr/lib/qt5/lib/pkgconfig:/opt/qt5/lib/pkgconfig:/usr/lib/qt5/lib:/opt/qt5/lib'%(qtlibs,qtlibs)
+ try:
+ if os.environ.get("QT5_XCOMPILE",None):
+ raise self.errors.ConfigurationError()
+ self.check_cfg(atleast_pkgconfig_version='0.1')
+ except self.errors.ConfigurationError:
+ for i in self.qt5_vars:
+ uselib=i.upper()
+ if Utils.unversioned_sys_platform()=="darwin":
+ frameworkName=i+".framework"
+ qtDynamicLib=os.path.join(qtlibs,frameworkName,i)
+ if os.path.exists(qtDynamicLib):
+ env.append_unique('FRAMEWORK_'+uselib,i)
+ self.msg('Checking for %s'%i,qtDynamicLib,'GREEN')
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtlibs,frameworkName,'Headers'))
+ elif env.DEST_OS!="win32":
+ qtDynamicLib=os.path.join(qtlibs,"lib"+i+".so")
+ qtStaticLib=os.path.join(qtlibs,"lib"+i+".a")
+ if os.path.exists(qtDynamicLib):
+ env.append_unique('LIB_'+uselib,i)
+ self.msg('Checking for %s'%i,qtDynamicLib,'GREEN')
+ elif os.path.exists(qtStaticLib):
+ env.append_unique('LIB_'+uselib,i)
+ self.msg('Checking for %s'%i,qtStaticLib,'GREEN')
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i))
+ else:
+ for k in("lib%s.a","lib%s5.a","%s.lib","%s5.lib"):
+ lib=os.path.join(qtlibs,k%i)
+ if os.path.exists(lib):
+ env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')])
+ self.msg('Checking for %s'%i,lib,'GREEN')
+ break
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i.replace('Qt5','Qt')))
+ uselib=i.upper()+"_debug"
+ for k in("lib%sd.a","lib%sd5.a","%sd.lib","%sd5.lib"):
+ lib=os.path.join(qtlibs,k%i)
+ if os.path.exists(lib):
+ env.append_unique('LIB_'+uselib,i+k[k.find("%s")+2:k.find('.')])
+ self.msg('Checking for %s'%i,lib,'GREEN')
+ break
+ else:
+ self.msg('Checking for %s'%i,False,'YELLOW')
+ env.append_unique('LIBPATH_'+uselib,qtlibs)
+ env.append_unique('INCLUDES_'+uselib,qtincludes)
+ env.append_unique('INCLUDES_'+uselib,os.path.join(qtincludes,i.replace('Qt5','Qt')))
+ else:
+ for i in self.qt5_vars_debug+self.qt5_vars:
+ self.check_cfg(package=i,args='--cflags --libs',mandatory=False)
+@conf
+def simplify_qt5_libs(self):
+ env=self.env
+ def process_lib(vars_,coreval):
+ for d in vars_:
+ var=d.upper()
+ if var=='QTCORE':
+ continue
+ value=env['LIBPATH_'+var]
+ if value:
+ core=env[coreval]
+ accu=[]
+ for lib in value:
+ if lib in core:
+ continue
+ accu.append(lib)
+ env['LIBPATH_'+var]=accu
+ process_lib(self.qt5_vars,'LIBPATH_QTCORE')
+ process_lib(self.qt5_vars_debug,'LIBPATH_QTCORE_DEBUG')
+@conf
+def add_qt5_rpath(self):
+ env=self.env
+ if getattr(Options.options,'want_rpath',False):
+ def process_rpath(vars_,coreval):
+ for d in vars_:
+ var=d.upper()
+ value=env['LIBPATH_'+var]
+ if value:
+ core=env[coreval]
+ accu=[]
+ for lib in value:
+ if var!='QTCORE':
+ if lib in core:
+ continue
+ accu.append('-Wl,--rpath='+lib)
+ env['RPATH_'+var]=accu
+ process_rpath(self.qt5_vars,'LIBPATH_QTCORE')
+ process_rpath(self.qt5_vars_debug,'LIBPATH_QTCORE_DEBUG')
+@conf
+def set_qt5_libs_to_check(self):
+ if not hasattr(self,'qt5_vars'):
+ self.qt5_vars=QT5_LIBS
+ self.qt5_vars=Utils.to_list(self.qt5_vars)
+ if not hasattr(self,'qt5_vars_debug'):
+ self.qt5_vars_debug=[a+'_debug'for a in self.qt5_vars]
+ self.qt5_vars_debug=Utils.to_list(self.qt5_vars_debug)
+@conf
+def set_qt5_defines(self):
+ if sys.platform!='win32':
+ return
+ for x in self.qt5_vars:
+ y=x.replace('Qt5','Qt')[2:].upper()
+ self.env.append_unique('DEFINES_%s'%x.upper(),'QT_%s_LIB'%y)
+ self.env.append_unique('DEFINES_%s_DEBUG'%x.upper(),'QT_%s_LIB'%y)
+def options(opt):
+ opt.add_option('--want-rpath',action='store_true',default=False,dest='want_rpath',help='enable the rpath for qt libraries')
+ opt.add_option('--header-ext',type='string',default='',help='header extension for moc files',dest='qt_header_ext')
+ for i in'qtdir qtbin qtlibs'.split():
+ opt.add_option('--'+i,type='string',default='',dest=i)
+ opt.add_option('--translate',action="store_true",help="collect translation strings",dest="trans_qt5",default=False)
diff --git a/waflib/Tools/ruby.py b/waflib/Tools/ruby.py
new file mode 100644
index 0000000..e81a6ef
--- /dev/null
+++ b/waflib/Tools/ruby.py
@@ -0,0 +1,101 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+from waflib import Options,Utils,Task
+from waflib.TaskGen import before_method,feature,extension
+from waflib.Configure import conf
+@feature('rubyext')
+@before_method('apply_incpaths','apply_lib_vars','apply_bundle','apply_link')
+def init_rubyext(self):
+ self.install_path='${ARCHDIR_RUBY}'
+ self.uselib=self.to_list(getattr(self,'uselib',''))
+ if not'RUBY'in self.uselib:
+ self.uselib.append('RUBY')
+ if not'RUBYEXT'in self.uselib:
+ self.uselib.append('RUBYEXT')
+@feature('rubyext')
+@before_method('apply_link','propagate_uselib')
+def apply_ruby_so_name(self):
+ self.env['cshlib_PATTERN']=self.env['cxxshlib_PATTERN']=self.env['rubyext_PATTERN']
+@conf
+def check_ruby_version(self,minver=()):
+ if Options.options.rubybinary:
+ self.env.RUBY=Options.options.rubybinary
+ else:
+ self.find_program('ruby',var='RUBY')
+ ruby=self.env.RUBY
+ try:
+ version=self.cmd_and_log(ruby+['-e','puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip()
+ except Exception:
+ self.fatal('could not determine ruby version')
+ self.env.RUBY_VERSION=version
+ try:
+ ver=tuple(map(int,version.split(".")))
+ except Exception:
+ self.fatal('unsupported ruby version %r'%version)
+ cver=''
+ if minver:
+ cver='> '+'.'.join(str(x)for x in minver)
+ if ver<minver:
+ self.fatal('ruby is too old %r'%ver)
+ self.msg('Checking for ruby version %s'%cver,version)
+@conf
+def check_ruby_ext_devel(self):
+ if not self.env.RUBY:
+ self.fatal('ruby detection is required first')
+ if not self.env.CC_NAME and not self.env.CXX_NAME:
+ self.fatal('load a c/c++ compiler first')
+ version=tuple(map(int,self.env.RUBY_VERSION.split(".")))
+ def read_out(cmd):
+ return Utils.to_list(self.cmd_and_log(self.env.RUBY+['-rrbconfig','-e',cmd]))
+ def read_config(key):
+ return read_out('puts RbConfig::CONFIG[%r]'%key)
+ cpppath=archdir=read_config('archdir')
+ if version>=(1,9,0):
+ ruby_hdrdir=read_config('rubyhdrdir')
+ cpppath+=ruby_hdrdir
+ if version>=(2,0,0):
+ cpppath+=read_config('rubyarchhdrdir')
+ cpppath+=[os.path.join(ruby_hdrdir[0],read_config('arch')[0])]
+ self.check(header_name='ruby.h',includes=cpppath,errmsg='could not find ruby header file',link_header_test=False)
+ self.env.LIBPATH_RUBYEXT=read_config('libdir')
+ self.env.LIBPATH_RUBYEXT+=archdir
+ self.env.INCLUDES_RUBYEXT=cpppath
+ self.env.CFLAGS_RUBYEXT=read_config('CCDLFLAGS')
+ self.env.rubyext_PATTERN='%s.'+read_config('DLEXT')[0]
+ flags=read_config('LDSHARED')
+ while flags and flags[0][0]!='-':
+ flags=flags[1:]
+ if len(flags)>1 and flags[1]=="ppc":
+ flags=flags[2:]
+ self.env.LINKFLAGS_RUBYEXT=flags
+ self.env.LINKFLAGS_RUBYEXT+=read_config('LIBS')
+ self.env.LINKFLAGS_RUBYEXT+=read_config('LIBRUBYARG_SHARED')
+ if Options.options.rubyarchdir:
+ self.env.ARCHDIR_RUBY=Options.options.rubyarchdir
+ else:
+ self.env.ARCHDIR_RUBY=read_config('sitearchdir')[0]
+ if Options.options.rubylibdir:
+ self.env.LIBDIR_RUBY=Options.options.rubylibdir
+ else:
+ self.env.LIBDIR_RUBY=read_config('sitelibdir')[0]
+@conf
+def check_ruby_module(self,module_name):
+ self.start_msg('Ruby module %s'%module_name)
+ try:
+ self.cmd_and_log(self.env.RUBY+['-e','require \'%s\';puts 1'%module_name])
+ except Exception:
+ self.end_msg(False)
+ self.fatal('Could not find the ruby module %r'%module_name)
+ self.end_msg(True)
+@extension('.rb')
+def process(self,node):
+ return self.create_task('run_ruby',node)
+class run_ruby(Task.Task):
+ run_str='${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}'
+def options(opt):
+ opt.add_option('--with-ruby-archdir',type='string',dest='rubyarchdir',help='Specify directory where to install arch specific files')
+ opt.add_option('--with-ruby-libdir',type='string',dest='rubylibdir',help='Specify alternate ruby library path')
+ opt.add_option('--with-ruby-binary',type='string',dest='rubybinary',help='Specify alternate ruby binary')
diff --git a/waflib/Tools/suncc.py b/waflib/Tools/suncc.py
new file mode 100644
index 0000000..f014abf
--- /dev/null
+++ b/waflib/Tools/suncc.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_scc(conf):
+ v=conf.env
+ cc=conf.find_program('cc',var='CC')
+ try:
+ conf.cmd_and_log(cc+['-flags'])
+ except Exception:
+ conf.fatal('%r is not a Sun compiler'%cc)
+ v.CC_NAME='sun'
+ conf.get_suncc_version(cc)
+@conf
+def scc_common_flags(conf):
+ v=conf.env
+ v['CC_SRC_F']=[]
+ v['CC_TGT_F']=['-c','-o']
+ if not v['LINK_CC']:v['LINK_CC']=v['CC']
+ v['CCLNK_SRC_F']=''
+ v['CCLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['SONAME_ST']='-Wl,-h,%s'
+ v['SHLIB_MARKER']='-Bdynamic'
+ v['STLIB_MARKER']='-Bstatic'
+ v['cprogram_PATTERN']='%s'
+ v['CFLAGS_cshlib']=['-xcode=pic32','-DPIC']
+ v['LINKFLAGS_cshlib']=['-G']
+ v['cshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cstlib']=['-Bstatic']
+ v['cstlib_PATTERN']='lib%s.a'
+def configure(conf):
+ conf.find_scc()
+ conf.find_ar()
+ conf.scc_common_flags()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/suncxx.py b/waflib/Tools/suncxx.py
new file mode 100644
index 0000000..7130fdf
--- /dev/null
+++ b/waflib/Tools/suncxx.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_sxx(conf):
+ v=conf.env
+ cc=conf.find_program(['CC','c++'],var='CXX')
+ try:
+ conf.cmd_and_log(cc+['-flags'])
+ except Exception:
+ conf.fatal('%r is not a Sun compiler'%cc)
+ v.CXX_NAME='sun'
+ conf.get_suncc_version(cc)
+@conf
+def sxx_common_flags(conf):
+ v=conf.env
+ v['CXX_SRC_F']=[]
+ v['CXX_TGT_F']=['-c','-o']
+ if not v['LINK_CXX']:v['LINK_CXX']=v['CXX']
+ v['CXXLNK_SRC_F']=[]
+ v['CXXLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['SONAME_ST']='-Wl,-h,%s'
+ v['SHLIB_MARKER']='-Bdynamic'
+ v['STLIB_MARKER']='-Bstatic'
+ v['cxxprogram_PATTERN']='%s'
+ v['CXXFLAGS_cxxshlib']=['-xcode=pic32','-DPIC']
+ v['LINKFLAGS_cxxshlib']=['-G']
+ v['cxxshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cxxstlib']=['-Bstatic']
+ v['cxxstlib_PATTERN']='lib%s.a'
+def configure(conf):
+ conf.find_sxx()
+ conf.find_ar()
+ conf.sxx_common_flags()
+ conf.cxx_load_tools()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/tex.py b/waflib/Tools/tex.py
new file mode 100644
index 0000000..a91fd91
--- /dev/null
+++ b/waflib/Tools/tex.py
@@ -0,0 +1,317 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re
+from waflib import Utils,Task,Errors,Logs,Node
+from waflib.TaskGen import feature,before_method
+re_bibunit=re.compile(r'\\(?P<type>putbib)\[(?P<file>[^\[\]]*)\]',re.M)
+def bibunitscan(self):
+ node=self.inputs[0]
+ nodes=[]
+ if not node:return nodes
+ code=node.read()
+ for match in re_bibunit.finditer(code):
+ path=match.group('file')
+ if path:
+ for k in('','.bib'):
+ Logs.debug('tex: trying %s%s'%(path,k))
+ fi=node.parent.find_resource(path+k)
+ if fi:
+ nodes.append(fi)
+ else:
+ Logs.debug('tex: could not find %s'%path)
+ Logs.debug("tex: found the following bibunit files: %s"%nodes)
+ return nodes
+exts_deps_tex=['','.ltx','.tex','.bib','.pdf','.png','.eps','.ps','.sty']
+exts_tex=['.ltx','.tex']
+re_tex=re.compile(r'\\(?P<type>usepackage|RequirePackage|include|bibliography([^\[\]{}]*)|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P<file>[^{}]*)}',re.M)
+g_bibtex_re=re.compile('bibdata',re.M)
+g_glossaries_re=re.compile('\\@newglossary',re.M)
+class tex(Task.Task):
+ bibtex_fun,_=Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}',shell=False)
+ bibtex_fun.__doc__="""
+ Execute the program **bibtex**
+ """
+ makeindex_fun,_=Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}',shell=False)
+ makeindex_fun.__doc__="""
+ Execute the program **makeindex**
+ """
+ makeglossaries_fun,_=Task.compile_fun('${MAKEGLOSSARIES} ${SRCFILE}',shell=False)
+ makeglossaries_fun.__doc__="""
+ Execute the program **makeglossaries**
+ """
+ def exec_command(self,cmd,**kw):
+ bld=self.generator.bld
+ Logs.info('runner: %r'%cmd)
+ try:
+ if not kw.get('cwd',None):
+ kw['cwd']=bld.cwd
+ except AttributeError:
+ bld.cwd=kw['cwd']=bld.variant_dir
+ return Utils.subprocess.Popen(cmd,**kw).wait()
+ def scan_aux(self,node):
+ nodes=[node]
+ re_aux=re.compile(r'\\@input{(?P<file>[^{}]*)}',re.M)
+ def parse_node(node):
+ code=node.read()
+ for match in re_aux.finditer(code):
+ path=match.group('file')
+ found=node.parent.find_or_declare(path)
+ if found and found not in nodes:
+ Logs.debug('tex: found aux node '+found.abspath())
+ nodes.append(found)
+ parse_node(found)
+ parse_node(node)
+ return nodes
+ def scan(self):
+ node=self.inputs[0]
+ nodes=[]
+ names=[]
+ seen=[]
+ if not node:return(nodes,names)
+ def parse_node(node):
+ if node in seen:
+ return
+ seen.append(node)
+ code=node.read()
+ global re_tex
+ for match in re_tex.finditer(code):
+ multibib=match.group('type')
+ if multibib and multibib.startswith('bibliography'):
+ multibib=multibib[len('bibliography'):]
+ if multibib.startswith('style'):
+ continue
+ else:
+ multibib=None
+ for path in match.group('file').split(','):
+ if path:
+ add_name=True
+ found=None
+ for k in exts_deps_tex:
+ for up in self.texinputs_nodes:
+ Logs.debug('tex: trying %s%s'%(path,k))
+ found=up.find_resource(path+k)
+ if found:
+ break
+ for tsk in self.generator.tasks:
+ if not found or found in tsk.outputs:
+ break
+ else:
+ nodes.append(found)
+ add_name=False
+ for ext in exts_tex:
+ if found.name.endswith(ext):
+ parse_node(found)
+ break
+ if found and multibib and found.name.endswith('.bib'):
+ try:
+ self.multibibs.append(found)
+ except AttributeError:
+ self.multibibs=[found]
+ if add_name:
+ names.append(path)
+ parse_node(node)
+ for x in nodes:
+ x.parent.get_bld().mkdir()
+ Logs.debug("tex: found the following : %s and names %s"%(nodes,names))
+ return(nodes,names)
+ def check_status(self,msg,retcode):
+ if retcode!=0:
+ raise Errors.WafError("%r command exit status %r"%(msg,retcode))
+ def bibfile(self):
+ for aux_node in self.aux_nodes:
+ try:
+ ct=aux_node.read()
+ except EnvironmentError:
+ Logs.error('Error reading %s: %r'%aux_node.abspath())
+ continue
+ if g_bibtex_re.findall(ct):
+ Logs.info('calling bibtex')
+ self.env.env={}
+ self.env.env.update(os.environ)
+ self.env.env.update({'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()})
+ self.env.SRCFILE=aux_node.name[:-4]
+ self.check_status('error when calling bibtex',self.bibtex_fun())
+ for node in getattr(self,'multibibs',[]):
+ self.env.env={}
+ self.env.env.update(os.environ)
+ self.env.env.update({'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()})
+ self.env.SRCFILE=node.name[:-4]
+ self.check_status('error when calling bibtex',self.bibtex_fun())
+ def bibunits(self):
+ try:
+ bibunits=bibunitscan(self)
+ except OSError:
+ Logs.error('error bibunitscan')
+ else:
+ if bibunits:
+ fn=['bu'+str(i)for i in range(1,len(bibunits)+1)]
+ if fn:
+ Logs.info('calling bibtex on bibunits')
+ for f in fn:
+ self.env.env={'BIBINPUTS':self.texinputs(),'BSTINPUTS':self.texinputs()}
+ self.env.SRCFILE=f
+ self.check_status('error when calling bibtex',self.bibtex_fun())
+ def makeindex(self):
+ self.idx_node=self.inputs[0].change_ext('.idx')
+ try:
+ idx_path=self.idx_node.abspath()
+ os.stat(idx_path)
+ except OSError:
+ Logs.info('index file %s absent, not calling makeindex'%idx_path)
+ else:
+ Logs.info('calling makeindex')
+ self.env.SRCFILE=self.idx_node.name
+ self.env.env={}
+ self.check_status('error when calling makeindex %s'%idx_path,self.makeindex_fun())
+ def bibtopic(self):
+ p=self.inputs[0].parent.get_bld()
+ if os.path.exists(os.path.join(p.abspath(),'btaux.aux')):
+ self.aux_nodes+=p.ant_glob('*[0-9].aux')
+ def makeglossaries(self):
+ src_file=self.inputs[0].abspath()
+ base_file=os.path.basename(src_file)
+ base,_=os.path.splitext(base_file)
+ for aux_node in self.aux_nodes:
+ try:
+ ct=aux_node.read()
+ except EnvironmentError:
+ Logs.error('Error reading %s: %r'%aux_node.abspath())
+ continue
+ if g_glossaries_re.findall(ct):
+ if not self.env.MAKEGLOSSARIES:
+ raise Errors.WafError("The program 'makeglossaries' is missing!")
+ Logs.warn('calling makeglossaries')
+ self.env.SRCFILE=base
+ self.check_status('error when calling makeglossaries %s'%base,self.makeglossaries_fun())
+ return
+ def texinputs(self):
+ return os.pathsep.join([k.abspath()for k in self.texinputs_nodes])+os.pathsep
+ def run(self):
+ env=self.env
+ if not env['PROMPT_LATEX']:
+ env.append_value('LATEXFLAGS','-interaction=batchmode')
+ env.append_value('PDFLATEXFLAGS','-interaction=batchmode')
+ env.append_value('XELATEXFLAGS','-interaction=batchmode')
+ self.cwd=self.inputs[0].parent.get_bld().abspath()
+ Logs.info('first pass on %s'%self.__class__.__name__)
+ cur_hash=self.hash_aux_nodes()
+ self.call_latex()
+ self.hash_aux_nodes()
+ self.bibtopic()
+ self.bibfile()
+ self.bibunits()
+ self.makeindex()
+ self.makeglossaries()
+ for i in range(10):
+ prev_hash=cur_hash
+ cur_hash=self.hash_aux_nodes()
+ if not cur_hash:
+ Logs.error('No aux.h to process')
+ if cur_hash and cur_hash==prev_hash:
+ break
+ Logs.info('calling %s'%self.__class__.__name__)
+ self.call_latex()
+ def hash_aux_nodes(self):
+ try:
+ self.aux_nodes
+ except AttributeError:
+ try:
+ self.aux_nodes=self.scan_aux(self.inputs[0].change_ext('.aux'))
+ except IOError:
+ return None
+ return Utils.h_list([Utils.h_file(x.abspath())for x in self.aux_nodes])
+ def call_latex(self):
+ self.env.env={}
+ self.env.env.update(os.environ)
+ self.env.env.update({'TEXINPUTS':self.texinputs()})
+ self.env.SRCFILE=self.inputs[0].abspath()
+ self.check_status('error when calling latex',self.texfun())
+class latex(tex):
+ texfun,vars=Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}',shell=False)
+class pdflatex(tex):
+ texfun,vars=Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}',shell=False)
+class xelatex(tex):
+ texfun,vars=Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}',shell=False)
+class dvips(Task.Task):
+ run_str='${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}'
+ color='BLUE'
+ after=['latex','pdflatex','xelatex']
+class dvipdf(Task.Task):
+ run_str='${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}'
+ color='BLUE'
+ after=['latex','pdflatex','xelatex']
+class pdf2ps(Task.Task):
+ run_str='${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}'
+ color='BLUE'
+ after=['latex','pdflatex','xelatex']
+@feature('tex')
+@before_method('process_source')
+def apply_tex(self):
+ if not getattr(self,'type',None)in('latex','pdflatex','xelatex'):
+ self.type='pdflatex'
+ outs=Utils.to_list(getattr(self,'outs',[]))
+ self.env['PROMPT_LATEX']=getattr(self,'prompt',1)
+ deps_lst=[]
+ if getattr(self,'deps',None):
+ deps=self.to_list(self.deps)
+ for dep in deps:
+ if isinstance(dep,str):
+ n=self.path.find_resource(dep)
+ if not n:
+ self.bld.fatal('Could not find %r for %r'%(dep,self))
+ if not n in deps_lst:
+ deps_lst.append(n)
+ elif isinstance(dep,Node.Node):
+ deps_lst.append(dep)
+ for node in self.to_nodes(self.source):
+ if self.type=='latex':
+ task=self.create_task('latex',node,node.change_ext('.dvi'))
+ elif self.type=='pdflatex':
+ task=self.create_task('pdflatex',node,node.change_ext('.pdf'))
+ elif self.type=='xelatex':
+ task=self.create_task('xelatex',node,node.change_ext('.pdf'))
+ task.env=self.env
+ if deps_lst:
+ for n in deps_lst:
+ if not n in task.dep_nodes:
+ task.dep_nodes.append(n)
+ if hasattr(self,'texinputs_nodes'):
+ task.texinputs_nodes=self.texinputs_nodes
+ else:
+ task.texinputs_nodes=[node.parent,node.parent.get_bld(),self.path,self.path.get_bld()]
+ lst=os.environ.get('TEXINPUTS','')
+ if self.env.TEXINPUTS:
+ lst+=os.pathsep+self.env.TEXINPUTS
+ if lst:
+ lst=lst.split(os.pathsep)
+ for x in lst:
+ if x:
+ if os.path.isabs(x):
+ p=self.bld.root.find_node(x)
+ if p:
+ task.texinputs_nodes.append(p)
+ else:
+ Logs.error('Invalid TEXINPUTS folder %s'%x)
+ else:
+ Logs.error('Cannot resolve relative paths in TEXINPUTS %s'%x)
+ if self.type=='latex':
+ if'ps'in outs:
+ tsk=self.create_task('dvips',task.outputs,node.change_ext('.ps'))
+ tsk.env.env=dict(os.environ)
+ if'pdf'in outs:
+ tsk=self.create_task('dvipdf',task.outputs,node.change_ext('.pdf'))
+ tsk.env.env=dict(os.environ)
+ elif self.type=='pdflatex':
+ if'ps'in outs:
+ self.create_task('pdf2ps',task.outputs,node.change_ext('.ps'))
+ self.source=[]
+def configure(self):
+ v=self.env
+ for p in'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps makeglossaries'.split():
+ try:
+ self.find_program(p,var=p.upper())
+ except self.errors.ConfigurationError:
+ pass
+ v['DVIPSFLAGS']='-Ppdf'
diff --git a/waflib/Tools/vala.py b/waflib/Tools/vala.py
new file mode 100644
index 0000000..0521cbb
--- /dev/null
+++ b/waflib/Tools/vala.py
@@ -0,0 +1,212 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re
+from waflib import Context,Task,Utils,Logs,Options,Errors,Node
+from waflib.TaskGen import extension,taskgen_method
+from waflib.Configure import conf
+class valac(Task.Task):
+ vars=["VALAC","VALAC_VERSION","VALAFLAGS"]
+ ext_out=['.h']
+ def run(self):
+ cmd=self.env.VALAC+self.env.VALAFLAGS
+ resources=getattr(self,'vala_exclude',[])
+ cmd.extend([a.abspath()for a in self.inputs if a not in resources])
+ ret=self.exec_command(cmd,cwd=self.vala_dir_node.abspath())
+ if ret:
+ return ret
+ if self.generator.dump_deps_node:
+ self.generator.dump_deps_node.write('\n'.join(self.generator.packages))
+ return ret
+valac=Task.update_outputs(valac)
+@taskgen_method
+def init_vala_task(self):
+ self.profile=getattr(self,'profile','gobject')
+ if self.profile=='gobject':
+ self.uselib=Utils.to_list(getattr(self,'uselib',[]))
+ if not'GOBJECT'in self.uselib:
+ self.uselib.append('GOBJECT')
+ def addflags(flags):
+ self.env.append_value('VALAFLAGS',flags)
+ if self.profile:
+ addflags('--profile=%s'%self.profile)
+ valatask=self.valatask
+ if hasattr(self,'vala_dir'):
+ if isinstance(self.vala_dir,str):
+ valatask.vala_dir_node=self.path.get_bld().make_node(self.vala_dir)
+ try:
+ valatask.vala_dir_node.mkdir()
+ except OSError:
+ raise self.bld.fatal('Cannot create the vala dir %r'%valatask.vala_dir_node)
+ else:
+ valatask.vala_dir_node=self.vala_dir
+ else:
+ valatask.vala_dir_node=self.path.get_bld()
+ addflags('--directory=%s'%valatask.vala_dir_node.abspath())
+ if hasattr(self,'thread'):
+ if self.profile=='gobject':
+ if not'GTHREAD'in self.uselib:
+ self.uselib.append('GTHREAD')
+ else:
+ Logs.warn("Profile %s means no threading support"%self.profile)
+ self.thread=False
+ if self.thread:
+ addflags('--thread')
+ self.is_lib='cprogram'not in self.features
+ if self.is_lib:
+ addflags('--library=%s'%self.target)
+ h_node=valatask.vala_dir_node.find_or_declare('%s.h'%self.target)
+ valatask.outputs.append(h_node)
+ addflags('--header=%s'%h_node.name)
+ valatask.outputs.append(valatask.vala_dir_node.find_or_declare('%s.vapi'%self.target))
+ if getattr(self,'gir',None):
+ gir_node=valatask.vala_dir_node.find_or_declare('%s.gir'%self.gir)
+ addflags('--gir=%s'%gir_node.name)
+ valatask.outputs.append(gir_node)
+ self.vala_target_glib=getattr(self,'vala_target_glib',getattr(Options.options,'vala_target_glib',None))
+ if self.vala_target_glib:
+ addflags('--target-glib=%s'%self.vala_target_glib)
+ addflags(['--define=%s'%x for x in Utils.to_list(getattr(self,'vala_defines',[]))])
+ packages_private=Utils.to_list(getattr(self,'packages_private',[]))
+ addflags(['--pkg=%s'%x for x in packages_private])
+ def _get_api_version():
+ api_version='1.0'
+ if hasattr(Context.g_module,'API_VERSION'):
+ version=Context.g_module.API_VERSION.split(".")
+ if version[0]=="0":
+ api_version="0."+version[1]
+ else:
+ api_version=version[0]+".0"
+ return api_version
+ self.includes=Utils.to_list(getattr(self,'includes',[]))
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ valatask.install_path=getattr(self,'install_path','')
+ valatask.vapi_path=getattr(self,'vapi_path','${DATAROOTDIR}/vala/vapi')
+ valatask.pkg_name=getattr(self,'pkg_name',self.env['PACKAGE'])
+ valatask.header_path=getattr(self,'header_path','${INCLUDEDIR}/%s-%s'%(valatask.pkg_name,_get_api_version()))
+ valatask.install_binding=getattr(self,'install_binding',True)
+ self.packages=packages=Utils.to_list(getattr(self,'packages',[]))
+ self.vapi_dirs=vapi_dirs=Utils.to_list(getattr(self,'vapi_dirs',[]))
+ if hasattr(self,'use'):
+ local_packages=Utils.to_list(self.use)[:]
+ seen=[]
+ while len(local_packages)>0:
+ package=local_packages.pop()
+ if package in seen:
+ continue
+ seen.append(package)
+ try:
+ package_obj=self.bld.get_tgen_by_name(package)
+ except Errors.WafError:
+ continue
+ package_name=package_obj.target
+ for task in package_obj.tasks:
+ for output in task.outputs:
+ if output.name==package_name+".vapi":
+ valatask.set_run_after(task)
+ if package_name not in packages:
+ packages.append(package_name)
+ if output.parent not in vapi_dirs:
+ vapi_dirs.append(output.parent)
+ if output.parent not in self.includes:
+ self.includes.append(output.parent)
+ if hasattr(package_obj,'use'):
+ lst=self.to_list(package_obj.use)
+ lst.reverse()
+ local_packages=[pkg for pkg in lst if pkg not in seen]+local_packages
+ addflags(['--pkg=%s'%p for p in packages])
+ for vapi_dir in vapi_dirs:
+ if isinstance(vapi_dir,Node.Node):
+ v_node=vapi_dir
+ else:
+ v_node=self.path.find_dir(vapi_dir)
+ if not v_node:
+ Logs.warn('Unable to locate Vala API directory: %r'%vapi_dir)
+ else:
+ addflags('--vapidir=%s'%v_node.abspath())
+ self.dump_deps_node=None
+ if self.is_lib and self.packages:
+ self.dump_deps_node=valatask.vala_dir_node.find_or_declare('%s.deps'%self.target)
+ valatask.outputs.append(self.dump_deps_node)
+ self.includes.append(self.bld.srcnode.abspath())
+ self.includes.append(self.bld.bldnode.abspath())
+ if self.is_lib and valatask.install_binding:
+ headers_list=[o for o in valatask.outputs if o.suffix()==".h"]
+ try:
+ self.install_vheader.source=headers_list
+ except AttributeError:
+ self.install_vheader=self.bld.install_files(valatask.header_path,headers_list,self.env)
+ vapi_list=[o for o in valatask.outputs if(o.suffix()in(".vapi",".deps"))]
+ try:
+ self.install_vapi.source=vapi_list
+ except AttributeError:
+ self.install_vapi=self.bld.install_files(valatask.vapi_path,vapi_list,self.env)
+ gir_list=[o for o in valatask.outputs if o.suffix()=='.gir']
+ try:
+ self.install_gir.source=gir_list
+ except AttributeError:
+ self.install_gir=self.bld.install_files(getattr(self,'gir_path','${DATAROOTDIR}/gir-1.0'),gir_list,self.env)
+ if hasattr(self,'vala_resources'):
+ nodes=self.to_nodes(self.vala_resources)
+ valatask.vala_exclude=getattr(valatask,'vala_exclude',[])+nodes
+ valatask.inputs.extend(nodes)
+ for x in nodes:
+ addflags(['--gresources',x.abspath()])
+@extension('.vala','.gs')
+def vala_file(self,node):
+ try:
+ valatask=self.valatask
+ except AttributeError:
+ valatask=self.valatask=self.create_task('valac')
+ self.init_vala_task()
+ valatask.inputs.append(node)
+ name=node.name[:node.name.rfind('.')]+'.c'
+ c_node=valatask.vala_dir_node.find_or_declare(name)
+ valatask.outputs.append(c_node)
+ self.source.append(c_node)
+@conf
+def find_valac(self,valac_name,min_version):
+ valac=self.find_program(valac_name,var='VALAC')
+ try:
+ output=self.cmd_and_log(valac+['--version'])
+ except Exception:
+ valac_version=None
+ else:
+ ver=re.search(r'\d+.\d+.\d+',output).group(0).split('.')
+ valac_version=tuple([int(x)for x in ver])
+ self.msg('Checking for %s version >= %r'%(valac_name,min_version),valac_version,valac_version and valac_version>=min_version)
+ if valac and valac_version<min_version:
+ self.fatal("%s version %r is too old, need >= %r"%(valac_name,valac_version,min_version))
+ self.env['VALAC_VERSION']=valac_version
+ return valac
+@conf
+def check_vala(self,min_version=(0,8,0),branch=None):
+ if not branch:
+ branch=min_version[:2]
+ try:
+ find_valac(self,'valac-%d.%d'%(branch[0],branch[1]),min_version)
+ except self.errors.ConfigurationError:
+ find_valac(self,'valac',min_version)
+@conf
+def check_vala_deps(self):
+ if not self.env['HAVE_GOBJECT']:
+ pkg_args={'package':'gobject-2.0','uselib_store':'GOBJECT','args':'--cflags --libs'}
+ if getattr(Options.options,'vala_target_glib',None):
+ pkg_args['atleast_version']=Options.options.vala_target_glib
+ self.check_cfg(**pkg_args)
+ if not self.env['HAVE_GTHREAD']:
+ pkg_args={'package':'gthread-2.0','uselib_store':'GTHREAD','args':'--cflags --libs'}
+ if getattr(Options.options,'vala_target_glib',None):
+ pkg_args['atleast_version']=Options.options.vala_target_glib
+ self.check_cfg(**pkg_args)
+def configure(self):
+ self.load('gnu_dirs')
+ self.check_vala_deps()
+ self.check_vala()
+ self.add_os_flags('VALAFLAGS')
+ self.env.append_unique('VALAFLAGS',['-C'])
+def options(opt):
+ opt.load('gnu_dirs')
+ valaopts=opt.add_option_group('Vala Compiler Options')
+ valaopts.add_option('--vala-target-glib',default=None,dest='vala_target_glib',metavar='MAJOR.MINOR',help='Target version of glib for Vala GObject code generation')
diff --git a/waflib/Tools/waf_unit_test.py b/waflib/Tools/waf_unit_test.py
new file mode 100644
index 0000000..5727879
--- /dev/null
+++ b/waflib/Tools/waf_unit_test.py
@@ -0,0 +1,106 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+from waflib.TaskGen import feature,after_method,taskgen_method
+from waflib import Utils,Task,Logs,Options
+testlock=Utils.threading.Lock()
+@feature('test')
+@after_method('apply_link')
+def make_test(self):
+ if getattr(self,'link_task',None):
+ self.create_task('utest',self.link_task.outputs)
+@taskgen_method
+def add_test_results(self,tup):
+ Logs.debug("ut: %r",tup)
+ self.utest_result=tup
+ try:
+ self.bld.utest_results.append(tup)
+ except AttributeError:
+ self.bld.utest_results=[tup]
+class utest(Task.Task):
+ color='PINK'
+ after=['vnum','inst']
+ vars=[]
+ def runnable_status(self):
+ if getattr(Options.options,'no_tests',False):
+ return Task.SKIP_ME
+ ret=super(utest,self).runnable_status()
+ if ret==Task.SKIP_ME:
+ if getattr(Options.options,'all_tests',False):
+ return Task.RUN_ME
+ return ret
+ def add_path(self,dct,path,var):
+ dct[var]=os.pathsep.join(Utils.to_list(path)+[os.environ.get(var,'')])
+ def get_test_env(self):
+ try:
+ fu=getattr(self.generator.bld,'all_test_paths')
+ except AttributeError:
+ fu=os.environ.copy()
+ lst=[]
+ for g in self.generator.bld.groups:
+ for tg in g:
+ if getattr(tg,'link_task',None):
+ s=tg.link_task.outputs[0].parent.abspath()
+ if s not in lst:
+ lst.append(s)
+ if Utils.is_win32:
+ self.add_path(fu,lst,'PATH')
+ elif Utils.unversioned_sys_platform()=='darwin':
+ self.add_path(fu,lst,'DYLD_LIBRARY_PATH')
+ self.add_path(fu,lst,'LD_LIBRARY_PATH')
+ else:
+ self.add_path(fu,lst,'LD_LIBRARY_PATH')
+ self.generator.bld.all_test_paths=fu
+ return fu
+ def run(self):
+ filename=self.inputs[0].abspath()
+ self.ut_exec=getattr(self.generator,'ut_exec',[filename])
+ if getattr(self.generator,'ut_fun',None):
+ self.generator.ut_fun(self)
+ cwd=getattr(self.generator,'ut_cwd','')or self.inputs[0].parent.abspath()
+ testcmd=getattr(self.generator,'ut_cmd',False)or getattr(Options.options,'testcmd',False)
+ if testcmd:
+ self.ut_exec=(testcmd%" ".join(self.ut_exec)).split(' ')
+ proc=Utils.subprocess.Popen(self.ut_exec,cwd=cwd,env=self.get_test_env(),stderr=Utils.subprocess.PIPE,stdout=Utils.subprocess.PIPE)
+ (stdout,stderr)=proc.communicate()
+ self.waf_unit_test_results=tup=(filename,proc.returncode,stdout,stderr)
+ testlock.acquire()
+ try:
+ return self.generator.add_test_results(tup)
+ finally:
+ testlock.release()
+ def post_run(self):
+ super(utest,self).post_run()
+ if getattr(Options.options,'clear_failed_tests',False)and self.waf_unit_test_results[1]:
+ self.generator.bld.task_sigs[self.uid()]=None
+def summary(bld):
+ lst=getattr(bld,'utest_results',[])
+ if lst:
+ Logs.pprint('CYAN','execution summary')
+ total=len(lst)
+ tfail=len([x for x in lst if x[1]])
+ Logs.pprint('CYAN',' tests that pass %d/%d'%(total-tfail,total))
+ for(f,code,out,err)in lst:
+ if not code:
+ Logs.pprint('CYAN',' %s'%f)
+ Logs.pprint('CYAN',' tests that fail %d/%d'%(tfail,total))
+ for(f,code,out,err)in lst:
+ if code:
+ Logs.pprint('CYAN',' %s'%f)
+def set_exit_code(bld):
+ lst=getattr(bld,'utest_results',[])
+ for(f,code,out,err)in lst:
+ if code:
+ msg=[]
+ if out:
+ msg.append('stdout:%s%s'%(os.linesep,out.decode('utf-8')))
+ if err:
+ msg.append('stderr:%s%s'%(os.linesep,err.decode('utf-8')))
+ bld.fatal(os.linesep.join(msg))
+def options(opt):
+ opt.add_option('--notests',action='store_true',default=False,help='Exec no unit tests',dest='no_tests')
+ opt.add_option('--alltests',action='store_true',default=False,help='Exec all unit tests',dest='all_tests')
+ opt.add_option('--clear-failed',action='store_true',default=False,help='Force failed unit tests to run again next time',dest='clear_failed_tests')
+ opt.add_option('--testcmd',action='store',default=False,help='Run the unit tests using the test-cmd string'' example "--test-cmd="valgrind --error-exitcode=1'' %s" to run under valgrind',dest='testcmd')
diff --git a/waflib/Tools/winres.py b/waflib/Tools/winres.py
new file mode 100644
index 0000000..a055887
--- /dev/null
+++ b/waflib/Tools/winres.py
@@ -0,0 +1,85 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import re,traceback
+from waflib import Task,Logs,Utils
+from waflib.TaskGen import extension
+from waflib.Tools import c_preproc
+@extension('.rc')
+def rc_file(self,node):
+ obj_ext='.rc.o'
+ if self.env['WINRC_TGT_F']=='/fo':
+ obj_ext='.res'
+ rctask=self.create_task('winrc',node,node.change_ext(obj_ext))
+ try:
+ self.compiled_tasks.append(rctask)
+ except AttributeError:
+ self.compiled_tasks=[rctask]
+re_lines=re.compile('(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|''(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)',re.IGNORECASE|re.MULTILINE)
+class rc_parser(c_preproc.c_parser):
+ def filter_comments(self,filepath):
+ code=Utils.readf(filepath)
+ if c_preproc.use_trigraphs:
+ for(a,b)in c_preproc.trig_def:code=code.split(a).join(b)
+ code=c_preproc.re_nl.sub('',code)
+ code=c_preproc.re_cpp.sub(c_preproc.repl,code)
+ ret=[]
+ for m in re.finditer(re_lines,code):
+ if m.group(2):
+ ret.append((m.group(2),m.group(3)))
+ else:
+ ret.append(('include',m.group(5)))
+ return ret
+ def addlines(self,node):
+ self.currentnode_stack.append(node.parent)
+ filepath=node.abspath()
+ self.count_files+=1
+ if self.count_files>c_preproc.recursion_limit:
+ raise c_preproc.PreprocError("recursion limit exceeded")
+ pc=self.parse_cache
+ Logs.debug('preproc: reading file %r',filepath)
+ try:
+ lns=pc[filepath]
+ except KeyError:
+ pass
+ else:
+ self.lines.extend(lns)
+ return
+ try:
+ lines=self.filter_comments(filepath)
+ lines.append((c_preproc.POPFILE,''))
+ lines.reverse()
+ pc[filepath]=lines
+ self.lines.extend(lines)
+ except IOError:
+ raise c_preproc.PreprocError("could not read the file %s"%filepath)
+ except Exception:
+ if Logs.verbose>0:
+ Logs.error("parsing %s failed"%filepath)
+ traceback.print_exc()
+class winrc(Task.Task):
+ run_str='${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}'
+ color='BLUE'
+ def scan(self):
+ tmp=rc_parser(self.generator.includes_nodes)
+ tmp.start(self.inputs[0],self.env)
+ nodes=tmp.nodes
+ names=tmp.names
+ if Logs.verbose:
+ Logs.debug('deps: deps for %s: %r; unresolved %r'%(str(self),nodes,names))
+ return(nodes,names)
+def configure(conf):
+ v=conf.env
+ v['WINRC_TGT_F']='-o'
+ v['WINRC_SRC_F']='-i'
+ if not conf.env.WINRC:
+ if v.CC_NAME=='msvc':
+ conf.find_program('RC',var='WINRC',path_list=v['PATH'])
+ v['WINRC_TGT_F']='/fo'
+ v['WINRC_SRC_F']=''
+ else:
+ conf.find_program('windres',var='WINRC',path_list=v['PATH'])
+ if not conf.env.WINRC:
+ conf.fatal('winrc was not found!')
+ v['WINRCFLAGS']=[]
diff --git a/waflib/Tools/xlc.py b/waflib/Tools/xlc.py
new file mode 100644
index 0000000..c56443b
--- /dev/null
+++ b/waflib/Tools/xlc.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_xlc(conf):
+ cc=conf.find_program(['xlc_r','xlc'],var='CC')
+ conf.get_xlc_version(cc)
+ conf.env.CC_NAME='xlc'
+@conf
+def xlc_common_flags(conf):
+ v=conf.env
+ v['CC_SRC_F']=[]
+ v['CC_TGT_F']=['-c','-o']
+ if not v['LINK_CC']:v['LINK_CC']=v['CC']
+ v['CCLNK_SRC_F']=[]
+ v['CCLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['RPATH_ST']='-Wl,-rpath,%s'
+ v['SONAME_ST']=[]
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['LINKFLAGS_cprogram']=['-Wl,-brtl']
+ v['cprogram_PATTERN']='%s'
+ v['CFLAGS_cshlib']=['-fPIC']
+ v['LINKFLAGS_cshlib']=['-G','-Wl,-brtl,-bexpfull']
+ v['cshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cstlib']=[]
+ v['cstlib_PATTERN']='lib%s.a'
+def configure(conf):
+ conf.find_xlc()
+ conf.find_ar()
+ conf.xlc_common_flags()
+ conf.cc_load_tools()
+ conf.cc_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Tools/xlcxx.py b/waflib/Tools/xlcxx.py
new file mode 100644
index 0000000..f348bbf
--- /dev/null
+++ b/waflib/Tools/xlcxx.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+@conf
+def find_xlcxx(conf):
+ cxx=conf.find_program(['xlc++_r','xlc++'],var='CXX')
+ conf.get_xlc_version(cxx)
+ conf.env.CXX_NAME='xlc++'
+@conf
+def xlcxx_common_flags(conf):
+ v=conf.env
+ v['CXX_SRC_F']=[]
+ v['CXX_TGT_F']=['-c','-o']
+ if not v['LINK_CXX']:v['LINK_CXX']=v['CXX']
+ v['CXXLNK_SRC_F']=[]
+ v['CXXLNK_TGT_F']=['-o']
+ v['CPPPATH_ST']='-I%s'
+ v['DEFINES_ST']='-D%s'
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STLIB_ST']='-l%s'
+ v['STLIBPATH_ST']='-L%s'
+ v['RPATH_ST']='-Wl,-rpath,%s'
+ v['SONAME_ST']=[]
+ v['SHLIB_MARKER']=[]
+ v['STLIB_MARKER']=[]
+ v['LINKFLAGS_cxxprogram']=['-Wl,-brtl']
+ v['cxxprogram_PATTERN']='%s'
+ v['CXXFLAGS_cxxshlib']=['-fPIC']
+ v['LINKFLAGS_cxxshlib']=['-G','-Wl,-brtl,-bexpfull']
+ v['cxxshlib_PATTERN']='lib%s.so'
+ v['LINKFLAGS_cxxstlib']=[]
+ v['cxxstlib_PATTERN']='lib%s.a'
+def configure(conf):
+ conf.find_xlcxx()
+ conf.find_ar()
+ conf.xlcxx_common_flags()
+ conf.cxx_load_tools()
+ conf.cxx_add_flags()
+ conf.link_add_flags()
diff --git a/waflib/Utils.py b/waflib/Utils.py
new file mode 100644
index 0000000..6c2a8e0
--- /dev/null
+++ b/waflib/Utils.py
@@ -0,0 +1,468 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,sys,errno,traceback,inspect,re,shutil,datetime,gc,platform
+import subprocess
+from collections import deque,defaultdict
+try:
+ import _winreg as winreg
+except ImportError:
+ try:
+ import winreg
+ except ImportError:
+ winreg=None
+from waflib import Errors
+try:
+ from collections import UserDict
+except ImportError:
+ from UserDict import UserDict
+try:
+ from hashlib import md5
+except ImportError:
+ try:
+ from md5 import md5
+ except ImportError:
+ pass
+try:
+ import threading
+except ImportError:
+ if not'JOBS'in os.environ:
+ os.environ['JOBS']='1'
+ class threading(object):
+ pass
+ class Lock(object):
+ def acquire(self):
+ pass
+ def release(self):
+ pass
+ threading.Lock=threading.Thread=Lock
+else:
+ run_old=threading.Thread.run
+ def run(*args,**kwargs):
+ try:
+ run_old(*args,**kwargs)
+ except(KeyboardInterrupt,SystemExit):
+ raise
+ except Exception:
+ sys.excepthook(*sys.exc_info())
+ threading.Thread.run=run
+SIG_NIL='iluvcuteoverload'
+O644=420
+O755=493
+rot_chr=['\\','|','/','-']
+rot_idx=0
+try:
+ from collections import OrderedDict as ordered_iter_dict
+except ImportError:
+ class ordered_iter_dict(dict):
+ def __init__(self,*k,**kw):
+ self.lst=[]
+ dict.__init__(self,*k,**kw)
+ def clear(self):
+ dict.clear(self)
+ self.lst=[]
+ def __setitem__(self,key,value):
+ dict.__setitem__(self,key,value)
+ try:
+ self.lst.remove(key)
+ except ValueError:
+ pass
+ self.lst.append(key)
+ def __delitem__(self,key):
+ dict.__delitem__(self,key)
+ try:
+ self.lst.remove(key)
+ except ValueError:
+ pass
+ def __iter__(self):
+ for x in self.lst:
+ yield x
+ def keys(self):
+ return self.lst
+is_win32=os.sep=='\\'or sys.platform=='win32'
+def readf(fname,m='r',encoding='ISO8859-1'):
+ if sys.hexversion>0x3000000 and not'b'in m:
+ m+='b'
+ f=open(fname,m)
+ try:
+ txt=f.read()
+ finally:
+ f.close()
+ if encoding:
+ txt=txt.decode(encoding)
+ else:
+ txt=txt.decode()
+ else:
+ f=open(fname,m)
+ try:
+ txt=f.read()
+ finally:
+ f.close()
+ return txt
+def writef(fname,data,m='w',encoding='ISO8859-1'):
+ if sys.hexversion>0x3000000 and not'b'in m:
+ data=data.encode(encoding)
+ m+='b'
+ f=open(fname,m)
+ try:
+ f.write(data)
+ finally:
+ f.close()
+def h_file(fname):
+ f=open(fname,'rb')
+ m=md5()
+ try:
+ while fname:
+ fname=f.read(200000)
+ m.update(fname)
+ finally:
+ f.close()
+ return m.digest()
+def readf_win32(f,m='r',encoding='ISO8859-1'):
+ flags=os.O_NOINHERIT|os.O_RDONLY
+ if'b'in m:
+ flags|=os.O_BINARY
+ if'+'in m:
+ flags|=os.O_RDWR
+ try:
+ fd=os.open(f,flags)
+ except OSError:
+ raise IOError('Cannot read from %r'%f)
+ if sys.hexversion>0x3000000 and not'b'in m:
+ m+='b'
+ f=os.fdopen(fd,m)
+ try:
+ txt=f.read()
+ finally:
+ f.close()
+ if encoding:
+ txt=txt.decode(encoding)
+ else:
+ txt=txt.decode()
+ else:
+ f=os.fdopen(fd,m)
+ try:
+ txt=f.read()
+ finally:
+ f.close()
+ return txt
+def writef_win32(f,data,m='w',encoding='ISO8859-1'):
+ if sys.hexversion>0x3000000 and not'b'in m:
+ data=data.encode(encoding)
+ m+='b'
+ flags=os.O_CREAT|os.O_TRUNC|os.O_WRONLY|os.O_NOINHERIT
+ if'b'in m:
+ flags|=os.O_BINARY
+ if'+'in m:
+ flags|=os.O_RDWR
+ try:
+ fd=os.open(f,flags)
+ except OSError:
+ raise IOError('Cannot write to %r'%f)
+ f=os.fdopen(fd,m)
+ try:
+ f.write(data)
+ finally:
+ f.close()
+def h_file_win32(fname):
+ try:
+ fd=os.open(fname,os.O_BINARY|os.O_RDONLY|os.O_NOINHERIT)
+ except OSError:
+ raise IOError('Cannot read from %r'%fname)
+ f=os.fdopen(fd,'rb')
+ m=md5()
+ try:
+ while fname:
+ fname=f.read(200000)
+ m.update(fname)
+ finally:
+ f.close()
+ return m.digest()
+readf_unix=readf
+writef_unix=writef
+h_file_unix=h_file
+if hasattr(os,'O_NOINHERIT')and sys.hexversion<0x3040000:
+ readf=readf_win32
+ writef=writef_win32
+ h_file=h_file_win32
+try:
+ x=''.encode('hex')
+except LookupError:
+ import binascii
+ def to_hex(s):
+ ret=binascii.hexlify(s)
+ if not isinstance(ret,str):
+ ret=ret.decode('utf-8')
+ return ret
+else:
+ def to_hex(s):
+ return s.encode('hex')
+to_hex.__doc__="""
+Return the hexadecimal representation of a string
+
+:param s: string to convert
+:type s: string
+"""
+def listdir_win32(s):
+ if not s:
+ try:
+ import ctypes
+ except ImportError:
+ return[x+':\\'for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')]
+ else:
+ dlen=4
+ maxdrives=26
+ buf=ctypes.create_string_buffer(maxdrives*dlen)
+ ndrives=ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen,ctypes.byref(buf))
+ return[str(buf.raw[4*i:4*i+2].decode('ascii'))for i in range(int(ndrives/dlen))]
+ if len(s)==2 and s[1]==":":
+ s+=os.sep
+ if not os.path.isdir(s):
+ e=OSError('%s is not a directory'%s)
+ e.errno=errno.ENOENT
+ raise e
+ return os.listdir(s)
+listdir=os.listdir
+if is_win32:
+ listdir=listdir_win32
+def num2ver(ver):
+ if isinstance(ver,str):
+ ver=tuple(ver.split('.'))
+ if isinstance(ver,tuple):
+ ret=0
+ for i in range(4):
+ if i<len(ver):
+ ret+=256**(3-i)*int(ver[i])
+ return ret
+ return ver
+def ex_stack():
+ exc_type,exc_value,tb=sys.exc_info()
+ exc_lines=traceback.format_exception(exc_type,exc_value,tb)
+ return''.join(exc_lines)
+def to_list(sth):
+ if isinstance(sth,str):
+ return sth.split()
+ else:
+ return sth
+def split_path_unix(path):
+ return path.split('/')
+def split_path_cygwin(path):
+ if path.startswith('//'):
+ ret=path.split('/')[2:]
+ ret[0]='/'+ret[0]
+ return ret
+ return path.split('/')
+re_sp=re.compile('[/\\\\]')
+def split_path_win32(path):
+ if path.startswith('\\\\'):
+ ret=re.split(re_sp,path)[2:]
+ ret[0]='\\'+ret[0]
+ return ret
+ return re.split(re_sp,path)
+msysroot=None
+def split_path_msys(path):
+ if(path.startswith('/')or path.startswith('\\'))and not path.startswith('//')and not path.startswith('\\\\'):
+ global msysroot
+ if not msysroot:
+ msysroot=subprocess.check_output(['cygpath','-w','/']).decode(sys.stdout.encoding or'iso8859-1')
+ msysroot=msysroot.strip()
+ path=os.path.normpath(msysroot+os.sep+path)
+ return split_path_win32(path)
+if sys.platform=='cygwin':
+ split_path=split_path_cygwin
+elif is_win32:
+ if os.environ.get('MSYSTEM',None):
+ split_path=split_path_msys
+ else:
+ split_path=split_path_win32
+else:
+ split_path=split_path_unix
+split_path.__doc__="""
+Split a path by / or \\. This function is not like os.path.split
+
+:type path: string
+:param path: path to split
+:return: list of strings
+"""
+def check_dir(path):
+ if not os.path.isdir(path):
+ try:
+ os.makedirs(path)
+ except OSError ,e:
+ if not os.path.isdir(path):
+ raise Errors.WafError('Cannot create the folder %r'%path,ex=e)
+def check_exe(name,env=None):
+ if not name:
+ raise ValueError('Cannot execute an empty string!')
+ def is_exe(fpath):
+ return os.path.isfile(fpath)and os.access(fpath,os.X_OK)
+ fpath,fname=os.path.split(name)
+ if fpath and is_exe(name):
+ return os.path.abspath(name)
+ else:
+ env=env or os.environ
+ for path in env["PATH"].split(os.pathsep):
+ path=path.strip('"')
+ exe_file=os.path.join(path,name)
+ if is_exe(exe_file):
+ return os.path.abspath(exe_file)
+ return None
+def def_attrs(cls,**kw):
+ for k,v in kw.items():
+ if not hasattr(cls,k):
+ setattr(cls,k,v)
+def quote_define_name(s):
+ fu=re.sub('[^a-zA-Z0-9]','_',s)
+ fu=re.sub('_+','_',fu)
+ fu=fu.upper()
+ return fu
+def h_list(lst):
+ m=md5()
+ m.update(str(lst))
+ return m.digest()
+def h_fun(fun):
+ try:
+ return fun.code
+ except AttributeError:
+ try:
+ h=inspect.getsource(fun)
+ except IOError:
+ h="nocode"
+ try:
+ fun.code=h
+ except AttributeError:
+ pass
+ return h
+def h_cmd(ins):
+ if isinstance(ins,str):
+ ret=ins
+ elif isinstance(ins,list)or isinstance(ins,tuple):
+ ret=str([h_cmd(x)for x in ins])
+ else:
+ ret=str(h_fun(ins))
+ if sys.hexversion>0x3000000:
+ ret=ret.encode('iso8859-1','xmlcharrefreplace')
+ return ret
+reg_subst=re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
+def subst_vars(expr,params):
+ def repl_var(m):
+ if m.group(1):
+ return'\\'
+ if m.group(2):
+ return'$'
+ try:
+ return params.get_flat(m.group(3))
+ except AttributeError:
+ return params[m.group(3)]
+ return reg_subst.sub(repl_var,expr)
+def destos_to_binfmt(key):
+ if key=='darwin':
+ return'mac-o'
+ elif key in('win32','cygwin','uwin','msys'):
+ return'pe'
+ return'elf'
+def unversioned_sys_platform():
+ s=sys.platform
+ if s.startswith('java'):
+ from java.lang import System
+ s=System.getProperty('os.name')
+ if s=='Mac OS X':
+ return'darwin'
+ elif s.startswith('Windows '):
+ return'win32'
+ elif s=='OS/2':
+ return'os2'
+ elif s=='HP-UX':
+ return'hp-ux'
+ elif s in('SunOS','Solaris'):
+ return'sunos'
+ else:s=s.lower()
+ if s=='powerpc':
+ return'darwin'
+ if s=='win32'or s=='os2':
+ return s
+ if s=='cli'and os.name=='nt':
+ return'win32'
+ return re.split('\d+$',s)[0]
+def nada(*k,**kw):
+ pass
+class Timer(object):
+ def __init__(self):
+ self.start_time=datetime.datetime.utcnow()
+ def __str__(self):
+ delta=datetime.datetime.utcnow()-self.start_time
+ days=delta.days
+ hours,rem=divmod(delta.seconds,3600)
+ minutes,seconds=divmod(rem,60)
+ seconds+=delta.microseconds*1e-6
+ result=''
+ if days:
+ result+='%dd'%days
+ if days or hours:
+ result+='%dh'%hours
+ if days or hours or minutes:
+ result+='%dm'%minutes
+ return'%s%.3fs'%(result,seconds)
+if is_win32:
+ old=shutil.copy2
+ def copy2(src,dst):
+ old(src,dst)
+ shutil.copystat(src,dst)
+ setattr(shutil,'copy2',copy2)
+if os.name=='java':
+ try:
+ gc.disable()
+ gc.enable()
+ except NotImplementedError:
+ gc.disable=gc.enable
+def read_la_file(path):
+ sp=re.compile(r'^([^=]+)=\'(.*)\'$')
+ dc={}
+ for line in readf(path).splitlines():
+ try:
+ _,left,right,_=sp.split(line.strip())
+ dc[left]=right
+ except ValueError:
+ pass
+ return dc
+def nogc(fun):
+ def f(*k,**kw):
+ try:
+ gc.disable()
+ ret=fun(*k,**kw)
+ finally:
+ gc.enable()
+ return ret
+ f.__doc__=fun.__doc__
+ return f
+def run_once(fun):
+ cache={}
+ def wrap(k):
+ try:
+ return cache[k]
+ except KeyError:
+ ret=fun(k)
+ cache[k]=ret
+ return ret
+ wrap.__cache__=cache
+ wrap.__name__=fun.__name__
+ return wrap
+def get_registry_app_path(key,filename):
+ if not winreg:
+ return None
+ try:
+ result=winreg.QueryValue(key,"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe"%filename[0])
+ except WindowsError:
+ pass
+ else:
+ if os.path.isfile(result):
+ return result
+def lib64():
+ if os.sep=='/':
+ if platform.architecture()[0]=='64bit':
+ if os.path.exists('/usr/lib64')and not os.path.exists('/usr/lib32'):
+ return'64'
+ return''
+def sane_path(p):
+ return os.path.abspath(os.path.expanduser(p))
diff --git a/waflib/__init__.py b/waflib/__init__.py
new file mode 100644
index 0000000..55e850d
--- /dev/null
+++ b/waflib/__init__.py
@@ -0,0 +1,4 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
diff --git a/waflib/ansiterm.py b/waflib/ansiterm.py
new file mode 100644
index 0000000..8de767d
--- /dev/null
+++ b/waflib/ansiterm.py
@@ -0,0 +1,238 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os,re,sys
+from waflib import Utils
+wlock=Utils.threading.Lock()
+try:
+ from ctypes import Structure,windll,c_short,c_ushort,c_ulong,c_int,byref,c_wchar,POINTER,c_long
+except ImportError:
+ class AnsiTerm(object):
+ def __init__(self,stream):
+ self.stream=stream
+ try:
+ self.errors=self.stream.errors
+ except AttributeError:
+ pass
+ self.encoding=self.stream.encoding
+ def write(self,txt):
+ try:
+ wlock.acquire()
+ self.stream.write(txt)
+ self.stream.flush()
+ finally:
+ wlock.release()
+ def fileno(self):
+ return self.stream.fileno()
+ def flush(self):
+ self.stream.flush()
+ def isatty(self):
+ return self.stream.isatty()
+else:
+ class COORD(Structure):
+ _fields_=[("X",c_short),("Y",c_short)]
+ class SMALL_RECT(Structure):
+ _fields_=[("Left",c_short),("Top",c_short),("Right",c_short),("Bottom",c_short)]
+ class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+ _fields_=[("Size",COORD),("CursorPosition",COORD),("Attributes",c_ushort),("Window",SMALL_RECT),("MaximumWindowSize",COORD)]
+ class CONSOLE_CURSOR_INFO(Structure):
+ _fields_=[('dwSize',c_ulong),('bVisible',c_int)]
+ try:
+ _type=unicode
+ except NameError:
+ _type=str
+ to_int=lambda number,default:number and int(number)or default
+ STD_OUTPUT_HANDLE=-11
+ STD_ERROR_HANDLE=-12
+ windll.kernel32.GetStdHandle.argtypes=[c_ulong]
+ windll.kernel32.GetStdHandle.restype=c_ulong
+ windll.kernel32.GetConsoleScreenBufferInfo.argtypes=[c_ulong,POINTER(CONSOLE_SCREEN_BUFFER_INFO)]
+ windll.kernel32.GetConsoleScreenBufferInfo.restype=c_long
+ windll.kernel32.SetConsoleTextAttribute.argtypes=[c_ulong,c_ushort]
+ windll.kernel32.SetConsoleTextAttribute.restype=c_long
+ windll.kernel32.FillConsoleOutputCharacterW.argtypes=[c_ulong,c_wchar,c_ulong,POINTER(COORD),POINTER(c_ulong)]
+ windll.kernel32.FillConsoleOutputCharacterW.restype=c_long
+ windll.kernel32.FillConsoleOutputAttribute.argtypes=[c_ulong,c_ushort,c_ulong,POINTER(COORD),POINTER(c_ulong)]
+ windll.kernel32.FillConsoleOutputAttribute.restype=c_long
+ windll.kernel32.SetConsoleCursorPosition.argtypes=[c_ulong,POINTER(COORD)]
+ windll.kernel32.SetConsoleCursorPosition.restype=c_long
+ windll.kernel32.SetConsoleCursorInfo.argtypes=[c_ulong,POINTER(CONSOLE_CURSOR_INFO)]
+ windll.kernel32.SetConsoleCursorInfo.restype=c_long
+ class AnsiTerm(object):
+ def __init__(self,s):
+ self.stream=s
+ try:
+ self.errors=s.errors
+ except AttributeError:
+ pass
+ self.encoding=s.encoding
+ self.cursor_history=[]
+ handle=(s.fileno()==2)and STD_ERROR_HANDLE or STD_OUTPUT_HANDLE
+ self.hconsole=windll.kernel32.GetStdHandle(handle)
+ self._sbinfo=CONSOLE_SCREEN_BUFFER_INFO()
+ self._csinfo=CONSOLE_CURSOR_INFO()
+ windll.kernel32.GetConsoleCursorInfo(self.hconsole,byref(self._csinfo))
+ self._orig_sbinfo=CONSOLE_SCREEN_BUFFER_INFO()
+ r=windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(self._orig_sbinfo))
+ self._isatty=r==1
+ def screen_buffer_info(self):
+ windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole,byref(self._sbinfo))
+ return self._sbinfo
+ def clear_line(self,param):
+ mode=param and int(param)or 0
+ sbinfo=self.screen_buffer_info()
+ if mode==1:
+ line_start=COORD(0,sbinfo.CursorPosition.Y)
+ line_length=sbinfo.Size.X
+ elif mode==2:
+ line_start=COORD(sbinfo.CursorPosition.X,sbinfo.CursorPosition.Y)
+ line_length=sbinfo.Size.X-sbinfo.CursorPosition.X
+ else:
+ line_start=sbinfo.CursorPosition
+ line_length=sbinfo.Size.X-sbinfo.CursorPosition.X
+ chars_written=c_ulong()
+ windll.kernel32.FillConsoleOutputCharacterW(self.hconsole,c_wchar(' '),line_length,line_start,byref(chars_written))
+ windll.kernel32.FillConsoleOutputAttribute(self.hconsole,sbinfo.Attributes,line_length,line_start,byref(chars_written))
+ def clear_screen(self,param):
+ mode=to_int(param,0)
+ sbinfo=self.screen_buffer_info()
+ if mode==1:
+ clear_start=COORD(0,0)
+ clear_length=sbinfo.CursorPosition.X*sbinfo.CursorPosition.Y
+ elif mode==2:
+ clear_start=COORD(0,0)
+ clear_length=sbinfo.Size.X*sbinfo.Size.Y
+ windll.kernel32.SetConsoleCursorPosition(self.hconsole,clear_start)
+ else:
+ clear_start=sbinfo.CursorPosition
+ clear_length=((sbinfo.Size.X-sbinfo.CursorPosition.X)+sbinfo.Size.X*(sbinfo.Size.Y-sbinfo.CursorPosition.Y))
+ chars_written=c_ulong()
+ windll.kernel32.FillConsoleOutputCharacterW(self.hconsole,c_wchar(' '),clear_length,clear_start,byref(chars_written))
+ windll.kernel32.FillConsoleOutputAttribute(self.hconsole,sbinfo.Attributes,clear_length,clear_start,byref(chars_written))
+ def push_cursor(self,param):
+ sbinfo=self.screen_buffer_info()
+ self.cursor_history.append(sbinfo.CursorPosition)
+ def pop_cursor(self,param):
+ if self.cursor_history:
+ old_pos=self.cursor_history.pop()
+ windll.kernel32.SetConsoleCursorPosition(self.hconsole,old_pos)
+ def set_cursor(self,param):
+ y,sep,x=param.partition(';')
+ x=to_int(x,1)-1
+ y=to_int(y,1)-1
+ sbinfo=self.screen_buffer_info()
+ new_pos=COORD(min(max(0,x),sbinfo.Size.X),min(max(0,y),sbinfo.Size.Y))
+ windll.kernel32.SetConsoleCursorPosition(self.hconsole,new_pos)
+ def set_column(self,param):
+ x=to_int(param,1)-1
+ sbinfo=self.screen_buffer_info()
+ new_pos=COORD(min(max(0,x),sbinfo.Size.X),sbinfo.CursorPosition.Y)
+ windll.kernel32.SetConsoleCursorPosition(self.hconsole,new_pos)
+ def move_cursor(self,x_offset=0,y_offset=0):
+ sbinfo=self.screen_buffer_info()
+ new_pos=COORD(min(max(0,sbinfo.CursorPosition.X+x_offset),sbinfo.Size.X),min(max(0,sbinfo.CursorPosition.Y+y_offset),sbinfo.Size.Y))
+ windll.kernel32.SetConsoleCursorPosition(self.hconsole,new_pos)
+ def move_up(self,param):
+ self.move_cursor(y_offset=-to_int(param,1))
+ def move_down(self,param):
+ self.move_cursor(y_offset=to_int(param,1))
+ def move_left(self,param):
+ self.move_cursor(x_offset=-to_int(param,1))
+ def move_right(self,param):
+ self.move_cursor(x_offset=to_int(param,1))
+ def next_line(self,param):
+ sbinfo=self.screen_buffer_info()
+ self.move_cursor(x_offset=-sbinfo.CursorPosition.X,y_offset=to_int(param,1))
+ def prev_line(self,param):
+ sbinfo=self.screen_buffer_info()
+ self.move_cursor(x_offset=-sbinfo.CursorPosition.X,y_offset=-to_int(param,1))
+ def rgb2bgr(self,c):
+ return((c&1)<<2)|(c&2)|((c&4)>>2)
+ def set_color(self,param):
+ cols=param.split(';')
+ sbinfo=self.screen_buffer_info()
+ attr=sbinfo.Attributes
+ for c in cols:
+ c=to_int(c,0)
+ if 29<c<38:
+ attr=(attr&0xfff0)|self.rgb2bgr(c-30)
+ elif 39<c<48:
+ attr=(attr&0xff0f)|(self.rgb2bgr(c-40)<<4)
+ elif c==0:
+ attr=self._orig_sbinfo.Attributes
+ elif c==1:
+ attr|=0x08
+ elif c==4:
+ attr|=0x80
+ elif c==7:
+ attr=(attr&0xff88)|((attr&0x70)>>4)|((attr&0x07)<<4)
+ windll.kernel32.SetConsoleTextAttribute(self.hconsole,attr)
+ def show_cursor(self,param):
+ self._csinfo.bVisible=1
+ windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(self._csinfo))
+ def hide_cursor(self,param):
+ self._csinfo.bVisible=0
+ windll.kernel32.SetConsoleCursorInfo(self.hconsole,byref(self._csinfo))
+ ansi_command_table={'A':move_up,'B':move_down,'C':move_right,'D':move_left,'E':next_line,'F':prev_line,'G':set_column,'H':set_cursor,'f':set_cursor,'J':clear_screen,'K':clear_line,'h':show_cursor,'l':hide_cursor,'m':set_color,'s':push_cursor,'u':pop_cursor,}
+ ansi_tokens=re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))')
+ def write(self,text):
+ try:
+ wlock.acquire()
+ if self._isatty:
+ for param,cmd,txt in self.ansi_tokens.findall(text):
+ if cmd:
+ cmd_func=self.ansi_command_table.get(cmd)
+ if cmd_func:
+ cmd_func(self,param)
+ else:
+ self.writeconsole(txt)
+ else:
+ self.stream.write(text)
+ finally:
+ wlock.release()
+ def writeconsole(self,txt):
+ chars_written=c_ulong()
+ writeconsole=windll.kernel32.WriteConsoleA
+ if isinstance(txt,_type):
+ writeconsole=windll.kernel32.WriteConsoleW
+ done=0
+ todo=len(txt)
+ chunk=32<<10
+ while todo!=0:
+ doing=min(chunk,todo)
+ buf=txt[done:done+doing]
+ r=writeconsole(self.hconsole,buf,doing,byref(chars_written),None)
+ if r==0:
+ chunk>>=1
+ continue
+ done+=doing
+ todo-=doing
+ def fileno(self):
+ return self.stream.fileno()
+ def flush(self):
+ pass
+ def isatty(self):
+ return self._isatty
+ if sys.stdout.isatty()or sys.stderr.isatty():
+ handle=sys.stdout.isatty()and STD_OUTPUT_HANDLE or STD_ERROR_HANDLE
+ console=windll.kernel32.GetStdHandle(handle)
+ sbinfo=CONSOLE_SCREEN_BUFFER_INFO()
+ def get_term_cols():
+ windll.kernel32.GetConsoleScreenBufferInfo(console,byref(sbinfo))
+ return sbinfo.Size.X-1
+try:
+ import struct,fcntl,termios
+except ImportError:
+ pass
+else:
+ if(sys.stdout.isatty()or sys.stderr.isatty())and os.environ.get('TERM','')not in('dumb','emacs'):
+ FD=sys.stdout.isatty()and sys.stdout.fileno()or sys.stderr.fileno()
+ def fun():
+ return struct.unpack("HHHH",fcntl.ioctl(FD,termios.TIOCGWINSZ,struct.pack("HHHH",0,0,0,0)))[1]
+ try:
+ fun()
+ except Exception ,e:
+ pass
+ else:
+ get_term_cols=fun
diff --git a/waflib/extras/__init__.py b/waflib/extras/__init__.py
new file mode 100644
index 0000000..55e850d
--- /dev/null
+++ b/waflib/extras/__init__.py
@@ -0,0 +1,4 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
diff --git a/waflib/extras/compat15.py b/waflib/extras/compat15.py
new file mode 100644
index 0000000..aa30079
--- /dev/null
+++ b/waflib/extras/compat15.py
@@ -0,0 +1,301 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import sys
+from waflib import ConfigSet,Logs,Options,Scripting,Task,Build,Configure,Node,Runner,TaskGen,Utils,Errors,Context
+sys.modules['Environment']=ConfigSet
+ConfigSet.Environment=ConfigSet.ConfigSet
+sys.modules['Logs']=Logs
+sys.modules['Options']=Options
+sys.modules['Scripting']=Scripting
+sys.modules['Task']=Task
+sys.modules['Build']=Build
+sys.modules['Configure']=Configure
+sys.modules['Node']=Node
+sys.modules['Runner']=Runner
+sys.modules['TaskGen']=TaskGen
+sys.modules['Utils']=Utils
+sys.modules['Constants']=Context
+Context.SRCDIR=''
+Context.BLDDIR=''
+from waflib.Tools import c_preproc
+sys.modules['preproc']=c_preproc
+from waflib.Tools import c_config
+sys.modules['config_c']=c_config
+ConfigSet.ConfigSet.copy=ConfigSet.ConfigSet.derive
+ConfigSet.ConfigSet.set_variant=Utils.nada
+Utils.pproc=Utils.subprocess
+Build.BuildContext.add_subdirs=Build.BuildContext.recurse
+Build.BuildContext.new_task_gen=Build.BuildContext.__call__
+Build.BuildContext.is_install=0
+Node.Node.relpath_gen=Node.Node.path_from
+Utils.pproc=Utils.subprocess
+Utils.get_term_cols=Logs.get_term_cols
+def cmd_output(cmd,**kw):
+ silent=False
+ if'silent'in kw:
+ silent=kw['silent']
+ del(kw['silent'])
+ if'e'in kw:
+ tmp=kw['e']
+ del(kw['e'])
+ kw['env']=tmp
+ kw['shell']=isinstance(cmd,str)
+ kw['stdout']=Utils.subprocess.PIPE
+ if silent:
+ kw['stderr']=Utils.subprocess.PIPE
+ try:
+ p=Utils.subprocess.Popen(cmd,**kw)
+ output=p.communicate()[0]
+ except OSError ,e:
+ raise ValueError(str(e))
+ if p.returncode:
+ if not silent:
+ msg="command execution failed: %s -> %r"%(cmd,str(output))
+ raise ValueError(msg)
+ output=''
+ return output
+Utils.cmd_output=cmd_output
+def name_to_obj(self,s,env=None):
+ if Logs.verbose:
+ Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"')
+ return self.get_tgen_by_name(s)
+Build.BuildContext.name_to_obj=name_to_obj
+def env_of_name(self,name):
+ try:
+ return self.all_envs[name]
+ except KeyError:
+ Logs.error('no such environment: '+name)
+ return None
+Build.BuildContext.env_of_name=env_of_name
+def set_env_name(self,name,env):
+ self.all_envs[name]=env
+ return env
+Configure.ConfigurationContext.set_env_name=set_env_name
+def retrieve(self,name,fromenv=None):
+ try:
+ env=self.all_envs[name]
+ except KeyError:
+ env=ConfigSet.ConfigSet()
+ self.prepare_env(env)
+ self.all_envs[name]=env
+ else:
+ if fromenv:
+ Logs.warn("The environment %s may have been configured already"%name)
+ return env
+Configure.ConfigurationContext.retrieve=retrieve
+Configure.ConfigurationContext.sub_config=Configure.ConfigurationContext.recurse
+Configure.ConfigurationContext.check_tool=Configure.ConfigurationContext.load
+Configure.conftest=Configure.conf
+Configure.ConfigurationError=Errors.ConfigurationError
+Utils.WafError=Errors.WafError
+Options.OptionsContext.sub_options=Options.OptionsContext.recurse
+Options.OptionsContext.tool_options=Context.Context.load
+Options.Handler=Options.OptionsContext
+Task.simple_task_type=Task.task_type_from_func=Task.task_factory
+Task.TaskBase.classes=Task.classes
+def setitem(self,key,value):
+ if key.startswith('CCFLAGS'):
+ key=key[1:]
+ self.table[key]=value
+ConfigSet.ConfigSet.__setitem__=setitem
+@TaskGen.feature('d')
+@TaskGen.before('apply_incpaths')
+def old_importpaths(self):
+ if getattr(self,'importpaths',[]):
+ self.includes=self.importpaths
+from waflib import Context
+eld=Context.load_tool
+def load_tool(*k,**kw):
+ ret=eld(*k,**kw)
+ if'set_options'in ret.__dict__:
+ if Logs.verbose:
+ Logs.warn('compat: rename "set_options" to options')
+ ret.options=ret.set_options
+ if'detect'in ret.__dict__:
+ if Logs.verbose:
+ Logs.warn('compat: rename "detect" to "configure"')
+ ret.configure=ret.detect
+ return ret
+Context.load_tool=load_tool
+def get_curdir(self):
+ return self.path.abspath()
+Context.Context.curdir=property(get_curdir,Utils.nada)
+def get_srcdir(self):
+ return self.srcnode.abspath()
+Configure.ConfigurationContext.srcdir=property(get_srcdir,Utils.nada)
+def get_blddir(self):
+ return self.bldnode.abspath()
+Configure.ConfigurationContext.blddir=property(get_blddir,Utils.nada)
+Configure.ConfigurationContext.check_message_1=Configure.ConfigurationContext.start_msg
+Configure.ConfigurationContext.check_message_2=Configure.ConfigurationContext.end_msg
+rev=Context.load_module
+def load_module(path,encoding=None):
+ ret=rev(path,encoding)
+ if'set_options'in ret.__dict__:
+ if Logs.verbose:
+ Logs.warn('compat: rename "set_options" to "options" (%r)'%path)
+ ret.options=ret.set_options
+ if'srcdir'in ret.__dict__:
+ if Logs.verbose:
+ Logs.warn('compat: rename "srcdir" to "top" (%r)'%path)
+ ret.top=ret.srcdir
+ if'blddir'in ret.__dict__:
+ if Logs.verbose:
+ Logs.warn('compat: rename "blddir" to "out" (%r)'%path)
+ ret.out=ret.blddir
+ Utils.g_module=Context.g_module
+ Options.launch_dir=Context.launch_dir
+ return ret
+Context.load_module=load_module
+old_post=TaskGen.task_gen.post
+def post(self):
+ self.features=self.to_list(self.features)
+ if'cc'in self.features:
+ if Logs.verbose:
+ Logs.warn('compat: the feature cc does not exist anymore (use "c")')
+ self.features.remove('cc')
+ self.features.append('c')
+ if'cstaticlib'in self.features:
+ if Logs.verbose:
+ Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")')
+ self.features.remove('cstaticlib')
+ self.features.append(('cxx'in self.features)and'cxxstlib'or'cstlib')
+ if getattr(self,'ccflags',None):
+ if Logs.verbose:
+ Logs.warn('compat: "ccflags" was renamed to "cflags"')
+ self.cflags=self.ccflags
+ return old_post(self)
+TaskGen.task_gen.post=post
+def waf_version(*k,**kw):
+ Logs.warn('wrong version (waf_version was removed in waf 1.6)')
+Utils.waf_version=waf_version
+import os
+@TaskGen.feature('c','cxx','d')
+@TaskGen.before('apply_incpaths','propagate_uselib_vars')
+@TaskGen.after('apply_link','process_source')
+def apply_uselib_local(self):
+ env=self.env
+ from waflib.Tools.ccroot import stlink_task
+ self.uselib=self.to_list(getattr(self,'uselib',[]))
+ self.includes=self.to_list(getattr(self,'includes',[]))
+ names=self.to_list(getattr(self,'uselib_local',[]))
+ get=self.bld.get_tgen_by_name
+ seen=set([])
+ seen_uselib=set([])
+ tmp=Utils.deque(names)
+ if tmp:
+ if Logs.verbose:
+ Logs.warn('compat: "uselib_local" is deprecated, replace by "use"')
+ while tmp:
+ lib_name=tmp.popleft()
+ if lib_name in seen:
+ continue
+ y=get(lib_name)
+ y.post()
+ seen.add(lib_name)
+ if getattr(y,'uselib_local',None):
+ for x in self.to_list(getattr(y,'uselib_local',[])):
+ obj=get(x)
+ obj.post()
+ if getattr(obj,'link_task',None):
+ if not isinstance(obj.link_task,stlink_task):
+ tmp.append(x)
+ if getattr(y,'link_task',None):
+ link_name=y.target[y.target.rfind(os.sep)+1:]
+ if isinstance(y.link_task,stlink_task):
+ env.append_value('STLIB',[link_name])
+ else:
+ env.append_value('LIB',[link_name])
+ self.link_task.set_run_after(y.link_task)
+ self.link_task.dep_nodes+=y.link_task.outputs
+ tmp_path=y.link_task.outputs[0].parent.bldpath()
+ if not tmp_path in env['LIBPATH']:
+ env.prepend_value('LIBPATH',[tmp_path])
+ for v in self.to_list(getattr(y,'uselib',[])):
+ if v not in seen_uselib:
+ seen_uselib.add(v)
+ if not env['STLIB_'+v]:
+ if not v in self.uselib:
+ self.uselib.insert(0,v)
+ if getattr(y,'export_includes',None):
+ self.includes.extend(y.to_incnodes(y.export_includes))
+@TaskGen.feature('cprogram','cxxprogram','cstlib','cxxstlib','cshlib','cxxshlib','dprogram','dstlib','dshlib')
+@TaskGen.after('apply_link')
+def apply_objdeps(self):
+ names=getattr(self,'add_objects',[])
+ if not names:
+ return
+ names=self.to_list(names)
+ get=self.bld.get_tgen_by_name
+ seen=[]
+ while names:
+ x=names[0]
+ if x in seen:
+ names=names[1:]
+ continue
+ y=get(x)
+ if getattr(y,'add_objects',None):
+ added=0
+ lst=y.to_list(y.add_objects)
+ lst.reverse()
+ for u in lst:
+ if u in seen:continue
+ added=1
+ names=[u]+names
+ if added:continue
+ y.post()
+ seen.append(x)
+ for t in getattr(y,'compiled_tasks',[]):
+ self.link_task.inputs.extend(t.outputs)
+@TaskGen.after('apply_link')
+def process_obj_files(self):
+ if not hasattr(self,'obj_files'):
+ return
+ for x in self.obj_files:
+ node=self.path.find_resource(x)
+ self.link_task.inputs.append(node)
+@TaskGen.taskgen_method
+def add_obj_file(self,file):
+ if not hasattr(self,'obj_files'):self.obj_files=[]
+ if not'process_obj_files'in self.meths:self.meths.append('process_obj_files')
+ self.obj_files.append(file)
+old_define=Configure.ConfigurationContext.__dict__['define']
+@Configure.conf
+def define(self,key,val,quote=True,comment=''):
+ old_define(self,key,val,quote,comment)
+ if key.startswith('HAVE_'):
+ self.env[key]=1
+old_undefine=Configure.ConfigurationContext.__dict__['undefine']
+@Configure.conf
+def undefine(self,key,comment=''):
+ old_undefine(self,key,comment)
+ if key.startswith('HAVE_'):
+ self.env[key]=0
+def set_incdirs(self,val):
+ Logs.warn('compat: change "export_incdirs" by "export_includes"')
+ self.export_includes=val
+TaskGen.task_gen.export_incdirs=property(None,set_incdirs)
+def install_dir(self,path):
+ if not path:
+ return[]
+ destpath=Utils.subst_vars(path,self.env)
+ if self.is_install>0:
+ Logs.info('* creating %s'%destpath)
+ Utils.check_dir(destpath)
+ elif self.is_install<0:
+ Logs.info('* removing %s'%destpath)
+ try:
+ os.remove(destpath)
+ except OSError:
+ pass
+Build.BuildContext.install_dir=install_dir
+repl={'apply_core':'process_source','apply_lib_vars':'process_source','apply_obj_vars':'propagate_uselib_vars','exec_rule':'process_rule'}
+def after(*k):
+ k=[repl.get(key,key)for key in k]
+ return TaskGen.after_method(*k)
+def before(*k):
+ k=[repl.get(key,key)for key in k]
+ return TaskGen.before_method(*k)
+TaskGen.before=before
diff --git a/waflib/fixpy2.py b/waflib/fixpy2.py
new file mode 100644
index 0000000..5e434d1
--- /dev/null
+++ b/waflib/fixpy2.py
@@ -0,0 +1,53 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
+
+import os
+all_modifs={}
+def fixdir(dir):
+ global all_modifs
+ for k in all_modifs:
+ for v in all_modifs[k]:
+ modif(os.path.join(dir,'waflib'),k,v)
+def modif(dir,name,fun):
+ if name=='*':
+ lst=[]
+ for y in'. Tools extras'.split():
+ for x in os.listdir(os.path.join(dir,y)):
+ if x.endswith('.py'):
+ lst.append(y+os.sep+x)
+ for x in lst:
+ modif(dir,x,fun)
+ return
+ filename=os.path.join(dir,name)
+ f=open(filename,'r')
+ try:
+ txt=f.read()
+ finally:
+ f.close()
+ txt=fun(txt)
+ f=open(filename,'w')
+ try:
+ f.write(txt)
+ finally:
+ f.close()
+def subst(*k):
+ def do_subst(fun):
+ global all_modifs
+ for x in k:
+ try:
+ all_modifs[x].append(fun)
+ except KeyError:
+ all_modifs[x]=[fun]
+ return fun
+ return do_subst
+@subst('*')
+def r1(code):
+ code=code.replace(',e:',',e:')
+ code=code.replace("",'')
+ code=code.replace('','')
+ return code
+@subst('Runner.py')
+def r4(code):
+ code=code.replace('next(self.biter)','self.biter.next()')
+ return code
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..c665ff5
--- /dev/null
+++ b/wscript
@@ -0,0 +1,394 @@
+#! /usr/bin/python
+#
+# usage:
+# $ python waf --help
+#
+# example:
+# $ ./waf distclean configure build
+#
+# Note: aubio uses the waf build system, which relies on Python. Provided you
+# have Python installed, you do *not* need to install anything to build aubio.
+# For more info about waf, see http://code.google.com/p/waf/ .
+
+import sys
+
+APPNAME = 'aubio'
+
+# source VERSION
+for l in open('VERSION').readlines(): exec (l.strip())
+
+VERSION = '.'.join ([str(x) for x in [
+ AUBIO_MAJOR_VERSION,
+ AUBIO_MINOR_VERSION,
+ AUBIO_PATCH_VERSION
+ ]]) + AUBIO_VERSION_STATUS
+
+LIB_VERSION = '.'.join ([str(x) for x in [
+ LIBAUBIO_LT_CUR,
+ LIBAUBIO_LT_REV,
+ LIBAUBIO_LT_AGE]])
+
+top = '.'
+out = 'build'
+
+def add_option_enable_disable(ctx, name, default = None,
+ help_str = None, help_disable_str = None):
+ if help_str == None:
+ help_str = 'enable ' + name + ' support'
+ if help_disable_str == None:
+ help_disable_str = 'do not ' + help_str
+ ctx.add_option('--enable-' + name, action = 'store_true',
+ default = default,
+ dest = 'enable_' + name.replace('-','_'),
+ help = help_str)
+ ctx.add_option('--disable-' + name, action = 'store_false',
+ #default = default,
+ dest = 'enable_' + name.replace('-','_'),
+ help = help_disable_str )
+
+def options(ctx):
+ add_option_enable_disable(ctx, 'fftw3f', default = False,
+ help_str = 'compile with fftw3f instead of ooura (recommended)',
+ help_disable_str = 'do not compile with fftw3f')
+ add_option_enable_disable(ctx, 'fftw3', default = False,
+ help_str = 'compile with fftw3 instead of ooura',
+ help_disable_str = 'do not compile with fftw3')
+ add_option_enable_disable(ctx, 'complex', default = False,
+ help_str ='compile with C99 complex',
+ help_disable_str = 'do not use C99 complex (default)' )
+ add_option_enable_disable(ctx, 'jack', default = None,
+ help_str = 'compile with jack (auto)',
+ help_disable_str = 'disable jack support')
+ add_option_enable_disable(ctx, 'sndfile', default = None,
+ help_str = 'compile with sndfile (auto)',
+ help_disable_str = 'disable sndfile')
+ add_option_enable_disable(ctx, 'avcodec', default = None,
+ help_str = 'compile with libavcodec (auto)',
+ help_disable_str = 'disable libavcodec')
+ add_option_enable_disable(ctx, 'samplerate', default = None,
+ help_str = 'compile with samplerate (auto)',
+ help_disable_str = 'disable samplerate')
+ add_option_enable_disable(ctx, 'memcpy', default = True,
+ help_str = 'use memcpy hacks (default)',
+ help_disable_str = 'do not use memcpy hacks')
+ add_option_enable_disable(ctx, 'double', default = False,
+ help_str = 'compile in double precision mode',
+ help_disable_str = 'compile in single precision mode (default)')
+ add_option_enable_disable(ctx, 'fat', default = False,
+ help_str = 'build fat binaries (darwin only)',
+ help_disable_str = 'do not build fat binaries (default)')
+ add_option_enable_disable(ctx, 'accelerate', default = None,
+ help_str = 'use Accelerate framework (darwin only) (auto)',
+ help_disable_str = 'do not use Accelerate framework')
+ add_option_enable_disable(ctx, 'apple-audio', default = None,
+ help_str = 'use CoreFoundation (darwin only) (auto)',
+ help_disable_str = 'do not use CoreFoundation framework')
+ add_option_enable_disable(ctx, 'atlas', default = None,
+ help_str = 'use Atlas library (auto)',
+ help_disable_str = 'do not use Atlas library')
+
+ add_option_enable_disable(ctx, 'docs', default = None,
+ help_str = 'build documentation (auto)',
+ help_disable_str = 'do not build documentation')
+
+ ctx.add_option('--with-target-platform', type='string',
+ help='set target platform for cross-compilation', dest='target_platform')
+
+ ctx.load('compiler_c')
+ ctx.load('waf_unit_test')
+ ctx.load('gnu_dirs')
+
+def configure(ctx):
+ from waflib import Options
+ ctx.load('compiler_c')
+ ctx.load('waf_unit_test')
+ ctx.load('gnu_dirs')
+
+ # check for common headers
+ ctx.check(header_name='stdlib.h')
+ ctx.check(header_name='stdio.h')
+ ctx.check(header_name='math.h')
+ ctx.check(header_name='string.h')
+ ctx.check(header_name='limits.h')
+ ctx.check(header_name='getopt.h', mandatory = False)
+ ctx.check(header_name='unistd.h', mandatory = False)
+
+ target_platform = sys.platform
+ if ctx.options.target_platform:
+ target_platform = ctx.options.target_platform
+ ctx.env['DEST_OS'] = target_platform
+
+ if ctx.env.CC_NAME != 'msvc':
+ ctx.env.CFLAGS += ['-g', '-Wall', '-Wextra']
+ else:
+ ctx.env.CFLAGS += ['/W4', '/MD']
+ ctx.env.CFLAGS += ['/D_CRT_SECURE_NO_WARNINGS']
+
+ ctx.check_cc(lib='m', uselib_store='M', mandatory=False)
+
+ if target_platform not in ['win32', 'win64']:
+ ctx.env.CFLAGS += ['-fPIC']
+ else:
+ ctx.define('HAVE_WIN_HACKS', 1)
+ ctx.env['cshlib_PATTERN'] = 'lib%s.dll'
+
+ if target_platform == 'darwin' and ctx.options.enable_fat:
+ ctx.env.CFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
+ ctx.env.LINKFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
+ MINSDKVER="10.4"
+ ctx.env.CFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
+ ctx.env.LINKFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
+
+ if target_platform in [ 'darwin', 'ios', 'iosimulator']:
+ if (ctx.options.enable_apple_audio != False):
+ ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
+ ctx.define('HAVE_SOURCE_APPLE_AUDIO', 1)
+ ctx.define('HAVE_SINK_APPLE_AUDIO', 1)
+ if (ctx.options.enable_accelerate != False):
+ ctx.define('HAVE_ACCELERATE', 1)
+ ctx.env.FRAMEWORK += ['Accelerate']
+
+ if target_platform in [ 'ios', 'iosimulator' ]:
+ MINSDKVER="6.1"
+ ctx.env.CFLAGS += ['-std=c99']
+ if (ctx.options.enable_apple_audio != False):
+ ctx.define('HAVE_AUDIO_UNIT', 1)
+ #ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
+ if target_platform == 'ios':
+ DEVROOT = "/Applications/Xcode.app/Contents"
+ DEVROOT += "/Developer/Platforms/iPhoneOS.platform/Developer"
+ SDKROOT = "%(DEVROOT)s/SDKs/iPhoneOS.sdk" % locals()
+ ctx.env.CFLAGS += [ '-fembed-bitcode' ]
+ ctx.env.CFLAGS += [ '-arch', 'arm64' ]
+ ctx.env.CFLAGS += [ '-arch', 'armv7' ]
+ ctx.env.CFLAGS += [ '-arch', 'armv7s' ]
+ ctx.env.LINKFLAGS += [ '-arch', 'arm64' ]
+ ctx.env.LINKFLAGS += ['-arch', 'armv7']
+ ctx.env.LINKFLAGS += ['-arch', 'armv7s']
+ ctx.env.CFLAGS += [ '-miphoneos-version-min=' + MINSDKVER ]
+ ctx.env.LINKFLAGS += [ '-miphoneos-version-min=' + MINSDKVER ]
+ else:
+ DEVROOT = "/Applications/Xcode.app/Contents"
+ DEVROOT += "/Developer/Platforms/iPhoneSimulator.platform/Developer"
+ SDKROOT = "%(DEVROOT)s/SDKs/iPhoneSimulator.sdk" % locals()
+ ctx.env.CFLAGS += [ '-arch', 'i386' ]
+ ctx.env.CFLAGS += [ '-arch', 'x86_64' ]
+ ctx.env.LINKFLAGS += ['-arch', 'i386']
+ ctx.env.LINKFLAGS += ['-arch', 'x86_64']
+ ctx.env.CFLAGS += [ '-mios-simulator-version-min=' + MINSDKVER ]
+ ctx.env.LINKFLAGS += [ '-mios-simulator-version-min=' + MINSDKVER ]
+ ctx.env.CFLAGS += [ '-isysroot' , SDKROOT]
+ ctx.env.LINKFLAGS += [ '-isysroot' , SDKROOT]
+
+ if target_platform == 'emscripten':
+ import os.path
+ ctx.env.CFLAGS += [ '-I' + os.path.join(os.environ['EMSCRIPTEN'], 'system', 'include') ]
+ ctx.env.CFLAGS += ['-Oz']
+ ctx.env.cprogram_PATTERN = "%s.js"
+ if (ctx.options.enable_atlas != True):
+ ctx.options.enable_atlas = False
+
+ # check support for C99 __VA_ARGS__ macros
+ check_c99_varargs = '''
+#include <stdio.h>
+#define AUBIO_ERR(...) fprintf(stderr, __VA_ARGS__)
+'''
+
+ if ctx.check_cc(fragment = check_c99_varargs,
+ type='cstlib',
+ msg = 'Checking for C99 __VA_ARGS__ macro',
+ mandatory = False):
+ ctx.define('HAVE_C99_VARARGS_MACROS', 1)
+
+ # show a message about enable_double status
+ if (ctx.options.enable_double == True):
+ ctx.msg('Checking for size of smpl_t', 'double')
+ ctx.msg('Checking for size of lsmp_t', 'long double')
+ else:
+ ctx.msg('Checking for size of smpl_t', 'float')
+ ctx.msg('Checking for size of lsmp_t', 'double')
+
+ # optionally use complex.h
+ if (ctx.options.enable_complex == True):
+ ctx.check(header_name='complex.h')
+ else:
+ ctx.msg('Checking if complex.h is enabled', 'no')
+
+ # check for fftw3
+ if (ctx.options.enable_fftw3 != False or ctx.options.enable_fftw3f != False):
+ # one of fftwf or fftw3f
+ if (ctx.options.enable_fftw3f != False):
+ ctx.check_cfg(package = 'fftw3f', atleast_version = '3.0.0',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_fftw3f)
+ if (ctx.options.enable_double == True):
+ ctx.msg('Warning',
+ 'fftw3f enabled, but compiling in double precision!')
+ else:
+ # fftw3f disabled, take most sensible one according to
+ # enable_double
+ if (ctx.options.enable_double == True):
+ ctx.check_cfg(package = 'fftw3', atleast_version = '3.0.0',
+ args = '--cflags --libs', mandatory =
+ ctx.options.enable_fftw3)
+ else:
+ ctx.check_cfg(package = 'fftw3f', atleast_version = '3.0.0',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_fftw3)
+ ctx.define('HAVE_FFTW3', 1)
+
+ # fftw not enabled, use vDSP or ooura
+ if 'HAVE_FFTW3F' in ctx.env.define_key:
+ ctx.msg('Checking for FFT implementation', 'fftw3f')
+ elif 'HAVE_FFTW3' in ctx.env.define_key:
+ ctx.msg('Checking for FFT implementation', 'fftw3')
+ elif 'HAVE_ACCELERATE' in ctx.env.define_key:
+ ctx.msg('Checking for FFT implementation', 'vDSP')
+ else:
+ ctx.msg('Checking for FFT implementation', 'ooura')
+
+ # check for libsndfile
+ if (ctx.options.enable_sndfile != False):
+ ctx.check_cfg(package = 'sndfile', atleast_version = '1.0.4',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_sndfile)
+
+ # check for libsamplerate
+ if (ctx.options.enable_samplerate != False):
+ ctx.check_cfg(package = 'samplerate', atleast_version = '0.0.15',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_samplerate)
+
+ # check for jack
+ if (ctx.options.enable_jack != False):
+ ctx.check_cfg(package = 'jack',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_jack)
+
+ # check for libav
+ if (ctx.options.enable_avcodec != False):
+ ctx.check_cfg(package = 'libavcodec', atleast_version = '54.35.0',
+ args = '--cflags --libs', uselib_store = 'AVCODEC',
+ mandatory = ctx.options.enable_avcodec)
+ ctx.check_cfg(package = 'libavformat', atleast_version = '52.3.0',
+ args = '--cflags --libs', uselib_store = 'AVFORMAT',
+ mandatory = ctx.options.enable_avcodec)
+ ctx.check_cfg(package = 'libavutil', atleast_version = '52.3.0',
+ args = '--cflags --libs', uselib_store = 'AVUTIL',
+ mandatory = ctx.options.enable_avcodec)
+ ctx.check_cfg(package = 'libavresample', atleast_version = '1.0.1',
+ args = '--cflags --libs', uselib_store = 'AVRESAMPLE',
+ mandatory = ctx.options.enable_avcodec)
+ if all ( 'HAVE_' + i in ctx.env
+ for i in ['AVCODEC', 'AVFORMAT', 'AVUTIL', 'AVRESAMPLE'] ):
+ ctx.define('HAVE_LIBAV', 1)
+ ctx.msg('Checking for all libav libraries', 'yes')
+ else:
+ ctx.msg('Checking for all libav libraries', 'not found', color = 'YELLOW')
+
+ ctx.define('HAVE_WAVREAD', 1)
+ ctx.define('HAVE_WAVWRITE', 1)
+
+ # use ATLAS
+ if (ctx.options.enable_atlas != False):
+ ctx.check(header_name = 'atlas/cblas.h', mandatory = ctx.options.enable_atlas)
+ #ctx.check(lib = 'lapack', uselib_store = 'LAPACK', mandatory = ctx.options.enable_atlas)
+ ctx.check(lib = 'cblas', uselib_store = 'BLAS', mandatory = ctx.options.enable_atlas)
+
+ # use memcpy hacks
+ if (ctx.options.enable_memcpy == True):
+ ctx.define('HAVE_MEMCPY_HACKS', 1)
+
+ # write configuration header
+ ctx.write_config_header('src/config.h')
+
+ # the following defines will be passed as arguments to the compiler
+ # instead of being written to src/config.h
+
+ # add some defines used in examples
+ ctx.define('AUBIO_PREFIX', ctx.env['PREFIX'])
+ ctx.define('PACKAGE', APPNAME)
+
+ # double precision mode
+ if (ctx.options.enable_double == True):
+ ctx.define('HAVE_AUBIO_DOUBLE', 1)
+
+ if (ctx.options.enable_docs != False):
+ # check if txt2man is installed, optional
+ try:
+ ctx.find_program('txt2man', var='TXT2MAN')
+ except ctx.errors.ConfigurationError:
+ ctx.to_log('txt2man was not found (ignoring)')
+
+ # check if doxygen is installed, optional
+ try:
+ ctx.find_program('doxygen', var='DOXYGEN')
+ except ctx.errors.ConfigurationError:
+ ctx.to_log('doxygen was not found (ignoring)')
+
+def build(bld):
+ bld.env['VERSION'] = VERSION
+ bld.env['LIB_VERSION'] = LIB_VERSION
+
+ # add sub directories
+ bld.recurse('src')
+ if bld.env['DEST_OS'] not in ['ios', 'iosimulator', 'android']:
+ bld.recurse('examples')
+ bld.recurse('tests')
+
+ bld( source = 'aubio.pc.in' )
+
+ # build manpages from txt files using txt2man
+ if bld.env['TXT2MAN']:
+ from waflib import TaskGen
+ if 'MANDIR' not in bld.env:
+ bld.env['MANDIR'] = bld.env['PREFIX'] + '/share/man'
+ rule_str = '${TXT2MAN} -t `basename ${TGT} | cut -f 1 -d . | tr a-z A-Z`'
+ rule_str += ' -r ${PACKAGE}\\ ${VERSION} -P ${PACKAGE}'
+ rule_str += ' -v ${PACKAGE}\\ User\\\'s\\ manual'
+ rule_str += ' -s 1 ${SRC} > ${TGT}'
+ TaskGen.declare_chain(
+ name = 'txt2man',
+ rule = rule_str,
+ ext_in = '.txt',
+ ext_out = '.1',
+ reentrant = False,
+ install_path = '${MANDIR}/man1',
+ )
+ bld( source = bld.path.ant_glob('doc/*.txt') )
+
+ # build documentation from source files using doxygen
+ if bld.env['DOXYGEN']:
+ bld( name = 'doxygen', rule = 'doxygen ${SRC} > /dev/null',
+ source = 'doc/web.cfg',
+ cwd = 'doc')
+ bld.install_files( '${PREFIX}' + '/share/doc/libaubio-doc',
+ bld.path.ant_glob('doc/web/html/**'),
+ cwd = bld.path.find_dir ('doc/web'),
+ relative_trick = True)
+
+def shutdown(bld):
+ from waflib import Logs
+ if bld.options.target_platform in ['ios', 'iosimulator']:
+ msg ='building for %s, contact the author for a commercial license' % bld.options.target_platform
+ Logs.pprint('RED', msg)
+ msg =' Paul Brossier <piem@aubio.org>'
+ Logs.pprint('RED', msg)
+
+def dist(ctx):
+ ctx.excl = ' **/.waf-1* **/*~ **/*.pyc **/*.swp **/.lock-w* **/.git*'
+ ctx.excl += ' **/build/*'
+ ctx.excl += ' **/python/gen **/python/build **/python/dist'
+ ctx.excl += ' **/python/ext/config.h'
+ ctx.excl += ' **/**.zip **/**.tar.bz2'
+ ctx.excl += ' **/doc/full/* **/doc/web/*'
+ ctx.excl += ' **/python/*.db'
+ ctx.excl += ' **/python.old/*'
+ ctx.excl += ' **/python/*/*.old'
+ ctx.excl += ' **/python/tests/sounds'
+ ctx.excl += ' **/**.asc'
+ ctx.excl += ' **/dist*'
+ ctx.excl += ' **/.DS_Store'
+ ctx.excl += ' **/.travis.yml'
+ ctx.excl += ' **/.landscape.yml'
+ ctx.excl += ' **/.appveyor.yml'