Mercurial > hg > vamp-plugin-sdk
changeset 460:b409560a805b
Merge from branch vampipe
author | Chris Cannam |
---|---|
date | Mon, 10 Oct 2016 15:48:35 +0100 |
parents | 4101e3f80aa0 (current diff) 3949cc56f2ce (diff) |
children | 6ac615fd02a3 |
files | src/vamp-sdk/FFTimpl.cpp |
diffstat | 45 files changed, 2318 insertions(+), 332 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Aug 18 12:00:24 2016 +0100 +++ b/.hgignore Mon Oct 10 15:48:35 2016 +0100 @@ -27,3 +27,5 @@ *.opensdf re:^build/x64/Debug/ re:^build/x64/Release/ +test/obtained +test/failures
--- a/COPYING Thu Aug 18 12:00:24 2016 +0100 +++ b/COPYING Mon Oct 10 15:48:35 2016 +0100 @@ -28,3 +28,38 @@ use or other dealings in this Software without prior written authorization. +The KissFFT code in src/vamp-sdk/ext is distributed under the following licence: + + Copyright (c) 2003-2010 Mark Borgerding + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the author nor the names of any contributors may be used + to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS + 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.
--- a/Makefile.in Thu Aug 18 12:00:24 2016 +0100 +++ b/Makefile.in Mon Oct 10 15:48:35 2016 +0100 @@ -41,7 +41,7 @@ CC = @CC@ CXX = @CXX@ CFLAGS = @CFLAGS@ -CXXFLAGS = -I. @CXXFLAGS@ @SNDFILE_CFLAGS@ +CXXFLAGS = -I. @CXXFLAGS@ @SNDFILE_CFLAGS@ # ar, ranlib # @@ -78,13 +78,13 @@ INSTALL_PLUGINS = $(INSTALL_PREFIX)/lib/vamp INSTALL_BINARIES = $(INSTALL_PREFIX)/bin -INSTALL_SDK_LIBNAME = libvamp-sdk.so.2.6.0 +INSTALL_SDK_LIBNAME = libvamp-sdk.so.2.7.0 INSTALL_SDK_LINK_ABI = libvamp-sdk.so.2 INSTALL_SDK_LINK_DEV = libvamp-sdk.so INSTALL_SDK_STATIC = libvamp-sdk.a INSTALL_SDK_LA = libvamp-sdk.la -INSTALL_HOSTSDK_LIBNAME = libvamp-hostsdk.so.3.6.0 +INSTALL_HOSTSDK_LIBNAME = libvamp-hostsdk.so.3.7.0 INSTALL_HOSTSDK_LINK_ABI = libvamp-hostsdk.so.3 INSTALL_HOSTSDK_LINK_DEV = libvamp-hostsdk.so INSTALL_HOSTSDK_STATIC = libvamp-hostsdk.a @@ -113,7 +113,7 @@ HOSTSDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) PLUGIN_LDFLAGS = $(DYNAMIC_LDFLAGS) -exported_symbols_list build/vamp-plugin.list - INSTALL_HOSTSDK_LIBNAME = libvamp-hostsdk.3.6.0.dylib + INSTALL_HOSTSDK_LIBNAME = libvamp-hostsdk.3.7.0.dylib INSTALL_HOSTSDK_LINK_ABI = libvamp-hostsdk.3.dylib # The OS X linker doesn't allow you to request static linkage when @@ -122,7 +122,7 @@ # dynamic, the static library will never be used. That's OK for the # host SDK, but we do want plugins to get static linkage of the plugin # SDK. So install the dynamic version under a different name. - INSTALL_SDK_LIBNAME = libvamp-sdk-dynamic.2.6.0.dylib + INSTALL_SDK_LIBNAME = libvamp-sdk-dynamic.2.7.0.dylib INSTALL_SDK_LINK_ABI = libvamp-sdk-dynamic.2.dylib endif @@ -146,13 +146,16 @@ $(HOSTSDKDIR)/Plugin.h \ $(HOSTSDKDIR)/PluginBase.h \ $(HOSTSDKDIR)/PluginHostAdapter.h \ - $(HOSTSDKDIR)/RealTime.h \ $(HOSTSDKDIR)/PluginBufferingAdapter.h \ $(HOSTSDKDIR)/PluginChannelAdapter.h \ $(HOSTSDKDIR)/PluginInputDomainAdapter.h \ $(HOSTSDKDIR)/PluginLoader.h \ $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ $(HOSTSDKDIR)/PluginWrapper.h \ + $(HOSTSDKDIR)/RealTime.h \ + $(HOSTSDKDIR)/PluginConfiguration.h \ + $(HOSTSDKDIR)/PluginStaticData.h \ + $(HOSTSDKDIR)/RequestResponse.h \ $(HOSTSDKDIR)/hostguard.h \ $(HOSTSDKDIR)/host-c.h \ $(HOSTSDKDIR)/vamp-hostsdk.h @@ -387,7 +390,7 @@ src/vamp-sdk/PluginAdapter.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h src/vamp-sdk/PluginAdapter.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h src/vamp-sdk/RealTime.o: ./vamp-sdk/RealTime.h vamp-sdk/plugguard.h -src/vamp-sdk/FFT.o: src/vamp-sdk/FFT.cpp vamp-sdk/FFT.h src/vamp-sdk/FFTimpl.cpp +src/vamp-sdk/FFT.o: src/vamp-sdk/FFT.cpp vamp-sdk/FFT.h src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/PluginBufferingAdapter.h src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/PluginWrapper.h src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/Plugin.h @@ -413,7 +416,6 @@ src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/plugguard.h src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/RealTime.h src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/FFT.h -src/vamp-hostsdk/PluginInputDomainAdapter.o: src/vamp-sdk/FFTimpl.cpp src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginHostAdapter.h src/vamp-hostsdk/PluginLoader.o: vamp/vamp.h vamp-sdk/Plugin.h src/vamp-hostsdk/PluginLoader.o: vamp-sdk/PluginBase.h
--- a/README Thu Aug 18 12:00:24 2016 +0100 +++ b/README Mon Oct 10 15:48:35 2016 +0100 @@ -9,7 +9,10 @@ Vamp is an API for C and C++ plugins that process sampled audio data to produce descriptive output (measurements or semantic observations). -This is version 2.6 of the Vamp plugin Software Development Kit. +This is version 2.7 of the Vamp plugin Software Development Kit. + +Plugins and hosts built with this SDK are binary compatible with those +built using any version 2.0 or newer of the SDK. Plugins and hosts built with this SDK are binary compatible with those built using version 1.0 of the SDK, with certain restrictions. See @@ -248,12 +251,14 @@ Vamp and the Vamp SDK were designed and made at the Centre for Digital Music at Queen Mary, University of London. -The SDK was written by Chris Cannam, copyright (c) 2005-2015 +The SDK was written by Chris Cannam, copyright (c) 2005-2016 Chris Cannam and QMUL. +The SDK incorporates KissFFT code, copyright (c) 2003-2010 Mark +Borgerding. + Mark Sandler and Christian Landone provided ideas and direction, and Mark Levy, Dan Stowell, Martin Gasser and Craig Sapp provided testing and other input for the 1.0 API and SDK. The API also uses some ideas from prior plugin systems, notably DSSI (http://dssi.sourceforge.net) and FEAPI (http://feapi.sourceforge.net). -
--- a/build/Doxyfile Thu Aug 18 12:00:24 2016 +0100 +++ b/build/Doxyfile Mon Oct 10 15:48:35 2016 +0100 @@ -31,7 +31,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 2.6 +PROJECT_NUMBER = 2.7 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put.
--- a/build/Makefile.mingw32 Thu Aug 18 12:00:24 2016 +0100 +++ b/build/Makefile.mingw32 Mon Oct 10 15:48:35 2016 +0100 @@ -132,6 +132,9 @@ $(HOSTSDKDIR)/PluginLoader.h \ $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ $(HOSTSDKDIR)/PluginWrapper.h \ + $(HOSTSDKDIR)/PluginConfiguration.h \ + $(HOSTSDKDIR)/PluginStaticData.h \ + $(HOSTSDKDIR)/RequestResponse.h \ $(HOSTSDKDIR)/hostguard.h \ $(HOSTSDKDIR)/host-c.h \ $(HOSTSDKDIR)/vamp-hostsdk.h
--- a/build/Makefile.mingw64 Thu Aug 18 12:00:24 2016 +0100 +++ b/build/Makefile.mingw64 Mon Oct 10 15:48:35 2016 +0100 @@ -132,6 +132,9 @@ $(HOSTSDKDIR)/PluginLoader.h \ $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ $(HOSTSDKDIR)/PluginWrapper.h \ + $(HOSTSDKDIR)/PluginConfiguration.h \ + $(HOSTSDKDIR)/PluginStaticData.h \ + $(HOSTSDKDIR)/RequestResponse.h \ $(HOSTSDKDIR)/hostguard.h \ $(HOSTSDKDIR)/host-c.h \ $(HOSTSDKDIR)/vamp-hostsdk.h
--- a/build/Makefile.osx Thu Aug 18 12:00:24 2016 +0100 +++ b/build/Makefile.osx Mon Oct 10 15:48:35 2016 +0100 @@ -140,6 +140,9 @@ $(HOSTSDKDIR)/PluginLoader.h \ $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ $(HOSTSDKDIR)/PluginWrapper.h \ + $(HOSTSDKDIR)/PluginConfiguration.h \ + $(HOSTSDKDIR)/PluginStaticData.h \ + $(HOSTSDKDIR)/RequestResponse.h \ $(HOSTSDKDIR)/hostguard.h \ $(HOSTSDKDIR)/host-c.h \ $(HOSTSDKDIR)/vamp-hostsdk.h
--- a/build/Makefile.osx.106 Thu Aug 18 12:00:24 2016 +0100 +++ b/build/Makefile.osx.106 Mon Oct 10 15:48:35 2016 +0100 @@ -161,7 +161,11 @@ $(HOSTSDKDIR)/PluginLoader.h \ $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ $(HOSTSDKDIR)/PluginWrapper.h \ + $(HOSTSDKDIR)/PluginConfiguration.h \ + $(HOSTSDKDIR)/PluginStaticData.h \ + $(HOSTSDKDIR)/RequestResponse.h \ $(HOSTSDKDIR)/hostguard.h \ + $(HOSTSDKDIR)/host-c.h \ $(HOSTSDKDIR)/vamp-hostsdk.h SDK_OBJECTS = \
--- a/build/libvamp-hostsdk.la.in Thu Aug 18 12:00:24 2016 +0100 +++ b/build/libvamp-hostsdk.la.in Mon Oct 10 15:48:35 2016 +0100 @@ -8,7 +8,7 @@ old_library='%STATIC%' dependency_libs='' current=3 -age=6 +age=7 revision=0 installed=yes libdir='%LIBS%'
--- a/build/libvamp-sdk.la.in Thu Aug 18 12:00:24 2016 +0100 +++ b/build/libvamp-sdk.la.in Mon Oct 10 15:48:35 2016 +0100 @@ -8,7 +8,7 @@ old_library='%STATIC%' dependency_libs='' current=2 -age=6 +age=7 revision=0 installed=yes libdir='%LIBS%'
--- a/build/update-version.sh Thu Aug 18 12:00:24 2016 +0100 +++ b/build/update-version.sh Mon Oct 10 15:48:35 2016 +0100 @@ -126,4 +126,7 @@ $p 's/^$/\nextern void libvamphostsdk_v_'$acs'_present(void) { }/' \ src/vamp-hostsdk/acsymbols.c -echo "Done, now check with e.g. hg diff -- and don't forget to update CHANGELOG" +echo "Done, now check changes with e.g. hg diff" +echo "*** Don't forget to update CHANGELOG" +echo "*** Don't forget to re-run \"aclocal -I . && autoconf\"" +
--- a/configure Thu Aug 18 12:00:24 2016 +0100 +++ b/configure Mon Oct 10 15:48:35 2016 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for vamp-plugin-sdk 2.6. +# Generated by GNU Autoconf 2.69 for vamp-plugin-sdk 2.7. # # Report bugs to <cannam@all-day-breakfast.com>. # @@ -580,8 +580,8 @@ # Identity of this package. PACKAGE_NAME='vamp-plugin-sdk' PACKAGE_TARNAME='vamp-plugin-sdk' -PACKAGE_VERSION='2.6' -PACKAGE_STRING='vamp-plugin-sdk 2.6' +PACKAGE_VERSION='2.7' +PACKAGE_STRING='vamp-plugin-sdk 2.7' PACKAGE_BUGREPORT='cannam@all-day-breakfast.com' PACKAGE_URL='' @@ -1243,7 +1243,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures vamp-plugin-sdk 2.6 to adapt to many kinds of systems. +\`configure' configures vamp-plugin-sdk 2.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1304,7 +1304,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of vamp-plugin-sdk 2.6:";; + short | recursive ) echo "Configuration of vamp-plugin-sdk 2.7:";; esac cat <<\_ACEOF @@ -1402,7 +1402,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -vamp-plugin-sdk configure 2.6 +vamp-plugin-sdk configure 2.7 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1651,7 +1651,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by vamp-plugin-sdk $as_me 2.6, which was +It was created by vamp-plugin-sdk $as_me 2.7, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4505,7 +4505,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by vamp-plugin-sdk $as_me 2.6, which was +This file was extended by vamp-plugin-sdk $as_me 2.7, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4558,7 +4558,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -vamp-plugin-sdk config.status 2.6 +vamp-plugin-sdk config.status 2.7 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\"
--- a/configure.ac Thu Aug 18 12:00:24 2016 +0100 +++ b/configure.ac Mon Oct 10 15:48:35 2016 +0100 @@ -1,5 +1,5 @@ -AC_INIT(vamp-plugin-sdk, 2.6, cannam@all-day-breakfast.com) +AC_INIT(vamp-plugin-sdk, 2.7, cannam@all-day-breakfast.com) AC_CONFIG_SRCDIR(vamp/vamp.h) AC_PROG_CXX
--- a/examples/AmplitudeFollower.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/examples/AmplitudeFollower.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -199,7 +199,7 @@ AmplitudeFollower::FeatureSet AmplitudeFollower::process(const float *const *inputBuffers, - Vamp::RealTime timestamp) + Vamp::RealTime /* timestamp */) { if (m_stepSize == 0) { cerr << "ERROR: AmplitudeFollower::process: "
--- a/host/vamp-simple-host.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/host/vamp-simple-host.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -508,7 +508,7 @@ const Plugin::OutputDescriptor &output, int outputNo, const Plugin::FeatureSet &features, ofstream *out, bool useFrames) { - static int featureCount = 0; + static int featureCount = -1; if (features.find(outputNo) == features.end()) return; @@ -523,12 +523,13 @@ rt = f.timestamp; haveRt = true; } else if (output.sampleType == Plugin::OutputDescriptor::FixedSampleRate) { - int n = featureCount; + int n = featureCount + 1; if (f.hasTimestamp) { n = int(round(toSeconds(f.timestamp) * output.sampleRate)); } rt = RealTime::fromSeconds(double(n) / output.sampleRate); haveRt = true; + featureCount = n; } if (useFrames) { @@ -570,8 +571,6 @@ (out ? *out : cout) << " " << f.label; (out ? *out : cout) << endl; - - ++featureCount; } }
--- a/pkgconfig/vamp-hostsdk.pc.in Thu Aug 18 12:00:24 2016 +0100 +++ b/pkgconfig/vamp-hostsdk.pc.in Mon Oct 10 15:48:35 2016 +0100 @@ -4,7 +4,7 @@ includedir=${prefix}/include Name: vamp-hostsdk -Version: 2.6 +Version: 2.7 Description: Development library for Vamp audio analysis plugin hosts Libs: -L${libdir} -lvamp-hostsdk -ldl Cflags: -I${includedir}
--- a/pkgconfig/vamp-sdk.pc.in Thu Aug 18 12:00:24 2016 +0100 +++ b/pkgconfig/vamp-sdk.pc.in Mon Oct 10 15:48:35 2016 +0100 @@ -4,7 +4,7 @@ includedir=${prefix}/include Name: vamp-sdk -Version: 2.6 +Version: 2.7 Description: Development library for Vamp audio analysis plugins Libs: -L${libdir} -lvamp-sdk Cflags: -I${includedir}
--- a/pkgconfig/vamp.pc.in Thu Aug 18 12:00:24 2016 +0100 +++ b/pkgconfig/vamp.pc.in Mon Oct 10 15:48:35 2016 +0100 @@ -4,7 +4,7 @@ includedir=${prefix}/include Name: vamp -Version: 2.6 +Version: 2.7 Description: An API for audio analysis and feature extraction plugins Libs: Cflags: -I${includedir}
--- a/src/vamp-hostsdk/PluginHostAdapter.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/PluginHostAdapter.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -37,7 +37,7 @@ #include <vamp-hostsdk/PluginHostAdapter.h> #include <cstdlib> -#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 6 ) +#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 7 ) #error Unexpected version of Vamp SDK header included #endif
--- a/src/vamp-hostsdk/PluginInputDomainAdapter.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/PluginInputDomainAdapter.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -43,40 +43,16 @@ #include "Window.h" - -/** - * If you want to compile using FFTW instead of the built-in FFT - * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3 - * in the Makefile. - * - * Be aware that FFTW is licensed under the GPL -- unlike this SDK, - * which is provided under a more liberal BSD license in order to - * permit use in closed source applications. The use of FFTW would - * mean that your code would need to be licensed under the GPL as - * well. Do not define this symbol unless you understand and accept - * the implications of this. - * - * Parties such as Linux distribution packagers who redistribute this - * SDK for use in other programs should _not_ define this symbol, as - * it would change the effective licensing terms under which the SDK - * was available to third party developers. - * - * The default is not to use FFTW, and to use the built-in FFT instead. - * - * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on - * its first invocation unless the host has saved and restored FFTW - * wisdom (see the FFTW documentation). - */ -#ifdef HAVE_FFTW3 -#include <fftw3.h> -#pragma message("*** NOTE: Compiling with FFTW3 support will result in a GPL binary") -#else -#include "../vamp-sdk/FFTimpl.cpp" -#endif - +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <limits.h> _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp) +#include "../vamp-sdk/FFTimpl.cpp" + namespace Vamp { namespace HostExt { @@ -110,30 +86,25 @@ int m_stepSize; int m_blockSize; float **m_freqbuf; - - double *m_ri; + Kiss::kiss_fft_scalar *m_ri; WindowType m_windowType; - Window<double> *m_window; + typedef Window<Kiss::kiss_fft_scalar> W; + W *m_window; ProcessTimestampMethod m_method; int m_processCount; float **m_shiftBuffers; -#ifdef HAVE_FFTW3 - fftw_plan m_plan; - fftw_complex *m_cbuf; -#else - double *m_ro; - double *m_io; -#endif + Kiss::kiss_fftr_cfg m_cfg; + Kiss::kiss_fft_cpx *m_cbuf; FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp); FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp); size_t makeBlockSizeAcceptable(size_t) const; - Window<double>::WindowType convertType(WindowType t) const; + W::WindowType convertType(WindowType t) const; }; PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : @@ -227,13 +198,8 @@ m_method(ShiftTimestamp), m_processCount(0), m_shiftBuffers(0), -#ifdef HAVE_FFTW3 - m_plan(0), + m_cfg(0), m_cbuf(0) -#else - m_ro(0), - m_io(0) -#endif { } @@ -253,19 +219,13 @@ delete[] m_freqbuf[c]; } delete[] m_freqbuf; -#ifdef HAVE_FFTW3 - if (m_plan) { - fftw_destroy_plan(m_plan); - fftw_free(m_ri); - fftw_free(m_cbuf); - m_plan = 0; + delete[] m_ri; + if (m_cfg) { + Kiss::kiss_fftr_free(m_cfg); + m_cfg = 0; + delete[] m_cbuf; + m_cbuf = 0; } -#else - delete[] m_ri; - delete[] m_ro; - delete[] m_io; -#endif - delete m_window; } } @@ -292,30 +252,23 @@ return false; } -#ifndef HAVE_FFTW3 - if (blockSize & (blockSize-1)) { - std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; + if (blockSize % 2) { + std::cerr << "ERROR: PluginInputDomainAdapter::initialise: odd blocksize " << blockSize << " not supported" << std::endl; return false; } -#endif if (m_channels > 0) { for (int c = 0; c < m_channels; ++c) { delete[] m_freqbuf[c]; } delete[] m_freqbuf; -#ifdef HAVE_FFTW3 - if (m_plan) { - fftw_destroy_plan(m_plan); - fftw_free(m_ri); - fftw_free(m_cbuf); - m_plan = 0; + delete[] m_ri; + if (m_cfg) { + Kiss::kiss_fftr_free(m_cfg); + m_cfg = 0; + delete[] m_cbuf; + m_cbuf = 0; } -#else - delete[] m_ri; - delete[] m_ro; - delete[] m_io; -#endif delete m_window; } @@ -327,22 +280,16 @@ for (int c = 0; c < m_channels; ++c) { m_freqbuf[c] = new float[m_blockSize + 2]; } + m_ri = new Kiss::kiss_fft_scalar[m_blockSize]; - m_window = new Window<double>(convertType(m_windowType), m_blockSize); + m_window = new W(convertType(m_windowType), m_blockSize); -#ifdef HAVE_FFTW3 - m_ri = (double *)fftw_malloc(blockSize * sizeof(double)); - m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex)); - m_plan = fftw_plan_dft_r2c_1d(int(blockSize), m_ri, m_cbuf, FFTW_MEASURE); -#else - m_ri = new double[m_blockSize]; - m_ro = new double[m_blockSize]; - m_io = new double[m_blockSize]; -#endif + m_cfg = Kiss::kiss_fftr_alloc(m_blockSize, false, 0, 0); + m_cbuf = new Kiss::kiss_fft_cpx[m_blockSize/2+1]; m_processCount = 0; - return m_plugin->initialise(channels, stepSize, blockSize); + return m_plugin->initialise(channels, stepSize, m_blockSize); } void @@ -388,36 +335,12 @@ std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl << "supported, increasing from " << blockSize << " to 2" << std::endl; blockSize = 2; + + } else if (blockSize % 2) { - } else if (blockSize & (blockSize-1)) { - -#ifdef HAVE_FFTW3 - // not an issue with FFTW -#else - - // not a power of two, can't handle that with our built-in FFT - // implementation - - size_t nearest = blockSize; - size_t power = 0; - while (nearest > 1) { - nearest >>= 1; - ++power; - } - nearest = 1; - while (power) { - nearest <<= 1; - --power; - } - - if (blockSize - nearest > (nearest*2) - blockSize) { - nearest = nearest*2; - } - - std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; - blockSize = nearest; - -#endif + std::cerr << "WARNING: PluginInputDomainAdapter::initialise: odd blocksize not" << std::endl + << "supported, increasing from " << blockSize << " to " << (blockSize+1) << std::endl; + blockSize = blockSize+1; } return blockSize; @@ -455,7 +378,7 @@ m_windowType = t; if (m_window) { delete m_window; - m_window = new Window<double>(convertType(m_windowType), m_blockSize); + m_window = new W(convertType(m_windowType), m_blockSize); } } @@ -465,26 +388,26 @@ return m_windowType; } -Window<double>::WindowType +PluginInputDomainAdapter::Impl::W::WindowType PluginInputDomainAdapter::Impl::convertType(WindowType t) const { switch (t) { case RectangularWindow: - return Window<double>::RectangularWindow; + return W::RectangularWindow; case BartlettWindow: - return Window<double>::BartlettWindow; + return W::BartlettWindow; case HammingWindow: - return Window<double>::HammingWindow; + return W::HammingWindow; case HanningWindow: - return Window<double>::HanningWindow; + return W::HanningWindow; case BlackmanWindow: - return Window<double>::BlackmanWindow; + return W::BlackmanWindow; case NuttallWindow: - return Window<double>::NuttallWindow; + return W::NuttallWindow; case BlackmanHarrisWindow: - return Window<double>::BlackmanHarrisWindow; + return W::BlackmanHarrisWindow; default: - return Window<double>::HanningWindow; + return W::HanningWindow; } } @@ -529,26 +452,17 @@ for (int i = 0; i < m_blockSize/2; ++i) { // FFT shift - double value = m_ri[i]; + Kiss::kiss_fft_scalar value = m_ri[i]; m_ri[i] = m_ri[i + m_blockSize/2]; m_ri[i + m_blockSize/2] = value; } -#ifdef HAVE_FFTW3 - fftw_execute(m_plan); - + Kiss::kiss_fftr(m_cfg, m_ri, m_cbuf); + for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); - m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); + m_freqbuf[c][i * 2] = m_cbuf[i].r; + m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i; } -#else - fft(m_blockSize, false, m_ri, 0, m_ro, m_io); - - for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_ro[i]); - m_freqbuf[c][i * 2 + 1] = float(m_io[i]); - } -#endif } return m_plugin->process(m_freqbuf, timestamp); @@ -587,26 +501,17 @@ for (int i = 0; i < m_blockSize/2; ++i) { // FFT shift - double value = m_ri[i]; + Kiss::kiss_fft_scalar value = m_ri[i]; m_ri[i] = m_ri[i + m_blockSize/2]; m_ri[i + m_blockSize/2] = value; } -#ifdef HAVE_FFTW3 - fftw_execute(m_plan); - + Kiss::kiss_fftr(m_cfg, m_ri, m_cbuf); + for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); - m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); + m_freqbuf[c][i * 2] = m_cbuf[i].r; + m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i; } -#else - fft(m_blockSize, false, m_ri, 0, m_ro, m_io); - - for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_ro[i]); - m_freqbuf[c][i * 2 + 1] = float(m_io[i]); - } -#endif } ++m_processCount; @@ -614,10 +519,6 @@ return m_plugin->process(m_freqbuf, timestamp); } -#ifndef HAVE_FFTW3 - -#endif - } }
--- a/src/vamp-hostsdk/PluginLoader.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/PluginLoader.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -6,7 +6,7 @@ An API for audio analysis and feature extraction plugins. Centre for Digital Music, Queen Mary, University of London. - Copyright 2006-2009 Chris Cannam and QMUL. + Copyright 2006-2016 Chris Cannam and QMUL. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -61,11 +61,16 @@ virtual ~Impl(); PluginKeyList listPlugins(); + PluginStaticDataList listPluginData(); Plugin *loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags); + LoadResponse loadPlugin(LoadRequest req); + + ConfigurationResponse configurePlugin(ConfigurationRequest req); + PluginKey composePluginKey(string libraryName, string identifier); PluginCategoryHierarchy getPluginCategory(PluginKey key); @@ -138,12 +143,18 @@ return m_instance; } -vector<PluginLoader::PluginKey> +PluginLoader::PluginKeyList PluginLoader::listPlugins() { return m_impl->listPlugins(); } +PluginLoader::PluginStaticDataList +PluginLoader::listPluginData() +{ + return m_impl->listPluginData(); +} + Plugin * PluginLoader::loadPlugin(PluginKey key, float inputSampleRate, @@ -152,6 +163,18 @@ return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); } +LoadResponse +PluginLoader::loadPlugin(LoadRequest req) +{ + return m_impl->loadPlugin(req); +} + +ConfigurationResponse +PluginLoader::configurePlugin(ConfigurationRequest req) +{ + return m_impl->configurePlugin(req); +} + PluginLoader::PluginKey PluginLoader::composePluginKey(string libraryName, string identifier) { @@ -185,7 +208,7 @@ m_cleaner.setInstance(instance); } -vector<PluginLoader::PluginKey> +PluginLoader::PluginKeyList PluginLoader::Impl::listPlugins() { if (!m_allPluginsEnumerated) enumeratePlugins(); @@ -199,6 +222,25 @@ return plugins; } +PluginLoader::PluginStaticDataList +PluginLoader::Impl::listPluginData() +{ + PluginKeyList keys = listPlugins(); + PluginStaticDataList dataList; + + for (PluginKeyList::const_iterator ki = keys.begin(); ki != keys.end(); ++ki) { + string key = *ki; + Plugin *p = loadPlugin(key, 44100, 0); + if (p) { + PluginCategoryHierarchy category = getPluginCategory(key); + dataList.push_back(PluginStaticData::fromPlugin(key, category, p)); + } + delete p; + } + + return dataList; +} + void PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin) { @@ -382,6 +424,60 @@ return 0; } +LoadResponse +PluginLoader::Impl::loadPlugin(LoadRequest req) +{ + Plugin *plugin = loadPlugin(req.pluginKey, + req.inputSampleRate, + req.adapterFlags); + LoadResponse response; + response.plugin = plugin; + if (!plugin) return response; + + response.plugin = plugin; + response.staticData = PluginStaticData::fromPlugin + (req.pluginKey, + getPluginCategory(req.pluginKey), + plugin); + + int defaultChannels = 0; + if (plugin->getMinChannelCount() == plugin->getMaxChannelCount()) { + defaultChannels = plugin->getMinChannelCount(); + } + + response.defaultConfiguration = PluginConfiguration::fromPlugin + (plugin, + defaultChannels, + plugin->getPreferredStepSize(), + plugin->getPreferredBlockSize()); + + return response; +} + +ConfigurationResponse +PluginLoader::Impl::configurePlugin(ConfigurationRequest req) +{ + for (PluginConfiguration::ParameterMap::const_iterator i = + req.configuration.parameterValues.begin(); + i != req.configuration.parameterValues.end(); ++i) { + req.plugin->setParameter(i->first, i->second); + } + + if (req.configuration.currentProgram != "") { + req.plugin->selectProgram(req.configuration.currentProgram); + } + + ConfigurationResponse response; + + if (req.plugin->initialise(req.configuration.channelCount, + req.configuration.stepSize, + req.configuration.blockSize)) { + response.outputs = req.plugin->getOutputDescriptors(); + } + + return response; +} + void PluginLoader::Impl::generateTaxonomy() {
--- a/src/vamp-hostsdk/PluginSummarisingAdapter.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/PluginSummarisingAdapter.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -868,10 +868,19 @@ map<float, int> distribution; +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "summing (discrete): "; +#endif for (int k = 0; k < sz; ++k) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << accumulator.results[k].values[bin] << " "; +#endif summary.sum += accumulator.results[k].values[bin]; distribution[accumulator.results[k].values[bin]] += 1; } +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << endl; +#endif int md = 0; @@ -908,11 +917,21 @@ double sum_c = 0.0; +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "summing (continuous): "; +#endif for (int k = 0; k < sz; ++k) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << accumulator.results[k].values[bin] << "*" + << toSec(accumulator.results[k].duration) << " "; +#endif double value = accumulator.results[k].values[bin] * toSec(accumulator.results[k].duration); sum_c += value; } +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << endl; +#endif #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
--- a/src/vamp-hostsdk/Window.h Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/Window.h Mon Oct 10 15:48:35 2016 +0100 @@ -76,8 +76,8 @@ void cut(T *src, T *dst) const { for (size_t i = 0; i < m_size; ++i) dst[i] = src[i] * m_cache[i]; } - template <typename T0> - void cut(T0 *src, T *dst) const { + template <typename T0, typename T1> + void cut(T0 *src, T1 *dst) const { for (size_t i = 0; i < m_size; ++i) dst[i] = src[i] * m_cache[i]; }
--- a/src/vamp-hostsdk/acsymbols.c Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-hostsdk/acsymbols.c Mon Oct 10 15:48:35 2016 +0100 @@ -1,6 +1,7 @@ /* These stubs are provided so that autoconf can check library * versions using C symbols only */ +extern void libvamphostsdk_v_2_7_present(void) { } extern void libvamphostsdk_v_2_6_present(void) { } extern void libvamphostsdk_v_2_5_present(void) { } extern void libvamphostsdk_v_2_4_present(void) { }
--- a/src/vamp-sdk/FFT.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-sdk/FFT.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -36,37 +36,224 @@ #include <vamp-sdk/FFT.h> -#include <cmath> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> -#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 6 ) +#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 7 ) #error Unexpected version of Vamp SDK header included #endif -#ifdef _MSC_VER -#include <stdlib.h> -#include <malloc.h> -#endif - _VAMP_SDK_PLUGSPACE_BEGIN(FFT.cpp) +#include "FFTimpl.cpp" + namespace Vamp { -#include "FFTimpl.cpp" - void -FFT::forward(unsigned int n, +FFT::forward(unsigned int un, const double *ri, const double *ii, double *ro, double *io) { - fft(n, false, ri, ii, ro, io); + int n(un); + Kiss::kiss_fft_cfg c = Kiss::kiss_fft_alloc(n, false, 0, 0); + Kiss::kiss_fft_cpx *in = new Kiss::kiss_fft_cpx[n]; + Kiss::kiss_fft_cpx *out = new Kiss::kiss_fft_cpx[n]; + for (int i = 0; i < n; ++i) { + in[i].r = ri[i]; + in[i].i = 0; + } + if (ii) { + for (int i = 0; i < n; ++i) { + in[i].i = ii[i]; + } + } + kiss_fft(c, in, out); + for (int i = 0; i < n; ++i) { + ro[i] = out[i].r; + io[i] = out[i].i; + } + Kiss::kiss_fft_free(c); + delete[] in; + delete[] out; } void -FFT::inverse(unsigned int n, +FFT::inverse(unsigned int un, const double *ri, const double *ii, double *ro, double *io) { - fft(n, true, ri, ii, ro, io); + int n(un); + Kiss::kiss_fft_cfg c = Kiss::kiss_fft_alloc(n, true, 0, 0); + Kiss::kiss_fft_cpx *in = new Kiss::kiss_fft_cpx[n]; + Kiss::kiss_fft_cpx *out = new Kiss::kiss_fft_cpx[n]; + for (int i = 0; i < n; ++i) { + in[i].r = ri[i]; + in[i].i = 0; + } + if (ii) { + for (int i = 0; i < n; ++i) { + in[i].i = ii[i]; + } + } + kiss_fft(c, in, out); + double scale = 1.0 / double(n); + for (int i = 0; i < n; ++i) { + ro[i] = out[i].r * scale; + io[i] = out[i].i * scale; + } + Kiss::kiss_fft_free(c); + delete[] in; + delete[] out; +} + +class FFTComplex::D +{ +public: + D(int n) : + m_n(n), + m_fconf(Kiss::kiss_fft_alloc(n, false, 0, 0)), + m_iconf(Kiss::kiss_fft_alloc(n, true, 0, 0)), + m_ci(new Kiss::kiss_fft_cpx[m_n]), + m_co(new Kiss::kiss_fft_cpx[m_n]) { } + + ~D() { + Kiss::kiss_fftr_free(m_fconf); + Kiss::kiss_fftr_free(m_iconf); + delete[] m_ci; + delete[] m_co; + } + + void forward(const double *ci, double *co) { + for (int i = 0; i < m_n; ++i) { + m_ci[i].r = ci[i*2]; + m_ci[i].i = ci[i*2+1]; + } + Kiss::kiss_fft(m_fconf, m_ci, m_co); + for (int i = 0; i < m_n; ++i) { + co[i*2] = m_co[i].r; + co[i*2+1] = m_co[i].i; + } + } + + void inverse(const double *ci, double *co) { + for (int i = 0; i < m_n; ++i) { + m_ci[i].r = ci[i*2]; + m_ci[i].i = ci[i*2+1]; + } + Kiss::kiss_fft(m_iconf, m_ci, m_co); + double scale = 1.0 / double(m_n); + for (int i = 0; i < m_n; ++i) { + co[i*2] = m_co[i].r * scale; + co[i*2+1] = m_co[i].i * scale; + } + } + +private: + int m_n; + Kiss::kiss_fft_cfg m_fconf; + Kiss::kiss_fft_cfg m_iconf; + Kiss::kiss_fft_cpx *m_ci; + Kiss::kiss_fft_cpx *m_co; +}; + +FFTComplex::FFTComplex(unsigned int n) : + m_d(new D(n)) +{ +} + +FFTComplex::~FFTComplex() +{ + delete m_d; +} + +void +FFTComplex::forward(const double *ci, double *co) +{ + m_d->forward(ci, co); +} + +void +FFTComplex::inverse(const double *ci, double *co) +{ + m_d->inverse(ci, co); +} + +class FFTReal::D +{ +public: + D(int n) : + m_n(n), + m_fconf(Kiss::kiss_fftr_alloc(n, false, 0, 0)), + m_iconf(Kiss::kiss_fftr_alloc(n, true, 0, 0)), + m_ri(new Kiss::kiss_fft_scalar[m_n]), + m_ro(new Kiss::kiss_fft_scalar[m_n]), + m_freq(new Kiss::kiss_fft_cpx[n/2+1]) { } + + ~D() { + Kiss::kiss_fftr_free(m_fconf); + Kiss::kiss_fftr_free(m_iconf); + delete[] m_ri; + delete[] m_ro; + delete[] m_freq; + } + + void forward(const double *ri, double *co) { + for (int i = 0; i < m_n; ++i) { + // in case kiss_fft_scalar is float + m_ri[i] = ri[i]; + } + Kiss::kiss_fftr(m_fconf, m_ri, m_freq); + int hs = m_n/2 + 1; + for (int i = 0; i < hs; ++i) { + co[i*2] = m_freq[i].r; + co[i*2+1] = m_freq[i].i; + } + } + + void inverse(const double *ci, double *ro) { + int hs = m_n/2 + 1; + for (int i = 0; i < hs; ++i) { + m_freq[i].r = ci[i*2]; + m_freq[i].i = ci[i*2+1]; + } + Kiss::kiss_fftri(m_iconf, m_freq, m_ro); + double scale = 1.0 / double(m_n); + for (int i = 0; i < m_n; ++i) { + ro[i] = m_ro[i] * scale; + } + } + +private: + int m_n; + Kiss::kiss_fftr_cfg m_fconf; + Kiss::kiss_fftr_cfg m_iconf; + Kiss::kiss_fft_scalar *m_ri; + Kiss::kiss_fft_scalar *m_ro; + Kiss::kiss_fft_cpx *m_freq; +}; + +FFTReal::FFTReal(unsigned int n) : + m_d(new D(n)) +{ +} + +FFTReal::~FFTReal() +{ + delete m_d; +} + +void +FFTReal::forward(const double *ri, double *co) +{ + m_d->forward(ri, co); +} + +void +FFTReal::inverse(const double *ci, double *ro) +{ + m_d->inverse(ci, ro); } }
--- a/src/vamp-sdk/FFTimpl.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-sdk/FFTimpl.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -1,116 +1,32 @@ -/* Public domain FFT implementation from Don Cross. */ +// Override C linkage for KissFFT headers. So long as we have already +// included all of the other (system etc) headers KissFFT depends on, +// this should work out OK +#undef __cplusplus -static void -fft(unsigned int n, bool inverse, - const double *ri, const double *ii, - double *ro, double *io) -{ - if (!ri || !ro || !io) return; +namespace Kiss { - unsigned int bits; - unsigned int i, j, k, m; - unsigned int blockSize, blockEnd; +#undef KISS_FFT_H +#undef KISS_FTR_H +#undef KISS_FFT__GUTS_H +#undef FIXED_POINT +#undef USE_SIMD +#undef kiss_fft_scalar - double tr, ti; - - if (n < 2) return; - if (n & (n-1)) return; - - double angle = 2.0 * M_PI; - if (inverse) angle = -angle; - - for (i = 0; ; ++i) { - if (n & (1 << i)) { - bits = i; - break; - } - } - -#ifdef _MSC_VER - int *table = (int *)_malloca(n * sizeof(int)); +#ifdef SINGLE_PRECISION_FFT +#pragma message("Using single-precision FFTs") +typedef float kiss_fft_scalar; +#define kiss_fft_scalar float #else - int table[n]; +typedef double kiss_fft_scalar; +#define kiss_fft_scalar double #endif - for (i = 0; i < n; ++i) { - m = i; - for (j = k = 0; j < bits; ++j) { - k = (k << 1) | (m & 1); - m >>= 1; - } - table[i] = k; - } +inline void free(void *ptr) { ::free(ptr); } +#include "ext/kiss_fft.c" +#include "ext/kiss_fftr.c" - if (ii) { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = ii[i]; - } - } else { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = 0.0; - } - } +#undef kiss_fft_scalar // leaving only the namespaced typedef - blockEnd = 1; - - for (blockSize = 2; blockSize <= n; blockSize <<= 1) { - - double delta = angle / (double)blockSize; - double sm2 = -sin(-2 * delta); - double sm1 = -sin(-delta); - double cm2 = cos(-2 * delta); - double cm1 = cos(-delta); - double w = 2 * cm1; - double ar[3], ai[3]; - - for (i = 0; i < n; i += blockSize) { - - ar[2] = cm2; - ar[1] = cm1; - - ai[2] = sm2; - ai[1] = sm1; - - for (j = i, m = 0; m < blockEnd; j++, m++) { - - ar[0] = w * ar[1] - ar[2]; - ar[2] = ar[1]; - ar[1] = ar[0]; - - ai[0] = w * ai[1] - ai[2]; - ai[2] = ai[1]; - ai[1] = ai[0]; - - k = j + blockEnd; - tr = ar[0] * ro[k] - ai[0] * io[k]; - ti = ar[0] * io[k] + ai[0] * ro[k]; - - ro[k] = ro[j] - tr; - io[k] = io[j] - ti; - - ro[j] += tr; - io[j] += ti; - } - } - - blockEnd = blockSize; - } - - if (inverse) { - - double denom = (double)n; - - for (i = 0; i < n; i++) { - ro[i] /= denom; - io[i] /= denom; - } - } - -#ifdef _MSC_VER - _freea(table); -#endif }
--- a/src/vamp-sdk/PluginAdapter.cpp Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-sdk/PluginAdapter.cpp Mon Oct 10 15:48:35 2016 +0100 @@ -39,7 +39,7 @@ #include <cstring> #include <cstdlib> -#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 6 ) +#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 7 ) #error Unexpected version of Vamp SDK header included #endif
--- a/src/vamp-sdk/acsymbols.c Thu Aug 18 12:00:24 2016 +0100 +++ b/src/vamp-sdk/acsymbols.c Mon Oct 10 15:48:35 2016 +0100 @@ -1,6 +1,7 @@ /* These stubs are provided so that autoconf can check library * versions using C symbols only */ +extern void libvampsdk_v_2_7_present(void) { } extern void libvampsdk_v_2_6_present(void) { } extern void libvampsdk_v_2_5_present(void) { } extern void libvampsdk_v_2_4_present(void) { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-sdk/ext/_kiss_fft_guts.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,168 @@ +#ifndef KISS_FFT__GUTS_H +#define KISS_FFT__GUTS_H +/* +Copyright (c) 2003-2010, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 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. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. +*/ + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" +#include <limits.h> + +#define MAXFACTORS 32 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +struct kiss_fft_state{ + int nfft; + int inverse; + int factors[2*MAXFACTORS]; + kiss_fft_cpx twiddles[1]; +}; + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#if (FIXED_POINT==32) +# define FRACBITS 31 +# define SAMPPROD int64_t +#define SAMP_MAX 2147483647 +#else +# define FRACBITS 15 +# define SAMPPROD int32_t +#define SAMP_MAX 32767 +#endif + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) + +# define S_MUL(a,b) sround( smul(a,b) ) + +# define C_MUL(m,a,b) \ + do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) + +# define DIVSCALAR(x,k) \ + (x) = sround( smul( x, SAMP_MAX/k ) ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = sround( smul( (c).r , s ) ) ;\ + (c).i = sround( smul( (c).i , s ) ) ; }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) + + +#ifdef FIXED_POINT +# define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + + +/* a debugging function */ +#define pcpx(c)\ + fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) + + +#ifdef KISS_FFT_USE_ALLOCA +// define this to allow use of alloca instead of malloc for temporary buffers +// Temporary buffers are used in two case: +// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5 +// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform. +#include <alloca.h> +#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes) +#define KISS_FFT_TMP_FREE(ptr) +#else +#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) +#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-sdk/ext/kiss_fft.c Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,409 @@ +/* +Copyright (c) 2003-2010, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 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. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. +*/ + + +#include "_kiss_fft_guts.h" +/* The guts header contains all the multiplication and addition macros that are defined for + fixed or floating point complex numbers. It also delares the kf_ internal functions. + */ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx * Fout2; + kiss_fft_cpx * tw1 = st->twiddles; + kiss_fft_cpx t; + Fout2 = Fout + m; + do{ + C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); + + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + }while (--m); +} + +static void kf_bfly4( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + const size_t m + ) +{ + kiss_fft_cpx *tw1,*tw2,*tw3; + kiss_fft_cpx scratch[6]; + size_t k=m; + const size_t m2=2*m; + const size_t m3=3*m; + + + tw3 = tw2 = tw1 = st->twiddles; + + do { + C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); + + C_MUL(scratch[0],Fout[m] , *tw1 ); + C_MUL(scratch[1],Fout[m2] , *tw2 ); + C_MUL(scratch[2],Fout[m3] , *tw3 ); + + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + if(st->inverse) { + Fout[m].r = scratch[5].r - scratch[4].i; + Fout[m].i = scratch[5].i + scratch[4].r; + Fout[m3].r = scratch[5].r + scratch[4].i; + Fout[m3].i = scratch[5].i - scratch[4].r; + }else{ + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + } + ++Fout; + }while(--k); +} + +static void kf_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + size_t m + ) +{ + size_t k=m; + const size_t m2 = 2*m; + kiss_fft_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_fft_cpx epi3; + epi3 = st->twiddles[fstride*m]; + + tw1=tw2=st->twiddles; + + do{ + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int u; + kiss_fft_cpx scratch[13]; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx *tw; + kiss_fft_cpx ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=st->twiddles; + for ( u=0; u<m; ++u ) { + C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5); + scratch[0] = *Fout0; + + C_MUL(scratch[1] ,*Fout1, tw[u*fstride]); + C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]); + C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]); + C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]); + + C_ADD( scratch[7],scratch[1],scratch[4]); + C_SUB( scratch[10],scratch[1],scratch[4]); + C_ADD( scratch[8],scratch[2],scratch[3]); + C_SUB( scratch[9],scratch[2],scratch[3]); + + Fout0->r += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } +} + +/* perform the butterfly for one stage of a mixed radix FFT */ +static void kf_bfly_generic( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int p + ) +{ + int u,k,q1,q; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx t; + int Norig = st->nfft; + + kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); + + for ( u=0; u<m; ++u ) { + k=u; + for ( q1=0 ; q1<p ; ++q1 ) { + scratch[q1] = Fout[ k ]; + C_FIXDIV(scratch[q1],p); + k += m; + } + + k=u; + for ( q1=0 ; q1<p ; ++q1 ) { + int twidx=0; + Fout[ k ] = scratch[0]; + for (q=1;q<p;++q ) { + twidx += fstride * k; + if (twidx>=Norig) twidx-=Norig; + C_MUL(t,scratch[q] , twiddles[twidx] ); + C_ADDTO( Fout[ k ] ,t); + } + k += m; + } + } + KISS_FFT_TMP_FREE(scratch); +} + +static +void kf_work( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + kiss_fft_cpx * Fout_beg=Fout; + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + const kiss_fft_cpx * Fout_end = Fout + p*m; + +#ifdef _OPENMP + // use openmp extensions at the + // top-level (not recursive) + if (fstride==1 && p<=5) + { + int k; + + // execute the p different work units in different threads +# pragma omp parallel for + for (k=0;k<p;++k) + kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st); + // all threads have joined by this point + + switch (p) { + case 2: kf_bfly2(Fout,fstride,st,m); break; + case 3: kf_bfly3(Fout,fstride,st,m); break; + case 4: kf_bfly4(Fout,fstride,st,m); break; + case 5: kf_bfly5(Fout,fstride,st,m); break; + default: kf_bfly_generic(Fout,fstride,st,m,p); break; + } + return; + } +#endif + + if (m==1) { + do{ + Fout->r = f->r; + Fout->i = f->i; + f += fstride*in_stride; + }while(++Fout != Fout_end ); + }else{ + do{ + // recursive call: + // DFT of size m*p performed by doing + // p instances of smaller DFTs of size m, + // each one takes a decimated version of the input + kf_work( Fout , f, fstride*p, in_stride, factors,st); + f += fstride*in_stride; + }while( (Fout += m) != Fout_end ); + } + + Fout=Fout_beg; + + // recombine the p smaller DFTs + switch (p) { + case 2: kf_bfly2(Fout,fstride,st,m); break; + case 3: kf_bfly3(Fout,fstride,st,m); break; + case 4: kf_bfly4(Fout,fstride,st,m); break; + case 5: kf_bfly5(Fout,fstride,st,m); break; + default: kf_bfly_generic(Fout,fstride,st,m,p); break; + } +} + +/* facbuf is populated by p1,m1,p2,m2, ... + where + p[i] * m[i] = m[i-1] + m0 = n */ +static +void kf_factor(int n,int * facbuf) +{ + int p=4; + double floor_sqrt; + floor_sqrt = floor( sqrt((double)n) ); + + /*factor out powers of 4, powers of 2, then any remaining primes */ + do { + while (n % p) { + switch (p) { + case 4: p = 2; break; + case 2: p = 3; break; + default: p += 2; break; + } + if (p > floor_sqrt) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); +} + +/* + * + * User-callable function to allocate all necessary storage space for the fft. + * + * The return value is a contiguous block of memory, allocated with malloc. As such, + * It can be freed with free(), rather than a kiss_fft-specific function. + * */ +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) +{ + kiss_fft_cfg st=NULL; + size_t memneeded = sizeof(struct kiss_fft_state) + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ + + if ( lenmem==NULL ) { + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); + }else{ + if (mem != NULL && *lenmem >= memneeded) + st = (kiss_fft_cfg)mem; + *lenmem = memneeded; + } + if (st) { + int i; + st->nfft=nfft; + st->inverse = inverse_fft; + + for (i=0;i<nfft;++i) { + const double pi=3.141592653589793238462643383279502884197169399375105820974944; + double phase = -2*pi*i / nfft; + if (st->inverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } + + kf_factor(nfft,st->factors); + } + return st; +} + + +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + if (fin == fout) { + //NOTE: this is not really an in-place FFT algorithm. + //It just performs an out-of-place FFT into a temp buffer + kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); + KISS_FFT_TMP_FREE(tmpbuf); + }else{ + kf_work( fout, fin, 1,in_stride, st->factors,st ); + } +} + +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + + +void kiss_fft_cleanup(void) +{ + // nothing needed any more +} + +int kiss_fft_next_fast_size(int n) +{ + while(1) { + int m=n; + while ( (m%2) == 0 ) m/=2; + while ( (m%3) == 0 ) m/=3; + while ( (m%5) == 0 ) m/=5; + if (m<=1) + break; /* n is completely factorable by twos, threes, and fives */ + n++; + } + return n; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-sdk/ext/kiss_fft.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,124 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include <xmmintrin.h> +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) +#define KISS_FFT_FREE _mm_free +#else +#define KISS_FFT_MALLOC malloc +#define KISS_FFT_FREE free +#endif + + +#ifdef FIXED_POINT +#include <sys/types.h> +# if (FIXED_POINT == 32) +# define kiss_fft_scalar int32_t +# else +# define kiss_fft_scalar int16_t +# endif +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +/* + A more generic version of the above function. It reads its input from every Nth sample. + * */ +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); + +/* If kiss_fft_alloc allocated a buffer, it is one contiguous + buffer and can be simply free()d when no longer needed*/ +#define kiss_fft_free free + +/* + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + your compiler output to call this before you exit. +*/ +void kiss_fft_cleanup(void); + + +/* + * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) + */ +int kiss_fft_next_fast_size(int n); + +/* for real ffts, we need an even size */ +#define kiss_fftr_next_fast_size_real(n) \ + (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-sdk/ext/kiss_fftr.c Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,159 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 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. + * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. +*/ + +#include "kiss_fftr.h" +#include "_kiss_fft_guts.h" + +struct kiss_fftr_state{ + kiss_fft_cfg substate; + kiss_fft_cpx * tmpbuf; + kiss_fft_cpx * super_twiddles; +#ifdef USE_SIMD + void * pad; +#endif +}; + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) +{ + int i; + kiss_fftr_cfg st = NULL; + size_t subsize, memneeded; + + if (nfft & 1) { + fprintf(stderr,"Real FFT optimization must be even.\n"); + return NULL; + } + nfft >>= 1; + + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2); + + if (lenmem == NULL) { + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); + } else { + if (*lenmem >= memneeded) + st = (kiss_fftr_cfg) mem; + *lenmem = memneeded; + } + if (!st) + return NULL; + + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); + st->super_twiddles = st->tmpbuf + nfft; + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); + + for (i = 0; i < nfft/2; ++i) { + double phase = + -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); + if (inverse_fft) + phase *= -1; + kf_cexp (st->super_twiddles+i,phase); + } + return st; +} + +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; + + if ( st->substate->inverse) { + fprintf(stderr,"kiss fft usage error: improper alloc\n"); + exit(1); + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0].r = tdc.r + tdc.i; + freqdata[ncfft].r = tdc.r - tdc.i; +#ifdef USE_SIMD + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); +#else + freqdata[ncfft].i = freqdata[0].i = 0; +#endif + + for ( k=1;k <= ncfft/2 ; ++k ) { + fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( tw , f2k , st->super_twiddles[k-1]); + + freqdata[k].r = HALF_OF(f1k.r + tw.r); + freqdata[k].i = HALF_OF(f1k.i + tw.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); + } +} + +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + fprintf (stderr, "kiss fft usage error: improper alloc\n"); + exit (1); + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + C_FIXDIV(st->tmpbuf[0],2); + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 ); + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k-1]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-sdk/ext/kiss_fftr.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,46 @@ +#ifndef KISS_FTR_H +#define KISS_FTR_H + +#include "kiss_fft.h" +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. + + + + */ + +typedef struct kiss_fftr_state *kiss_fftr_cfg; + + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); +/* + nfft must be even + + If you don't care to allocate space, use mem = lenmem = NULL +*/ + + +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ + +#define kiss_fftr_free free + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/expected/vamp-test-plugin-freq_curve-fsr-mixed.txt Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,11 @@ +=== vamp-test-plugin:vamp-test-plugin-freq:curve-fsr-mixed + 2.400000000: 0 1 of 10: 0 at 2.4 snap to 2.4 + 2.800000000: 0.1 2 of 10: 0.1 at 2.9 snap to 2.8 + 3.200000000: 0.2 3 of 10: 0.2 at 3.14 snap to 3.2 + 3.600000000: 0.3 4 of 10: 0.3 at 3.5 snap to 3.6 + 4.000000000: 0.4 5 of 10: 0.4 at 4 + 4.400000000: 0.5 6 of 10: 0.5 at 4.4 + 4.000000000: 0.6 7 of 10: 0.6 at 3.9 snap to 4 + 4.400000000: 0.7 8 of 10: 0.7 at 4.4 snap to 4.4 + 4.800000000: 0.8 9 of 10: 0.8 at 4.8 + 5.200000000: 0.9 10 of 10: 0.9 at 5 snap to 5.2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/expected/vamp-test-plugin_curve-fsr-mixed.txt Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,11 @@ +=== vamp-test-plugin:vamp-test-plugin:curve-fsr-mixed + 2.400000000: 0 1 of 10: 0 at 2.4 snap to 2.4 + 2.800000000: 0.1 2 of 10: 0.1 at 2.9 snap to 2.8 + 3.200000000: 0.2 3 of 10: 0.2 at 3.14 snap to 3.2 + 3.600000000: 0.3 4 of 10: 0.3 at 3.5 snap to 3.6 + 4.000000000: 0.4 5 of 10: 0.4 at 4 + 4.400000000: 0.5 6 of 10: 0.5 at 4.4 + 4.000000000: 0.6 7 of 10: 0.6 at 3.9 snap to 4 + 4.400000000: 0.7 8 of 10: 0.7 at 4.4 snap to 4.4 + 4.800000000: 0.8 9 of 10: 0.8 at 4.8 + 5.200000000: 0.9 10 of 10: 0.9 at 5 snap to 5.2
--- a/test/run-test-plugin-regression.sh Thu Aug 18 12:00:24 2016 +0100 +++ b/test/run-test-plugin-regression.sh Mon Oct 10 15:48:35 2016 +0100 @@ -7,8 +7,7 @@ TEST_PLUGIN_DIR="$MYDIR/../../vamp-test-plugin" HOST_DIR="$MYDIR/../host" HOST="$HOST_DIR/vamp-simple-host" -#TEST_FILE="$MYDIR/20sec-silence.wav" -TEST_FILE="/tmp/test.wav" +TEST_FILE="$MYDIR/testsignal.wav" mkdir -p "$MYDIR/obtained" mkdir -p "$MYDIR/failures"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testsignal.ipynb Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,236 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import librosa\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "block=1024\n", + "length=block*20" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "diracs = [ x/float(length) if (x % block) == 0 else 0.0 for x in range(0,length) ]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7f7fe1e18320>]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nAAAASUVORK5CYII=\n", + "text/plain": [ + "<matplotlib.figure.Figure at 0x7f8020199278>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(diracs)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import math\n", + "wave = [ (int(x/block) / float(length/block)) * math.sin(x*math.pi/(block/8)) for x in range(0,length)]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7f7fe1e54780>]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<matplotlib.figure.Figure at 0x7f7fe1e54cc0>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(wave)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "duration=20.0\n", + "rate=22050\n", + "nsamples=duration*rate\n", + "repeats=int(nsamples/length)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "data=[diracs * repeats, wave * repeats]" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "ndata = np.uint8(np.array(data) * 127.0 + 128.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(430080, 2)" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ndata = np.swapaxes(ndata, 0, 1)\n", + "ndata.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from scipy.io.wavfile import write\n", + "write('/tmp/test.wav', rate, ndata)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginConfiguration.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,113 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2016 Chris Cannam and QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef VAMP_PLUGIN_CONFIGURATION_H +#define VAMP_PLUGIN_CONFIGURATION_H + +#include "hostguard.h" + +#include "Plugin.h" + +#include <map> +#include <string> + +_VAMP_SDK_HOSTSPACE_BEGIN(PluginConfiguration.h) + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginConfiguration PluginConfiguration.h <vamp-hostsdk/PluginConfiguration.h> + * + * Vamp::HostExt::PluginConfiguration is a structure bundling together + * data that affect the configuration of a plugin: parameter values, + * programs, and initialisation settings. Although an interactive Vamp + * plugin host may configure a plugin in stages, for example to take + * into account that a plugin's preferred step and block size may + * change when its parameters are changed, a batch host or a host + * supporting store and recall of configurations may wish to keep all + * configuration settings together. + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK. + */ +struct PluginConfiguration +{ + PluginConfiguration() : // invalid configuration by default + channelCount(0), stepSize(0), blockSize(0) { } + + int channelCount; + int stepSize; + int blockSize; + typedef std::map<std::string, float> ParameterMap; + ParameterMap parameterValues; + std::string currentProgram; + + static PluginConfiguration + fromPlugin(Plugin *p, + int channelCount, + int stepSize, + int blockSize) { + + PluginConfiguration c; + + c.channelCount = channelCount; + c.stepSize = stepSize; + c.blockSize = blockSize; + + PluginBase::ParameterList params = p->getParameterDescriptors(); + for (PluginBase::ParameterList::const_iterator i = params.begin(); + i != params.end(); ++i) { + std::string pid = i->identifier; + c.parameterValues[pid] = p->getParameter(pid); + } + + if (!p->getPrograms().empty()) { + c.currentProgram = p->getCurrentProgram(); + } + + return c; + } +}; + +} + +} + +_VAMP_SDK_HOSTSPACE_END(PluginConfiguration.h) + +#endif
--- a/vamp-hostsdk/PluginLoader.h Thu Aug 18 12:00:24 2016 +0100 +++ b/vamp-hostsdk/PluginLoader.h Mon Oct 10 15:48:35 2016 +0100 @@ -43,6 +43,7 @@ #include "hostguard.h" #include "PluginWrapper.h" +#include "RequestResponse.h" _VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.h) @@ -122,12 +123,28 @@ typedef std::vector<std::string> PluginCategoryHierarchy; /** + * PluginStaticDataList is a list containing static information + * about a set of Vamp plugins. + * + * \see PluginStaticData, listPluginData() + */ + typedef std::vector<PluginStaticData> PluginStaticDataList; + + /** * Search for all available Vamp plugins, and return a list of * them in the order in which they were found. */ PluginKeyList listPlugins(); /** + * Search for all available Vamp plugins, and return a list of + * static data about each plugin in the order in which they were + * found. This is slower but returns more comprehensive + * information than listPlugins(). + */ + PluginStaticDataList listPluginData(); + + /** * AdapterFlags contains a set of values that may be OR'd together * to indicate in which circumstances PluginLoader should use a * plugin adapter to make a plugin easier to use for a host that @@ -202,6 +219,33 @@ int adapterFlags = 0); /** + * Load a Vamp plugin, given its key, inputSampleRate and the + * adapter flags, bundled into a LoadRequest structure. The loaded + * plugin is returned along with its static data and default + * configuration in a LoadResponse. + * + * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter, LoadRequest, LoadResponse + */ + LoadResponse loadPlugin(LoadRequest req); + + /** + * Configure and initialise a Vamp plugin. This applies the + * parameter and program settings found in the PluginConfiguration + * part of the supplied ConfigurationRequest and initialises the + * plugin. (Many hosts will prefer to do this themselves in + * stages, by calling methods on the plugin directly.) + * + * Return a ConfigurationResponse containing the result of calling + * getOutputDescriptors() on the configured and initialised + * plugin, representing the outputs of the plugin following + * configuration (since output ranges etc can depend on the + * parameters). If initialisation fails, returns an empty list. + * + * \see PluginConfiguration, ConfigurationRequest, ConfigurationResponse + */ + ConfigurationResponse configurePlugin(ConfigurationRequest req); + + /** * Given a Vamp plugin library name and plugin identifier, return * the corresponding plugin key in a form suitable for passing in to * loadPlugin().
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginStaticData.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,133 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2016 Chris Cannam and QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef VAMP_PLUGIN_STATIC_DATA_H +#define VAMP_PLUGIN_STATIC_DATA_H + +#include "hostguard.h" +#include "Plugin.h" + +_VAMP_SDK_HOSTSPACE_BEGIN(PluginStaticData.h) + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginStaticData PluginStaticData.h <vamp-hostsdk/PluginStaticData.h> + * + * Vamp::HostExt::PluginStaticData is a structure bundling together + * all the information about a plugin that cannot be changed by the + * plugin after it is loaded. That is, everything that does not depend + * on a parameter or initialisation setting. + * + * All of the information in here can be queried from other sources + * directly (notably the Plugin class itself); this structure just + * pulls it together in one place and provides something that can be + * stored and recalled without having a Plugin object to hand. + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK and is used only by host SDK functions that were also + * introduced in that release (or newer). + */ +struct PluginStaticData +{ +public: + struct Basic { + std::string identifier; + std::string name; + std::string description; + }; + typedef std::vector<Basic> BasicList; + + PluginStaticData() : // invalid static data by default + pluginVersion(0), minChannelCount(0), maxChannelCount(0), + inputDomain(Plugin::TimeDomain) { } + + std::string pluginKey; + Basic basic; + std::string maker; + std::string copyright; + int pluginVersion; + std::vector<std::string> category; + int minChannelCount; + int maxChannelCount; + PluginBase::ParameterList parameters; + PluginBase::ProgramList programs; + Plugin::InputDomain inputDomain; + BasicList basicOutputInfo; + + static PluginStaticData + fromPlugin(std::string pluginKey, + std::vector<std::string> category, + Plugin *p) { + + PluginStaticData d; + d.pluginKey = pluginKey; + d.basic.identifier = p->getIdentifier(); + d.basic.name = p->getName(); + d.basic.description = p->getDescription(); + d.maker = p->getMaker(); + d.copyright = p->getCopyright(); + d.pluginVersion = p->getPluginVersion(); + d.category = category; + d.minChannelCount = p->getMinChannelCount(); + d.maxChannelCount = p->getMaxChannelCount(); + d.parameters = p->getParameterDescriptors(); + d.programs = p->getPrograms(); + d.inputDomain = p->getInputDomain(); + + Plugin::OutputList outputs = p->getOutputDescriptors(); + for (Plugin::OutputList::const_iterator i = outputs.begin(); + i != outputs.end(); ++i) { + Basic b; + b.identifier = i->identifier; + b.name = i->name; + b.description = i->description; + d.basicOutputInfo.push_back(b); + } + + return d; + } +}; + +} + +} + +_VAMP_SDK_HOSTSPACE_END(PluginStaticData.h) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/RequestResponse.h Mon Oct 10 15:48:35 2016 +0100 @@ -0,0 +1,250 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2016 Chris Cannam and QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef VAMP_REQUEST_RESPONSE_H +#define VAMP_REQUEST_RESPONSE_H + +#include "PluginStaticData.h" +#include "PluginConfiguration.h" + +#include "hostguard.h" + +#include <map> +#include <string> + +_VAMP_SDK_HOSTSPACE_BEGIN(RequestResponse.h) + +namespace Vamp { + +class Plugin; + +namespace HostExt { + +/** + * \class LoadRequest RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * Vamp::HostExt::LoadRequest is a structure containing the + * information necessary to load a plugin. When a request is made to + * load a plugin using a LoadRequest, the response is typically + * returned in a LoadResponse structure. + * + * \see LoadResponse + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, along with the PluginLoader method that accepts this structure + * rather than accepting its elements individually. + */ +struct LoadRequest +{ + LoadRequest() : // invalid request by default + inputSampleRate(0.f), + adapterFlags(0) { } + + /** + * PluginKey is a string type that is used to identify a plugin + * uniquely within the scope of "the current system". For further + * details \see PluginLoader::PluginKey. + */ + typedef std::string PluginKey; + + /** + * The identifying key for the plugin to be loaded. + */ + PluginKey pluginKey; + + /** + * Sample rate to be passed to the plugin's constructor. + */ + float inputSampleRate; + + /** + * A bitwise OR of the values in the PluginLoader::AdapterFlags + * enumeration, indicating under which circumstances an adapter + * should be used to wrap the original plugin. If adapterFlags is + * 0, no optional adapters will be used. + * + * \see PluginLoader::AdapterFlags, PluginLoader::loadPlugin + */ + int adapterFlags; +}; + +/** + * \class LoadResponse RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * Vamp::HostExt::LoadResponse is a structure containing the + * information returned by PluginLoader when asked to load a plugin + * using a LoadRequest. + * + * If the plugin could not be loaded, the plugin field will be 0. + * + * The caller takes ownership of the plugin contained here, which + * should be deleted (using the standard C++ delete keyword) after + * use. + * + * \see LoadRequest + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, along with the PluginLoader method that returns this structure. + */ +struct LoadResponse +{ + LoadResponse() : // invalid (failed) response by default + plugin(0) { } + + /** + * A pointer to the loaded plugin, or 0 if loading failed. Caller + * takes ownership of the plugin and must delete it after use. + */ + Plugin *plugin; + + /** + * The static data associated with the loaded plugin, that is, all + * information about it that does not depend on its configuration + * (parameters, programs, initialisation parameters). The contents + * of this structure are only valid if plugin is non-0. + * + * Much of the data in here is duplicated with the plugin itself. + */ + PluginStaticData staticData; + + /** + * The default configuration for this plugin, that is, default + * values for parameters etc. The contents of this structure are + * only valid if plugin is non-0. + */ + PluginConfiguration defaultConfiguration; +}; + +/** + * \class ConfigurationRequest RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * A wrapper for a plugin pointer and PluginConfiguration, bundling up + * the data needed to configure a plugin after it has been loaded. + * + * \see PluginConfiguration, ConfigurationResponse, LoadRequest, LoadResponse + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, along with the PluginLoader method that returns this structure. + */ +struct ConfigurationRequest +{ +public: + ConfigurationRequest() : // invalid request by default + plugin(0) { } + + Plugin *plugin; + PluginConfiguration configuration; +}; + +/** + * \class ConfigurationResponse RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * The return value from a configuration request (i.e. setting the + * parameters and initialising the plugin). If the configuration was + * successful, the output list will contain the final + * post-initialisation output descriptors. If configuration failed, + * the output list will be empty. + * + * \see PluginConfiguration, ConfigurationRequest, LoadRequest, LoadResponse + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, along with the PluginLoader method that returns this structure. + */ +struct ConfigurationResponse +{ +public: + ConfigurationResponse() // failed by default + { } + + Plugin::OutputList outputs; +}; + +/** + * \class ProcessRequest RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * A structure that bundles the necessary data for making a process + * call: plugin, input buffers, and timestamp. Caller retains + * ownership of the plugin, but the buffers are passed "by value" to + * avoid ownership concerns. + * + * \see Plugin::process() + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, but it is not currently used by the SDK. It is supplied as a + * convenience for code using the SDK, and for symmetry with the load + * and configuration request structs. + */ +struct ProcessRequest +{ +public: + ProcessRequest() : // invalid by default + plugin(0) { } + + Plugin *plugin; + std::vector<std::vector<float> > inputBuffers; + RealTime timestamp; +}; + +/** + * \class ProcessResponse RequestResponse.h <vamp-hostsdk/RequestResponse.h> + * + * A structure that bundles the data returned by a process call and by + * Plugin::getRemainingFeatures(). This is simply a FeatureSet + * wrapper, named for symmetry with the other request-response pairs. + * + * \see Plugin::process(), Plugin::getRemainingFeatures() + * + * \note This class was introduced in version 2.7 of the Vamp plugin + * SDK, but it is not currently used by the SDK. It is supplied as a + * convenience for code using the SDK, and for symmetry with the load + * and configuration request structs. + */ +struct ProcessResponse +{ +public: + ProcessResponse() // empty by default + { } + + Plugin::FeatureSet features; +}; + +} + +} + +_VAMP_SDK_HOSTSPACE_END(RequestResponse.h) + +#endif
--- a/vamp-hostsdk/hostguard.h Thu Aug 18 12:00:24 2016 +0100 +++ b/vamp-hostsdk/hostguard.h Mon Oct 10 15:48:35 2016 +0100 @@ -43,9 +43,9 @@ #define _VAMP_IN_HOSTSDK -#define VAMP_SDK_VERSION "2.6" +#define VAMP_SDK_VERSION "2.7" #define VAMP_SDK_MAJOR_VERSION 2 -#define VAMP_SDK_MINOR_VERSION 6 +#define VAMP_SDK_MINOR_VERSION 7 #ifdef _VAMP_NO_HOST_NAMESPACE #define _VAMP_SDK_HOSTSPACE_BEGIN(h)
--- a/vamp-sdk/FFT.h Thu Aug 18 12:00:24 2016 +0100 +++ b/vamp-sdk/FFT.h Mon Oct 10 15:48:35 2016 +0100 @@ -44,23 +44,24 @@ /** * A simple FFT implementation provided for convenience of plugin - * authors. - * - * This class provides double-precision FFTs in power-of-two sizes - * only. It is slower than more sophisticated library - * implementations. If these requirements aren't suitable, make other - * arrangements. + * authors. This class provides one-shot (i.e. fixed table state is + * recalculated every time) double-precision complex-complex + * transforms. For repeated transforms from real time-domain data, use + * an FFTComplex or FFTReal object instead. * - * The inverse transform is scaled by 1/n. + * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT + * flag, then all FFTs will use single precision internally. The + * default is double precision. The API uses doubles in either case. * - * The implementation is from Don Cross's public domain FFT code. + * The forward transform is unscaled; the inverse transform is scaled + * by 1/n. */ class FFT { public: /** - * Calculate a forward transform of size n. - * n must be a power of 2, greater than 1. + * Calculate a one-shot forward transform of size n. + * n must be a multiple of 2. * * ri and ii must point to the real and imaginary component arrays * of the input. For real input, ii may be NULL. @@ -75,7 +76,7 @@ double *ro, double *io); /** - * Calculate an inverse transform of size n. + * Calculate a one-shot inverse transform of size n. * n must be a power of 2, greater than 1. * * ri and ii must point to the real and imaginary component arrays @@ -93,6 +94,108 @@ double *ro, double *io); }; +/** + * A simple FFT implementation provided for convenience of plugin + * authors. This class provides double-precision complex-complex + * transforms. + * + * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT + * flag, then all FFTs will use single precision internally. The + * default is double precision. The API uses doubles in either case. + * + * The forward transform is unscaled; the inverse transform is scaled + * by 1/n. + */ +class FFTComplex +{ +public: + /** + * Prepare to calculate transforms of size n. + * n must be a multiple of 2. + */ + FFTComplex(unsigned int n); + + ~FFTComplex(); + + /** + * Calculate a forward transform of size n. + * + * ci must point to the interleaved complex input data of size n + * (that is, 2n doubles in total). + * + * co must point to enough space to receive an interleaved complex + * output array of size n (that is, 2n doubles in total). + */ + void forward(const double *ci, double *co); + + /** + * Calculate an inverse transform of size n. + * + * ci must point to an interleaved complex input array of size n + * (that is, 2n doubles in total). + * + * co must point to enough space to receive the interleaved + * complex output data of size n (that is, 2n doubles in + * total). The output is scaled by 1/n. + */ + void inverse(const double *ci, double *co); + +private: + class D; + D *m_d; +}; + +/** + * A simple FFT implementation provided for convenience of plugin + * authors. This class provides transforms between double-precision + * real time-domain and double-precision complex frequency-domain + * data. + * + * Note: If the SDK has been compiled with the SINGLE_PRECISION_FFT + * flag, then all FFTs will use single precision internally. The + * default is double precision. The API uses doubles in either case. + * + * The forward transform is unscaled; the inverse transform is scaled + * by 1/n. + */ +class FFTReal +{ +public: + /** + * Prepare to calculate transforms of size n. + * n must be a multiple of 2. + */ + FFTReal(unsigned int n); + + ~FFTReal(); + + /** + * Calculate a forward transform of size n. + * + * ri must point to the real input data of size n. + * + * co must point to enough space to receive an interleaved complex + * output array of size n/2+1 (that is, n+2 doubles in total). + */ + void forward(const double *ri, double *co); + + /** + * Calculate an inverse transform of size n. + * + * ci must point to an interleaved complex input array of size + * n/2+1 (that is, n+2 doubles in total). + * + * ro must point to enough space to receive the real output data + * of size n. The output is scaled by 1/n and only the real part + * is returned. + */ + void inverse(const double *ci, double *ro); + +private: + class D; + D *m_d; +}; + } _VAMP_SDK_PLUGSPACE_END(FFT.h)
--- a/vamp-sdk/plugguard.h Thu Aug 18 12:00:24 2016 +0100 +++ b/vamp-sdk/plugguard.h Mon Oct 10 15:48:35 2016 +0100 @@ -71,9 +71,9 @@ #define _VAMP_IN_PLUGINSDK 1 -#define VAMP_SDK_VERSION "2.6" +#define VAMP_SDK_VERSION "2.7" #define VAMP_SDK_MAJOR_VERSION 2 -#define VAMP_SDK_MINOR_VERSION 6 +#define VAMP_SDK_MINOR_VERSION 7 #ifdef _VAMP_NO_PLUGIN_NAMESPACE #define _VAMP_SDK_PLUGSPACE_BEGIN(h)