bringing vamp-sdk into 2.0-ongoing branch

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2867 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2008-01-10 13:47:50 +00:00
parent b3e24ac78f
commit 051d64131f
39 changed files with 8747 additions and 0 deletions

26
libs/vamp-sdk/COPYING Normal file
View file

@ -0,0 +1,26 @@
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 X CONSORTIUM 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.

1235
libs/vamp-sdk/Doxyfile Normal file

File diff suppressed because it is too large Load diff

249
libs/vamp-sdk/Makefile Normal file
View file

@ -0,0 +1,249 @@
# Makefile for the Vamp plugin SDK. This builds the SDK objects,
# libraries, example plugins, and the test host. Please adjust to
# suit your operating system requirements.
APIDIR = vamp
SDKDIR = vamp-sdk
HOSTEXTDIR = vamp-sdk/hostext
EXAMPLEDIR = examples
HOSTDIR = host
###
### Start of user-serviceable parts
###
# Default build target (or use "make <target>" to select one).
# Targets are:
# all -- build everything
# sdk -- build all the Vamp SDK libraries for plugins and hosts
# sdkstatic -- build only the static versions of the SDK libraries
# plugins -- build the example plugins (and the SDK if required)
# host -- build the simple Vamp plugin host (and the SDK if required)
# test -- build the host and example plugins, and run a quick test
# clean -- remove binary targets
# distclean -- remove all targets
#
default: all
# Compile flags
#
CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I. -fpic
# ar, ranlib
#
AR := ar
RANLIB := ranlib
# Libraries required for the plugins.
# (Note that it is desirable to statically link libstdc++ if possible,
# because our plugin exposes only a C API so there are no boundary
# compatibility problems.)
#
PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a
#PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a $(shell g++ -print-file-name=libstdc++.a)
# File extension for a dynamically loadable object
#
PLUGIN_EXT = .so
#PLUGIN_EXT = .dll
#PLUGIN_EXT = .dylib
# Libraries required for the host.
#
HOST_LIBS = $(SDKDIR)/libvamp-hostsdk.a -lsndfile -ldl
# Locations for "make install". This will need quite a bit of
# editing for non-Linux platforms. Of course you don't necessarily
# have to use "make install".
#
INSTALL_PREFIX := /usr
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_SDK_LIBS := $(INSTALL_PREFIX)/lib
INSTALL_SDK_LIBNAME := libvamp-sdk.so.1.1.0
INSTALL_SDK_LINK_ABI := libvamp-sdk.so.1
INSTALL_SDK_LINK_DEV := libvamp-sdk.so
INSTALL_SDK_STATIC := libvamp-sdk.a
INSTALL_SDK_LA := libvamp-sdk.la
INSTALL_HOSTSDK_LIBNAME := libvamp-hostsdk.so.2.0.0
INSTALL_HOSTSDK_LINK_ABI := libvamp-hostsdk.so.2
INSTALL_HOSTSDK_LINK_DEV := libvamp-hostsdk.so
INSTALL_HOSTSDK_STATIC := libvamp-hostsdk.a
INSTALL_HOSTSDK_LA := libvamp-hostsdk.la
INSTALL_PKGCONFIG := $(INSTALL_PREFIX)/lib/pkgconfig
# Flags required to tell the compiler to create a dynamically loadable object
#
DYNAMIC_LDFLAGS = -shared -Wl,-Bsymbolic
PLUGIN_LDFLAGS = $(DYNAMIC_LDFLAGS)
SDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_SDK_LIBNAME)
HOSTSDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_HOSTSDK_LIBNAME)
## For OS/X with g++:
#PLUGIN_LDFLAGS = -dynamiclib
### End of user-serviceable parts
API_HEADERS = \
$(APIDIR)/vamp.h
SDK_HEADERS = \
$(SDKDIR)/Plugin.h \
$(SDKDIR)/PluginAdapter.h \
$(SDKDIR)/PluginBase.h \
$(SDKDIR)/RealTime.h
HOSTSDK_HEADERS = \
$(SDKDIR)/Plugin.h \
$(SDKDIR)/PluginBase.h \
$(SDKDIR)/PluginHostAdapter.h \
$(SDKDIR)/RealTime.h
HOSTEXT_HEADERS = \
$(HOSTEXTDIR)/PluginChannelAdapter.h \
$(HOSTEXTDIR)/PluginInputDomainAdapter.h \
$(HOSTEXTDIR)/PluginLoader.h \
$(HOSTEXTDIR)/PluginWrapper.h
SDK_OBJECTS = \
$(SDKDIR)/PluginAdapter.o \
$(SDKDIR)/RealTime.o
HOSTSDK_OBJECTS = \
$(SDKDIR)/PluginHostAdapter.o \
$(HOSTEXTDIR)/PluginChannelAdapter.o \
$(HOSTEXTDIR)/PluginInputDomainAdapter.o \
$(HOSTEXTDIR)/PluginLoader.o \
$(HOSTEXTDIR)/PluginWrapper.o \
$(SDKDIR)/RealTime.o
SDK_STATIC = \
$(SDKDIR)/libvamp-sdk.a
HOSTSDK_STATIC = \
$(SDKDIR)/libvamp-hostsdk.a
SDK_DYNAMIC = \
$(SDKDIR)/libvamp-sdk.so
HOSTSDK_DYNAMIC = \
$(SDKDIR)/libvamp-hostsdk.so
SDK_LA = \
$(SDKDIR)/libvamp-sdk.la
HOSTSDK_LA = \
$(SDKDIR)/libvamp-hostsdk.la
PLUGIN_HEADERS = \
$(EXAMPLEDIR)/SpectralCentroid.h \
$(EXAMPLEDIR)/PercussionOnsetDetector.h \
$(EXAMPLEDIR)/AmplitudeFollower.h \
$(EXAMPLEDIR)/ZeroCrossing.h
PLUGIN_OBJECTS = \
$(EXAMPLEDIR)/SpectralCentroid.o \
$(EXAMPLEDIR)/PercussionOnsetDetector.o \
$(EXAMPLEDIR)/AmplitudeFollower.o \
$(EXAMPLEDIR)/ZeroCrossing.o \
$(EXAMPLEDIR)/plugins.o
PLUGIN_TARGET = \
$(EXAMPLEDIR)/vamp-example-plugins$(PLUGIN_EXT)
HOST_HEADERS = \
$(HOSTDIR)/system.h
HOST_OBJECTS = \
$(HOSTDIR)/vamp-simple-host.o
HOST_TARGET = \
$(HOSTDIR)/vamp-simple-host
sdk: sdkstatic $(SDK_DYNAMIC) $(HOSTSDK_DYNAMIC)
sdkstatic: $(SDK_STATIC) $(HOSTSDK_STATIC)
$(RANLIB) $(SDK_STATIC)
$(RANLIB) $(HOSTSDK_STATIC)
plugins: $(PLUGIN_TARGET)
host: $(HOST_TARGET)
all: sdk plugins host test
$(SDK_STATIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS)
$(AR) r $@ $(SDK_OBJECTS)
$(HOSTSDK_STATIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_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)
$(CXX) $(LDFLAGS) $(HOSTSDK_DYNAMIC_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS)
$(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS)
$(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(PLUGIN_OBJECTS) $(PLUGIN_LIBS)
$(HOST_TARGET): $(HOST_OBJECTS) $(HOSTSDK_STATIC) $(HOST_HEADERS)
$(CXX) $(LDFLAGS) $(HOST_LDFLAGS) -o $@ $(HOST_OBJECTS) $(HOST_LIBS)
test: plugins host
VAMP_PATH=$(EXAMPLEDIR) $(HOST_TARGET) -l
clean:
rm -f $(SDK_OBJECTS) $(HOSTSDK_OBJECTS) $(PLUGIN_OBJECTS) $(HOST_OBJECTS)
distclean: clean
rm -f $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) *~ */*~
install: $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET)
mkdir -p $(INSTALL_API_HEADERS)
mkdir -p $(INSTALL_SDK_HEADERS)
mkdir -p $(INSTALL_HOSTEXT_HEADERS)
mkdir -p $(INSTALL_SDK_LIBS)
mkdir -p $(INSTALL_PKGCONFIG)
cp $(API_HEADERS) $(INSTALL_API_HEADERS)
cp $(SDK_HEADERS) $(INSTALL_SDK_HEADERS)
cp $(HOSTSDK_HEADERS) $(INSTALL_SDK_HEADERS)
cp $(HOSTEXT_HEADERS) $(INSTALL_HOSTEXT_HEADERS)
cp $(SDK_STATIC) $(INSTALL_SDK_LIBS)
cp $(HOSTSDK_STATIC) $(INSTALL_SDK_LIBS)
cp $(SDK_DYNAMIC) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LIBNAME)
cp $(HOSTSDK_DYNAMIC) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LIBNAME)
rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI)
ln -s $(INSTALL_SDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI)
rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI)
ln -s $(INSTALL_HOSTSDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI)
rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV)
ln -s $(INSTALL_SDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV)
rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV)
ln -s $(INSTALL_HOSTSDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV)
sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(APIDIR)/vamp.pc.in \
> $(INSTALL_PKGCONFIG)/vamp.pc
sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-sdk.pc.in \
> $(INSTALL_PKGCONFIG)/vamp-sdk.pc
sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-hostsdk.pc.in \
> $(INSTALL_PKGCONFIG)/vamp-hostsdk.pc
sed -e "s,%LIBNAME%,$(INSTALL_SDK_LIBNAME),g" \
-e "s,%LINK_ABI%,$(INSTALL_SDK_LINK_ABI),g" \
-e "s,%LINK_DEV%,$(INSTALL_SDK_LINK_DEV),g" \
-e "s,%STATIC%,$(INSTALL_SDK_STATIC),g" \
-e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(SDK_LA).in \
> $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LA)
sed -e "s,%LIBNAME%,$(INSTALL_HOSTSDK_LIBNAME),g" \
-e "s,%LINK_ABI%,$(INSTALL_HOSTSDK_LINK_ABI),g" \
-e "s,%LINK_DEV%,$(INSTALL_HOSTSDK_LINK_DEV),g" \
-e "s,%STATIC%,$(INSTALL_HOSTSDK_STATIC),g" \
-e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(HOSTSDK_LA).in \
> $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LA)

240
libs/vamp-sdk/README Normal file
View file

@ -0,0 +1,240 @@
Vamp
====
An API for audio analysis and feature extraction plugins.
http://www.vamp-plugins.org/
Vamp is an API for C and C++ plugins that process sampled audio data
to produce descriptive output (measurements or semantic observations).
The principal differences between Vamp and a real-time audio
processing plugin system such as VST are:
* Vamp plugins may output complex multidimensional data with labels.
As a consequence, they are likely to work best when the output
data has a much lower sampling rate than the input. (This also
means it is usually desirable to implement them in C++ using the
high-level base class provided rather than use the raw C API.)
* While Vamp plugins receive data block-by-block, they are not
required to return output immediately on receiving the input.
A Vamp plugin may be non-causal, preferring to store up data
based on its input until the end of a processing run and then
return all results at once.
* Vamp plugins have more control over their inputs than a typical
real-time processing plugin. For example, they can indicate to
the host their preferred processing block and step sizes, and these
may differ.
* Vamp plugins may ask to receive data in the frequency domain
instead of the time domain. The host takes the responsibility
for converting the input data using an FFT of windowed frames.
This simplifies plugins that do straightforward frequency-domain
processing and permits the host to cache frequency-domain data
when possible.
* A Vamp plugin is configured once before each processing run, and
receives no further parameter changes during use -- unlike real-
time plugin APIs in which the input parameters may change at any
time. This also means that fundamental properties such as the
number of values per output or the preferred processing block
size may depend on the input parameters.
* Vamp plugins do not have to be able to run in real time.
About this SDK
==============
This is version 1.1b of the Vamp plugin Software Development Kit.
Plugins and hosts built with this SDK are binary compatible with those
built using version 1.0 of the SDK.
This SDK contains the following:
* vamp/vamp.h
The formal C language plugin API for Vamp plugins.
A Vamp plugin is a dynamic library (.so, .dll or .dylib depending on
platform) exposing one C-linkage entry point (vampGetPluginDescriptor)
which returns data defined in the rest of this C header.
Although the C API is the official API for Vamp, we don't recommend
that you program directly to it. The C++ abstraction found in the
vamp-sdk directory (below) is preferable for most purposes and is
more thoroughly documented.
* vamp-sdk
C++ classes for straightforwardly implementing Vamp plugins and hosts.
Plugins should subclass Vamp::Plugin and then use Vamp::PluginAdapter
to expose the correct C API for the plugin. Plugin authors should
read vamp-sdk/PluginBase.h and Plugin.h for code documentation, and
refer to the example plugin code in the examples directory. Plugins
should link with -lvampsdk. [*NOTE: this has changed from vamp-sdk in
previous versions, to avoid conflict with the use of hyphens for
library versioning schemes on some platforms.]
Hosts may use the Vamp::PluginHostAdapter to convert the loaded
plugin's C API back into a Vamp::Plugin object. Host authors should
refer to the example host code in the host directory. Hosts should
link with -lvamphostsdk. [*NOTE: this has changed from vamp-hostsdk
in previous versions, to avoid conflict with the use of hyphens for
library versioning schemes on some platforms.]
* vamp-sdk/hostext
Additional C++ classes to make a host's life easier (introduced in
version 1.1 of the Vamp SDK).
Vamp::HostExt::PluginLoader provides a very easy interface for a host
to discover, load, and find out category information about the
available plugins. Most "casual" Vamp hosts will probably want to use
this class.
Vamp::HostExt::PluginInputDomainAdapter provides a means for hosts to
handle plugins that expect frequency-domain input, without having to
convert the input themselves.
Vamp::HostExt::PluginChannelAdapter provides a means for hosts to use
plugins that do not necessarily support the same number of audio
channels as they have available, without having to worry about
applying a channel management / mixdown policy themselves.
The PluginLoader class can also use the input domain and channel
adapters automatically to make the entire conversion process
transparent to the host if required.
* examples
Example plugins implemented using the C++ classes. ZeroCrossing
calculates the positions and density of zero-crossing points in an
audio waveform. SpectralCentroid calculates the centre of gravity of
the frequency domain representation of each block of audio.
AmplitudeFollower tracks the amplitude of a signal based on a method
from the SuperCollider real-time audio system.
PercussionOnsetDetector estimates the locations of percussive onsets
using a simple method described in "Drum Source Separation using
Percussive Feature Detection and Spectral Modulation" by Dan Barry,
Derry Fitzgerald, Eugene Coyle and Bob Lawlor, ISSC 2005.
* host
A simple command-line Vamp host, capable of loading a plugin and using
it to process a complete audio file, with its default parameters.
Requires libsndfile (http://www.mega-nerd.com/libsndfile/).
If you don't have libsndfile, you may want to edit the Makefile to
change the default build target from "all" to "sdk", so as to compile
only the SDK and not the host.
Plugin Lookup and Categorisation
================================
The Vamp API does not officially specify how to load plugin libraries
or where to find them. However, the SDK does include a function
(Vamp::PluginHostAdapter::getPluginPath()) that returns a recommended
directory search path that hosts may use for plugin libraries, and a
class (Vamp::HostExt::PluginLoader) that implements a sensible
cross-platform lookup policy using this path. We recommend using this
class in your host unless you have a good reason not to want to. This
implementation also permits the user to set the environment variable
VAMP_PATH to override the default path if desired.
The policy used by Vamp::HostExt::PluginLoader -- and our
recommendation for any host -- is to search each directory in the path
returned by getPluginPath for .DLL (on Windows), .so (on Linux,
Solaris, BSD etc) or .dylib (on OS/X) files, then to load each one and
perform a dynamic name lookup on the vampGetPluginDescriptor function
to enumerate the plugins in the library. This operation will
necessarily be system-dependent.
Vamp also has an informal convention for sorting plugins into
functional categories. In addition to the library file itself, a
plugin library may install a category file with the same name as the
library but .cat extension. The existence and format of this file are
not specified by the Vamp API, but by convention the file may contain
lines of the format
vamp:pluginlibrary:pluginname::General Category > Specific Category
which a host may read and use to assign plugins a location within a
category tree for display to the user. The expectation is that
advanced users may also choose to set up their own preferred category
trees, which is why this information is not queried as part of the
Vamp plugin's API itself. The Vamp::HostExt::PluginLoader class also
provides support for plugin category lookup using this scheme.
Building and Installing the SDK and Examples
============================================
To build the SDK, the simple host, and the example plugins, edit the
Makefile to suit your platform according to the comments in it, then
run "make".
To use an IDE to build a plugin or host using the Vamp SDK, simply add
the .cpp files in the vamp-sdk directory to your project.
Installing the example plugins so that they can be found by other Vamp
hosts depends on your platform:
* Windows: copy the files
examples/vamp-example-plugins.dll
examples/vamp-example-plugins.cat
to
C:\Program Files\Vamp Plugins
* Linux: copy the files
examples/vamp-example-plugins.so
examples/vamp-example-plugins.cat
to
/usr/local/lib/vamp/
* OS/X: copy the files
examples/vamp-example-plugins.dylib
examples/vamp-example-plugins.cat
to
/Library/Audio/Plug-Ins/Vamp
Licensing
=========
This plugin SDK is freely redistributable under a "new-style BSD"
licence. See the file COPYING for more details. In short, you may
modify and redistribute the SDK and example plugins within any
commercial or non-commercial, proprietary or open-source plugin or
application under almost any conditions, with no obligation to provide
source code, provided you retain the original copyright note.
See Also
========
Sonic Visualiser, an interactive open-source graphical audio
inspection, analysis and visualisation tool supporting Vamp plugins.
http://www.sonicvisualiser.org/
Authors
=======
Vamp and the Vamp SDK were designed and made at the Centre for Digital
Music at Queen Mary, University of London.
The SDK was written by Chris Cannam, copyright (c) 2005-2007
Chris Cannam and QMUL.
Mark Sandler and Christian Landone provided ideas and direction, and
Mark Levy, Dan Stowell, Martin Gasser and Craig Sapp provided testing
and other input for the 1.0 API and SDK. The API also uses some ideas
from prior plugin systems, notably DSSI (http://dssi.sourceforge.net)
and FEAPI (http://feapi.sourceforge.net).

View file

@ -0,0 +1,247 @@
/* -*- 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.
This file copyright 2006 Dan Stowell.
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 "AmplitudeFollower.h"
#include <cmath>
#include <string>
#include <vector>
#include <iostream>
using std::string;
using std::vector;
using std::cerr;
using std::endl;
/**
* An implementation of SuperCollider's amplitude-follower algorithm
* as a simple Vamp plugin.
*/
AmplitudeFollower::AmplitudeFollower(float inputSampleRate) :
Plugin(inputSampleRate),
m_stepSize(0),
m_previn(0.0f),
m_clampcoef(0.01f),
m_relaxcoef(0.01f)
{
}
AmplitudeFollower::~AmplitudeFollower()
{
}
string
AmplitudeFollower::getIdentifier() const
{
return "amplitudefollower";
}
string
AmplitudeFollower::getName() const
{
return "Amplitude Follower";
}
string
AmplitudeFollower::getDescription() const
{
return "Track the amplitude of the audio signal";
}
string
AmplitudeFollower::getMaker() const
{
return "Vamp SDK Example Plugins";
}
int
AmplitudeFollower::getPluginVersion() const
{
return 1;
}
string
AmplitudeFollower::getCopyright() const
{
return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)";
}
bool
AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (channels < getMinChannelCount() ||
channels > getMaxChannelCount()) return false;
m_stepSize = std::min(stepSize, blockSize);
// Translate the coefficients
// from their "convenient" 60dB convergence-time values
// to real coefficients
m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate));
m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate));
return true;
}
void
AmplitudeFollower::reset()
{
m_previn = 0.0f;
}
AmplitudeFollower::OutputList
AmplitudeFollower::getOutputDescriptors() const
{
OutputList list;
OutputDescriptor sca;
sca.identifier = "amplitude";
sca.name = "Amplitude";
sca.description = "";
sca.unit = "V";
sca.hasFixedBinCount = true;
sca.binCount = 1;
sca.hasKnownExtents = false;
sca.isQuantized = false;
sca.sampleType = OutputDescriptor::OneSamplePerStep;
list.push_back(sca);
return list;
}
AmplitudeFollower::ParameterList
AmplitudeFollower::getParameterDescriptors() const
{
ParameterList list;
ParameterDescriptor att;
att.identifier = "attack";
att.name = "Attack time";
att.description = "";
att.unit = "s";
att.minValue = 0.0f;
att.maxValue = 1.f;
att.defaultValue = 0.01f;
att.isQuantized = false;
list.push_back(att);
ParameterDescriptor dec;
dec.identifier = "release";
dec.name = "Release time";
dec.description = "";
dec.unit = "s";
dec.minValue = 0.0f;
dec.maxValue = 1.f;
dec.defaultValue = 0.01f;
dec.isQuantized = false;
list.push_back(dec);
return list;
}
void AmplitudeFollower::setParameter(std::string paramid, float newval)
{
if (paramid == "attack") {
m_clampcoef = newval;
} else if (paramid == "release") {
m_relaxcoef = newval;
}
}
float AmplitudeFollower::getParameter(std::string paramid) const
{
if (paramid == "attack") {
return m_clampcoef;
} else if (paramid == "release") {
return m_relaxcoef;
}
return 0.0f;
}
AmplitudeFollower::FeatureSet
AmplitudeFollower::process(const float *const *inputBuffers,
Vamp::RealTime timestamp)
{
if (m_stepSize == 0) {
cerr << "ERROR: AmplitudeFollower::process: "
<< "AmplitudeFollower has not been initialised"
<< endl;
return FeatureSet();
}
float previn = m_previn;
FeatureSet returnFeatures;
float val;
float peak = 0.0f;
for (size_t i = 0; i < m_stepSize; ++i) {
val = fabs(inputBuffers[0][i]);
if (val < previn) {
val = val + (previn - val) * m_relaxcoef;
} else {
val = val + (previn - val) * m_clampcoef;
}
if (val > peak) peak = val;
previn = val;
}
m_previn = previn;
// Now store the "feature" (peak amp) for this sample
Feature feature;
feature.hasTimestamp = false;
feature.values.push_back(peak);
returnFeatures[0].push_back(feature);
return returnFeatures;
}
AmplitudeFollower::FeatureSet
AmplitudeFollower::getRemainingFeatures()
{
return FeatureSet();
}

