Mercurial > hg > vamp-plugin-sdk
changeset 233:521734d2b498 distinct-libraries
* Flatten directory tree a bit, update doxygen
line wrap: on
line diff
--- a/Makefile Fri Nov 07 14:33:21 2008 +0000 +++ b/Makefile Fri Nov 07 15:28:33 2008 +0000 @@ -7,12 +7,10 @@ SDKDIR = vamp-sdk HOSTSDKDIR = vamp-hostsdk -HOSTEXTDIR = vamp-hostsdk/hostext SRCDIR = src SDKSRCDIR = src/vamp-sdk HOSTSDKSRCDIR = src/vamp-hostsdk -HOSTEXTSRCDIR = src/vamp-hostsdk/hostext EXAMPLEDIR = examples HOSTDIR = host @@ -71,7 +69,7 @@ INSTALL_PREFIX := /usr/local INSTALL_API_HEADERS := $(INSTALL_PREFIX)/include/vamp INSTALL_SDK_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk -INSTALL_HOSTEXT_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk/hostext +INSTALL_HOSTSDK_HEADERS := $(INSTALL_PREFIX)/include/vamp-hostsdk INSTALL_SDK_LIBS := $(INSTALL_PREFIX)/lib INSTALL_SDK_LIBNAME := libvamp-sdk.so.2.0.0 @@ -123,15 +121,13 @@ $(HOSTSDKDIR)/Plugin.h \ $(HOSTSDKDIR)/PluginBase.h \ $(HOSTSDKDIR)/PluginHostAdapter.h \ - $(HOSTSDKDIR)/RealTime.h - -HOSTEXT_HEADERS = \ - $(HOSTEXTDIR)/PluginBufferingAdapter.h \ - $(HOSTEXTDIR)/PluginChannelAdapter.h \ - $(HOSTEXTDIR)/PluginInputDomainAdapter.h \ - $(HOSTEXTDIR)/PluginLoader.h \ - $(HOSTEXTDIR)/PluginSummarisingAdapter.h \ - $(HOSTEXTDIR)/PluginWrapper.h + $(HOSTSDKDIR)/RealTime.h \ + $(HOSTSDKDIR)/PluginBufferingAdapter.h \ + $(HOSTSDKDIR)/PluginChannelAdapter.h \ + $(HOSTSDKDIR)/PluginInputDomainAdapter.h \ + $(HOSTSDKDIR)/PluginLoader.h \ + $(HOSTSDKDIR)/PluginSummarisingAdapter.h \ + $(HOSTSDKDIR)/PluginWrapper.h SDK_OBJECTS = \ $(SDKSRCDIR)/PluginAdapter.o \ @@ -140,12 +136,12 @@ HOSTSDK_OBJECTS = \ $(HOSTSDKSRCDIR)/PluginHostAdapter.o \ $(HOSTSDKSRCDIR)/RealTime.o \ - $(HOSTEXTSRCDIR)/PluginBufferingAdapter.o \ - $(HOSTEXTSRCDIR)/PluginChannelAdapter.o \ - $(HOSTEXTSRCDIR)/PluginInputDomainAdapter.o \ - $(HOSTEXTSRCDIR)/PluginLoader.o \ - $(HOSTEXTSRCDIR)/PluginSummarisingAdapter.o \ - $(HOSTEXTSRCDIR)/PluginWrapper.o + $(HOSTSDKSRCDIR)/PluginBufferingAdapter.o \ + $(HOSTSDKSRCDIR)/PluginChannelAdapter.o \ + $(HOSTSDKSRCDIR)/PluginInputDomainAdapter.o \ + $(HOSTSDKSRCDIR)/PluginLoader.o \ + $(HOSTSDKSRCDIR)/PluginSummarisingAdapter.o \ + $(HOSTSDKSRCDIR)/PluginWrapper.o SDK_STATIC = \ $(SRCDIR)/libvamp-sdk.a @@ -215,13 +211,13 @@ $(SDK_STATIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) $(AR) r $@ $(SDK_OBJECTS) -$(HOSTSDK_STATIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) +$(HOSTSDK_STATIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(AR) r $@ $(HOSTSDK_OBJECTS) $(SDK_DYNAMIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) $(CXX) $(LDFLAGS) $(SDK_DYNAMIC_LDFLAGS) -o $@ $(SDK_OBJECTS) -$(HOSTSDK_DYNAMIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) +$(HOSTSDK_DYNAMIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(CXX) $(LDFLAGS) $(HOSTSDK_DYNAMIC_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS) $(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS) @@ -245,13 +241,11 @@ install: $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) mkdir -p $(DESTDIR)$(INSTALL_API_HEADERS) mkdir -p $(DESTDIR)$(INSTALL_SDK_HEADERS) - mkdir -p $(DESTDIR)$(INSTALL_HOSTEXT_HEADERS) mkdir -p $(DESTDIR)$(INSTALL_SDK_LIBS) mkdir -p $(DESTDIR)$(INSTALL_PKGCONFIG) cp $(API_HEADERS) $(DESTDIR)$(INSTALL_API_HEADERS) cp $(SDK_HEADERS) $(DESTDIR)$(INSTALL_SDK_HEADERS) - cp $(HOSTSDK_HEADERS) $(DESTDIR)$(INSTALL_SDK_HEADERS) - cp $(HOSTEXT_HEADERS) $(DESTDIR)$(INSTALL_HOSTEXT_HEADERS) + cp $(HOSTSDK_HEADERS) $(DESTDIR)$(INSTALL_HOSTSDK_HEADERS) cp $(SDK_STATIC) $(DESTDIR)$(INSTALL_SDK_LIBS) cp $(HOSTSDK_STATIC) $(DESTDIR)$(INSTALL_SDK_LIBS) cp $(SDK_DYNAMIC) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LIBNAME) @@ -313,22 +307,22 @@ host/vamp-simple-host.o: ./vamp-hostsdk/PluginHostAdapter.h vamp/vamp.h host/vamp-simple-host.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h host/vamp-simple-host.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h -host/vamp-simple-host.o: ./vamp-hostsdk/hostext/PluginInputDomainAdapter.h -host/vamp-simple-host.o: ./vamp-hostsdk/hostext/PluginWrapper.h +host/vamp-simple-host.o: ./vamp-hostsdk/PluginInputDomainAdapter.h +host/vamp-simple-host.o: ./vamp-hostsdk/PluginWrapper.h host/vamp-simple-host.o: ./vamp-hostsdk/Plugin.h ./vamp-hostsdk/hostguard.h host/vamp-simple-host.o: vamp-sdk/Plugin.h -host/vamp-simple-host.o: ./vamp-hostsdk/hostext/PluginLoader.h host/system.h +host/vamp-simple-host.o: ./vamp-hostsdk/PluginLoader.h host/system.h rdf/generator/template-generator.o: ./vamp-hostsdk/PluginHostAdapter.h rdf/generator/template-generator.o: vamp/vamp.h vamp-sdk/Plugin.h rdf/generator/template-generator.o: vamp-sdk/PluginBase.h rdf/generator/template-generator.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h -rdf/generator/template-generator.o: ./vamp-hostsdk/hostext/PluginChannelAdapter.h -rdf/generator/template-generator.o: ./vamp-hostsdk/hostext/PluginWrapper.h +rdf/generator/template-generator.o: ./vamp-hostsdk/PluginChannelAdapter.h +rdf/generator/template-generator.o: ./vamp-hostsdk/PluginWrapper.h rdf/generator/template-generator.o: ./vamp-hostsdk/Plugin.h rdf/generator/template-generator.o: ./vamp-hostsdk/hostguard.h rdf/generator/template-generator.o: vamp-sdk/Plugin.h -rdf/generator/template-generator.o: ./vamp-hostsdk/hostext/PluginInputDomainAdapter.h -rdf/generator/template-generator.o: ./vamp-hostsdk/hostext/PluginLoader.h +rdf/generator/template-generator.o: ./vamp-hostsdk/PluginInputDomainAdapter.h +rdf/generator/template-generator.o: ./vamp-hostsdk/PluginLoader.h src/vamp-hostsdk/PluginHostAdapter.o: ./vamp-hostsdk/PluginHostAdapter.h src/vamp-hostsdk/PluginHostAdapter.o: vamp/vamp.h vamp-sdk/Plugin.h src/vamp-hostsdk/PluginHostAdapter.o: vamp-sdk/PluginBase.h @@ -340,55 +334,55 @@ 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-hostsdk/hostext/PluginBufferingAdapter.o: ./vamp-hostsdk/hostext/PluginBufferingAdapter.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginBufferingAdapter.o: vamp-sdk/RealTime.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: ./vamp-hostsdk/hostext/PluginChannelAdapter.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginChannelAdapter.o: vamp-sdk/RealTime.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: ./vamp-hostsdk/hostext/PluginInputDomainAdapter.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginInputDomainAdapter.o: vamp-sdk/RealTime.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/PluginHostAdapter.h -src/vamp-hostsdk/hostext/PluginLoader.o: vamp/vamp.h vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginLoader.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginLoader.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginLoader.o: vamp-sdk/RealTime.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostext/PluginLoader.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginLoader.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostext/PluginInputDomainAdapter.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostext/PluginChannelAdapter.h -src/vamp-hostsdk/hostext/PluginLoader.o: ./vamp-hostsdk/hostext/PluginBufferingAdapter.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: ./vamp-hostsdk/hostext/PluginSummarisingAdapter.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginSummarisingAdapter.o: vamp-sdk/RealTime.h -src/vamp-hostsdk/hostext/PluginWrapper.o: ./vamp-hostsdk/hostext/PluginWrapper.h -src/vamp-hostsdk/hostext/PluginWrapper.o: ./vamp-hostsdk/Plugin.h -src/vamp-hostsdk/hostext/PluginWrapper.o: ./vamp-hostsdk/hostguard.h -src/vamp-hostsdk/hostext/PluginWrapper.o: vamp-sdk/Plugin.h -src/vamp-hostsdk/hostext/PluginWrapper.o: vamp-sdk/PluginBase.h -src/vamp-hostsdk/hostext/PluginWrapper.o: vamp-sdk/plugguard.h -src/vamp-hostsdk/hostext/PluginWrapper.o: vamp-sdk/RealTime.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 +src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/PluginBase.h +src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/RealTime.h +src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/PluginChannelAdapter.h +src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/PluginWrapper.h +src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/Plugin.h +src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/PluginBase.h +src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/RealTime.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/PluginInputDomainAdapter.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/PluginWrapper.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/Plugin.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/PluginBase.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/RealTime.h +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 +src/vamp-hostsdk/PluginLoader.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginLoader.o: vamp-sdk/RealTime.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginLoader.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginWrapper.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/Plugin.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginLoader.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginInputDomainAdapter.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginChannelAdapter.h +src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginBufferingAdapter.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/PluginSummarisingAdapter.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/PluginWrapper.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/Plugin.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/PluginBase.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/RealTime.h +src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/PluginWrapper.h +src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/Plugin.h +src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/hostguard.h +src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/Plugin.h +src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/PluginBase.h +src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/plugguard.h +src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/RealTime.h
--- a/build/Doxyfile Fri Nov 07 14:33:21 2008 +0000 +++ b/build/Doxyfile Fri Nov 07 15:28:33 2008 +0000 @@ -516,10 +516,7 @@ INPUT = vamp \ vamp-sdk \ vamp-hostsdk \ - vamp-hostsdk/hostext \ - src/vamp-sdk \ - src/vamp-hostsdk \ - src/vamp-hostsdk/hostext \ + src \ examples \ host @@ -1130,17 +1127,7 @@ # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = HAVE_FFTW3F \ - HAVE_FISHSOUND \ - HAVE_JACK \ - HAVE_LIBLO \ - HAVE_LRDF \ - HAVE_MAD \ - HAVE_OGGZ \ - HAVE_PORTAUDIO \ - HAVE_SAMPLERATE \ - HAVE_SNDFILE \ - HAVE_VAMP +PREDEFINED = _VAMP_NO_PLUGIN_NAMESPACE # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded.
--- a/host/vamp-simple-host.cpp Fri Nov 07 14:33:21 2008 +0000 +++ b/host/vamp-simple-host.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -36,8 +36,8 @@ */ #include <vamp-hostsdk/PluginHostAdapter.h> -#include <vamp-hostsdk/hostext/PluginInputDomainAdapter.h> -#include <vamp-hostsdk/hostext/PluginLoader.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> #include <iostream> #include <fstream>
--- a/pkgconfig/vamp-hostsdk.pc.in Fri Nov 07 14:33:21 2008 +0000 +++ b/pkgconfig/vamp-hostsdk.pc.in Fri Nov 07 15:28:33 2008 +0000 @@ -4,7 +4,7 @@ includedir=${prefix}/include Name: vamp-hostsdk -Version: 1.3.0 +Version: 2.0.0 Description: Development library for Vamp audio analysis plugin hosts Libs: -L${libdir} -lvamp-hostsdk Cflags: -I${includedir}
--- a/rdf/generator/Makefile.linux Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ - -CXXFLAGS := -I../.. -O2 -Wall - -template-generator: template-generator.o - g++ $^ -o $@ -L../../vamp-sdk -Wl,-Bstatic -lvamp-hostsdk -Wl,-Bdynamic -ldl - -clean: - rm *.o -
--- a/rdf/generator/template-generator.cpp Fri Nov 07 14:33:21 2008 +0000 +++ b/rdf/generator/template-generator.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -1,9 +1,9 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #include <vamp-hostsdk/PluginHostAdapter.h> -#include <vamp-hostsdk/hostext/PluginChannelAdapter.h> -#include <vamp-hostsdk/hostext/PluginInputDomainAdapter.h> -#include <vamp-hostsdk/hostext/PluginLoader.h> +#include <vamp-hostsdk/PluginChannelAdapter.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> #include <vamp/vamp.h> #include <iostream>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginBufferingAdapter.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,657 @@ +/* -*- 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-2007 Chris Cannam and QMUL. + This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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. +*/ + +#include <vector> +#include <map> + +#include <vamp-hostsdk/PluginBufferingAdapter.h> + +using std::vector; +using std::map; + +namespace Vamp { + +namespace HostExt { + +class PluginBufferingAdapter::Impl +{ +public: + Impl(Plugin *plugin, float inputSampleRate); + ~Impl(); + + void setPluginStepSize(size_t stepSize); + void setPluginBlockSize(size_t blockSize); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); + + OutputList getOutputDescriptors() const; + + void reset(); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + class RingBuffer + { + public: + RingBuffer(int n) : + m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } + virtual ~RingBuffer() { delete[] m_buffer; } + + int getSize() const { return m_size-1; } + void reset() { m_writer = 0; m_reader = 0; } + + int getReadSpace() const { + int writer = m_writer, reader = m_reader, space; + if (writer > reader) space = writer - reader; + else if (writer < reader) space = (writer + m_size) - reader; + else space = 0; + return space; + } + + int getWriteSpace() const { + int writer = m_writer; + int reader = m_reader; + int space = (reader + m_size - writer - 1); + if (space >= m_size) space -= m_size; + return space; + } + + int peek(float *destination, int n) const { + + int available = getReadSpace(); + + if (n > available) { + for (int i = available; i < n; ++i) { + destination[i] = 0.f; + } + n = available; + } + if (n == 0) return n; + + int reader = m_reader; + int here = m_size - reader; + const float *const bufbase = m_buffer + reader; + + if (here >= n) { + for (int i = 0; i < n; ++i) { + destination[i] = bufbase[i]; + } + } else { + for (int i = 0; i < here; ++i) { + destination[i] = bufbase[i]; + } + float *const destbase = destination + here; + const int nh = n - here; + for (int i = 0; i < nh; ++i) { + destbase[i] = m_buffer[i]; + } + } + + return n; + } + + int skip(int n) { + + int available = getReadSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; + + int reader = m_reader; + reader += n; + while (reader >= m_size) reader -= m_size; + m_reader = reader; + return n; + } + + int write(const float *source, int n) { + + int available = getWriteSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; + + int writer = m_writer; + int here = m_size - writer; + float *const bufbase = m_buffer + writer; + + if (here >= n) { + for (int i = 0; i < n; ++i) { + bufbase[i] = source[i]; + } + } else { + for (int i = 0; i < here; ++i) { + bufbase[i] = source[i]; + } + const int nh = n - here; + const float *const srcbase = source + here; + float *const buf = m_buffer; + for (int i = 0; i < nh; ++i) { + buf[i] = srcbase[i]; + } + } + + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; + + return n; + } + + int zero(int n) { + + int available = getWriteSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; + + int writer = m_writer; + int here = m_size - writer; + float *const bufbase = m_buffer + writer; + + if (here >= n) { + for (int i = 0; i < n; ++i) { + bufbase[i] = 0.f; + } + } else { + for (int i = 0; i < here; ++i) { + bufbase[i] = 0.f; + } + const int nh = n - here; + for (int i = 0; i < nh; ++i) { + m_buffer[i] = 0.f; + } + } + + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; + + return n; + } + + protected: + float *m_buffer; + int m_writer; + int m_reader; + int m_size; + + private: + RingBuffer(const RingBuffer &); // not provided + RingBuffer &operator=(const RingBuffer &); // not provided + }; + + Plugin *m_plugin; + size_t m_inputStepSize; // value passed to wrapper initialise() + size_t m_inputBlockSize; // value passed to wrapper initialise() + size_t m_setStepSize; // value passed to setPluginStepSize() + size_t m_setBlockSize; // value passed to setPluginBlockSize() + size_t m_stepSize; // value actually used to initialise plugin + size_t m_blockSize; // value actually used to initialise plugin + size_t m_channels; + vector<RingBuffer *> m_queue; + float **m_buffers; + float m_inputSampleRate; + long m_frame; + bool m_unrun; + mutable OutputList m_outputs; + mutable std::map<int, bool> m_rewriteOutputTimes; + + void processBlock(FeatureSet& allFeatureSets); +}; + +PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : + PluginWrapper(plugin) +{ + m_impl = new Impl(plugin, m_inputSampleRate); +} + +PluginBufferingAdapter::~PluginBufferingAdapter() +{ + delete m_impl; +} + +size_t +PluginBufferingAdapter::getPreferredStepSize() const +{ + return getPreferredBlockSize(); +} + +size_t +PluginBufferingAdapter::getPreferredBlockSize() const +{ + return PluginWrapper::getPreferredBlockSize(); +} + +size_t +PluginBufferingAdapter::getPluginPreferredStepSize() const +{ + return PluginWrapper::getPreferredStepSize(); +} + +size_t +PluginBufferingAdapter::getPluginPreferredBlockSize() const +{ + return PluginWrapper::getPreferredBlockSize(); +} + +void +PluginBufferingAdapter::setPluginStepSize(size_t stepSize) +{ + m_impl->setPluginStepSize(stepSize); +} + +void +PluginBufferingAdapter::setPluginBlockSize(size_t blockSize) +{ + m_impl->setPluginBlockSize(blockSize); +} + +void +PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize, + size_t &blockSize) +{ + m_impl->getActualStepAndBlockSizes(stepSize, blockSize); +} + +bool +PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + return m_impl->initialise(channels, stepSize, blockSize); +} + +PluginBufferingAdapter::OutputList +PluginBufferingAdapter::getOutputDescriptors() const +{ + return m_impl->getOutputDescriptors(); +} + +void +PluginBufferingAdapter::reset() +{ + m_impl->reset(); +} + +PluginBufferingAdapter::FeatureSet +PluginBufferingAdapter::process(const float *const *inputBuffers, + RealTime timestamp) +{ + return m_impl->process(inputBuffers, timestamp); +} + +PluginBufferingAdapter::FeatureSet +PluginBufferingAdapter::getRemainingFeatures() +{ + return m_impl->getRemainingFeatures(); +} + +PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : + m_plugin(plugin), + m_inputStepSize(0), + m_inputBlockSize(0), + m_setStepSize(0), + m_setBlockSize(0), + m_stepSize(0), + m_blockSize(0), + m_channels(0), + m_queue(0), + m_buffers(0), + m_inputSampleRate(inputSampleRate), + m_frame(0), + m_unrun(true) +{ + (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes +} + +PluginBufferingAdapter::Impl::~Impl() +{ + // the adapter will delete the plugin + + for (size_t i = 0; i < m_channels; ++i) { + delete m_queue[i]; + delete[] m_buffers[i]; + } + delete[] m_buffers; +} + +void +PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize) +{ + if (m_inputStepSize != 0) { + std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl; + return; + } + m_setStepSize = stepSize; +} + +void +PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize) +{ + if (m_inputBlockSize != 0) { + std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl; + return; + } + m_setBlockSize = blockSize; +} + +void +PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize, + size_t &blockSize) +{ + stepSize = m_stepSize; + blockSize = m_blockSize; +} + +bool +PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (stepSize != blockSize) { + std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; + return false; + } + + m_channels = channels; + m_inputStepSize = stepSize; + m_inputBlockSize = blockSize; + + // if the user has requested particular step or block sizes, use + // those; otherwise use the step and block sizes which the plugin + // prefers + + m_stepSize = 0; + m_blockSize = 0; + + if (m_setStepSize > 0) { + m_stepSize = m_setStepSize; + } + if (m_setBlockSize > 0) { + m_blockSize = m_setBlockSize; + } + + if (m_stepSize == 0 && m_blockSize == 0) { + m_stepSize = m_plugin->getPreferredStepSize(); + m_blockSize = m_plugin->getPreferredBlockSize(); + } + + bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); + + // or sensible defaults if it has no preference + if (m_blockSize == 0) { + if (m_stepSize == 0) { + m_blockSize = 1024; + } else if (freq) { + m_blockSize = m_stepSize * 2; + } else { + m_blockSize = m_stepSize; + } + } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above) + if (freq) { + m_stepSize = m_blockSize/2; + } else { + m_stepSize = m_blockSize; + } + } + + // current implementation breaks if step is greater than block + if (m_stepSize > m_blockSize) { + size_t newBlockSize; + if (freq) { + newBlockSize = m_stepSize * 2; + } else { + newBlockSize = m_stepSize; + } + std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl; + m_blockSize = newBlockSize; + } + + std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize + << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; + + m_buffers = new float *[m_channels]; + + for (size_t i = 0; i < m_channels; ++i) { + m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize)); + m_buffers[i] = new float[m_blockSize]; + } + + return m_plugin->initialise(m_channels, m_stepSize, m_blockSize); +} + +PluginBufferingAdapter::OutputList +PluginBufferingAdapter::Impl::getOutputDescriptors() const +{ + if (m_outputs.empty()) { + m_outputs = m_plugin->getOutputDescriptors(); + } + + PluginBufferingAdapter::OutputList outs = m_outputs; + + for (size_t i = 0; i < outs.size(); ++i) { + + switch (outs[i].sampleType) { + + case OutputDescriptor::OneSamplePerStep: + outs[i].sampleType = OutputDescriptor::FixedSampleRate; + outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; + m_rewriteOutputTimes[i] = true; + break; + + case OutputDescriptor::FixedSampleRate: + if (outs[i].sampleRate == 0.f) { + outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; + } + // We actually only need to rewrite output times for + // features that don't have timestamps already, but we + // can't tell from here whether our features will have + // timestamps or not + m_rewriteOutputTimes[i] = true; + break; + + case OutputDescriptor::VariableSampleRate: + m_rewriteOutputTimes[i] = false; + break; + } + } + + return outs; +} + +void +PluginBufferingAdapter::Impl::reset() +{ + m_frame = 0; + m_unrun = true; + + for (size_t i = 0; i < m_queue.size(); ++i) { + m_queue[i]->reset(); + } + + m_plugin->reset(); +} + +PluginBufferingAdapter::FeatureSet +PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, + RealTime timestamp) +{ + if (m_inputStepSize == 0) { + std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl; + return FeatureSet(); + } + + FeatureSet allFeatureSets; + + if (m_unrun) { + m_frame = RealTime::realTime2Frame(timestamp, + int(m_inputSampleRate + 0.5)); + m_unrun = false; + } + + // queue the new input + + for (size_t i = 0; i < m_channels; ++i) { + int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize); + if (written < int(m_inputBlockSize) && i == 0) { + std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " + << "Buffer overflow: wrote " << written + << " of " << m_inputBlockSize + << " input samples (for plugin step size " + << m_stepSize << ", block size " << m_blockSize << ")" + << std::endl; + } + } + + // process as much as we can + + while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { + processBlock(allFeatureSets); + } + + return allFeatureSets; +} + +PluginBufferingAdapter::FeatureSet +PluginBufferingAdapter::Impl::getRemainingFeatures() +{ + FeatureSet allFeatureSets; + + // process remaining samples in queue + while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { + processBlock(allFeatureSets); + } + + // pad any last samples remaining and process + if (m_queue[0]->getReadSpace() > 0) { + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); + } + processBlock(allFeatureSets); + } + + // get remaining features + + FeatureSet featureSet = m_plugin->getRemainingFeatures(); + + for (map<int, FeatureList>::iterator iter = featureSet.begin(); + iter != featureSet.end(); ++iter) { + FeatureList featureList = iter->second; + for (size_t i = 0; i < featureList.size(); ++i) { + allFeatureSets[iter->first].push_back(featureList[i]); + } + } + + return allFeatureSets; +} + +void +PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) +{ + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->peek(m_buffers[i], m_blockSize); + } + + long frame = m_frame; + RealTime timestamp = RealTime::frame2RealTime + (frame, int(m_inputSampleRate + 0.5)); + + FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); + + for (FeatureSet::iterator iter = featureSet.begin(); + iter != featureSet.end(); ++iter) { + + int outputNo = iter->first; + + if (m_rewriteOutputTimes[outputNo]) { + + FeatureList featureList = iter->second; + + for (size_t i = 0; i < featureList.size(); ++i) { + + switch (m_outputs[outputNo].sampleType) { + + case OutputDescriptor::OneSamplePerStep: + // use our internal timestamp, always + featureList[i].timestamp = timestamp; + featureList[i].hasTimestamp = true; + break; + + case OutputDescriptor::FixedSampleRate: + // use our internal timestamp if feature lacks one + if (!featureList[i].hasTimestamp) { + featureList[i].timestamp = timestamp; + featureList[i].hasTimestamp = true; + } + break; + + case OutputDescriptor::VariableSampleRate: + break; // plugin must set timestamp + + default: + break; + } + + allFeatureSets[outputNo].push_back(featureList[i]); + } + } else { + for (size_t i = 0; i < iter->second.size(); ++i) { + allFeatureSets[outputNo].push_back(iter->second[i]); + } + } + } + + // step forward + + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->skip(m_stepSize); + } + + // increment internal frame counter each time we step forward + m_frame += m_stepSize; +} + +} + +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginChannelAdapter.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,266 @@ +/* -*- 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-2007 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. +*/ + +#include <vamp-hostsdk/PluginChannelAdapter.h> + +namespace Vamp { + +namespace HostExt { + +class PluginChannelAdapter::Impl +{ +public: + Impl(Plugin *plugin); + ~Impl(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp); + +protected: + Plugin *m_plugin; + size_t m_blockSize; + size_t m_inputChannels; + size_t m_pluginChannels; + float **m_buffer; + float **m_deinterleave; + const float **m_forwardPtrs; +}; + +PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) : + PluginWrapper(plugin) +{ + m_impl = new Impl(plugin); +} + +PluginChannelAdapter::~PluginChannelAdapter() +{ + delete m_impl; +} + +bool +PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + return m_impl->initialise(channels, stepSize, blockSize); +} + +PluginChannelAdapter::FeatureSet +PluginChannelAdapter::process(const float *const *inputBuffers, + RealTime timestamp) +{ + return m_impl->process(inputBuffers, timestamp); +} + +PluginChannelAdapter::FeatureSet +PluginChannelAdapter::processInterleaved(const float *inputBuffers, + RealTime timestamp) +{ + return m_impl->processInterleaved(inputBuffers, timestamp); +} + +PluginChannelAdapter::Impl::Impl(Plugin *plugin) : + m_plugin(plugin), + m_blockSize(0), + m_inputChannels(0), + m_pluginChannels(0), + m_buffer(0), + m_deinterleave(0), + m_forwardPtrs(0) +{ +} + +PluginChannelAdapter::Impl::~Impl() +{ + // the adapter will delete the plugin + + if (m_buffer) { + if (m_inputChannels > m_pluginChannels) { + delete[] m_buffer[0]; + } else { + for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) { + delete[] m_buffer[i]; + } + } + delete[] m_buffer; + m_buffer = 0; + } + + if (m_deinterleave) { + for (size_t i = 0; i < m_inputChannels; ++i) { + delete[] m_deinterleave[i]; + } + delete[] m_deinterleave; + m_deinterleave = 0; + } + + if (m_forwardPtrs) { + delete[] m_forwardPtrs; + m_forwardPtrs = 0; + } +} + +bool +PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + m_blockSize = blockSize; + + size_t minch = m_plugin->getMinChannelCount(); + size_t maxch = m_plugin->getMaxChannelCount(); + + m_inputChannels = channels; + + if (m_inputChannels < minch) { + + m_forwardPtrs = new const float *[minch]; + + if (m_inputChannels > 1) { + // We need a set of zero-valued buffers to add to the + // forwarded pointers + m_buffer = new float*[minch - channels]; + for (size_t i = 0; i < minch; ++i) { + m_buffer[i] = new float[blockSize]; + for (size_t j = 0; j < blockSize; ++j) { + m_buffer[i][j] = 0.f; + } + } + } + + m_pluginChannels = minch; + + std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; + + } else if (m_inputChannels > maxch) { + + // We only need m_buffer if we are mixing down to a single + // channel -- otherwise we can just forward the same float* as + // passed in to process(), expecting the excess to be ignored + + if (maxch == 1) { + m_buffer = new float *[1]; + m_buffer[0] = new float[blockSize]; + + std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl; + + } else { + + std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; + } + + m_pluginChannels = maxch; + + } else { + + std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl; + m_pluginChannels = m_inputChannels; + } + + return m_plugin->initialise(m_pluginChannels, stepSize, blockSize); +} + +PluginChannelAdapter::FeatureSet +PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers, + RealTime timestamp) +{ + if (!m_deinterleave) { + m_deinterleave = new float *[m_inputChannels]; + for (size_t i = 0; i < m_inputChannels; ++i) { + m_deinterleave[i] = new float[m_blockSize]; + } + } + + for (size_t i = 0; i < m_inputChannels; ++i) { + for (size_t j = 0; j < m_blockSize; ++j) { + m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i]; + } + } + + return process(m_deinterleave, timestamp); +} + +PluginChannelAdapter::FeatureSet +PluginChannelAdapter::Impl::process(const float *const *inputBuffers, + RealTime timestamp) +{ +// std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl; + + if (m_inputChannels < m_pluginChannels) { + + if (m_inputChannels == 1) { + for (size_t i = 0; i < m_pluginChannels; ++i) { + m_forwardPtrs[i] = inputBuffers[0]; + } + } else { + for (size_t i = 0; i < m_inputChannels; ++i) { + m_forwardPtrs[i] = inputBuffers[i]; + } + for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) { + m_forwardPtrs[i] = m_buffer[i - m_inputChannels]; + } + } + + return m_plugin->process(m_forwardPtrs, timestamp); + + } else if (m_inputChannels > m_pluginChannels) { + + if (m_pluginChannels == 1) { + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] = inputBuffers[0][j]; + } + for (size_t i = 1; i < m_inputChannels; ++i) { + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] += inputBuffers[i][j]; + } + } + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] /= m_inputChannels; + } + return m_plugin->process(m_buffer, timestamp); + } else { + return m_plugin->process(inputBuffers, timestamp); + } + + } else { + + return m_plugin->process(inputBuffers, timestamp); + } +} + +} + +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginInputDomainAdapter.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,578 @@ +/* -*- 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-2007 Chris Cannam and QMUL. + + This file is based in part on Don Cross's public domain FFT + implementation. + + 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. +*/ + +#include <vamp-hostsdk/PluginInputDomainAdapter.h> + +#include <cmath> + + +/** + * 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> +#endif + + +namespace Vamp { + +namespace HostExt { + +class PluginInputDomainAdapter::Impl +{ +public: + Impl(Plugin *plugin, float inputSampleRate); + ~Impl(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + RealTime getTimestampAdjustment() const; + +protected: + Plugin *m_plugin; + float m_inputSampleRate; + int m_channels; + int m_blockSize; + float **m_freqbuf; + + double *m_ri; + double *m_window; + +#ifdef HAVE_FFTW3 + fftw_plan m_plan; + fftw_complex *m_cbuf; +#else + double *m_ro; + double *m_io; + void fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io); +#endif + + size_t makeBlockSizeAcceptable(size_t) const; +}; + +PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : + PluginWrapper(plugin) +{ + m_impl = new Impl(plugin, m_inputSampleRate); +} + +PluginInputDomainAdapter::~PluginInputDomainAdapter() +{ + delete m_impl; +} + +bool +PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + return m_impl->initialise(channels, stepSize, blockSize); +} + +Plugin::InputDomain +PluginInputDomainAdapter::getInputDomain() const +{ + return TimeDomain; +} + +size_t +PluginInputDomainAdapter::getPreferredStepSize() const +{ + return m_impl->getPreferredStepSize(); +} + +size_t +PluginInputDomainAdapter::getPreferredBlockSize() const +{ + return m_impl->getPreferredBlockSize(); +} + +Plugin::FeatureSet +PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp) +{ + return m_impl->process(inputBuffers, timestamp); +} + +RealTime +PluginInputDomainAdapter::getTimestampAdjustment() const +{ + return m_impl->getTimestampAdjustment(); +} + + +PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : + m_plugin(plugin), + m_inputSampleRate(inputSampleRate), + m_channels(0), + m_blockSize(0), + m_freqbuf(0), + m_ri(0), + m_window(0), +#ifdef HAVE_FFTW3 + m_plan(0), + m_cbuf(0) +#else + m_ro(0), + m_io(0) +#endif +{ +} + +PluginInputDomainAdapter::Impl::~Impl() +{ + // the adapter will delete the plugin + + 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; + } +#else + delete[] m_ri; + delete[] m_ro; + delete[] m_io; +#endif + delete[] m_window; + } +} + +// for some visual studii apparently +#ifndef M_PI +#define M_PI 3.14159265358979232846 +#endif + +bool +PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (m_plugin->getInputDomain() == TimeDomain) { + + m_blockSize = int(blockSize); + m_channels = int(channels); + + return m_plugin->initialise(channels, stepSize, blockSize); + } + + if (blockSize < 2) { + std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl; + return false; + } + + if (blockSize & (blockSize-1)) { + std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; + return false; + } + + 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; + } +#else + delete[] m_ri; + delete[] m_ro; + delete[] m_io; +#endif + delete[] m_window; + } + + m_blockSize = int(blockSize); + m_channels = int(channels); + + m_freqbuf = new float *[m_channels]; + for (int c = 0; c < m_channels; ++c) { + m_freqbuf[c] = new float[m_blockSize + 2]; + } + m_window = new double[m_blockSize]; + + for (int i = 0; i < m_blockSize; ++i) { + // Hanning window + m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / 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(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 + + return m_plugin->initialise(channels, stepSize, blockSize); +} + +size_t +PluginInputDomainAdapter::Impl::getPreferredStepSize() const +{ + size_t step = m_plugin->getPreferredStepSize(); + + if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { + step = getPreferredBlockSize() / 2; + } + + return step; +} + +size_t +PluginInputDomainAdapter::Impl::getPreferredBlockSize() const +{ + size_t block = m_plugin->getPreferredBlockSize(); + + if (m_plugin->getInputDomain() == FrequencyDomain) { + if (block == 0) { + block = 1024; + } else { + block = makeBlockSizeAcceptable(block); + } + } + + return block; +} + +size_t +PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const +{ + if (blockSize < 2) { + + std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl + << "supported, increasing from " << blockSize << " to 2" << std::endl; + 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: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; + blockSize = nearest; + +#endif + } + + return blockSize; +} + +RealTime +PluginInputDomainAdapter::Impl::getTimestampAdjustment() const +{ + if (m_plugin->getInputDomain() == TimeDomain) { + return RealTime::zeroTime; + } else { + return RealTime::frame2RealTime + (m_blockSize/2, int(m_inputSampleRate + 0.5)); + } +} + +Plugin::FeatureSet +PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, + RealTime timestamp) +{ + if (m_plugin->getInputDomain() == TimeDomain) { + return m_plugin->process(inputBuffers, timestamp); + } + + // The timestamp supplied should be (according to the Vamp::Plugin + // spec) the time of the start of the time-domain input block. + // However, we want to pass to the plugin an FFT output calculated + // from the block of samples _centred_ on that timestamp. + // + // We have two options: + // + // 1. Buffer the input, calculating the fft of the values at the + // passed-in block minus blockSize/2 rather than starting at the + // passed-in block. So each time we call process on the plugin, + // we are passing in the same timestamp as was passed to our own + // process plugin, but not (the frequency domain representation + // of) the same set of samples. Advantages: avoids confusion in + // the host by ensuring the returned values have timestamps + // comparable with that passed in to this function (in fact this + // is pretty much essential for one-value-per-block outputs); + // consistent with hosts such as SV that deal with the + // frequency-domain transform themselves. Disadvantages: means + // making the not necessarily correct assumption that the samples + // preceding the first official block are all zero (or some other + // known value). + // + // 2. Increase the passed-in timestamps by half the blocksize. So + // when we call process, we are passing in the frequency domain + // representation of the same set of samples as passed to us, but + // with a different timestamp. Advantages: simplicity; avoids + // iffy assumption mentioned above. Disadvantages: inconsistency + // with SV in cases where stepSize != blockSize/2; potential + // confusion arising from returned timestamps being calculated + // from the adjusted input timestamps rather than the original + // ones (and inaccuracy where the returned timestamp is implied, + // as in one-value-per-block). + // + // Neither way is ideal, but I don't think either is strictly + // incorrect either. I think this is just a case where the same + // plugin can legitimately produce differing results from the same + // input data, depending on how that data is packaged. + // + // We'll go for option 2, adjusting the timestamps. Note in + // particular that this means some results can differ from those + // produced by SV. + +// std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp; + + timestamp = timestamp + getTimestampAdjustment(); + +// std::cerr << " to " << timestamp << std::endl; + + for (int c = 0; c < m_channels; ++c) { + + for (int i = 0; i < m_blockSize; ++i) { + m_ri[i] = double(inputBuffers[c][i]) * m_window[i]; + } + + for (int i = 0; i < m_blockSize/2; ++i) { + // FFT shift + double 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); + + 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]); + } + +#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); +} + +#ifndef HAVE_FFTW3 + +void +PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io) +{ + if (!ri || !ro || !io) return; + + unsigned int bits; + unsigned int i, j, k, m; + unsigned int blockSize, blockEnd; + + 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; + } + } + + static unsigned int tableSize = 0; + static int *table = 0; + + if (tableSize != n) { + + delete[] table; + + table = new int[n]; + + 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; + } + + tableSize = n; + } + + 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; + } + } + + 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; + } + } +} + +#endif + +} + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginLoader.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,636 @@ +/* -*- 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-2007 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. +*/ + +#include <vamp-hostsdk/PluginHostAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginChannelAdapter.h> +#include <vamp-hostsdk/PluginBufferingAdapter.h> + +#include <fstream> +#include <cctype> // tolower + +#include <cstring> + +#ifdef _WIN32 + +#include <windows.h> +#include <tchar.h> +#define PLUGIN_SUFFIX "dll" + +#else /* ! _WIN32 */ + +#include <dirent.h> +#include <dlfcn.h> + +#ifdef __APPLE__ +#define PLUGIN_SUFFIX "dylib" +#else /* ! __APPLE__ */ +#define PLUGIN_SUFFIX "so" +#endif /* ! __APPLE__ */ + +#endif /* ! _WIN32 */ + +using namespace std; + +namespace Vamp { + +namespace HostExt { + +class PluginLoader::Impl +{ +public: + Impl(); + virtual ~Impl(); + + PluginKeyList listPlugins(); + + Plugin *loadPlugin(PluginKey key, + float inputSampleRate, + int adapterFlags); + + PluginKey composePluginKey(string libraryName, string identifier); + + PluginCategoryHierarchy getPluginCategory(PluginKey key); + + string getLibraryPathForPlugin(PluginKey key); + + static void setInstanceToClean(PluginLoader *instance); + +protected: + class PluginDeletionNotifyAdapter : public PluginWrapper { + public: + PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader); + virtual ~PluginDeletionNotifyAdapter(); + protected: + Impl *m_loader; + }; + + class InstanceCleaner { + public: + InstanceCleaner() : m_instance(0) { } + ~InstanceCleaner() { delete m_instance; } + void setInstance(PluginLoader *instance) { m_instance = instance; } + protected: + PluginLoader *m_instance; + }; + + virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); + + map<PluginKey, string> m_pluginLibraryNameMap; + bool m_allPluginsEnumerated; + void enumeratePlugins(PluginKey forPlugin = ""); + + map<PluginKey, PluginCategoryHierarchy> m_taxonomy; + void generateTaxonomy(); + + map<Plugin *, void *> m_pluginLibraryHandleMap; + + bool decomposePluginKey(PluginKey key, + string &libraryName, string &identifier); + + void *loadLibrary(string path); + void unloadLibrary(void *handle); + void *lookupInLibrary(void *handle, const char *symbol); + + string splicePath(string a, string b); + vector<string> listFiles(string dir, string ext); + + static InstanceCleaner m_cleaner; +}; + +PluginLoader * +PluginLoader::m_instance = 0; + +PluginLoader::Impl::InstanceCleaner +PluginLoader::Impl::m_cleaner; + +PluginLoader::PluginLoader() +{ + m_impl = new Impl(); +} + +PluginLoader::~PluginLoader() +{ + delete m_impl; +} + +PluginLoader * +PluginLoader::getInstance() +{ + if (!m_instance) { + // The cleaner doesn't own the instance, because we leave the + // instance pointer in the base class for binary backwards + // compatibility reasons and to avoid waste + m_instance = new PluginLoader(); + Impl::setInstanceToClean(m_instance); + } + return m_instance; +} + +vector<PluginLoader::PluginKey> +PluginLoader::listPlugins() +{ + return m_impl->listPlugins(); +} + +Plugin * +PluginLoader::loadPlugin(PluginKey key, + float inputSampleRate, + int adapterFlags) +{ + return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); +} + +PluginLoader::PluginKey +PluginLoader::composePluginKey(string libraryName, string identifier) +{ + return m_impl->composePluginKey(libraryName, identifier); +} + +PluginLoader::PluginCategoryHierarchy +PluginLoader::getPluginCategory(PluginKey key) +{ + return m_impl->getPluginCategory(key); +} + +string +PluginLoader::getLibraryPathForPlugin(PluginKey key) +{ + return m_impl->getLibraryPathForPlugin(key); +} + +PluginLoader::Impl::Impl() : + m_allPluginsEnumerated(false) +{ +} + +PluginLoader::Impl::~Impl() +{ +} + +void +PluginLoader::Impl::setInstanceToClean(PluginLoader *instance) +{ + m_cleaner.setInstance(instance); +} + +vector<PluginLoader::PluginKey> +PluginLoader::Impl::listPlugins() +{ + if (!m_allPluginsEnumerated) enumeratePlugins(); + + vector<PluginKey> plugins; + for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin(); + mi != m_pluginLibraryNameMap.end(); ++mi) { + plugins.push_back(mi->first); + } + + return plugins; +} + +void +PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin) +{ + vector<string> path = PluginHostAdapter::getPluginPath(); + + string libraryName, identifier; + if (forPlugin != "") { + if (!decomposePluginKey(forPlugin, libraryName, identifier)) { + std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \"" + << forPlugin << "\" in enumerate" << std::endl; + return; + } + } + + for (size_t i = 0; i < path.size(); ++i) { + + vector<string> files = listFiles(path[i], PLUGIN_SUFFIX); + + for (vector<string>::iterator fi = files.begin(); + fi != files.end(); ++fi) { + + if (libraryName != "") { + // libraryName is lowercased and lacking an extension, + // as it came from the plugin key + string temp = *fi; + for (size_t i = 0; i < temp.length(); ++i) { + temp[i] = tolower(temp[i]); + } + string::size_type pi = temp.find('.'); + if (pi == string::npos) { + if (libraryName != temp) continue; + } else { + if (libraryName != temp.substr(0, pi)) continue; + } + } + + string fullPath = path[i]; + fullPath = splicePath(fullPath, *fi); + void *handle = loadLibrary(fullPath); + if (!handle) continue; + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)lookupInLibrary + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + unloadLibrary(handle); + continue; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + ++index; + if (identifier != "") { + if (descriptor->identifier != identifier) continue; + } + PluginKey key = composePluginKey(*fi, descriptor->identifier); +// std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl; + if (m_pluginLibraryNameMap.find(key) == + m_pluginLibraryNameMap.end()) { + m_pluginLibraryNameMap[key] = fullPath; + } + } + + unloadLibrary(handle); + } + } + + if (forPlugin == "") m_allPluginsEnumerated = true; +} + +PluginLoader::PluginKey +PluginLoader::Impl::composePluginKey(string libraryName, string identifier) +{ + string basename = libraryName; + + string::size_type li = basename.rfind('/'); + if (li != string::npos) basename = basename.substr(li + 1); + + li = basename.find('.'); + if (li != string::npos) basename = basename.substr(0, li); + + for (size_t i = 0; i < basename.length(); ++i) { + basename[i] = tolower(basename[i]); + } + + return basename + ":" + identifier; +} + +bool +PluginLoader::Impl::decomposePluginKey(PluginKey key, + string &libraryName, + string &identifier) +{ + string::size_type ki = key.find(':'); + if (ki == string::npos) { + return false; + } + + libraryName = key.substr(0, ki); + identifier = key.substr(ki + 1); + return true; +} + +PluginLoader::PluginCategoryHierarchy +PluginLoader::Impl::getPluginCategory(PluginKey plugin) +{ + if (m_taxonomy.empty()) generateTaxonomy(); + if (m_taxonomy.find(plugin) == m_taxonomy.end()) { + return PluginCategoryHierarchy(); + } + return m_taxonomy[plugin]; +} + +string +PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin) +{ + if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { + if (m_allPluginsEnumerated) return ""; + enumeratePlugins(plugin); + } + if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { + return ""; + } + return m_pluginLibraryNameMap[plugin]; +} + +Plugin * +PluginLoader::Impl::loadPlugin(PluginKey key, + float inputSampleRate, int adapterFlags) +{ + string libname, identifier; + if (!decomposePluginKey(key, libname, identifier)) { + std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \"" + << key << "\" in loadPlugin" << std::endl; + return 0; + } + + string fullPath = getLibraryPathForPlugin(key); + if (fullPath == "") return 0; + + void *handle = loadLibrary(fullPath); + if (!handle) return 0; + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)lookupInLibrary + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + unloadLibrary(handle); + return 0; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + if (string(descriptor->identifier) == identifier) { + + Vamp::PluginHostAdapter *plugin = + new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + + Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this); + + m_pluginLibraryHandleMap[adapter] = handle; + + if (adapterFlags & ADAPT_INPUT_DOMAIN) { + if (adapter->getInputDomain() == Plugin::FrequencyDomain) { + adapter = new PluginInputDomainAdapter(adapter); + } + } + + if (adapterFlags & ADAPT_BUFFER_SIZE) { + adapter = new PluginBufferingAdapter(adapter); + } + + if (adapterFlags & ADAPT_CHANNEL_COUNT) { + adapter = new PluginChannelAdapter(adapter); + } + + return adapter; + } + + ++index; + } + + cerr << "Vamp::HostExt::PluginLoader: Plugin \"" + << identifier << "\" not found in library \"" + << fullPath << "\"" << endl; + + return 0; +} + +void +PluginLoader::Impl::generateTaxonomy() +{ +// cerr << "PluginLoader::Impl::generateTaxonomy" << endl; + + vector<string> path = PluginHostAdapter::getPluginPath(); + string libfragment = "/lib/"; + vector<string> catpath; + + string suffix = "cat"; + + for (vector<string>::iterator i = path.begin(); + i != path.end(); ++i) { + + // It doesn't matter that we're using literal forward-slash in + // this bit, as it's only relevant if the path contains + // "/lib/", which is only meaningful and only plausible on + // systems with forward-slash delimiters + + string dir = *i; + string::size_type li = dir.find(libfragment); + + if (li != string::npos) { + catpath.push_back + (dir.substr(0, li) + + "/share/" + + dir.substr(li + libfragment.length())); + } + + catpath.push_back(dir); + } + + char buffer[1024]; + + for (vector<string>::iterator i = catpath.begin(); + i != catpath.end(); ++i) { + + vector<string> files = listFiles(*i, suffix); + + for (vector<string>::iterator fi = files.begin(); + fi != files.end(); ++fi) { + + string filepath = splicePath(*i, *fi); + ifstream is(filepath.c_str(), ifstream::in | ifstream::binary); + + if (is.fail()) { +// cerr << "failed to open: " << filepath << endl; + continue; + } + +// cerr << "opened: " << filepath << endl; + + while (!!is.getline(buffer, 1024)) { + + string line(buffer); + +// cerr << "line = " << line << endl; + + string::size_type di = line.find("::"); + if (di == string::npos) continue; + + string id = line.substr(0, di); + string encodedCat = line.substr(di + 2); + + if (id.substr(0, 5) != "vamp:") continue; + id = id.substr(5); + + while (encodedCat.length() >= 1 && + encodedCat[encodedCat.length()-1] == '\r') { + encodedCat = encodedCat.substr(0, encodedCat.length()-1); + } + +// cerr << "id = " << id << ", cat = " << encodedCat << endl; + + PluginCategoryHierarchy category; + string::size_type ai; + while ((ai = encodedCat.find(" > ")) != string::npos) { + category.push_back(encodedCat.substr(0, ai)); + encodedCat = encodedCat.substr(ai + 3); + } + if (encodedCat != "") category.push_back(encodedCat); + + m_taxonomy[id] = category; + } + } + } +} + +void * +PluginLoader::Impl::loadLibrary(string path) +{ + void *handle = 0; +#ifdef _WIN32 + handle = LoadLibrary(path.c_str()); + if (!handle) { + cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" + << path << "\"" << endl; + } +#else + handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); + if (!handle) { + cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" + << path << "\": " << dlerror() << endl; + } +#endif + return handle; +} + +void +PluginLoader::Impl::unloadLibrary(void *handle) +{ +#ifdef _WIN32 + FreeLibrary((HINSTANCE)handle); +#else + dlclose(handle); +#endif +} + +void * +PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol) +{ +#ifdef _WIN32 + return (void *)GetProcAddress((HINSTANCE)handle, symbol); +#else + return (void *)dlsym(handle, symbol); +#endif +} + +string +PluginLoader::Impl::splicePath(string a, string b) +{ +#ifdef _WIN32 + return a + "\\" + b; +#else + return a + "/" + b; +#endif +} + +vector<string> +PluginLoader::Impl::listFiles(string dir, string extension) +{ + vector<string> files; + +#ifdef _WIN32 + + string expression = dir + "\\*." + extension; + WIN32_FIND_DATA data; + HANDLE fh = FindFirstFile(expression.c_str(), &data); + if (fh == INVALID_HANDLE_VALUE) return files; + + bool ok = true; + while (ok) { + files.push_back(data.cFileName); + ok = FindNextFile(fh, &data); + } + + FindClose(fh); + +#else + + size_t extlen = extension.length(); + DIR *d = opendir(dir.c_str()); + if (!d) return files; + + struct dirent *e = 0; + while ((e = readdir(d))) { + + if (!e->d_name) continue; + + size_t len = strlen(e->d_name); + if (len < extlen + 2 || + e->d_name + len - extlen - 1 != "." + extension) { + continue; + } + + files.push_back(e->d_name); + } + + closedir(d); +#endif + + return files; +} + +void +PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter) +{ + void *handle = m_pluginLibraryHandleMap[adapter]; + if (handle) unloadLibrary(handle); + m_pluginLibraryHandleMap.erase(adapter); +} + +PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin, + Impl *loader) : + PluginWrapper(plugin), + m_loader(loader) +{ +} + +PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() +{ + // We need to delete the plugin before calling pluginDeleted, as + // the delete call may require calling through to the descriptor + // (for e.g. cleanup) but pluginDeleted may unload the required + // library for the call. To prevent a double deletion when our + // parent's destructor runs (after this one), be sure to set + // m_plugin to 0 after deletion. + delete m_plugin; + m_plugin = 0; + + if (m_loader) m_loader->pluginDeleted(this); +} + +} + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginSummarisingAdapter.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,913 @@ +/* -*- 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-2008 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. +*/ + +#include <vamp-hostsdk/PluginSummarisingAdapter.h> + +#include <map> +#include <algorithm> +#include <cmath> +#include <climits> + +#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1 +//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1 + +namespace Vamp { + +namespace HostExt { + +class PluginSummarisingAdapter::Impl +{ +public: + Impl(Plugin *plugin, float inputSampleRate); + ~Impl(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet getRemainingFeatures(); + + void setSummarySegmentBoundaries(const SegmentBoundaries &); + + FeatureList getSummaryForOutput(int output, + SummaryType type, + AveragingMethod avg); + + FeatureSet getSummaryForAllOutputs(SummaryType type, + AveragingMethod avg); + +protected: + Plugin *m_plugin; + float m_inputSampleRate; + size_t m_stepSize; + size_t m_blockSize; + + SegmentBoundaries m_boundaries; + + typedef std::vector<float> ValueList; + + struct Result { // smaller than Feature + RealTime time; + RealTime duration; + ValueList values; // bin number -> value + }; + + typedef std::vector<Result> ResultList; + + struct OutputAccumulator { + int bins; + ResultList results; + OutputAccumulator() : bins(0) { } + }; + + typedef std::map<int, OutputAccumulator> OutputAccumulatorMap; + OutputAccumulatorMap m_accumulators; // output number -> accumulator + + typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap; + typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap; + OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented + + typedef std::map<int, RealTime> OutputTimestampMap; + OutputTimestampMap m_prevTimestamps; // output number -> timestamp + OutputTimestampMap m_prevDurations; // output number -> durations + + struct OutputBinSummary { + + int count; + + // extents + double minimum; + double maximum; + double sum; + + // sample-average results + double median; + double mode; + double variance; + + // continuous-time average results + double median_c; + double mode_c; + double mean_c; + double variance_c; + }; + + typedef std::map<int, OutputBinSummary> OutputSummary; + typedef std::map<RealTime, OutputSummary> SummarySegmentMap; + typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap; + + OutputSummarySegmentMap m_summaries; + + bool m_reduced; + RealTime m_endTime; + + void accumulate(const FeatureSet &fs, RealTime, bool final); + void accumulate(int output, const Feature &f, RealTime, bool final); + void accumulateFinalDurations(); + void findSegmentBounds(RealTime t, RealTime &start, RealTime &end); + void segment(); + void reduce(); + + std::string getSummaryLabel(SummaryType type, AveragingMethod avg); +}; + +static RealTime INVALID_DURATION(INT_MIN, INT_MIN); + +PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) : + PluginWrapper(plugin) +{ + m_impl = new Impl(plugin, m_inputSampleRate); +} + +PluginSummarisingAdapter::~PluginSummarisingAdapter() +{ + delete m_impl; +} + +bool +PluginSummarisingAdapter::initialise(size_t channels, + size_t stepSize, size_t blockSize) +{ + return + PluginWrapper::initialise(channels, stepSize, blockSize) && + m_impl->initialise(channels, stepSize, blockSize); +} + +Plugin::FeatureSet +PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp) +{ + return m_impl->process(inputBuffers, timestamp); +} + +Plugin::FeatureSet +PluginSummarisingAdapter::getRemainingFeatures() +{ + return m_impl->getRemainingFeatures(); +} + +void +PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b) +{ + m_impl->setSummarySegmentBoundaries(b); +} + +Plugin::FeatureList +PluginSummarisingAdapter::getSummaryForOutput(int output, + SummaryType type, + AveragingMethod avg) +{ + return m_impl->getSummaryForOutput(output, type, avg); +} + +Plugin::FeatureSet +PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type, + AveragingMethod avg) +{ + return m_impl->getSummaryForAllOutputs(type, avg); +} + +PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : + m_plugin(plugin), + m_inputSampleRate(inputSampleRate), + m_reduced(false) +{ +} + +PluginSummarisingAdapter::Impl::~Impl() +{ +} + +bool +PluginSummarisingAdapter::Impl::initialise(size_t channels, + size_t stepSize, size_t blockSize) +{ + m_stepSize = stepSize; + m_blockSize = blockSize; + return true; +} + +Plugin::FeatureSet +PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, + RealTime timestamp) +{ + if (m_reduced) { + std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; + } + FeatureSet fs = m_plugin->process(inputBuffers, timestamp); + accumulate(fs, timestamp, false); + m_endTime = timestamp + + RealTime::frame2RealTime(m_stepSize, m_inputSampleRate); + return fs; +} + +Plugin::FeatureSet +PluginSummarisingAdapter::Impl::getRemainingFeatures() +{ + if (m_reduced) { + std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; + } + FeatureSet fs = m_plugin->getRemainingFeatures(); + accumulate(fs, m_endTime, true); + return fs; +} + +void +PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b) +{ + m_boundaries = b; +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl; + for (SegmentBoundaries::const_iterator i = m_boundaries.begin(); + i != m_boundaries.end(); ++i) { + std::cerr << *i << " "; + } + std::cerr << std::endl; +#endif +} + +Plugin::FeatureList +PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, + SummaryType type, + AveragingMethod avg) +{ + if (!m_reduced) { + accumulateFinalDurations(); + segment(); + reduce(); + m_reduced = true; + } + + bool continuous = (avg == ContinuousTimeAverage); + + FeatureList fl; + for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); + i != m_summaries[output].end(); ++i) { + + Feature f; + + f.hasTimestamp = true; + f.timestamp = i->first; + + f.hasDuration = true; + SummarySegmentMap::const_iterator ii = i; + if (++ii == m_summaries[output].end()) { + f.duration = m_endTime - f.timestamp; + } else { + f.duration = ii->first - f.timestamp; + } + + f.label = getSummaryLabel(type, avg); + + for (OutputSummary::const_iterator j = i->second.begin(); + j != i->second.end(); ++j) { + + // these will be ordered by bin number, and no bin numbers + // will be missing except at the end (because of the way + // the accumulators were initially filled in accumulate()) + + const OutputBinSummary &summary = j->second; + double result = 0.f; + + switch (type) { + + case Minimum: + result = summary.minimum; + break; + + case Maximum: + result = summary.maximum; + break; + + case Mean: + if (continuous) { + result = summary.mean_c; + } else if (summary.count) { + result = summary.sum / summary.count; + } + break; + + case Median: + if (continuous) result = summary.median_c; + else result = summary.median; + break; + + case Mode: + if (continuous) result = summary.mode_c; + else result = summary.mode; + break; + + case Sum: + result = summary.sum; + break; + + case Variance: + if (continuous) result = summary.variance_c; + else result = summary.variance; + break; + + case StandardDeviation: + if (continuous) result = sqrtf(summary.variance_c); + else result = sqrtf(summary.variance); + break; + + case Count: + result = summary.count; + break; + + case UnknownSummaryType: + break; + + default: + break; + } + + f.values.push_back(result); + } + + fl.push_back(f); + } + return fl; +} + +Plugin::FeatureSet +PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, + AveragingMethod avg) +{ + if (!m_reduced) { + accumulateFinalDurations(); + segment(); + reduce(); + m_reduced = true; + } + + FeatureSet fs; + for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); + i != m_summaries.end(); ++i) { + fs[i->first] = getSummaryForOutput(i->first, type, avg); + } + return fs; +} + +void +PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs, + RealTime timestamp, + bool final) +{ + for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) { + for (FeatureList::const_iterator j = i->second.begin(); + j != i->second.end(); ++j) { + if (j->hasTimestamp) { + accumulate(i->first, *j, j->timestamp, final); + } else { + //!!! is this correct? + accumulate(i->first, *j, timestamp, final); + } + } + } +} + +std::string +PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type, + AveragingMethod avg) +{ + std::string label; + std::string avglabel; + + if (avg == SampleAverage) avglabel = ", sample average"; + else avglabel = ", continuous-time average"; + + switch (type) { + case Minimum: label = "(minimum value)"; break; + case Maximum: label = "(maximum value)"; break; + case Mean: label = "(mean value" + avglabel + ")"; break; + case Median: label = "(median value" + avglabel + ")"; break; + case Mode: label = "(modal value" + avglabel + ")"; break; + case Sum: label = "(sum)"; break; + case Variance: label = "(variance" + avglabel + ")"; break; + case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break; + case Count: label = "(count)"; break; + case UnknownSummaryType: label = "(unknown summary)"; break; + } + + return label; +} + +void +PluginSummarisingAdapter::Impl::accumulate(int output, + const Feature &f, + RealTime timestamp, + bool final) +{ +//!!! to do: use timestamp to determine which segment we're on + +//!!! What should happen if a feature's duration spans a segment +// boundary? I think we probably want to chop it, and pretend that it +// appears in both -- don't we? do we? A very long feature (e.g. key, +// if the whole audio is in a single key) might span many or all +// segments, and we want that to be reflected in the results (e.g. it +// is the modal key in all of those segments, not just the first). +// That is actually quite complicated to do! + +//!!! This affects how we record things. If features spanning a +// boundary should be chopped, then we need to have per-segment +// accumulators (and the feature value goes into both -- perhaps we +// need a separate phase to split the accumulator up into segments). +// If features spanning a boundary should be counted only in the first +// segment, with their full duration, then we should store them in a +// single accumulator and distribute into segments only on reduce. + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl; +#endif + + // At each process step, accumulate() is called once for each + // feature on each output within that process's returned feature + // list, and with the timestamp passed in being that of the start + // of the process block. + + // At the end (in getRemainingFeatures), accumulate() is called + // once for each feature on each output within the feature list + // returned by getRemainingFeatures, and with the timestamp being + // the same as the last process block and final set to true. + + // (What if getRemainingFeatures doesn't return any features? We + // still need to ensure that the final duration is written. Need + // a separate function to close the durations.) + + // At each call, we pull out the value for the feature and stuff + // it into the accumulator's appropriate values array; and we + // calculate the duration for the _previous_ feature, or pull it + // from the prevDurations array if the previous feature had a + // duration in its structure, and stuff that into the + // accumulator's appropriate durations array. + + if (m_prevDurations.find(output) != m_prevDurations.end()) { + + // Not the first time accumulate has been called for this + // output -- there has been a previous feature + + RealTime prevDuration; + + // Note that m_prevDurations[output] only contains the + // duration field that was contained in the previous feature. + // If it didn't have an explicit duration, + // m_prevDurations[output] should be INVALID_DURATION and we + // will have to calculate the duration from the previous and + // current timestamps. + + if (m_prevDurations[output] != INVALID_DURATION) { + prevDuration = m_prevDurations[output]; +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl; +#endif + } else { + prevDuration = timestamp - m_prevTimestamps[output]; +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "Previous duration from diff: " << timestamp << " - " + << m_prevTimestamps[output] << std::endl; +#endif + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "output " << output << ": "; + std::cerr << "Pushing previous duration as " << prevDuration << std::endl; +#endif + + m_accumulators[output].results + [m_accumulators[output].results.size() - 1] + .duration = prevDuration; + } + + if (f.hasDuration) m_prevDurations[output] = f.duration; + else m_prevDurations[output] = INVALID_DURATION; + + m_prevTimestamps[output] = timestamp; + + if (f.hasDuration) { + RealTime et = timestamp; + et = et + f.duration; + if (et > m_endTime) m_endTime = et; + } + + Result result; + result.time = timestamp; + result.duration = INVALID_DURATION; + + if (f.values.size() > m_accumulators[output].bins) { + m_accumulators[output].bins = f.values.size(); + } + + for (int i = 0; i < int(f.values.size()); ++i) { + result.values.push_back(f.values[i]); + } + + m_accumulators[output].results.push_back(result); +} + +void +PluginSummarisingAdapter::Impl::accumulateFinalDurations() +{ + for (OutputTimestampMap::iterator i = m_prevTimestamps.begin(); + i != m_prevTimestamps.end(); ++i) { + + int output = i->first; + + int acount = m_accumulators[output].results.size(); + + if (acount == 0) continue; + + RealTime prevTimestamp = i->second; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "output " << output << ": "; +#endif + + if (m_prevDurations.find(output) != m_prevDurations.end() && + m_prevDurations[output] != INVALID_DURATION) { + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl; +#endif + + m_accumulators[output].results[acount - 1].duration = + m_prevDurations[output]; + + } else { + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl; +#endif + + m_accumulators[output].results[acount - 1].duration = + m_endTime - m_prevTimestamps[output]; + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "so duration for result no " << acount-1 << " is " + << m_accumulators[output].results[acount-1].duration + << std::endl; +#endif + } +} + +void +PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t, + RealTime &start, + RealTime &end) +{ +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT + std::cerr << "findSegmentBounds: t = " << t << std::endl; +#endif + + SegmentBoundaries::const_iterator i = std::upper_bound + (m_boundaries.begin(), m_boundaries.end(), t); + + start = RealTime::zeroTime; + end = m_endTime; + + if (i != m_boundaries.end()) { + end = *i; + } + + if (i != m_boundaries.begin()) { + start = *--i; + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT + std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl; +#endif +} + +void +PluginSummarisingAdapter::Impl::segment() +{ + SegmentBoundaries::iterator boundaryitr = m_boundaries.begin(); + RealTime segmentStart = RealTime::zeroTime; + + for (OutputAccumulatorMap::iterator i = m_accumulators.begin(); + i != m_accumulators.end(); ++i) { + + int output = i->first; + OutputAccumulator &source = i->second; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT + std::cerr << "segment: total results for output " << output << " = " + << source.results.size() << std::endl; +#endif + + //!!! This is basically nonsense if the results have no values + //!!! (i.e. their times and counts are the only things of + //!!! interest) but perhaps it's the user's problem if they + //!!! ask for segmentation in that case + + for (int n = 0; n < source.results.size(); ++n) { + + // This result spans source.results[n].time to + // source.results[n].time + source.results[n].duration. + // We need to dispose it into segments appropriately + + RealTime resultStart = source.results[n].time; + RealTime resultEnd = resultStart + source.results[n].duration; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT + std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl; +#endif + + RealTime segmentStart = RealTime::zeroTime; + RealTime segmentEnd = resultEnd - RealTime(1, 0); + + while (segmentEnd < resultEnd) { + + findSegmentBounds(resultStart, segmentStart, segmentEnd); + + RealTime chunkStart = resultStart; + if (chunkStart < segmentStart) chunkStart = segmentStart; + + RealTime chunkEnd = resultEnd; + if (chunkEnd > segmentEnd) chunkEnd = segmentEnd; + + m_segmentedAccumulators[output][segmentStart].bins = source.bins; + + Result chunk; + chunk.time = chunkStart; + chunk.duration = chunkEnd - chunkStart; + chunk.values = source.results[n].values; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT + std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl; +#endif + + m_segmentedAccumulators[output][segmentStart].results + .push_back(chunk); + + resultStart = chunkEnd; + } + } + } +} + +struct ValueDurationFloatPair +{ + float value; + float duration; + + ValueDurationFloatPair() : value(0), duration(0) { } + ValueDurationFloatPair(float v, float d) : value(v), duration(d) { } + ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) { + value = p.value; + duration = p.duration; + return *this; + } + bool operator<(const ValueDurationFloatPair &p) const { + return value < p.value; + } +}; + +static double toSec(const RealTime &r) +{ + return r.sec + double(r.nsec) / 1000000000.0; +} + +void +PluginSummarisingAdapter::Impl::reduce() +{ + for (OutputSegmentAccumulatorMap::iterator i = + m_segmentedAccumulators.begin(); + i != m_segmentedAccumulators.end(); ++i) { + + int output = i->first; + SegmentAccumulatorMap &segments = i->second; + + for (SegmentAccumulatorMap::iterator j = segments.begin(); + j != segments.end(); ++j) { + + RealTime segmentStart = j->first; + OutputAccumulator &accumulator = j->second; + + int sz = accumulator.results.size(); + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "reduce: segment starting at " << segmentStart + << " on output " << output << " has " << sz << " result(s)" << std::endl; +#endif + + double totalDuration = 0.0; + //!!! is this right? + if (sz > 0) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "last time = " << accumulator.results[sz-1].time + << ", duration = " << accumulator.results[sz-1].duration + << " (step = " << m_stepSize << ", block = " << m_blockSize << ")" + << std::endl; +#endif + totalDuration = toSec((accumulator.results[sz-1].time + + accumulator.results[sz-1].duration) - + segmentStart); + } + + for (int bin = 0; bin < accumulator.bins; ++bin) { + + // work on all values over time for a single bin + + OutputBinSummary summary; + + summary.count = sz; + + summary.minimum = 0.f; + summary.maximum = 0.f; + + summary.median = 0.f; + summary.mode = 0.f; + summary.sum = 0.f; + summary.variance = 0.f; + + summary.median_c = 0.f; + summary.mode_c = 0.f; + summary.mean_c = 0.f; + summary.variance_c = 0.f; + + if (sz == 0) continue; + + std::vector<ValueDurationFloatPair> valvec; + + for (int k = 0; k < sz; ++k) { + while (accumulator.results[k].values.size() < + accumulator.bins) { + accumulator.results[k].values.push_back(0.f); + } + } + + for (int k = 0; k < sz; ++k) { + float value = accumulator.results[k].values[bin]; + valvec.push_back(ValueDurationFloatPair + (value, + toSec(accumulator.results[k].duration))); + } + + std::sort(valvec.begin(), valvec.end()); + + summary.minimum = valvec[0].value; + summary.maximum = valvec[sz-1].value; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "total duration = " << totalDuration << std::endl; +#endif + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER +/* + std::cerr << "value vector for medians:" << std::endl; + for (int k = 0; k < sz; ++k) { + std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") "; + } + std::cerr << std::endl; +*/ +#endif + + if (sz % 2 == 1) { + summary.median = valvec[sz/2].value; + } else { + summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2; + } + + double duracc = 0.0; + summary.median_c = valvec[sz-1].value; + + for (int k = 0; k < sz; ++k) { + duracc += valvec[k].duration; + if (duracc > totalDuration/2) { + summary.median_c = valvec[k].value; + break; + } + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "median_c = " << summary.median_c << std::endl; + std::cerr << "median = " << summary.median << std::endl; +#endif + + std::map<float, int> distribution; + + for (int k = 0; k < sz; ++k) { + summary.sum += accumulator.results[k].values[bin]; + distribution[accumulator.results[k].values[bin]] += 1; + } + + int md = 0; + + for (std::map<float, int>::iterator di = distribution.begin(); + di != distribution.end(); ++di) { + if (di->second > md) { + md = di->second; + summary.mode = di->first; + } + } + + distribution.clear(); + + std::map<float, double> distribution_c; + + for (int k = 0; k < sz; ++k) { + distribution_c[accumulator.results[k].values[bin]] + += toSec(accumulator.results[k].duration); + } + + double mrd = 0.0; + + for (std::map<float, double>::iterator di = distribution_c.begin(); + di != distribution_c.end(); ++di) { + if (di->second > mrd) { + mrd = di->second; + summary.mode_c = di->first; + } + } + + distribution_c.clear(); + + if (totalDuration > 0.0) { + + double sum_c = 0.0; + + for (int k = 0; k < sz; ++k) { + double value = accumulator.results[k].values[bin] + * toSec(accumulator.results[k].duration); + sum_c += value; + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = " + << sum_c / totalDuration << " (sz = " << sz << ")" << std::endl; +#endif + + summary.mean_c = sum_c / totalDuration; + + for (int k = 0; k < sz; ++k) { + double value = accumulator.results[k].values[bin]; +// * toSec(accumulator.results[k].duration); + summary.variance_c += + (value - summary.mean_c) * (value - summary.mean_c) + * toSec(accumulator.results[k].duration); + } + +// summary.variance_c /= summary.count; + summary.variance_c /= totalDuration; + } + + double mean = summary.sum / summary.count; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + std::cerr << "mean = " << summary.sum << " / " << summary.count << " = " + << summary.sum / summary.count << std::endl; +#endif + + for (int k = 0; k < sz; ++k) { + float value = accumulator.results[k].values[bin]; + summary.variance += (value - mean) * (value - mean); + } + summary.variance /= summary.count; + + m_summaries[output][segmentStart][bin] = summary; + } + } + } + + m_segmentedAccumulators.clear(); + m_accumulators.clear(); +} + + +} + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-hostsdk/PluginWrapper.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,201 @@ +/* -*- 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-2007 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. +*/ + +#include <vamp-hostsdk/PluginWrapper.h> + +namespace Vamp { + +namespace HostExt { + +class PluginRateExtractor : public Plugin +{ +public: + PluginRateExtractor() : Plugin(0) { } + float getRate() const { return m_inputSampleRate; } +}; + +PluginWrapper::PluginWrapper(Plugin *plugin) : + Plugin(((PluginRateExtractor *)plugin)->getRate()), + m_plugin(plugin) +{ +} + +PluginWrapper::~PluginWrapper() +{ + delete m_plugin; +} + +bool +PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + return m_plugin->initialise(channels, stepSize, blockSize); +} + +void +PluginWrapper::reset() +{ + m_plugin->reset(); +} + +Plugin::InputDomain +PluginWrapper::getInputDomain() const +{ + return m_plugin->getInputDomain(); +} + +unsigned int +PluginWrapper::getVampApiVersion() const +{ + return m_plugin->getVampApiVersion(); +} + +std::string +PluginWrapper::getIdentifier() const +{ + return m_plugin->getIdentifier(); +} + +std::string +PluginWrapper::getName() const +{ + return m_plugin->getName(); +} + +std::string +PluginWrapper::getDescription() const +{ + return m_plugin->getDescription(); +} + +std::string +PluginWrapper::getMaker() const +{ + return m_plugin->getMaker(); +} + +int +PluginWrapper::getPluginVersion() const +{ + return m_plugin->getPluginVersion(); +} + +std::string +PluginWrapper::getCopyright() const +{ + return m_plugin->getCopyright(); +} + +PluginBase::ParameterList +PluginWrapper::getParameterDescriptors() const +{ + return m_plugin->getParameterDescriptors(); +} + +float +PluginWrapper::getParameter(std::string parameter) const +{ + return m_plugin->getParameter(parameter); +} + +void +PluginWrapper::setParameter(std::string parameter, float value) +{ + m_plugin->setParameter(parameter, value); +} + +PluginBase::ProgramList +PluginWrapper::getPrograms() const +{ + return m_plugin->getPrograms(); +} + +std::string +PluginWrapper::getCurrentProgram() const +{ + return m_plugin->getCurrentProgram(); +} + +void +PluginWrapper::selectProgram(std::string program) +{ + m_plugin->selectProgram(program); +} + +size_t +PluginWrapper::getPreferredStepSize() const +{ + return m_plugin->getPreferredStepSize(); +} + +size_t +PluginWrapper::getPreferredBlockSize() const +{ + return m_plugin->getPreferredBlockSize(); +} + +size_t +PluginWrapper::getMinChannelCount() const +{ + return m_plugin->getMinChannelCount(); +} + +size_t PluginWrapper::getMaxChannelCount() const +{ + return m_plugin->getMaxChannelCount(); +} + +Plugin::OutputList +PluginWrapper::getOutputDescriptors() const +{ + return m_plugin->getOutputDescriptors(); +} + +Plugin::FeatureSet +PluginWrapper::process(const float *const *inputBuffers, RealTime timestamp) +{ + return m_plugin->process(inputBuffers, timestamp); +} + +Plugin::FeatureSet +PluginWrapper::getRemainingFeatures() +{ + return m_plugin->getRemainingFeatures(); +} + +} + +} +
--- a/src/vamp-hostsdk/hostext/PluginBufferingAdapter.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,657 +0,0 @@ -/* -*- 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-2007 Chris Cannam and QMUL. - This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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. -*/ - -#include <vector> -#include <map> - -#include <vamp-hostsdk/hostext/PluginBufferingAdapter.h> - -using std::vector; -using std::map; - -namespace Vamp { - -namespace HostExt { - -class PluginBufferingAdapter::Impl -{ -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); - - void setPluginStepSize(size_t stepSize); - void setPluginBlockSize(size_t blockSize); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - - OutputList getOutputDescriptors() const; - - void reset(); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - FeatureSet getRemainingFeatures(); - -protected: - class RingBuffer - { - public: - RingBuffer(int n) : - m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } - virtual ~RingBuffer() { delete[] m_buffer; } - - int getSize() const { return m_size-1; } - void reset() { m_writer = 0; m_reader = 0; } - - int getReadSpace() const { - int writer = m_writer, reader = m_reader, space; - if (writer > reader) space = writer - reader; - else if (writer < reader) space = (writer + m_size) - reader; - else space = 0; - return space; - } - - int getWriteSpace() const { - int writer = m_writer; - int reader = m_reader; - int space = (reader + m_size - writer - 1); - if (space >= m_size) space -= m_size; - return space; - } - - int peek(float *destination, int n) const { - - int available = getReadSpace(); - - if (n > available) { - for (int i = available; i < n; ++i) { - destination[i] = 0.f; - } - n = available; - } - if (n == 0) return n; - - int reader = m_reader; - int here = m_size - reader; - const float *const bufbase = m_buffer + reader; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - destination[i] = bufbase[i]; - } - } else { - for (int i = 0; i < here; ++i) { - destination[i] = bufbase[i]; - } - float *const destbase = destination + here; - const int nh = n - here; - for (int i = 0; i < nh; ++i) { - destbase[i] = m_buffer[i]; - } - } - - return n; - } - - int skip(int n) { - - int available = getReadSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int reader = m_reader; - reader += n; - while (reader >= m_size) reader -= m_size; - m_reader = reader; - return n; - } - - int write(const float *source, int n) { - - int available = getWriteSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int writer = m_writer; - int here = m_size - writer; - float *const bufbase = m_buffer + writer; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - bufbase[i] = source[i]; - } - } else { - for (int i = 0; i < here; ++i) { - bufbase[i] = source[i]; - } - const int nh = n - here; - const float *const srcbase = source + here; - float *const buf = m_buffer; - for (int i = 0; i < nh; ++i) { - buf[i] = srcbase[i]; - } - } - - writer += n; - while (writer >= m_size) writer -= m_size; - m_writer = writer; - - return n; - } - - int zero(int n) { - - int available = getWriteSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int writer = m_writer; - int here = m_size - writer; - float *const bufbase = m_buffer + writer; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - bufbase[i] = 0.f; - } - } else { - for (int i = 0; i < here; ++i) { - bufbase[i] = 0.f; - } - const int nh = n - here; - for (int i = 0; i < nh; ++i) { - m_buffer[i] = 0.f; - } - } - - writer += n; - while (writer >= m_size) writer -= m_size; - m_writer = writer; - - return n; - } - - protected: - float *m_buffer; - int m_writer; - int m_reader; - int m_size; - - private: - RingBuffer(const RingBuffer &); // not provided - RingBuffer &operator=(const RingBuffer &); // not provided - }; - - Plugin *m_plugin; - size_t m_inputStepSize; // value passed to wrapper initialise() - size_t m_inputBlockSize; // value passed to wrapper initialise() - size_t m_setStepSize; // value passed to setPluginStepSize() - size_t m_setBlockSize; // value passed to setPluginBlockSize() - size_t m_stepSize; // value actually used to initialise plugin - size_t m_blockSize; // value actually used to initialise plugin - size_t m_channels; - vector<RingBuffer *> m_queue; - float **m_buffers; - float m_inputSampleRate; - long m_frame; - bool m_unrun; - mutable OutputList m_outputs; - mutable std::map<int, bool> m_rewriteOutputTimes; - - void processBlock(FeatureSet& allFeatureSets); -}; - -PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin, m_inputSampleRate); -} - -PluginBufferingAdapter::~PluginBufferingAdapter() -{ - delete m_impl; -} - -size_t -PluginBufferingAdapter::getPreferredStepSize() const -{ - return getPreferredBlockSize(); -} - -size_t -PluginBufferingAdapter::getPreferredBlockSize() const -{ - return PluginWrapper::getPreferredBlockSize(); -} - -size_t -PluginBufferingAdapter::getPluginPreferredStepSize() const -{ - return PluginWrapper::getPreferredStepSize(); -} - -size_t -PluginBufferingAdapter::getPluginPreferredBlockSize() const -{ - return PluginWrapper::getPreferredBlockSize(); -} - -void -PluginBufferingAdapter::setPluginStepSize(size_t stepSize) -{ - m_impl->setPluginStepSize(stepSize); -} - -void -PluginBufferingAdapter::setPluginBlockSize(size_t blockSize) -{ - m_impl->setPluginBlockSize(blockSize); -} - -void -PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize, - size_t &blockSize) -{ - m_impl->getActualStepAndBlockSizes(stepSize, blockSize); -} - -bool -PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - return m_impl->initialise(channels, stepSize, blockSize); -} - -PluginBufferingAdapter::OutputList -PluginBufferingAdapter::getOutputDescriptors() const -{ - return m_impl->getOutputDescriptors(); -} - -void -PluginBufferingAdapter::reset() -{ - m_impl->reset(); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::process(const float *const *inputBuffers, - RealTime timestamp) -{ - return m_impl->process(inputBuffers, timestamp); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::getRemainingFeatures() -{ - return m_impl->getRemainingFeatures(); -} - -PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputStepSize(0), - m_inputBlockSize(0), - m_setStepSize(0), - m_setBlockSize(0), - m_stepSize(0), - m_blockSize(0), - m_channels(0), - m_queue(0), - m_buffers(0), - m_inputSampleRate(inputSampleRate), - m_frame(0), - m_unrun(true) -{ - (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes -} - -PluginBufferingAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin - - for (size_t i = 0; i < m_channels; ++i) { - delete m_queue[i]; - delete[] m_buffers[i]; - } - delete[] m_buffers; -} - -void -PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize) -{ - if (m_inputStepSize != 0) { - std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl; - return; - } - m_setStepSize = stepSize; -} - -void -PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize) -{ - if (m_inputBlockSize != 0) { - std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl; - return; - } - m_setBlockSize = blockSize; -} - -void -PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize, - size_t &blockSize) -{ - stepSize = m_stepSize; - blockSize = m_blockSize; -} - -bool -PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (stepSize != blockSize) { - std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; - return false; - } - - m_channels = channels; - m_inputStepSize = stepSize; - m_inputBlockSize = blockSize; - - // if the user has requested particular step or block sizes, use - // those; otherwise use the step and block sizes which the plugin - // prefers - - m_stepSize = 0; - m_blockSize = 0; - - if (m_setStepSize > 0) { - m_stepSize = m_setStepSize; - } - if (m_setBlockSize > 0) { - m_blockSize = m_setBlockSize; - } - - if (m_stepSize == 0 && m_blockSize == 0) { - m_stepSize = m_plugin->getPreferredStepSize(); - m_blockSize = m_plugin->getPreferredBlockSize(); - } - - bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); - - // or sensible defaults if it has no preference - if (m_blockSize == 0) { - if (m_stepSize == 0) { - m_blockSize = 1024; - } else if (freq) { - m_blockSize = m_stepSize * 2; - } else { - m_blockSize = m_stepSize; - } - } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above) - if (freq) { - m_stepSize = m_blockSize/2; - } else { - m_stepSize = m_blockSize; - } - } - - // current implementation breaks if step is greater than block - if (m_stepSize > m_blockSize) { - size_t newBlockSize; - if (freq) { - newBlockSize = m_stepSize * 2; - } else { - newBlockSize = m_stepSize; - } - std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl; - m_blockSize = newBlockSize; - } - - std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize - << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; - - m_buffers = new float *[m_channels]; - - for (size_t i = 0; i < m_channels; ++i) { - m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize)); - m_buffers[i] = new float[m_blockSize]; - } - - return m_plugin->initialise(m_channels, m_stepSize, m_blockSize); -} - -PluginBufferingAdapter::OutputList -PluginBufferingAdapter::Impl::getOutputDescriptors() const -{ - if (m_outputs.empty()) { - m_outputs = m_plugin->getOutputDescriptors(); - } - - PluginBufferingAdapter::OutputList outs = m_outputs; - - for (size_t i = 0; i < outs.size(); ++i) { - - switch (outs[i].sampleType) { - - case OutputDescriptor::OneSamplePerStep: - outs[i].sampleType = OutputDescriptor::FixedSampleRate; - outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; - m_rewriteOutputTimes[i] = true; - break; - - case OutputDescriptor::FixedSampleRate: - if (outs[i].sampleRate == 0.f) { - outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; - } - // We actually only need to rewrite output times for - // features that don't have timestamps already, but we - // can't tell from here whether our features will have - // timestamps or not - m_rewriteOutputTimes[i] = true; - break; - - case OutputDescriptor::VariableSampleRate: - m_rewriteOutputTimes[i] = false; - break; - } - } - - return outs; -} - -void -PluginBufferingAdapter::Impl::reset() -{ - m_frame = 0; - m_unrun = true; - - for (size_t i = 0; i < m_queue.size(); ++i) { - m_queue[i]->reset(); - } - - m_plugin->reset(); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_inputStepSize == 0) { - std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl; - return FeatureSet(); - } - - FeatureSet allFeatureSets; - - if (m_unrun) { - m_frame = RealTime::realTime2Frame(timestamp, - int(m_inputSampleRate + 0.5)); - m_unrun = false; - } - - // queue the new input - - for (size_t i = 0; i < m_channels; ++i) { - int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize); - if (written < int(m_inputBlockSize) && i == 0) { - std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " - << "Buffer overflow: wrote " << written - << " of " << m_inputBlockSize - << " input samples (for plugin step size " - << m_stepSize << ", block size " << m_blockSize << ")" - << std::endl; - } - } - - // process as much as we can - - while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { - processBlock(allFeatureSets); - } - - return allFeatureSets; -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::Impl::getRemainingFeatures() -{ - FeatureSet allFeatureSets; - - // process remaining samples in queue - while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { - processBlock(allFeatureSets); - } - - // pad any last samples remaining and process - if (m_queue[0]->getReadSpace() > 0) { - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); - } - processBlock(allFeatureSets); - } - - // get remaining features - - FeatureSet featureSet = m_plugin->getRemainingFeatures(); - - for (map<int, FeatureList>::iterator iter = featureSet.begin(); - iter != featureSet.end(); ++iter) { - FeatureList featureList = iter->second; - for (size_t i = 0; i < featureList.size(); ++i) { - allFeatureSets[iter->first].push_back(featureList[i]); - } - } - - return allFeatureSets; -} - -void -PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) -{ - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->peek(m_buffers[i], m_blockSize); - } - - long frame = m_frame; - RealTime timestamp = RealTime::frame2RealTime - (frame, int(m_inputSampleRate + 0.5)); - - FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); - - for (FeatureSet::iterator iter = featureSet.begin(); - iter != featureSet.end(); ++iter) { - - int outputNo = iter->first; - - if (m_rewriteOutputTimes[outputNo]) { - - FeatureList featureList = iter->second; - - for (size_t i = 0; i < featureList.size(); ++i) { - - switch (m_outputs[outputNo].sampleType) { - - case OutputDescriptor::OneSamplePerStep: - // use our internal timestamp, always - featureList[i].timestamp = timestamp; - featureList[i].hasTimestamp = true; - break; - - case OutputDescriptor::FixedSampleRate: - // use our internal timestamp if feature lacks one - if (!featureList[i].hasTimestamp) { - featureList[i].timestamp = timestamp; - featureList[i].hasTimestamp = true; - } - break; - - case OutputDescriptor::VariableSampleRate: - break; // plugin must set timestamp - - default: - break; - } - - allFeatureSets[outputNo].push_back(featureList[i]); - } - } else { - for (size_t i = 0; i < iter->second.size(); ++i) { - allFeatureSets[outputNo].push_back(iter->second[i]); - } - } - } - - // step forward - - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->skip(m_stepSize); - } - - // increment internal frame counter each time we step forward - m_frame += m_stepSize; -} - -} - -} - -
--- a/src/vamp-hostsdk/hostext/PluginChannelAdapter.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,266 +0,0 @@ -/* -*- 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-2007 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. -*/ - -#include <vamp-hostsdk/hostext/PluginChannelAdapter.h> - -namespace Vamp { - -namespace HostExt { - -class PluginChannelAdapter::Impl -{ -public: - Impl(Plugin *plugin); - ~Impl(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp); - -protected: - Plugin *m_plugin; - size_t m_blockSize; - size_t m_inputChannels; - size_t m_pluginChannels; - float **m_buffer; - float **m_deinterleave; - const float **m_forwardPtrs; -}; - -PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin); -} - -PluginChannelAdapter::~PluginChannelAdapter() -{ - delete m_impl; -} - -bool -PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - return m_impl->initialise(channels, stepSize, blockSize); -} - -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::process(const float *const *inputBuffers, - RealTime timestamp) -{ - return m_impl->process(inputBuffers, timestamp); -} - -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::processInterleaved(const float *inputBuffers, - RealTime timestamp) -{ - return m_impl->processInterleaved(inputBuffers, timestamp); -} - -PluginChannelAdapter::Impl::Impl(Plugin *plugin) : - m_plugin(plugin), - m_blockSize(0), - m_inputChannels(0), - m_pluginChannels(0), - m_buffer(0), - m_deinterleave(0), - m_forwardPtrs(0) -{ -} - -PluginChannelAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin - - if (m_buffer) { - if (m_inputChannels > m_pluginChannels) { - delete[] m_buffer[0]; - } else { - for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) { - delete[] m_buffer[i]; - } - } - delete[] m_buffer; - m_buffer = 0; - } - - if (m_deinterleave) { - for (size_t i = 0; i < m_inputChannels; ++i) { - delete[] m_deinterleave[i]; - } - delete[] m_deinterleave; - m_deinterleave = 0; - } - - if (m_forwardPtrs) { - delete[] m_forwardPtrs; - m_forwardPtrs = 0; - } -} - -bool -PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - m_blockSize = blockSize; - - size_t minch = m_plugin->getMinChannelCount(); - size_t maxch = m_plugin->getMaxChannelCount(); - - m_inputChannels = channels; - - if (m_inputChannels < minch) { - - m_forwardPtrs = new const float *[minch]; - - if (m_inputChannels > 1) { - // We need a set of zero-valued buffers to add to the - // forwarded pointers - m_buffer = new float*[minch - channels]; - for (size_t i = 0; i < minch; ++i) { - m_buffer[i] = new float[blockSize]; - for (size_t j = 0; j < blockSize; ++j) { - m_buffer[i][j] = 0.f; - } - } - } - - m_pluginChannels = minch; - - std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; - - } else if (m_inputChannels > maxch) { - - // We only need m_buffer if we are mixing down to a single - // channel -- otherwise we can just forward the same float* as - // passed in to process(), expecting the excess to be ignored - - if (maxch == 1) { - m_buffer = new float *[1]; - m_buffer[0] = new float[blockSize]; - - std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl; - - } else { - - std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; - } - - m_pluginChannels = maxch; - - } else { - - std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl; - m_pluginChannels = m_inputChannels; - } - - return m_plugin->initialise(m_pluginChannels, stepSize, blockSize); -} - -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers, - RealTime timestamp) -{ - if (!m_deinterleave) { - m_deinterleave = new float *[m_inputChannels]; - for (size_t i = 0; i < m_inputChannels; ++i) { - m_deinterleave[i] = new float[m_blockSize]; - } - } - - for (size_t i = 0; i < m_inputChannels; ++i) { - for (size_t j = 0; j < m_blockSize; ++j) { - m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i]; - } - } - - return process(m_deinterleave, timestamp); -} - -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ -// std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl; - - if (m_inputChannels < m_pluginChannels) { - - if (m_inputChannels == 1) { - for (size_t i = 0; i < m_pluginChannels; ++i) { - m_forwardPtrs[i] = inputBuffers[0]; - } - } else { - for (size_t i = 0; i < m_inputChannels; ++i) { - m_forwardPtrs[i] = inputBuffers[i]; - } - for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) { - m_forwardPtrs[i] = m_buffer[i - m_inputChannels]; - } - } - - return m_plugin->process(m_forwardPtrs, timestamp); - - } else if (m_inputChannels > m_pluginChannels) { - - if (m_pluginChannels == 1) { - for (size_t j = 0; j < m_blockSize; ++j) { - m_buffer[0][j] = inputBuffers[0][j]; - } - for (size_t i = 1; i < m_inputChannels; ++i) { - for (size_t j = 0; j < m_blockSize; ++j) { - m_buffer[0][j] += inputBuffers[i][j]; - } - } - for (size_t j = 0; j < m_blockSize; ++j) { - m_buffer[0][j] /= m_inputChannels; - } - return m_plugin->process(m_buffer, timestamp); - } else { - return m_plugin->process(inputBuffers, timestamp); - } - - } else { - - return m_plugin->process(inputBuffers, timestamp); - } -} - -} - -} - -
--- a/src/vamp-hostsdk/hostext/PluginInputDomainAdapter.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,578 +0,0 @@ -/* -*- 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-2007 Chris Cannam and QMUL. - - This file is based in part on Don Cross's public domain FFT - implementation. - - 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. -*/ - -#include <vamp-hostsdk/hostext/PluginInputDomainAdapter.h> - -#include <cmath> - - -/** - * 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> -#endif - - -namespace Vamp { - -namespace HostExt { - -class PluginInputDomainAdapter::Impl -{ -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - RealTime getTimestampAdjustment() const; - -protected: - Plugin *m_plugin; - float m_inputSampleRate; - int m_channels; - int m_blockSize; - float **m_freqbuf; - - double *m_ri; - double *m_window; - -#ifdef HAVE_FFTW3 - fftw_plan m_plan; - fftw_complex *m_cbuf; -#else - double *m_ro; - double *m_io; - void fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io); -#endif - - size_t makeBlockSizeAcceptable(size_t) const; -}; - -PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin, m_inputSampleRate); -} - -PluginInputDomainAdapter::~PluginInputDomainAdapter() -{ - delete m_impl; -} - -bool -PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - return m_impl->initialise(channels, stepSize, blockSize); -} - -Plugin::InputDomain -PluginInputDomainAdapter::getInputDomain() const -{ - return TimeDomain; -} - -size_t -PluginInputDomainAdapter::getPreferredStepSize() const -{ - return m_impl->getPreferredStepSize(); -} - -size_t -PluginInputDomainAdapter::getPreferredBlockSize() const -{ - return m_impl->getPreferredBlockSize(); -} - -Plugin::FeatureSet -PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp) -{ - return m_impl->process(inputBuffers, timestamp); -} - -RealTime -PluginInputDomainAdapter::getTimestampAdjustment() const -{ - return m_impl->getTimestampAdjustment(); -} - - -PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputSampleRate(inputSampleRate), - m_channels(0), - m_blockSize(0), - m_freqbuf(0), - m_ri(0), - m_window(0), -#ifdef HAVE_FFTW3 - m_plan(0), - m_cbuf(0) -#else - m_ro(0), - m_io(0) -#endif -{ -} - -PluginInputDomainAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin - - 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; - } -#else - delete[] m_ri; - delete[] m_ro; - delete[] m_io; -#endif - delete[] m_window; - } -} - -// for some visual studii apparently -#ifndef M_PI -#define M_PI 3.14159265358979232846 -#endif - -bool -PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (m_plugin->getInputDomain() == TimeDomain) { - - m_blockSize = int(blockSize); - m_channels = int(channels); - - return m_plugin->initialise(channels, stepSize, blockSize); - } - - if (blockSize < 2) { - std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl; - return false; - } - - if (blockSize & (blockSize-1)) { - std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; - return false; - } - - 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; - } -#else - delete[] m_ri; - delete[] m_ro; - delete[] m_io; -#endif - delete[] m_window; - } - - m_blockSize = int(blockSize); - m_channels = int(channels); - - m_freqbuf = new float *[m_channels]; - for (int c = 0; c < m_channels; ++c) { - m_freqbuf[c] = new float[m_blockSize + 2]; - } - m_window = new double[m_blockSize]; - - for (int i = 0; i < m_blockSize; ++i) { - // Hanning window - m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / 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(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 - - return m_plugin->initialise(channels, stepSize, blockSize); -} - -size_t -PluginInputDomainAdapter::Impl::getPreferredStepSize() const -{ - size_t step = m_plugin->getPreferredStepSize(); - - if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { - step = getPreferredBlockSize() / 2; - } - - return step; -} - -size_t -PluginInputDomainAdapter::Impl::getPreferredBlockSize() const -{ - size_t block = m_plugin->getPreferredBlockSize(); - - if (m_plugin->getInputDomain() == FrequencyDomain) { - if (block == 0) { - block = 1024; - } else { - block = makeBlockSizeAcceptable(block); - } - } - - return block; -} - -size_t -PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const -{ - if (blockSize < 2) { - - std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl - << "supported, increasing from " << blockSize << " to 2" << std::endl; - 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: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; - blockSize = nearest; - -#endif - } - - return blockSize; -} - -RealTime -PluginInputDomainAdapter::Impl::getTimestampAdjustment() const -{ - if (m_plugin->getInputDomain() == TimeDomain) { - return RealTime::zeroTime; - } else { - return RealTime::frame2RealTime - (m_blockSize/2, int(m_inputSampleRate + 0.5)); - } -} - -Plugin::FeatureSet -PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_plugin->getInputDomain() == TimeDomain) { - return m_plugin->process(inputBuffers, timestamp); - } - - // The timestamp supplied should be (according to the Vamp::Plugin - // spec) the time of the start of the time-domain input block. - // However, we want to pass to the plugin an FFT output calculated - // from the block of samples _centred_ on that timestamp. - // - // We have two options: - // - // 1. Buffer the input, calculating the fft of the values at the - // passed-in block minus blockSize/2 rather than starting at the - // passed-in block. So each time we call process on the plugin, - // we are passing in the same timestamp as was passed to our own - // process plugin, but not (the frequency domain representation - // of) the same set of samples. Advantages: avoids confusion in - // the host by ensuring the returned values have timestamps - // comparable with that passed in to this function (in fact this - // is pretty much essential for one-value-per-block outputs); - // consistent with hosts such as SV that deal with the - // frequency-domain transform themselves. Disadvantages: means - // making the not necessarily correct assumption that the samples - // preceding the first official block are all zero (or some other - // known value). - // - // 2. Increase the passed-in timestamps by half the blocksize. So - // when we call process, we are passing in the frequency domain - // representation of the same set of samples as passed to us, but - // with a different timestamp. Advantages: simplicity; avoids - // iffy assumption mentioned above. Disadvantages: inconsistency - // with SV in cases where stepSize != blockSize/2; potential - // confusion arising from returned timestamps being calculated - // from the adjusted input timestamps rather than the original - // ones (and inaccuracy where the returned timestamp is implied, - // as in one-value-per-block). - // - // Neither way is ideal, but I don't think either is strictly - // incorrect either. I think this is just a case where the same - // plugin can legitimately produce differing results from the same - // input data, depending on how that data is packaged. - // - // We'll go for option 2, adjusting the timestamps. Note in - // particular that this means some results can differ from those - // produced by SV. - -// std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp; - - timestamp = timestamp + getTimestampAdjustment(); - -// std::cerr << " to " << timestamp << std::endl; - - for (int c = 0; c < m_channels; ++c) { - - for (int i = 0; i < m_blockSize; ++i) { - m_ri[i] = double(inputBuffers[c][i]) * m_window[i]; - } - - for (int i = 0; i < m_blockSize/2; ++i) { - // FFT shift - double 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); - - 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]); - } - -#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); -} - -#ifndef HAVE_FFTW3 - -void -PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io) -{ - if (!ri || !ro || !io) return; - - unsigned int bits; - unsigned int i, j, k, m; - unsigned int blockSize, blockEnd; - - 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; - } - } - - static unsigned int tableSize = 0; - static int *table = 0; - - if (tableSize != n) { - - delete[] table; - - table = new int[n]; - - 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; - } - - tableSize = n; - } - - 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; - } - } - - 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; - } - } -} - -#endif - -} - -} -
--- a/src/vamp-hostsdk/hostext/PluginLoader.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,636 +0,0 @@ -/* -*- 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-2007 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. -*/ - -#include <vamp-hostsdk/PluginHostAdapter.h> -#include <vamp-hostsdk/hostext/PluginLoader.h> -#include <vamp-hostsdk/hostext/PluginInputDomainAdapter.h> -#include <vamp-hostsdk/hostext/PluginChannelAdapter.h> -#include <vamp-hostsdk/hostext/PluginBufferingAdapter.h> - -#include <fstream> -#include <cctype> // tolower - -#include <cstring> - -#ifdef _WIN32 - -#include <windows.h> -#include <tchar.h> -#define PLUGIN_SUFFIX "dll" - -#else /* ! _WIN32 */ - -#include <dirent.h> -#include <dlfcn.h> - -#ifdef __APPLE__ -#define PLUGIN_SUFFIX "dylib" -#else /* ! __APPLE__ */ -#define PLUGIN_SUFFIX "so" -#endif /* ! __APPLE__ */ - -#endif /* ! _WIN32 */ - -using namespace std; - -namespace Vamp { - -namespace HostExt { - -class PluginLoader::Impl -{ -public: - Impl(); - virtual ~Impl(); - - PluginKeyList listPlugins(); - - Plugin *loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags); - - PluginKey composePluginKey(string libraryName, string identifier); - - PluginCategoryHierarchy getPluginCategory(PluginKey key); - - string getLibraryPathForPlugin(PluginKey key); - - static void setInstanceToClean(PluginLoader *instance); - -protected: - class PluginDeletionNotifyAdapter : public PluginWrapper { - public: - PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader); - virtual ~PluginDeletionNotifyAdapter(); - protected: - Impl *m_loader; - }; - - class InstanceCleaner { - public: - InstanceCleaner() : m_instance(0) { } - ~InstanceCleaner() { delete m_instance; } - void setInstance(PluginLoader *instance) { m_instance = instance; } - protected: - PluginLoader *m_instance; - }; - - virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); - - map<PluginKey, string> m_pluginLibraryNameMap; - bool m_allPluginsEnumerated; - void enumeratePlugins(PluginKey forPlugin = ""); - - map<PluginKey, PluginCategoryHierarchy> m_taxonomy; - void generateTaxonomy(); - - map<Plugin *, void *> m_pluginLibraryHandleMap; - - bool decomposePluginKey(PluginKey key, - string &libraryName, string &identifier); - - void *loadLibrary(string path); - void unloadLibrary(void *handle); - void *lookupInLibrary(void *handle, const char *symbol); - - string splicePath(string a, string b); - vector<string> listFiles(string dir, string ext); - - static InstanceCleaner m_cleaner; -}; - -PluginLoader * -PluginLoader::m_instance = 0; - -PluginLoader::Impl::InstanceCleaner -PluginLoader::Impl::m_cleaner; - -PluginLoader::PluginLoader() -{ - m_impl = new Impl(); -} - -PluginLoader::~PluginLoader() -{ - delete m_impl; -} - -PluginLoader * -PluginLoader::getInstance() -{ - if (!m_instance) { - // The cleaner doesn't own the instance, because we leave the - // instance pointer in the base class for binary backwards - // compatibility reasons and to avoid waste - m_instance = new PluginLoader(); - Impl::setInstanceToClean(m_instance); - } - return m_instance; -} - -vector<PluginLoader::PluginKey> -PluginLoader::listPlugins() -{ - return m_impl->listPlugins(); -} - -Plugin * -PluginLoader::loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags) -{ - return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); -} - -PluginLoader::PluginKey -PluginLoader::composePluginKey(string libraryName, string identifier) -{ - return m_impl->composePluginKey(libraryName, identifier); -} - -PluginLoader::PluginCategoryHierarchy -PluginLoader::getPluginCategory(PluginKey key) -{ - return m_impl->getPluginCategory(key); -} - -string -PluginLoader::getLibraryPathForPlugin(PluginKey key) -{ - return m_impl->getLibraryPathForPlugin(key); -} - -PluginLoader::Impl::Impl() : - m_allPluginsEnumerated(false) -{ -} - -PluginLoader::Impl::~Impl() -{ -} - -void -PluginLoader::Impl::setInstanceToClean(PluginLoader *instance) -{ - m_cleaner.setInstance(instance); -} - -vector<PluginLoader::PluginKey> -PluginLoader::Impl::listPlugins() -{ - if (!m_allPluginsEnumerated) enumeratePlugins(); - - vector<PluginKey> plugins; - for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin(); - mi != m_pluginLibraryNameMap.end(); ++mi) { - plugins.push_back(mi->first); - } - - return plugins; -} - -void -PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin) -{ - vector<string> path = PluginHostAdapter::getPluginPath(); - - string libraryName, identifier; - if (forPlugin != "") { - if (!decomposePluginKey(forPlugin, libraryName, identifier)) { - std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \"" - << forPlugin << "\" in enumerate" << std::endl; - return; - } - } - - for (size_t i = 0; i < path.size(); ++i) { - - vector<string> files = listFiles(path[i], PLUGIN_SUFFIX); - - for (vector<string>::iterator fi = files.begin(); - fi != files.end(); ++fi) { - - if (libraryName != "") { - // libraryName is lowercased and lacking an extension, - // as it came from the plugin key - string temp = *fi; - for (size_t i = 0; i < temp.length(); ++i) { - temp[i] = tolower(temp[i]); - } - string::size_type pi = temp.find('.'); - if (pi == string::npos) { - if (libraryName != temp) continue; - } else { - if (libraryName != temp.substr(0, pi)) continue; - } - } - - string fullPath = path[i]; - fullPath = splicePath(fullPath, *fi); - void *handle = loadLibrary(fullPath); - if (!handle) continue; - - VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)lookupInLibrary - (handle, "vampGetPluginDescriptor"); - - if (!fn) { - unloadLibrary(handle); - continue; - } - - int index = 0; - const VampPluginDescriptor *descriptor = 0; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - ++index; - if (identifier != "") { - if (descriptor->identifier != identifier) continue; - } - PluginKey key = composePluginKey(*fi, descriptor->identifier); -// std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl; - if (m_pluginLibraryNameMap.find(key) == - m_pluginLibraryNameMap.end()) { - m_pluginLibraryNameMap[key] = fullPath; - } - } - - unloadLibrary(handle); - } - } - - if (forPlugin == "") m_allPluginsEnumerated = true; -} - -PluginLoader::PluginKey -PluginLoader::Impl::composePluginKey(string libraryName, string identifier) -{ - string basename = libraryName; - - string::size_type li = basename.rfind('/'); - if (li != string::npos) basename = basename.substr(li + 1); - - li = basename.find('.'); - if (li != string::npos) basename = basename.substr(0, li); - - for (size_t i = 0; i < basename.length(); ++i) { - basename[i] = tolower(basename[i]); - } - - return basename + ":" + identifier; -} - -bool -PluginLoader::Impl::decomposePluginKey(PluginKey key, - string &libraryName, - string &identifier) -{ - string::size_type ki = key.find(':'); - if (ki == string::npos) { - return false; - } - - libraryName = key.substr(0, ki); - identifier = key.substr(ki + 1); - return true; -} - -PluginLoader::PluginCategoryHierarchy -PluginLoader::Impl::getPluginCategory(PluginKey plugin) -{ - if (m_taxonomy.empty()) generateTaxonomy(); - if (m_taxonomy.find(plugin) == m_taxonomy.end()) { - return PluginCategoryHierarchy(); - } - return m_taxonomy[plugin]; -} - -string -PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin) -{ - if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { - if (m_allPluginsEnumerated) return ""; - enumeratePlugins(plugin); - } - if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { - return ""; - } - return m_pluginLibraryNameMap[plugin]; -} - -Plugin * -PluginLoader::Impl::loadPlugin(PluginKey key, - float inputSampleRate, int adapterFlags) -{ - string libname, identifier; - if (!decomposePluginKey(key, libname, identifier)) { - std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \"" - << key << "\" in loadPlugin" << std::endl; - return 0; - } - - string fullPath = getLibraryPathForPlugin(key); - if (fullPath == "") return 0; - - void *handle = loadLibrary(fullPath); - if (!handle) return 0; - - VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)lookupInLibrary - (handle, "vampGetPluginDescriptor"); - - if (!fn) { - unloadLibrary(handle); - return 0; - } - - int index = 0; - const VampPluginDescriptor *descriptor = 0; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - - if (string(descriptor->identifier) == identifier) { - - Vamp::PluginHostAdapter *plugin = - new Vamp::PluginHostAdapter(descriptor, inputSampleRate); - - Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this); - - m_pluginLibraryHandleMap[adapter] = handle; - - if (adapterFlags & ADAPT_INPUT_DOMAIN) { - if (adapter->getInputDomain() == Plugin::FrequencyDomain) { - adapter = new PluginInputDomainAdapter(adapter); - } - } - - if (adapterFlags & ADAPT_BUFFER_SIZE) { - adapter = new PluginBufferingAdapter(adapter); - } - - if (adapterFlags & ADAPT_CHANNEL_COUNT) { - adapter = new PluginChannelAdapter(adapter); - } - - return adapter; - } - - ++index; - } - - cerr << "Vamp::HostExt::PluginLoader: Plugin \"" - << identifier << "\" not found in library \"" - << fullPath << "\"" << endl; - - return 0; -} - -void -PluginLoader::Impl::generateTaxonomy() -{ -// cerr << "PluginLoader::Impl::generateTaxonomy" << endl; - - vector<string> path = PluginHostAdapter::getPluginPath(); - string libfragment = "/lib/"; - vector<string> catpath; - - string suffix = "cat"; - - for (vector<string>::iterator i = path.begin(); - i != path.end(); ++i) { - - // It doesn't matter that we're using literal forward-slash in - // this bit, as it's only relevant if the path contains - // "/lib/", which is only meaningful and only plausible on - // systems with forward-slash delimiters - - string dir = *i; - string::size_type li = dir.find(libfragment); - - if (li != string::npos) { - catpath.push_back - (dir.substr(0, li) - + "/share/" - + dir.substr(li + libfragment.length())); - } - - catpath.push_back(dir); - } - - char buffer[1024]; - - for (vector<string>::iterator i = catpath.begin(); - i != catpath.end(); ++i) { - - vector<string> files = listFiles(*i, suffix); - - for (vector<string>::iterator fi = files.begin(); - fi != files.end(); ++fi) { - - string filepath = splicePath(*i, *fi); - ifstream is(filepath.c_str(), ifstream::in | ifstream::binary); - - if (is.fail()) { -// cerr << "failed to open: " << filepath << endl; - continue; - } - -// cerr << "opened: " << filepath << endl; - - while (!!is.getline(buffer, 1024)) { - - string line(buffer); - -// cerr << "line = " << line << endl; - - string::size_type di = line.find("::"); - if (di == string::npos) continue; - - string id = line.substr(0, di); - string encodedCat = line.substr(di + 2); - - if (id.substr(0, 5) != "vamp:") continue; - id = id.substr(5); - - while (encodedCat.length() >= 1 && - encodedCat[encodedCat.length()-1] == '\r') { - encodedCat = encodedCat.substr(0, encodedCat.length()-1); - } - -// cerr << "id = " << id << ", cat = " << encodedCat << endl; - - PluginCategoryHierarchy category; - string::size_type ai; - while ((ai = encodedCat.find(" > ")) != string::npos) { - category.push_back(encodedCat.substr(0, ai)); - encodedCat = encodedCat.substr(ai + 3); - } - if (encodedCat != "") category.push_back(encodedCat); - - m_taxonomy[id] = category; - } - } - } -} - -void * -PluginLoader::Impl::loadLibrary(string path) -{ - void *handle = 0; -#ifdef _WIN32 - handle = LoadLibrary(path.c_str()); - if (!handle) { - cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" - << path << "\"" << endl; - } -#else - handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); - if (!handle) { - cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" - << path << "\": " << dlerror() << endl; - } -#endif - return handle; -} - -void -PluginLoader::Impl::unloadLibrary(void *handle) -{ -#ifdef _WIN32 - FreeLibrary((HINSTANCE)handle); -#else - dlclose(handle); -#endif -} - -void * -PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol) -{ -#ifdef _WIN32 - return (void *)GetProcAddress((HINSTANCE)handle, symbol); -#else - return (void *)dlsym(handle, symbol); -#endif -} - -string -PluginLoader::Impl::splicePath(string a, string b) -{ -#ifdef _WIN32 - return a + "\\" + b; -#else - return a + "/" + b; -#endif -} - -vector<string> -PluginLoader::Impl::listFiles(string dir, string extension) -{ - vector<string> files; - -#ifdef _WIN32 - - string expression = dir + "\\*." + extension; - WIN32_FIND_DATA data; - HANDLE fh = FindFirstFile(expression.c_str(), &data); - if (fh == INVALID_HANDLE_VALUE) return files; - - bool ok = true; - while (ok) { - files.push_back(data.cFileName); - ok = FindNextFile(fh, &data); - } - - FindClose(fh); - -#else - - size_t extlen = extension.length(); - DIR *d = opendir(dir.c_str()); - if (!d) return files; - - struct dirent *e = 0; - while ((e = readdir(d))) { - - if (!e->d_name) continue; - - size_t len = strlen(e->d_name); - if (len < extlen + 2 || - e->d_name + len - extlen - 1 != "." + extension) { - continue; - } - - files.push_back(e->d_name); - } - - closedir(d); -#endif - - return files; -} - -void -PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter) -{ - void *handle = m_pluginLibraryHandleMap[adapter]; - if (handle) unloadLibrary(handle); - m_pluginLibraryHandleMap.erase(adapter); -} - -PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin, - Impl *loader) : - PluginWrapper(plugin), - m_loader(loader) -{ -} - -PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() -{ - // We need to delete the plugin before calling pluginDeleted, as - // the delete call may require calling through to the descriptor - // (for e.g. cleanup) but pluginDeleted may unload the required - // library for the call. To prevent a double deletion when our - // parent's destructor runs (after this one), be sure to set - // m_plugin to 0 after deletion. - delete m_plugin; - m_plugin = 0; - - if (m_loader) m_loader->pluginDeleted(this); -} - -} - -}
--- a/src/vamp-hostsdk/hostext/PluginSummarisingAdapter.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,913 +0,0 @@ -/* -*- 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-2008 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. -*/ - -#include <vamp-hostsdk/hostext/PluginSummarisingAdapter.h> - -#include <map> -#include <algorithm> -#include <cmath> -#include <climits> - -#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1 -//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1 - -namespace Vamp { - -namespace HostExt { - -class PluginSummarisingAdapter::Impl -{ -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet getRemainingFeatures(); - - void setSummarySegmentBoundaries(const SegmentBoundaries &); - - FeatureList getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg); - - FeatureSet getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg); - -protected: - Plugin *m_plugin; - float m_inputSampleRate; - size_t m_stepSize; - size_t m_blockSize; - - SegmentBoundaries m_boundaries; - - typedef std::vector<float> ValueList; - - struct Result { // smaller than Feature - RealTime time; - RealTime duration; - ValueList values; // bin number -> value - }; - - typedef std::vector<Result> ResultList; - - struct OutputAccumulator { - int bins; - ResultList results; - OutputAccumulator() : bins(0) { } - }; - - typedef std::map<int, OutputAccumulator> OutputAccumulatorMap; - OutputAccumulatorMap m_accumulators; // output number -> accumulator - - typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap; - typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap; - OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented - - typedef std::map<int, RealTime> OutputTimestampMap; - OutputTimestampMap m_prevTimestamps; // output number -> timestamp - OutputTimestampMap m_prevDurations; // output number -> durations - - struct OutputBinSummary { - - int count; - - // extents - double minimum; - double maximum; - double sum; - - // sample-average results - double median; - double mode; - double variance; - - // continuous-time average results - double median_c; - double mode_c; - double mean_c; - double variance_c; - }; - - typedef std::map<int, OutputBinSummary> OutputSummary; - typedef std::map<RealTime, OutputSummary> SummarySegmentMap; - typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap; - - OutputSummarySegmentMap m_summaries; - - bool m_reduced; - RealTime m_endTime; - - void accumulate(const FeatureSet &fs, RealTime, bool final); - void accumulate(int output, const Feature &f, RealTime, bool final); - void accumulateFinalDurations(); - void findSegmentBounds(RealTime t, RealTime &start, RealTime &end); - void segment(); - void reduce(); - - std::string getSummaryLabel(SummaryType type, AveragingMethod avg); -}; - -static RealTime INVALID_DURATION(INT_MIN, INT_MIN); - -PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin, m_inputSampleRate); -} - -PluginSummarisingAdapter::~PluginSummarisingAdapter() -{ - delete m_impl; -} - -bool -PluginSummarisingAdapter::initialise(size_t channels, - size_t stepSize, size_t blockSize) -{ - return - PluginWrapper::initialise(channels, stepSize, blockSize) && - m_impl->initialise(channels, stepSize, blockSize); -} - -Plugin::FeatureSet -PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp) -{ - return m_impl->process(inputBuffers, timestamp); -} - -Plugin::FeatureSet -PluginSummarisingAdapter::getRemainingFeatures() -{ - return m_impl->getRemainingFeatures(); -} - -void -PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b) -{ - m_impl->setSummarySegmentBoundaries(b); -} - -Plugin::FeatureList -PluginSummarisingAdapter::getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg) -{ - return m_impl->getSummaryForOutput(output, type, avg); -} - -Plugin::FeatureSet -PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg) -{ - return m_impl->getSummaryForAllOutputs(type, avg); -} - -PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputSampleRate(inputSampleRate), - m_reduced(false) -{ -} - -PluginSummarisingAdapter::Impl::~Impl() -{ -} - -bool -PluginSummarisingAdapter::Impl::initialise(size_t channels, - size_t stepSize, size_t blockSize) -{ - m_stepSize = stepSize; - m_blockSize = blockSize; - return true; -} - -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_reduced) { - std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; - } - FeatureSet fs = m_plugin->process(inputBuffers, timestamp); - accumulate(fs, timestamp, false); - m_endTime = timestamp + - RealTime::frame2RealTime(m_stepSize, m_inputSampleRate); - return fs; -} - -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::getRemainingFeatures() -{ - if (m_reduced) { - std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; - } - FeatureSet fs = m_plugin->getRemainingFeatures(); - accumulate(fs, m_endTime, true); - return fs; -} - -void -PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b) -{ - m_boundaries = b; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl; - for (SegmentBoundaries::const_iterator i = m_boundaries.begin(); - i != m_boundaries.end(); ++i) { - std::cerr << *i << " "; - } - std::cerr << std::endl; -#endif -} - -Plugin::FeatureList -PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg) -{ - if (!m_reduced) { - accumulateFinalDurations(); - segment(); - reduce(); - m_reduced = true; - } - - bool continuous = (avg == ContinuousTimeAverage); - - FeatureList fl; - for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); - i != m_summaries[output].end(); ++i) { - - Feature f; - - f.hasTimestamp = true; - f.timestamp = i->first; - - f.hasDuration = true; - SummarySegmentMap::const_iterator ii = i; - if (++ii == m_summaries[output].end()) { - f.duration = m_endTime - f.timestamp; - } else { - f.duration = ii->first - f.timestamp; - } - - f.label = getSummaryLabel(type, avg); - - for (OutputSummary::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { - - // these will be ordered by bin number, and no bin numbers - // will be missing except at the end (because of the way - // the accumulators were initially filled in accumulate()) - - const OutputBinSummary &summary = j->second; - double result = 0.f; - - switch (type) { - - case Minimum: - result = summary.minimum; - break; - - case Maximum: - result = summary.maximum; - break; - - case Mean: - if (continuous) { - result = summary.mean_c; - } else if (summary.count) { - result = summary.sum / summary.count; - } - break; - - case Median: - if (continuous) result = summary.median_c; - else result = summary.median; - break; - - case Mode: - if (continuous) result = summary.mode_c; - else result = summary.mode; - break; - - case Sum: - result = summary.sum; - break; - - case Variance: - if (continuous) result = summary.variance_c; - else result = summary.variance; - break; - - case StandardDeviation: - if (continuous) result = sqrtf(summary.variance_c); - else result = sqrtf(summary.variance); - break; - - case Count: - result = summary.count; - break; - - case UnknownSummaryType: - break; - - default: - break; - } - - f.values.push_back(result); - } - - fl.push_back(f); - } - return fl; -} - -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg) -{ - if (!m_reduced) { - accumulateFinalDurations(); - segment(); - reduce(); - m_reduced = true; - } - - FeatureSet fs; - for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); - i != m_summaries.end(); ++i) { - fs[i->first] = getSummaryForOutput(i->first, type, avg); - } - return fs; -} - -void -PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs, - RealTime timestamp, - bool final) -{ - for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) { - for (FeatureList::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { - if (j->hasTimestamp) { - accumulate(i->first, *j, j->timestamp, final); - } else { - //!!! is this correct? - accumulate(i->first, *j, timestamp, final); - } - } - } -} - -std::string -PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type, - AveragingMethod avg) -{ - std::string label; - std::string avglabel; - - if (avg == SampleAverage) avglabel = ", sample average"; - else avglabel = ", continuous-time average"; - - switch (type) { - case Minimum: label = "(minimum value)"; break; - case Maximum: label = "(maximum value)"; break; - case Mean: label = "(mean value" + avglabel + ")"; break; - case Median: label = "(median value" + avglabel + ")"; break; - case Mode: label = "(modal value" + avglabel + ")"; break; - case Sum: label = "(sum)"; break; - case Variance: label = "(variance" + avglabel + ")"; break; - case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break; - case Count: label = "(count)"; break; - case UnknownSummaryType: label = "(unknown summary)"; break; - } - - return label; -} - -void -PluginSummarisingAdapter::Impl::accumulate(int output, - const Feature &f, - RealTime timestamp, - bool final) -{ -//!!! to do: use timestamp to determine which segment we're on - -//!!! What should happen if a feature's duration spans a segment -// boundary? I think we probably want to chop it, and pretend that it -// appears in both -- don't we? do we? A very long feature (e.g. key, -// if the whole audio is in a single key) might span many or all -// segments, and we want that to be reflected in the results (e.g. it -// is the modal key in all of those segments, not just the first). -// That is actually quite complicated to do! - -//!!! This affects how we record things. If features spanning a -// boundary should be chopped, then we need to have per-segment -// accumulators (and the feature value goes into both -- perhaps we -// need a separate phase to split the accumulator up into segments). -// If features spanning a boundary should be counted only in the first -// segment, with their full duration, then we should store them in a -// single accumulator and distribute into segments only on reduce. - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl; -#endif - - // At each process step, accumulate() is called once for each - // feature on each output within that process's returned feature - // list, and with the timestamp passed in being that of the start - // of the process block. - - // At the end (in getRemainingFeatures), accumulate() is called - // once for each feature on each output within the feature list - // returned by getRemainingFeatures, and with the timestamp being - // the same as the last process block and final set to true. - - // (What if getRemainingFeatures doesn't return any features? We - // still need to ensure that the final duration is written. Need - // a separate function to close the durations.) - - // At each call, we pull out the value for the feature and stuff - // it into the accumulator's appropriate values array; and we - // calculate the duration for the _previous_ feature, or pull it - // from the prevDurations array if the previous feature had a - // duration in its structure, and stuff that into the - // accumulator's appropriate durations array. - - if (m_prevDurations.find(output) != m_prevDurations.end()) { - - // Not the first time accumulate has been called for this - // output -- there has been a previous feature - - RealTime prevDuration; - - // Note that m_prevDurations[output] only contains the - // duration field that was contained in the previous feature. - // If it didn't have an explicit duration, - // m_prevDurations[output] should be INVALID_DURATION and we - // will have to calculate the duration from the previous and - // current timestamps. - - if (m_prevDurations[output] != INVALID_DURATION) { - prevDuration = m_prevDurations[output]; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl; -#endif - } else { - prevDuration = timestamp - m_prevTimestamps[output]; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "Previous duration from diff: " << timestamp << " - " - << m_prevTimestamps[output] << std::endl; -#endif - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "output " << output << ": "; - std::cerr << "Pushing previous duration as " << prevDuration << std::endl; -#endif - - m_accumulators[output].results - [m_accumulators[output].results.size() - 1] - .duration = prevDuration; - } - - if (f.hasDuration) m_prevDurations[output] = f.duration; - else m_prevDurations[output] = INVALID_DURATION; - - m_prevTimestamps[output] = timestamp; - - if (f.hasDuration) { - RealTime et = timestamp; - et = et + f.duration; - if (et > m_endTime) m_endTime = et; - } - - Result result; - result.time = timestamp; - result.duration = INVALID_DURATION; - - if (f.values.size() > m_accumulators[output].bins) { - m_accumulators[output].bins = f.values.size(); - } - - for (int i = 0; i < int(f.values.size()); ++i) { - result.values.push_back(f.values[i]); - } - - m_accumulators[output].results.push_back(result); -} - -void -PluginSummarisingAdapter::Impl::accumulateFinalDurations() -{ - for (OutputTimestampMap::iterator i = m_prevTimestamps.begin(); - i != m_prevTimestamps.end(); ++i) { - - int output = i->first; - - int acount = m_accumulators[output].results.size(); - - if (acount == 0) continue; - - RealTime prevTimestamp = i->second; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "output " << output << ": "; -#endif - - if (m_prevDurations.find(output) != m_prevDurations.end() && - m_prevDurations[output] != INVALID_DURATION) { - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl; -#endif - - m_accumulators[output].results[acount - 1].duration = - m_prevDurations[output]; - - } else { - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl; -#endif - - m_accumulators[output].results[acount - 1].duration = - m_endTime - m_prevTimestamps[output]; - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "so duration for result no " << acount-1 << " is " - << m_accumulators[output].results[acount-1].duration - << std::endl; -#endif - } -} - -void -PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t, - RealTime &start, - RealTime &end) -{ -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - std::cerr << "findSegmentBounds: t = " << t << std::endl; -#endif - - SegmentBoundaries::const_iterator i = std::upper_bound - (m_boundaries.begin(), m_boundaries.end(), t); - - start = RealTime::zeroTime; - end = m_endTime; - - if (i != m_boundaries.end()) { - end = *i; - } - - if (i != m_boundaries.begin()) { - start = *--i; - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl; -#endif -} - -void -PluginSummarisingAdapter::Impl::segment() -{ - SegmentBoundaries::iterator boundaryitr = m_boundaries.begin(); - RealTime segmentStart = RealTime::zeroTime; - - for (OutputAccumulatorMap::iterator i = m_accumulators.begin(); - i != m_accumulators.end(); ++i) { - - int output = i->first; - OutputAccumulator &source = i->second; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - std::cerr << "segment: total results for output " << output << " = " - << source.results.size() << std::endl; -#endif - - //!!! This is basically nonsense if the results have no values - //!!! (i.e. their times and counts are the only things of - //!!! interest) but perhaps it's the user's problem if they - //!!! ask for segmentation in that case - - for (int n = 0; n < source.results.size(); ++n) { - - // This result spans source.results[n].time to - // source.results[n].time + source.results[n].duration. - // We need to dispose it into segments appropriately - - RealTime resultStart = source.results[n].time; - RealTime resultEnd = resultStart + source.results[n].duration; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl; -#endif - - RealTime segmentStart = RealTime::zeroTime; - RealTime segmentEnd = resultEnd - RealTime(1, 0); - - while (segmentEnd < resultEnd) { - - findSegmentBounds(resultStart, segmentStart, segmentEnd); - - RealTime chunkStart = resultStart; - if (chunkStart < segmentStart) chunkStart = segmentStart; - - RealTime chunkEnd = resultEnd; - if (chunkEnd > segmentEnd) chunkEnd = segmentEnd; - - m_segmentedAccumulators[output][segmentStart].bins = source.bins; - - Result chunk; - chunk.time = chunkStart; - chunk.duration = chunkEnd - chunkStart; - chunk.values = source.results[n].values; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl; -#endif - - m_segmentedAccumulators[output][segmentStart].results - .push_back(chunk); - - resultStart = chunkEnd; - } - } - } -} - -struct ValueDurationFloatPair -{ - float value; - float duration; - - ValueDurationFloatPair() : value(0), duration(0) { } - ValueDurationFloatPair(float v, float d) : value(v), duration(d) { } - ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) { - value = p.value; - duration = p.duration; - return *this; - } - bool operator<(const ValueDurationFloatPair &p) const { - return value < p.value; - } -}; - -static double toSec(const RealTime &r) -{ - return r.sec + double(r.nsec) / 1000000000.0; -} - -void -PluginSummarisingAdapter::Impl::reduce() -{ - for (OutputSegmentAccumulatorMap::iterator i = - m_segmentedAccumulators.begin(); - i != m_segmentedAccumulators.end(); ++i) { - - int output = i->first; - SegmentAccumulatorMap &segments = i->second; - - for (SegmentAccumulatorMap::iterator j = segments.begin(); - j != segments.end(); ++j) { - - RealTime segmentStart = j->first; - OutputAccumulator &accumulator = j->second; - - int sz = accumulator.results.size(); - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "reduce: segment starting at " << segmentStart - << " on output " << output << " has " << sz << " result(s)" << std::endl; -#endif - - double totalDuration = 0.0; - //!!! is this right? - if (sz > 0) { -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "last time = " << accumulator.results[sz-1].time - << ", duration = " << accumulator.results[sz-1].duration - << " (step = " << m_stepSize << ", block = " << m_blockSize << ")" - << std::endl; -#endif - totalDuration = toSec((accumulator.results[sz-1].time + - accumulator.results[sz-1].duration) - - segmentStart); - } - - for (int bin = 0; bin < accumulator.bins; ++bin) { - - // work on all values over time for a single bin - - OutputBinSummary summary; - - summary.count = sz; - - summary.minimum = 0.f; - summary.maximum = 0.f; - - summary.median = 0.f; - summary.mode = 0.f; - summary.sum = 0.f; - summary.variance = 0.f; - - summary.median_c = 0.f; - summary.mode_c = 0.f; - summary.mean_c = 0.f; - summary.variance_c = 0.f; - - if (sz == 0) continue; - - std::vector<ValueDurationFloatPair> valvec; - - for (int k = 0; k < sz; ++k) { - while (accumulator.results[k].values.size() < - accumulator.bins) { - accumulator.results[k].values.push_back(0.f); - } - } - - for (int k = 0; k < sz; ++k) { - float value = accumulator.results[k].values[bin]; - valvec.push_back(ValueDurationFloatPair - (value, - toSec(accumulator.results[k].duration))); - } - - std::sort(valvec.begin(), valvec.end()); - - summary.minimum = valvec[0].value; - summary.maximum = valvec[sz-1].value; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "total duration = " << totalDuration << std::endl; -#endif - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER -/* - std::cerr << "value vector for medians:" << std::endl; - for (int k = 0; k < sz; ++k) { - std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") "; - } - std::cerr << std::endl; -*/ -#endif - - if (sz % 2 == 1) { - summary.median = valvec[sz/2].value; - } else { - summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2; - } - - double duracc = 0.0; - summary.median_c = valvec[sz-1].value; - - for (int k = 0; k < sz; ++k) { - duracc += valvec[k].duration; - if (duracc > totalDuration/2) { - summary.median_c = valvec[k].value; - break; - } - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "median_c = " << summary.median_c << std::endl; - std::cerr << "median = " << summary.median << std::endl; -#endif - - std::map<float, int> distribution; - - for (int k = 0; k < sz; ++k) { - summary.sum += accumulator.results[k].values[bin]; - distribution[accumulator.results[k].values[bin]] += 1; - } - - int md = 0; - - for (std::map<float, int>::iterator di = distribution.begin(); - di != distribution.end(); ++di) { - if (di->second > md) { - md = di->second; - summary.mode = di->first; - } - } - - distribution.clear(); - - std::map<float, double> distribution_c; - - for (int k = 0; k < sz; ++k) { - distribution_c[accumulator.results[k].values[bin]] - += toSec(accumulator.results[k].duration); - } - - double mrd = 0.0; - - for (std::map<float, double>::iterator di = distribution_c.begin(); - di != distribution_c.end(); ++di) { - if (di->second > mrd) { - mrd = di->second; - summary.mode_c = di->first; - } - } - - distribution_c.clear(); - - if (totalDuration > 0.0) { - - double sum_c = 0.0; - - for (int k = 0; k < sz; ++k) { - double value = accumulator.results[k].values[bin] - * toSec(accumulator.results[k].duration); - sum_c += value; - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = " - << sum_c / totalDuration << " (sz = " << sz << ")" << std::endl; -#endif - - summary.mean_c = sum_c / totalDuration; - - for (int k = 0; k < sz; ++k) { - double value = accumulator.results[k].values[bin]; -// * toSec(accumulator.results[k].duration); - summary.variance_c += - (value - summary.mean_c) * (value - summary.mean_c) - * toSec(accumulator.results[k].duration); - } - -// summary.variance_c /= summary.count; - summary.variance_c /= totalDuration; - } - - double mean = summary.sum / summary.count; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - std::cerr << "mean = " << summary.sum << " / " << summary.count << " = " - << summary.sum / summary.count << std::endl; -#endif - - for (int k = 0; k < sz; ++k) { - float value = accumulator.results[k].values[bin]; - summary.variance += (value - mean) * (value - mean); - } - summary.variance /= summary.count; - - m_summaries[output][segmentStart][bin] = summary; - } - } - } - - m_segmentedAccumulators.clear(); - m_accumulators.clear(); -} - - -} - -} -
--- a/src/vamp-hostsdk/hostext/PluginWrapper.cpp Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* -*- 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-2007 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. -*/ - -#include <vamp-hostsdk/hostext/PluginWrapper.h> - -namespace Vamp { - -namespace HostExt { - -class PluginRateExtractor : public Plugin -{ -public: - PluginRateExtractor() : Plugin(0) { } - float getRate() const { return m_inputSampleRate; } -}; - -PluginWrapper::PluginWrapper(Plugin *plugin) : - Plugin(((PluginRateExtractor *)plugin)->getRate()), - m_plugin(plugin) -{ -} - -PluginWrapper::~PluginWrapper() -{ - delete m_plugin; -} - -bool -PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - return m_plugin->initialise(channels, stepSize, blockSize); -} - -void -PluginWrapper::reset() -{ - m_plugin->reset(); -} - -Plugin::InputDomain -PluginWrapper::getInputDomain() const -{ - return m_plugin->getInputDomain(); -} - -unsigned int -PluginWrapper::getVampApiVersion() const -{ - return m_plugin->getVampApiVersion(); -} - -std::string -PluginWrapper::getIdentifier() const -{ - return m_plugin->getIdentifier(); -} - -std::string -PluginWrapper::getName() const -{ - return m_plugin->getName(); -} - -std::string -PluginWrapper::getDescription() const -{ - return m_plugin->getDescription(); -} - -std::string -PluginWrapper::getMaker() const -{ - return m_plugin->getMaker(); -} - -int -PluginWrapper::getPluginVersion() const -{ - return m_plugin->getPluginVersion(); -} - -std::string -PluginWrapper::getCopyright() const -{ - return m_plugin->getCopyright(); -} - -PluginBase::ParameterList -PluginWrapper::getParameterDescriptors() const -{ - return m_plugin->getParameterDescriptors(); -} - -float -PluginWrapper::getParameter(std::string parameter) const -{ - return m_plugin->getParameter(parameter); -} - -void -PluginWrapper::setParameter(std::string parameter, float value) -{ - m_plugin->setParameter(parameter, value); -} - -PluginBase::ProgramList -PluginWrapper::getPrograms() const -{ - return m_plugin->getPrograms(); -} - -std::string -PluginWrapper::getCurrentProgram() const -{ - return m_plugin->getCurrentProgram(); -} - -void -PluginWrapper::selectProgram(std::string program) -{ - m_plugin->selectProgram(program); -} - -size_t -PluginWrapper::getPreferredStepSize() const -{ - return m_plugin->getPreferredStepSize(); -} - -size_t -PluginWrapper::getPreferredBlockSize() const -{ - return m_plugin->getPreferredBlockSize(); -} - -size_t -PluginWrapper::getMinChannelCount() const -{ - return m_plugin->getMinChannelCount(); -} - -size_t PluginWrapper::getMaxChannelCount() const -{ - return m_plugin->getMaxChannelCount(); -} - -Plugin::OutputList -PluginWrapper::getOutputDescriptors() const -{ - return m_plugin->getOutputDescriptors(); -} - -Plugin::FeatureSet -PluginWrapper::process(const float *const *inputBuffers, RealTime timestamp) -{ - return m_plugin->process(inputBuffers, timestamp); -} - -Plugin::FeatureSet -PluginWrapper::getRemainingFeatures() -{ - return m_plugin->getRemainingFeatures(); -} - -} - -} -
--- a/src/vamp-sdk/PluginAdapter.cpp Fri Nov 07 14:33:21 2008 +0000 +++ b/src/vamp-sdk/PluginAdapter.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -41,7 +41,7 @@ //#define DEBUG_PLUGIN_ADAPTER 1 -namespace _VampPlugin { +_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.cpp) namespace Vamp { @@ -873,5 +873,5 @@ } -} +_VAMP_SDK_PLUGSPACE_END(PluginAdapter.cpp)
--- a/src/vamp-sdk/RealTime.cpp Fri Nov 07 14:33:21 2008 +0000 +++ b/src/vamp-sdk/RealTime.cpp Fri Nov 07 15:28:33 2008 +0000 @@ -59,9 +59,7 @@ #include <vamp-sdk/RealTime.h> -#ifdef _VAMP_IN_PLUGINSDK -namespace _VampPlugin { -#endif +_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.cpp) namespace Vamp { @@ -248,8 +246,7 @@ } -#ifdef _VAMP_IN_PLUGINSDK -} -#endif +_VAMP_SDK_PLUGSPACE_END(RealTime.cpp) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginBufferingAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,181 @@ +/* -*- 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-2007 Chris Cannam and QMUL. + This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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_BUFFERING_ADAPTER_H_ +#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_ + +#include "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-hostsdk/PluginBufferingAdapter.h> + * + * PluginBufferingAdapter is a Vamp plugin adapter that allows plugins + * to be used by a host supplying an audio stream in non-overlapping + * buffers of arbitrary size. + * + * A host using PluginBufferingAdapter may ignore the preferred step + * and block size reported by the plugin, and still expect the plugin + * to run. The value of blockSize and stepSize passed to initialise + * should be the size of the buffer which the host will supply; the + * stepSize should be equal to the blockSize. + * + * If the internal step size used for the plugin differs from that + * supplied by the host, the adapter will modify the sample type and + * rate specifications for the plugin outputs appropriately, and set + * timestamps on the output features for outputs that formerly used a + * different sample rate specification. This is necessary in order to + * obtain correct time stamping. + * + * In other respects, the PluginBufferingAdapter behaves identically + * to the plugin that it wraps. The wrapped plugin will be deleted + * when the wrapper is deleted. + */ + +class PluginBufferingAdapter : public PluginWrapper +{ +public: + PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginBufferingAdapter(); + + /** + * Return the preferred step size for this adapter. + * + * Because of the way this adapter works, its preferred step size + * will always be the same as its preferred block size. This may + * or may not be the same as the preferred step size of the + * underlying plugin, which may be obtained by calling + * getPluginPreferredStepSize(). + */ + size_t getPreferredStepSize() const; + + /** + * Return the preferred block size for this adapter. + * + * This may or may not be the same as the preferred block size of + * the underlying plugin, which may be obtained by calling + * getPluginPreferredBlockSize(). + * + * Note that this adapter may be initialised with any block size, + * not just its supposedly preferred one. + */ + size_t getPreferredBlockSize() const; + + /** + * Initialise the adapter (and therefore the plugin) for the given + * number of channels. Initialise the adapter for the given step + * and block size, which must be equal. + * + * The step and block size used for the underlying plugin will + * depend on its preferences, or any values previously passed to + * setPluginStepSize and setPluginBlockSize. + */ + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + /** + * Return the preferred step size of the plugin wrapped by this + * adapter. + * + * This is included mainly for informational purposes. This value + * is not likely to be a valid step size for the adapter itself, + * and it is not usually of any use in interpreting the results + * (because the adapter re-writes OneSamplePerStep outputs to + * FixedSampleRate so that the hop size no longer needs to be + * known beforehand in order to interpret them). + */ + size_t getPluginPreferredStepSize() const; + + /** + * Return the preferred block size of the plugin wrapped by this + * adapter. + * + * This is included mainly for informational purposes. + */ + size_t getPluginPreferredBlockSize() const; + + /** + * Set the step size that will be used for the underlying plugin + * when initialise() is called. If this is not set, the plugin's + * own preferred step size will be used. You will not usually + * need to call this function. If you do call it, it must be + * before the first call to initialise(). + */ + void setPluginStepSize(size_t stepSize); + + /** + * Set the block size that will be used for the underlying plugin + * when initialise() is called. If this is not set, the plugin's + * own preferred block size will be used. You will not usually + * need to call this function. If you do call it, it must be + * before the first call to initialise(). + */ + void setPluginBlockSize(size_t blockSize); + + /** + * Return the step and block sizes that were actually used when + * initialising the underlying plugin. + * + * This is included mainly for informational purposes. You will + * not usually need to call this function. If this is called + * before initialise(), it will return 0 for both values. If it + * is called after a failed call to initialise(), it will return + * the values that were used in the failed call to the plugin's + * initialise() function. + */ + void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); + + OutputList getOutputDescriptors() const; + + void reset(); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginChannelAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,139 @@ +/* -*- 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-2007 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_CHANNEL_ADAPTER_H_ +#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_ + +#include "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginChannelAdapter PluginChannelAdapter.h <vamp-hostsdk/PluginChannelAdapter.h> + * + * PluginChannelAdapter is a Vamp plugin adapter that implements a + * policy for management of plugins that expect a different number of + * input channels from the number actually available in the source + * audio data. + * + * A host using PluginChannelAdapter may ignore the getMinChannelCount + * and getMaxChannelCount reported by the plugin, and still expect the + * plugin to run. + * + * PluginChannelAdapter implements the following policy: + * + * - If the plugin supports the provided number of channels directly, + * PluginChannelAdapter will just run the plugin as normal. + * + * - If the plugin only supports exactly one channel but more than + * one channel is provided, PluginChannelAdapter will use the mean of + * the channels. This ensures that the resulting values remain + * within the same magnitude range as expected for mono data. + * + * - If the plugin requires more than one channel but exactly one is + * provided, the provided channel will be duplicated across all the + * plugin input channels. + * + * If none of the above apply: + * + * - If the plugin requires more channels than are provided, the + * minimum acceptable number of channels will be produced by adding + * empty (zero valued) channels to those provided. + * + * - If the plugin requires fewer channels than are provided, the + * maximum acceptable number of channels will be produced by + * discarding the excess channels. + * + * Hosts requiring a different channel policy from the above will need + * to implement it themselves, instead of using PluginChannelAdapter. + * + * Note that PluginChannelAdapter does not override the minimum and + * maximum channel counts returned by the wrapped plugin. The host + * will need to be aware that it is using a PluginChannelAdapter, and + * be prepared to ignore these counts as necessary. (This contrasts + * with the approach used in PluginInputDomainAdapter, which aims to + * make the host completely unaware of which underlying input domain + * is in fact in use.) + * + * (The rationale for this is that a host may wish to use the + * PluginChannelAdapter but still discriminate in some way on the + * basis of the number of channels actually supported. For example, a + * simple stereo audio host may prefer to reject plugins that require + * more than two channels on the grounds that doesn't actually + * understand what they are for, rather than allow the channel adapter + * to make a potentially meaningless channel conversion for them.) + * + * In every respect other than its management of channels, the + * PluginChannelAdapter behaves identically to the plugin that it + * wraps. The wrapped plugin will be deleted when the wrapper is + * deleted. + * + * \note This class was introduced in version 1.1 of the Vamp plugin SDK. + */ + +class PluginChannelAdapter : public PluginWrapper +{ +public: + PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginChannelAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + /** + * Call process(), providing interleaved audio data with the + * number of channels passed to initialise(). The adapter will + * de-interleave into temporary buffers as appropriate before + * calling process(). + * + * \note This function was introduced in version 1.4 of the Vamp + * plugin SDK. + */ + FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp); + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif
--- a/vamp-hostsdk/PluginHostAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-hostsdk/PluginHostAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -45,7 +45,7 @@ namespace Vamp { /** - * \class PluginHostAdapter PluginHostAdapter.h <vamp-sdk/PluginHostAdapter.h> + * \class PluginHostAdapter PluginHostAdapter.h <vamp-hostsdk/PluginHostAdapter.h> * * PluginHostAdapter is a wrapper class that a Vamp host can use to * make the C-language VampPluginDescriptor object appear as a C++
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginInputDomainAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,126 @@ +/* -*- 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-2007 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_INPUT_DOMAIN_ADAPTER_H_ +#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_ + +#include "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-hostsdk/PluginInputDomainAdapter.h> + * + * PluginInputDomainAdapter is a Vamp plugin adapter that converts + * time-domain input into frequency-domain input for plugins that need + * it. This permits a host to use time- and frequency-domain plugins + * interchangeably without needing to handle the conversion itself. + * + * This adapter uses a basic Hanning windowed FFT that supports + * power-of-two block sizes only. If a frequency domain plugin + * requests a non-power-of-two blocksize, the adapter will adjust it + * to a nearby power of two instead. Thus, getPreferredBlockSize() + * will always return a power of two if the wrapped plugin is a + * frequency domain one. If the plugin doesn't accept the adjusted + * power of two block size, initialise() will fail. + * + * The adapter provides no way for the host to discover whether the + * underlying plugin is actually a time or frequency domain plugin + * (except that if the preferred block size is not a power of two, it + * must be a time domain plugin). + * + * The FFT implementation is simple and self-contained, but unlikely + * to be the fastest available: a host can usually do better if it + * cares enough. + * + * In every respect other than its input domain handling, the + * PluginInputDomainAdapter behaves identically to the plugin that it + * wraps. The wrapped plugin will be deleted when the wrapper is + * deleted. + * + * \note This class was introduced in version 1.1 of the Vamp plugin SDK. + */ + +class PluginInputDomainAdapter : public PluginWrapper +{ +public: + PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginInputDomainAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + InputDomain getInputDomain() const; + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + /** + * Return the amount by which the timestamps supplied to process() + * are being incremented when they are passed to the plugin's own + * process() implementation. + * + * The Vamp API mandates that the timestamp passed to the plugin + * for time-domain input should be the time of the first sample in + * the block, but the timestamp passed for frequency-domain input + * should be the timestamp of the centre of the block. + * + * The PluginInputDomainAdapter adjusts its timestamps properly so + * that the plugin receives correct times, but in some + * circumstances (such as for establishing the correct timing of + * implicitly-timed features, i.e. features without their own + * timestamps) the host may need to be aware that this adjustment + * is taking place. + * + * If the plugin requires time-domain input, this function will + * return zero. The result of calling this function before + * initialise() has been called is undefined. + */ + RealTime getTimestampAdjustment() const; + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginLoader.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,238 @@ +/* -*- 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-2007 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_LOADER_H_ +#define _VAMP_PLUGIN_LOADER_H_ + +#include <vector> +#include <string> +#include <map> + +#include "PluginWrapper.h" + +namespace Vamp { + +class Plugin; + +namespace HostExt { + +/** + * \class PluginLoader PluginLoader.h <vamp-hostsdk/PluginLoader.h> + * + * Vamp::HostExt::PluginLoader is a convenience class for discovering + * and loading Vamp plugins using the typical plugin-path, library + * naming, and categorisation conventions described in the Vamp SDK + * documentation. This class is intended to greatly simplify the task + * of becoming a Vamp plugin host for any C++ application. + * + * Hosts are not required by the Vamp specification to use the same + * plugin search path and naming conventions as implemented by this + * class, and are certainly not required to use this actual class. + * But we do strongly recommend it. + * + * \note This class was introduced in version 1.1 of the Vamp plugin SDK. + */ + +class PluginLoader +{ +public: + /** + * Obtain a pointer to the singleton instance of PluginLoader. + * Use this to obtain your loader object. + */ + static PluginLoader *getInstance(); + + /** + * PluginKey is a string type that is used to identify a plugin + * uniquely within the scope of "the current system". It consists + * of the lower-cased base name of the plugin library, a colon + * separator, and the identifier string for the plugin. It is + * only meaningful in the context of a given plugin path (the one + * returned by PluginHostAdapter::getPluginPath()). + * + * Use composePluginKey() to construct a plugin key from a known + * plugin library name and identifier. + * + * Note: the fact that the library component of the key is + * lower-cased implies that library names are matched + * case-insensitively by the PluginLoader class, regardless of the + * case sensitivity of the underlying filesystem. (Plugin + * identifiers _are_ case sensitive, however.) Also, it is not + * possible to portably extract a working library name from a + * plugin key, as the result may fail on case-sensitive + * filesystems. Use getLibraryPathForPlugin() instead. + */ + typedef std::string PluginKey; + + /** + * PluginKeyList is a sequence of plugin keys, such as returned by + * listPlugins(). + */ + typedef std::vector<PluginKey> PluginKeyList; + + /** + * PluginCategoryHierarchy is a sequence of general->specific + * category names, as may be associated with a single plugin. + * This sequence describes the location of a plugin within a + * category forest, containing the human-readable names of the + * plugin's category tree root, followed by each of the nodes down + * to the leaf containing the plugin. + * + * \see getPluginCategory() + */ + typedef std::vector<std::string> PluginCategoryHierarchy; + + /** + * Search for all available Vamp plugins, and return a list of + * them in the order in which they were found. + */ + PluginKeyList listPlugins(); + + /** + * 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 + * does not want to cater for complex features. + * + * The available flags are: + * + * ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain + * input, wrap it in a PluginInputDomainAdapter that automatically + * converts the plugin to one that expects time-domain input. + * This enables a host to accommodate time- and frequency-domain + * plugins without needing to do any conversion itself. + * + * ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter + * to handle any mismatch between the number of channels of audio + * the plugin can handle and the number available in the host. + * This enables a host to use plugins that may require the input + * to be mixed down to mono, etc., without having to worry about + * doing that itself. + * + * ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter + * permitting the host to provide audio input using any block + * size, with no overlap, regardless of the plugin's preferred + * block size (suitable for hosts that read from non-seekable + * streaming media, for example). This adapter introduces some + * run-time overhead and also changes the semantics of the plugin + * slightly (see the PluginBufferingAdapter header documentation + * for details). + * + * ADAPT_ALL_SAFE - Perform all available adaptations that are + * meaningful for the plugin and "safe". Currently this means to + * ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input; + * ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never. + * + * ADAPT_ALL - Perform all available adaptations that are + * meaningful for the plugin. + * + * See PluginInputDomainAdapter, PluginChannelAdapter and + * PluginBufferingAdapter for more details of the classes that the + * loader may use if these flags are set. + */ + enum AdapterFlags { + + ADAPT_INPUT_DOMAIN = 0x01, + ADAPT_CHANNEL_COUNT = 0x02, + ADAPT_BUFFER_SIZE = 0x04, + + ADAPT_ALL_SAFE = 0x03, + + ADAPT_ALL = 0xff + }; + + /** + * Load a Vamp plugin, given its identifying key. If the plugin + * could not be loaded, returns 0. + * + * The returned plugin should be deleted (using the standard C++ + * delete keyword) after use. + * + * \param adapterFlags a bitwise OR of the values in the 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. Otherwise, the returned plugin + * may be of an adapter class type which will behave identically + * to the original plugin, apart from any particular features + * implemented by the adapter itself. + * + * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter + */ + Plugin *loadPlugin(PluginKey key, + float inputSampleRate, + int adapterFlags = 0); + + /** + * Given a Vamp plugin library name and plugin identifier, return + * the corresponding plugin key in a form suitable for passing in to + * loadPlugin(). + */ + PluginKey composePluginKey(std::string libraryName, + std::string identifier); + + /** + * Return the category hierarchy for a Vamp plugin, given its + * identifying key. + * + * If the plugin has no category information, return an empty + * hierarchy. + * + * \see PluginCategoryHierarchy + */ + PluginCategoryHierarchy getPluginCategory(PluginKey plugin); + + /** + * Return the file path of the dynamic library from which the + * given plugin will be loaded (if available). + */ + std::string getLibraryPathForPlugin(PluginKey plugin); + +protected: + PluginLoader(); + virtual ~PluginLoader(); + + class Impl; + Impl *m_impl; + + static PluginLoader *m_instance; +}; + +} + +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginSummarisingAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,125 @@ +/* -*- 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-2008 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_SUMMARISING_ADAPTER_H_ +#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_ + +#include "PluginWrapper.h" + +#include <set> + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-hostsdk/PluginSummarisingAdapter.h> + * + * \note This class was introduced in version 2.0 of the Vamp plugin SDK. + */ + +class PluginSummarisingAdapter : public PluginWrapper +{ +public: + PluginSummarisingAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginSummarisingAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet getRemainingFeatures(); + + typedef std::set<RealTime> SegmentBoundaries; + void setSummarySegmentBoundaries(const SegmentBoundaries &); + + enum SummaryType { + Minimum = 0, + Maximum = 1, + Mean = 2, + Median = 3, + Mode = 4, + Sum = 5, + Variance = 6, + StandardDeviation = 7, + Count = 8, + + UnknownSummaryType = 999 + }; + + /** + * AveragingMethod indicates how the adapter should handle + * average-based summaries of features whose results are not + * equally spaced in time. + * + * If SampleAverage is specified, summary types based on averages + * will be calculated by treating each result individually without + * regard to its time: for example, the mean will be the sum of + * all values divided by the number of values. + * + * If ContinuousTimeAverage is specified, each feature will be + * considered to have a duration, either as specified in the + * feature's duration field, or until the following feature: thus, + * for example, the mean will be the sum of the products of values + * and durations, divided by the total duration. + * + * Although SampleAverage is useful for many types of feature, + * ContinuousTimeAverage is essential for some situations, for + * example finding the result that spans the largest proportion of + * the input given a feature that emits a new result only when the + * value changes (the modal value integrated over time). + */ + enum AveragingMethod { + SampleAverage = 0, + ContinuousTimeAverage = 1, + }; + + FeatureList getSummaryForOutput(int output, + SummaryType type, + AveragingMethod method = SampleAverage); + + FeatureSet getSummaryForAllOutputs(SummaryType type, + AveragingMethod method = SampleAverage); + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginWrapper.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,130 @@ +/* -*- 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-2007 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_WRAPPER_H_ +#define _VAMP_PLUGIN_WRAPPER_H_ + +#include <vamp-hostsdk/Plugin.h> + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginWrapper PluginWrapper.h <vamp-hostsdk/PluginWrapper.h> + * + * PluginWrapper is a simple base class for adapter plugins. It takes + * a pointer to a "to be wrapped" Vamp plugin on construction, and + * provides implementations of all the Vamp plugin methods that simply + * delegate through to the wrapped plugin. A subclass can therefore + * override only the methods that are meaningful for the particular + * adapter. + * + * \note This class was introduced in version 1.1 of the Vamp plugin SDK. + */ + +class PluginWrapper : public Plugin +{ +public: + virtual ~PluginWrapper(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const; + + unsigned int getVampApiVersion() const; + std::string getIdentifier() const; + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + ParameterList getParameterDescriptors() const; + float getParameter(std::string) const; + void setParameter(std::string, float); + + ProgramList getPrograms() const; + std::string getCurrentProgram() const; + void selectProgram(std::string); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + size_t getMinChannelCount() const; + size_t getMaxChannelCount() const; + + OutputList getOutputDescriptors() const; + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + + FeatureSet getRemainingFeatures(); + + /** + * Return a pointer to the plugin wrapper of type WrapperType + * surrounding this wrapper's plugin, if present. + * + * This is useful in situations where a plugin is wrapped by + * multiple different wrappers (one inside another) and the host + * wants to call some wrapper-specific function on one of the + * layers without having to care about the order in which they are + * wrapped. For example, the plugin returned by + * PluginLoader::loadPlugin may have more than one wrapper; if the + * host wanted to query or fine-tune some property of one of them, + * it would be hard to do so without knowing the order of the + * wrappers. This function therefore gives direct access to the + * wrapper of a particular type. + */ + template <typename WrapperType> + WrapperType *getWrapper() { + WrapperType *w = dynamic_cast<WrapperType *>(this); + if (w) return w; + PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin); + if (pw) return pw->getWrapper<WrapperType>(); + return 0; + } + +protected: + PluginWrapper(Plugin *plugin); // I take ownership of plugin + Plugin *m_plugin; +}; + +} + +} + +#endif
--- a/vamp-hostsdk/hostext/PluginBufferingAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* -*- 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-2007 Chris Cannam and QMUL. - This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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_BUFFERING_ADAPTER_H_ -#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_ - -#include "PluginWrapper.h" - -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-sdk/hostext/PluginBufferingAdapter.h> - * - * PluginBufferingAdapter is a Vamp plugin adapter that allows plugins - * to be used by a host supplying an audio stream in non-overlapping - * buffers of arbitrary size. - * - * A host using PluginBufferingAdapter may ignore the preferred step - * and block size reported by the plugin, and still expect the plugin - * to run. The value of blockSize and stepSize passed to initialise - * should be the size of the buffer which the host will supply; the - * stepSize should be equal to the blockSize. - * - * If the internal step size used for the plugin differs from that - * supplied by the host, the adapter will modify the sample type and - * rate specifications for the plugin outputs appropriately, and set - * timestamps on the output features for outputs that formerly used a - * different sample rate specification. This is necessary in order to - * obtain correct time stamping. - * - * In other respects, the PluginBufferingAdapter behaves identically - * to the plugin that it wraps. The wrapped plugin will be deleted - * when the wrapper is deleted. - */ - -class PluginBufferingAdapter : public PluginWrapper -{ -public: - PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin - virtual ~PluginBufferingAdapter(); - - /** - * Return the preferred step size for this adapter. - * - * Because of the way this adapter works, its preferred step size - * will always be the same as its preferred block size. This may - * or may not be the same as the preferred step size of the - * underlying plugin, which may be obtained by calling - * getPluginPreferredStepSize(). - */ - size_t getPreferredStepSize() const; - - /** - * Return the preferred block size for this adapter. - * - * This may or may not be the same as the preferred block size of - * the underlying plugin, which may be obtained by calling - * getPluginPreferredBlockSize(). - * - * Note that this adapter may be initialised with any block size, - * not just its supposedly preferred one. - */ - size_t getPreferredBlockSize() const; - - /** - * Initialise the adapter (and therefore the plugin) for the given - * number of channels. Initialise the adapter for the given step - * and block size, which must be equal. - * - * The step and block size used for the underlying plugin will - * depend on its preferences, or any values previously passed to - * setPluginStepSize and setPluginBlockSize. - */ - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - /** - * Return the preferred step size of the plugin wrapped by this - * adapter. - * - * This is included mainly for informational purposes. This value - * is not likely to be a valid step size for the adapter itself, - * and it is not usually of any use in interpreting the results - * (because the adapter re-writes OneSamplePerStep outputs to - * FixedSampleRate so that the hop size no longer needs to be - * known beforehand in order to interpret them). - */ - size_t getPluginPreferredStepSize() const; - - /** - * Return the preferred block size of the plugin wrapped by this - * adapter. - * - * This is included mainly for informational purposes. - */ - size_t getPluginPreferredBlockSize() const; - - /** - * Set the step size that will be used for the underlying plugin - * when initialise() is called. If this is not set, the plugin's - * own preferred step size will be used. You will not usually - * need to call this function. If you do call it, it must be - * before the first call to initialise(). - */ - void setPluginStepSize(size_t stepSize); - - /** - * Set the block size that will be used for the underlying plugin - * when initialise() is called. If this is not set, the plugin's - * own preferred block size will be used. You will not usually - * need to call this function. If you do call it, it must be - * before the first call to initialise(). - */ - void setPluginBlockSize(size_t blockSize); - - /** - * Return the step and block sizes that were actually used when - * initialising the underlying plugin. - * - * This is included mainly for informational purposes. You will - * not usually need to call this function. If this is called - * before initialise(), it will return 0 for both values. If it - * is called after a failed call to initialise(), it will return - * the values that were used in the failed call to the plugin's - * initialise() function. - */ - void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - - OutputList getOutputDescriptors() const; - - void reset(); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - FeatureSet getRemainingFeatures(); - -protected: - class Impl; - Impl *m_impl; -}; - -} - -} - -#endif
--- a/vamp-hostsdk/hostext/PluginChannelAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* -*- 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-2007 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_CHANNEL_ADAPTER_H_ -#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_ - -#include "PluginWrapper.h" - -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginChannelAdapter PluginChannelAdapter.h <vamp-sdk/hostext/PluginChannelAdapter.h> - * - * PluginChannelAdapter is a Vamp plugin adapter that implements a - * policy for management of plugins that expect a different number of - * input channels from the number actually available in the source - * audio data. - * - * A host using PluginChannelAdapter may ignore the getMinChannelCount - * and getMaxChannelCount reported by the plugin, and still expect the - * plugin to run. - * - * PluginChannelAdapter implements the following policy: - * - * - If the plugin supports the provided number of channels directly, - * PluginChannelAdapter will just run the plugin as normal. - * - * - If the plugin only supports exactly one channel but more than - * one channel is provided, PluginChannelAdapter will use the mean of - * the channels. This ensures that the resulting values remain - * within the same magnitude range as expected for mono data. - * - * - If the plugin requires more than one channel but exactly one is - * provided, the provided channel will be duplicated across all the - * plugin input channels. - * - * If none of the above apply: - * - * - If the plugin requires more channels than are provided, the - * minimum acceptable number of channels will be produced by adding - * empty (zero valued) channels to those provided. - * - * - If the plugin requires fewer channels than are provided, the - * maximum acceptable number of channels will be produced by - * discarding the excess channels. - * - * Hosts requiring a different channel policy from the above will need - * to implement it themselves, instead of using PluginChannelAdapter. - * - * Note that PluginChannelAdapter does not override the minimum and - * maximum channel counts returned by the wrapped plugin. The host - * will need to be aware that it is using a PluginChannelAdapter, and - * be prepared to ignore these counts as necessary. (This contrasts - * with the approach used in PluginInputDomainAdapter, which aims to - * make the host completely unaware of which underlying input domain - * is in fact in use.) - * - * (The rationale for this is that a host may wish to use the - * PluginChannelAdapter but still discriminate in some way on the - * basis of the number of channels actually supported. For example, a - * simple stereo audio host may prefer to reject plugins that require - * more than two channels on the grounds that doesn't actually - * understand what they are for, rather than allow the channel adapter - * to make a potentially meaningless channel conversion for them.) - * - * In every respect other than its management of channels, the - * PluginChannelAdapter behaves identically to the plugin that it - * wraps. The wrapped plugin will be deleted when the wrapper is - * deleted. - * - * \note This class was introduced in version 1.1 of the Vamp plugin SDK. - */ - -class PluginChannelAdapter : public PluginWrapper -{ -public: - PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin - virtual ~PluginChannelAdapter(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - /** - * Call process(), providing interleaved audio data with the - * number of channels passed to initialise(). The adapter will - * de-interleave into temporary buffers as appropriate before - * calling process(). - * - * \note This function was introduced in version 1.4 of the Vamp - * plugin SDK. - */ - FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp); - -protected: - class Impl; - Impl *m_impl; -}; - -} - -} - -#endif
--- a/vamp-hostsdk/hostext/PluginInputDomainAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* -*- 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-2007 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_INPUT_DOMAIN_ADAPTER_H_ -#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_ - -#include "PluginWrapper.h" - -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-sdk/hostext/PluginInputDomainAdapter.h> - * - * PluginInputDomainAdapter is a Vamp plugin adapter that converts - * time-domain input into frequency-domain input for plugins that need - * it. This permits a host to use time- and frequency-domain plugins - * interchangeably without needing to handle the conversion itself. - * - * This adapter uses a basic Hanning windowed FFT that supports - * power-of-two block sizes only. If a frequency domain plugin - * requests a non-power-of-two blocksize, the adapter will adjust it - * to a nearby power of two instead. Thus, getPreferredBlockSize() - * will always return a power of two if the wrapped plugin is a - * frequency domain one. If the plugin doesn't accept the adjusted - * power of two block size, initialise() will fail. - * - * The adapter provides no way for the host to discover whether the - * underlying plugin is actually a time or frequency domain plugin - * (except that if the preferred block size is not a power of two, it - * must be a time domain plugin). - * - * The FFT implementation is simple and self-contained, but unlikely - * to be the fastest available: a host can usually do better if it - * cares enough. - * - * In every respect other than its input domain handling, the - * PluginInputDomainAdapter behaves identically to the plugin that it - * wraps. The wrapped plugin will be deleted when the wrapper is - * deleted. - * - * \note This class was introduced in version 1.1 of the Vamp plugin SDK. - */ - -class PluginInputDomainAdapter : public PluginWrapper -{ -public: - PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin - virtual ~PluginInputDomainAdapter(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - InputDomain getInputDomain() const; - - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - /** - * Return the amount by which the timestamps supplied to process() - * are being incremented when they are passed to the plugin's own - * process() implementation. - * - * The Vamp API mandates that the timestamp passed to the plugin - * for time-domain input should be the time of the first sample in - * the block, but the timestamp passed for frequency-domain input - * should be the timestamp of the centre of the block. - * - * The PluginInputDomainAdapter adjusts its timestamps properly so - * that the plugin receives correct times, but in some - * circumstances (such as for establishing the correct timing of - * implicitly-timed features, i.e. features without their own - * timestamps) the host may need to be aware that this adjustment - * is taking place. - * - * If the plugin requires time-domain input, this function will - * return zero. The result of calling this function before - * initialise() has been called is undefined. - */ - RealTime getTimestampAdjustment() const; - -protected: - class Impl; - Impl *m_impl; -}; - -} - -} - -#endif
--- a/vamp-hostsdk/hostext/PluginLoader.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* -*- 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-2007 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_LOADER_H_ -#define _VAMP_PLUGIN_LOADER_H_ - -#include <vector> -#include <string> -#include <map> - -#include "PluginWrapper.h" - -namespace Vamp { - -class Plugin; - -namespace HostExt { - -/** - * \class PluginLoader PluginLoader.h <vamp-sdk/hostext/PluginLoader.h> - * - * Vamp::HostExt::PluginLoader is a convenience class for discovering - * and loading Vamp plugins using the typical plugin-path, library - * naming, and categorisation conventions described in the Vamp SDK - * documentation. This class is intended to greatly simplify the task - * of becoming a Vamp plugin host for any C++ application. - * - * Hosts are not required by the Vamp specification to use the same - * plugin search path and naming conventions as implemented by this - * class, and are certainly not required to use this actual class. - * But we do strongly recommend it. - * - * \note This class was introduced in version 1.1 of the Vamp plugin SDK. - */ - -class PluginLoader -{ -public: - /** - * Obtain a pointer to the singleton instance of PluginLoader. - * Use this to obtain your loader object. - */ - static PluginLoader *getInstance(); - - /** - * PluginKey is a string type that is used to identify a plugin - * uniquely within the scope of "the current system". It consists - * of the lower-cased base name of the plugin library, a colon - * separator, and the identifier string for the plugin. It is - * only meaningful in the context of a given plugin path (the one - * returned by PluginHostAdapter::getPluginPath()). - * - * Use composePluginKey() to construct a plugin key from a known - * plugin library name and identifier. - * - * Note: the fact that the library component of the key is - * lower-cased implies that library names are matched - * case-insensitively by the PluginLoader class, regardless of the - * case sensitivity of the underlying filesystem. (Plugin - * identifiers _are_ case sensitive, however.) Also, it is not - * possible to portably extract a working library name from a - * plugin key, as the result may fail on case-sensitive - * filesystems. Use getLibraryPathForPlugin() instead. - */ - typedef std::string PluginKey; - - /** - * PluginKeyList is a sequence of plugin keys, such as returned by - * listPlugins(). - */ - typedef std::vector<PluginKey> PluginKeyList; - - /** - * PluginCategoryHierarchy is a sequence of general->specific - * category names, as may be associated with a single plugin. - * This sequence describes the location of a plugin within a - * category forest, containing the human-readable names of the - * plugin's category tree root, followed by each of the nodes down - * to the leaf containing the plugin. - * - * \see getPluginCategory() - */ - typedef std::vector<std::string> PluginCategoryHierarchy; - - /** - * Search for all available Vamp plugins, and return a list of - * them in the order in which they were found. - */ - PluginKeyList listPlugins(); - - /** - * 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 - * does not want to cater for complex features. - * - * The available flags are: - * - * ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain - * input, wrap it in a PluginInputDomainAdapter that automatically - * converts the plugin to one that expects time-domain input. - * This enables a host to accommodate time- and frequency-domain - * plugins without needing to do any conversion itself. - * - * ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter - * to handle any mismatch between the number of channels of audio - * the plugin can handle and the number available in the host. - * This enables a host to use plugins that may require the input - * to be mixed down to mono, etc., without having to worry about - * doing that itself. - * - * ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter - * permitting the host to provide audio input using any block - * size, with no overlap, regardless of the plugin's preferred - * block size (suitable for hosts that read from non-seekable - * streaming media, for example). This adapter introduces some - * run-time overhead and also changes the semantics of the plugin - * slightly (see the PluginBufferingAdapter header documentation - * for details). - * - * ADAPT_ALL_SAFE - Perform all available adaptations that are - * meaningful for the plugin and "safe". Currently this means to - * ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input; - * ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never. - * - * ADAPT_ALL - Perform all available adaptations that are - * meaningful for the plugin. - * - * See PluginInputDomainAdapter, PluginChannelAdapter and - * PluginBufferingAdapter for more details of the classes that the - * loader may use if these flags are set. - */ - enum AdapterFlags { - - ADAPT_INPUT_DOMAIN = 0x01, - ADAPT_CHANNEL_COUNT = 0x02, - ADAPT_BUFFER_SIZE = 0x04, - - ADAPT_ALL_SAFE = 0x03, - - ADAPT_ALL = 0xff - }; - - /** - * Load a Vamp plugin, given its identifying key. If the plugin - * could not be loaded, returns 0. - * - * The returned plugin should be deleted (using the standard C++ - * delete keyword) after use. - * - * \param adapterFlags a bitwise OR of the values in the 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. Otherwise, the returned plugin - * may be of an adapter class type which will behave identically - * to the original plugin, apart from any particular features - * implemented by the adapter itself. - * - * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter - */ - Plugin *loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags = 0); - - /** - * Given a Vamp plugin library name and plugin identifier, return - * the corresponding plugin key in a form suitable for passing in to - * loadPlugin(). - */ - PluginKey composePluginKey(std::string libraryName, - std::string identifier); - - /** - * Return the category hierarchy for a Vamp plugin, given its - * identifying key. - * - * If the plugin has no category information, return an empty - * hierarchy. - * - * \see PluginCategoryHierarchy - */ - PluginCategoryHierarchy getPluginCategory(PluginKey plugin); - - /** - * Return the file path of the dynamic library from which the - * given plugin will be loaded (if available). - */ - std::string getLibraryPathForPlugin(PluginKey plugin); - -protected: - PluginLoader(); - virtual ~PluginLoader(); - - class Impl; - Impl *m_impl; - - static PluginLoader *m_instance; -}; - -} - -} - -#endif -
--- a/vamp-hostsdk/hostext/PluginSummarisingAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* -*- 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-2008 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_SUMMARISING_ADAPTER_H_ -#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_ - -#include "PluginWrapper.h" - -#include <set> - -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-sdk/hostext/PluginSummarisingAdapter.h> - * - * \note This class was introduced in version 2.0 of the Vamp plugin SDK. - */ - -class PluginSummarisingAdapter : public PluginWrapper -{ -public: - PluginSummarisingAdapter(Plugin *plugin); // I take ownership of plugin - virtual ~PluginSummarisingAdapter(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet getRemainingFeatures(); - - typedef std::set<RealTime> SegmentBoundaries; - void setSummarySegmentBoundaries(const SegmentBoundaries &); - - enum SummaryType { - Minimum = 0, - Maximum = 1, - Mean = 2, - Median = 3, - Mode = 4, - Sum = 5, - Variance = 6, - StandardDeviation = 7, - Count = 8, - - UnknownSummaryType = 999 - }; - - /** - * AveragingMethod indicates how the adapter should handle - * average-based summaries of features whose results are not - * equally spaced in time. - * - * If SampleAverage is specified, summary types based on averages - * will be calculated by treating each result individually without - * regard to its time: for example, the mean will be the sum of - * all values divided by the number of values. - * - * If ContinuousTimeAverage is specified, each feature will be - * considered to have a duration, either as specified in the - * feature's duration field, or until the following feature: thus, - * for example, the mean will be the sum of the products of values - * and durations, divided by the total duration. - * - * Although SampleAverage is useful for many types of feature, - * ContinuousTimeAverage is essential for some situations, for - * example finding the result that spans the largest proportion of - * the input given a feature that emits a new result only when the - * value changes (the modal value integrated over time). - */ - enum AveragingMethod { - SampleAverage = 0, - ContinuousTimeAverage = 1, - }; - - FeatureList getSummaryForOutput(int output, - SummaryType type, - AveragingMethod method = SampleAverage); - - FeatureSet getSummaryForAllOutputs(SummaryType type, - AveragingMethod method = SampleAverage); - -protected: - class Impl; - Impl *m_impl; -}; - -} - -} - -#endif
--- a/vamp-hostsdk/hostext/PluginWrapper.h Fri Nov 07 14:33:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* -*- 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-2007 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_WRAPPER_H_ -#define _VAMP_PLUGIN_WRAPPER_H_ - -#include <vamp-hostsdk/Plugin.h> - -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginWrapper PluginWrapper.h <vamp-sdk/hostext/PluginWrapper.h> - * - * PluginWrapper is a simple base class for adapter plugins. It takes - * a pointer to a "to be wrapped" Vamp plugin on construction, and - * provides implementations of all the Vamp plugin methods that simply - * delegate through to the wrapped plugin. A subclass can therefore - * override only the methods that are meaningful for the particular - * adapter. - * - * \note This class was introduced in version 1.1 of the Vamp plugin SDK. - */ - -class PluginWrapper : public Plugin -{ -public: - virtual ~PluginWrapper(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); - - InputDomain getInputDomain() const; - - unsigned int getVampApiVersion() const; - std::string getIdentifier() const; - std::string getName() const; - std::string getDescription() const; - std::string getMaker() const; - int getPluginVersion() const; - std::string getCopyright() const; - - ParameterList getParameterDescriptors() const; - float getParameter(std::string) const; - void setParameter(std::string, float); - - ProgramList getPrograms() const; - std::string getCurrentProgram() const; - void selectProgram(std::string); - - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; - - size_t getMinChannelCount() const; - size_t getMaxChannelCount() const; - - OutputList getOutputDescriptors() const; - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - FeatureSet getRemainingFeatures(); - - /** - * Return a pointer to the plugin wrapper of type WrapperType - * surrounding this wrapper's plugin, if present. - * - * This is useful in situations where a plugin is wrapped by - * multiple different wrappers (one inside another) and the host - * wants to call some wrapper-specific function on one of the - * layers without having to care about the order in which they are - * wrapped. For example, the plugin returned by - * PluginLoader::loadPlugin may have more than one wrapper; if the - * host wanted to query or fine-tune some property of one of them, - * it would be hard to do so without knowing the order of the - * wrappers. This function therefore gives direct access to the - * wrapper of a particular type. - */ - template <typename WrapperType> - WrapperType *getWrapper() { - WrapperType *w = dynamic_cast<WrapperType *>(this); - if (w) return w; - PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin); - if (pw) return pw->getWrapper<WrapperType>(); - return 0; - } - -protected: - PluginWrapper(Plugin *plugin); // I take ownership of plugin - Plugin *m_plugin; -}; - -} - -} - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/vamp-hostsdk.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,53 @@ +/* -*- 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 Chris Cannam. + + 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_HOSTSDK_SINGLE_INCLUDE_H_ +#define _VAMP_HOSTSDK_SINGLE_INCLUDE_H_ + +#include "PluginBase.h" +#include "PluginBufferingAdapter.h" +#include "PluginChannelAdapter.h" +#include "Plugin.h" +#include "PluginHostAdapter.h" +#include "PluginInputDomainAdapter.h" +#include "PluginLoader.h" +#include "PluginSummarisingAdapter.h" +#include "PluginWrapper.h" +#include "RealTime.h" + +#endif + +
--- a/vamp-sdk/Plugin.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-sdk/Plugin.h Fri Nov 07 15:28:33 2008 +0000 @@ -45,7 +45,7 @@ #include "RealTime.h" #include "plugguard.h" -_VAMP_SDK_HEADER_BEGIN(Plugin.h) +_VAMP_SDK_PLUGSPACE_BEGIN(Plugin.h) namespace Vamp { @@ -433,7 +433,7 @@ } -_VAMP_SDK_HEADER_END(Plugin.h) +_VAMP_SDK_PLUGSPACE_END(Plugin.h) #endif
--- a/vamp-sdk/PluginAdapter.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-sdk/PluginAdapter.h Fri Nov 07 15:28:33 2008 +0000 @@ -43,7 +43,7 @@ #include "Plugin.h" #include "plugguard.h" -_VAMP_SDK_HEADER_BEGIN(PluginAdapter.h) +_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.h) namespace Vamp { @@ -115,7 +115,7 @@ } -_VAMP_SDK_HEADER_END(PluginAdapter.h) +_VAMP_SDK_PLUGSPACE_END(PluginAdapter.h) #endif
--- a/vamp-sdk/PluginBase.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-sdk/PluginBase.h Fri Nov 07 15:28:33 2008 +0000 @@ -41,7 +41,7 @@ #include <vector> #include "plugguard.h" -_VAMP_SDK_HEADER_BEGIN(PluginBase.h) +_VAMP_SDK_PLUGSPACE_BEGIN(PluginBase.h) namespace Vamp { @@ -253,6 +253,6 @@ } -_VAMP_SDK_HEADER_END(PluginBase.h) +_VAMP_SDK_PLUGSPACE_END(PluginBase.h) #endif
--- a/vamp-sdk/RealTime.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-sdk/RealTime.h Fri Nov 07 15:28:33 2008 +0000 @@ -52,7 +52,7 @@ #endif #include "plugguard.h" -_VAMP_SDK_HEADER_BEGIN(RealTime.h) +_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.h) namespace Vamp { @@ -162,6 +162,6 @@ } -_VAMP_SDK_HEADER_END(RealTime.h) +_VAMP_SDK_PLUGSPACE_END(RealTime.h) #endif
--- a/vamp-sdk/plugguard.h Fri Nov 07 14:33:21 2008 +0000 +++ b/vamp-sdk/plugguard.h Fri Nov 07 15:28:33 2008 +0000 @@ -50,8 +50,8 @@ * with non-plugin class implementations in the host on load. * * - Hosts include vamp-hostsdk/Plugin.h, vamp-hostsdk/PluginBase.h, - * vamp-hostsdk/PluginHostAdapter, vamp-hostsdk/hostext/<x>.h etc. - * These files include vamp-hostsdk/guards.h, which makes a note + * vamp-hostsdk/PluginHostAdapter, vamp-hostsdk/PluginLoader.h etc. + * These files include vamp-hostsdk/hostguard.h, which makes a note * that we are in a host. A file such as vamp-hostsdk/Plugin.h * then simply includes vamp-sdk/Plugin.h, and this guard header * takes notice of the fact that it has been included from a host @@ -73,19 +73,24 @@ #ifdef _VAMP_IN_HOSTSDK -#define _VAMP_SDK_HEADER_BEGIN(h) -#define _VAMP_SDK_HEADER_END(h) +#define _VAMP_SDK_PLUGSPACE_BEGIN(h) +#define _VAMP_SDK_PLUGSPACE_END(h) #else #define _VAMP_IN_PLUGINSDK -#define _VAMP_SDK_HEADER_BEGIN(h) \ +#ifdef _VAMP_NO_PLUGIN_NAMESPACE +#define _VAMP_SDK_PLUGSPACE_BEGIN(h) +#define _VAMP_SDK_PLUGSPACE_END(h) +#else +#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \ namespace _VampPlugin { -#define _VAMP_SDK_HEADER_END(h) \ +#define _VAMP_SDK_PLUGSPACE_END(h) \ } \ using namespace _VampPlugin; +#endif #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-sdk/vamp-sdk.h Fri Nov 07 15:28:33 2008 +0000 @@ -0,0 +1,46 @@ +/* -*- 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 Chris Cannam. + + 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_SDK_SINGLE_INCLUDE_H_ +#define _VAMP_SDK_SINGLE_INCLUDE_H_ + +#include "PluginBase.h" +#include "Plugin.h" +#include "RealTime.h" + +#endif + +