View file

@ -0,0 +1,84 @@
/* -*- 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.
This file copyright 2006 Dan Stowell.
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 _AMPLITUDE_FOLLOWER_PLUGIN_H_
#define _AMPLITUDE_FOLLOWER_PLUGIN_H_
#include "vamp-sdk/Plugin.h"
/**
* Example plugin implementing the SuperCollider amplitude follower
* function.
*/
class AmplitudeFollower : public Vamp::Plugin
{
public:
AmplitudeFollower(float inputSampleRate);
virtual ~AmplitudeFollower();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const { return TimeDomain; }
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
OutputList getOutputDescriptors() const;
ParameterList getParameterDescriptors() const;
float getParameter(std::string paramid) const;
void setParameter(std::string paramid, float newval);
FeatureSet process(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
size_t m_stepSize;
float m_previn;
float m_clampcoef;
float m_relaxcoef;
};
#endif

View file

@ -0,0 +1,285 @@
/* -*- 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.
*/
#include "PercussionOnsetDetector.h"
using std::string;
using std::vector;
using std::cerr;
using std::endl;
#include <cmath>
PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
Plugin(inputSampleRate),
m_stepSize(0),
m_blockSize(0),
m_threshold(3),
m_sensitivity(40),
m_priorMagnitudes(0),
m_dfMinus1(0),
m_dfMinus2(0)
{
}
PercussionOnsetDetector::~PercussionOnsetDetector()
{
delete[] m_priorMagnitudes;
}
string
PercussionOnsetDetector::getIdentifier() const
{
return "percussiononsets";
}
string
PercussionOnsetDetector::getName() const
{
return "Simple Percussion Onset Detector";
}
string
PercussionOnsetDetector::getDescription() const
{
return "Detect percussive note onsets by identifying broadband energy rises";
}
string
PercussionOnsetDetector::getMaker() const
{
return "Vamp SDK Example Plugins";
}
int
PercussionOnsetDetector::getPluginVersion() const
{
return 2;
}
string
PercussionOnsetDetector::getCopyright() const
{
return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)";
}
size_t
PercussionOnsetDetector::getPreferredStepSize() const
{
return 0;
}
size_t
PercussionOnsetDetector::getPreferredBlockSize() const
{
return 1024;
}
bool
PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (channels < getMinChannelCount() ||
channels > getMaxChannelCount()) return false;
m_stepSize = stepSize;
m_blockSize = blockSize;
m_priorMagnitudes = new float[m_blockSize/2];
for (size_t i = 0; i < m_blockSize/2; ++i) {
m_priorMagnitudes[i] = 0.f;
}
m_dfMinus1 = 0.f;
m_dfMinus2 = 0.f;
return true;
}
void
PercussionOnsetDetector::reset()
{
for (size_t i = 0; i < m_blockSize/2; ++i) {
m_priorMagnitudes[i] = 0.f;
}
m_dfMinus1 = 0.f;
m_dfMinus2 = 0.f;
}
PercussionOnsetDetector::ParameterList
PercussionOnsetDetector::getParameterDescriptors() const
{
ParameterList list;
ParameterDescriptor d;
d.identifier = "threshold";
d.name = "Energy rise threshold";
d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
d.unit = "dB";
d.minValue = 0;
d.maxValue = 20;
d.defaultValue = 3;
d.isQuantized = false;
list.push_back(d);
d.identifier = "sensitivity";
d.name = "Sensitivity";
d.description = "Sensitivity of peak detector applied to broadband detection function";
d.unit = "%";
d.minValue = 0;
d.maxValue = 100;
d.defaultValue = 40;
d.isQuantized = false;
list.push_back(d);
return list;
}
float
PercussionOnsetDetector::getParameter(std::string id) const
{
if (id == "threshold") return m_threshold;
if (id == "sensitivity") return m_sensitivity;
return 0.f;
}
void
PercussionOnsetDetector::setParameter(std::string id, float value)
{
if (id == "threshold") {
if (value < 0) value = 0;
if (value > 20) value = 20;
m_threshold = value;
} else if (id == "sensitivity") {
if (value < 0) value = 0;
if (value > 100) value = 100;
m_sensitivity = value;
}
}
PercussionOnsetDetector::OutputList
PercussionOnsetDetector::getOutputDescriptors() const
{
OutputList list;
OutputDescriptor d;
d.identifier = "onsets";
d.name = "Onsets";
d.description = "Percussive note onset locations";
d.unit = "";
d.hasFixedBinCount = true;
d.binCount = 0;
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleType = OutputDescriptor::VariableSampleRate;
d.sampleRate = m_inputSampleRate;
list.push_back(d);
d.identifier = "detectionfunction";
d.name = "Detection Function";
d.description = "Broadband energy rise detection function";
d.binCount = 1;
d.isQuantized = true;
d.quantizeStep = 1.0;
d.sampleType = OutputDescriptor::OneSamplePerStep;
list.push_back(d);
return list;
}
PercussionOnsetDetector::FeatureSet
PercussionOnsetDetector::process(const float *const *inputBuffers,
Vamp::RealTime ts)
{
if (m_stepSize == 0) {
cerr << "ERROR: PercussionOnsetDetector::process: "
<< "PercussionOnsetDetector has not been initialised"
<< endl;
return FeatureSet();
}
int count = 0;
for (size_t i = 1; i < m_blockSize/2; ++i) {
float real = inputBuffers[0][i*2];
float imag = inputBuffers[0][i*2 + 1];
float sqrmag = real * real + imag * imag;
if (m_priorMagnitudes[i] > 0.f) {
float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
if (diff >= m_threshold) ++count;
}
m_priorMagnitudes[i] = sqrmag;
}
FeatureSet returnFeatures;
Feature detectionFunction;
detectionFunction.hasTimestamp = false;
detectionFunction.values.push_back(count);
returnFeatures[1].push_back(detectionFunction);
if (m_dfMinus2 < m_dfMinus1 &&
m_dfMinus1 >= count &&
m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
Feature onset;
onset.hasTimestamp = true;
onset.timestamp = ts - Vamp::RealTime::frame2RealTime
(m_stepSize, lrintf(m_inputSampleRate));
returnFeatures[0].push_back(onset);
}
m_dfMinus2 = m_dfMinus1;
m_dfMinus1 = count;
return returnFeatures;
}
PercussionOnsetDetector::FeatureSet
PercussionOnsetDetector::getRemainingFeatures()
{
return FeatureSet();
}

View file

@ -0,0 +1,90 @@
/* -*- 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 _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_
#define _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_
#include "vamp-sdk/Plugin.h"
/**
* Example plugin that detects percussive events.
*/
class PercussionOnsetDetector : public Vamp::Plugin
{
public:
PercussionOnsetDetector(float inputSampleRate);
virtual ~PercussionOnsetDetector();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const { return FrequencyDomain; }
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
ParameterList getParameterDescriptors() const;
float getParameter(std::string id) const;
void setParameter(std::string id, float value);
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
size_t m_stepSize;
size_t m_blockSize;
float m_threshold;
float m_sensitivity;
float *m_priorMagnitudes;
float m_dfMinus1;
float m_dfMinus2;
};
#endif

View file

@ -0,0 +1,188 @@
/* -*- 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.
*/
#include "SpectralCentroid.h"
using std::string;
using std::vector;
using std::cerr;
using std::endl;
#include <cmath>
SpectralCentroid::SpectralCentroid(float inputSampleRate) :
Plugin(inputSampleRate),
m_stepSize(0),
m_blockSize(0)
{
}
SpectralCentroid::~SpectralCentroid()
{
}
string
SpectralCentroid::getIdentifier() const
{
return "spectralcentroid";
}
string
SpectralCentroid::getName() const
{
return "Spectral Centroid";
}
string
SpectralCentroid::getDescription() const
{
return "Calculate the centroid frequency of the spectrum of the input signal";
}
string
SpectralCentroid::getMaker() const
{
return "Vamp SDK Example Plugins";
}
int
SpectralCentroid::getPluginVersion() const
{
return 2;
}
string
SpectralCentroid::getCopyright() const
{
return "Freely redistributable (BSD license)";
}
bool
SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (channels < getMinChannelCount() ||
channels > getMaxChannelCount()) return false;
m_stepSize = stepSize;
m_blockSize = blockSize;
return true;
}
void
SpectralCentroid::reset()
{
}
SpectralCentroid::OutputList
SpectralCentroid::getOutputDescriptors() const
{
OutputList list;
OutputDescriptor d;
d.identifier = "logcentroid";
d.name = "Log Frequency Centroid";
d.description = "Centroid of the log weighted frequency spectrum";
d.unit = "Hz";
d.hasFixedBinCount = true;
d.binCount = 1;
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleType = OutputDescriptor::OneSamplePerStep;
list.push_back(d);
d.identifier = "linearcentroid";
d.name = "Linear Frequency Centroid";
d.description = "Centroid of the linear frequency spectrum";
list.push_back(d);
return list;
}
SpectralCentroid::FeatureSet
SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime)
{
if (m_stepSize == 0) {
cerr << "ERROR: SpectralCentroid::process: "
<< "SpectralCentroid has not been initialised"
<< endl;
return FeatureSet();
}
double numLin = 0.0, numLog = 0.0, denom = 0.0;
for (size_t i = 1; i <= m_blockSize/2; ++i) {
double freq = (double(i) * m_inputSampleRate) / m_blockSize;
double real = inputBuffers[0][i*2];
double imag = inputBuffers[0][i*2 + 1];
double power = sqrt(real * real + imag * imag) / (m_blockSize/2);
numLin += freq * power;
numLog += log10f(freq) * power;
denom += power;
}
FeatureSet returnFeatures;
// std::cerr << "power " << denom << ", block size " << m_blockSize << std::endl;
if (denom != 0.0) {
float centroidLin = float(numLin / denom);
float centroidLog = powf(10, float(numLog / denom));
Feature feature;
feature.hasTimestamp = false;
if (!std::isnan(centroidLog) && !std::isinf(centroidLog)) {
feature.values.push_back(centroidLog);
}
returnFeatures[0].push_back(feature);
feature.values.clear();
if (!std::isnan(centroidLin) && !std::isinf(centroidLin)) {
feature.values.push_back(centroidLin);
}
returnFeatures[1].push_back(feature);
}
return returnFeatures;
}
SpectralCentroid::FeatureSet
SpectralCentroid::getRemainingFeatures()
{
return FeatureSet();
}

View file

@ -0,0 +1,78 @@
/* -*- 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 _SPECTRAL_CENTROID_PLUGIN_H_
#define _SPECTRAL_CENTROID_PLUGIN_H_
#include "vamp-sdk/Plugin.h"
/**
* Example plugin that calculates the centre of gravity of the
* frequency domain representation of each block of audio.
*/
class SpectralCentroid : public Vamp::Plugin
{
public:
SpectralCentroid(float inputSampleRate);
virtual ~SpectralCentroid();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const { return FrequencyDomain; }
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
size_t m_stepSize;
size_t m_blockSize;
};
#endif

View file

@ -0,0 +1,194 @@
/* -*- 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.
*/
#include "ZeroCrossing.h"
using std::string;
using std::vector;
using std::cerr;
using std::endl;
ZeroCrossing::ZeroCrossing(float inputSampleRate) :
Plugin(inputSampleRate),
m_stepSize(0),
m_previousSample(0.0f)
{
}
ZeroCrossing::~ZeroCrossing()
{
}
string
ZeroCrossing::getIdentifier() const
{
return "zerocrossing";
}
string
ZeroCrossing::getName() const
{
return "Zero Crossings";
}
string
ZeroCrossing::getDescription() const
{
return "Detect and count zero crossing points";
}
string
ZeroCrossing::getMaker() const
{
return "Vamp SDK Example Plugins";
}
int
ZeroCrossing::getPluginVersion() const
{
return 2;
}
string
ZeroCrossing::getCopyright() const
{
return "Freely redistributable (BSD license)";
}
bool
ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (channels < getMinChannelCount() ||
channels > getMaxChannelCount()) return false;
m_stepSize = std::min(stepSize, blockSize);
return true;
}
void
ZeroCrossing::reset()
{
m_previousSample = 0.0f;
}
ZeroCrossing::OutputList
ZeroCrossing::getOutputDescriptors() const
{
OutputList list;
OutputDescriptor zc;
zc.identifier = "counts";
zc.name = "Zero Crossing Counts";
zc.description = "The number of zero crossing points per processing block";
zc.unit = "crossings";
zc.hasFixedBinCount = true;
zc.binCount = 1;
zc.hasKnownExtents = false;
zc.isQuantized = true;
zc.quantizeStep = 1.0;
zc.sampleType = OutputDescriptor::OneSamplePerStep;
list.push_back(zc);
zc.identifier = "zerocrossings";
zc.name = "Zero Crossings";
zc.description = "The locations of zero crossing points";
zc.unit = "";
zc.hasFixedBinCount = true;
zc.binCount = 0;
zc.sampleType = OutputDescriptor::VariableSampleRate;
zc.sampleRate = m_inputSampleRate;
list.push_back(zc);
return list;
}
ZeroCrossing::FeatureSet
ZeroCrossing::process(const float *const *inputBuffers,
Vamp::RealTime timestamp)
{
if (m_stepSize == 0) {
cerr << "ERROR: ZeroCrossing::process: "
<< "ZeroCrossing has not been initialised"
<< endl;
return FeatureSet();
}
float prev = m_previousSample;
size_t count = 0;
FeatureSet returnFeatures;
for (size_t i = 0; i < m_stepSize; ++i) {
float sample = inputBuffers[0][i];
bool crossing = false;
if (sample <= 0.0) {
if (prev > 0.0) crossing = true;
} else if (sample > 0.0) {
if (prev <= 0.0) crossing = true;
}
if (crossing) {
++count;
Feature feature;
feature.hasTimestamp = true;
feature.timestamp = timestamp +
Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate);
returnFeatures[1].push_back(feature);
}
prev = sample;
}
m_previousSample = prev;
Feature feature;
feature.hasTimestamp = false;
feature.values.push_back(count);
returnFeatures[0].push_back(feature);
return returnFeatures;
}
ZeroCrossing::FeatureSet
ZeroCrossing::getRemainingFeatures()
{
return FeatureSet();
}

View file

@ -0,0 +1,78 @@
/* -*- 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 _ZERO_CROSSING_PLUGIN_H_
#define _ZERO_CROSSING_PLUGIN_H_
#include "vamp-sdk/Plugin.h"
/**
* Example plugin that calculates the positions and density of
* zero-crossing points in an audio waveform.
*/
class ZeroCrossing : public Vamp::Plugin
{
public:
ZeroCrossing(float inputSampleRate);
virtual ~ZeroCrossing();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const { return TimeDomain; }
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
size_t m_stepSize;
float m_previousSample;
};
#endif

View file

@ -0,0 +1,63 @@
/* -*- 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.
*/
#include "vamp/vamp.h"
#include "vamp-sdk/PluginAdapter.h"
#include "ZeroCrossing.h"
#include "SpectralCentroid.h"
#include "PercussionOnsetDetector.h"
#include "AmplitudeFollower.h"
static Vamp::PluginAdapter<ZeroCrossing> zeroCrossingAdapter;
static Vamp::PluginAdapter<SpectralCentroid> spectralCentroidAdapter;
static Vamp::PluginAdapter<PercussionOnsetDetector> percussionOnsetAdapter;
static Vamp::PluginAdapter<AmplitudeFollower> amplitudeAdapter;
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
unsigned int index)
{
if (version < 1) return 0;
switch (index) {
case 0: return zeroCrossingAdapter.getDescriptor();
case 1: return spectralCentroidAdapter.getDescriptor();
case 2: return percussionOnsetAdapter.getDescriptor();
case 3: return amplitudeAdapter.getDescriptor();
default: return 0;
}
}

View file

@ -0,0 +1,5 @@
vamp:vamp-example-plugins:zerocrossing::Low Level Features
vamp:vamp-example-plugins:spectralcentroid::Low Level Features
vamp:vamp-example-plugins:percussiononsets::Time > Onsets
vamp:vamp-example-plugins:amplitudefollower::Low Level Features

View file

@ -0,0 +1,75 @@
/* -*- 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 _SYSTEM_H_
#define _SYSTEM_H_
#ifdef _WIN32
#include <windows.h>
#define DLOPEN(a,b) LoadLibrary((a).c_str())
#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b))
#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a))
#define DLERROR() ""
#define PLUGIN_SUFFIX "dll"
#else
#include <dlfcn.h>
#define DLOPEN(a,b) dlopen((a).c_str(),(b))
#define DLSYM(a,b) dlsym((a),(b))
#define DLCLOSE(a) dlclose((a))
#define DLERROR() dlerror()
#ifdef __APPLE__
#define PLUGIN_SUFFIX "dylib"
#define HAVE_OPENDIR 1
#else
#define PLUGIN_SUFFIX "so"
#define HAVE_OPENDIR 1
#endif /* __APPLE__ */
#endif /* ! _WIN32 */
#endif

View file

@ -0,0 +1,492 @@
/* -*- 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.
FFT code from 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-sdk/PluginHostAdapter.h"
#include "vamp-sdk/hostext/PluginChannelAdapter.h"
#include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
#include "vamp-sdk/hostext/PluginLoader.h"
#include "vamp/vamp.h"
#include <iostream>
#include <fstream>
#include <sndfile.h>
#include "system.h"
#include <cmath>
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::ofstream;
using std::ios;
using Vamp::HostExt::PluginLoader;
#define HOST_VERSION "1.1"
void printFeatures(int, int, int, Vamp::Plugin::FeatureSet, ofstream *);
void transformInput(float *, size_t);
void fft(unsigned int, bool, double *, double *, double *, double *);
void printPluginPath(bool verbose);
void enumeratePlugins();
void listPluginsInLibrary(string soname);
int runPlugin(string myname, string soname, string id, string output,
int outputNo, string inputFile, string outfilename);
void usage(const char *name)
{
cerr << "\n"
<< name << ": A simple Vamp plugin host.\n\n"
"Centre for Digital Music, Queen Mary, University of London.\n"
"Copyright 2006-2007 Chris Cannam and QMUL.\n"
"Freely redistributable; published under a BSD-style license.\n\n"
"Usage:\n\n"
" " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o outfile.txt]\n"
" " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o outfile.txt]\n\n"
" -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
" audio data in \"file.wav\", retrieving the named \"output\", or output\n"
" number \"outputno\" (the first output by default) and dumping it to\n"
" standard output, or to \"outfile.txt\" if the -o option is given.\n\n"
" \"pluginlibrary\" should be a library name, not a file path; the\n"
" standard Vamp library search path will be used to locate it. If\n"
" a file path is supplied, the directory part(s) will be ignored.\n\n"
" " << name << " -l\n\n"
" -- List the plugin libraries and Vamp plugins in the library search path.\n\n"
" " << name << " -p\n\n"
" -- Print out the Vamp library search path.\n\n"
" " << name << " -v\n\n"
" -- Display version information only.\n\n"
<< endl;
exit(2);
}
int main(int argc, char **argv)
{
char *scooter = argv[0];
char *name = 0;
while (scooter && *scooter) {
if (*scooter == '/' || *scooter == '\\') name = ++scooter;
else ++scooter;
}
if (!name || !*name) name = argv[0];
if (argc < 2) usage(name);
if (argc == 2) {
if (!strcmp(argv[1], "-v")) {
cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
<< "Vamp API version: " << VAMP_API_VERSION << endl
<< "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
return 0;
} else if (!strcmp(argv[1], "-l")) {
printPluginPath(true);
enumeratePlugins();
return 0;
} else if (!strcmp(argv[1], "-p")) {
printPluginPath(false);
return 0;
} else usage(name);
}
if (argc < 3) usage(name);
string soname = argv[1];
string wavname = argv[2];
string plugid = "";
string output = "";
int outputNo = -1;
string outfilename;
if (argc >= 4) {
int idx = 3;
if (isdigit(*argv[idx])) {
outputNo = atoi(argv[idx++]);
}
if (argc == idx + 2) {
if (!strcmp(argv[idx], "-o")) {
outfilename = argv[idx+1];
} else usage(name);
} else if (argc != idx) {
(usage(name));
}
}
cerr << endl << name << ": Running..." << endl;
cerr << "Reading file: \"" << wavname << "\", writing to ";
if (outfilename == "") {
cerr << "standard output" << endl;
} else {
cerr << "\"" << outfilename << "\"" << endl;
}
string::size_type sep = soname.find(':');
if (sep != string::npos) {
plugid = soname.substr(sep + 1);
soname = soname.substr(0, sep);
sep = plugid.find(':');
if (sep != string::npos) {
output = plugid.substr(sep + 1);
plugid = plugid.substr(0, sep);
}
}
if (plugid == "") {
usage(name);
}
if (output != "" && outputNo != -1) {
usage(name);
}
if (output == "" && outputNo == -1) {
outputNo = 0;
}
return runPlugin(name, soname, plugid, output, outputNo,
wavname, outfilename);
}
int runPlugin(string myname, string soname, string id,
string output, int outputNo, string wavname,
string outfilename)
{
PluginLoader *loader = PluginLoader::getInstance();
PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
SNDFILE *sndfile;
SF_INFO sfinfo;
memset(&sfinfo, 0, sizeof(SF_INFO));
sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
if (!sndfile) {
cerr << myname << ": ERROR: Failed to open input file \""
<< wavname << "\": " << sf_strerror(sndfile) << endl;
return 1;
}
ofstream *out = 0;
if (outfilename != "") {
out = new ofstream(outfilename.c_str(), ios::out);
if (!*out) {
cerr << myname << ": ERROR: Failed to open output file \""
<< outfilename << "\" for writing" << endl;
delete out;
return 1;
}
}
Vamp::Plugin *plugin = loader->loadPlugin
(key, sfinfo.samplerate, PluginLoader::ADAPT_ALL);
if (!plugin) {
cerr << myname << ": ERROR: Failed to load plugin \"" << id
<< "\" from library \"" << soname << "\"" << endl;
sf_close(sndfile);
if (out) {
out->close();
delete out;
}
return 1;
}
cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
int blockSize = plugin->getPreferredBlockSize();
int stepSize = plugin->getPreferredStepSize();
if (blockSize == 0) blockSize = 1024;
if (stepSize == 0) {
if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
stepSize = blockSize/2;
} else {
stepSize = blockSize;
}
}
int channels = sfinfo.channels;
float *filebuf = new float[blockSize * channels];
float **plugbuf = new float*[channels];
for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
cerr << "Using block size = " << blockSize << ", step size = "
<< stepSize << endl;
int minch = plugin->getMinChannelCount();
int maxch = plugin->getMaxChannelCount();
cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
Vamp::Plugin::OutputDescriptor od;
int returnValue = 1;
int progress = 0;
if (outputs.empty()) {
cerr << "ERROR: Plugin has no outputs!" << endl;
goto done;
}
if (outputNo < 0) {
for (size_t oi = 0; oi < outputs.size(); ++oi) {
if (outputs[oi].identifier == output) {
outputNo = oi;
break;
}
}
if (outputNo < 0) {
cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
goto done;
}
} else {
if (int(outputs.size()) <= outputNo) {
cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
goto done;
}
}
od = outputs[outputNo];
cerr << "Output is: \"" << od.identifier << "\"" << endl;
if (!plugin->initialise(channels, stepSize, blockSize)) {
cerr << "ERROR: Plugin initialise (channels = " << channels
<< ", stepSize = " << stepSize << ", blockSize = "
<< blockSize << ") failed." << endl;
goto done;
}
for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
int count;
if (sf_seek(sndfile, i, SEEK_SET) < 0) {
cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl;
break;
}
if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
break;
}
for (int c = 0; c < channels; ++c) {
int j = 0;
while (j < count) {
plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
++j;
}
while (j < blockSize) {
plugbuf[c][j] = 0.0f;
++j;
}
}
printFeatures
(i, sfinfo.samplerate, outputNo, plugin->process
(plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)),
out);
int pp = progress;
progress = lrintf((float(i) / sfinfo.frames) * 100.f);
if (progress != pp && out) {
cerr << "\r" << progress << "%";
}
}
if (out) cerr << "\rDone" << endl;
printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
plugin->getRemainingFeatures(), out);
returnValue = 0;
done:
delete plugin;
if (out) {
out->close();
delete out;
}
sf_close(sndfile);
return returnValue;
}
void
printPluginPath(bool verbose)
{
if (verbose) {
cout << "\nVamp plugin search path: ";
}
vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
for (size_t i = 0; i < path.size(); ++i) {
if (verbose) {
cout << "[" << path[i] << "]";
} else {
cout << path[i] << endl;
}
}
if (verbose) cout << endl;
}
void
enumeratePlugins()
{
PluginLoader *loader = PluginLoader::getInstance();
cout << "\nVamp plugin libraries found in search path:" << endl;
std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
typedef std::multimap<std::string, PluginLoader::PluginKey>
LibraryMap;
LibraryMap libraryMap;
for (size_t i = 0; i < plugins.size(); ++i) {
std::string path = loader->getLibraryPathForPlugin(plugins[i]);
libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
}
std::string prevPath = "";
int index = 0;
for (LibraryMap::iterator i = libraryMap.begin();
i != libraryMap.end(); ++i) {
std::string path = i->first;
PluginLoader::PluginKey key = i->second;
if (path != prevPath) {
prevPath = path;
index = 0;
cout << "\n " << path << ":" << endl;
}
Vamp::Plugin *plugin = loader->loadPlugin(key, 48000);
if (plugin) {
char c = char('A' + index);
if (c > 'Z') c = char('a' + (index - 26));
cout << " [" << c << "] [v"
<< plugin->getVampApiVersion() << "] "
<< plugin->getName() << ", \""
<< plugin->getIdentifier() << "\"" << " ["
<< plugin->getMaker() << "]" << endl;
PluginLoader::PluginCategoryHierarchy category =
loader->getPluginCategory(key);
if (!category.empty()) {
cout << " ";
for (size_t ci = 0; ci < category.size(); ++ci) {
cout << " > " << category[ci];
}
cout << endl;
}
if (plugin->getDescription() != "") {
cout << " - " << plugin->getDescription() << endl;
}
Vamp::Plugin::OutputList outputs =
plugin->getOutputDescriptors();
if (outputs.size() > 1) {
for (size_t j = 0; j < outputs.size(); ++j) {
cout << " (" << j << ") "
<< outputs[j].name << ", \""
<< outputs[j].identifier << "\"" << endl;
if (outputs[j].description != "") {
cout << " - "
<< outputs[j].description << endl;
}
}
}
++index;
delete plugin;
}
}
cout << endl;
}
void
printFeatures(int frame, int sr, int output,
Vamp::Plugin::FeatureSet features, ofstream *out)
{
for (unsigned int i = 0; i < features[output].size(); ++i) {
Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr);
if (features[output][i].hasTimestamp) {
rt = features[output][i].timestamp;
}
(out ? *out : cout) << rt.toString() << ":";
for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
(out ? *out : cout) << " " << features[output][i].values[j];
}
(out ? *out : cout) << endl;
}
}

View file

@ -0,0 +1,405 @@
/* -*- 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_PLUGIN_H_
#define _VAMP_PLUGIN_H_
#include "PluginBase.h"
#include "RealTime.h"
#include <string>
#include <vector>
#include <map>
namespace Vamp {
/**
* \class Plugin Plugin.h <vamp-sdk/Plugin.h>
*
* Vamp::Plugin is a base class for plugin instance classes
* that provide feature extraction from audio or related data.
*
* In most cases, the input will be audio and the output will be a
* stream of derived data at a lower sampling resolution than the
* input.
*
* Note that this class inherits several abstract methods from
* PluginBase. These must be implemented by the subclass.
*
*
* PLUGIN LIFECYCLE
*
* Feature extraction plugins are managed differently from real-time
* plugins (such as VST effects). The main difference is that the
* parameters for a feature extraction plugin are configured before
* the plugin is used, and do not change during use.
*
* 1. Host constructs the plugin, passing it the input sample rate.
* The plugin may do basic initialisation, but should not do anything
* computationally expensive at this point. You must make sure your
* plugin is cheap to construct, otherwise you'll seriously affect the
* startup performance of almost all hosts. If you have serious
* initialisation to do, the proper place is in initialise() (step 5).
*
* 2. Host may query the plugin's available outputs.
*
* 3. Host queries programs and parameter descriptors, and may set
* some or all of them. Parameters that are not explicitly set should
* take their default values as specified in the parameter descriptor.
* When a program is set, the parameter values may change and the host
* will re-query them to check.
*
* 4. Host queries the preferred step size, block size and number of
* channels. These may all vary depending on the parameter values.
* (Note however that you cannot make the number of distinct outputs
* dependent on parameter values.)
*
* 5. Plugin is properly initialised with a call to initialise. This
* fixes the step size, block size, and number of channels, as well as
* all of the parameter and program settings. If the values passed in
* to initialise do not match the plugin's advertised preferred values
* from step 4, the plugin may refuse to initialise and return false
* (although if possible it should accept the new values). Any
* computationally expensive setup code should take place here.
*
* 6. Host finally checks the number of values, resolution, extents
* etc per output (which may vary depending on the number of channels,
* step size and block size as well as the parameter values).
*
* 7. Host will repeatedly call the process method to pass in blocks
* of input data. This method may return features extracted from that
* data (if the plugin is causal).
*
* 8. Host will call getRemainingFeatures exactly once, after all the
* input data has been processed. This may return any non-causal or
* leftover features.
*
* 9. At any point after initialise was called, the host may
* optionally call the reset method and restart processing. (This
* does not mean it can change the parameters, which are fixed from
* initialise until destruction.)
*
* A plugin does not need to handle the case where setParameter or
* selectProgram is called after initialise has been called. It's the
* host's responsibility not to do that. Similarly, the plugin may
* safely assume that initialise is called no more than once.
*/
class Plugin : public PluginBase
{
public:
virtual ~Plugin() { }
/**
* Initialise a plugin to prepare it for use with the given number
* of input channels, step size (window increment, in sample
* frames) and block size (window size, in sample frames).
*
* The input sample rate should have been already specified at
* construction time.
*
* Return true for successful initialisation, false if the number
* of input channels, step size and/or block size cannot be
* supported.
*/
virtual bool initialise(size_t inputChannels,
size_t stepSize,
size_t blockSize) = 0;
/**
* Reset the plugin after use, to prepare it for another clean
* run. Not called for the first initialisation (i.e. initialise
* must also do a reset).
*/
virtual void reset() = 0;
enum InputDomain { TimeDomain, FrequencyDomain };
/**
* Get the plugin's required input domain. If this is TimeDomain,
* the samples provided to the process() function (below) will be
* in the time domain, as for a traditional audio processing
* plugin. If this is FrequencyDomain, the host will carry out a
* windowed FFT of size equal to the negotiated block size on the
* data before passing the frequency bin data in to process().
* The plugin does not get to choose the window type -- the host
* will either let the user do so, or will use a Hanning window.
*/
virtual InputDomain getInputDomain() const = 0;
/**
* Get the preferred block size (window size -- the number of
* sample frames passed in each block to the process() function).
* This should be called before initialise().
*
* A plugin that can handle any block size may return 0. The
* final block size will be set in the initialise() call.
*/
virtual size_t getPreferredBlockSize() const { return 0; }
/**
* Get the preferred step size (window increment -- the distance
* in sample frames between the start frames of consecutive blocks
* passed to the process() function) for the plugin. This should
* be called before initialise().
*
* A plugin may return 0 if it has no particular interest in the
* step size. In this case, the host should make the step size
* equal to the block size if the plugin is accepting input in the
* time domain. If the plugin is accepting input in the frequency
* domain, the host may use any step size. The final step size
* will be set in the initialise() call.
*/
virtual size_t getPreferredStepSize() const { return 0; }
/**
* Get the minimum supported number of input channels.
*/
virtual size_t getMinChannelCount() const { return 1; }
/**
* Get the maximum supported number of input channels.
*/
virtual size_t getMaxChannelCount() const { return 1; }
struct OutputDescriptor
{
/**
* The name of the output, in computer-usable form. Should be
* reasonably short and without whitespace or punctuation, using
* the characters [a-zA-Z0-9_] only.
* Example: "zero_crossing_count"
*/
std::string identifier;
/**
* The human-readable name of the output.
* Example: "Zero Crossing Counts"
*/
std::string name;
/**
* A human-readable short text describing the output. May be
* empty if the name has said it all already.
* Example: "The number of zero crossing points per processing block"
*/
std::string description;
/**
* The unit of the output, in human-readable form.
*/
std::string unit;
/**
* True if the output has the same number of values per sample
* for every output sample. Outputs for which this is false
* are unlikely to be very useful in a general-purpose host.
*/
bool hasFixedBinCount;
/**
* The number of values per result of the output. Undefined
* if hasFixedBinCount is false. If this is zero, the output
* is point data (i.e. only the time of each output is of
* interest, the value list will be empty).
*/
size_t binCount;
/**
* The (human-readable) names of each of the bins, if
* appropriate. This is always optional.
*/
std::vector<std::string> binNames;
/**
* True if the results in each output bin fall within a fixed
* numeric range (minimum and maximum values). Undefined if
* binCount is zero.
*/
bool hasKnownExtents;
/**
* Minimum value of the results in the output. Undefined if
* hasKnownExtents is false or binCount is zero.
*/
float minValue;
/**
* Maximum value of the results in the output. Undefined if
* hasKnownExtents is false or binCount is zero.
*/
float maxValue;
/**
* True if the output values are quantized to a particular
* resolution. Undefined if binCount is zero.
*/
bool isQuantized;
/**
* Quantization resolution of the output values (e.g. 1.0 if
* they are all integers). Undefined if isQuantized is false
* or binCount is zero.
*/
float quantizeStep;
enum SampleType {
/// Results from each process() align with that call's block start
OneSamplePerStep,
/// Results are evenly spaced in time (sampleRate specified below)
FixedSampleRate,
/// Results are unevenly spaced and have individual timestamps
VariableSampleRate
};
/**
* Positioning in time of the output results.
*/
SampleType sampleType;
/**
* Sample rate of the output results, as samples per second.
* Undefined if sampleType is OneSamplePerStep.
*
* If sampleType is VariableSampleRate and this value is
* non-zero, then it may be used to calculate a resolution for
* the output (i.e. the "duration" of each sample, in time,
* will be 1/sampleRate seconds). It's recommended to set
* this to zero if that behaviour is not desired.
*/
float sampleRate;
};
typedef std::vector<OutputDescriptor> OutputList;
/**
* Get the outputs of this plugin. An output's index in this list
* is used as its numeric index when looking it up in the
* FeatureSet returned from the process() call.
*/
virtual OutputList getOutputDescriptors() const = 0;
struct Feature
{
/**
* True if an output feature has its own timestamp. This is
* mandatory if the output has VariableSampleRate, and is
* likely to be disregarded otherwise.
*/
bool hasTimestamp;
/**
* Timestamp of the output feature. This is mandatory if the
* output has VariableSampleRate, and is likely to be
* disregarded otherwise. Undefined if hasTimestamp is false.
*/
RealTime timestamp;
/**
* Results for a single sample of this feature. If the output
* hasFixedBinCount, there must be the same number of values
* as the output's binCount count.
*/
std::vector<float> values;
/**
* Label for the sample of this feature.
*/
std::string label;
};
typedef std::vector<Feature> FeatureList;
typedef std::map<int, FeatureList> FeatureSet; // key is output no
/**
* Process a single block of input data.
*
* If the plugin's inputDomain is TimeDomain, inputBuffers will
* point to one array of floats per input channel, and each of
* these arrays will contain blockSize consecutive audio samples
* (the host will zero-pad as necessary). The timestamp will be
* the real time in seconds of the start of the supplied block of
* samples.
*
* If the plugin's inputDomain is FrequencyDomain, inputBuffers
* will point to one array of floats per input channel, and each
* of these arrays will contain blockSize/2+1 consecutive pairs of
* real and imaginary component floats corresponding to bins
* 0..(blockSize/2) of the FFT output. That is, bin 0 (the first
* pair of floats) contains the DC output, up to bin blockSize/2
* which contains the Nyquist-frequency output. There will
* therefore be blockSize+2 floats per channel in total. The
* timestamp will be the real time in seconds of the centre of the
* FFT input window (i.e. the very first block passed to process
* might contain the FFT of half a block of zero samples and the
* first half-block of the actual data, with a timestamp of zero).
*
* Return any features that have become available after this
* process call. (These do not necessarily have to fall within
* the process block, except for OneSamplePerStep outputs.)
*/
virtual FeatureSet process(const float *const *inputBuffers,
RealTime timestamp) = 0;
/**
* After all blocks have been processed, calculate and return any
* remaining features derived from the complete input.
*/
virtual FeatureSet getRemainingFeatures() = 0;
/**
* Used to distinguish between Vamp::Plugin and other potential
* sibling subclasses of PluginBase. Do not reimplement this
* function in your subclass.
*/
virtual std::string getType() const { return "Feature Extraction Plugin"; }
protected:
Plugin(float inputSampleRate) :
m_inputSampleRate(inputSampleRate) { }
float m_inputSampleRate;
};
}
#endif

View file

@ -0,0 +1,851 @@
/* -*- 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.
*/
#include "PluginAdapter.h"
//#define DEBUG_PLUGIN_ADAPTER 1
namespace Vamp {
class PluginAdapterBase::Impl
{
public:
Impl(PluginAdapterBase *);
~Impl();
const VampPluginDescriptor *getDescriptor();
protected:
PluginAdapterBase *m_base;
static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate);
static void vampCleanup(VampPluginHandle handle);
static int vampInitialise(VampPluginHandle handle, unsigned int channels,
unsigned int stepSize, unsigned int blockSize);
static void vampReset(VampPluginHandle handle);
static float vampGetParameter(VampPluginHandle handle, int param);
static void vampSetParameter(VampPluginHandle handle, int param, float value);
static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
static unsigned int vampGetOutputCount(VampPluginHandle handle);
static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i);
static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
static VampFeatureList *vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec);
static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
static void vampReleaseFeatureSet(VampFeatureList *fs);
void cleanup(Plugin *plugin);
void checkOutputMap(Plugin *plugin);
unsigned int getOutputCount(Plugin *plugin);
VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
unsigned int i);
VampFeatureList *process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec);
VampFeatureList *getRemainingFeatures(Plugin *plugin);
VampFeatureList *convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features);
// maps both plugins and descriptors to adapters
typedef std::map<const void *, Impl *> AdapterMap;
static AdapterMap *m_adapterMap;
static Impl *lookupAdapter(VampPluginHandle);
bool m_populated;
VampPluginDescriptor m_descriptor;
Plugin::ParameterList m_parameters;
Plugin::ProgramList m_programs;
typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
OutputMap m_pluginOutputs;
std::map<Plugin *, VampFeatureList *> m_fs;
std::map<Plugin *, std::vector<size_t> > m_fsizes;
std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
void resizeFS(Plugin *plugin, int n);
void resizeFL(Plugin *plugin, int n, size_t sz);
void resizeFV(Plugin *plugin, int n, int j, size_t sz);
};
PluginAdapterBase::PluginAdapterBase()
{
m_impl = new Impl(this);
}
PluginAdapterBase::~PluginAdapterBase()
{
delete m_impl;
}
const VampPluginDescriptor *
PluginAdapterBase::getDescriptor()
{
return m_impl->getDescriptor();
}
PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
m_base(base),
m_populated(false)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
#endif
}
const VampPluginDescriptor *
PluginAdapterBase::Impl::getDescriptor()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
#endif
if (m_populated) return &m_descriptor;
Plugin *plugin = m_base->createPlugin(48000);
if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
<< "Plugin object API version "
<< plugin->getVampApiVersion()
<< " does not match actual API version "
<< VAMP_API_VERSION << std::endl;
delete plugin;
return 0;
}
m_parameters = plugin->getParameterDescriptors();
m_programs = plugin->getPrograms();
m_descriptor.vampApiVersion = plugin->getVampApiVersion();
m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
m_descriptor.name = strdup(plugin->getName().c_str());
m_descriptor.description = strdup(plugin->getDescription().c_str());
m_descriptor.maker = strdup(plugin->getMaker().c_str());
m_descriptor.pluginVersion = plugin->getPluginVersion();
m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
m_descriptor.parameterCount = m_parameters.size();
m_descriptor.parameters = (const VampParameterDescriptor **)
malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
unsigned int i;
for (i = 0; i < m_parameters.size(); ++i) {
VampParameterDescriptor *desc = (VampParameterDescriptor *)
malloc(sizeof(VampParameterDescriptor));
desc->identifier = strdup(m_parameters[i].identifier.c_str());
desc->name = strdup(m_parameters[i].name.c_str());
desc->description = strdup(m_parameters[i].description.c_str());
desc->unit = strdup(m_parameters[i].unit.c_str());
desc->minValue = m_parameters[i].minValue;
desc->maxValue = m_parameters[i].maxValue;
desc->defaultValue = m_parameters[i].defaultValue;
desc->isQuantized = m_parameters[i].isQuantized;
desc->quantizeStep = m_parameters[i].quantizeStep;
desc->valueNames = 0;
if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
desc->valueNames = (const char **)
malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
}
desc->valueNames[m_parameters[i].valueNames.size()] = 0;
}
m_descriptor.parameters[i] = desc;
}
m_descriptor.programCount = m_programs.size();
m_descriptor.programs = (const char **)
malloc(m_programs.size() * sizeof(const char *));
for (i = 0; i < m_programs.size(); ++i) {
m_descriptor.programs[i] = strdup(m_programs[i].c_str());
}
if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
m_descriptor.inputDomain = vampFrequencyDomain;
} else {
m_descriptor.inputDomain = vampTimeDomain;
}
m_descriptor.instantiate = vampInstantiate;
m_descriptor.cleanup = vampCleanup;
m_descriptor.initialise = vampInitialise;
m_descriptor.reset = vampReset;
m_descriptor.getParameter = vampGetParameter;
m_descriptor.setParameter = vampSetParameter;
m_descriptor.getCurrentProgram = vampGetCurrentProgram;
m_descriptor.selectProgram = vampSelectProgram;
m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
m_descriptor.getMinChannelCount = vampGetMinChannelCount;
m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
m_descriptor.getOutputCount = vampGetOutputCount;
m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
m_descriptor.process = vampProcess;
m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
if (!m_adapterMap) {
m_adapterMap = new AdapterMap;
}
(*m_adapterMap)[&m_descriptor] = this;
delete plugin;
m_populated = true;
return &m_descriptor;
}
PluginAdapterBase::Impl::~Impl()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
#endif
if (!m_populated) return;
free((void *)m_descriptor.identifier);
free((void *)m_descriptor.name);
free((void *)m_descriptor.description);
free((void *)m_descriptor.maker);
free((void *)m_descriptor.copyright);
for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
const VampParameterDescriptor *desc = m_descriptor.parameters[i];
free((void *)desc->identifier);
free((void *)desc->name);
free((void *)desc->description);
free((void *)desc->unit);
if (desc->valueNames) {
for (unsigned int j = 0; desc->valueNames[j]; ++j) {
free((void *)desc->valueNames[j]);
}
free((void *)desc->valueNames);
}
}
free((void *)m_descriptor.parameters);
for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
free((void *)m_descriptor.programs[i]);
}
free((void *)m_descriptor.programs);
if (m_adapterMap) {
m_adapterMap->erase(&m_descriptor);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
}
PluginAdapterBase::Impl *
PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
#endif
if (!m_adapterMap) return 0;
AdapterMap::const_iterator i = m_adapterMap->find(handle);
if (i == m_adapterMap->end()) return 0;
return i->second;
}
VampPluginHandle
PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
#endif
if (!m_adapterMap) {
m_adapterMap = new AdapterMap();
}
if (m_adapterMap->find(desc) == m_adapterMap->end()) {
std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
return 0;
}
Impl *adapter = (*m_adapterMap)[desc];
if (desc != &adapter->m_descriptor) return 0;
Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
if (plugin) {
(*m_adapterMap)[plugin] = adapter;
}
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
#endif
return plugin;
}
void
PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) {
delete ((Plugin *)handle);
return;
}
adapter->cleanup(((Plugin *)handle));
}
int
PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
unsigned int channels,
unsigned int stepSize,
unsigned int blockSize)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
#endif
bool result = ((Plugin *)handle)->initialise
(channels, stepSize, blockSize);
return result ? 1 : 0;
}
void
PluginAdapterBase::Impl::vampReset(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
#endif
((Plugin *)handle)->reset();
}
float
PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
int param)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0.0;
Plugin::ParameterList &list = adapter->m_parameters;
return ((Plugin *)handle)->getParameter(list[param].identifier);
}
void
PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
int param, float value)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ParameterList &list = adapter->m_parameters;
((Plugin *)handle)->setParameter(list[param].identifier, value);
}
unsigned int
PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
Plugin::ProgramList &list = adapter->m_programs;
std::string program = ((Plugin *)handle)->getCurrentProgram();
for (unsigned int i = 0; i < list.size(); ++i) {
if (list[i] == program) return i;
}
return 0;
}
void
PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
unsigned int program)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ProgramList &list = adapter->m_programs;
((Plugin *)handle)->selectProgram(list[program]);
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredStepSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredBlockSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMinChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMaxChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputCount((Plugin *)handle);
}
VampOutputDescriptor *
PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputDescriptor((Plugin *)handle, i);
}
void
PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
#endif
if (desc->identifier) free((void *)desc->identifier);
if (desc->name) free((void *)desc->name);
if (desc->description) free((void *)desc->description);
if (desc->unit) free((void *)desc->unit);
if (desc->hasFixedBinCount && desc->binNames) {
for (unsigned int i = 0; i < desc->binCount; ++i) {
if (desc->binNames[i]) {
free((void *)desc->binNames[i]);
}
}
}
if (desc->binNames) free((void *)desc->binNames);
free((void *)desc);
}
VampFeatureList *
PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->process((Plugin *)handle,
inputBuffers, sec, nsec);
}
VampFeatureList *
PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->getRemainingFeatures((Plugin *)handle);
}
void
PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
#endif
}
void
PluginAdapterBase::Impl::cleanup(Plugin *plugin)
{
if (m_fs.find(plugin) != m_fs.end()) {
size_t outputCount = 0;
if (m_pluginOutputs[plugin]) {
outputCount = m_pluginOutputs[plugin]->size();
}
VampFeatureList *list = m_fs[plugin];
for (unsigned int i = 0; i < outputCount; ++i) {
for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
if (list[i].features[j].label) {
free(list[i].features[j].label);
}
if (list[i].features[j].values) {
free(list[i].features[j].values);
}
}
if (list[i].features) free(list[i].features);
}
m_fs.erase(plugin);
m_fsizes.erase(plugin);
m_fvsizes.erase(plugin);
}
if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
delete m_pluginOutputs[plugin];
m_pluginOutputs.erase(plugin);
}
if (m_adapterMap) {
m_adapterMap->erase(plugin);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
delete ((Plugin *)plugin);
}
void
PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
{
if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() ||
!m_pluginOutputs[plugin]) {
m_pluginOutputs[plugin] = new Plugin::OutputList
(plugin->getOutputDescriptors());
// std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
}
}
unsigned int
PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
{
checkOutputMap(plugin);
return m_pluginOutputs[plugin]->size();
}
VampOutputDescriptor *
PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
unsigned int i)
{
checkOutputMap(plugin);
Plugin::OutputDescriptor &od =
(*m_pluginOutputs[plugin])[i];
VampOutputDescriptor *desc = (VampOutputDescriptor *)
malloc(sizeof(VampOutputDescriptor));
desc->identifier = strdup(od.identifier.c_str());
desc->name = strdup(od.name.c_str());
desc->description = strdup(od.description.c_str());
desc->unit = strdup(od.unit.c_str());
desc->hasFixedBinCount = od.hasFixedBinCount;
desc->binCount = od.binCount;
if (od.hasFixedBinCount && od.binCount > 0) {
desc->binNames = (const char **)
malloc(od.binCount * sizeof(const char *));
for (unsigned int i = 0; i < od.binCount; ++i) {
if (i < od.binNames.size()) {
desc->binNames[i] = strdup(od.binNames[i].c_str());
} else {
desc->binNames[i] = 0;
}
}
} else {
desc->binNames = 0;
}
desc->hasKnownExtents = od.hasKnownExtents;
desc->minValue = od.minValue;
desc->maxValue = od.maxValue;
desc->isQuantized = od.isQuantized;
desc->quantizeStep = od.quantizeStep;
switch (od.sampleType) {
case Plugin::OutputDescriptor::OneSamplePerStep:
desc->sampleType = vampOneSamplePerStep; break;
case Plugin::OutputDescriptor::FixedSampleRate:
desc->sampleType = vampFixedSampleRate; break;
case Plugin::OutputDescriptor::VariableSampleRate:
desc->sampleType = vampVariableSampleRate; break;
}
desc->sampleRate = od.sampleRate;
return desc;
}
VampFeatureList *
PluginAdapterBase::Impl::process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec)
{
// std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
RealTime rt(sec, nsec);
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->process(inputBuffers, rt));
}
VampFeatureList *
PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
{
// std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->getRemainingFeatures());
}
VampFeatureList *
PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features)
{
int lastN = -1;
int outputCount = 0;
if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
resizeFS(plugin, outputCount);
VampFeatureList *fs = m_fs[plugin];
for (Plugin::FeatureSet::const_iterator fi = features.begin();
fi != features.end(); ++fi) {
int n = fi->first;
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
if (n >= int(outputCount)) {
std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
continue;
}
if (n > lastN + 1) {
for (int i = lastN + 1; i < n; ++i) {
fs[i].featureCount = 0;
}
}
const Plugin::FeatureList &fl = fi->second;
size_t sz = fl.size();
if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
fs[n].featureCount = sz;
for (size_t j = 0; j < sz; ++j) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
VampFeature *feature = &fs[n].features[j];
feature->hasTimestamp = fl[j].hasTimestamp;
feature->sec = fl[j].timestamp.sec;
feature->nsec = fl[j].timestamp.nsec;
feature->valueCount = fl[j].values.size();
if (feature->label) free(feature->label);
if (fl[j].label.empty()) {
feature->label = 0;
} else {
feature->label = strdup(fl[j].label.c_str());
}
if (feature->valueCount > m_fvsizes[plugin][n][j]) {
resizeFV(plugin, n, j, feature->valueCount);
}
for (unsigned int k = 0; k < feature->valueCount; ++k) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
feature->values[k] = fl[j].values[k];
}
}
lastN = n;
}
if (lastN == -1) return 0;
if (int(outputCount) > lastN + 1) {
for (int i = lastN + 1; i < int(outputCount); ++i) {
fs[i].featureCount = 0;
}
}
return fs;
}
void
PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
int i = m_fsizes[plugin].size();
if (i >= n) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin] = (VampFeatureList *)realloc
(m_fs[plugin], n * sizeof(VampFeatureList));
while (i < n) {
m_fs[plugin][i].featureCount = 0;
m_fs[plugin][i].features = 0;
m_fsizes[plugin].push_back(0);
m_fvsizes[plugin].push_back(std::vector<size_t>());
i++;
}
}
void
PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
// << sz << ")" << std::endl;
size_t i = m_fsizes[plugin][n];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features = (VampFeature *)realloc
(m_fs[plugin][n].features, sz * sizeof(VampFeature));
while (m_fsizes[plugin][n] < sz) {
m_fs[plugin][n].features[m_fsizes[plugin][n]].valueCount = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].values = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].label = 0;
m_fvsizes[plugin][n].push_back(0);
m_fsizes[plugin][n]++;
}
}
void
PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
// << j << ", " << sz << ")" << std::endl;
size_t i = m_fvsizes[plugin][n][j];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features[j].values = (float *)realloc
(m_fs[plugin][n].features[j].values, sz * sizeof(float));
m_fvsizes[plugin][n][j] = sz;
}
PluginAdapterBase::Impl::AdapterMap *
PluginAdapterBase::Impl::m_adapterMap = 0;
}

View file

@ -0,0 +1,117 @@
/* -*- 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_PLUGIN_ADAPTER_H_
#define _VAMP_PLUGIN_ADAPTER_H_
#include <vamp/vamp.h>
#include "Plugin.h"
#include <map>
namespace Vamp {
/**
* \class PluginAdapterBase PluginAdapter.h <vamp-sdk/PluginAdapter.h>
*
* PluginAdapter and PluginAdapterBase provide a wrapper class that a
* plugin library can use to make its C++ Vamp::Plugin objects
* available through the Vamp C API.
*
* Almost all Vamp plugin libraries will want to make use of this. To
* do so, all they need to do is declare a PluginAdapter<T> for each
* plugin class T in their library. It's very simple, and you need to
* know absolutely nothing about how it works in order to use it.
* Just cut and paste from an existing plugin's discovery function.
* \see vampGetPluginDescriptor
*/
class PluginAdapterBase
{
public:
virtual ~PluginAdapterBase();
/**
* Return a VampPluginDescriptor describing the plugin that is
* wrapped by this adapter.
*/
const VampPluginDescriptor *getDescriptor();
protected:
PluginAdapterBase();
virtual Plugin *createPlugin(float inputSampleRate) = 0;
class Impl;
Impl *m_impl;
};
/**
* \class PluginAdapter PluginAdapter.h <vamp-sdk/PluginAdapter.h>
*
* PluginAdapter turns a PluginAdapterBase into a specific wrapper for
* a particular plugin implementation.
*
* See PluginAdapterBase.
*/
template <typename P>
class PluginAdapter : public PluginAdapterBase
{
public:
PluginAdapter() : PluginAdapterBase() { }
virtual ~PluginAdapter() { }
protected:
Plugin *createPlugin(float inputSampleRate) {
P *p = new P(inputSampleRate);
Plugin *plugin = dynamic_cast<Plugin *>(p);
if (!plugin) {
std::cerr << "ERROR: PluginAdapter::createPlugin: "
<< "Template type is not a plugin!"
<< std::endl;
delete p;
return 0;
}
return plugin;
}
};
}
#endif

View file

@ -0,0 +1,252 @@
/* -*- 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_PLUGIN_BASE_H_
#define _VAMP_PLUGIN_BASE_H_
#include <string>
#include <vector>
#define VAMP_SDK_VERSION "1.1"
namespace Vamp {
/**
* A base class for plugins with optional configurable parameters,
* programs, etc. The Vamp::Plugin is derived from this, and
* individual Vamp plugins should derive from that.
*
* This class does not provide the necessary interfaces to instantiate
* or run a plugin. It only specifies an interface for retrieving
* those controls that the host may wish to show to the user for
* editing. It could meaningfully be subclassed by real-time plugins
* or other sorts of plugin as well as Vamp plugins.
*/
class PluginBase
{
public:
virtual ~PluginBase() { }
/**
* Get the Vamp API compatibility level of the plugin.
*/
virtual unsigned int getVampApiVersion() const { return 1; }
/**
* Get the computer-usable name of the plugin. This should be
* reasonably short and contain no whitespace or punctuation
* characters. It may only contain the characters [a-zA-Z0-9_].
* This is the authoritative way for a program to identify a
* plugin within a given library.
*
* This text may be visible to the user, but it should not be the
* main text used to identify a plugin to the user (that will be
* the name, below).
*
* Example: "zero_crossings"
*/
virtual std::string getIdentifier() const = 0;
/**
* Get a human-readable name or title of the plugin. This
* should be brief and self-contained, as it may be used to
* identify the plugin to the user in isolation (i.e. without also
* showing the plugin's "identifier").
*
* Example: "Zero Crossings"
*/
virtual std::string getName() const = 0;
/**
* Get a human-readable description for the plugin, typically
* a line of text that may optionally be displayed in addition
* to the plugin's "name". May be empty if the name has said
* it all already.
*
* Example: "Detect and count zero crossing points"
*/
virtual std::string getDescription() const = 0;
/**
* Get the name of the author or vendor of the plugin in
* human-readable form. This should be a short identifying text,
* as it may be used to label plugins from the same source in a
* menu or similar.
*/
virtual std::string getMaker() const = 0;
/**
* Get the copyright statement or licensing summary for the
* plugin. This can be an informative text, without the same
* presentation constraints as mentioned for getMaker above.
*/
virtual std::string getCopyright() const = 0;
/**
* Get the version number of the plugin.
*/
virtual int getPluginVersion() const = 0;
struct ParameterDescriptor
{
/**
* The name of the parameter, in computer-usable form. Should
* be reasonably short, and may only contain the characters
* [a-zA-Z0-9_].
*/
std::string identifier;
/**
* The human-readable name of the parameter.
*/
std::string name;
/**
* A human-readable short text describing the parameter. May be
* empty if the name has said it all already.
*/
std::string description;
/**
* The unit of the parameter, in human-readable form.
*/
std::string unit;
/**
* The minimum value of the parameter.
*/
float minValue;
/**
* The maximum value of the parameter.
*/
float maxValue;
/**
* The default value of the parameter. The plugin should
* ensure that parameters have this value on initialisation
* (i.e. the host is not required to explicitly set parameters
* if it wants to use their default values).
*/
float defaultValue;
/**
* True if the parameter values are quantized to a particular
* resolution.
*/
bool isQuantized;
/**
* Quantization resolution of the parameter values (e.g. 1.0
* if they are all integers). Undefined if isQuantized is
* false.
*/
float quantizeStep;
/**
* Names for the quantized values. If isQuantized is true,
* this may either be empty or contain one string for each of
* the quantize steps from minValue up to maxValue inclusive.
* Undefined if isQuantized is false.
*
* If these names are provided, they should be shown to the
* user in preference to the values themselves. The user may
* never see the actual numeric values unless they are also
* encoded in the names.
*/
std::vector<std::string> valueNames;
};
typedef std::vector<ParameterDescriptor> ParameterList;
/**
* Get the controllable parameters of this plugin.
*/
virtual ParameterList getParameterDescriptors() const {
return ParameterList();
}
/**
* Get the value of a named parameter. The argument is the identifier
* field from that parameter's descriptor.
*/
virtual float getParameter(std::string) const { return 0.0; }
/**
* Set a named parameter. The first argument is the identifier field
* from that parameter's descriptor.
*/
virtual void setParameter(std::string, float) { }
typedef std::vector<std::string> ProgramList;
/**
* Get the program settings available in this plugin. A program
* is a named shorthand for a set of parameter values; changing
* the program may cause the plugin to alter the values of its
* published parameters (and/or non-public internal processing
* parameters). The host should re-read the plugin's parameter
* values after setting a new program.
*
* The programs must have unique names.
*/
virtual ProgramList getPrograms() const { return ProgramList(); }
/**
* Get the current program.
*/
virtual std::string getCurrentProgram() const { return ""; }
/**
* Select a program. (If the given program name is not one of the
* available programs, do nothing.)
*/
virtual void selectProgram(std::string) { }
/**
* Get the type of plugin. This is to be implemented by the
* immediate subclass, not by actual plugins. Do not attempt to
* implement this in plugin code.
*/
virtual std::string getType() const = 0;
};
}
#endif

View file

@ -0,0 +1,418 @@
/* -*- 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.
*/
#include "PluginHostAdapter.h"
namespace Vamp
{
PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate) :
Plugin(inputSampleRate),
m_descriptor(descriptor)
{
// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
if (!m_handle) {
// std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
}
}
PluginHostAdapter::~PluginHostAdapter()
{
// std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
if (m_handle) m_descriptor->cleanup(m_handle);
}
std::vector<std::string>
PluginHostAdapter::getPluginPath()
{
std::vector<std::string> path;
std::string envPath;
char *cpath = getenv("VAMP_PATH");
if (cpath) envPath = cpath;
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
#else
#define PATH_SEPARATOR ':'
#ifdef __APPLE__
#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
#else
#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
#endif
#endif
if (envPath == "") {
envPath = DEFAULT_VAMP_PATH;
char *chome = getenv("HOME");
if (chome) {
std::string home(chome);
std::string::size_type f;
while ((f = envPath.find("$HOME")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 5, home);
}
}
#ifdef _WIN32
char *cpfiles = getenv("ProgramFiles");
if (!cpfiles) cpfiles = "C:\\Program Files";
std::string pfiles(cpfiles);
std::string::size_type f;
while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 14, pfiles);
}
#endif
}
std::string::size_type index = 0, newindex = 0;
while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
path.push_back(envPath.substr(index, newindex - index));
index = newindex + 1;
}
path.push_back(envPath.substr(index));
return path;
}
bool
PluginHostAdapter::initialise(size_t channels,
size_t stepSize,
size_t blockSize)
{
if (!m_handle) return false;
return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ?
true : false;
}
void
PluginHostAdapter::reset()
{
if (!m_handle) return;
m_descriptor->reset(m_handle);
}
PluginHostAdapter::InputDomain
PluginHostAdapter::getInputDomain() const
{
if (m_descriptor->inputDomain == vampFrequencyDomain) {
return FrequencyDomain;
} else {
return TimeDomain;
}
}
unsigned int
PluginHostAdapter::getVampApiVersion() const
{
return m_descriptor->vampApiVersion;
}
std::string
PluginHostAdapter::getIdentifier() const
{
return m_descriptor->identifier;
}
std::string
PluginHostAdapter::getName() const
{
return m_descriptor->name;
}
std::string
PluginHostAdapter::getDescription() const
{
return m_descriptor->description;
}
std::string
PluginHostAdapter::getMaker() const
{
return m_descriptor->maker;
}
int
PluginHostAdapter::getPluginVersion() const
{
return m_descriptor->pluginVersion;
}
std::string
PluginHostAdapter::getCopyright() const
{
return m_descriptor->copyright;
}
PluginHostAdapter::ParameterList
PluginHostAdapter::getParameterDescriptors() const
{
ParameterList list;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
const VampParameterDescriptor *spd = m_descriptor->parameters[i];
ParameterDescriptor pd;
pd.identifier = spd->identifier;
pd.name = spd->name;
pd.description = spd->description;
pd.unit = spd->unit;
pd.minValue = spd->minValue;
pd.maxValue = spd->maxValue;
pd.defaultValue = spd->defaultValue;
pd.isQuantized = spd->isQuantized;
pd.quantizeStep = spd->quantizeStep;
if (pd.isQuantized && spd->valueNames) {
for (unsigned int j = 0; spd->valueNames[j]; ++j) {
pd.valueNames.push_back(spd->valueNames[j]);
}
}
list.push_back(pd);
}
return list;
}
float
PluginHostAdapter::getParameter(std::string param) const
{
if (!m_handle) return 0.0;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
return m_descriptor->getParameter(m_handle, i);
}
}
return 0.0;
}
void
PluginHostAdapter::setParameter(std::string param,
float value)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
m_descriptor->setParameter(m_handle, i, value);
return;
}
}
}
PluginHostAdapter::ProgramList
PluginHostAdapter::getPrograms() const
{
ProgramList list;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
list.push_back(m_descriptor->programs[i]);
}
return list;
}
std::string
PluginHostAdapter::getCurrentProgram() const
{
if (!m_handle) return "";
int pn = m_descriptor->getCurrentProgram(m_handle);
return m_descriptor->programs[pn];
}
void
PluginHostAdapter::selectProgram(std::string program)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
if (program == m_descriptor->programs[i]) {
m_descriptor->selectProgram(m_handle, i);
return;
}
}
}
size_t
PluginHostAdapter::getPreferredStepSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredStepSize(m_handle);
}
size_t
PluginHostAdapter::getPreferredBlockSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredBlockSize(m_handle);
}
size_t
PluginHostAdapter::getMinChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMinChannelCount(m_handle);
}
size_t
PluginHostAdapter::getMaxChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMaxChannelCount(m_handle);
}
PluginHostAdapter::OutputList
PluginHostAdapter::getOutputDescriptors() const
{
OutputList list;
if (!m_handle) {
// std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
return list;
}
unsigned int count = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < count; ++i) {
VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
OutputDescriptor d;
d.identifier = sd->identifier;
d.name = sd->name;
d.description = sd->description;
d.unit = sd->unit;
d.hasFixedBinCount = sd->hasFixedBinCount;
d.binCount = sd->binCount;
if (d.hasFixedBinCount) {
for (unsigned int j = 0; j < sd->binCount; ++j) {
d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
}
}
d.hasKnownExtents = sd->hasKnownExtents;
d.minValue = sd->minValue;
d.maxValue = sd->maxValue;
d.isQuantized = sd->isQuantized;
d.quantizeStep = sd->quantizeStep;
switch (sd->sampleType) {
case vampOneSamplePerStep:
d.sampleType = OutputDescriptor::OneSamplePerStep; break;
case vampFixedSampleRate:
d.sampleType = OutputDescriptor::FixedSampleRate; break;
case vampVariableSampleRate:
d.sampleType = OutputDescriptor::VariableSampleRate; break;
}
d.sampleRate = sd->sampleRate;
list.push_back(d);
m_descriptor->releaseOutputDescriptor(sd);
}
return list;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::process(const float *const *inputBuffers,
RealTime timestamp)
{
FeatureSet fs;
if (!m_handle) return fs;
int sec = timestamp.sec;
int nsec = timestamp.nsec;
VampFeatureList *features = m_descriptor->process(m_handle,
inputBuffers,
sec, nsec);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::getRemainingFeatures()
{
FeatureSet fs;
if (!m_handle) return fs;
VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
void
PluginHostAdapter::convertFeatures(VampFeatureList *features,
FeatureSet &fs)
{
if (!features) return;
unsigned int outputs = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < outputs; ++i) {
VampFeatureList &list = features[i];
if (list.featureCount > 0) {
for (unsigned int j = 0; j < list.featureCount; ++j) {
Feature feature;
feature.hasTimestamp = list.features[j].hasTimestamp;
feature.timestamp = RealTime(list.features[j].sec,
list.features[j].nsec);
for (unsigned int k = 0; k < list.features[j].valueCount; ++k) {
feature.values.push_back(list.features[j].values[k]);
}
if (list.features[j].label) {
feature.label = list.features[j].label;
}
fs[i].push_back(feature);
}
}
}
}
}

View file

@ -0,0 +1,117 @@
/* -*- 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_PLUGIN_HOST_ADAPTER_H_
#define _VAMP_PLUGIN_HOST_ADAPTER_H_
#include <vamp/vamp.h>
#include <vamp-sdk/Plugin.h>
#include <vector>
namespace Vamp {
/**
* \class PluginHostAdapter PluginHostAdapter.h <vamp-sdk/PluginHostAdapter.h>
*
* PluginHostAdapter is a wrapper class that a Vamp host can use to
* make the C-language VampPluginDescriptor object appear as a C++
* Vamp::Plugin object.
*
* The Vamp API is defined in vamp/vamp.h as a C API. The C++ objects
* used for convenience by plugins and hosts actually communicate
* using the C low-level API, but the details of this communication
* are handled seamlessly by the Vamp SDK implementation provided the
* plugin and host use the proper C++ wrapper objects.
*
* See also PluginAdapter, the plugin-side wrapper that makes a C++
* plugin object available using the C query API.
*/
class PluginHostAdapter : public Plugin
{
public:
PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate);
virtual ~PluginHostAdapter();
static std::vector<std::string> getPluginPath();
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();
protected:
void convertFeatures(VampFeatureList *, FeatureSet &);
const VampPluginDescriptor *m_descriptor;
VampPluginHandle m_handle;
};
}
#endif

View file

@ -0,0 +1,254 @@
/* -*- 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.
*/
/*
This is a modified version of a source file from the
Rosegarden MIDI and audio sequencer and notation editor.
This file copyright 2000-2006 Chris Cannam.
Relicensed by the author as detailed above.
*/
#include <iostream>
#if (__GNUC__ < 3)
#include <strstream>
#define stringstream strstream
#else
#include <sstream>
#endif
using std::cerr;
using std::endl;
#include "RealTime.h"
#ifndef _WIN32
#include <sys/time.h>
#endif
namespace Vamp {
// A RealTime consists of two ints that must be at least 32 bits each.
// A signed 32-bit int can store values exceeding +/- 2 billion. This
// means we can safely use our lower int for nanoseconds, as there are
// 1 billion nanoseconds in a second and we need to handle double that
// because of the implementations of addition etc that we use.
//
// The maximum valid RealTime on a 32-bit system is somewhere around
// 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
#define ONE_BILLION 1000000000
RealTime::RealTime(int s, int n) :
sec(s), nsec(n)
{
if (sec == 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
} else if (sec < 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
} else {
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
while (nsec < 0) { nsec += ONE_BILLION; --sec; }
}
}
RealTime
RealTime::fromSeconds(double sec)
{
return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
}
RealTime
RealTime::fromMilliseconds(int msec)
{
return RealTime(msec / 1000, (msec % 1000) * 1000000);
}
#ifndef _WIN32
RealTime
RealTime::fromTimeval(const struct timeval &tv)
{
return RealTime(tv.tv_sec, tv.tv_usec * 1000);
}
#endif
std::ostream &operator<<(std::ostream &out, const RealTime &rt)
{
if (rt < RealTime::zeroTime) {
out << "-";
} else {
out << " ";
}
int s = (rt.sec < 0 ? -rt.sec : rt.sec);
int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
out << s << ".";
int nn(n);
if (nn == 0) out << "00000000";
else while (nn < (ONE_BILLION / 10)) {
out << "0";
nn *= 10;
}
out << n << "R";
return out;
}
std::string
RealTime::toString() const
{
std::stringstream out;
out << *this;
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
// remove trailing R
return s.substr(0, s.length() - 1);
}
std::string
RealTime::toText(bool fixedDp) const
{
if (*this < RealTime::zeroTime) return "-" + (-*this).toText();
std::stringstream out;
if (sec >= 3600) {
out << (sec / 3600) << ":";
}
if (sec >= 60) {
out << (sec % 3600) / 60 << ":";
}
if (sec >= 10) {
out << ((sec % 60) / 10);
}
out << (sec % 10);
int ms = msec();
if (ms != 0) {
out << ".";
out << (ms / 100);
ms = ms % 100;
if (ms != 0) {
out << (ms / 10);
ms = ms % 10;
} else if (fixedDp) {
out << "0";
}
if (ms != 0) {
out << ms;
} else if (fixedDp) {
out << "0";
}
} else if (fixedDp) {
out << ".000";
}
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
return s;
}
RealTime
RealTime::operator/(int d) const
{
int secdiv = sec / d;
int secrem = sec % d;
double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
return RealTime(secdiv, int(nsecdiv + 0.5));
}
double
RealTime::operator/(const RealTime &r) const
{
double lTotal = double(sec) * ONE_BILLION + double(nsec);
double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
if (rTotal == 0) return 0.0;
else return lTotal/rTotal;
}
long
RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
{
if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
// We like integers. The last term is always zero unless the
// sample rate is greater than 1MHz, but hell, you never know...
long frame =
time.sec * sampleRate +
(time.msec() * sampleRate) / 1000 +
((time.usec() - 1000 * time.msec()) * sampleRate) / 1000000 +
((time.nsec - 1000 * time.usec()) * sampleRate) / 1000000000;
return frame;
}
RealTime
RealTime::frame2RealTime(long frame, unsigned int sampleRate)
{
if (frame < 0) return -frame2RealTime(-frame, sampleRate);
RealTime rt;
rt.sec = frame / long(sampleRate);
frame -= rt.sec * long(sampleRate);
rt.nsec = (int)(((float(frame) * 1000000) / long(sampleRate)) * 1000);
return rt;
}
const RealTime RealTime::zeroTime(0,0);
}

View file

@ -0,0 +1,154 @@
/* -*- 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.
*/
/*
This is a modified version of a source file from the
Rosegarden MIDI and audio sequencer and notation editor.
This file copyright 2000-2006 Chris Cannam.
Relicensed by the author as detailed above.
*/
#ifndef _VAMP_REAL_TIME_H_
#define _VAMP_REAL_TIME_H_
#include <iostream>
#include <string>
#ifndef _WIN32
struct timeval;
#endif
namespace Vamp {
/**
* \class RealTime RealTime.h <vamp-sdk/RealTime.h>
*
* RealTime represents time values to nanosecond precision
* with accurate arithmetic and frame-rate conversion functions.
*/
struct RealTime
{
int sec;
int nsec;
int usec() const { return nsec / 1000; }
int msec() const { return nsec / 1000000; }
RealTime(): sec(0), nsec(0) {}
RealTime(int s, int n);
RealTime(const RealTime &r) :
sec(r.sec), nsec(r.nsec) { }
static RealTime fromSeconds(double sec);
static RealTime fromMilliseconds(int msec);
#ifndef _WIN32
static RealTime fromTimeval(const struct timeval &);
#endif
RealTime &operator=(const RealTime &r) {
sec = r.sec; nsec = r.nsec; return *this;
}
RealTime operator+(const RealTime &r) const {
return RealTime(sec + r.sec, nsec + r.nsec);
}
RealTime operator-(const RealTime &r) const {
return RealTime(sec - r.sec, nsec - r.nsec);
}
RealTime operator-() const {
return RealTime(-sec, -nsec);
}
bool operator <(const RealTime &r) const {
if (sec == r.sec) return nsec < r.nsec;
else return sec < r.sec;
}
bool operator >(const RealTime &r) const {
if (sec == r.sec) return nsec > r.nsec;
else return sec > r.sec;
}
bool operator==(const RealTime &r) const {
return (sec == r.sec && nsec == r.nsec);
}
bool operator!=(const RealTime &r) const {
return !(r == *this);
}
bool operator>=(const RealTime &r) const {
if (sec == r.sec) return nsec >= r.nsec;
else return sec >= r.sec;
}
bool operator<=(const RealTime &r) const {
if (sec == r.sec) return nsec <= r.nsec;
else return sec <= r.sec;
}
RealTime operator/(int d) const;
// Find the fractional difference between times
//
double operator/(const RealTime &r) const;
// Return a human-readable debug-type string to full precision
// (probably not a format to show to a user directly)
//
std::string toString() const;
// Return a user-readable string to the nearest millisecond
// in a form like HH:MM:SS.mmm
//
std::string toText(bool fixedDp = false) const;
// Convenience functions for handling sample frames
//
static long realTime2Frame(const RealTime &r, unsigned int sampleRate);
static RealTime frame2RealTime(long frame, unsigned int sampleRate);
static const RealTime zeroTime;
};
std::ostream &operator<<(std::ostream &out, const RealTime &rt);
}
#endif

View file

@ -0,0 +1,120 @@
/** \mainpage Vamp Plugin SDK
\section about About Vamp
Vamp is an API for C and C++ plugins that process sampled audio data
to produce descriptive output (measurements or semantic observations).
Find more information at http://www.vamp-plugins.org/ .
Although the official API for Vamp plugins is defined in C for maximum
binary compatibility, we strongly recommend using the provided C++
classes in the SDK to implement your own plugins and hosts.
\section plugins For Plugins
Plugins should subclass Vamp::Plugin, and then use a
Vamp::PluginAdapter to expose the correct C API for the plugin. Read
the documentation for Vamp::PluginBase and Vamp::Plugin before
starting.
Plugins should be compiled and linked into dynamic libraries using the
usual convention for your platform, and should link (preferably
statically) with -lvamp-sdk. Any number of plugins can reside in a
single dynamic library. See plugins.cpp in the example plugins
directory for the sort of code that will need to accompany your plugin
class or classes, to make it possible for a host to look up your
plugins properly.
The following example plugins are provided:
- ZeroCrossing calculates the positions and density of zero-crossing
points in an audio waveform.
- SpectralCentroid calculates the centre of gravity of the frequency
domain representation of each block of audio.
- AmplitudeFollower is an implementation of SuperCollider's
amplitude-follower algorithm as a simple Vamp plugin.
- PercussionOnsetDetector estimates the locations of percussive
onsets using a simple method described in "Drum Source Separation
using Percussive Feature Detection and Spectral Modulation" by Dan
Barry, Derry Fitzgerald, Eugene Coyle and Bob Lawlor, ISSC 2005.
\section hosts For Hosts
Hosts will normally use a Vamp::PluginHostAdapter to convert each
plugin's exposed C API back into a useful Vamp::Plugin C++ object.
Starting with version 1.1 of the Vamp SDK, there are several classes
in the Vamp::HostExt namespace that aim to make the host's life as
easy as possible:
- Vamp::HostExt::PluginLoader provides a very simple interface for a
host to discover, load, and find out category information about the
available plugins. Most "casual" Vamp hosts will probably want to
use this class.
- Vamp::HostExt::PluginInputDomainAdapter provides a simple means for
hosts to handle plugins that expect frequency-domain input, without
having to convert the input themselves.
- Vamp::HostExt::PluginChannelAdapter provides a simple means for
hosts to use plugins that do not necessarily support the same number
of audio channels as they have available, without having to apply a
channel management / mixdown policy themselves.
The PluginLoader class can also use the input domain and channel
adapters automatically to make the entire conversion process
transparent to the host if required.
Hosts should link with -lvamp-hostsdk.
(The following notes in this section are mostly relevant for
developers that are not using the HostExt classes, or that wish to
know more about the policy they implement.)
The Vamp API does not officially specify how to load plugin libraries
or where to find them. However, the SDK does include a function
(Vamp::PluginHostAdapter::getPluginPath()) that returns a recommended
directory search path that hosts may use for plugin libraries.
Our suggestion for a host is to search each directory in this path for
.DLL (on Windows), .so (on Linux, Solaris, BSD etc) or .dylib (on
OS/X) files, then to load each one and perform a dynamic name lookup
on the vampGetPluginDescriptor function to enumerate the plugins in
the library. The example host has some code that may help, but this
operation will necessarily be system-dependent.
Vamp also has an informal convention for sorting plugins into
functional categories. In addition to the library file itself, a
plugin library may install a category file with the same name as the
library but .cat extension. The existence and format of this file are
not specified by the Vamp API, but by convention the file may contain
lines of the format
\code
vamp:pluginlibrary:pluginname::General Category > Specific Category
\endcode
which a host may read and use to assign plugins a location within a
category tree for display to the user. The expectation is that
advanced users may also choose to set up their own preferred category
trees, which is why this information is not queried as part of the
Vamp API itself.
There is an example host in the "host" directory from which code may
be drawn.
\section license License
This plugin SDK is freely redistributable under a "new-style BSD"
licence. See the file COPYING for more details. In short, you may
modify and redistribute the SDK and example plugins within any
commercial or non-commercial, proprietary or open-source plugin or
application under almost any conditions, with no obligation to provide
source code, provided you retain the original copyright note.
*/

View file

@ -0,0 +1,228 @@
/* -*- 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 "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);
protected:
Plugin *m_plugin;
size_t m_blockSize;
size_t m_inputChannels;
size_t m_pluginChannels;
float **m_buffer;
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::Impl::Impl(Plugin *plugin) :
m_plugin(plugin),
m_blockSize(0),
m_inputChannels(0),
m_pluginChannels(0),
m_buffer(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_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::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);
}
}
}
}

View file

@ -0,0 +1,128 @@
/* -*- 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);
protected:
class Impl;
Impl *m_impl;
};
}
}
#endif

View file

@ -0,0 +1,458 @@
/* -*- 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 "PluginInputDomainAdapter.h"
#include <cmath>
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);
protected:
Plugin *m_plugin;
float m_inputSampleRate;
size_t m_channels;
size_t m_blockSize;
float **m_freqbuf;
double *m_ri;
double *m_ro;
double *m_io;
void fft(unsigned int n, bool inverse,
double *ri, double *ii, double *ro, double *io);
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);
}
PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputSampleRate(inputSampleRate),
m_channels(0),
m_blockSize(0),
m_freqbuf(0)
{
}
PluginInputDomainAdapter::Impl::~Impl()
{
// the adapter will delete the plugin
if (m_channels > 0) {
for (size_t c = 0; c < m_channels; ++c) {
delete[] m_freqbuf[c];
}
delete[] m_freqbuf;
delete[] m_ri;
delete[] m_ro;
delete[] m_io;
}
}
bool
PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (m_plugin->getInputDomain() == TimeDomain) {
m_blockSize = blockSize;
m_channels = 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 (size_t c = 0; c < m_channels; ++c) {
delete[] m_freqbuf[c];
}
delete[] m_freqbuf;
delete[] m_ri;
delete[] m_ro;
delete[] m_io;
}
m_blockSize = blockSize;
m_channels = channels;
m_freqbuf = new float *[m_channels];
for (size_t c = 0; c < m_channels; ++c) {
m_freqbuf[c] = new float[m_blockSize + 2];
}
m_ri = new double[m_blockSize];
m_ro = new double[m_blockSize];
m_io = new double[m_blockSize];
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)) {
// not a power of two, can't handle that with our current 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;
}
return blockSize;
}
// for some visual studii apparently
#ifndef M_PI
#define M_PI 3.14159265358979232846
#endif
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 + RealTime::frame2RealTime
(m_blockSize/2, int(m_inputSampleRate + 0.5));
// std::cerr << " to " << timestamp << std::endl;
for (size_t c = 0; c < m_channels; ++c) {
for (size_t i = 0; i < m_blockSize; ++i) {
// Hanning window
m_ri[i] = double(inputBuffers[c][i])
* (0.50 - 0.50 * cos((2 * M_PI * i)
/ m_blockSize));
}
for (size_t 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;
}
fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
for (size_t i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = m_ro[i];
m_freqbuf[c][i * 2 + 1] = m_io[i];
}
}
return m_plugin->process(m_freqbuf, timestamp);
}
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;
}
}
}
}
}

View file

@ -0,0 +1,103 @@
/* -*- 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);
protected:
class Impl;
Impl *m_impl;
};
}
}
#endif

View file

@ -0,0 +1,601 @@
/* -*- 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-sdk/PluginHostAdapter.h"
#include "PluginLoader.h"
#include "PluginInputDomainAdapter.h"
#include "PluginChannelAdapter.h"
#include <fstream>
#include <cctype> // tolower
#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);
protected:
class PluginDeletionNotifyAdapter : public PluginWrapper {
public:
PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
virtual ~PluginDeletionNotifyAdapter();
protected:
Impl *m_loader;
};
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);
};
PluginLoader *
PluginLoader::m_instance = 0;
PluginLoader::PluginLoader()
{
m_impl = new Impl();
}
PluginLoader::~PluginLoader()
{
delete m_impl;
}
PluginLoader *
PluginLoader::getInstance()
{
if (!m_instance) m_instance = new PluginLoader();
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()
{
}
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_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);
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_type & DT_REG) || !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);
}
}
}

View file

@ -0,0 +1,218 @@
/* -*- 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_ALL - Perform all available adaptations, where meaningful.
*
* See PluginInputDomainAdapter and PluginChannelAdapter 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_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

View file

@ -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 "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();
}
}
}

View file

@ -0,0 +1,106 @@
/* -*- 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-sdk/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();
protected:
PluginWrapper(Plugin *plugin); // I take ownership of plugin
Plugin *m_plugin;
};
}
}
#endif

View file

@ -0,0 +1,9 @@
dlname='%LINK_ABI%'
library_names='%LIBNAME% %LINK_ABI% %LINK_DEV%'
old_library='%STATIC%'
dependency_libs=''
current=2
age=0
revision=0
installed=yes
libdir='%LIBS%'

View file

@ -0,0 +1,9 @@
dlname='%LINK_ABI%'
library_names='%LIBNAME% %LINK_ABI% %LINK_DEV%'
old_library='%STATIC%'
dependency_libs=''
current=1
age=1
revision=0
installed=yes
libdir='%LIBS%'

View file

@ -0,0 +1,10 @@
prefix=%PREFIX%
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: vamp-hostsdk
Version: 1.1.0
Description: Development library for Vamp audio analysis plugin hosts
Libs: -L${libdir} -lvamp-hostsdk
Cflags: -I${includedir}

View file

@ -0,0 +1,10 @@
prefix=%PREFIX%
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: vamp-sdk
Version: 1.1.0
Description: Development library for Vamp audio analysis plugins
Libs: -L${libdir} -lvamp-sdk
Cflags: -I${includedir}

339
libs/vamp-sdk/vamp/vamp.h Normal file
View file

@ -0,0 +1,339 @@
/* -*- 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_HEADER_INCLUDED
#define VAMP_HEADER_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/**
* Plugin API version. This is incremented when a change is made that
* changes the binary layout of the descriptor records. When this
* happens, there should be a mechanism for retaining compatibility
* with older hosts and/or plugins.
*
* See also the vampApiVersion field in the plugin descriptor, and the
* hostApiVersion argument to the vampGetPluginDescriptor function.
*/
#define VAMP_API_VERSION 1
/**
* C language API for Vamp plugins.
*
* This is the formal plugin API for Vamp. Plugin authors may prefer
* to use the C++ classes provided in the Vamp plugin SDK, instead of
* using this API directly. There is an adapter class provided that
* makes C++ plugins available using this C API with relatively little
* work, and the C++ headers are more thoroughly documented.
*
* IMPORTANT: The comments in this file summarise the purpose of each
* of the declared fields and functions, but do not provide a complete
* guide to their permitted values and expected usage. Please refer
* to the C++ headers in the Vamp plugin SDK for further details and
* plugin lifecycle documentation.
*/
typedef struct _VampParameterDescriptor
{
/** Computer-usable name of the parameter. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the parameter. May be translatable. */
const char *name;
/** Human-readable short text about the parameter. May be translatable. */
const char *description;
/** Human-readable unit of the parameter. */
const char *unit;
/** Minimum value. */
float minValue;
/** Maximum value. */
float maxValue;
/** Default value. Plugin is responsible for setting this on initialise. */
float defaultValue;
/** 1 if parameter values are quantized to a particular resolution. */
int isQuantized;
/** Quantization resolution, if isQuantized. */
float quantizeStep;
/** Human-readable names of the values, if isQuantized. May be NULL. */
const char **valueNames;
} VampParameterDescriptor;
typedef enum
{
/** Each process call returns results aligned with call's block start. */
vampOneSamplePerStep,
/** Returned results are evenly spaced at samplerate specified below. */
vampFixedSampleRate,
/** Returned results have their own individual timestamps. */
vampVariableSampleRate
} VampSampleType;
typedef struct _VampOutputDescriptor
{
/** Computer-usable name of the output. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the output. May be translatable. */
const char *name;
/** Human-readable short text about the output. May be translatable. */
const char *description;
/** Human-readable name of the unit of the output. */
const char *unit;
/** 1 if output has equal number of values for each returned result. */
int hasFixedBinCount;
/** Number of values per result, if hasFixedBinCount. */
unsigned int binCount;
/** Names of returned value bins, if hasFixedBinCount. May be NULL. */
const char **binNames;
/** 1 if each returned value falls within the same fixed min/max range. */
int hasKnownExtents;
/** Minimum value for a returned result in any bin, if hasKnownExtents. */
float minValue;
/** Maximum value for a returned result in any bin, if hasKnownExtents. */
float maxValue;
/** 1 if returned results are quantized to a particular resolution. */
int isQuantized;
/** Quantization resolution for returned results, if isQuantized. */
float quantizeStep;
/** Time positioning method for returned results (see VampSampleType). */
VampSampleType sampleType;
/** Sample rate of returned results, if sampleType is vampFixedSampleRate.
"Resolution" of result, if sampleType is vampVariableSampleRate. */
float sampleRate;
} VampOutputDescriptor;
typedef struct _VampFeature
{
/** 1 if the feature has a timestamp (i.e. if vampVariableSampleRate). */
int hasTimestamp;
/** Seconds component of timestamp. */
int sec;
/** Nanoseconds component of timestamp. */
int nsec;
/** Number of values. Must be binCount if hasFixedBinCount. */
unsigned int valueCount;
/** Values for this returned sample. */
float *values;
/** Label for this returned sample. May be NULL. */
char *label;
} VampFeature;
typedef struct _VampFeatureList
{
/** Number of features in this feature list. */
unsigned int featureCount;
/** Features in this feature list. May be NULL if featureCount is zero. */
VampFeature *features;
} VampFeatureList;
typedef enum
{
vampTimeDomain,
vampFrequencyDomain
} VampInputDomain;
typedef void *VampPluginHandle;
typedef struct _VampPluginDescriptor
{
/** API version with which this descriptor is compatible. */
unsigned int vampApiVersion;
/** Computer-usable name of the plugin. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the plugin. May be translatable. */
const char *name;
/** Human-readable short text about the plugin. May be translatable. */
const char *description;
/** Human-readable name of plugin's author or vendor. */
const char *maker;
/** Version number of the plugin. */
int pluginVersion;
/** Human-readable summary of copyright or licensing for plugin. */
const char *copyright;
/** Number of parameter inputs. */
unsigned int parameterCount;
/** Fixed descriptors for parameter inputs. */
const VampParameterDescriptor **parameters;
/** Number of programs. */
unsigned int programCount;
/** Fixed names for programs. */
const char **programs;
/** Preferred input domain for audio input (time or frequency). */
VampInputDomain inputDomain;
/** Create and return a new instance of this plugin. */
VampPluginHandle (*instantiate)(const struct _VampPluginDescriptor *,
float inputSampleRate);
/** Destroy an instance of this plugin. */
void (*cleanup)(VampPluginHandle);
/** Initialise an instance following parameter configuration. */
int (*initialise)(VampPluginHandle,
unsigned int inputChannels,
unsigned int stepSize,
unsigned int blockSize);
/** Reset an instance, ready to use again on new input data. */
void (*reset)(VampPluginHandle);
/** Get a parameter value. */
float (*getParameter)(VampPluginHandle, int);
/** Set a parameter value. May only be called before initialise. */
void (*setParameter)(VampPluginHandle, int, float);
/** Get the current program (if programCount > 0). */
unsigned int (*getCurrentProgram)(VampPluginHandle);
/** Set the current program. May only be called before initialise. */
void (*selectProgram)(VampPluginHandle, unsigned int);
/** Get the plugin's preferred processing window increment in samples. */
unsigned int (*getPreferredStepSize)(VampPluginHandle);
/** Get the plugin's preferred processing window size in samples. */
unsigned int (*getPreferredBlockSize)(VampPluginHandle);
/** Get the minimum number of input channels this plugin can handle. */
unsigned int (*getMinChannelCount)(VampPluginHandle);
/** Get the maximum number of input channels this plugin can handle. */
unsigned int (*getMaxChannelCount)(VampPluginHandle);
/** Get the number of feature outputs (distinct sets of results). */
unsigned int (*getOutputCount)(VampPluginHandle);
/** Get a descriptor for a given feature output. Returned pointer
is valid only until next call to getOutputDescriptor for this
handle, or releaseOutputDescriptor for this descriptor. Host
must call releaseOutputDescriptor after use. */
VampOutputDescriptor *(*getOutputDescriptor)(VampPluginHandle,
unsigned int);
/** Destroy a descriptor for a feature output. */
void (*releaseOutputDescriptor)(VampOutputDescriptor *);
/** Process an input block and return a set of features. Returned
pointer is valid only until next call to process,
getRemainingFeatures, or cleanup for this handle, or
releaseFeatureSet for this feature set. Host must call
releaseFeatureSet after use. */
VampFeatureList *(*process)(VampPluginHandle,
const float *const *inputBuffers,
int sec,
int nsec);
/** Return any remaining features at the end of processing. */
VampFeatureList *(*getRemainingFeatures)(VampPluginHandle);
/** Release a feature set returned from process or getRemainingFeatures. */
void (*releaseFeatureSet)(VampFeatureList *);
} VampPluginDescriptor;
/** Get the descriptor for a given plugin index in this library.
Return NULL if the index is outside the range of valid indices for
this plugin library.
The hostApiVersion argument tells the library code the highest
Vamp API version supported by the host. The function should
return a plugin descriptor compatible with the highest API version
supported by the library that is no higher than that supported by
the host. Provided the descriptor has the correct vampApiVersion
field for its actual compatibility level, the host should be able
to do the right thing with it: use it if possible, discard it
otherwise.
*/
const VampPluginDescriptor *vampGetPluginDescriptor
(unsigned int hostApiVersion, unsigned int index);
/** Function pointer type for vampGetPluginDescriptor. */
typedef const VampPluginDescriptor *(*VampGetPluginDescriptorFunction)
(unsigned int, unsigned int);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,10 @@
prefix=%PREFIX%
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: vamp
Version: 1.0
Description: An API for audio analysis and feature extraction plugins
Libs:
Cflags: -I${includedir}