From e95b339dbbd0757328f7e811294bb7b8871f8cff Mon Sep 17 00:00:00 2001 From: chatlanin Date: Thu, 8 Aug 2024 11:53:48 +0300 Subject: [PATCH] base rename --- host/system.h | 50 - host/test-c.c | 40 - host/vamp-simple-host.cpp | 863 --------- src/meson.build | 10 +- src/vamp-hostsdk/Files.cpp | 2 +- src/vamp-hostsdk/Files.h | 3 - src/vamp-hostsdk/PluginBufferingAdapter.cpp | 1338 +++++++------ src/vamp-hostsdk/PluginBufferingAdapter.h | 165 +- src/vamp-hostsdk/PluginChannelAdapter.cpp | 345 ++-- src/vamp-hostsdk/PluginChannelAdapter.h | 109 +- src/vamp-hostsdk/PluginHostAdapter.cpp | 640 +++---- src/vamp-hostsdk/PluginHostAdapter.h | 88 +- src/vamp-hostsdk/PluginInputDomainAdapter.cpp | 870 +++++---- src/vamp-hostsdk/PluginInputDomainAdapter.h | 208 +- src/vamp-hostsdk/PluginLoader.cpp | 955 +++++----- src/vamp-hostsdk/PluginLoader.h | 253 +-- src/vamp-hostsdk/PluginSummarisingAdapter.cpp | 1504 +++++++-------- src/vamp-hostsdk/PluginSummarisingAdapter.h | 145 +- src/vamp-hostsdk/PluginWrapper.cpp | 198 +- src/vamp-hostsdk/PluginWrapper.h | 98 +- src/vamp-hostsdk/Window.h | 4 +- src/vamp-hostsdk/acsymbols.cpp | 16 - src/vamp-hostsdk/host-c.cpp | 12 +- src/vamp-hostsdk/vamp-hostsdk.h | 46 +- src/vamp-sdk/FFT.cpp | 3 +- src/vamp-sdk/FFT.h | 3 +- src/vamp-sdk/Plugin.h | 481 +---- src/vamp-sdk/PluginAdapter.cpp | 1684 ++++++++--------- src/vamp-sdk/PluginAdapter.h | 96 +- src/vamp-sdk/PluginBase.h | 218 --- src/vamp-sdk/RealTime.cpp | 199 -- src/vamp-sdk/RealTime.h | 114 -- src/vamp-sdk/acsymbols.cpp | 16 - src/vamp-sdk/base_plugin.hpp | 46 + src/vamp-sdk/real_time/real_time.cpp | 160 ++ src/vamp-sdk/real_time/real_time.hpp | 99 + test/main.cpp | 104 +- 37 files changed, 4225 insertions(+), 6960 deletions(-) delete mode 100644 host/system.h delete mode 100644 host/test-c.c delete mode 100644 host/vamp-simple-host.cpp delete mode 100644 src/vamp-hostsdk/acsymbols.cpp delete mode 100644 src/vamp-sdk/PluginBase.h delete mode 100644 src/vamp-sdk/RealTime.cpp delete mode 100644 src/vamp-sdk/RealTime.h delete mode 100644 src/vamp-sdk/acsymbols.cpp create mode 100644 src/vamp-sdk/base_plugin.hpp create mode 100644 src/vamp-sdk/real_time/real_time.cpp create mode 100644 src/vamp-sdk/real_time/real_time.hpp diff --git a/host/system.h b/host/system.h deleted file mode 100644 index 170b6dd..0000000 --- a/host/system.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 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_ - -#include - -#define DLOPEN(a,b) dlopen((a).c_str(),(b)) -#define DLSYM(a,b) dlsym((a),(b)) -#define DLCLOSE(a) dlclose((a)) -#define DLERROR() dlerror() -#define PLUGIN_SUFFIX "so" -#define HAVE_OPENDIR 1 - -#endif - diff --git a/host/test-c.c b/host/test-c.c deleted file mode 100644 index 196ad51..0000000 --- a/host/test-c.c +++ /dev/null @@ -1,40 +0,0 @@ - -#include - -#include - -int main(int argc, char **argv) -{ - int i; - int libcount = vhGetLibraryCount(); - - printf("Vamp plugin libraries found:\n"); - for (i = 0; i < libcount; ++i) { - printf("%d: %s\n", i, vhGetLibraryName(i)); - } - - printf("Going to try loading qm-vamp-plugins...\n"); - int libindex = vhGetLibraryIndex("qm-vamp-plugins"); - vhLibrary lib = vhLoadLibrary(libindex); - if (!lib) { - printf("Failure!\n"); - return 1; - } - - int plugincount = vhGetPluginCount(lib); - printf("Success: it contains %d plugins; they are:\n", plugincount); - - for (i = 0; i < plugincount; ++i) { - const VampPluginDescriptor *descriptor = vhGetPluginDescriptor(lib, i); - if (!descriptor) { - printf("\n"); - } else { - printf("%s\n", descriptor->identifier); - } - } - - vhUnloadLibrary(lib); - - return 0; -} - diff --git a/host/vamp-simple-host.cpp b/host/vamp-simple-host.cpp deleted file mode 100644 index e47ac52..0000000 --- a/host/vamp-simple-host.cpp +++ /dev/null @@ -1,863 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam, copyright 2007-2008 QMUL. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - - -/* - * This "simple" Vamp plugin host is no longer as simple as it was; it - * now has a lot of options and includes a lot of code to handle the - * various useful listing modes it supports. - * - * However, the runPlugin function still contains a reasonable - * implementation of a fairly generic Vamp plugin host capable of - * evaluating a given output on a given plugin for a sound file read - * via libsndfile. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "system.h" - -#include - -using namespace std; - -using Vamp::Plugin; -using Vamp::PluginHostAdapter; -using Vamp::RealTime; -using Vamp::HostExt::PluginLoader; -using Vamp::HostExt::PluginWrapper; -using Vamp::HostExt::PluginInputDomainAdapter; - -#define HOST_VERSION "1.5" - -enum Verbosity { - PluginIds, - PluginOutputIds, - PluginInformation, - PluginInformationDetailed -}; - -void printFeatures(int, int, - const Plugin::OutputDescriptor &, int, - const Plugin::FeatureSet &, ofstream *, bool frames); -void transformInput(float *, size_t); -void fft(unsigned int, bool, double *, double *, double *, double *); -void printPluginPath(bool verbose); -void printPluginCategoryList(); -void enumeratePlugins(Verbosity); -void listPluginsInLibrary(string soname); -int runPlugin(string myname, string soname, string id, string output, - int outputNo, string inputFile, string outfilename, bool frames); - -void usage(const char *name) -{ - cerr << "\n" - << name << ": A command-line host for Vamp audio analysis plugins.\n\n" - "Centre for Digital Music, Queen Mary, University of London.\n" - "Copyright 2006-2009 Chris Cannam and QMUL.\n" - "Freely redistributable; published under a BSD-style license.\n\n" - "Usage:\n\n" - " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" - " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.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 \"out.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" - " If the -s option is given, results will be labelled with the audio\n" - " sample frame at which they occur. Otherwise, they will be labelled\n" - " with time in seconds.\n\n" - " " << name << " -l\n" - " " << name << " --list\n\n" - " -- List the plugin libraries and Vamp plugins in the library search path\n" - " in a verbose human-readable format.\n\n" - " " << name << " -L\n" - " " << name << " --list-full\n\n" - " -- List all data reported by all the Vamp plugins in the library search\n" - " path in a very verbose human-readable format.\n\n" - " " << name << " --list-ids\n\n" - " -- List the plugins in the search path in a terse machine-readable format,\n" - " in the form vamp:soname:identifier.\n\n" - " " << name << " --list-outputs\n\n" - " -- List the outputs for plugins in the search path in a machine-readable\n" - " format, in the form vamp:soname:identifier:output.\n\n" - " " << name << " --list-by-category\n\n" - " -- List the plugins as a plugin index by category, in a machine-readable\n" - " format. The format may change in future releases.\n\n" - " " << name << " -p\n\n" - " -- Print out the Vamp library search path.\n\n" - " " << name << " -v\n\n" - " -- Display version information only.\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") || !strcmp(argv[1], "--list")) { - - printPluginPath(true); - enumeratePlugins(PluginInformation); - return 0; - - } else if (!strcmp(argv[1], "-L") || !strcmp(argv[1], "--list-full")) { - - enumeratePlugins(PluginInformationDetailed); - return 0; - - } else if (!strcmp(argv[1], "-p")) { - - printPluginPath(false); - return 0; - - } else if (!strcmp(argv[1], "--list-ids")) { - - enumeratePlugins(PluginIds); - return 0; - - } else if (!strcmp(argv[1], "--list-outputs")) { - - enumeratePlugins(PluginOutputIds); - return 0; - - } else if (!strcmp(argv[1], "--list-by-category")) { - - printPluginCategoryList(); - return 0; - - } else usage(name); - } - - if (argc < 3) usage(name); - - bool useFrames = false; - - int base = 1; - if (!strcmp(argv[1], "-s")) { - useFrames = true; - base = 2; - } - - string soname = argv[base]; - string wavname = argv[base+1]; - string plugid = ""; - string output = ""; - int outputNo = -1; - string outfilename; - - if (argc >= base+3) { - - int idx = base+2; - - 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, useFrames); -} - - -int runPlugin(string myname, string soname, string id, - string output, int outputNo, string wavname, - string outfilename, bool useFrames) -{ - 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; - } - } - - Plugin *plugin = loader->loadPlugin - (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); - 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; - - // Note that the following would be much simpler if we used a - // PluginBufferingAdapter as well -- i.e. if we had passed - // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead - // of ADAPT_ALL_SAFE. Then we could simply specify our own block - // size, keep the step size equal to the block size, and ignore - // the plugin's bleatings. However, there are some issues with - // using a PluginBufferingAdapter that make the results sometimes - // technically different from (if effectively the same as) the - // un-adapted plugin, so we aren't doing that here. See the - // PluginBufferingAdapter documentation for details. - - int blockSize = plugin->getPreferredBlockSize(); - int stepSize = plugin->getPreferredStepSize(); - - if (blockSize == 0) { - blockSize = 1024; - } - if (stepSize == 0) { - if (plugin->getInputDomain() == Plugin::FrequencyDomain) { - stepSize = blockSize/2; - } else { - stepSize = blockSize; - } - } else if (stepSize > blockSize) { - cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; - if (plugin->getInputDomain() == Plugin::FrequencyDomain) { - blockSize = stepSize * 2; - } else { - blockSize = stepSize; - } - cerr << blockSize << endl; - } - int overlapSize = blockSize - stepSize; - sf_count_t currentStep = 0; - int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF - - 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; - - // The channel queries here are for informational purposes only -- - // a PluginChannelAdapter is being used automatically behind the - // scenes, and it will take case of any channel mismatch - - 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; - - Plugin::OutputList outputs = plugin->getOutputDescriptors(); - Plugin::OutputDescriptor od; - Plugin::FeatureSet features; - - int returnValue = 1; - int progress = 0; - - RealTime rt; - PluginWrapper *wrapper = 0; - RealTime adjustment = RealTime::zeroTime; - - 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; - } - - wrapper = dynamic_cast(plugin); - if (wrapper) { - // See documentation for - // PluginInputDomainAdapter::getTimestampAdjustment - PluginInputDomainAdapter *ida = - wrapper->getWrapper(); - if (ida) adjustment = ida->getTimestampAdjustment(); - } - - // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input. - do { - - int count; - - if ((blockSize==stepSize) || (currentStep==0)) { - // read a full fresh block - if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { - cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; - break; - } - if (count != blockSize) --finalStepsRemaining; - } else { - // otherwise shunt the existing data down and read the remainder. - memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float)); - if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) { - cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; - break; - } - if (count != stepSize) --finalStepsRemaining; - count += overlapSize; - } - - 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; - } - } - - rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); - - features = plugin->process(plugbuf, rt); - - printFeatures - (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), - sfinfo.samplerate, od, outputNo, features, out, useFrames); - - if (sfinfo.frames > 0){ - int pp = progress; - progress = (int)((float(currentStep * stepSize) / sfinfo.frames) * 100.f + 0.5f); - if (progress != pp && out) { - cerr << "\r" << progress << "%"; - } - } - - ++currentStep; - - } while (finalStepsRemaining > 0); - - if (out) cerr << "\rDone" << endl; - - rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); - - features = plugin->getRemainingFeatures(); - - printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), - sfinfo.samplerate, od, outputNo, features, out, useFrames); - - returnValue = 0; - -done: - delete plugin; - if (out) { - out->close(); - delete out; - } - sf_close(sndfile); - return returnValue; -} - -static double -toSeconds(const RealTime &time) -{ - return time.sec + double(time.nsec + 1) / 1000000000.0; -} - -void -printFeatures(int frame, int sr, - const Plugin::OutputDescriptor &output, int outputNo, - const Plugin::FeatureSet &features, ofstream *out, bool useFrames) -{ - static int featureCount = -1; - - if (features.find(outputNo) == features.end()) return; - - for (size_t i = 0; i < features.at(outputNo).size(); ++i) { - - const Plugin::Feature &f = features.at(outputNo).at(i); - - bool haveRt = false; - RealTime rt; - - if (output.sampleType == Plugin::OutputDescriptor::VariableSampleRate) { - rt = f.timestamp; - haveRt = true; - } else if (output.sampleType == Plugin::OutputDescriptor::FixedSampleRate) { - int n = featureCount + 1; - if (f.hasTimestamp) { - n = int(round(toSeconds(f.timestamp) * output.sampleRate)); - } - rt = RealTime::fromSeconds(double(n) / output.sampleRate); - haveRt = true; - featureCount = n; - } - - if (useFrames) { - - int displayFrame = frame; - - if (haveRt) { - displayFrame = RealTime::realTime2Frame(rt, sr); - } - - (out ? *out : cout) << displayFrame; - - if (f.hasDuration) { - displayFrame = RealTime::realTime2Frame(f.duration, sr); - (out ? *out : cout) << "," << displayFrame; - } - - (out ? *out : cout) << ":"; - - } else { - - if (!haveRt) { - rt = RealTime::frame2RealTime(frame, sr); - } - - (out ? *out : cout) << rt.toString(); - - if (f.hasDuration) { - rt = f.duration; - (out ? *out : cout) << "," << rt.toString(); - } - - (out ? *out : cout) << ":"; - } - - for (unsigned int j = 0; j < f.values.size(); ++j) { - (out ? *out : cout) << " " << f.values[j]; - } - (out ? *out : cout) << " " << f.label; - - (out ? *out : cout) << endl; - } -} - -void -printPluginPath(bool verbose) -{ - if (verbose) { - cout << "\nVamp plugin search path: "; - } - - vector path = 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; -} - -static -string -header(string text, int level) -{ - string out = '\n' + text + '\n'; - for (size_t i = 0; i < text.length(); ++i) { - out += (level == 1 ? '=' : level == 2 ? '-' : '~'); - } - out += '\n'; - return out; -} - -void -enumeratePlugins(Verbosity verbosity) -{ - PluginLoader *loader = PluginLoader::getInstance(); - - if (verbosity == PluginInformation) { - cout << "\nVamp plugin libraries found in search path:" << endl; - } - - vector plugins = loader->listPlugins(); - typedef multimap - LibraryMap; - LibraryMap libraryMap; - - for (size_t i = 0; i < plugins.size(); ++i) { - string path = loader->getLibraryPathForPlugin(plugins[i]); - libraryMap.insert(LibraryMap::value_type(path, plugins[i])); - } - - string prevPath = ""; - int index = 0; - - for (LibraryMap::iterator i = libraryMap.begin(); - i != libraryMap.end(); ++i) { - - string path = i->first; - PluginLoader::PluginKey key = i->second; - - if (path != prevPath) { - prevPath = path; - index = 0; - if (verbosity == PluginInformation) { - cout << "\n " << path << ":" << endl; - } else if (verbosity == PluginInformationDetailed) { - string::size_type ki = i->second.find(':'); - string text = "Library \"" + i->second.substr(0, ki) + "\""; - cout << "\n" << header(text, 1); - } - } - - Plugin *plugin = loader->loadPlugin(key, 48000); - if (plugin) { - - char c = char('A' + index); - if (c > 'Z') c = char('a' + (index - 26)); - - PluginLoader::PluginCategoryHierarchy category = - loader->getPluginCategory(key); - string catstr; - if (!category.empty()) { - for (size_t ci = 0; ci < category.size(); ++ci) { - if (ci > 0) catstr += " > "; - catstr += category[ci]; - } - } - - if (verbosity == PluginInformation) { - - cout << " [" << c << "] [v" - << plugin->getVampApiVersion() << "] " - << plugin->getName() << ", \"" - << plugin->getIdentifier() << "\"" << " [" - << plugin->getMaker() << "]" << endl; - - if (catstr != "") { - cout << " > " << catstr << endl; - } - - if (plugin->getDescription() != "") { - cout << " - " << plugin->getDescription() << endl; - } - - } else if (verbosity == PluginInformationDetailed) { - - cout << header(plugin->getName(), 2); - cout << " - Identifier: " - << key << endl; - cout << " - Plugin Version: " - << plugin->getPluginVersion() << endl; - cout << " - Vamp API Version: " - << plugin->getVampApiVersion() << endl; - cout << " - Maker: \"" - << plugin->getMaker() << "\"" << endl; - cout << " - Copyright: \"" - << plugin->getCopyright() << "\"" << endl; - cout << " - Description: \"" - << plugin->getDescription() << "\"" << endl; - cout << " - Input Domain: " - << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? - "Time Domain" : "Frequency Domain") << endl; - cout << " - Default Step Size: " - << plugin->getPreferredStepSize() << endl; - cout << " - Default Block Size: " - << plugin->getPreferredBlockSize() << endl; - cout << " - Minimum Channels: " - << plugin->getMinChannelCount() << endl; - cout << " - Maximum Channels: " - << plugin->getMaxChannelCount() << endl; - - } else if (verbosity == PluginIds) { - cout << "vamp:" << key << endl; - } - - Plugin::OutputList outputs = - plugin->getOutputDescriptors(); - - if (verbosity == PluginInformationDetailed) { - - Plugin::ParameterList params = plugin->getParameterDescriptors(); - for (size_t j = 0; j < params.size(); ++j) { - Plugin::ParameterDescriptor &pd(params[j]); - cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; - cout << " - Identifier: " << pd.identifier << endl; - cout << " - Description: \"" << pd.description << "\"" << endl; - if (pd.unit != "") { - cout << " - Unit: " << pd.unit << endl; - } - cout << " - Range: "; - cout << pd.minValue << " -> " << pd.maxValue << endl; - cout << " - Default: "; - cout << pd.defaultValue << endl; - if (pd.isQuantized) { - cout << " - Quantize Step: " - << pd.quantizeStep << endl; - } - if (!pd.valueNames.empty()) { - cout << " - Value Names: "; - for (size_t k = 0; k < pd.valueNames.size(); ++k) { - if (k > 0) cout << ", "; - cout << "\"" << pd.valueNames[k] << "\""; - } - cout << endl; - } - } - - if (outputs.empty()) { - cout << "\n** Note: This plugin reports no outputs!" << endl; - } - for (size_t j = 0; j < outputs.size(); ++j) { - Plugin::OutputDescriptor &od(outputs[j]); - cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; - cout << " - Identifier: " << od.identifier << endl; - cout << " - Description: \"" << od.description << "\"" << endl; - if (od.unit != "") { - cout << " - Unit: " << od.unit << endl; - } - if (od.hasFixedBinCount) { - cout << " - Default Bin Count: " << od.binCount << endl; - } - if (!od.binNames.empty()) { - bool have = false; - for (size_t k = 0; k < od.binNames.size(); ++k) { - if (od.binNames[k] != "") { - have = true; break; - } - } - if (have) { - cout << " - Bin Names: "; - for (size_t k = 0; k < od.binNames.size(); ++k) { - if (k > 0) cout << ", "; - cout << "\"" << od.binNames[k] << "\""; - } - cout << endl; - } - } - if (od.hasKnownExtents) { - cout << " - Default Extents: "; - cout << od.minValue << " -> " << od.maxValue << endl; - } - if (od.isQuantized) { - cout << " - Quantize Step: " - << od.quantizeStep << endl; - } - cout << " - Sample Type: " - << (od.sampleType == - Plugin::OutputDescriptor::OneSamplePerStep ? - "One Sample Per Step" : - od.sampleType == - Plugin::OutputDescriptor::FixedSampleRate ? - "Fixed Sample Rate" : - "Variable Sample Rate") << endl; - if (od.sampleType != - Plugin::OutputDescriptor::OneSamplePerStep) { - cout << " - Default Rate: " - << od.sampleRate << endl; - } - cout << " - Has Duration: " - << (od.hasDuration ? "Yes" : "No") << endl; - } - } - - if (outputs.size() > 1 || verbosity == PluginOutputIds) { - for (size_t j = 0; j < outputs.size(); ++j) { - if (verbosity == PluginInformation) { - cout << " (" << j << ") " - << outputs[j].name << ", \"" - << outputs[j].identifier << "\"" << endl; - if (outputs[j].description != "") { - cout << " - " - << outputs[j].description << endl; - } - } else if (verbosity == PluginOutputIds) { - cout << "vamp:" << key << ":" << outputs[j].identifier << endl; - } - } - } - - ++index; - - delete plugin; - } - } - - if (verbosity == PluginInformation || - verbosity == PluginInformationDetailed) { - cout << endl; - } -} - -void -printPluginCategoryList() -{ - PluginLoader *loader = PluginLoader::getInstance(); - - vector plugins = loader->listPlugins(); - - set printedcats; - - for (size_t i = 0; i < plugins.size(); ++i) { - - PluginLoader::PluginKey key = plugins[i]; - - PluginLoader::PluginCategoryHierarchy category = - loader->getPluginCategory(key); - - Plugin *plugin = loader->loadPlugin(key, 48000); - if (!plugin) continue; - - string catstr = ""; - - if (category.empty()) catstr = '|'; - else { - for (size_t j = 0; j < category.size(); ++j) { - catstr += category[j]; - catstr += '|'; - if (printedcats.find(catstr) == printedcats.end()) { - std::cout << catstr << std::endl; - printedcats.insert(catstr); - } - } - } - - std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl; - } -} - diff --git a/src/meson.build b/src/meson.build index 90c293b..b37c2fc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,8 @@ inc += include_directories('.') headers = [ + 'vamp-sdk/real_time/real_time.hpp', + 'vamp.h', 'vamp-hostsdk/Files.h', 'vamp-hostsdk/host-c.h', @@ -17,17 +19,15 @@ headers = [ 'vamp-sdk/ext/vamp_kiss_fft.h', 'vamp-sdk/ext/vamp_kiss_fft_guts.h', 'vamp-sdk/ext/vamp_kiss_fftr.h', - 'vamp-sdk/FFT.h', 'vamp-sdk/Plugin.h', 'vamp-sdk/PluginAdapter.h', - 'vamp-sdk/PluginBase.h', - 'vamp-sdk/RealTime.h', 'vamp-sdk/vamp-sdk.h' ] sources = [ - 'vamp-hostsdk/acsymbols.cpp', + 'vamp-sdk/real_time/real_time.cpp', + 'vamp-hostsdk/Files.cpp', 'vamp-hostsdk/host-c.cpp', 'vamp-hostsdk/PluginBufferingAdapter.cpp', @@ -38,10 +38,8 @@ sources = [ 'vamp-hostsdk/PluginSummarisingAdapter.cpp', 'vamp-hostsdk/PluginWrapper.cpp', - 'vamp-sdk/acsymbols.cpp', 'vamp-sdk/FFT.cpp', 'vamp-sdk/PluginAdapter.cpp', - 'vamp-sdk/RealTime.cpp' ] lib = library( diff --git a/src/vamp-hostsdk/Files.cpp b/src/vamp-hostsdk/Files.cpp index 5049eb5..731c683 100644 --- a/src/vamp-hostsdk/Files.cpp +++ b/src/vamp-hostsdk/Files.cpp @@ -18,7 +18,7 @@ std::vector Files::listLibraryFiles() std::vector Files::listLibraryFilesMatching(Filter filter) { - std::vector path = Vamp::PluginHostAdapter::getPluginPath(); + std::vector path = vamp::PluginHostAdapter::getPluginPath(); std::vector libraryFiles; // we match case-insensitively, but only with ascii range diff --git a/src/vamp-hostsdk/Files.h b/src/vamp-hostsdk/Files.h index 8b42b73..93e5ebd 100644 --- a/src/vamp-hostsdk/Files.h +++ b/src/vamp-hostsdk/Files.h @@ -3,9 +3,6 @@ #include #include -/** - * This is a private implementation class for the Vamp Host SDK. - */ class Files { public: diff --git a/src/vamp-hostsdk/PluginBufferingAdapter.cpp b/src/vamp-hostsdk/PluginBufferingAdapter.cpp index cb17d07..b88fba3 100644 --- a/src/vamp-hostsdk/PluginBufferingAdapter.cpp +++ b/src/vamp-hostsdk/PluginBufferingAdapter.cpp @@ -5,718 +5,708 @@ #include "vamp-hostsdk/PluginInputDomainAdapter.h" #include -using std::cerr; -using std::endl; using std::vector; using std::map; -namespace Vamp { - -namespace HostExt { - -class PluginBufferingAdapter::Impl +namespace vamp::host { -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); - - void setPluginStepSize(size_t stepSize); - void setPluginBlockSize(size_t blockSize); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - - OutputList getOutputDescriptors() const; - - void setParameter(std::string, float); - void selectProgram(std::string); - - void reset(); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - FeatureSet getRemainingFeatures(); - -protected: - class RingBuffer - { + class PluginBufferingAdapter::Impl + { public: - RingBuffer(int n) : - m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } - virtual ~RingBuffer() { delete[] m_buffer; } + Impl(plugin* p, float inputSampleRate); + ~Impl(); + + void setPluginStepSize(size_t stepSize); + void setPluginBlockSize(size_t blockSize); - int getSize() const { return m_size-1; } - void reset() { m_writer = 0; m_reader = 0; } + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - int getReadSpace() const { - int writer = m_writer, reader = m_reader, space; - if (writer > reader) space = writer - reader; - else if (writer < reader) space = (writer + m_size) - reader; - else space = 0; - return space; - } + void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - int getWriteSpace() const { - int writer = m_writer; - int reader = m_reader; - int space = (reader + m_size - writer - 1); - if (space >= m_size) space -= m_size; - return space; - } - - int peek(float *destination, int n) const { + OutputList getOutputDescriptors() const; - int available = getReadSpace(); + void setParameter(std::string, float); + void selectProgram(std::string); - if (n > available) { - for (int i = available; i < n; ++i) { - destination[i] = 0.f; - } - n = available; - } - if (n == 0) return n; - - int reader = m_reader; - int here = m_size - reader; - const float *const bufbase = m_buffer + reader; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - destination[i] = bufbase[i]; - } - } else { - for (int i = 0; i < here; ++i) { - destination[i] = bufbase[i]; - } - float *const destbase = destination + here; - const int nh = n - here; - for (int i = 0; i < nh; ++i) { - destbase[i] = m_buffer[i]; - } - } - - return n; - } - - int skip(int n) { - - int available = getReadSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int reader = m_reader; - reader += n; - while (reader >= m_size) reader -= m_size; - m_reader = reader; - return n; - } - - int write(const float *source, int n) { - - int available = getWriteSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int writer = m_writer; - int here = m_size - writer; - float *const bufbase = m_buffer + writer; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - bufbase[i] = source[i]; - } - } else { - for (int i = 0; i < here; ++i) { - bufbase[i] = source[i]; - } - const int nh = n - here; - const float *const srcbase = source + here; - float *const buf = m_buffer; - for (int i = 0; i < nh; ++i) { - buf[i] = srcbase[i]; - } - } - - writer += n; - while (writer >= m_size) writer -= m_size; - m_writer = writer; - - return n; - } - - int zero(int n) { - - int available = getWriteSpace(); - if (n > available) { - n = available; - } - if (n == 0) return n; - - int writer = m_writer; - int here = m_size - writer; - float *const bufbase = m_buffer + writer; - - if (here >= n) { - for (int i = 0; i < n; ++i) { - bufbase[i] = 0.f; - } - } else { - for (int i = 0; i < here; ++i) { - bufbase[i] = 0.f; - } - const int nh = n - here; - for (int i = 0; i < nh; ++i) { - m_buffer[i] = 0.f; - } - } - - writer += n; - while (writer >= m_size) writer -= m_size; - m_writer = writer; - - return n; - } + void reset(); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + + FeatureSet getRemainingFeatures(); + protected: - float *m_buffer; - int m_writer; - int m_reader; - int m_size; + class RingBuffer + { + public: + RingBuffer(int n) : + m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } + virtual ~RingBuffer() { delete[] m_buffer; } - private: - RingBuffer(const RingBuffer &); // not provided - RingBuffer &operator=(const RingBuffer &); // not provided - }; + int getSize() const { return m_size-1; } + void reset() { m_writer = 0; m_reader = 0; } - Plugin *m_plugin; - size_t m_inputStepSize; // value passed to wrapper initialise() - size_t m_inputBlockSize; // value passed to wrapper initialise() - size_t m_setStepSize; // value passed to setPluginStepSize() - size_t m_setBlockSize; // value passed to setPluginBlockSize() - size_t m_stepSize; // value actually used to initialise plugin - size_t m_blockSize; // value actually used to initialise plugin - size_t m_channels; - vector m_queue; - float **m_buffers; - float m_inputSampleRate; - long m_frame; - bool m_unrun; - mutable OutputList m_outputs; - mutable std::map m_rewriteOutputTimes; - std::map m_fixedRateFeatureNos; // output no -> feature no - - void processBlock(FeatureSet& allFeatureSets); - void adjustFixedRateFeatureTime(int outputNo, Feature &); -}; - -PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin, m_inputSampleRate); -} - -PluginBufferingAdapter::~PluginBufferingAdapter() -{ - delete m_impl; -} + int getReadSpace() const { + int writer = m_writer, reader = m_reader, space; + if (writer > reader) space = writer - reader; + else if (writer < reader) space = (writer + m_size) - reader; + else space = 0; + return space; + } -size_t -PluginBufferingAdapter::getPreferredStepSize() const -{ - return getPreferredBlockSize(); -} + int getWriteSpace() const { + int writer = m_writer; + int reader = m_reader; + int space = (reader + m_size - writer - 1); + if (space >= m_size) space -= m_size; + return space; + } + + int peek(float *destination, int n) const { -size_t -PluginBufferingAdapter::getPreferredBlockSize() const -{ - return PluginWrapper::getPreferredBlockSize(); -} + int available = getReadSpace(); -size_t -PluginBufferingAdapter::getPluginPreferredStepSize() const -{ - return PluginWrapper::getPreferredStepSize(); -} + if (n > available) { + for (int i = available; i < n; ++i) { + destination[i] = 0.f; + } + n = available; + } + if (n == 0) return n; -size_t -PluginBufferingAdapter::getPluginPreferredBlockSize() const -{ - return PluginWrapper::getPreferredBlockSize(); -} + int reader = m_reader; + int here = m_size - reader; + const float *const bufbase = m_buffer + reader; -void -PluginBufferingAdapter::setPluginStepSize(size_t stepSize) -{ - m_impl->setPluginStepSize(stepSize); -} + if (here >= n) { + for (int i = 0; i < n; ++i) { + destination[i] = bufbase[i]; + } + } else { + for (int i = 0; i < here; ++i) { + destination[i] = bufbase[i]; + } + float *const destbase = destination + here; + const int nh = n - here; + for (int i = 0; i < nh; ++i) { + destbase[i] = m_buffer[i]; + } + } -void -PluginBufferingAdapter::setPluginBlockSize(size_t blockSize) -{ - m_impl->setPluginBlockSize(blockSize); -} + return n; + } -void -PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize, - size_t &blockSize) -{ - m_impl->getActualStepAndBlockSizes(stepSize, blockSize); -} - -bool -PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - return m_impl->initialise(channels, stepSize, blockSize); -} + int skip(int n) { + + int available = getReadSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; -PluginBufferingAdapter::OutputList -PluginBufferingAdapter::getOutputDescriptors() const -{ - return m_impl->getOutputDescriptors(); -} + int reader = m_reader; + reader += n; + while (reader >= m_size) reader -= m_size; + m_reader = reader; + return n; + } + + int write(const float *source, int n) { -void -PluginBufferingAdapter::setParameter(std::string name, float value) -{ - m_impl->setParameter(name, value); -} + int available = getWriteSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; -void -PluginBufferingAdapter::selectProgram(std::string name) -{ - m_impl->selectProgram(name); -} + int writer = m_writer; + int here = m_size - writer; + float *const bufbase = m_buffer + writer; + + if (here >= n) { + for (int i = 0; i < n; ++i) { + bufbase[i] = source[i]; + } + } else { + for (int i = 0; i < here; ++i) { + bufbase[i] = source[i]; + } + const int nh = n - here; + const float *const srcbase = source + here; + float *const buf = m_buffer; + for (int i = 0; i < nh; ++i) { + buf[i] = srcbase[i]; + } + } -void -PluginBufferingAdapter::reset() -{ - m_impl->reset(); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::process(const float *const *inputBuffers, - RealTime timestamp) -{ - return m_impl->process(inputBuffers, timestamp); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::getRemainingFeatures() -{ - return m_impl->getRemainingFeatures(); -} - -PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputStepSize(0), - m_inputBlockSize(0), - m_setStepSize(0), - m_setBlockSize(0), - m_stepSize(0), - m_blockSize(0), - m_channels(0), - m_queue(0), - m_buffers(0), - m_inputSampleRate(inputSampleRate), - m_frame(0), - m_unrun(true) -{ - (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes -} - -PluginBufferingAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; - for (size_t i = 0; i < m_channels; ++i) { - delete m_queue[i]; - delete[] m_buffers[i]; - } - delete[] m_buffers; -} - -void -PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize) -{ - if (m_inputStepSize != 0) { - std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl; - return; - } - m_setStepSize = stepSize; -} - -void -PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize) -{ - if (m_inputBlockSize != 0) { - std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl; - return; - } - m_setBlockSize = blockSize; -} + return n; + } -void -PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize, - size_t &blockSize) -{ - stepSize = m_stepSize; - blockSize = m_blockSize; -} + int zero(int n) { + + int available = getWriteSpace(); + if (n > available) { + n = available; + } + if (n == 0) return n; -bool -PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (stepSize != blockSize) { - std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; - return false; - } + int writer = m_writer; + int here = m_size - writer; + float *const bufbase = m_buffer + writer; - m_channels = channels; - m_inputStepSize = stepSize; - m_inputBlockSize = blockSize; + if (here >= n) { + for (int i = 0; i < n; ++i) { + bufbase[i] = 0.f; + } + } else { + for (int i = 0; i < here; ++i) { + bufbase[i] = 0.f; + } + const int nh = n - here; + for (int i = 0; i < nh; ++i) { + m_buffer[i] = 0.f; + } + } + + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; - // if the user has requested particular step or block sizes, use - // those; otherwise use the step and block sizes which the plugin - // prefers + return n; + } - m_stepSize = 0; - m_blockSize = 0; + protected: + float *m_buffer; + int m_writer; + int m_reader; + int m_size; - if (m_setStepSize > 0) { - m_stepSize = m_setStepSize; - } - if (m_setBlockSize > 0) { - m_blockSize = m_setBlockSize; - } + private: + RingBuffer(const RingBuffer &); // not provided + RingBuffer &operator=(const RingBuffer &); // not provided + }; - if (m_stepSize == 0 && m_blockSize == 0) { - m_stepSize = m_plugin->getPreferredStepSize(); - m_blockSize = m_plugin->getPreferredBlockSize(); - } + plugin* m_plugin; + size_t m_inputStepSize; // value passed to wrapper initialise() + size_t m_inputBlockSize; // value passed to wrapper initialise() + size_t m_setStepSize; // value passed to setPluginStepSize() + size_t m_setBlockSize; // value passed to setPluginBlockSize() + size_t m_stepSize; // value actually used to initialise plugin + size_t m_blockSize; // value actually used to initialise plugin + size_t m_channels; + vector m_queue; + float** m_buffers; + float m_inputSampleRate; + long m_frame; + bool m_unrun; + mutable OutputList m_outputs; + mutable std::map m_rewriteOutputTimes; + std::map m_fixedRateFeatureNos; // output no -> feature no + + void processBlock(FeatureSet& allFeatureSets); + void adjustFixedRateFeatureTime(int outputNo, Feature &); + }; + + PluginBufferingAdapter::PluginBufferingAdapter(plugin* p) : PluginWrapper(p) + { + m_impl = new Impl(p, m_inputSampleRate); + } + + PluginBufferingAdapter::~PluginBufferingAdapter() + { + delete m_impl; + } + + size_t + PluginBufferingAdapter::getPreferredStepSize() const + { + return getPreferredBlockSize(); + } + + size_t + PluginBufferingAdapter::getPreferredBlockSize() const + { + return PluginWrapper::getPreferredBlockSize(); + } + + size_t + PluginBufferingAdapter::getPluginPreferredStepSize() const + { + return PluginWrapper::getPreferredStepSize(); + } + + size_t + PluginBufferingAdapter::getPluginPreferredBlockSize() const + { + return PluginWrapper::getPreferredBlockSize(); + } + + void + PluginBufferingAdapter::setPluginStepSize(size_t stepSize) + { + m_impl->setPluginStepSize(stepSize); + } + + void + PluginBufferingAdapter::setPluginBlockSize(size_t blockSize) + { + m_impl->setPluginBlockSize(blockSize); + } + + void + PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize, + size_t &blockSize) + { + m_impl->getActualStepAndBlockSizes(stepSize, blockSize); + } + + bool + PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) + { + return m_impl->initialise(channels, stepSize, blockSize); + } + + PluginBufferingAdapter::OutputList + PluginBufferingAdapter::getOutputDescriptors() const + { + return m_impl->getOutputDescriptors(); + } + + void + PluginBufferingAdapter::setParameter(std::string name, float value) + { + m_impl->setParameter(name, value); + } + + void + PluginBufferingAdapter::selectProgram(std::string name) + { + m_impl->selectProgram(name); + } + + void + PluginBufferingAdapter::reset() + { + m_impl->reset(); + } + + PluginBufferingAdapter::FeatureSet + PluginBufferingAdapter::process(const float *const *inputBuffers, + real_time timestamp) + { + return m_impl->process(inputBuffers, timestamp); + } + + PluginBufferingAdapter::FeatureSet + PluginBufferingAdapter::getRemainingFeatures() + { + return m_impl->getRemainingFeatures(); + } + + PluginBufferingAdapter::Impl::Impl(plugin* p, float inputSampleRate) : + m_plugin(p), + m_inputStepSize(0), + m_inputBlockSize(0), + m_setStepSize(0), + m_setBlockSize(0), + m_stepSize(0), + m_blockSize(0), + m_channels(0), + m_queue(0), + m_buffers(0), + m_inputSampleRate(inputSampleRate), + m_frame(0), + m_unrun(true) + { + (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes + } + + PluginBufferingAdapter::Impl::~Impl() + { + // the adapter will delete the plugin + + for (size_t i = 0; i < m_channels; ++i) { + delete m_queue[i]; + delete[] m_buffers[i]; + } + delete[] m_buffers; + } + + void + PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize) + { + if (m_inputStepSize != 0) { + std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl; + return; + } + m_setStepSize = stepSize; + } + + void + PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize) + { + if (m_inputBlockSize != 0) { + std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl; + return; + } + m_setBlockSize = blockSize; + } + + void + PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize, + size_t &blockSize) + { + stepSize = m_stepSize; + blockSize = m_blockSize; + } + + bool + PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) + { + if (stepSize != blockSize) { + std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; + return false; + } + + m_channels = channels; + m_inputStepSize = stepSize; + m_inputBlockSize = blockSize; + + // if the user has requested particular step or block sizes, use + // those; otherwise use the step and block sizes which the plugin + // prefers + + m_stepSize = 0; + m_blockSize = 0; + + if (m_setStepSize > 0) { + m_stepSize = m_setStepSize; + } + if (m_setBlockSize > 0) { + m_blockSize = m_setBlockSize; + } + + if (m_stepSize == 0 && m_blockSize == 0) { + m_stepSize = m_plugin->getPreferredStepSize(); + m_blockSize = m_plugin->getPreferredBlockSize(); + } + + bool freq = (m_plugin->getInputDomain() == vamp::plugin::FrequencyDomain); + + // or sensible defaults if it has no preference + if (m_blockSize == 0) { + if (m_stepSize == 0) { + m_blockSize = 1024; + if (freq) { + m_stepSize = m_blockSize / 2; + } else { + m_stepSize = m_blockSize; + } + } else if (freq) { + m_blockSize = m_stepSize * 2; + } else { + m_blockSize = m_stepSize; + } + } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above) + if (freq) { + m_stepSize = m_blockSize/2; + } else { + m_stepSize = m_blockSize; + } + } + + // current implementation breaks if step is greater than block + if (m_stepSize > m_blockSize) { + size_t newBlockSize; + if (freq) { + newBlockSize = m_stepSize * 2; + } else { + newBlockSize = m_stepSize; + } + std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl; + m_blockSize = newBlockSize; + } + + // std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize + // << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; + + m_buffers = new float *[m_channels]; + + for (size_t i = 0; i < m_channels; ++i) { + m_queue.push_back(new RingBuffer(int(m_blockSize + m_inputBlockSize))); + m_buffers[i] = new float[m_blockSize]; + } + + bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize); + + // std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl; + + if (success) { + // Re-query outputs; properties such as bin count may have + // changed on initialise + m_outputs.clear(); + (void)getOutputDescriptors(); + } + + return success; + } + + PluginBufferingAdapter::OutputList + PluginBufferingAdapter::Impl::getOutputDescriptors() const + { + if (m_outputs.empty()) { + // std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl; + + m_outputs = m_plugin->getOutputDescriptors(); + } + + PluginBufferingAdapter::OutputList outs = m_outputs; + + for (int i = 0; i < int(outs.size()); ++i) { + + switch (outs[i].sampleType) { + + case OutputDescriptor::OneSamplePerStep: + outs[i].sampleType = OutputDescriptor::FixedSampleRate; + outs[i].sampleRate = m_inputSampleRate / float(m_stepSize); + m_rewriteOutputTimes[i] = true; + break; + + case OutputDescriptor::FixedSampleRate: + if (outs[i].sampleRate == 0.f) { + outs[i].sampleRate = m_inputSampleRate / float(m_stepSize); + } + // We actually only need to rewrite output times for + // features that don't have timestamps already, but we + // can't tell from here whether our features will have + // timestamps or not + m_rewriteOutputTimes[i] = true; + break; + + case OutputDescriptor::VariableSampleRate: + m_rewriteOutputTimes[i] = false; + break; + } + } + + return outs; + } + + void + PluginBufferingAdapter::Impl::setParameter(std::string name, float value) + { + m_plugin->set_parameter(name, value); + + // Re-query outputs; properties such as bin count may have changed + m_outputs.clear(); + (void)getOutputDescriptors(); + } + + void + PluginBufferingAdapter::Impl::selectProgram(std::string name) + { + m_plugin->select_program(name); + + // Re-query outputs; properties such as bin count may have changed + m_outputs.clear(); + (void)getOutputDescriptors(); + } + + void + PluginBufferingAdapter::Impl::reset() + { + m_frame = 0; + m_unrun = true; + + for (size_t i = 0; i < m_queue.size(); ++i) { + m_queue[i]->reset(); + } + + m_fixedRateFeatureNos.clear(); + + m_plugin->reset(); + } + + PluginBufferingAdapter::FeatureSet + PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, + real_time timestamp) + { + if (m_inputStepSize == 0) { + std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl; + return FeatureSet(); + } + + FeatureSet allFeatureSets; + + if (m_unrun) { + m_frame = real_time::rt2f(timestamp, int(m_inputSampleRate + 0.5)); + m_unrun = false; + } + + // queue the new input + + for (size_t i = 0; i < m_channels; ++i) { + int written = m_queue[i]->write(inputBuffers[i], int(m_inputBlockSize)); + if (written < int(m_inputBlockSize) && i == 0) { + std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " + << "Buffer overflow: wrote " << written + << " of " << m_inputBlockSize + << " input samples (for plugin step size " + << m_stepSize << ", block size " << m_blockSize << ")" + << std::endl; + } + } + + // process as much as we can + + while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { + processBlock(allFeatureSets); + } + + return allFeatureSets; + } + + void + PluginBufferingAdapter::Impl::adjustFixedRateFeatureTime(int outputNo, + Feature &feature) + { + // cerr << "adjustFixedRateFeatureTime: from " << feature.timestamp; + + double rate = m_outputs[outputNo].sampleRate; + if (rate == 0.0) { + rate = m_inputSampleRate / float(m_stepSize); + } + + if (feature.hasTimestamp) { + double secs = feature.timestamp.sec; + secs += feature.timestamp.nsec / 1e9; + m_fixedRateFeatureNos[outputNo] = int(secs * rate + 0.5); + // cerr << " [secs = " << secs << ", no = " << m_fixedRateFeatureNos[outputNo] << "]"; + } + + feature.timestamp = real_time::from_seconds + (m_fixedRateFeatureNos[outputNo] / rate); + + // cerr << " to " << feature.timestamp << " (rate = " << rate << ", hasTimestamp = " << feature.hasTimestamp << ")" << endl; + + feature.hasTimestamp = true; + + m_fixedRateFeatureNos[outputNo] = m_fixedRateFeatureNos[outputNo] + 1; + } + + PluginBufferingAdapter::FeatureSet + PluginBufferingAdapter::Impl::getRemainingFeatures() + { + FeatureSet allFeatureSets; + + // process remaining samples in queue + while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { + processBlock(allFeatureSets); + } + + // pad any last samples remaining and process + if (m_queue[0]->getReadSpace() > 0) { + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->zero(int(m_blockSize) - m_queue[i]->getReadSpace()); + } + processBlock(allFeatureSets); + } + + // get remaining features + + FeatureSet featureSet = m_plugin->getRemainingFeatures(); + + for (map::iterator iter = featureSet.begin(); + iter != featureSet.end(); ++iter) { + + int outputNo = iter->first; + FeatureList featureList = iter->second; + + for (size_t i = 0; i < featureList.size(); ++i) { + + if (m_outputs[outputNo].sampleType == + OutputDescriptor::FixedSampleRate) { + adjustFixedRateFeatureTime(outputNo, featureList[i]); + } + + allFeatureSets[outputNo].push_back(featureList[i]); + } + } + + return allFeatureSets; + } + + void + PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) + { + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->peek(m_buffers[i], int(m_blockSize)); + } + + long frame = m_frame; + real_time timestamp = real_time::f2rt(frame, int(m_inputSampleRate + 0.5)); + + FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); + + PluginWrapper *wrapper = dynamic_cast(m_plugin); + real_time adjustment; + if (wrapper) { + PluginInputDomainAdapter *ida = + wrapper->getWrapper(); + if (ida) adjustment = ida->getTimestampAdjustment(); + } + + for (FeatureSet::iterator iter = featureSet.begin(); + iter != featureSet.end(); ++iter) { + + int outputNo = iter->first; + + if (m_rewriteOutputTimes[outputNo]) { + + FeatureList featureList = iter->second; - bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); - - // or sensible defaults if it has no preference - if (m_blockSize == 0) { - if (m_stepSize == 0) { - m_blockSize = 1024; - if (freq) { - m_stepSize = m_blockSize / 2; - } else { - m_stepSize = m_blockSize; - } - } else if (freq) { - m_blockSize = m_stepSize * 2; - } else { - m_blockSize = m_stepSize; - } - } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above) - if (freq) { - m_stepSize = m_blockSize/2; - } else { - m_stepSize = m_blockSize; - } - } - - // current implementation breaks if step is greater than block - if (m_stepSize > m_blockSize) { - size_t newBlockSize; - if (freq) { - newBlockSize = m_stepSize * 2; - } else { - newBlockSize = m_stepSize; - } - std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl; - m_blockSize = newBlockSize; - } - -// std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize -// << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; + for (size_t i = 0; i < featureList.size(); ++i) { - m_buffers = new float *[m_channels]; + switch (m_outputs[outputNo].sampleType) { - for (size_t i = 0; i < m_channels; ++i) { - m_queue.push_back(new RingBuffer(int(m_blockSize + m_inputBlockSize))); - m_buffers[i] = new float[m_blockSize]; - } - - bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize); + case OutputDescriptor::OneSamplePerStep: + // use our internal timestamp, always + featureList[i].timestamp = timestamp + adjustment; + featureList[i].hasTimestamp = true; + break; -// std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl; + case OutputDescriptor::FixedSampleRate: + adjustFixedRateFeatureTime(outputNo, featureList[i]); + break; - if (success) { - // Re-query outputs; properties such as bin count may have - // changed on initialise - m_outputs.clear(); - (void)getOutputDescriptors(); - } + case OutputDescriptor::VariableSampleRate: + // plugin must set timestamp + break; - return success; -} - -PluginBufferingAdapter::OutputList -PluginBufferingAdapter::Impl::getOutputDescriptors() const -{ - if (m_outputs.empty()) { -// std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl; - - m_outputs = m_plugin->getOutputDescriptors(); - } - - PluginBufferingAdapter::OutputList outs = m_outputs; - - for (int i = 0; i < int(outs.size()); ++i) { - - switch (outs[i].sampleType) { - - case OutputDescriptor::OneSamplePerStep: - outs[i].sampleType = OutputDescriptor::FixedSampleRate; - outs[i].sampleRate = m_inputSampleRate / float(m_stepSize); - m_rewriteOutputTimes[i] = true; - break; - - case OutputDescriptor::FixedSampleRate: - if (outs[i].sampleRate == 0.f) { - outs[i].sampleRate = m_inputSampleRate / float(m_stepSize); - } - // We actually only need to rewrite output times for - // features that don't have timestamps already, but we - // can't tell from here whether our features will have - // timestamps or not - m_rewriteOutputTimes[i] = true; - break; - - case OutputDescriptor::VariableSampleRate: - m_rewriteOutputTimes[i] = false; - break; - } - } - - return outs; -} - -void -PluginBufferingAdapter::Impl::setParameter(std::string name, float value) -{ - m_plugin->setParameter(name, value); - - // Re-query outputs; properties such as bin count may have changed - m_outputs.clear(); - (void)getOutputDescriptors(); -} - -void -PluginBufferingAdapter::Impl::selectProgram(std::string name) -{ - m_plugin->selectProgram(name); - - // Re-query outputs; properties such as bin count may have changed - m_outputs.clear(); - (void)getOutputDescriptors(); -} - -void -PluginBufferingAdapter::Impl::reset() -{ - m_frame = 0; - m_unrun = true; - - for (size_t i = 0; i < m_queue.size(); ++i) { - m_queue[i]->reset(); - } - - m_fixedRateFeatureNos.clear(); - - m_plugin->reset(); -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_inputStepSize == 0) { - std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl; - return FeatureSet(); - } - - FeatureSet allFeatureSets; - - if (m_unrun) { - m_frame = RealTime::realTime2Frame(timestamp, - int(m_inputSampleRate + 0.5)); - m_unrun = false; - } - - // queue the new input - - for (size_t i = 0; i < m_channels; ++i) { - int written = m_queue[i]->write(inputBuffers[i], int(m_inputBlockSize)); - if (written < int(m_inputBlockSize) && i == 0) { - std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " - << "Buffer overflow: wrote " << written - << " of " << m_inputBlockSize - << " input samples (for plugin step size " - << m_stepSize << ", block size " << m_blockSize << ")" - << std::endl; - } - } - - // process as much as we can - - while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { - processBlock(allFeatureSets); - } - - return allFeatureSets; -} - -void -PluginBufferingAdapter::Impl::adjustFixedRateFeatureTime(int outputNo, - Feature &feature) -{ -// cerr << "adjustFixedRateFeatureTime: from " << feature.timestamp; - - double rate = m_outputs[outputNo].sampleRate; - if (rate == 0.0) { - rate = m_inputSampleRate / float(m_stepSize); - } - - if (feature.hasTimestamp) { - double secs = feature.timestamp.sec; - secs += feature.timestamp.nsec / 1e9; - m_fixedRateFeatureNos[outputNo] = int(secs * rate + 0.5); -// cerr << " [secs = " << secs << ", no = " << m_fixedRateFeatureNos[outputNo] << "]"; - } - - feature.timestamp = RealTime::fromSeconds - (m_fixedRateFeatureNos[outputNo] / rate); - -// cerr << " to " << feature.timestamp << " (rate = " << rate << ", hasTimestamp = " << feature.hasTimestamp << ")" << endl; - - feature.hasTimestamp = true; - - m_fixedRateFeatureNos[outputNo] = m_fixedRateFeatureNos[outputNo] + 1; -} - -PluginBufferingAdapter::FeatureSet -PluginBufferingAdapter::Impl::getRemainingFeatures() -{ - FeatureSet allFeatureSets; - - // process remaining samples in queue - while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { - processBlock(allFeatureSets); - } - - // pad any last samples remaining and process - if (m_queue[0]->getReadSpace() > 0) { - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->zero(int(m_blockSize) - m_queue[i]->getReadSpace()); - } - processBlock(allFeatureSets); - } - - // get remaining features - - FeatureSet featureSet = m_plugin->getRemainingFeatures(); - - for (map::iterator iter = featureSet.begin(); - iter != featureSet.end(); ++iter) { - - int outputNo = iter->first; - FeatureList featureList = iter->second; - - for (size_t i = 0; i < featureList.size(); ++i) { - - if (m_outputs[outputNo].sampleType == - OutputDescriptor::FixedSampleRate) { - adjustFixedRateFeatureTime(outputNo, featureList[i]); - } - - allFeatureSets[outputNo].push_back(featureList[i]); - } - } - - return allFeatureSets; -} - -void -PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) -{ - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->peek(m_buffers[i], int(m_blockSize)); - } - - long frame = m_frame; - RealTime timestamp = RealTime::frame2RealTime - (frame, int(m_inputSampleRate + 0.5)); - - FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); - - PluginWrapper *wrapper = dynamic_cast(m_plugin); - RealTime adjustment; - if (wrapper) { - PluginInputDomainAdapter *ida = - wrapper->getWrapper(); - if (ida) adjustment = ida->getTimestampAdjustment(); - } - - for (FeatureSet::iterator iter = featureSet.begin(); - iter != featureSet.end(); ++iter) { - - int outputNo = iter->first; - - if (m_rewriteOutputTimes[outputNo]) { - - FeatureList featureList = iter->second; - - for (size_t i = 0; i < featureList.size(); ++i) { - - switch (m_outputs[outputNo].sampleType) { - - case OutputDescriptor::OneSamplePerStep: - // use our internal timestamp, always - featureList[i].timestamp = timestamp + adjustment; - featureList[i].hasTimestamp = true; - break; - - case OutputDescriptor::FixedSampleRate: - adjustFixedRateFeatureTime(outputNo, featureList[i]); - break; - - case OutputDescriptor::VariableSampleRate: - // plugin must set timestamp - break; - - default: - break; - } - - allFeatureSets[outputNo].push_back(featureList[i]); - } - } else { - for (size_t i = 0; i < iter->second.size(); ++i) { - allFeatureSets[outputNo].push_back(iter->second[i]); - } - } - } - - // step forward - - for (size_t i = 0; i < m_channels; ++i) { - m_queue[i]->skip(int(m_stepSize)); - } - - // increment internal frame counter each time we step forward - m_frame += m_stepSize; -} - -} - + default: + break; + } + + allFeatureSets[outputNo].push_back(featureList[i]); + } + } else { + for (size_t i = 0; i < iter->second.size(); ++i) { + allFeatureSets[outputNo].push_back(iter->second[i]); + } + } + } + + // step forward + + for (size_t i = 0; i < m_channels; ++i) { + m_queue[i]->skip(int(m_stepSize)); + } + + // increment internal frame counter each time we step forward + m_frame += m_stepSize; + } } diff --git a/src/vamp-hostsdk/PluginBufferingAdapter.h b/src/vamp-hostsdk/PluginBufferingAdapter.h index feb1c64..6c7e8e3 100644 --- a/src/vamp-hostsdk/PluginBufferingAdapter.h +++ b/src/vamp-hostsdk/PluginBufferingAdapter.h @@ -2,148 +2,35 @@ #include "vamp-hostsdk/PluginWrapper.h" -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginBufferingAdapter PluginBufferingAdapter.h - * - * PluginBufferingAdapter is a Vamp plugin adapter that allows plugins - * to be used by a host supplying an audio stream in non-overlapping - * buffers of arbitrary size. - * - * A host using PluginBufferingAdapter may ignore the preferred step - * and block size reported by the plugin, and still expect the plugin - * to run. The value of blockSize and stepSize passed to initialise - * should be the size of the buffer which the host will supply; the - * stepSize should be equal to the blockSize. - * - * If the internal step size used for the plugin differs from that - * supplied by the host, the adapter will modify the sample type and - * rate specifications for the plugin outputs appropriately, and set - * timestamps on the output features for outputs that formerly used a - * different sample rate specification. This is necessary in order to - * obtain correct time stamping. - * - * In other respects, the PluginBufferingAdapter behaves identically - * to the plugin that it wraps. The wrapped plugin will be deleted - * when the wrapper is deleted. - */ - -class PluginBufferingAdapter : public PluginWrapper +namespace vamp::host { -public: - /** - * Construct a PluginBufferingAdapter wrapping the given plugin. - * The adapter takes ownership of the plugin, which will be - * deleted when the adapter is deleted. - */ - PluginBufferingAdapter(Plugin *plugin); - virtual ~PluginBufferingAdapter(); + class PluginBufferingAdapter : public PluginWrapper + { + public: + PluginBufferingAdapter(plugin* p); + virtual ~PluginBufferingAdapter(); + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + size_t getPluginPreferredStepSize() const; + size_t getPluginPreferredBlockSize() const; + void setPluginStepSize(size_t stepSize); + void setPluginBlockSize(size_t blockSize); + void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - /** - * Return the preferred step size for this adapter. - * - * Because of the way this adapter works, its preferred step size - * will always be the same as its preferred block size. This may - * or may not be the same as the preferred step size of the - * underlying plugin, which may be obtained by calling - * getPluginPreferredStepSize(). - */ - size_t getPreferredStepSize() const; + void setParameter(std::string, float); + void selectProgram(std::string); - /** - * Return the preferred block size for this adapter. - * - * This may or may not be the same as the preferred block size of - * the underlying plugin, which may be obtained by calling - * getPluginPreferredBlockSize(). - * - * Note that this adapter may be initialised with any block size, - * not just its supposedly preferred one. - */ - size_t getPreferredBlockSize() const; + OutputList getOutputDescriptors() const; - /** - * Initialise the adapter (and therefore the plugin) for the given - * number of channels. Initialise the adapter for the given step - * and block size, which must be equal. - * - * The step and block size used for the underlying plugin will - * depend on its preferences, or any values previously passed to - * setPluginStepSize and setPluginBlockSize. - */ - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - - /** - * Return the preferred step size of the plugin wrapped by this - * adapter. - * - * This is included mainly for informational purposes. This value - * is not likely to be a valid step size for the adapter itself, - * and it is not usually of any use in interpreting the results - * (because the adapter re-writes OneSamplePerStep outputs to - * FixedSampleRate so that the hop size no longer needs to be - * known beforehand in order to interpret them). - */ - size_t getPluginPreferredStepSize() const; - - /** - * Return the preferred block size of the plugin wrapped by this - * adapter. - * - * This is included mainly for informational purposes. - */ - size_t getPluginPreferredBlockSize() const; - - /** - * Set the step size that will be used for the underlying plugin - * when initialise() is called. If this is not set, the plugin's - * own preferred step size will be used. You will not usually - * need to call this function. If you do call it, it must be - * before the first call to initialise(). - */ - void setPluginStepSize(size_t stepSize); - - /** - * Set the block size that will be used for the underlying plugin - * when initialise() is called. If this is not set, the plugin's - * own preferred block size will be used. You will not usually - * need to call this function. If you do call it, it must be - * before the first call to initialise(). - */ - void setPluginBlockSize(size_t blockSize); - - /** - * Return the step and block sizes that were actually used when - * initialising the underlying plugin. - * - * This is included mainly for informational purposes. You will - * not usually need to call this function. If this is called - * before initialise(), it will return 0 for both values. If it - * is called after a failed call to initialise(), it will return - * the values that were used in the failed call to the plugin's - * initialise() function. - */ - void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); - - void setParameter(std::string, float); - void selectProgram(std::string); - - OutputList getOutputDescriptors() const; - - void reset(); - - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - FeatureSet getRemainingFeatures(); - -protected: - class Impl; - Impl *m_impl; -}; - -} + void reset(); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + + FeatureSet getRemainingFeatures(); + + protected: + class Impl; + Impl *m_impl; + }; } diff --git a/src/vamp-hostsdk/PluginChannelAdapter.cpp b/src/vamp-hostsdk/PluginChannelAdapter.cpp index 4f04afa..ed7ae5c 100644 --- a/src/vamp-hostsdk/PluginChannelAdapter.cpp +++ b/src/vamp-hostsdk/PluginChannelAdapter.cpp @@ -1,105 +1,102 @@ #include "vamp-hostsdk/PluginChannelAdapter.h" -namespace Vamp { - -namespace HostExt { - -class PluginChannelAdapter::Impl +namespace vamp::host { -public: - Impl(Plugin *plugin); - ~Impl(); + class PluginChannelAdapter::Impl + { + public: + Impl(plugin* p); + ~Impl(); - bool initialise(size_t channels, size_t stepSize, size_t blockSize); + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + FeatureSet processInterleaved(const float *inputBuffers, real_time timestamp); -protected: - Plugin *m_plugin; - size_t m_blockSize; - size_t m_inputChannels; - size_t m_pluginChannels; - float **m_buffer; - float **m_deinterleave; - const float **m_forwardPtrs; -}; + protected: + plugin *m_plugin; + size_t m_blockSize; + size_t m_inputChannels; + size_t m_pluginChannels; + float **m_buffer; + float **m_deinterleave; + const float **m_forwardPtrs; + }; -PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin); -} + PluginChannelAdapter::PluginChannelAdapter(plugin* p) : PluginWrapper(p) + { + m_impl = new Impl(p); + } -PluginChannelAdapter::~PluginChannelAdapter() -{ + PluginChannelAdapter::~PluginChannelAdapter() + { delete m_impl; -} + } -bool -PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ + 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) -{ + PluginChannelAdapter::FeatureSet PluginChannelAdapter::process(const float *const *inputBuffers, real_time timestamp) + { return m_impl->process(inputBuffers, timestamp); -} + } -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::processInterleaved(const float *inputBuffers, - RealTime timestamp) -{ + PluginChannelAdapter::FeatureSet PluginChannelAdapter::processInterleaved(const float *inputBuffers, real_time timestamp) + { return m_impl->processInterleaved(inputBuffers, timestamp); -} + } -PluginChannelAdapter::Impl::Impl(Plugin *plugin) : - m_plugin(plugin), - m_blockSize(0), - m_inputChannels(0), - m_pluginChannels(0), - m_buffer(0), - m_deinterleave(0), - m_forwardPtrs(0) -{ -} + PluginChannelAdapter::Impl::Impl(plugin* p) : + m_plugin(p), + m_blockSize(0), + m_inputChannels(0), + m_pluginChannels(0), + m_buffer(0), + m_deinterleave(0), + m_forwardPtrs(0) + { + } -PluginChannelAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin - - if (m_buffer) { - if (m_inputChannels > m_pluginChannels) { - delete[] m_buffer[0]; - } else { - for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) { - delete[] m_buffer[i]; - } + PluginChannelAdapter::Impl::~Impl() + { + 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; + } + delete[] m_buffer; + m_buffer = 0; } - if (m_deinterleave) { - for (size_t i = 0; i < m_inputChannels; ++i) { - delete[] m_deinterleave[i]; - } - delete[] m_deinterleave; - m_deinterleave = 0; + if (m_deinterleave) + { + for (size_t i = 0; i < m_inputChannels; ++i) + { + delete[] m_deinterleave[i]; + } + delete[] m_deinterleave; + m_deinterleave = 0; } - if (m_forwardPtrs) { - delete[] m_forwardPtrs; - m_forwardPtrs = 0; + if (m_forwardPtrs) + { + delete[] m_forwardPtrs; + m_forwardPtrs = 0; } -} + } -bool -PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ + bool PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) + { m_blockSize = blockSize; size_t minch = m_plugin->getMinChannelCount(); @@ -107,122 +104,126 @@ PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t m_inputChannels = channels; - if (m_inputChannels < minch) { + if (m_inputChannels < minch) + { + m_forwardPtrs = new const float *[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; - } - } + 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; + m_pluginChannels = minch; -// std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; + } + else if (m_inputChannels > maxch) + { + if (maxch == 1) + { + m_buffer = new float *[1]; + m_buffer[0] = new float[blockSize]; + } - } else if (m_inputChannels > maxch) { + m_pluginChannels = 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; + } + else + { + m_pluginChannels = m_inputChannels; } return m_plugin->initialise(m_pluginChannels, stepSize, blockSize); -} + } -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers, - RealTime timestamp) -{ - if (!m_deinterleave) { - m_deinterleave = new float *[m_inputChannels]; - for (size_t i = 0; i < m_inputChannels; ++i) { - m_deinterleave[i] = new float[m_blockSize]; - } + PluginChannelAdapter::FeatureSet PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers, real_time timestamp) + { + if (!m_deinterleave) + { + m_deinterleave = new float *[m_inputChannels]; + for (size_t i = 0; i < m_inputChannels; ++i) + { + m_deinterleave[i] = new float[m_blockSize]; + } } - for (size_t i = 0; i < m_inputChannels; ++i) { - for (size_t j = 0; j < m_blockSize; ++j) { - m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i]; - } + for (size_t i = 0; i < m_inputChannels; ++i) + { + for (size_t j = 0; j < m_blockSize; ++j) + { + m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i]; + } } return process(m_deinterleave, timestamp); -} + } -PluginChannelAdapter::FeatureSet -PluginChannelAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ -// std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl; + PluginChannelAdapter::FeatureSet PluginChannelAdapter::Impl::process(const float *const *inputBuffers, real_time timestamp) + { + 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]; + } + } - 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]; } - 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] /= float(m_inputChannels); - } - return m_plugin->process(m_buffer, timestamp); - } else { - return m_plugin->process(inputBuffers, timestamp); + 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]; + } } - } else { + for (size_t j = 0; j < m_blockSize; ++j) + { + m_buffer[0][j] /= float(m_inputChannels); + } + return m_plugin->process(m_buffer, timestamp); + } + else + { return m_plugin->process(inputBuffers, timestamp); + } + } + else + { + return m_plugin->process(inputBuffers, timestamp); } -} - -} - + } } diff --git a/src/vamp-hostsdk/PluginChannelAdapter.h b/src/vamp-hostsdk/PluginChannelAdapter.h index 507eac0..197f58c 100644 --- a/src/vamp-hostsdk/PluginChannelAdapter.h +++ b/src/vamp-hostsdk/PluginChannelAdapter.h @@ -2,104 +2,21 @@ #include "vamp-hostsdk/PluginWrapper.h" -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginChannelAdapter 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 +namespace vamp::host { -public: - /** - * Construct a PluginChannelAdapter wrapping the given plugin. - * The adapter takes ownership of the plugin, which will be - * deleted when the adapter is deleted. - */ - PluginChannelAdapter(Plugin *plugin); - virtual ~PluginChannelAdapter(); + class PluginChannelAdapter : public PluginWrapper + { + public: + PluginChannelAdapter(plugin* p); + virtual ~PluginChannelAdapter(); - bool initialise(size_t channels, size_t stepSize, size_t blockSize); + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - - /** - * Call process(), providing interleaved audio data with the - * number of channels passed to initialise(). The adapter will - * de-interleave into temporary buffers as appropriate before - * calling process(). - * - * \note This function was introduced in version 1.4 of the Vamp - * plugin SDK. - */ - FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp); - -protected: - class Impl; - Impl *m_impl; -}; - -} + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + FeatureSet processInterleaved(const float *inputBuffer, real_time timestamp); + protected: + class Impl; + Impl* m_impl; + }; } diff --git a/src/vamp-hostsdk/PluginHostAdapter.cpp b/src/vamp-hostsdk/PluginHostAdapter.cpp index 77659f3..a5bd5fe 100644 --- a/src/vamp-hostsdk/PluginHostAdapter.cpp +++ b/src/vamp-hostsdk/PluginHostAdapter.cpp @@ -3,91 +3,60 @@ #include "vamp-hostsdk/Files.h" -namespace Vamp +namespace vamp { - -PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, - float inputSampleRate) : - Plugin(inputSampleRate), - m_descriptor(descriptor) -{ -// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl; + PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, float inputSampleRate) : plugin(inputSampleRate), m_descriptor(descriptor) + { 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; + PluginHostAdapter::~PluginHostAdapter() + { if (m_handle) m_descriptor->cleanup(m_handle); -} + } -std::vector -PluginHostAdapter::getPluginPath() -{ + std::vector PluginHostAdapter::getPluginPath() + { std::vector path; std::string envPath; if (Files::isNonNative32Bit()) { - (void)Files::getEnvUtf8("VAMP_PATH_32", envPath); + (void)Files::getEnvUtf8("VAMP_PATH_32", envPath); } else { - (void)Files::getEnvUtf8("VAMP_PATH", envPath); + (void)Files::getEnvUtf8("VAMP_PATH", envPath); } -#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; - std::string home; - if (Files::getEnvUtf8("HOME", home)) { - std::string::size_type f; - while ((f = envPath.find("$HOME")) != std::string::npos && - f < envPath.length()) { - envPath.replace(f, 5, home); - } - } -#ifdef _WIN32 - std::string pfiles; - if (!Files::getEnvUtf8("ProgramFiles", pfiles)) { - pfiles = "C:\\Program Files"; - } +#define PATH_SEPARATOR ':' + if (envPath == "") + { + envPath = DEFAULT_VAMP_PATH; + std::string home; + if (Files::getEnvUtf8("HOME", home)) + { std::string::size_type f; - while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && - f < envPath.length()) { - envPath.replace(f, 14, pfiles); + while ((f = envPath.find("$HOME")) != std::string::npos && f < envPath.length()) + { + envPath.replace(f, 5, home); } -#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; + 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) -{ + bool PluginHostAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) + { if (!m_handle) return false; return m_descriptor->initialise (m_handle, @@ -95,100 +64,72 @@ PluginHostAdapter::initialise(size_t channels, (unsigned int)stepSize, (unsigned int)blockSize) ? true : false; -} + } -void -PluginHostAdapter::reset() -{ - if (!m_handle) { -// std::cerr << "PluginHostAdapter::reset: no handle" << std::endl; - return; - } -// std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl; + void PluginHostAdapter::reset() + { m_descriptor->reset(m_handle); -} + } -PluginHostAdapter::InputDomain -PluginHostAdapter::getInputDomain() const -{ - if (m_descriptor->inputDomain == vampFrequencyDomain) { - return FrequencyDomain; - } else { - return TimeDomain; + 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 -{ + std::string PluginHostAdapter::get_identifier() const + { return m_descriptor->identifier; -} + } -std::string -PluginHostAdapter::getName() const -{ + std::string PluginHostAdapter::get_name() const + { return m_descriptor->name; -} + } -std::string -PluginHostAdapter::getDescription() const -{ + std::string PluginHostAdapter::get_description() const + { return m_descriptor->description; -} + } -std::string -PluginHostAdapter::getMaker() const -{ + std::string PluginHostAdapter::get_maker() const + { return m_descriptor->maker; -} + } -int -PluginHostAdapter::getPluginVersion() const -{ - return m_descriptor->pluginVersion; -} + PluginHostAdapter::parameter_descriptors PluginHostAdapter::get_parameter_descriptors() const + { + parameter_descriptors list; + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + const VampParameterDescriptor *spd = m_descriptor->parameters[i]; + parameter_descriptor pd; + pd.identifier = spd->identifier; + pd.name = spd->name; + pd.description = spd->description; + pd.unit = spd->unit; + pd.min_value = spd->minValue; + pd.max_value = spd->maxValue; + pd.default_value = spd->defaultValue; + pd.is_quantized = spd->isQuantized; + pd.quantize_step = spd->quantizeStep; + if (pd.is_quantized && spd->valueNames) { + for (unsigned int j = 0; spd->valueNames[j]; ++j) { + pd.value_names.push_back(spd->valueNames[j]); + } + } + list.push_back(pd); + } + return list; + } -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 -{ + float PluginHostAdapter::get_parameter(std::string param) const + { if (!m_handle) return 0.0; for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { @@ -198,12 +139,10 @@ PluginHostAdapter::getParameter(std::string param) const } return 0.0; -} + } -void -PluginHostAdapter::setParameter(std::string param, - float value) -{ + void PluginHostAdapter::set_parameter(std::string param, float value) + { if (!m_handle) return; for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { @@ -212,213 +151,206 @@ PluginHostAdapter::setParameter(std::string param, 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); - if (pn < (int)m_descriptor->programCount) { - return m_descriptor->programs[pn]; - } else { - return ""; - } -} - -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 && sd->binNames) { - 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; - - if (m_descriptor->vampApiVersion >= 2) { - d.hasDuration = sd->hasDuration; - } else { - d.hasDuration = false; - } - - 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) { - - Feature feature; - feature.values.reserve(list.features[0].v1.valueCount); - - for (unsigned int j = 0; j < list.featureCount; ++j) { - - feature.hasTimestamp = list.features[j].v1.hasTimestamp; - feature.timestamp = RealTime(list.features[j].v1.sec, - list.features[j].v1.nsec); - feature.hasDuration = false; - - if (m_descriptor->vampApiVersion >= 2) { - unsigned int j2 = j + list.featureCount; - feature.hasDuration = list.features[j2].v2.hasDuration; - feature.duration = RealTime(list.features[j2].v2.durationSec, - list.features[j2].v2.durationNsec); - } - - for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) { - feature.values.push_back(list.features[j].v1.values[k]); - } - - if (list.features[j].v1.label) { - feature.label = list.features[j].v1.label; - } - - fs[i].push_back(feature); - - if (list.features[j].v1.valueCount > 0) { - feature.values.clear(); - } - - if (list.features[j].v1.label) { - feature.label = ""; - } - } - } - } -} - + } + + PluginHostAdapter::programs PluginHostAdapter::get_programs() const + { + programs list; + + for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { + list.push_back(m_descriptor->programs[i]); + } + + return list; + } + + std::string PluginHostAdapter::get_current_program() const + { + if (!m_handle) return ""; + + int pn = m_descriptor->getCurrentProgram(m_handle); + if (pn < (int)m_descriptor->programCount) { + return m_descriptor->programs[pn]; + } else { + return ""; + } + } + + void PluginHostAdapter::select_program(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 && sd->binNames) { + 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; + + if (m_descriptor->vampApiVersion >= 2) { + d.hasDuration = sd->hasDuration; + } else { + d.hasDuration = false; + } + + list.push_back(d); + + m_descriptor->releaseOutputDescriptor(sd); + } + + return list; + } + + PluginHostAdapter::FeatureSet + PluginHostAdapter::process(const float *const *inputBuffers, + real_time 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) { + + Feature feature; + feature.values.reserve(list.features[0].v1.valueCount); + + for (unsigned int j = 0; j < list.featureCount; ++j) { + + feature.hasTimestamp = list.features[j].v1.hasTimestamp; + feature.timestamp = real_time(list.features[j].v1.sec, + list.features[j].v1.nsec); + feature.hasDuration = false; + + if (m_descriptor->vampApiVersion >= 2) { + unsigned int j2 = j + list.featureCount; + feature.hasDuration = list.features[j2].v2.hasDuration; + feature.duration = real_time(list.features[j2].v2.durationSec, + list.features[j2].v2.durationNsec); + } + + for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) { + feature.values.push_back(list.features[j].v1.values[k]); + } + + if (list.features[j].v1.label) { + feature.label = list.features[j].v1.label; + } + + fs[i].push_back(feature); + + if (list.features[j].v1.valueCount > 0) { + feature.values.clear(); + } + + if (list.features[j].v1.label) { + feature.label = ""; + } + } + } + } + } } diff --git a/src/vamp-hostsdk/PluginHostAdapter.h b/src/vamp-hostsdk/PluginHostAdapter.h index bf4b943..2b9cf90 100644 --- a/src/vamp-hostsdk/PluginHostAdapter.h +++ b/src/vamp-hostsdk/PluginHostAdapter.h @@ -4,72 +4,50 @@ #include "vamp.h" #include -namespace Vamp { - -/** - * \class PluginHostAdapter 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 +namespace vamp { -public: - PluginHostAdapter(const VampPluginDescriptor *descriptor, - float inputSampleRate); - virtual ~PluginHostAdapter(); - - static std::vector getPluginPath(); + class PluginHostAdapter : public plugin + { + public: + PluginHostAdapter(const VampPluginDescriptor* descriptor, float inputSampleRate); + virtual ~PluginHostAdapter(); + + static std::vector getPluginPath(); - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + bool initialise(size_t channels, size_t stepSize, size_t blockSize) override; + void reset() override; - InputDomain getInputDomain() const; + InputDomain getInputDomain() const override; - 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; + std::string get_identifier() const override; + std::string get_name() const override; + std::string get_description() const override; + std::string get_maker() const override; - ParameterList getParameterDescriptors() const; - float getParameter(std::string) const; - void setParameter(std::string, float); + parameter_descriptors get_parameter_descriptors() const override; + float get_parameter(std::string) const override; + void set_parameter(std::string, float) override; - ProgramList getPrograms() const; - std::string getCurrentProgram() const; - void selectProgram(std::string); + programs get_programs() const override; + std::string get_current_program() const override; + void select_program(std::string) override; - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; + size_t getPreferredStepSize() const override; + size_t getPreferredBlockSize() const override; - size_t getMinChannelCount() const; - size_t getMaxChannelCount() const; + size_t getMinChannelCount() const override; + size_t getMaxChannelCount() const override; - OutputList getOutputDescriptors() const; + OutputList getOutputDescriptors() const override; - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet process(const float *const *inputBuffers, real_time timestamp) override; - FeatureSet getRemainingFeatures(); + FeatureSet getRemainingFeatures() override; -protected: - void convertFeatures(VampFeatureList *, FeatureSet &); - - const VampPluginDescriptor *m_descriptor; - VampPluginHandle m_handle; -}; + protected: + void convertFeatures(VampFeatureList *, FeatureSet &); + const VampPluginDescriptor *m_descriptor; + VampPluginHandle m_handle; + }; } diff --git a/src/vamp-hostsdk/PluginInputDomainAdapter.cpp b/src/vamp-hostsdk/PluginInputDomainAdapter.cpp index 2bcf614..5e04eda 100644 --- a/src/vamp-hostsdk/PluginInputDomainAdapter.cpp +++ b/src/vamp-hostsdk/PluginInputDomainAdapter.cpp @@ -1,482 +1,472 @@ #include "vamp-hostsdk/PluginInputDomainAdapter.h" +#include "vamp-hostsdk/Window.h" #include "vamp-sdk/ext/vamp_kiss_fft.h" #include "vamp-sdk/ext/vamp_kiss_fftr.h" #include -#include "Window.h" #include -#include #include -#include #include -namespace Vamp { - -namespace HostExt { - -class PluginInputDomainAdapter::Impl +namespace vamp::host { -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); + class PluginInputDomainAdapter::Impl + { + public: + Impl(plugin* p, float inputSampleRate); + ~Impl(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + + void setProcessTimestampMethod(ProcessTimestampMethod m); + ProcessTimestampMethod getProcessTimestampMethod() const; + + real_time getTimestampAdjustment() const; + + WindowType getWindowType() const; + void setWindowType(WindowType type); + + protected: + plugin* m_plugin; + float m_inputSampleRate; + int m_channels; + int m_stepSize; + int m_blockSize; + float **m_freqbuf; + vamp_kiss_fft_scalar *m_ri; + + WindowType m_windowType; + typedef Window W; + W *m_window; + + ProcessTimestampMethod m_method; + int m_processCount; + float **m_shiftBuffers; + + vamp_kiss_fftr_cfg m_cfg; + vamp_kiss_fft_cpx *m_cbuf; + + FeatureSet processShiftingTimestamp(const float *const *inputBuffers, real_time timestamp); + FeatureSet processShiftingData(const float *const *inputBuffers, real_time timestamp); + + size_t makeBlockSizeAcceptable(size_t) const; + + W::WindowType convertType(WindowType t) const; + }; + + PluginInputDomainAdapter::PluginInputDomainAdapter(plugin* p) : + PluginWrapper(p) + { + m_impl = new Impl(p, m_inputSampleRate); + } + + PluginInputDomainAdapter::~PluginInputDomainAdapter() + { + delete m_impl; + } - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + bool + PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) + { + return m_impl->initialise(channels, stepSize, blockSize); + } - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; + void + PluginInputDomainAdapter::reset() + { + m_impl->reset(); + } - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + plugin::InputDomain PluginInputDomainAdapter::getInputDomain() const + { + return TimeDomain; + } - void setProcessTimestampMethod(ProcessTimestampMethod m); - ProcessTimestampMethod getProcessTimestampMethod() const; - - RealTime getTimestampAdjustment() const; + size_t + PluginInputDomainAdapter::getPreferredStepSize() const + { + return m_impl->getPreferredStepSize(); + } - WindowType getWindowType() const; - void setWindowType(WindowType type); + size_t + PluginInputDomainAdapter::getPreferredBlockSize() const + { + return m_impl->getPreferredBlockSize(); + } -protected: - Plugin *m_plugin; - float m_inputSampleRate; - int m_channels; - int m_stepSize; - int m_blockSize; - float **m_freqbuf; - vamp_kiss_fft_scalar *m_ri; + plugin::FeatureSet + PluginInputDomainAdapter::process(const float *const *inputBuffers, real_time timestamp) + { + return m_impl->process(inputBuffers, timestamp); + } - WindowType m_windowType; - typedef Window W; - W *m_window; + void + PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m) + { + m_impl->setProcessTimestampMethod(m); + } - ProcessTimestampMethod m_method; - int m_processCount; - float **m_shiftBuffers; + PluginInputDomainAdapter::ProcessTimestampMethod + PluginInputDomainAdapter::getProcessTimestampMethod() const + { + return m_impl->getProcessTimestampMethod(); + } - vamp_kiss_fftr_cfg m_cfg; - vamp_kiss_fft_cpx *m_cbuf; + real_time + PluginInputDomainAdapter::getTimestampAdjustment() const + { + return m_impl->getTimestampAdjustment(); + } - FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp); - FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp); + PluginInputDomainAdapter::WindowType + PluginInputDomainAdapter::getWindowType() const + { + return m_impl->getWindowType(); + } - size_t makeBlockSizeAcceptable(size_t) const; - - W::WindowType convertType(WindowType 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); -} - -void -PluginInputDomainAdapter::reset() -{ - m_impl->reset(); -} - -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); -} - -void -PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m) -{ - m_impl->setProcessTimestampMethod(m); -} - -PluginInputDomainAdapter::ProcessTimestampMethod -PluginInputDomainAdapter::getProcessTimestampMethod() const -{ - return m_impl->getProcessTimestampMethod(); -} - -RealTime -PluginInputDomainAdapter::getTimestampAdjustment() const -{ - return m_impl->getTimestampAdjustment(); -} - -PluginInputDomainAdapter::WindowType -PluginInputDomainAdapter::getWindowType() const -{ - return m_impl->getWindowType(); -} - -void -PluginInputDomainAdapter::setWindowType(WindowType w) -{ - m_impl->setWindowType(w); -} + void + PluginInputDomainAdapter::setWindowType(WindowType w) + { + m_impl->setWindowType(w); + } -PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputSampleRate(inputSampleRate), - m_channels(0), - m_stepSize(0), - m_blockSize(0), - m_freqbuf(0), - m_ri(0), - m_windowType(HanningWindow), - m_window(0), - m_method(ShiftTimestamp), - m_processCount(0), - m_shiftBuffers(0), - m_cfg(0), - m_cbuf(0) -{ -} + PluginInputDomainAdapter::Impl::Impl(plugin* p, float inputSampleRate) : + m_plugin(p), + m_inputSampleRate(inputSampleRate), + m_channels(0), + m_stepSize(0), + m_blockSize(0), + m_freqbuf(0), + m_ri(0), + m_windowType(HanningWindow), + m_window(0), + m_method(ShiftTimestamp), + m_processCount(0), + m_shiftBuffers(0), + m_cfg(0), + m_cbuf(0) + { + } -PluginInputDomainAdapter::Impl::~Impl() -{ - // the adapter will delete the plugin + PluginInputDomainAdapter::Impl::~Impl() + { + // the adapter will delete the plugin - if (m_shiftBuffers) { - for (int c = 0; c < m_channels; ++c) { - delete[] m_shiftBuffers[c]; - } - delete[] m_shiftBuffers; - } + if (m_shiftBuffers) { + for (int c = 0; c < m_channels; ++c) { + delete[] m_shiftBuffers[c]; + } + delete[] m_shiftBuffers; + } - if (m_channels > 0) { - for (int c = 0; c < m_channels; ++c) { - delete[] m_freqbuf[c]; - } - delete[] m_freqbuf; - delete[] m_ri; - if (m_cfg) { - vamp_kiss_fftr_free(m_cfg); - m_cfg = 0; - delete[] m_cbuf; - m_cbuf = 0; - } - delete m_window; - } -} + if (m_channels > 0) { + for (int c = 0; c < m_channels; ++c) { + delete[] m_freqbuf[c]; + } + delete[] m_freqbuf; + delete[] m_ri; + if (m_cfg) { + vamp_kiss_fftr_free(m_cfg); + m_cfg = 0; + delete[] m_cbuf; + m_cbuf = 0; + } + delete m_window; + } + } -// for some visual studii apparently + // for some visual studii apparently #ifndef M_PI #define M_PI 3.14159265358979232846 #endif - -bool -PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (m_plugin->getInputDomain() == TimeDomain) { + + bool + PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) + { + if (m_plugin->getInputDomain() == TimeDomain) { - m_stepSize = int(stepSize); - m_blockSize = int(blockSize); - m_channels = int(channels); + m_stepSize = int(stepSize); + m_blockSize = int(blockSize); + m_channels = int(channels); - return m_plugin->initialise(channels, stepSize, blockSize); - } + return m_plugin->initialise(channels, stepSize, blockSize); + } - if (blockSize < 2) { - std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl; - return false; - } - - if (blockSize % 2) { - std::cerr << "ERROR: PluginInputDomainAdapter::initialise: odd blocksize " << blockSize << " not supported" << std::endl; - return false; - } + if (blockSize < 2) { + std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl; + return false; + } + + if (blockSize % 2) { + std::cerr << "ERROR: PluginInputDomainAdapter::initialise: odd blocksize " << blockSize << " not supported" << std::endl; + return false; + } - if (m_channels > 0) { - for (int c = 0; c < m_channels; ++c) { - delete[] m_freqbuf[c]; - } - delete[] m_freqbuf; - delete[] m_ri; - if (m_cfg) { - vamp_kiss_fftr_free(m_cfg); - m_cfg = 0; - delete[] m_cbuf; - m_cbuf = 0; - } - delete m_window; - } + if (m_channels > 0) { + for (int c = 0; c < m_channels; ++c) { + delete[] m_freqbuf[c]; + } + delete[] m_freqbuf; + delete[] m_ri; + if (m_cfg) { + vamp_kiss_fftr_free(m_cfg); + m_cfg = 0; + delete[] m_cbuf; + m_cbuf = 0; + } + delete m_window; + } - m_stepSize = int(stepSize); - m_blockSize = int(blockSize); - m_channels = int(channels); + m_stepSize = int(stepSize); + m_blockSize = int(blockSize); + m_channels = int(channels); - m_freqbuf = new float *[m_channels]; - for (int c = 0; c < m_channels; ++c) { - m_freqbuf[c] = new float[m_blockSize + 2]; - } - m_ri = new vamp_kiss_fft_scalar[m_blockSize]; + m_freqbuf = new float *[m_channels]; + for (int c = 0; c < m_channels; ++c) { + m_freqbuf[c] = new float[m_blockSize + 2]; + } + m_ri = new vamp_kiss_fft_scalar[m_blockSize]; - m_window = new W(convertType(m_windowType), m_blockSize); + m_window = new W(convertType(m_windowType), m_blockSize); - m_cfg = vamp_kiss_fftr_alloc(m_blockSize, false, 0, 0); - m_cbuf = new vamp_kiss_fft_cpx[m_blockSize/2+1]; + m_cfg = vamp_kiss_fftr_alloc(m_blockSize, false, 0, 0); + m_cbuf = new vamp_kiss_fft_cpx[m_blockSize/2+1]; - m_processCount = 0; + m_processCount = 0; - return m_plugin->initialise(channels, stepSize, m_blockSize); -} - -void -PluginInputDomainAdapter::Impl::reset() -{ - m_processCount = 0; - m_plugin->reset(); -} - -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: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl - << "supported, increasing from " << blockSize << " to 2" << std::endl; - blockSize = 2; - - } else if (blockSize % 2) { - - std::cerr << "WARNING: PluginInputDomainAdapter::initialise: odd blocksize not" << std::endl - << "supported, increasing from " << blockSize << " to " << (blockSize+1) << std::endl; - blockSize = blockSize+1; - } - - return blockSize; -} - -RealTime -PluginInputDomainAdapter::Impl::getTimestampAdjustment() const -{ - if (m_plugin->getInputDomain() == TimeDomain) { - return RealTime::zeroTime; - } else if (m_method == ShiftData || m_method == NoShift) { - return RealTime::zeroTime; - } else { - return RealTime::frame2RealTime - (m_blockSize/2, int(m_inputSampleRate + 0.5)); - } -} - -void -PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m) -{ - m_method = m; -} - -PluginInputDomainAdapter::ProcessTimestampMethod -PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const -{ - return m_method; -} - -void -PluginInputDomainAdapter::Impl::setWindowType(WindowType t) -{ - if (m_windowType == t) return; - m_windowType = t; - if (m_window) { - delete m_window; - m_window = new W(convertType(m_windowType), m_blockSize); - } -} - -PluginInputDomainAdapter::WindowType -PluginInputDomainAdapter::Impl::getWindowType() const -{ - return m_windowType; -} - -PluginInputDomainAdapter::Impl::W::WindowType -PluginInputDomainAdapter::Impl::convertType(WindowType t) const -{ - switch (t) { - case RectangularWindow: - return W::RectangularWindow; - case BartlettWindow: - return W::BartlettWindow; - case HammingWindow: - return W::HammingWindow; - case HanningWindow: - return W::HanningWindow; - case BlackmanWindow: - return W::BlackmanWindow; - case NuttallWindow: - return W::NuttallWindow; - case BlackmanHarrisWindow: - return W::BlackmanHarrisWindow; - default: - return W::HanningWindow; - } -} - -Plugin::FeatureSet -PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_plugin->getInputDomain() == TimeDomain) { - return m_plugin->process(inputBuffers, timestamp); - } - - if (m_method == ShiftTimestamp || m_method == NoShift) { - return processShiftingTimestamp(inputBuffers, timestamp); - } else { - return processShiftingData(inputBuffers, timestamp); - } -} - -Plugin::FeatureSet -PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers, - RealTime timestamp) -{ - unsigned int roundedRate = 1; - if (m_inputSampleRate > 0.f) { - roundedRate = (unsigned int)round(m_inputSampleRate); - } - - if (m_method == ShiftTimestamp) { - // we may need to add one nsec if timestamp + - // getTimestampAdjustment() rounds down - timestamp = timestamp + getTimestampAdjustment(); - RealTime nsec(0, 1); - if (RealTime::realTime2Frame(timestamp, roundedRate) < - RealTime::realTime2Frame(timestamp + nsec, roundedRate)) { - timestamp = timestamp + nsec; - } - } - - for (int c = 0; c < m_channels; ++c) { - - m_window->cut(inputBuffers[c], m_ri); - - for (int i = 0; i < m_blockSize/2; ++i) { - // FFT shift - vamp_kiss_fft_scalar value = m_ri[i]; - m_ri[i] = m_ri[i + m_blockSize/2]; - m_ri[i + m_blockSize/2] = value; - } - - vamp_kiss_fftr(m_cfg, m_ri, m_cbuf); - - for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_cbuf[i].r); - m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i].i); - } - } - - return m_plugin->process(m_freqbuf, timestamp); -} - -Plugin::FeatureSet -PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_processCount == 0) { - if (!m_shiftBuffers) { - m_shiftBuffers = new float *[m_channels]; - for (int c = 0; c < m_channels; ++c) { - m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2]; - } - } - for (int c = 0; c < m_channels; ++c) { - for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) { - m_shiftBuffers[c][i] = 0.f; - } - } - } - - for (int c = 0; c < m_channels; ++c) { - for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) { - m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i]; - } - for (int i = 0; i < m_blockSize; ++i) { - m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i]; - } - } - - for (int c = 0; c < m_channels; ++c) { - - m_window->cut(m_shiftBuffers[c], m_ri); - - for (int i = 0; i < m_blockSize/2; ++i) { - // FFT shift - vamp_kiss_fft_scalar value = m_ri[i]; - m_ri[i] = m_ri[i + m_blockSize/2]; - m_ri[i + m_blockSize/2] = value; - } - - vamp_kiss_fftr(m_cfg, m_ri, m_cbuf); - - for (int i = 0; i <= m_blockSize/2; ++i) { - m_freqbuf[c][i * 2] = float(m_cbuf[i].r); - m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i].i); - } - } - - ++m_processCount; - - return m_plugin->process(m_freqbuf, timestamp); -} - -} - + return m_plugin->initialise(channels, stepSize, m_blockSize); + } + + void + PluginInputDomainAdapter::Impl::reset() + { + m_processCount = 0; + m_plugin->reset(); + } + + 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: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl + << "supported, increasing from " << blockSize << " to 2" << std::endl; + blockSize = 2; + + } else if (blockSize % 2) { + + std::cerr << "WARNING: PluginInputDomainAdapter::initialise: odd blocksize not" << std::endl + << "supported, increasing from " << blockSize << " to " << (blockSize+1) << std::endl; + blockSize = blockSize+1; + } + + return blockSize; + } + + real_time PluginInputDomainAdapter::Impl::getTimestampAdjustment() const + { + if (m_plugin->getInputDomain() == TimeDomain) { + return real_time::zero_time; + } else if (m_method == ShiftData || m_method == NoShift) { + return real_time::zero_time; + } else { + return real_time::f2rt(m_blockSize/2, int(m_inputSampleRate + 0.5)); + } + } + + void + PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m) + { + m_method = m; + } + + PluginInputDomainAdapter::ProcessTimestampMethod + PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const + { + return m_method; + } + + void + PluginInputDomainAdapter::Impl::setWindowType(WindowType t) + { + if (m_windowType == t) return; + m_windowType = t; + if (m_window) { + delete m_window; + m_window = new W(convertType(m_windowType), m_blockSize); + } + } + + PluginInputDomainAdapter::WindowType + PluginInputDomainAdapter::Impl::getWindowType() const + { + return m_windowType; + } + + PluginInputDomainAdapter::Impl::W::WindowType + PluginInputDomainAdapter::Impl::convertType(WindowType t) const + { + switch (t) { + case RectangularWindow: + return W::RectangularWindow; + case BartlettWindow: + return W::BartlettWindow; + case HammingWindow: + return W::HammingWindow; + case HanningWindow: + return W::HanningWindow; + case BlackmanWindow: + return W::BlackmanWindow; + case NuttallWindow: + return W::NuttallWindow; + case BlackmanHarrisWindow: + return W::BlackmanHarrisWindow; + default: + return W::HanningWindow; + } + } + + plugin::FeatureSet + PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, + real_time timestamp) + { + if (m_plugin->getInputDomain() == TimeDomain) { + return m_plugin->process(inputBuffers, timestamp); + } + + if (m_method == ShiftTimestamp || m_method == NoShift) { + return processShiftingTimestamp(inputBuffers, timestamp); + } else { + return processShiftingData(inputBuffers, timestamp); + } + } + + plugin::FeatureSet + PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers, + real_time timestamp) + { + unsigned int roundedRate = 1; + if (m_inputSampleRate > 0.f) { + roundedRate = (unsigned int)round(m_inputSampleRate); + } + + if (m_method == ShiftTimestamp) { + // we may need to add one nsec if timestamp + + // getTimestampAdjustment() rounds down + timestamp = timestamp + getTimestampAdjustment(); + real_time nsec(0, 1); + if (real_time::rt2f(timestamp, roundedRate) < + real_time::rt2f(timestamp + nsec, roundedRate)) { + timestamp = timestamp + nsec; + } + } + + for (int c = 0; c < m_channels; ++c) { + + m_window->cut(inputBuffers[c], m_ri); + + for (int i = 0; i < m_blockSize/2; ++i) { + // FFT shift + vamp_kiss_fft_scalar value = m_ri[i]; + m_ri[i] = m_ri[i + m_blockSize/2]; + m_ri[i + m_blockSize/2] = value; + } + + vamp_kiss_fftr(m_cfg, m_ri, m_cbuf); + + for (int i = 0; i <= m_blockSize/2; ++i) { + m_freqbuf[c][i * 2] = float(m_cbuf[i].r); + m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i].i); + } + } + + return m_plugin->process(m_freqbuf, timestamp); + } + + plugin::FeatureSet + PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers, + real_time timestamp) + { + if (m_processCount == 0) { + if (!m_shiftBuffers) { + m_shiftBuffers = new float *[m_channels]; + for (int c = 0; c < m_channels; ++c) { + m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2]; + } + } + for (int c = 0; c < m_channels; ++c) { + for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) { + m_shiftBuffers[c][i] = 0.f; + } + } + } + + for (int c = 0; c < m_channels; ++c) { + for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) { + m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i]; + } + for (int i = 0; i < m_blockSize; ++i) { + m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i]; + } + } + + for (int c = 0; c < m_channels; ++c) { + + m_window->cut(m_shiftBuffers[c], m_ri); + + for (int i = 0; i < m_blockSize/2; ++i) { + // FFT shift + vamp_kiss_fft_scalar value = m_ri[i]; + m_ri[i] = m_ri[i + m_blockSize/2]; + m_ri[i + m_blockSize/2] = value; + } + + vamp_kiss_fftr(m_cfg, m_ri, m_cbuf); + + for (int i = 0; i <= m_blockSize/2; ++i) { + m_freqbuf[c][i * 2] = float(m_cbuf[i].r); + m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i].i); + } + } + + ++m_processCount; + + return m_plugin->process(m_freqbuf, timestamp); + } } diff --git a/src/vamp-hostsdk/PluginInputDomainAdapter.h b/src/vamp-hostsdk/PluginInputDomainAdapter.h index e87679a..07e79e7 100644 --- a/src/vamp-hostsdk/PluginInputDomainAdapter.h +++ b/src/vamp-hostsdk/PluginInputDomainAdapter.h @@ -2,190 +2,58 @@ #include "vamp-hostsdk/PluginWrapper.h" -namespace Vamp { - -namespace HostExt { - -/** - * \class PluginInputDomainAdapter 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 windowed FFT (using Hann window by - * default) 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. - * - * The window shape for the FFT frame can be set using setWindowType - * and the current shape retrieved using getWindowType. (This was - * added in v2.3 of the SDK.) - * - * 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 +namespace vamp::host { -public: - /** - * Construct a PluginInputDomainAdapter wrapping the given plugin. - * The adapter takes ownership of the plugin, which will be - * deleted when the adapter is deleted. - */ - PluginInputDomainAdapter(Plugin *plugin); - virtual ~PluginInputDomainAdapter(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + class PluginInputDomainAdapter : public PluginWrapper + { + public: + PluginInputDomainAdapter(plugin* p); + virtual ~PluginInputDomainAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); - InputDomain getInputDomain() const; + InputDomain getInputDomain() const; - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); - /** - * ProcessTimestampMethod determines how the - * PluginInputDomainAdapter handles timestamps for the data passed - * to the process() function of the plugin it wraps, in the case - * where the plugin is expecting frequency-domain data. - * - * The Vamp specification requires that the timestamp passed to - * the plugin for frequency-domain input should be that of the - * centre of the processing block, rather than the start as is the - * case for time-domain input. - * - * Since PluginInputDomainAdapter aims to be transparent in use, - * it needs to handle this timestamp adjustment itself. However, - * some control is available over the method used for adjustment, - * by means of the ProcessTimestampMethod setting. - * - * If ProcessTimestampMethod is set to ShiftTimestamp (the - * default), then the data passed to the wrapped plugin will be - * calculated from the same input data block as passed to the - * wrapper, but the timestamp passed to the plugin will be - * advanced by half of the window size. - * - * If ProcessTimestampMethod is set to ShiftData, then the - * timestamp passed to the wrapped plugin will be the same as that - * passed to the process call of the wrapper, but the data block - * used to calculate the input will be shifted back (earlier) by - * half of the window size, with half a block of zero padding at - * the start of the first process call. This has the advantage of - * preserving the first half block of audio without any - * deterioration from window shaping. - * - * If ProcessTimestampMethod is set to NoShift, then no adjustment - * will be made and the timestamps will be incorrect. - */ - enum ProcessTimestampMethod { - ShiftTimestamp, - ShiftData, - NoShift - }; + enum ProcessTimestampMethod { + ShiftTimestamp, + ShiftData, + NoShift + }; - /** - * Set the method used for timestamp adjustment in plugins taking - * frequency-domain input. See the ProcessTimestampMethod - * documentation for details. - * - * This function must be called before the first call to - * process(). - */ - void setProcessTimestampMethod(ProcessTimestampMethod); + void setProcessTimestampMethod(ProcessTimestampMethod); + ProcessTimestampMethod getProcessTimestampMethod() const; + real_time getTimestampAdjustment() const; - /** - * Retrieve the method used for timestamp adjustment in plugins - * taking frequency-domain input. See the ProcessTimestampMethod - * documentation for details. - */ - ProcessTimestampMethod getProcessTimestampMethod() const; + enum WindowType { - /** - * Return the amount by which the timestamps supplied to process() - * are being incremented when they are passed to the plugin's own - * process() implementation. - * - * The Vamp API mandates that the timestamp passed to the plugin - * for time-domain input should be the time of the first sample in - * the block, but the timestamp passed for frequency-domain input - * should be the timestamp of the centre of the block. - * - * The PluginInputDomainAdapter adjusts its timestamps properly so - * that the plugin receives correct times, but in some - * circumstances (such as for establishing the correct timing of - * implicitly-timed features, i.e. features without their own - * timestamps) the host may need to be aware that this adjustment - * is taking place. - * - * If the plugin requires time-domain input or the - * PluginInputDomainAdapter is configured with its - * ProcessTimestampMethod set to ShiftData instead of - * ShiftTimestamp, then this function will return zero. - * - * The result of calling this function before initialise() has - * been called is undefined. - */ - RealTime getTimestampAdjustment() const; + RectangularWindow = 0, - /** - * The set of supported window shapes. - */ - enum WindowType { + BartlettWindow = 1, /// synonym for RectangularWindow + TriangularWindow = 1, /// synonym for BartlettWindow - RectangularWindow = 0, + HammingWindow = 2, - BartlettWindow = 1, /// synonym for RectangularWindow - TriangularWindow = 1, /// synonym for BartlettWindow + HanningWindow = 3, /// synonym for HannWindow + HannWindow = 3, /// synonym for HanningWindow - HammingWindow = 2, + BlackmanWindow = 4, - HanningWindow = 3, /// synonym for HannWindow - HannWindow = 3, /// synonym for HanningWindow + NuttallWindow = 7, - BlackmanWindow = 4, + BlackmanHarrisWindow = 8 + }; - NuttallWindow = 7, - - BlackmanHarrisWindow = 8 - }; - - /** - * Return the current window shape. The default is HanningWindow. - */ - WindowType getWindowType() const; - - /** - * Set the current window shape. - */ - void setWindowType(WindowType type); - - -protected: - class Impl; - Impl *m_impl; -}; + WindowType getWindowType() const; + void setWindowType(WindowType type); -} + protected: + class Impl; + Impl *m_impl; + }; } diff --git a/src/vamp-hostsdk/PluginLoader.cpp b/src/vamp-hostsdk/PluginLoader.cpp index 40c416f..58c3c8f 100644 --- a/src/vamp-hostsdk/PluginLoader.cpp +++ b/src/vamp-hostsdk/PluginLoader.cpp @@ -1,567 +1,552 @@ #include "vamp-hostsdk/PluginLoader.h" + +#include + #include "vamp-hostsdk/PluginInputDomainAdapter.h" #include "vamp-hostsdk/PluginChannelAdapter.h" #include "vamp-hostsdk/PluginBufferingAdapter.h" #include "vamp-hostsdk/PluginHostAdapter.h" - #include "vamp.h" - #include "vamp-hostsdk/Files.h" -#include - -namespace Vamp { - -namespace HostExt { - -class PluginLoader::Impl +namespace vamp::host { -public: - Impl(); - virtual ~Impl(); - - PluginKeyList listPlugins(); - PluginKeyList listPluginsIn(std::vector); - PluginKeyList listPluginsNotIn(std::vector); - - Plugin *loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags); - - PluginKey composePluginKey(std::string libraryName, std::string identifier); - - PluginCategoryHierarchy getPluginCategory(PluginKey key); - - std::string getLibraryPathForPlugin(PluginKey key); - - static void setInstanceToClean(PluginLoader *instance); - -protected: - class PluginDeletionNotifyAdapter : public PluginWrapper { + class PluginLoader::Impl + { public: - PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader); - virtual ~PluginDeletionNotifyAdapter(); + Impl(); + virtual ~Impl(); + + PluginKeyList listPlugins(); + PluginKeyList listPluginsIn(std::vector); + PluginKeyList listPluginsNotIn(std::vector); + + plugin *loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags); + + PluginKey composePluginKey(std::string libraryName, std::string identifier); + + PluginCategoryHierarchy getPluginCategory(PluginKey key); + + std::string getLibraryPathForPlugin(PluginKey key); + + static void setInstanceToClean(PluginLoader *instance); + protected: - Impl *m_loader; - }; + class PluginDeletionNotifyAdapter : public PluginWrapper + { + public: + PluginDeletionNotifyAdapter(plugin* p, Impl *loader); + virtual ~PluginDeletionNotifyAdapter(); + protected: + Impl *m_loader; + }; - class InstanceCleaner { - public: - InstanceCleaner() : m_instance(0) { } - ~InstanceCleaner() { delete m_instance; } - void setInstance(PluginLoader *instance) { m_instance = instance; } - protected: - PluginLoader *m_instance; - }; + class InstanceCleaner + { + public: + InstanceCleaner() : m_instance(0) { } + ~InstanceCleaner() { delete m_instance; } + void setInstance(PluginLoader *instance) { m_instance = instance; } + protected: + PluginLoader *m_instance; + }; - virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); + virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); - std::map m_pluginLibraryNameMap; - bool m_allPluginsEnumerated; + std::map m_pluginLibraryNameMap; + bool m_allPluginsEnumerated; - struct Enumeration { + struct Enumeration + { enum { All, SinglePlugin, InLibraries, NotInLibraries } type; PluginKey key; std::vector libraryNames; Enumeration() : type(All) { } - }; - std::vector listLibraryFilesFor(Enumeration); + }; + std::vector listLibraryFilesFor(Enumeration); - /// Populate m_pluginLibraryNameMap and return a list of the keys - /// that were added to it - std::vector enumeratePlugins(Enumeration); + /// Populate m_pluginLibraryNameMap and return a list of the keys + /// that were added to it + std::vector enumeratePlugins(Enumeration); - std::map m_taxonomy; - void generateTaxonomy(); + std::map m_taxonomy; + void generateTaxonomy(); - std::map m_pluginLibraryHandleMap; + std::map m_pluginLibraryHandleMap; - bool decomposePluginKey(PluginKey key, - std::string &libraryName, std::string &identifier); + bool decomposePluginKey(PluginKey key, std::string &libraryName, std::string &identifier); - static InstanceCleaner m_cleaner; -}; + static InstanceCleaner m_cleaner; + }; -PluginLoader * -PluginLoader::m_instance = 0; + PluginLoader * + PluginLoader::m_instance = 0; -PluginLoader::Impl::InstanceCleaner -PluginLoader::Impl::m_cleaner; + PluginLoader::Impl::InstanceCleaner + PluginLoader::Impl::m_cleaner; -PluginLoader::PluginLoader() -{ + PluginLoader::PluginLoader() + { m_impl = new Impl(); -} + } -PluginLoader::~PluginLoader() -{ - delete m_impl; -} + PluginLoader::~PluginLoader() + { + delete m_impl; + } -PluginLoader * -PluginLoader::getInstance() -{ - if (!m_instance) { - // The cleaner doesn't own the instance, because we leave the - // instance pointer in the base class for binary backwards - // compatibility reasons and to avoid waste + PluginLoader * + PluginLoader::getInstance() + { + if (!m_instance) { + // Очиститель не является владельцем экземпляра, потому что мы оставляем указатель + // instance в базовом классе для обратной передачи двоичных данных + // из соображений совместимости и во избежание ненужных затрат m_instance = new PluginLoader(); Impl::setInstanceToClean(m_instance); - } - return m_instance; -} + } + return m_instance; + } -PluginLoader::PluginKeyList -PluginLoader::listPlugins() -{ + PluginLoader::PluginKeyList + PluginLoader::listPlugins() + { return m_impl->listPlugins(); -} + } -PluginLoader::PluginKeyList -PluginLoader::listPluginsIn(std::vector libs) -{ - return m_impl->listPluginsIn(libs); -} + PluginLoader::PluginKeyList + PluginLoader::listPluginsIn(std::vector libs) + { + return m_impl->listPluginsIn(libs); + } -PluginLoader::PluginKeyList -PluginLoader::listPluginsNotIn(std::vector libs) -{ - return m_impl->listPluginsNotIn(libs); -} + PluginLoader::PluginKeyList + PluginLoader::listPluginsNotIn(std::vector libs) + { + return m_impl->listPluginsNotIn(libs); + } -Plugin * -PluginLoader::loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags) -{ - return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); -} + plugin* PluginLoader::loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags) + { + return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); + } -PluginLoader::PluginKey -PluginLoader::composePluginKey(std::string libraryName, std::string identifier) -{ - return m_impl->composePluginKey(libraryName, identifier); -} + PluginLoader::PluginKey + PluginLoader::composePluginKey(std::string libraryName, std::string identifier) + { + return m_impl->composePluginKey(libraryName, identifier); + } -PluginLoader::PluginCategoryHierarchy -PluginLoader::getPluginCategory(PluginKey key) -{ - return m_impl->getPluginCategory(key); -} + PluginLoader::PluginCategoryHierarchy + PluginLoader::getPluginCategory(PluginKey key) + { + return m_impl->getPluginCategory(key); + } - std::string -PluginLoader::getLibraryPathForPlugin(PluginKey key) -{ - return m_impl->getLibraryPathForPlugin(key); -} - -PluginLoader::Impl::Impl() : - m_allPluginsEnumerated(false) -{ -} + std::string + PluginLoader::getLibraryPathForPlugin(PluginKey key) + { + return m_impl->getLibraryPathForPlugin(key); + } + + PluginLoader::Impl::Impl() : + m_allPluginsEnumerated(false) + { + } -PluginLoader::Impl::~Impl() -{ -} + PluginLoader::Impl::~Impl() + { + } -void -PluginLoader::Impl::setInstanceToClean(PluginLoader *instance) -{ - m_cleaner.setInstance(instance); -} + void + PluginLoader::Impl::setInstanceToClean(PluginLoader *instance) + { + m_cleaner.setInstance(instance); + } -PluginLoader::PluginKeyList -PluginLoader::Impl::listPlugins() -{ - if (!m_allPluginsEnumerated) enumeratePlugins(Enumeration()); + PluginLoader::PluginKeyList + PluginLoader::Impl::listPlugins() + { + if (!m_allPluginsEnumerated) enumeratePlugins(Enumeration()); - std::vector plugins; - for (std::map::const_iterator i = - m_pluginLibraryNameMap.begin(); - i != m_pluginLibraryNameMap.end(); ++i) { - plugins.push_back(i->first); - } + std::vector plugins; + for (std::map::const_iterator i = + m_pluginLibraryNameMap.begin(); + i != m_pluginLibraryNameMap.end(); ++i) { + plugins.push_back(i->first); + } - return plugins; -} + return plugins; + } -PluginLoader::PluginKeyList -PluginLoader::Impl::listPluginsIn(std::vector libs) -{ - Enumeration enumeration; - enumeration.type = Enumeration::InLibraries; - enumeration.libraryNames = libs; - return enumeratePlugins(enumeration); -} + PluginLoader::PluginKeyList + PluginLoader::Impl::listPluginsIn(std::vector libs) + { + Enumeration enumeration; + enumeration.type = Enumeration::InLibraries; + enumeration.libraryNames = libs; + return enumeratePlugins(enumeration); + } -PluginLoader::PluginKeyList -PluginLoader::Impl::listPluginsNotIn(std::vector libs) -{ - Enumeration enumeration; - enumeration.type = Enumeration::NotInLibraries; - enumeration.libraryNames = libs; - return enumeratePlugins(enumeration); -} + PluginLoader::PluginKeyList + PluginLoader::Impl::listPluginsNotIn(std::vector libs) + { + Enumeration enumeration; + enumeration.type = Enumeration::NotInLibraries; + enumeration.libraryNames = libs; + return enumeratePlugins(enumeration); + } - std::vector -PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration) -{ - Files::Filter filter; - - switch (enumeration.type) { + std::vector + PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration) + { + Files::Filter filter; + + switch (enumeration.type) { - case Enumeration::All: - filter.type = Files::Filter::All; - break; + case Enumeration::All: + filter.type = Files::Filter::All; + break; - case Enumeration::SinglePlugin: - { - std::string libraryName, identifier; - if (!decomposePluginKey(enumeration.key, libraryName, identifier)) { - std::cerr << "WARNING: Vamp::HostExt::PluginLoader: " - << "Invalid plugin key \"" << enumeration.key - << "\" in enumerate" << std::endl; - return std::vector(); - } - filter.type = Files::Filter::Matching; - filter.libraryNames.clear(); - filter.libraryNames.push_back(libraryName); - break; - } + case Enumeration::SinglePlugin: + { + std::string libraryName, identifier; + if (!decomposePluginKey(enumeration.key, libraryName, identifier)) { + std::cerr << "WARNING: Vamp::HostExt::PluginLoader: " + << "Invalid plugin key \"" << enumeration.key + << "\" in enumerate" << std::endl; + return std::vector(); + } + filter.type = Files::Filter::Matching; + filter.libraryNames.clear(); + filter.libraryNames.push_back(libraryName); + break; + } - case Enumeration::InLibraries: - filter.type = Files::Filter::Matching; - filter.libraryNames = enumeration.libraryNames; - break; + case Enumeration::InLibraries: + filter.type = Files::Filter::Matching; + filter.libraryNames = enumeration.libraryNames; + break; - case Enumeration::NotInLibraries: - filter.type = Files::Filter::NotMatching; - filter.libraryNames = enumeration.libraryNames; - break; - } - - return Files::listLibraryFilesMatching(filter); -} + case Enumeration::NotInLibraries: + filter.type = Files::Filter::NotMatching; + filter.libraryNames = enumeration.libraryNames; + break; + } + + return Files::listLibraryFilesMatching(filter); + } - std::vector -PluginLoader::Impl::enumeratePlugins(Enumeration enumeration) -{ - std::string libraryName, identifier; - if (enumeration.type == Enumeration::SinglePlugin) { - decomposePluginKey(enumeration.key, libraryName, identifier); - } - - std::vector fullPaths = listLibraryFilesFor(enumeration); + std::vector + PluginLoader::Impl::enumeratePlugins(Enumeration enumeration) + { + std::string libraryName, identifier; + if (enumeration.type == Enumeration::SinglePlugin) { + decomposePluginKey(enumeration.key, libraryName, identifier); + } + + std::vector fullPaths = listLibraryFilesFor(enumeration); - // For these we should warn if a plugin can be loaded from a library - bool specific = (enumeration.type == Enumeration::SinglePlugin || - enumeration.type == Enumeration::InLibraries); + // For these we should warn if a plugin can be loaded from a library + bool specific = (enumeration.type == Enumeration::SinglePlugin || + enumeration.type == Enumeration::InLibraries); - std::vector added; - - for (size_t i = 0; i < fullPaths.size(); ++i) { + std::vector added; + + for (size_t i = 0; i < fullPaths.size(); ++i) { - std::string fullPath = fullPaths[i]; - void *handle = Files::loadLibrary(fullPath); - if (!handle) continue; - - VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)Files::lookupInLibrary - (handle, "vampGetPluginDescriptor"); - - if (!fn) { - if (specific) { - std::cerr << "Vamp::HostExt::PluginLoader: " - << "No vampGetPluginDescriptor function found in library \"" - << fullPath << "\"" << std::endl; - } - Files::unloadLibrary(handle); - continue; - } - - int index = 0; - const VampPluginDescriptor *descriptor = 0; - bool found = false; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - ++index; - if (identifier != "") { - if (descriptor->identifier != identifier) { - continue; - } - } - found = true; - PluginKey key = composePluginKey(fullPath, descriptor->identifier); - if (m_pluginLibraryNameMap.find(key) == - m_pluginLibraryNameMap.end()) { - m_pluginLibraryNameMap[key] = fullPath; - } - added.push_back(key); - } + std::string fullPath = fullPaths[i]; + void *handle = Files::loadLibrary(fullPath); + if (!handle) continue; + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)Files::lookupInLibrary + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + if (specific) { + std::cerr << "Vamp::HostExt::PluginLoader: " + << "No vampGetPluginDescriptor function found in library \"" + << fullPath << "\"" << std::endl; + } + Files::unloadLibrary(handle); + continue; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + bool found = false; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + ++index; + if (identifier != "") { + if (descriptor->identifier != identifier) { + continue; + } + } + found = true; + PluginKey key = composePluginKey(fullPath, descriptor->identifier); + if (m_pluginLibraryNameMap.find(key) == + m_pluginLibraryNameMap.end()) { + m_pluginLibraryNameMap[key] = fullPath; + } + added.push_back(key); + } - if (!found && specific) { - std::cerr << "Vamp::HostExt::PluginLoader: Plugin \"" - << identifier << "\" not found in library \"" - << fullPath << "\"" << std::endl; - } - - Files::unloadLibrary(handle); - } + if (!found && specific) { + std::cerr << "Vamp::HostExt::PluginLoader: Plugin \"" + << identifier << "\" not found in library \"" + << fullPath << "\"" << std::endl; + } + + Files::unloadLibrary(handle); + } - if (enumeration.type == Enumeration::All) { - m_allPluginsEnumerated = true; - } + if (enumeration.type == Enumeration::All) { + m_allPluginsEnumerated = true; + } - return added; -} + return added; + } -PluginLoader::PluginKey -PluginLoader::Impl::composePluginKey(std::string libraryName, std::string identifier) -{ - std::string basename = Files::lcBasename(libraryName); - return basename + ":" + identifier; -} + PluginLoader::PluginKey + PluginLoader::Impl::composePluginKey(std::string libraryName, std::string identifier) + { + std::string basename = Files::lcBasename(libraryName); + return basename + ":" + identifier; + } -bool -PluginLoader::Impl::decomposePluginKey(PluginKey key, - std::string &libraryName, - std::string &identifier) -{ - std::string::size_type ki = key.find(':'); - if (ki == std::string::npos) { - return false; - } + bool + PluginLoader::Impl::decomposePluginKey(PluginKey key, + std::string &libraryName, + std::string &identifier) + { + std::string::size_type ki = key.find(':'); + if (ki == std::string::npos) { + return false; + } - libraryName = key.substr(0, ki); - identifier = key.substr(ki + 1); - return true; -} + 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]; -} + 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]; + } - std::string -PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin) -{ - if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { - if (m_allPluginsEnumerated) return ""; - Enumeration enumeration; - enumeration.type = Enumeration::SinglePlugin; - enumeration.key = plugin; - enumeratePlugins(enumeration); - } - if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { - return ""; - } - return m_pluginLibraryNameMap[plugin]; -} + std::string + PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin) + { + if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { + if (m_allPluginsEnumerated) return ""; + Enumeration enumeration; + enumeration.type = Enumeration::SinglePlugin; + enumeration.key = plugin; + enumeratePlugins(enumeration); + } + if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { + return ""; + } + return m_pluginLibraryNameMap[plugin]; + } -Plugin * -PluginLoader::Impl::loadPlugin(PluginKey key, - float inputSampleRate, int adapterFlags) -{ - std::string libname, identifier; - if (!decomposePluginKey(key, libname, identifier)) { - std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \"" - << key << "\" in loadPlugin" << std::endl; - return 0; - } - - std::string fullPath = getLibraryPathForPlugin(key); - if (fullPath == "") { - std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl; - return 0; - } - - void *handle = Files::loadLibrary(fullPath); - if (!handle) return 0; - - VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)Files::lookupInLibrary - (handle, "vampGetPluginDescriptor"); + plugin* PluginLoader::Impl::loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags) + { + std::string libname, identifier; + if (!decomposePluginKey(key, libname, identifier)) { + std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \"" + << key << "\" in loadPlugin" << std::endl; + return 0; + } + + std::string fullPath = getLibraryPathForPlugin(key); + if (fullPath == "") { + std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl; + return 0; + } + + void* handle = Files::loadLibrary(fullPath); + if (!handle) return 0; + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)Files::lookupInLibrary(handle, "vampGetPluginDescriptor"); - if (!fn) { - std::cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \"" - << fullPath << "\"" << std::endl; + if (!fn) + { + std::cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \"" << fullPath << "\"" << std::endl; Files::unloadLibrary(handle); return 0; - } + } - int index = 0; - const VampPluginDescriptor *descriptor = 0; + int index = 0; + const VampPluginDescriptor* descriptor = 0; - while ((descriptor = fn(VAMP_API_VERSION, index))) { + while ((descriptor = fn(VAMP_API_VERSION, index))) + { + if (std::string(descriptor->identifier) == identifier) + { + vamp::PluginHostAdapter* p = new vamp::PluginHostAdapter(descriptor, inputSampleRate); - if (std::string(descriptor->identifier) == identifier) { + plugin* adapter = new PluginDeletionNotifyAdapter(p, this); - Vamp::PluginHostAdapter *plugin = - new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + m_pluginLibraryHandleMap[adapter] = handle; - Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this); + if (adapterFlags & ADAPT_INPUT_DOMAIN) { + if (adapter->getInputDomain() == plugin::FrequencyDomain) { + adapter = new PluginInputDomainAdapter(adapter); + } + } - m_pluginLibraryHandleMap[adapter] = handle; + if (adapterFlags & ADAPT_BUFFER_SIZE) { + adapter = new PluginBufferingAdapter(adapter); + } - if (adapterFlags & ADAPT_INPUT_DOMAIN) { - if (adapter->getInputDomain() == Plugin::FrequencyDomain) { - adapter = new PluginInputDomainAdapter(adapter); - } - } + if (adapterFlags & ADAPT_CHANNEL_COUNT) { + adapter = new PluginChannelAdapter(adapter); + } - if (adapterFlags & ADAPT_BUFFER_SIZE) { - adapter = new PluginBufferingAdapter(adapter); - } - - if (adapterFlags & ADAPT_CHANNEL_COUNT) { - adapter = new PluginChannelAdapter(adapter); - } - - return adapter; + return adapter; } ++index; - } + } - std::cerr << "Vamp::HostExt::PluginLoader: Plugin \"" - << identifier << "\" not found in library \"" - << fullPath << "\"" << std::endl; - - return 0; -} - -void -PluginLoader::Impl::generateTaxonomy() -{ -// cerr << "PluginLoader::Impl::generateTaxonomy" << endl; - - std::vector path = PluginHostAdapter::getPluginPath(); - std::string libfragment = "/lib/"; - std::vector catpath; - - std::string suffix = "cat"; - - for (std::vector::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 - - std::string dir = *i; - std::string::size_type li = dir.find(libfragment); - - if (li != std::string::npos) { - catpath.push_back - (dir.substr(0, li) - + "/share/" - + dir.substr(li + libfragment.length())); - } - - catpath.push_back(dir); - } - - char buffer[1024]; - - for (std::vector::iterator i = catpath.begin(); - i != catpath.end(); ++i) { - - std::vector files = Files::listFiles(*i, suffix); - - for (std::vector::iterator fi = files.begin(); - fi != files.end(); ++fi) { - - std::string filepath = Files::splicePath(*i, *fi); - std::ifstream is(filepath.c_str(), std::ifstream::in | std::ifstream::binary); - - if (is.fail()) { -// cerr << "failed to open: " << filepath << endl; - continue; - } - -// cerr << "opened: " << filepath << endl; - - while (!!is.getline(buffer, 1024)) { - - std::string line(buffer); - -// cerr << "line = " << line << endl; - - std::string::size_type di = line.find("::"); - if (di == std::string::npos) continue; - - std::string id = line.substr(0, di); - std::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; - std::string::size_type ai; - while ((ai = encodedCat.find(" > ")) != std::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::pluginDeleted(PluginDeletionNotifyAdapter *adapter) -{ - void *handle = m_pluginLibraryHandleMap[adapter]; - if (!handle) return; - - m_pluginLibraryHandleMap.erase(adapter); - - for (auto h: m_pluginLibraryHandleMap) { - if (h.second == handle) { - // still in use - return; - } - } - - Files::unloadLibrary(handle); -} - -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); -} - -} + std::cerr << "Vamp::HostExt::PluginLoader: Plugin \"" + << identifier << "\" not found in library \"" + << fullPath << "\"" << std::endl; + return 0; + } + + void + PluginLoader::Impl::generateTaxonomy() + { + // cerr << "PluginLoader::Impl::generateTaxonomy" << endl; + + std::vector path = PluginHostAdapter::getPluginPath(); + std::string libfragment = "/lib/"; + std::vector catpath; + + std::string suffix = "cat"; + + for (std::vector::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 + + std::string dir = *i; + std::string::size_type li = dir.find(libfragment); + + if (li != std::string::npos) { + catpath.push_back + (dir.substr(0, li) + + "/share/" + + dir.substr(li + libfragment.length())); + } + + catpath.push_back(dir); + } + + char buffer[1024]; + + for (std::vector::iterator i = catpath.begin(); + i != catpath.end(); ++i) { + + std::vector files = Files::listFiles(*i, suffix); + + for (std::vector::iterator fi = files.begin(); + fi != files.end(); ++fi) { + + std::string filepath = Files::splicePath(*i, *fi); + std::ifstream is(filepath.c_str(), std::ifstream::in | std::ifstream::binary); + + if (is.fail()) { + // cerr << "failed to open: " << filepath << endl; + continue; + } + + // cerr << "opened: " << filepath << endl; + + while (!!is.getline(buffer, 1024)) { + + std::string line(buffer); + + // cerr << "line = " << line << endl; + + std::string::size_type di = line.find("::"); + if (di == std::string::npos) continue; + + std::string id = line.substr(0, di); + std::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; + std::string::size_type ai; + while ((ai = encodedCat.find(" > ")) != std::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::pluginDeleted(PluginDeletionNotifyAdapter *adapter) + { + void *handle = m_pluginLibraryHandleMap[adapter]; + if (!handle) return; + + m_pluginLibraryHandleMap.erase(adapter); + + for (auto h: m_pluginLibraryHandleMap) { + if (h.second == handle) { + // still in use + return; + } + } + + Files::unloadLibrary(handle); + } + + PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(plugin* p, Impl *loader) : + PluginWrapper(p), + 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); + } } diff --git a/src/vamp-hostsdk/PluginLoader.h b/src/vamp-hostsdk/PluginLoader.h index c37657e..ee15c1b 100644 --- a/src/vamp-hostsdk/PluginLoader.h +++ b/src/vamp-hostsdk/PluginLoader.h @@ -1,235 +1,52 @@ #pragma once +#include "vamp-sdk/Plugin.h" + #include #include -#include -#include "vamp-hostsdk/PluginWrapper.h" - -namespace Vamp { - -class Plugin; - -namespace HostExt { - -/** - * \class PluginLoader 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. - * - * This class is not thread-safe; use it from a single application - * thread, or guard access to it with a mutex. - * - * \note This class was introduced in version 1.1 of the Vamp plugin SDK. - */ - -class PluginLoader +namespace vamp::host { -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; + class PluginLoader + { + public: + static PluginLoader *getInstance(); + typedef std::string PluginKey; + typedef std::vector PluginKeyList; + typedef std::vector PluginCategoryHierarchy; + PluginKeyList listPlugins(); - /** - * PluginKeyList is a sequence of plugin keys, such as returned by - * listPlugins(). - */ - typedef std::vector PluginKeyList; + PluginKeyList listPluginsIn(std::vector libraryNames); + PluginKeyList listPluginsNotIn(std::vector libraryNames); + enum AdapterFlags { - /** - * 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 PluginCategoryHierarchy; + ADAPT_INPUT_DOMAIN = 0x01, + ADAPT_CHANNEL_COUNT = 0x02, + ADAPT_BUFFER_SIZE = 0x04, - /** - * Search for all available Vamp plugins, and return a list of - * them in the order in which they were found. - */ - PluginKeyList listPlugins(); + ADAPT_ALL_SAFE = 0x03, - /** - * Search for available Vamp plugins in libraries with the given - * library names, and return a list of them in the order in which - * they were found. Do not attempt to load any plugin libraries - * other than those named. - * - * The library names should be supplied without path or - * suffix. For example, use "vamp-example-plugins" to find plugins - * in /install/path/of/vamp-example-plugins.dll (or .so etc). This - * is the same concept of "library name" as appears in the plugin - * key: \see composePluginKey(). - */ - PluginKeyList listPluginsIn(std::vector libraryNames); + ADAPT_ALL = 0xff + }; - /** - * Search for available Vamp plugins in libraries other than those - * with the given library names, and return a list of them in the - * order in which they were found. Do not attempt to load any of - * the libraries named. - * - * The library names should be supplied without path or - * suffix. For example, use "vamp-example-plugins" to find plugins - * not appearing in /install/path/of/vamp-example-plugins.dll (or - * .so etc). This is the same concept of "library name" as appears - * in the plugin key: \see composePluginKey(). - */ - PluginKeyList listPluginsNotIn(std::vector libraryNames); + plugin *loadPlugin(PluginKey key, + float inputSampleRate, + int adapterFlags = 0); + + PluginKey composePluginKey(std::string libraryName, + std::string identifier); - /** - * AdapterFlags contains a set of values that may be OR'd together - * to indicate in which circumstances PluginLoader should use a - * plugin adapter to make a plugin easier to use for a host that - * does not want to cater for complex features. - * - * The available flags are: - * - * ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain - * input, wrap it in a PluginInputDomainAdapter that automatically - * converts the plugin to one that expects time-domain input. - * This enables a host to accommodate time- and frequency-domain - * plugins without needing to do any conversion itself. - * - * ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter - * to handle any mismatch between the number of channels of audio - * the plugin can handle and the number available in the host. - * This enables a host to use plugins that may require the input - * to be mixed down to mono, etc., without having to worry about - * doing that itself. - * - * ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter - * permitting the host to provide audio input using any block - * size, with no overlap, regardless of the plugin's preferred - * block size (suitable for hosts that read from non-seekable - * streaming media, for example). This adapter introduces some - * run-time overhead and also changes the semantics of the plugin - * slightly (see the PluginBufferingAdapter header documentation - * for details). - * - * ADAPT_ALL_SAFE - Perform all available adaptations that are - * meaningful for the plugin and "safe". Currently this means to - * ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input; - * ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never. - * - * ADAPT_ALL - Perform all available adaptations that are - * meaningful for the plugin. - * - * See PluginInputDomainAdapter, PluginChannelAdapter and - * PluginBufferingAdapter for more details of the classes that the - * loader may use if these flags are set. - */ - enum AdapterFlags { + PluginCategoryHierarchy getPluginCategory(PluginKey plugin); + std::string getLibraryPathForPlugin(PluginKey plugin); - ADAPT_INPUT_DOMAIN = 0x01, - ADAPT_CHANNEL_COUNT = 0x02, - ADAPT_BUFFER_SIZE = 0x04, + protected: + PluginLoader(); + virtual ~PluginLoader(); - ADAPT_ALL_SAFE = 0x03, - - ADAPT_ALL = 0xff - }; - - /** - * Load a Vamp plugin, given its identifying key. If the plugin - * could not be loaded, returns 0. - * - * The returned plugin should be deleted (using the standard C++ - * delete keyword) after use. - * - * \param adapterFlags a bitwise OR of the values in the AdapterFlags - * enumeration, indicating under which circumstances an adapter should be - * used to wrap the original plugin. If adapterFlags is 0, no - * optional adapters will be used. Otherwise, the returned plugin - * may be of an adapter class type which will behave identically - * to the original plugin, apart from any particular features - * implemented by the adapter itself. - * - * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter - */ - Plugin *loadPlugin(PluginKey key, - float inputSampleRate, - int adapterFlags = 0); - - /** - * Given a Vamp plugin library name and plugin identifier, return - * the corresponding plugin key in a form suitable for passing in to - * loadPlugin(). - * - * (Note that the reverse of this is not well-defined and is not - * offered in this API - consider using getLibraryPathForPlugin - * instead. See documentation for the PluginKey type for details.) - * - * \see PluginKey, getLibraryPathForPlugin, 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; -}; - -} + class Impl; + Impl *m_impl; + static PluginLoader *m_instance; + }; } diff --git a/src/vamp-hostsdk/PluginSummarisingAdapter.cpp b/src/vamp-hostsdk/PluginSummarisingAdapter.cpp index 495bd6c..966725d 100644 --- a/src/vamp-hostsdk/PluginSummarisingAdapter.cpp +++ b/src/vamp-hostsdk/PluginSummarisingAdapter.cpp @@ -1,948 +1,798 @@ #include "vamp-hostsdk/PluginSummarisingAdapter.h" -#include -#include #include +#include #include -using namespace std; - -//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1 -//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1 - -namespace Vamp { - -namespace HostExt { - -class PluginSummarisingAdapter::Impl +namespace vamp::host { -public: - Impl(Plugin *plugin, float inputSampleRate); - ~Impl(); + class PluginSummarisingAdapter::Impl + { + public: + Impl(plugin* p, float inputSampleRate); + ~Impl(); - bool initialise(size_t channels, size_t stepSize, size_t blockSize); + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + void reset(); - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet getRemainingFeatures(); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + FeatureSet getRemainingFeatures(); - void setSummarySegmentBoundaries(const SegmentBoundaries &); + void setSummarySegmentBoundaries(const SegmentBoundaries &); - FeatureList getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg); + FeatureList getSummaryForOutput(int output, + SummaryType type, + AveragingMethod avg); - FeatureSet getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg); + FeatureSet getSummaryForAllOutputs(SummaryType type, + AveragingMethod avg); -protected: - Plugin *m_plugin; - float m_inputSampleRate; - size_t m_stepSize; - size_t m_blockSize; + protected: + plugin *m_plugin; + float m_inputSampleRate; + size_t m_stepSize; + size_t m_blockSize; - SegmentBoundaries m_boundaries; + SegmentBoundaries m_boundaries; - typedef vector ValueList; + typedef std::vector ValueList; - struct Result { // smaller than Feature - RealTime time; - RealTime duration; - ValueList values; // bin number -> value - }; + struct Result { // smaller than Feature + real_time time; + real_time duration; + ValueList values; // bin number -> value + }; - typedef vector ResultList; + typedef std::vector ResultList; - struct OutputAccumulator { - int bins; - ResultList results; - OutputAccumulator() : bins(0) { } - }; + struct OutputAccumulator { + int bins; + ResultList results; + OutputAccumulator() : bins(0) { } + }; - typedef map OutputAccumulatorMap; - OutputAccumulatorMap m_accumulators; // output number -> accumulator + typedef std::map OutputAccumulatorMap; + OutputAccumulatorMap m_accumulators; // output number -> accumulator - typedef map SegmentAccumulatorMap; - typedef map OutputSegmentAccumulatorMap; - OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented + typedef std::map SegmentAccumulatorMap; + typedef std::map OutputSegmentAccumulatorMap; + OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented - typedef map OutputTimestampMap; - OutputTimestampMap m_prevTimestamps; // output number -> timestamp - OutputTimestampMap m_prevDurations; // output number -> durations + typedef std::map OutputTimestampMap; + OutputTimestampMap m_prevTimestamps; // output number -> timestamp + OutputTimestampMap m_prevDurations; // output number -> durations - struct OutputBinSummary { + struct OutputBinSummary { - int count; + int count; - // extents - double minimum; - double maximum; - double sum; + // extents + double minimum; + double maximum; + double sum; - // sample-average results - double median; - double mode; - double variance; + // sample-average results + double median; + double mode; + double variance; - // continuous-time average results - double median_c; - double mode_c; - double mean_c; - double variance_c; - }; + // continuous-time average results + double median_c; + double mode_c; + double mean_c; + double variance_c; + }; - typedef map OutputSummary; - typedef map SummarySegmentMap; - typedef map OutputSummarySegmentMap; + typedef std::map OutputSummary; + typedef std::map SummarySegmentMap; + typedef std::map OutputSummarySegmentMap; - OutputSummarySegmentMap m_summaries; + OutputSummarySegmentMap m_summaries; - bool m_reduced; - RealTime m_endTime; + bool m_reduced; + real_time m_endTime; - void accumulate(const FeatureSet &fs, RealTime, bool final); - void accumulate(int output, const Feature &f, RealTime, bool final); - void accumulateFinalDurations(); - void findSegmentBounds(RealTime t, RealTime &start, RealTime &end); - void segment(); - void reduce(); + void accumulate(const FeatureSet &fs, real_time, bool final); + void accumulate(int output, const Feature &f, real_time, bool final); + void accumulateFinalDurations(); + void findSegmentBounds(real_time t, real_time &start, real_time &end); + void segment(); + void reduce(); - string getSummaryLabel(SummaryType type, AveragingMethod avg); -}; + std::string getSummaryLabel(SummaryType type, AveragingMethod avg); + }; -static RealTime INVALID_DURATION(INT_MIN, INT_MIN); - -PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) : - PluginWrapper(plugin) -{ - m_impl = new Impl(plugin, m_inputSampleRate); -} + static real_time INVALID_DURATION(INT_MIN, INT_MIN); + + PluginSummarisingAdapter::PluginSummarisingAdapter(plugin* p) : PluginWrapper(p) + { + m_impl = new Impl(p, m_inputSampleRate); + } -PluginSummarisingAdapter::~PluginSummarisingAdapter() -{ + PluginSummarisingAdapter::~PluginSummarisingAdapter() + { delete m_impl; -} + } -bool -PluginSummarisingAdapter::initialise(size_t channels, - size_t stepSize, size_t blockSize) -{ - return - PluginWrapper::initialise(channels, stepSize, blockSize) && - m_impl->initialise(channels, stepSize, blockSize); -} + bool + PluginSummarisingAdapter::initialise(size_t channels, + size_t stepSize, size_t blockSize) + { + return + PluginWrapper::initialise(channels, stepSize, blockSize) && + m_impl->initialise(channels, stepSize, blockSize); + } -void -PluginSummarisingAdapter::reset() -{ - m_impl->reset(); -} + void + PluginSummarisingAdapter::reset() + { + m_impl->reset(); + } -Plugin::FeatureSet -PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp) -{ + plugin::FeatureSet + PluginSummarisingAdapter::process(const float *const *inputBuffers, real_time timestamp) + { return m_impl->process(inputBuffers, timestamp); -} + } -Plugin::FeatureSet -PluginSummarisingAdapter::getRemainingFeatures() -{ + plugin::FeatureSet + PluginSummarisingAdapter::getRemainingFeatures() + { return m_impl->getRemainingFeatures(); -} + } -void -PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b) -{ + void + PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b) + { m_impl->setSummarySegmentBoundaries(b); -} + } -Plugin::FeatureList -PluginSummarisingAdapter::getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg) -{ + plugin::FeatureList + PluginSummarisingAdapter::getSummaryForOutput(int output, SummaryType type, AveragingMethod avg) + { return m_impl->getSummaryForOutput(output, type, avg); -} + } -Plugin::FeatureSet -PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg) -{ + plugin::FeatureSet PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type, AveragingMethod avg) + { return m_impl->getSummaryForAllOutputs(type, avg); -} + } -PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : - m_plugin(plugin), - m_inputSampleRate(inputSampleRate), - m_reduced(false) -{ -} + PluginSummarisingAdapter::Impl::Impl(plugin* p, float inputSampleRate) : m_plugin(p), m_inputSampleRate(inputSampleRate), m_reduced(false) + { + } -PluginSummarisingAdapter::Impl::~Impl() -{ -} + PluginSummarisingAdapter::Impl::~Impl() + { + } -bool -PluginSummarisingAdapter::Impl::initialise(size_t, size_t stepSize, size_t blockSize) -{ + bool PluginSummarisingAdapter::Impl::initialise(size_t, size_t stepSize, size_t blockSize) + { m_stepSize = stepSize; m_blockSize = blockSize; return true; -} + } -void -PluginSummarisingAdapter::Impl::reset() -{ + void PluginSummarisingAdapter::Impl::reset() + { m_accumulators.clear(); m_segmentedAccumulators.clear(); m_prevTimestamps.clear(); m_prevDurations.clear(); m_summaries.clear(); m_reduced = false; - m_endTime = RealTime(); + m_endTime = real_time(); m_plugin->reset(); -} + } -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, - RealTime timestamp) -{ - if (m_reduced) { - cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << endl; - } - FeatureSet fs = m_plugin->process(inputBuffers, timestamp); - accumulate(fs, timestamp, false); - m_endTime = timestamp + - RealTime::frame2RealTime(m_stepSize, int(m_inputSampleRate + 0.5)); + plugin::FeatureSet PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, real_time timestamp) + { + if (m_reduced) { + std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; + } + FeatureSet fs = m_plugin->process(inputBuffers, timestamp); + accumulate(fs, timestamp, false); + m_endTime = timestamp + real_time::f2rt(m_stepSize, int(m_inputSampleRate + 0.5)); + return fs; + } + + plugin::FeatureSet PluginSummarisingAdapter::Impl::getRemainingFeatures() + { + if (m_reduced) { + std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; + } + FeatureSet fs = m_plugin->getRemainingFeatures(); + accumulate(fs, m_endTime, true); + return fs; + } + + void + PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b) + { + m_boundaries = b; #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "timestamp = " << timestamp << ", end time becomes " << m_endTime - << endl; + cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << endl; + for (SegmentBoundaries::const_iterator i = m_boundaries.begin(); + i != m_boundaries.end(); ++i) { + cerr << *i << " "; + } + cerr << endl; #endif - return fs; -} + } -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::getRemainingFeatures() -{ - if (m_reduced) { - cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << endl; - } - FeatureSet fs = m_plugin->getRemainingFeatures(); - accumulate(fs, m_endTime, true); - return fs; -} + plugin::FeatureList + PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, + SummaryType type, + AveragingMethod avg) + { + if (!m_reduced) { + accumulateFinalDurations(); + segment(); + reduce(); + m_reduced = true; + } -void -PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b) -{ - m_boundaries = b; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << endl; - for (SegmentBoundaries::const_iterator i = m_boundaries.begin(); - i != m_boundaries.end(); ++i) { - cerr << *i << " "; - } - cerr << endl; -#endif -} + bool continuous = (avg == ContinuousTimeAverage); -Plugin::FeatureList -PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, - SummaryType type, - AveragingMethod avg) -{ - if (!m_reduced) { - accumulateFinalDurations(); - segment(); - reduce(); - m_reduced = true; - } + FeatureList fl; + for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); + i != m_summaries[output].end(); ++i) { - bool continuous = (avg == ContinuousTimeAverage); + Feature f; - FeatureList fl; - for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); - i != m_summaries[output].end(); ++i) { + f.hasTimestamp = true; + f.timestamp = i->first; - Feature f; + f.hasDuration = true; + SummarySegmentMap::const_iterator ii = i; + if (++ii == m_summaries[output].end()) { + f.duration = m_endTime - f.timestamp; + } else { + f.duration = ii->first - f.timestamp; + } - f.hasTimestamp = true; - f.timestamp = i->first; + f.label = getSummaryLabel(type, avg); - f.hasDuration = true; - SummarySegmentMap::const_iterator ii = i; - if (++ii == m_summaries[output].end()) { - f.duration = m_endTime - f.timestamp; - } else { - f.duration = ii->first - f.timestamp; - } + for (OutputSummary::const_iterator j = i->second.begin(); + j != i->second.end(); ++j) { - f.label = getSummaryLabel(type, avg); + // these will be ordered by bin number, and no bin numbers + // will be missing except at the end (because of the way + // the accumulators were initially filled in accumulate()) - for (OutputSummary::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { + const OutputBinSummary &summary = j->second; + double result = 0.f; - // these will be ordered by bin number, and no bin numbers - // will be missing except at the end (because of the way - // the accumulators were initially filled in accumulate()) + switch (type) { - const OutputBinSummary &summary = j->second; - double result = 0.f; + case Minimum: + result = summary.minimum; + break; - switch (type) { + case Maximum: + result = summary.maximum; + break; - case Minimum: - result = summary.minimum; - break; + case Mean: + if (continuous) { + result = summary.mean_c; + } else if (summary.count) { + result = summary.sum / summary.count; + } + break; - case Maximum: - result = summary.maximum; - break; + case Median: + if (continuous) result = summary.median_c; + else result = summary.median; + break; - case Mean: - if (continuous) { - result = summary.mean_c; - } else if (summary.count) { - result = summary.sum / summary.count; - } - break; + case Mode: + if (continuous) result = summary.mode_c; + else result = summary.mode; + break; - case Median: - if (continuous) result = summary.median_c; - else result = summary.median; - break; + case Sum: + result = summary.sum; + break; - case Mode: - if (continuous) result = summary.mode_c; - else result = summary.mode; - break; + case Variance: + if (continuous) result = summary.variance_c; + else result = summary.variance; + break; - case Sum: - result = summary.sum; - break; + case StandardDeviation: + if (continuous) result = sqrt(summary.variance_c); + else result = sqrt(summary.variance); + break; - case Variance: - if (continuous) result = summary.variance_c; - else result = summary.variance; - break; + case Count: + result = summary.count; + break; - case StandardDeviation: - if (continuous) result = sqrt(summary.variance_c); - else result = sqrt(summary.variance); - break; + case UnknownSummaryType: + break; - case Count: - result = summary.count; - break; + default: + break; + } + + f.values.push_back(float(result)); + } - case UnknownSummaryType: - break; + fl.push_back(f); + } + return fl; + } - default: - break; - } - - f.values.push_back(float(result)); - } + plugin::FeatureSet + PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, + AveragingMethod avg) + { + if (!m_reduced) { + accumulateFinalDurations(); + segment(); + reduce(); + m_reduced = true; + } - fl.push_back(f); - } - return fl; -} + FeatureSet fs; + for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); + i != m_summaries.end(); ++i) { + fs[i->first] = getSummaryForOutput(i->first, type, avg); + } + return fs; + } -Plugin::FeatureSet -PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, - AveragingMethod avg) -{ - if (!m_reduced) { - accumulateFinalDurations(); - segment(); - reduce(); - m_reduced = true; - } + void + PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs, + real_time timestamp, + bool final) + { + for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) { + for (FeatureList::const_iterator j = i->second.begin(); + j != i->second.end(); ++j) { + if (j->hasTimestamp) { + accumulate(i->first, *j, j->timestamp, final); + } else { + //!!! is this correct? + accumulate(i->first, *j, timestamp, final); + } + } + } + } - FeatureSet fs; - for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); - i != m_summaries.end(); ++i) { - fs[i->first] = getSummaryForOutput(i->first, type, avg); - } - return fs; -} + std::string + PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type, + AveragingMethod avg) + { + std::string label; + std::string avglabel; -void -PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs, - RealTime timestamp, - bool final) -{ - for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) { - for (FeatureList::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { - if (j->hasTimestamp) { - accumulate(i->first, *j, j->timestamp, final); - } else { - //!!! is this correct? - accumulate(i->first, *j, timestamp, final); - } - } - } -} + if (avg == SampleAverage) avglabel = ", sample average"; + else avglabel = ", continuous-time average"; -string -PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type, - AveragingMethod avg) -{ - string label; - string avglabel; + switch (type) { + case Minimum: label = "(minimum value)"; break; + case Maximum: label = "(maximum value)"; break; + case Mean: label = "(mean value" + avglabel + ")"; break; + case Median: label = "(median value" + avglabel + ")"; break; + case Mode: label = "(modal value" + avglabel + ")"; break; + case Sum: label = "(sum)"; break; + case Variance: label = "(variance" + avglabel + ")"; break; + case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break; + case Count: label = "(count)"; break; + case UnknownSummaryType: label = "(unknown summary)"; break; + } + + return label; + } - if (avg == SampleAverage) avglabel = ", sample average"; - else avglabel = ", continuous-time average"; + void + PluginSummarisingAdapter::Impl::accumulate(int output, const Feature &f, real_time timestamp, bool) + { + if (m_prevDurations.find(output) != m_prevDurations.end()) { - switch (type) { - case Minimum: label = "(minimum value)"; break; - case Maximum: label = "(maximum value)"; break; - case Mean: label = "(mean value" + avglabel + ")"; break; - case Median: label = "(median value" + avglabel + ")"; break; - case Mode: label = "(modal value" + avglabel + ")"; break; - case Sum: label = "(sum)"; break; - case Variance: label = "(variance" + avglabel + ")"; break; - case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break; - case Count: label = "(count)"; break; - case UnknownSummaryType: label = "(unknown summary)"; break; - } - - return label; -} + real_time prevDuration; -void -PluginSummarisingAdapter::Impl::accumulate(int output, - const Feature &f, - RealTime timestamp, - bool -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - final -#endif - ) -{ - // What should happen if a feature's duration spans a segment - // boundary? I think we probably want to chop it, and pretend - // that it appears in both. A very long feature (e.g. key, if the - // whole audio is in a single key) might span many or all - // segments, and we want that to be reflected in the results - // (e.g. it is the modal key in all of those segments, not just - // the first). This is actually quite complicated to do. + // Note that m_prevDurations[output] only contains the + // duration field that was contained in the previous feature. + // If it didn't have an explicit duration, + // m_prevDurations[output] should be INVALID_DURATION and we + // will have to calculate the duration from the previous and + // current timestamps. - // If features spanning a boundary should be chopped, then we need - // to have per-segment accumulators (and the feature value goes - // into both -- with a separate phase to split the accumulator up - // into segments). + if (m_prevDurations[output] != INVALID_DURATION) { + prevDuration = m_prevDurations[output]; + } else { + prevDuration = timestamp - m_prevTimestamps[output]; + } -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << endl; -#endif + + m_accumulators[output].results + [m_accumulators[output].results.size() - 1] + .duration = prevDuration; + } - // At each process step, accumulate() is called once for each - // feature on each output within that process's returned feature - // list, and with the timestamp passed in being that of the start - // of the process block. + if (f.hasDuration) m_prevDurations[output] = f.duration; + else m_prevDurations[output] = INVALID_DURATION; - // At the end (in getRemainingFeatures), accumulate() is called - // once for each feature on each output within the feature list - // returned by getRemainingFeatures, and with the timestamp being - // the same as the last process block and final set to true. + m_prevTimestamps[output] = timestamp; - // (What if getRemainingFeatures doesn't return any features? We - // still need to ensure that the final duration is written. Need - // a separate function to close the durations.) + if (f.hasDuration) { + real_time et = timestamp; + et = et + f.duration; + if (et > m_endTime) m_endTime = et; + } - // At each call, we pull out the value for the feature and stuff - // it into the accumulator's appropriate values array; and we - // calculate the duration for the _previous_ feature, or pull it - // from the prevDurations array if the previous feature had a - // duration in its structure, and stuff that into the - // accumulator's appropriate durations array. + Result result; + result.time = timestamp; + result.duration = INVALID_DURATION; - if (m_prevDurations.find(output) != m_prevDurations.end()) { + if (int(f.values.size()) > m_accumulators[output].bins) { + m_accumulators[output].bins = int(f.values.size()); + } - // Not the first time accumulate has been called for this - // output -- there has been a previous feature + for (int i = 0; i < int(f.values.size()); ++i) { + result.values.push_back(f.values[i]); + } - RealTime prevDuration; + m_accumulators[output].results.push_back(result); + } - // Note that m_prevDurations[output] only contains the - // duration field that was contained in the previous feature. - // If it didn't have an explicit duration, - // m_prevDurations[output] should be INVALID_DURATION and we - // will have to calculate the duration from the previous and - // current timestamps. + void + PluginSummarisingAdapter::Impl::accumulateFinalDurations() + { + for (OutputTimestampMap::iterator i = m_prevTimestamps.begin(); + i != m_prevTimestamps.end(); ++i) { - if (m_prevDurations[output] != INVALID_DURATION) { - prevDuration = m_prevDurations[output]; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "Previous duration from previous feature: " << prevDuration << endl; -#endif - } else { - prevDuration = timestamp - m_prevTimestamps[output]; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "Previous duration from diff: " << timestamp << " - " - << m_prevTimestamps[output] << endl; -#endif - } + int output = i->first; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "output " << output << ": "; - cerr << "Pushing previous duration as " << prevDuration << endl; -#endif - - m_accumulators[output].results - [m_accumulators[output].results.size() - 1] - .duration = prevDuration; - } + int acount = int(m_accumulators[output].results.size()); - if (f.hasDuration) m_prevDurations[output] = f.duration; - else m_prevDurations[output] = INVALID_DURATION; + if (acount == 0) continue; - m_prevTimestamps[output] = timestamp; + if (m_prevDurations.find(output) != m_prevDurations.end() && + m_prevDurations[output] != INVALID_DURATION) { + m_accumulators[output].results[acount - 1].duration = + m_prevDurations[output]; - if (f.hasDuration) { - RealTime et = timestamp; - et = et + f.duration; - if (et > m_endTime) m_endTime = et; -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "feature has duration, updating end time to " << m_endTime << endl; -#endif - } + } else { - Result result; - result.time = timestamp; - result.duration = INVALID_DURATION; + m_accumulators[output].results[acount - 1].duration = + m_endTime - m_prevTimestamps[output]; + } + + } + } - if (int(f.values.size()) > m_accumulators[output].bins) { - m_accumulators[output].bins = int(f.values.size()); - } - - for (int i = 0; i < int(f.values.size()); ++i) { - result.values.push_back(f.values[i]); - } - - m_accumulators[output].results.push_back(result); -} - -void -PluginSummarisingAdapter::Impl::accumulateFinalDurations() -{ - for (OutputTimestampMap::iterator i = m_prevTimestamps.begin(); - i != m_prevTimestamps.end(); ++i) { - - int output = i->first; - - int acount = int(m_accumulators[output].results.size()); - - if (acount == 0) continue; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "output " << output << ": "; -#endif - - if (m_prevDurations.find(output) != m_prevDurations.end() && - m_prevDurations[output] != INVALID_DURATION) { - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "Pushing final duration from feature as " << m_prevDurations[output] << endl; -#endif - - m_accumulators[output].results[acount - 1].duration = - m_prevDurations[output]; - - } else { - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << endl; -#endif - - m_accumulators[output].results[acount - 1].duration = - m_endTime - m_prevTimestamps[output]; - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "so duration for result no " << acount-1 << " is " - << m_accumulators[output].results[acount-1].duration - << endl; -#endif - } -} - -void -PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t, - RealTime &start, - RealTime &end) -{ + void + PluginSummarisingAdapter::Impl::findSegmentBounds(real_time t, + real_time &start, + real_time &end) + { #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "findSegmentBounds: t = " << t << endl; + cerr << "findSegmentBounds: t = " << t << endl; #endif - SegmentBoundaries::const_iterator i = upper_bound - (m_boundaries.begin(), m_boundaries.end(), t); + SegmentBoundaries::const_iterator i = std::upper_bound(m_boundaries.begin(), m_boundaries.end(), t); - start = RealTime::zeroTime; - end = m_endTime; + start = real_time::zero_time; + end = m_endTime; - if (i != m_boundaries.end()) { - end = *i; - } + if (i != m_boundaries.end()) { + end = *i; + } - if (i != m_boundaries.begin()) { - start = *--i; - } + if (i != m_boundaries.begin()) { + start = *--i; + } + } -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << endl; + void + PluginSummarisingAdapter::Impl::segment() + { + + for (OutputAccumulatorMap::iterator i = m_accumulators.begin(); + i != m_accumulators.end(); ++i) { + + int output = i->first; + OutputAccumulator &source = i->second; + + for (int n = 0; n < int(source.results.size()); ++n) { + real_time resultStart = source.results[n].time; + real_time resultEnd = resultStart + source.results[n].duration; + + real_time segmentStart = real_time::zero_time; + real_time segmentEnd = resultEnd - real_time(1, 0); + + real_time prevSegmentStart = segmentStart - real_time(1, 0); + + while (segmentEnd < resultEnd) { + + findSegmentBounds(resultStart, segmentStart, segmentEnd); + + if (segmentStart == prevSegmentStart) { + break; + } + prevSegmentStart = segmentStart; + + real_time chunkStart = resultStart; + if (chunkStart < segmentStart) chunkStart = segmentStart; + + real_time chunkEnd = resultEnd; + if (chunkEnd > segmentEnd) chunkEnd = segmentEnd; + + m_segmentedAccumulators[output][segmentStart].bins = source.bins; + + Result chunk; + chunk.time = chunkStart; + chunk.duration = chunkEnd - chunkStart; + chunk.values = source.results[n].values; + + m_segmentedAccumulators[output][segmentStart].results.push_back(chunk); + + resultStart = chunkEnd; + } + } + } + } + + struct ValueDurationFloatPair + { + float value; + float duration; + + ValueDurationFloatPair() : value(0), duration(0) { } + ValueDurationFloatPair(float v, float d) : value(v), duration(d) { } + ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) { + value = p.value; + duration = p.duration; + return *this; + } + bool operator<(const ValueDurationFloatPair &p) const { + return value < p.value; + } + }; + + static double toSec(const real_time &r) + { + return r.sec + double(r.nsec) / 1000000000.0; + } + + void + PluginSummarisingAdapter::Impl::reduce() + { + for (OutputSegmentAccumulatorMap::iterator i = + m_segmentedAccumulators.begin(); + i != m_segmentedAccumulators.end(); ++i) { + + int output = i->first; + SegmentAccumulatorMap &segments = i->second; + + for (SegmentAccumulatorMap::iterator j = segments.begin(); + j != segments.end(); ++j) { + + real_time segmentStart = j->first; + OutputAccumulator &accumulator = j->second; + + int sz = int(accumulator.results.size()); + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "reduce: segment starting at " << segmentStart + << " on output " << output << " has " << sz << " result(s)" << endl; #endif -} - -void -PluginSummarisingAdapter::Impl::segment() -{ -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "segment: starting" << endl; -#endif - - for (OutputAccumulatorMap::iterator i = m_accumulators.begin(); - i != m_accumulators.end(); ++i) { - - int output = i->first; - OutputAccumulator &source = i->second; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "segment: total results for output " << output << " = " - << source.results.size() << endl; -#endif - - // This is basically nonsense if the results have no values - // (i.e. their times and counts are the only things of - // interest)... but perhaps it's the user's problem if they - // ask for segmentation (or any summary at all) in that case - - for (int n = 0; n < int(source.results.size()); ++n) { - - // This result spans source.results[n].time to - // source.results[n].time + source.results[n].duration. - // We need to dispose it into segments appropriately - - RealTime resultStart = source.results[n].time; - RealTime resultEnd = resultStart + source.results[n].duration; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << endl; -#endif - - RealTime segmentStart = RealTime::zeroTime; - RealTime segmentEnd = resultEnd - RealTime(1, 0); - - RealTime prevSegmentStart = segmentStart - RealTime(1, 0); - - while (segmentEnd < resultEnd) { - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "segment end " << segmentEnd << " < result end " - << resultEnd << " (with result start " << resultStart << ")" << endl; -#endif - - findSegmentBounds(resultStart, segmentStart, segmentEnd); - - if (segmentStart == prevSegmentStart) { - // This can happen when we reach the end of the - // input, if a feature's end time overruns the - // input audio end time - break; - } - prevSegmentStart = segmentStart; - - RealTime chunkStart = resultStart; - if (chunkStart < segmentStart) chunkStart = segmentStart; - - RealTime chunkEnd = resultEnd; - if (chunkEnd > segmentEnd) chunkEnd = segmentEnd; - - m_segmentedAccumulators[output][segmentStart].bins = source.bins; - - Result chunk; - chunk.time = chunkStart; - chunk.duration = chunkEnd - chunkStart; - chunk.values = source.results[n].values; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT - cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << endl; -#endif - - m_segmentedAccumulators[output][segmentStart].results - .push_back(chunk); - - resultStart = chunkEnd; - } - } - } -} - -struct ValueDurationFloatPair -{ - float value; - float duration; - - ValueDurationFloatPair() : value(0), duration(0) { } - ValueDurationFloatPair(float v, float d) : value(v), duration(d) { } - ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) { - value = p.value; - duration = p.duration; - return *this; - } - bool operator<(const ValueDurationFloatPair &p) const { - return value < p.value; - } -}; - -static double toSec(const RealTime &r) -{ - return r.sec + double(r.nsec) / 1000000000.0; -} - -void -PluginSummarisingAdapter::Impl::reduce() -{ - for (OutputSegmentAccumulatorMap::iterator i = - m_segmentedAccumulators.begin(); - i != m_segmentedAccumulators.end(); ++i) { - - int output = i->first; - SegmentAccumulatorMap &segments = i->second; - - for (SegmentAccumulatorMap::iterator j = segments.begin(); - j != segments.end(); ++j) { - - RealTime segmentStart = j->first; - OutputAccumulator &accumulator = j->second; - - int sz = int(accumulator.results.size()); - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "reduce: segment starting at " << segmentStart - << " on output " << output << " has " << sz << " result(s)" << endl; -#endif - - double totalDuration = 0.0; - //!!! is this right? - if (sz > 0) { -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "last time = " << accumulator.results[sz-1].time - << ", duration = " << accumulator.results[sz-1].duration - << " (step = " << m_stepSize << ", block = " << m_blockSize << ")" - << endl; -#endif - totalDuration = toSec((accumulator.results[sz-1].time + - accumulator.results[sz-1].duration) - - segmentStart); - } - - for (int bin = 0; bin < accumulator.bins; ++bin) { - - // work on all values over time for a single bin - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "bin " << bin << ":" << endl; -#endif - - OutputBinSummary summary; - - summary.count = sz; - - summary.minimum = 0.f; - summary.maximum = 0.f; - - summary.median = 0.f; - summary.mode = 0.f; - summary.sum = 0.f; - summary.variance = 0.f; - - summary.median_c = 0.f; - summary.mode_c = 0.f; - summary.mean_c = 0.f; - summary.variance_c = 0.f; - - if (sz == 0) continue; - - vector valvec; - - for (int k = 0; k < sz; ++k) { - while (int(accumulator.results[k].values.size()) < - accumulator.bins) { - accumulator.results[k].values.push_back(0.f); - } - } - - for (int k = 0; k < sz; ++k) { - float value = accumulator.results[k].values[bin]; - valvec.push_back - (ValueDurationFloatPair - (value, - float(toSec(accumulator.results[k].duration)))); - } - - sort(valvec.begin(), valvec.end()); - - summary.minimum = valvec[0].value; - summary.maximum = valvec[sz-1].value; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "total duration = " << totalDuration << endl; -#endif - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER -/* - cerr << "value vector for medians:" << endl; - for (int k = 0; k < sz; ++k) { - cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") "; - } - cerr << endl; -*/ -#endif - - if (sz % 2 == 1) { - summary.median = valvec[sz/2].value; - } else { - summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2; - } - - double duracc = 0.0; - summary.median_c = valvec[sz-1].value; - - for (int k = 0; k < sz; ++k) { - duracc += valvec[k].duration; - if (duracc > totalDuration/2) { - summary.median_c = valvec[k].value; - break; - } - } - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "median_c = " << summary.median_c << endl; - cerr << "median = " << summary.median << endl; -#endif - - map distribution; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "summing (discrete): "; -#endif - for (int k = 0; k < sz; ++k) { -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << accumulator.results[k].values[bin] << " "; -#endif - summary.sum += accumulator.results[k].values[bin]; - distribution[accumulator.results[k].values[bin]] += 1; - } -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << endl; -#endif - - int md = 0; - - for (map::iterator di = distribution.begin(); - di != distribution.end(); ++di) { - if (di->second > md) { - md = di->second; - summary.mode = di->first; - } - } - - distribution.clear(); - - map distribution_c; - - for (int k = 0; k < sz; ++k) { - distribution_c[accumulator.results[k].values[bin]] - += toSec(accumulator.results[k].duration); - } - - double mrd = 0.0; - - for (map::iterator di = distribution_c.begin(); - di != distribution_c.end(); ++di) { - if (di->second > mrd) { -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "element " << di->first << " spans time " - << di->second << " and so is an improved mode " - << "candidate over element " << summary.mode_c - << " which spanned " << mrd << endl; -#endif - mrd = di->second; - summary.mode_c = di->first; - } - } - - distribution_c.clear(); - - if (totalDuration > 0.0) { - - double sum_c = 0.0; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "summing (continuous): "; -#endif - for (int k = 0; k < sz; ++k) { -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << accumulator.results[k].values[bin] << "*" - << toSec(accumulator.results[k].duration) << " "; -#endif - double value = accumulator.results[k].values[bin] - * toSec(accumulator.results[k].duration); - sum_c += value; - } -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << endl; -#endif - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "mean_c = " << sum_c << " / " << totalDuration << " = " - << sum_c / totalDuration << " (sz = " << sz << ")" << endl; -#endif - - summary.mean_c = sum_c / totalDuration; - - for (int k = 0; k < sz; ++k) { - double value = accumulator.results[k].values[bin]; -// * toSec(accumulator.results[k].duration); - summary.variance_c += - (value - summary.mean_c) * (value - summary.mean_c) - * toSec(accumulator.results[k].duration); - } - -// summary.variance_c /= summary.count; - summary.variance_c /= totalDuration; - } - - double mean = summary.sum / summary.count; - -#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER - cerr << "mean = " << summary.sum << " / " << summary.count << " = " - << summary.sum / summary.count << endl; -#endif - - for (int k = 0; k < sz; ++k) { - float value = accumulator.results[k].values[bin]; - summary.variance += (value - mean) * (value - mean); - } - summary.variance /= summary.count; - - m_summaries[output][segmentStart][bin] = summary; - } - } - } - - m_segmentedAccumulators.clear(); - m_accumulators.clear(); -} - - -} - + + double totalDuration = 0.0; + //!!! is this right? + if (sz > 0) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "last time = " << accumulator.results[sz-1].time + << ", duration = " << accumulator.results[sz-1].duration + << " (step = " << m_stepSize << ", block = " << m_blockSize << ")" + << endl; +#endif + totalDuration = toSec((accumulator.results[sz-1].time + + accumulator.results[sz-1].duration) - + segmentStart); + } + + for (int bin = 0; bin < accumulator.bins; ++bin) { + + // work on all values over time for a single bin + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "bin " << bin << ":" << endl; +#endif + + OutputBinSummary summary; + + summary.count = sz; + + summary.minimum = 0.f; + summary.maximum = 0.f; + + summary.median = 0.f; + summary.mode = 0.f; + summary.sum = 0.f; + summary.variance = 0.f; + + summary.median_c = 0.f; + summary.mode_c = 0.f; + summary.mean_c = 0.f; + summary.variance_c = 0.f; + + if (sz == 0) continue; + + std::vector valvec; + + for (int k = 0; k < sz; ++k) { + while (int(accumulator.results[k].values.size()) < + accumulator.bins) { + accumulator.results[k].values.push_back(0.f); + } + } + + for (int k = 0; k < sz; ++k) { + float value = accumulator.results[k].values[bin]; + valvec.push_back + (ValueDurationFloatPair + (value, + float(toSec(accumulator.results[k].duration)))); + } + + sort(valvec.begin(), valvec.end()); + + summary.minimum = valvec[0].value; + summary.maximum = valvec[sz-1].value; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "total duration = " << totalDuration << endl; +#endif + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + /* + cerr << "value vector for medians:" << endl; + for (int k = 0; k < sz; ++k) { + cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") "; + } + cerr << endl; + */ +#endif + + if (sz % 2 == 1) { + summary.median = valvec[sz/2].value; + } else { + summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2; + } + + double duracc = 0.0; + summary.median_c = valvec[sz-1].value; + + for (int k = 0; k < sz; ++k) { + duracc += valvec[k].duration; + if (duracc > totalDuration/2) { + summary.median_c = valvec[k].value; + break; + } + } + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "median_c = " << summary.median_c << endl; + cerr << "median = " << summary.median << endl; +#endif + + std::map distribution; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "summing (discrete): "; +#endif + for (int k = 0; k < sz; ++k) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << accumulator.results[k].values[bin] << " "; +#endif + summary.sum += accumulator.results[k].values[bin]; + distribution[accumulator.results[k].values[bin]] += 1; + } +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << endl; +#endif + + int md = 0; + + for (std::map::iterator di = distribution.begin(); + di != distribution.end(); ++di) { + if (di->second > md) { + md = di->second; + summary.mode = di->first; + } + } + + distribution.clear(); + + std::map distribution_c; + + for (int k = 0; k < sz; ++k) { + distribution_c[accumulator.results[k].values[bin]] + += toSec(accumulator.results[k].duration); + } + + double mrd = 0.0; + + for (std::map::iterator di = distribution_c.begin(); + di != distribution_c.end(); ++di) { + if (di->second > mrd) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "element " << di->first << " spans time " + << di->second << " and so is an improved mode " + << "candidate over element " << summary.mode_c + << " which spanned " << mrd << endl; +#endif + mrd = di->second; + summary.mode_c = di->first; + } + } + + distribution_c.clear(); + + if (totalDuration > 0.0) { + + double sum_c = 0.0; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "summing (continuous): "; +#endif + for (int k = 0; k < sz; ++k) { +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << accumulator.results[k].values[bin] << "*" + << toSec(accumulator.results[k].duration) << " "; +#endif + double value = accumulator.results[k].values[bin] + * toSec(accumulator.results[k].duration); + sum_c += value; + } +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << endl; +#endif + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "mean_c = " << sum_c << " / " << totalDuration << " = " + << sum_c / totalDuration << " (sz = " << sz << ")" << endl; +#endif + + summary.mean_c = sum_c / totalDuration; + + for (int k = 0; k < sz; ++k) { + double value = accumulator.results[k].values[bin]; + // * toSec(accumulator.results[k].duration); + summary.variance_c += + (value - summary.mean_c) * (value - summary.mean_c) + * toSec(accumulator.results[k].duration); + } + + // summary.variance_c /= summary.count; + summary.variance_c /= totalDuration; + } + + double mean = summary.sum / summary.count; + +#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER + cerr << "mean = " << summary.sum << " / " << summary.count << " = " + << summary.sum / summary.count << endl; +#endif + + for (int k = 0; k < sz; ++k) { + float value = accumulator.results[k].values[bin]; + summary.variance += (value - mean) * (value - mean); + } + summary.variance /= summary.count; + + m_summaries[output][segmentStart][bin] = summary; + } + } + } + + m_segmentedAccumulators.clear(); + m_accumulators.clear(); + } } diff --git a/src/vamp-hostsdk/PluginSummarisingAdapter.h b/src/vamp-hostsdk/PluginSummarisingAdapter.h index 28b804f..a3dc9df 100644 --- a/src/vamp-hostsdk/PluginSummarisingAdapter.h +++ b/src/vamp-hostsdk/PluginSummarisingAdapter.h @@ -4,80 +4,26 @@ #include -namespace Vamp { -namespace HostExt { - -/** - * \class PluginSummarisingAdapter PluginSummarisingAdapter.h - * - * PluginSummarisingAdapter is a Vamp plugin adapter that provides - * summarisation methods such as mean and median averages of output - * features, for use in any context where an available plugin produces - * individual values but the result that is actually needed is some - * sort of aggregate. - * - * To make use of PluginSummarisingAdapter, the host should configure, - * initialise and run the plugin through the adapter interface just as - * normal. Then, after the process and getRemainingFeatures methods - * have been properly called and processing is complete, the host may - * call getSummaryForOutput or getSummaryForAllOutputs to obtain - * summarised features: averages, maximum values, etc, depending on - * the SummaryType passed to the function. - * - * By default PluginSummarisingAdapter calculates a single summary of - * each output's feature across the whole duration of processed audio. - * A host needing summaries of sub-segments of the whole audio may - * call setSummarySegmentBoundaries before retrieving the summaries, - * providing a list of times such that one summary will be provided - * for each segment between two consecutive times. - * - * PluginSummarisingAdapter is straightforward rather than fast. It - * calculates all of the summary types for all outputs always, and - * then returns only the ones that are requested. It is designed on - * the basis that, for most features, summarising and storing - * summarised results is far cheaper than calculating the results in - * the first place. If this is not true for your particular feature, - * PluginSummarisingAdapter may not be the best approach for you. - * - * \note This class was introduced in version 2.0 of the Vamp plugin SDK. - */ - -class PluginSummarisingAdapter : public PluginWrapper +namespace vamp::host { -public: - /** - * Construct a PluginSummarisingAdapter wrapping the given plugin. - * The adapter takes ownership of the plugin, which will be - * deleted when the adapter is deleted. - */ - PluginSummarisingAdapter(Plugin *plugin); - virtual ~PluginSummarisingAdapter(); + class PluginSummarisingAdapter : public PluginWrapper + { + public: + PluginSummarisingAdapter(plugin* p); + virtual ~PluginSummarisingAdapter(); - bool initialise(size_t channels, size_t stepSize, size_t blockSize); + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + void reset(); - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); - FeatureSet getRemainingFeatures(); + FeatureSet process(const float *const *inputBuffers, real_time timestamp); + FeatureSet getRemainingFeatures(); - typedef std::set SegmentBoundaries; + typedef std::set SegmentBoundaries; - /** - * Specify a series of segment boundaries, such that one summary - * will be returned for each of the contiguous intra-boundary - * segments. This function must be called before - * getSummaryForOutput or getSummaryForAllOutputs. - * - * Note that you cannot retrieve results with multiple different - * segmentations by repeatedly calling this function followed by - * one of the getSummary functions. The summaries are all - * calculated at the first call to any getSummary function, and - * once the summaries have been calculated, they remain - * calculated. - */ - void setSummarySegmentBoundaries(const SegmentBoundaries &); + void setSummarySegmentBoundaries(const SegmentBoundaries &); - enum SummaryType { + enum SummaryType { Minimum = 0, Maximum = 1, Mean = 2, @@ -89,64 +35,19 @@ public: Count = 8, UnknownSummaryType = 999 - }; + }; - /** - * AveragingMethod indicates how the adapter should handle - * average-based summaries of features whose results are not - * equally spaced in time. - * - * If SampleAverage is specified, summary types based on averages - * will be calculated by treating each result individually without - * regard to its time: for example, the mean will be the sum of - * all values divided by the number of values. - * - * If ContinuousTimeAverage is specified, each feature will be - * considered to have a duration, either as specified in the - * feature's duration field, or until the following feature: thus, - * for example, the mean will be the sum of the products of values - * and durations, divided by the total duration. - * - * Although SampleAverage is useful for many types of feature, - * ContinuousTimeAverage is essential for some situations, for - * example finding the result that spans the largest proportion of - * the input given a feature that emits a new result only when the - * value changes (the modal value integrated over time). - */ - enum AveragingMethod { + enum AveragingMethod + { SampleAverage = 0, ContinuousTimeAverage = 1 - }; + }; - /** - * Return summaries of the features that were returned on the - * given output, using the given SummaryType and AveragingMethod. - * - * The plugin must have been fully run (process() and - * getRemainingFeatures() calls all made as appropriate) before - * this function is called. - */ - FeatureList getSummaryForOutput(int output, - SummaryType type, - AveragingMethod method = SampleAverage); - - /** - * Return summaries of the features that were returned on all of - * the plugin's outputs, using the given SummaryType and - * AveragingMethod. - * - * The plugin must have been fully run (process() and - * getRemainingFeatures() calls all made as appropriate) before - * this function is called. - */ - FeatureSet getSummaryForAllOutputs(SummaryType type, - AveragingMethod method = SampleAverage); - -protected: - class Impl; - Impl *m_impl; -}; - -} + FeatureList getSummaryForOutput(int output, SummaryType type, AveragingMethod method = SampleAverage); + FeatureSet getSummaryForAllOutputs(SummaryType type, AveragingMethod method = SampleAverage); + protected: + class Impl; + Impl *m_impl; + }; } diff --git a/src/vamp-hostsdk/PluginWrapper.cpp b/src/vamp-hostsdk/PluginWrapper.cpp index 44972ab..46fa4a4 100644 --- a/src/vamp-hostsdk/PluginWrapper.cpp +++ b/src/vamp-hostsdk/PluginWrapper.cpp @@ -1,157 +1,113 @@ #include "vamp-hostsdk/PluginWrapper.h" -namespace Vamp { - -namespace HostExt { - -PluginWrapper::PluginWrapper(Plugin *plugin) : - Plugin(plugin->getInputSampleRate()), - m_plugin(plugin) +namespace vamp::host { -} + PluginWrapper::PluginWrapper(plugin* p) : plugin(p->getInputSampleRate()), m_plugin(p) + { + } -PluginWrapper::~PluginWrapper() -{ + PluginWrapper::~PluginWrapper() + { delete m_plugin; -} + } -bool -PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ + bool PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize) + { return m_plugin->initialise(channels, stepSize, blockSize); -} + } -void -PluginWrapper::reset() -{ + void PluginWrapper::reset() + { m_plugin->reset(); -} + } -Plugin::InputDomain -PluginWrapper::getInputDomain() const -{ + plugin::InputDomain PluginWrapper::getInputDomain() const + { return m_plugin->getInputDomain(); -} + } -unsigned int -PluginWrapper::getVampApiVersion() const -{ - return m_plugin->getVampApiVersion(); -} + std::string PluginWrapper::get_identifier() const + { + return m_plugin->get_identifier(); + } -std::string -PluginWrapper::getIdentifier() const -{ - return m_plugin->getIdentifier(); -} + std::string PluginWrapper::get_name() const + { + return m_plugin->get_name(); + } -std::string -PluginWrapper::getName() const -{ - return m_plugin->getName(); -} + std::string PluginWrapper::get_description() const + { + return m_plugin->get_description(); + } -std::string -PluginWrapper::getDescription() const -{ - return m_plugin->getDescription(); -} + std::string PluginWrapper::get_maker() const + { + return m_plugin->get_maker(); + } -std::string -PluginWrapper::getMaker() const -{ - return m_plugin->getMaker(); -} + plugin::parameter_descriptors PluginWrapper::get_parameter_descriptors() const + { + return m_plugin->get_parameter_descriptors(); + } -int -PluginWrapper::getPluginVersion() const -{ - return m_plugin->getPluginVersion(); -} + float PluginWrapper::get_parameter(std::string parameter) const + { + return m_plugin->get_parameter(parameter); + } -std::string -PluginWrapper::getCopyright() const -{ - return m_plugin->getCopyright(); -} + void PluginWrapper::set_parameter(std::string parameter, float value) + { + m_plugin->set_parameter(parameter, value); + } -PluginBase::ParameterList -PluginWrapper::getParameterDescriptors() const -{ - return m_plugin->getParameterDescriptors(); -} + plugin::programs PluginWrapper::get_programs() const + { + return m_plugin->get_programs(); + } -float -PluginWrapper::getParameter(std::string parameter) const -{ - return m_plugin->getParameter(parameter); -} + std::string PluginWrapper::get_current_program() const + { + return m_plugin->get_current_program(); + } -void -PluginWrapper::setParameter(std::string parameter, float value) -{ - m_plugin->setParameter(parameter, value); -} + void PluginWrapper::select_program(std::string program) + { + m_plugin->select_program(program); + } -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 -{ + size_t PluginWrapper::getPreferredStepSize() const + { return m_plugin->getPreferredStepSize(); -} + } -size_t -PluginWrapper::getPreferredBlockSize() const -{ + size_t PluginWrapper::getPreferredBlockSize() const + { return m_plugin->getPreferredBlockSize(); -} + } -size_t -PluginWrapper::getMinChannelCount() const -{ + size_t PluginWrapper::getMinChannelCount() const + { return m_plugin->getMinChannelCount(); -} + } -size_t PluginWrapper::getMaxChannelCount() const -{ + size_t PluginWrapper::getMaxChannelCount() const + { return m_plugin->getMaxChannelCount(); -} + } -Plugin::OutputList -PluginWrapper::getOutputDescriptors() const -{ + plugin::OutputList PluginWrapper::getOutputDescriptors() const + { return m_plugin->getOutputDescriptors(); -} + } -Plugin::FeatureSet -PluginWrapper::process(const float *const *inputBuffers, RealTime timestamp) -{ + plugin::FeatureSet PluginWrapper::process(const float *const *inputBuffers, real_time timestamp) + { return m_plugin->process(inputBuffers, timestamp); -} + } -Plugin::FeatureSet -PluginWrapper::getRemainingFeatures() -{ + plugin::FeatureSet PluginWrapper::getRemainingFeatures() + { return m_plugin->getRemainingFeatures(); -} - -} - + } } diff --git a/src/vamp-hostsdk/PluginWrapper.h b/src/vamp-hostsdk/PluginWrapper.h index b28a3f8..e4983c3 100644 --- a/src/vamp-hostsdk/PluginWrapper.h +++ b/src/vamp-hostsdk/PluginWrapper.h @@ -2,87 +2,57 @@ #include "vamp-sdk/Plugin.h" -namespace Vamp::HostExt { - -/** - * \class PluginWrapper 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 +namespace vamp::host { -public: - virtual ~PluginWrapper(); - - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + class PluginWrapper : public plugin + { + public: + virtual ~PluginWrapper(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize) override; + void reset() override; - InputDomain getInputDomain() const; + InputDomain getInputDomain() const override; - 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; + std::string get_identifier() const override; + std::string get_name() const override; + std::string get_description() const override; + std::string get_maker() const override; - ParameterList getParameterDescriptors() const; - float getParameter(std::string) const; - void setParameter(std::string, float); + parameter_descriptors get_parameter_descriptors() const override; + float get_parameter(std::string) const override; + void set_parameter(std::string, float) override; - ProgramList getPrograms() const; - std::string getCurrentProgram() const; - void selectProgram(std::string); + programs get_programs() const override; + std::string get_current_program() const override; + void select_program(std::string) override; - size_t getPreferredStepSize() const; - size_t getPreferredBlockSize() const; + size_t getPreferredStepSize() const override; + size_t getPreferredBlockSize() const override; - size_t getMinChannelCount() const; - size_t getMaxChannelCount() const; + size_t getMinChannelCount() const override; + size_t getMaxChannelCount() const override; - OutputList getOutputDescriptors() const; + OutputList getOutputDescriptors() const override; - FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + FeatureSet process(const float *const *inputBuffers, real_time timestamp) override; - FeatureSet getRemainingFeatures(); + FeatureSet getRemainingFeatures() override; - /** - * Return a pointer to the plugin wrapper of type WrapperType - * surrounding this wrapper's plugin, if present. - * - * This is useful in situations where a plugin is wrapped by - * multiple different wrappers (one inside another) and the host - * wants to call some wrapper-specific function on one of the - * layers without having to care about the order in which they are - * wrapped. For example, the plugin returned by - * PluginLoader::loadPlugin may have more than one wrapper; if the - * host wanted to query or fine-tune some property of one of them, - * it would be hard to do so without knowing the order of the - * wrappers. This function therefore gives direct access to the - * wrapper of a particular type. - */ - template - WrapperType *getWrapper() { + template + WrapperType* getWrapper() + { WrapperType *w = dynamic_cast(this); if (w) return w; PluginWrapper *pw = dynamic_cast(m_plugin); if (pw) return pw->getWrapper(); return 0; - } + } -protected: - PluginWrapper(Plugin *plugin); // I take ownership of plugin - Plugin *m_plugin; -}; + protected: + PluginWrapper(plugin* p); + plugin* m_plugin; + }; } diff --git a/src/vamp-hostsdk/Window.h b/src/vamp-hostsdk/Window.h index 4c2b686..dcc53fe 100644 --- a/src/vamp-hostsdk/Window.h +++ b/src/vamp-hostsdk/Window.h @@ -6,7 +6,7 @@ template class Window { -public: + public: enum WindowType { RectangularWindow, BartlettWindow, @@ -46,7 +46,7 @@ public: WindowType getType() const { return m_type; } size_t getSize() const { return m_size; } -protected: + protected: WindowType m_type; size_t m_size; T *m_cache; diff --git a/src/vamp-hostsdk/acsymbols.cpp b/src/vamp-hostsdk/acsymbols.cpp deleted file mode 100644 index 36963bd..0000000 --- a/src/vamp-hostsdk/acsymbols.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* These stubs are provided so that autoconf can check library - * versions using C symbols only */ - -extern void libvamphostsdk_v_2_9_present(void) { } -extern void libvamphostsdk_v_2_8_present(void) { } -extern void libvamphostsdk_v_2_7_1_present(void) { } -extern void libvamphostsdk_v_2_7_present(void) { } -extern void libvamphostsdk_v_2_6_present(void) { } -extern void libvamphostsdk_v_2_5_present(void) { } -extern void libvamphostsdk_v_2_4_present(void) { } -extern void libvamphostsdk_v_2_3_1_present(void) { } -extern void libvamphostsdk_v_2_3_present(void) { } -extern void libvamphostsdk_v_2_2_1_present(void) { } -extern void libvamphostsdk_v_2_2_present(void) { } -extern void libvamphostsdk_v_2_1_present(void) { } -extern void libvamphostsdk_v_2_0_present(void) { } diff --git a/src/vamp-hostsdk/host-c.cpp b/src/vamp-hostsdk/host-c.cpp index 0ec11a5..cc8373b 100644 --- a/src/vamp-hostsdk/host-c.cpp +++ b/src/vamp-hostsdk/host-c.cpp @@ -6,10 +6,8 @@ #include -using namespace std; - -static vector files; -static map cnames; +static std::vector files; +static std::map cnames; static bool haveFiles = false; struct vhLibrary_t { @@ -63,7 +61,7 @@ vhLibrary vhLoadLibrary(int index) return 0; } - string fullPath = files[index]; + std::string fullPath = files[index]; void *lib = Files::loadLibrary(fullPath); if (!lib) return 0; @@ -72,8 +70,8 @@ vhLibrary vhLoadLibrary(int index) (VampGetPluginDescriptorFunction)Files::lookupInLibrary (lib, "vampGetPluginDescriptor"); if (!func) { - cerr << "vhLoadLibrary: No vampGetPluginDescriptor function found in library \"" - << fullPath << "\"" << endl; + std::cerr << "vhLoadLibrary: No vampGetPluginDescriptor function found in library \"" + << fullPath << "\"" << std::endl; Files::unloadLibrary(lib); return 0; } diff --git a/src/vamp-hostsdk/vamp-hostsdk.h b/src/vamp-hostsdk/vamp-hostsdk.h index f32583d..a358e69 100644 --- a/src/vamp-hostsdk/vamp-hostsdk.h +++ b/src/vamp-hostsdk/vamp-hostsdk.h @@ -1,53 +1,9 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +#pragma once -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#ifndef _VAMP_HOSTSDK_SINGLE_INCLUDE_H_ -#define _VAMP_HOSTSDK_SINGLE_INCLUDE_H_ - -#include "PluginBase.h" #include "PluginBufferingAdapter.h" #include "PluginChannelAdapter.h" -#include "Plugin.h" #include "PluginHostAdapter.h" #include "PluginInputDomainAdapter.h" #include "PluginLoader.h" #include "PluginSummarisingAdapter.h" #include "PluginWrapper.h" -#include "RealTime.h" - -#endif - - diff --git a/src/vamp-sdk/FFT.cpp b/src/vamp-sdk/FFT.cpp index 734c341..89a98a2 100644 --- a/src/vamp-sdk/FFT.cpp +++ b/src/vamp-sdk/FFT.cpp @@ -6,7 +6,8 @@ #include "vamp-sdk/ext/vamp_kiss_fft.h" #include "vamp-sdk/ext/vamp_kiss_fftr.h" -namespace Vamp { +namespace vamp +{ void FFT::forward(unsigned int un, const double* ri, const double* ii, double* ro, double* io) { diff --git a/src/vamp-sdk/FFT.h b/src/vamp-sdk/FFT.h index 130d493..becada3 100644 --- a/src/vamp-sdk/FFT.h +++ b/src/vamp-sdk/FFT.h @@ -1,6 +1,7 @@ #pragma once -namespace Vamp { +namespace vamp +{ /** * A simple FFT implementation provided for convenience of plugin diff --git a/src/vamp-sdk/Plugin.h b/src/vamp-sdk/Plugin.h index 9c4961c..7811ce6 100644 --- a/src/vamp-sdk/Plugin.h +++ b/src/vamp-sdk/Plugin.h @@ -4,409 +4,120 @@ #include #include -#include "PluginBase.h" -#include "RealTime.h" +#include "real_time/real_time.hpp" -namespace Vamp { - -/** - * \class Plugin 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 +namespace vamp { -public: - virtual ~Plugin() { } + class plugin + { + 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; + enum InputDomain { TimeDomain, FrequencyDomain }; - /** - * 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; + struct OutputDescriptor + { + std::string identifier; + std::string name; + std::string description; + std::string unit; + bool hasFixedBinCount; + size_t binCount; + std::vector binNames; + bool hasKnownExtents; + float minValue; + float maxValue; + bool isQuantized; + float quantizeStep; - 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 - * input data for the FFT will be rotated so as to place the - * origin in the centre of the block. - * 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; + enum SampleType + { + OneSamplePerStep, + FixedSampleRate, + VariableSampleRate + }; - /** - * 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; } + SampleType sampleType; + float sampleRate; - /** - * 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 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; - - /** - * True if the returned results for this output are known to - * have a duration field. - */ bool hasDuration; - OutputDescriptor() : // defaults for mandatory non-class-type members - hasFixedBinCount(false), - binCount(0), - hasKnownExtents(false), - minValue(0), - maxValue(0), - isQuantized(false), - quantizeStep(0), - sampleType(OneSamplePerStep), - sampleRate(0), - hasDuration(false) { } - }; + OutputDescriptor() : + hasFixedBinCount(false), + binCount(0), + hasKnownExtents(false), + minValue(0), + maxValue(0), + isQuantized(false), + quantizeStep(0), + sampleType(OneSamplePerStep), + sampleRate(0), + hasDuration(false) { } + }; - typedef std::vector OutputList; + using OutputList = std::vector; - /** - * 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, optional if - * the output has FixedSampleRate, and unused if the output - * has OneSamplePerStep. - */ - bool hasTimestamp; - - /** - * Timestamp of the output feature. This is mandatory if the - * output has VariableSampleRate or if the output has - * FixedSampleRate and hasTimestamp is true, and unused - * otherwise. - */ - RealTime timestamp; - - /** - * True if an output feature has a specified duration. This - * is optional if the output has VariableSampleRate or - * FixedSampleRate, and and unused if the output has - * OneSamplePerStep. - */ + struct Feature + { + bool hasTimestamp; + real_time timestamp; bool hasDuration; + real_time duration; + std::vector values; + std::string label; + Feature() : hasTimestamp(false), hasDuration(false) { } + }; - /** - * Duration of the output feature. This is mandatory if the - * output has VariableSampleRate or FixedSampleRate and - * hasDuration is true, and unused otherwise. - */ - RealTime duration; - - /** - * 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 values; + using FeatureList = std::vector; + using FeatureSet = std::map; - /** - * Label for the sample of this feature. - */ - std::string label; + virtual OutputList getOutputDescriptors() const = 0; + virtual bool initialise(size_t inputChannels, size_t stepSize, size_t blockSize) = 0; + virtual void reset() = 0; + virtual InputDomain getInputDomain() const = 0; + virtual size_t getPreferredBlockSize() const { return 0; } + virtual size_t getPreferredStepSize() const { return 0; } + virtual size_t getMinChannelCount() const { return 1; } + virtual size_t getMaxChannelCount() const { return 1; } + virtual FeatureSet process(const float *const *inputBuffers, real_time timestamp) = 0; + virtual FeatureSet getRemainingFeatures() = 0; + virtual std::string get_type() const { return "Feature Extraction Plugin"; } - Feature() : // defaults for mandatory non-class-type members - hasTimestamp(false), hasDuration(false) { } - }; + float getInputSampleRate() const { return m_inputSampleRate; } - typedef std::vector FeatureList; - typedef std::map FeatureSet; // key is output no + struct parameter_descriptor + { + std::string identifier; + std::string name; + std::string description; + std::string unit; + float min_value { 0.f }; + float max_value { 0.f }; + float default_value { 0.f }; + bool is_quantized { false }; + float quantize_step { 0.f }; + std::vector value_names; + }; - /** - * 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 in this - * case 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; + using parameter_descriptors = std::vector; + using programs = std::vector; - /** - * 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"; } - - /** - * Retrieve the input sample rate set on construction. - */ - float getInputSampleRate() const { return m_inputSampleRate; } - -protected: - Plugin(float inputSampleRate) : - m_inputSampleRate(inputSampleRate) { } - - float m_inputSampleRate; -}; + public: + virtual std::string get_identifier() const = 0; + virtual std::string get_name() const = 0; + virtual std::string get_description() const = 0; + virtual std::string get_maker() const = 0; + virtual float get_parameter(std::string) const { return 0.f; } + virtual std::string get_current_program() const { return ""; } + virtual parameter_descriptors get_parameter_descriptors() const { return parameter_descriptors(); } + virtual programs get_programs() const { return programs(); } + virtual void set_parameter(std::string, float) { } + virtual void select_program(std::string) { } + + protected: + plugin(float inputSampleRate) : m_inputSampleRate(inputSampleRate) { } + float m_inputSampleRate; + }; } diff --git a/src/vamp-sdk/PluginAdapter.cpp b/src/vamp-sdk/PluginAdapter.cpp index 97f3d42..4d7c04c 100644 --- a/src/vamp-sdk/PluginAdapter.cpp +++ b/src/vamp-sdk/PluginAdapter.cpp @@ -5,960 +5,778 @@ #include -using std::map; -using std::vector; -using std::string; -using std::cerr; -using std::endl; -using std::mutex; -using std::lock_guard; - -namespace Vamp { - -class PluginAdapterBase::Impl +namespace vamp { -public: - Impl(PluginAdapterBase *); - ~Impl(); + class PluginAdapterBase::Impl + { + public: + Impl(PluginAdapterBase *); + ~Impl(); - const VampPluginDescriptor *getDescriptor(); + const VampPluginDescriptor *getDescriptor(); -protected: - PluginAdapterBase *m_base; + protected: + PluginAdapterBase *m_base; - static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc, - float inputSampleRate); + static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc, + float inputSampleRate); - static void vampCleanup(VampPluginHandle handle); + static void vampCleanup(VampPluginHandle handle); - static int vampInitialise(VampPluginHandle handle, unsigned int channels, - unsigned int stepSize, unsigned int blockSize); + static int vampInitialise(VampPluginHandle handle, unsigned int channels, + unsigned int stepSize, unsigned int blockSize); - static void vampReset(VampPluginHandle handle); + static void vampReset(VampPluginHandle handle); - static float vampGetParameter(VampPluginHandle handle, int param); - static void vampSetParameter(VampPluginHandle handle, int param, float value); + 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 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 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 unsigned int vampGetOutputCount(VampPluginHandle handle); - static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle, - unsigned int i); + static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle, + unsigned int i); - static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc); + static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc); - static VampFeatureList *vampProcess(VampPluginHandle handle, - const float *const *inputBuffers, - int sec, - int nsec); + static VampFeatureList *vampProcess(VampPluginHandle handle, + const float *const *inputBuffers, + int sec, + int nsec); - static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle); + static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle); - static void vampReleaseFeatureSet(VampFeatureList *fs); + static void vampReleaseFeatureSet(VampFeatureList *fs); - void checkOutputMap(Plugin *plugin); - void markOutputsChanged(Plugin *plugin); + void checkOutputMap(plugin* p); + void markOutputsChanged(plugin* p); - void cleanup(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); + void cleanup(plugin* p); + unsigned int getOutputCount(plugin* p); + VampOutputDescriptor *getOutputDescriptor(plugin* p, unsigned int i); + VampFeatureList *process(plugin* p, const float *const *inputBuffers, int sec, int nsec); + VampFeatureList *getRemainingFeatures(plugin* p); + VampFeatureList *convertFeatures(plugin* p, const plugin::FeatureSet &features); + + // maps both plugins and descriptors to adapters + typedef std::map AdapterMap; + + static AdapterMap *m_adapterMap; + + static std::mutex &adapterMapMutex() { + static std::mutex m; + return m; + } + + static Impl *lookupAdapter(VampPluginHandle); + + std::mutex m_mutex; // guards all of the below + + bool m_populated; + VampPluginDescriptor m_descriptor; + plugin::parameter_descriptors m_parameters; + plugin::programs m_programs; + + typedef std::map OutputMap; + OutputMap m_pluginOutputs; + + std::map m_fs; + std::map > m_fsizes; + std::map > > m_fvsizes; + void resizeFS(plugin* p, int n); + void resizeFL(plugin* p, int n, size_t sz); + void resizeFV(plugin* p, 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) + { + + (void)adapterMapMutex(); // see comment in adapterMapMutex function above + } + + const VampPluginDescriptor * + PluginAdapterBase::Impl::getDescriptor() + { + + std::lock_guard guard(m_mutex); + + if (m_populated) return &m_descriptor; + + plugin *p = m_base->createPlugin(48000); - // maps both plugins and descriptors to adapters - typedef map AdapterMap; + if (!p) { + std::cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << std::endl; + return 0; + } - static AdapterMap *m_adapterMap; + m_parameters = p->get_parameter_descriptors(); + m_programs = p->get_programs(); - static mutex &adapterMapMutex() { - // If this mutex was a global static, then it might be - // destroyed before the last adapter, and we would end up - // trying to lock an invalid mutex when removing an adapter - // from the adapter map. To ensure it outlasts the adapters, - // we need to ensure it is constructed before the construction - // of any of them is complete, since destruction order is - // reverse of construction. So we have to make sure this is - // called from the PluginAdapterBase::Impl constructor below. - static mutex m; - return m; - } - - static Impl *lookupAdapter(VampPluginHandle); + m_descriptor.identifier = strdup(p->get_identifier().c_str()); + m_descriptor.name = strdup(p->get_name().c_str()); + m_descriptor.description = strdup(p->get_description().c_str()); + m_descriptor.maker = strdup(p->get_maker().c_str()); + + m_descriptor.parameterCount = m_parameters.size(); + m_descriptor.parameters = (const VampParameterDescriptor **) + malloc(m_parameters.size() * sizeof(VampParameterDescriptor)); - mutex m_mutex; // guards all of the below + 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].min_value; + desc->maxValue = m_parameters[i].max_value; + desc->defaultValue = m_parameters[i].default_value; + desc->isQuantized = m_parameters[i].is_quantized; + desc->quantizeStep = m_parameters[i].quantize_step; + desc->valueNames = 0; + if (desc->isQuantized && !m_parameters[i].value_names.empty()) { + desc->valueNames = (const char **) + malloc((m_parameters[i].value_names.size()+1) * sizeof(char *)); + for (unsigned int j = 0; j < m_parameters[i].value_names.size(); ++j) { + desc->valueNames[j] = strdup(m_parameters[i].value_names[j].c_str()); + } + desc->valueNames[m_parameters[i].value_names.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 (p->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; + + std::lock_guard adapterMapGuard(adapterMapMutex()); + + if (!m_adapterMap) { + m_adapterMap = new AdapterMap; + } + (*m_adapterMap)[&m_descriptor] = this; + + delete p; + + m_populated = true; + return &m_descriptor; + } + + PluginAdapterBase::Impl::~Impl() + { + std::lock_guard guard(m_mutex); + + 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 *)desc); + } + 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); + + std::lock_guard adapterMapGuard(adapterMapMutex()); + + 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) + { + std::lock_guard adapterMapGuard(adapterMapMutex()); + + 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) + { + std::lock_guard adapterMapGuard(adapterMapMutex()); + + 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* p = adapter->m_base->createPlugin(inputSampleRate); + if (p) { + (*m_adapterMap)[p] = adapter; + } + return p; + } + + void + PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle) + { + + 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) + { + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + bool result = ((plugin*)handle)->initialise(channels, stepSize, blockSize); + adapter->markOutputsChanged((plugin*)handle); + return result ? 1 : 0; + } + + void + PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) + { + ((plugin *)handle)->reset(); + } + + float + PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle, + int param) + { + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0.0; + plugin::parameter_descriptors &list = adapter->m_parameters; + return ((plugin *)handle)->get_parameter(list[param].identifier); + } + + void + PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle, + int param, float value) + { + Impl *adapter = lookupAdapter(handle); + if (!adapter) return; + plugin::parameter_descriptors &list = adapter->m_parameters; + ((plugin *)handle)->set_parameter(list[param].identifier, value); + adapter->markOutputsChanged((plugin *)handle); + } + + unsigned int + PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle) + { + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + plugin::programs &list = adapter->m_programs; + std::string program = ((plugin *)handle)->get_current_program(); + 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 + cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return; + + plugin::programs &list = adapter->m_programs; + ((plugin *)handle)->select_program(list[program]); + + adapter->markOutputsChanged((plugin *)handle); + } + + unsigned int + PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle) + { + return ((plugin *)handle)->getPreferredStepSize(); + } + + unsigned int + PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) + { + return ((plugin *)handle)->getPreferredBlockSize(); + } + + unsigned int + PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle) + { + return ((plugin *)handle)->getMinChannelCount(); + } + + unsigned int PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle) + { + return ((plugin *)handle)->getMaxChannelCount(); + } + + unsigned int + PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle) + { + Impl *adapter = lookupAdapter(handle); + + if (!adapter) return 0; + return adapter->getOutputCount((plugin *)handle); + } + + VampOutputDescriptor * + PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle, + unsigned int i) + { + Impl *adapter = lookupAdapter(handle); + + if (!adapter) return 0; + return adapter->getOutputDescriptor((plugin *)handle, i); + } + + void + PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc) + { + 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) + { + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->process((plugin *)handle, inputBuffers, sec, nsec); + } + + VampFeatureList * + PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle) + { + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->getRemainingFeatures((plugin *)handle); + } + + void + PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *) + { + } + + void + PluginAdapterBase::Impl::cleanup(plugin* p) + { + + std::lock_guard adapterMapGuard(adapterMapMutex()); + std::lock_guard guard(m_mutex); + + if (m_fs.find(p) != m_fs.end()) { + size_t outputCount = 0; + if (m_pluginOutputs[p]) { + outputCount = m_pluginOutputs[p]->size(); + } + VampFeatureList *list = m_fs[p]; + for (unsigned int i = 0; i < outputCount; ++i) { + for (unsigned int j = 0; j < m_fsizes[p][i]; ++j) { + if (list[i].features[j].v1.label) { + free(list[i].features[j].v1.label); + } + if (list[i].features[j].v1.values) { + free(list[i].features[j].v1.values); + } + } + if (list[i].features) free(list[i].features); + } + if (list) free((void *)list); + m_fs.erase(p); + m_fsizes.erase(p); + m_fvsizes.erase(p); + } + + if (m_pluginOutputs.find(p) != m_pluginOutputs.end()) { + delete m_pluginOutputs[p]; + m_pluginOutputs.erase(p); + } + + if (m_adapterMap) { + m_adapterMap->erase(p); + + if (m_adapterMap->empty()) { + delete m_adapterMap; + m_adapterMap = 0; + } + } + + delete ((plugin *)p); + } + + void + PluginAdapterBase::Impl::checkOutputMap(plugin* p) + { + // must be called with m_mutex held + + OutputMap::iterator i = m_pluginOutputs.find(p); + + if (i == m_pluginOutputs.end() || !i->second) { + + m_pluginOutputs[p] = new plugin::OutputList(p->getOutputDescriptors()); + } + } + + void + PluginAdapterBase::Impl::markOutputsChanged(plugin* p) + { + std::lock_guard guard(m_mutex); + + OutputMap::iterator i = m_pluginOutputs.find(p); + + if (i != m_pluginOutputs.end()) { + + plugin::OutputList *list = i->second; + m_pluginOutputs.erase(i); + delete list; + } + } + + unsigned int + PluginAdapterBase::Impl::getOutputCount(plugin* p) + { + std::lock_guard guard(m_mutex); + + checkOutputMap(p); + + return m_pluginOutputs[p]->size(); + } + + VampOutputDescriptor * + PluginAdapterBase::Impl::getOutputDescriptor(plugin* p, unsigned int i) + { + std::lock_guard guard(m_mutex); + + checkOutputMap(p); + + plugin::OutputDescriptor &od = (*m_pluginOutputs[p])[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; + desc->hasDuration = od.hasDuration; + + return desc; + } + + VampFeatureList * + PluginAdapterBase::Impl::process(plugin *plugin, + const float *const *inputBuffers, + int sec, int nsec) + { + // cerr << "PluginAdapterBase::Impl::process" << endl; + + real_time rt(sec, nsec); + + // We don't want to hold the mutex during the actual process call, + // only while looking up the associated metadata + { + std::lock_guard guard(m_mutex); + checkOutputMap(plugin); + } + + return convertFeatures(plugin, plugin->process(inputBuffers, rt)); + } + + VampFeatureList * + PluginAdapterBase::Impl::getRemainingFeatures(plugin* p) + { + { + std::lock_guard guard(m_mutex); + checkOutputMap(p); + } + + return convertFeatures(p, p->getRemainingFeatures()); + } + + VampFeatureList * + PluginAdapterBase::Impl::convertFeatures(plugin* p, const plugin::FeatureSet &features) + { + std::lock_guard guard(m_mutex); + + int lastN = -1; + + int outputCount = 0; + if (m_pluginOutputs[p]) outputCount = m_pluginOutputs[p]->size(); + + resizeFS(p, outputCount); + VampFeatureList *fs = m_fs[p]; + + // cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << endl; + + for (plugin::FeatureSet::const_iterator fi = features.begin(); + fi != features.end(); ++fi) { + + int n = fi->first; + + // cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << 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[p][n]) resizeFL(p, n, sz); + fs[n].featureCount = sz; + + for (size_t j = 0; j < sz; ++j) { + + // cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << endl; + + VampFeature *feature = &fs[n].features[j].v1; + + feature->hasTimestamp = fl[j].hasTimestamp; + feature->sec = fl[j].timestamp.sec; + feature->nsec = fl[j].timestamp.nsec; + feature->valueCount = fl[j].values.size(); + + VampFeatureV2 *v2 = &fs[n].features[j + sz].v2; + + v2->hasDuration = fl[j].hasDuration; + v2->durationSec = fl[j].duration.sec; + v2->durationNsec = fl[j].duration.nsec; + + 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[p][n][j]) { + resizeFV(p, n, j, feature->valueCount); + } + + for (unsigned int k = 0; k < feature->valueCount; ++k) { + // cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << 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* p, int n) + { + + int i = m_fsizes[p].size(); + if (i >= n) return; + + m_fs[p] = (VampFeatureList *)realloc + (m_fs[p], n * sizeof(VampFeatureList)); + + while (i < n) { + m_fs[p][i].featureCount = 0; + m_fs[p][i].features = 0; + m_fsizes[p].push_back(0); + m_fvsizes[p].push_back(std::vector()); + i++; + } + } + + void + PluginAdapterBase::Impl::resizeFL(plugin* p, int n, size_t sz) + { + size_t i = m_fsizes[p][n]; + if (i >= sz) return; + + m_fs[p][n].features = (VampFeatureUnion *)realloc + (m_fs[p][n].features, 2 * sz * sizeof(VampFeatureUnion)); + + while (m_fsizes[p][n] < sz) { + m_fs[p][n].features[m_fsizes[p][n]].v1.hasTimestamp = 0; + m_fs[p][n].features[m_fsizes[p][n]].v1.valueCount = 0; + m_fs[p][n].features[m_fsizes[p][n]].v1.values = 0; + m_fs[p][n].features[m_fsizes[p][n]].v1.label = 0; + m_fs[p][n].features[m_fsizes[p][n] + sz].v2.hasDuration = 0; + m_fvsizes[p][n].push_back(0); + m_fsizes[p][n]++; + } + } + + void + PluginAdapterBase::Impl::resizeFV(plugin* p, int n, int j, size_t sz) + { + + size_t i = m_fvsizes[p][n][j]; + if (i >= sz) return; + + m_fs[p][n].features[j].v1.values = (float *)realloc + (m_fs[p][n].features[j].v1.values, sz * sizeof(float)); + + m_fvsizes[p][n][j] = sz; + } - bool m_populated; - VampPluginDescriptor m_descriptor; - Plugin::ParameterList m_parameters; - Plugin::ProgramList m_programs; - - typedef map OutputMap; - OutputMap m_pluginOutputs; - - map m_fs; - map > m_fsizes; - map > > 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 - cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << endl; -#endif - - (void)adapterMapMutex(); // see comment in adapterMapMutex function above -} - -const VampPluginDescriptor * -PluginAdapterBase::Impl::getDescriptor() -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << endl; -#endif - - lock_guard guard(m_mutex); - - if (m_populated) return &m_descriptor; - - Plugin *plugin = m_base->createPlugin(48000); - - if (!plugin) { - cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << endl; - return 0; - } - - if (plugin->getVampApiVersion() != VAMP_API_VERSION) { - cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: " - << "API version " << plugin->getVampApiVersion() - << " for\nplugin \"" << plugin->getIdentifier() << "\" " - << "differs from version " - << VAMP_API_VERSION << " for adapter.\n" - << "This plugin is probably linked against a different version of the Vamp SDK\n" - << "from the version it was compiled with. It will need to be re-linked correctly\n" - << "before it can be used." << 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; - - lock_guard adapterMapGuard(adapterMapMutex()); - - 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 - cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << endl; -#endif - - lock_guard guard(m_mutex); - - 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 *)desc); - } - 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); - - lock_guard adapterMapGuard(adapterMapMutex()); - - 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 - cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << endl; -#endif - - lock_guard adapterMapGuard(adapterMapMutex()); - - 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 - cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << endl; -#endif - - lock_guard adapterMapGuard(adapterMapMutex()); - - if (!m_adapterMap) { - m_adapterMap = new AdapterMap(); - } - - if (m_adapterMap->find(desc) == m_adapterMap->end()) { - cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << 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 - cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << endl; -#endif - - return plugin; -} - -void -PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << 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 - cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - bool result = ((Plugin *)handle)->initialise(channels, stepSize, blockSize); - adapter->markOutputsChanged((Plugin *)handle); - return result ? 1 : 0; -} - -void -PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << endl; -#endif - - ((Plugin *)handle)->reset(); -} - -float -PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle, - int param) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << 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 - cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return; - Plugin::ParameterList &list = adapter->m_parameters; - ((Plugin *)handle)->setParameter(list[param].identifier, value); - adapter->markOutputsChanged((Plugin *)handle); -} - -unsigned int -PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - Plugin::ProgramList &list = adapter->m_programs; - 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 - cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return; - - Plugin::ProgramList &list = adapter->m_programs; - ((Plugin *)handle)->selectProgram(list[program]); - - adapter->markOutputsChanged((Plugin *)handle); -} - -unsigned int -PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << endl; -#endif - - return ((Plugin *)handle)->getPreferredStepSize(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << endl; -#endif - - return ((Plugin *)handle)->getPreferredBlockSize(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << endl; -#endif - - return ((Plugin *)handle)->getMinChannelCount(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << endl; -#endif - - return ((Plugin *)handle)->getMaxChannelCount(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - -// cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << endl; - - if (!adapter) return 0; - return adapter->getOutputCount((Plugin *)handle); -} - -VampOutputDescriptor * -PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle, - unsigned int i) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - -// cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << endl; - - if (!adapter) return 0; - return adapter->getOutputDescriptor((Plugin *)handle, i); -} - -void -PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << 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 - cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << 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 - cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - return adapter->getRemainingFeatures((Plugin *)handle); -} - -void -PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << endl; -#endif -} - -void -PluginAdapterBase::Impl::cleanup(Plugin *plugin) -{ - // at this point no mutex is held - - lock_guard adapterMapGuard(adapterMapMutex()); - lock_guard guard(m_mutex); - - if (m_fs.find(plugin) != m_fs.end()) { - size_t outputCount = 0; - if (m_pluginOutputs[plugin]) { - outputCount = m_pluginOutputs[plugin]->size(); - } -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::cleanup: " << outputCount << " output(s)" << endl; -#endif - 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].v1.label) { - free(list[i].features[j].v1.label); - } - if (list[i].features[j].v1.values) { - free(list[i].features[j].v1.values); - } - } - if (list[i].features) free(list[i].features); - } - if (list) free((void *)list); - 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) -{ - // must be called with m_mutex held - - OutputMap::iterator i = m_pluginOutputs.find(plugin); - - if (i == m_pluginOutputs.end() || !i->second) { - - m_pluginOutputs[plugin] = new Plugin::OutputList - (plugin->getOutputDescriptors()); - -// cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << endl; - } -} - -void -PluginAdapterBase::Impl::markOutputsChanged(Plugin *plugin) -{ - lock_guard guard(m_mutex); - - OutputMap::iterator i = m_pluginOutputs.find(plugin); - -// cerr << "PluginAdapterBase::Impl::markOutputsChanged" << endl; - - if (i != m_pluginOutputs.end()) { - - Plugin::OutputList *list = i->second; - m_pluginOutputs.erase(i); - delete list; - } -} - -unsigned int -PluginAdapterBase::Impl::getOutputCount(Plugin *plugin) -{ - lock_guard guard(m_mutex); - - checkOutputMap(plugin); - - return m_pluginOutputs[plugin]->size(); -} - -VampOutputDescriptor * -PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin, - unsigned int i) -{ - lock_guard guard(m_mutex); - - 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 - // We would like to do "&& !od.binNames.empty()" here -- but we - // can't, because it will crash older versions of the host adapter - // which try to copy the names across whenever the bin count is - // non-zero, regardless of whether they exist or not - ) { - 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; - desc->hasDuration = od.hasDuration; - - return desc; -} - -VampFeatureList * -PluginAdapterBase::Impl::process(Plugin *plugin, - const float *const *inputBuffers, - int sec, int nsec) -{ -// cerr << "PluginAdapterBase::Impl::process" << endl; - - RealTime rt(sec, nsec); - - // We don't want to hold the mutex during the actual process call, - // only while looking up the associated metadata - { - lock_guard guard(m_mutex); - checkOutputMap(plugin); - } - - return convertFeatures(plugin, plugin->process(inputBuffers, rt)); -} - -VampFeatureList * -PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin) -{ -// cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << endl; - - // We don't want to hold the mutex during the actual call, only - // while looking up the associated metadata - { - lock_guard guard(m_mutex); - checkOutputMap(plugin); - } - - return convertFeatures(plugin, plugin->getRemainingFeatures()); -} - -VampFeatureList * -PluginAdapterBase::Impl::convertFeatures(Plugin *plugin, - const Plugin::FeatureSet &features) -{ - lock_guard guard(m_mutex); - - int lastN = -1; - - int outputCount = 0; - if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size(); - - resizeFS(plugin, outputCount); - VampFeatureList *fs = m_fs[plugin]; - -// cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << endl; - - for (Plugin::FeatureSet::const_iterator fi = features.begin(); - fi != features.end(); ++fi) { - - int n = fi->first; - -// cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << endl; - - if (n >= int(outputCount)) { - cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << 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) { - -// cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << endl; - - VampFeature *feature = &fs[n].features[j].v1; - - feature->hasTimestamp = fl[j].hasTimestamp; - feature->sec = fl[j].timestamp.sec; - feature->nsec = fl[j].timestamp.nsec; - feature->valueCount = fl[j].values.size(); - - VampFeatureV2 *v2 = &fs[n].features[j + sz].v2; - - v2->hasDuration = fl[j].hasDuration; - v2->durationSec = fl[j].duration.sec; - v2->durationNsec = fl[j].duration.nsec; - - 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) { -// cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << 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; - } - } - -// cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << endl; -// for (int i = 0; i < outputCount; ++i) { -// cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << endl; -// } - - - return fs; -} - -void -PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n) -{ - // called with m_mutex held - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << endl; -#endif - - int i = m_fsizes[plugin].size(); - if (i >= n) return; - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "resizing from " << i << endl; -#endif - - 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(vector()); - i++; - } -} - -void -PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz) -{ - // called with m_mutex held - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", " - << sz << ")" << endl; -#endif - - size_t i = m_fsizes[plugin][n]; - if (i >= sz) return; - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "resizing from " << i << endl; -#endif - - m_fs[plugin][n].features = (VampFeatureUnion *)realloc - (m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion)); - - while (m_fsizes[plugin][n] < sz) { - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 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) -{ - // called with m_mutex held - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", " - << j << ", " << sz << ")" << endl; -#endif - - size_t i = m_fvsizes[plugin][n][j]; - if (i >= sz) return; - -#ifdef DEBUG_PLUGIN_ADAPTER - cerr << "resizing from " << i << endl; -#endif - - m_fs[plugin][n].features[j].v1.values = (float *)realloc - (m_fs[plugin][n].features[j].v1.values, sz * sizeof(float)); - - m_fvsizes[plugin][n][j] = sz; -} - -PluginAdapterBase::Impl::AdapterMap * -PluginAdapterBase::Impl::m_adapterMap = 0; - + PluginAdapterBase::Impl::AdapterMap * + PluginAdapterBase::Impl::m_adapterMap = 0; } diff --git a/src/vamp-sdk/PluginAdapter.h b/src/vamp-sdk/PluginAdapter.h index 7593eea..94f2b50 100644 --- a/src/vamp-sdk/PluginAdapter.h +++ b/src/vamp-sdk/PluginAdapter.h @@ -1,76 +1,44 @@ #pragma once -#include #include "vamp.h" - #include "vamp-sdk/Plugin.h" -namespace Vamp { - -/** - * \class PluginAdapterBase 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 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 +namespace vamp { -public: - virtual ~PluginAdapterBase(); + class PluginAdapterBase + { + public: + virtual ~PluginAdapterBase(); + const VampPluginDescriptor *getDescriptor(); - /** - * Return a VampPluginDescriptor describing the plugin that is - * wrapped by this adapter. - */ - const VampPluginDescriptor *getDescriptor(); + protected: + PluginAdapterBase(); -protected: - PluginAdapterBase(); + virtual plugin* createPlugin(float inputSampleRate) = 0; - virtual Plugin *createPlugin(float inputSampleRate) = 0; + class Impl; + Impl* m_impl; + }; - class Impl; - Impl *m_impl; -}; + template + class PluginAdapter : public PluginAdapterBase + { + public: + PluginAdapter() : PluginAdapterBase() { } + virtual ~PluginAdapter() { } -/** - * \class PluginAdapter PluginAdapter.h - * - * PluginAdapter turns a PluginAdapterBase into a specific wrapper for - * a particular plugin implementation. - * - * See PluginAdapterBase. - */ - -template -class PluginAdapter : public PluginAdapterBase -{ -public: - PluginAdapter() : PluginAdapterBase() { } - virtual ~PluginAdapter() { } - -protected: - Plugin *createPlugin(float inputSampleRate) { - P *p = new P(inputSampleRate); - Plugin *plugin = dynamic_cast(p); - if (!plugin) { - std::cerr << "ERROR: PluginAdapter::createPlugin: " - << "Template type is not a plugin!" - << std::endl; - delete p; - return 0; - } - return plugin; - } -}; - + protected: + plugin* createPlugin(float inputSampleRate) { + Plugin* pl = new Plugin(inputSampleRate); + plugin* p = dynamic_cast(pl); + if (!p) { + std::cerr << "ERROR: PluginAdapter::createPlugin: " + << "Template type is not a plugin!" + << std::endl; + delete pl; + return 0; + } + return p; + } + }; } diff --git a/src/vamp-sdk/PluginBase.h b/src/vamp-sdk/PluginBase.h deleted file mode 100644 index 8596cf9..0000000 --- a/src/vamp-sdk/PluginBase.h +++ /dev/null @@ -1,218 +0,0 @@ -#pragma once - -#include -#include - -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 2; } - - /** - * 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 valueNames; - - ParameterDescriptor() : // the defaults are invalid: you must set them - minValue(0), - maxValue(0), - defaultValue(0), - isQuantized(false), - quantizeStep(0) { } - }; - - typedef std::vector 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 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; -}; - -} diff --git a/src/vamp-sdk/RealTime.cpp b/src/vamp-sdk/RealTime.cpp deleted file mode 100644 index f59eb2e..0000000 --- a/src/vamp-sdk/RealTime.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include - -#if (defined(__GNUC__)) && (__GNUC__ < 3) -#include -#define stringstream strstream -#else -#include -#endif - -using std::cerr; -using std::endl; - -#ifndef _WIN32 -#include -#endif - -#include "vamp-sdk/RealTime.h" - -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) -{ - while (nsec <= -ONE_BILLION && sec > INT_MIN) { nsec += ONE_BILLION; --sec; } - while (nsec >= ONE_BILLION && sec < INT_MAX) { nsec -= ONE_BILLION; ++sec; } - while (nsec > 0 && sec < 0) { nsec -= ONE_BILLION; ++sec; } - while (nsec < 0 && sec > 0) { nsec += ONE_BILLION; --sec; } -} - -RealTime -RealTime::fromSeconds(double sec) -{ - if (sec != sec) { // NaN - cerr << "ERROR: NaN/Inf passed to Vamp::RealTime::fromSeconds" << endl; - return RealTime::zeroTime; - } else if (sec >= 0) { - return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); - } else { - return -fromSeconds(-sec); - } -} - -RealTime -RealTime::fromMilliseconds(int msec) -{ - return RealTime(msec / 1000, (msec % 1000) * 1000000); -} - -#ifndef _WIN32 -RealTime -RealTime::fromTimeval(const struct timeval &tv) -{ - return RealTime(int(tv.tv_sec), int(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; - - 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(fixedDp); - - std::stringstream out; - - if (sec >= 3600) { - out << (sec / 3600) << ":"; - } - - if (sec >= 60) { - int minutes = (sec % 3600) / 60; - if (sec >= 3600 && minutes < 10) out << "0"; - out << minutes << ":"; - } - - 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"; - } - - 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); - double s = time.sec + double(time.nsec) / ONE_BILLION; - return long(s * sampleRate + 0.5); -} - -RealTime -RealTime::frame2RealTime(long frame, unsigned int sampleRate) -{ - if (frame < 0) return -frame2RealTime(-frame, sampleRate); - - int sec = int(frame / long(sampleRate)); - frame -= sec * long(sampleRate); - int nsec = (int)((double(frame) / double(sampleRate)) * ONE_BILLION + 0.5); - // Use ctor here instead of setting data members directly to - // ensure nsec > ONE_BILLION is handled properly. It's extremely - // unlikely, but not impossible. - return RealTime(sec, nsec); -} - -const RealTime RealTime::zeroTime(0,0); - -} diff --git a/src/vamp-sdk/RealTime.h b/src/vamp-sdk/RealTime.h deleted file mode 100644 index 0a931d8..0000000 --- a/src/vamp-sdk/RealTime.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include -#include - -struct timeval; - -namespace Vamp { - -/** - * \class RealTime 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; - - /** - * Return the ratio of two 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; - - /** - * Convert a RealTime into a sample frame at the given sample rate. - */ - static long realTime2Frame(const RealTime &r, unsigned int sampleRate); - - /** - * Convert a sample frame at the given sample rate into a RealTime. - */ - static RealTime frame2RealTime(long frame, unsigned int sampleRate); - - static const RealTime zeroTime; -}; - -std::ostream &operator<<(std::ostream &out, const RealTime &rt); - -} diff --git a/src/vamp-sdk/acsymbols.cpp b/src/vamp-sdk/acsymbols.cpp deleted file mode 100644 index 8449e51..0000000 --- a/src/vamp-sdk/acsymbols.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* These stubs are provided so that autoconf can check library - * versions using C symbols only */ - -extern void libvampsdk_v_2_9_present(void) { } -extern void libvampsdk_v_2_8_present(void) { } -extern void libvampsdk_v_2_7_1_present(void) { } -extern void libvampsdk_v_2_7_present(void) { } -extern void libvampsdk_v_2_6_present(void) { } -extern void libvampsdk_v_2_5_present(void) { } -extern void libvampsdk_v_2_4_present(void) { } -extern void libvampsdk_v_2_3_1_present(void) { } -extern void libvampsdk_v_2_3_present(void) { } -extern void libvampsdk_v_2_2_1_present(void) { } -extern void libvampsdk_v_2_2_present(void) { } -extern void libvampsdk_v_2_1_present(void) { } -extern void libvampsdk_v_2_0_present(void) { } diff --git a/src/vamp-sdk/base_plugin.hpp b/src/vamp-sdk/base_plugin.hpp new file mode 100644 index 0000000..962b66c --- /dev/null +++ b/src/vamp-sdk/base_plugin.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +namespace vamp +{ + class base_plugin + { + public: + base_plugin() = default; + virtual ~base_plugin(); + + public: + struct parameter_descriptor + { + std::string identifier; + std::string name; + std::string description; + std::string unit; + float min_value { 0.f }; + float max_value { 0.f }; + float default_value { 0.f }; + bool is_quantized { false }; + float quantize_step { 0.f }; + std::vector value_names; + }; + + using parameter_descriptors = std::vector; + using programs = std::vector; + + public: + virtual std::string get_identifier() const = 0; + virtual std::string get_name() const = 0; + virtual std::string get_description() const = 0; + virtual std::string get_maker() const = 0; + virtual float get_parameter(std::string) const { return 0.f; } + virtual std::string get_current_program() const { return ""; } + virtual std::string get_type() const = 0; + virtual parameter_descriptors get_parameter_descriptors() const { return parameter_descriptors(); } + virtual programs get_programs() const { return programs(); } + + virtual void set_parameter(std::string, float) { } + virtual void select_program(std::string) { } + }; +} diff --git a/src/vamp-sdk/real_time/real_time.cpp b/src/vamp-sdk/real_time/real_time.cpp new file mode 100644 index 0000000..b148213 --- /dev/null +++ b/src/vamp-sdk/real_time/real_time.cpp @@ -0,0 +1,160 @@ +#include "real_time.hpp" + +#include +#include +#include +#include + +namespace vamp +{ + const real_time real_time::zero_time{ 0, 0 }; + + real_time::real_time(int s, int n) : sec{ s }, nsec{ n } + { + while (nsec <= -ONE_BILLION && sec > std::numeric_limits().max()) { nsec += ONE_BILLION; --sec; } + while (nsec >= ONE_BILLION && sec < std::numeric_limits().max()) { nsec -= ONE_BILLION; ++sec; } + while (nsec > 0 && sec < 0) { nsec -= ONE_BILLION; ++sec; } + while (nsec < 0 && sec > 0) { nsec += ONE_BILLION; --sec; } + } + + real_time real_time::from_seconds(double sec) + { + if (sec != sec) + return real_time::zero_time; + else if (sec >= 0) + return real_time{ static_cast(sec), static_cast((sec - int(sec)) * ONE_BILLION + 0.5) }; + else + return -from_seconds(-sec); + } + + real_time real_time::from_milliseconds(int msec) + { + return real_time{ msec / 1'000, (msec % 1'000) * 1'000'000 }; + } + + real_time real_time::from_timeval(const struct timeval& tv) + { + return real_time{ int(tv.tv_sec), int(tv.tv_usec * 1000) }; + } + + std::ostream& operator<<(std::ostream& out, const real_time& rt) + { + if (rt < real_time::zero_time) + 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 real_time::to_string() const + { + std::stringstream out; + out << *this; + std::string s = out.str(); + + // remove trailing R + return s.substr(0, s.length() - 1); + } + + std::string real_time::to_text(bool fixed_dp) const + { + if (*this < real_time::zero_time) return "-" + (-*this).to_text(fixed_dp); + + std::stringstream out; + + if (sec >= 3'600) out << (sec / 3'600) << ":"; + + if (sec >= 60) + { + int minutes = (sec % 3'600) / 60; + if (sec >= 3'600 && minutes < 10) out << "0"; + out << minutes << ":"; + } + + 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 (fixed_dp) + { + out << "0"; + } + if (ms != 0) + { + out << ms; + } + else if (fixed_dp) + { + out << "0"; + } + } + else if (fixed_dp) + { + out << ".000"; + } + + std::string s = out.str(); + + return s; + } + + real_time real_time::operator/(int d) const + { + int secdiv = sec / d; + int secrem = sec % d; + double nsecdiv = (static_cast(nsec) + ONE_BILLION * static_cast(secrem)) / d; + return real_time{ secdiv, static_cast(nsecdiv + 0.5) }; + } + + double real_time::operator/(const real_time& r) const + { + double l_total = static_cast(sec) * ONE_BILLION + static_cast(nsec); + double r_total = static_cast(r.sec) * ONE_BILLION + static_cast(r.nsec); + if (r_total == 0) return 0.0; + else return l_total / r_total; + } + + long real_time::rt2f(const real_time& time, unsigned int sample_rate) + { + if (time < real_time::zero_time) return -rt2f(-time, sample_rate); + double s = time.sec + static_cast(time.nsec) / ONE_BILLION; + return static_cast(s * sample_rate + 0.5); + } + + real_time real_time::f2rt(long frame, unsigned int sample_rate) + { + if (frame < 0) return -f2rt(-frame, sample_rate); + + int sec = static_cast(frame / static_cast(sample_rate)); + frame -= sec * static_cast(sample_rate); + int nsec = static_cast((static_cast(frame) / static_cast(sample_rate)) * ONE_BILLION + 0.5); + return real_time{ sec, nsec }; + } +} diff --git a/src/vamp-sdk/real_time/real_time.hpp b/src/vamp-sdk/real_time/real_time.hpp new file mode 100644 index 0000000..5fd8494 --- /dev/null +++ b/src/vamp-sdk/real_time/real_time.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +#define ONE_BILLION 1'000'000'000 +struct timeval; + +namespace vamp +{ + struct real_time + { + public: + real_time() = default; + real_time(int s, int n); + real_time(const real_time& r) : sec{ r.sec }, nsec{ r.nsec } { } + + public: + int sec { 0 }; + int nsec { 0 }; + + public: + static real_time from_seconds(double sec); + static real_time from_milliseconds(int msec); + static real_time from_timeval(const struct timeval &); + // real_time to frame + static long rt2f(const real_time &r, unsigned int sample_rate); + // frame to real_time + static real_time f2rt(long frame, unsigned int sample_rate); + static const real_time zero_time; + + public: + int usec() const { return nsec / 1000; } + int msec() const { return nsec / 1000000; } + + std::string to_string() const; + std::string to_text(bool fixed_dp = false) const; + + public: + real_time &operator=(const real_time &r) + { + sec = r.sec; nsec = r.nsec; return *this; + } + + real_time operator+(const real_time &r) const + { + return real_time(sec + r.sec, nsec + r.nsec); + } + + real_time operator-(const real_time &r) const + { + return real_time(sec - r.sec, nsec - r.nsec); + } + + real_time operator-() const + { + return real_time(-sec, -nsec); + } + + bool operator <(const real_time &r) const + { + if (sec == r.sec) return nsec < r.nsec; + else return sec < r.sec; + } + + bool operator >(const real_time &r) const + { + if (sec == r.sec) return nsec > r.nsec; + else return sec > r.sec; + } + + bool operator==(const real_time &r) const + { + return (sec == r.sec && nsec == r.nsec); + } + + bool operator!=(const real_time &r) const + { + return !(r == *this); + } + + bool operator>=(const real_time &r) const + { + if (sec == r.sec) return nsec >= r.nsec; + else return sec >= r.sec; + } + + bool operator<=(const real_time &r) const + { + if (sec == r.sec) return nsec <= r.nsec; + else return sec <= r.sec; + } + + real_time operator/(int d) const; + double operator/(const real_time &r) const; + + friend std::ostream &operator<<(std::ostream &out, const real_time &rt); + }; +} diff --git a/test/main.cpp b/test/main.cpp index 87efab7..cecbe65 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,49 +1,45 @@ #include "hack/logger/logger.hpp" +#include "vamp-sdk/Plugin.h" #include "vamp-hostsdk/PluginInputDomainAdapter.h" #include "vamp-hostsdk/PluginBufferingAdapter.h" -#include "vamp-sdk/Plugin.h" -class MyPlugin : public Vamp::Plugin +class MyPlugin : public vamp::plugin { -public: + public: MyPlugin(float inputSampleRate); virtual ~MyPlugin(); - std::string getIdentifier() const; - std::string getName() const; - std::string getDescription() const; - std::string getMaker() const; - int getPluginVersion() const; - std::string getCopyright() const; + std::string get_identifier() const override; + std::string get_name() const override; + std::string get_description() const override; + std::string get_maker() const override; - InputDomain getInputDomain() const; - size_t getPreferredBlockSize() const; - size_t getPreferredStepSize() const; - size_t getMinChannelCount() const; - size_t getMaxChannelCount() const; + InputDomain getInputDomain() const override; + size_t getPreferredBlockSize() const override; + size_t getPreferredStepSize() const override; + size_t getMinChannelCount() const override; + size_t getMaxChannelCount() const override; - ParameterList getParameterDescriptors() const; - float getParameter(std::string identifier) const; - void setParameter(std::string identifier, float value); + parameter_descriptors get_parameter_descriptors() const override; + float get_parameter(std::string identifier) const override; + void set_parameter(std::string identifier, float value) override; - ProgramList getPrograms() const; - std::string getCurrentProgram() const; - void selectProgram(std::string name); + programs get_programs() const override; + std::string get_current_program() const override; + void select_program(std::string name) override; - OutputList getOutputDescriptors() const; + OutputList getOutputDescriptors() const override; - bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void reset(); + bool initialise(size_t channels, size_t stepSize, size_t blockSize) override; + void reset() override; - FeatureSet process(const float *const *inputBuffers, - Vamp::RealTime timestamp); - - FeatureSet getRemainingFeatures(); + FeatureSet process(const float *const *inputBuffers, vamp::real_time timestamp) override; + FeatureSet getRemainingFeatures() override; }; -MyPlugin::MyPlugin(float inputSampleRate) : Plugin(inputSampleRate) +MyPlugin::MyPlugin(float inputSampleRate) : plugin(inputSampleRate) { } @@ -51,32 +47,22 @@ MyPlugin::~MyPlugin() { } -std::string MyPlugin::getIdentifier() const +std::string MyPlugin::get_identifier() const { return "myplugin"; } -std::string MyPlugin::getName() const +std::string MyPlugin::get_name() const { return "My Plugin"; } -std::string MyPlugin::getDescription() const +std::string MyPlugin::get_description() const { return ""; } -std::string MyPlugin::getMaker() const -{ - return ""; -} - -int MyPlugin::getPluginVersion() const -{ - return 1; -} - -std::string MyPlugin::getCopyright() const +std::string MyPlugin::get_maker() const { return ""; } @@ -106,48 +92,48 @@ size_t MyPlugin::getMaxChannelCount() const return 1; } -MyPlugin::ParameterList MyPlugin::getParameterDescriptors() const +MyPlugin::parameter_descriptors MyPlugin::get_parameter_descriptors() const { - ParameterList list; - ParameterDescriptor d; + parameter_descriptors list; + parameter_descriptor d; d.identifier = "parameter"; d.name = "Some Parameter"; d.description = ""; d.unit = ""; - d.minValue = 0; - d.maxValue = 10; - d.defaultValue = 5; - d.isQuantized = false; + d.min_value = 0; + d.max_value = 10; + d.default_value = 5; + d.is_quantized = false; list.push_back(d); return list; } -float MyPlugin::getParameter(std::string identifier) const +float MyPlugin::get_parameter(std::string identifier) const { if (identifier == "parameter") return 5; return 0; } -void MyPlugin::setParameter(std::string identifier, float value) +void MyPlugin::set_parameter(std::string identifier, float value) { if (identifier == "parameter") { } } -MyPlugin::ProgramList MyPlugin::getPrograms() const +MyPlugin::programs MyPlugin::get_programs() const { - ProgramList list; + programs list; return list; } -std::string MyPlugin::getCurrentProgram() const +std::string MyPlugin::get_current_program() const { return ""; } -void MyPlugin::selectProgram(std::string name) +void MyPlugin::select_program(std::string name) { } @@ -181,7 +167,7 @@ void MyPlugin::reset() { } -MyPlugin::FeatureSet MyPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) +MyPlugin::FeatureSet MyPlugin::process(const float *const *inputBuffers, vamp::real_time timestamp) { return FeatureSet(); } @@ -195,10 +181,10 @@ auto main() -> int { float samplerate = 10.f; MyPlugin* ch = new MyPlugin(samplerate); - Vamp::HostExt::PluginInputDomainAdapter* ia = new Vamp::HostExt::PluginInputDomainAdapter(ch); - ia->setProcessTimestampMethod(Vamp::HostExt::PluginInputDomainAdapter::ShiftData); + vamp::host::PluginInputDomainAdapter* ia = new vamp::host::PluginInputDomainAdapter(ch); + ia->setProcessTimestampMethod(vamp::host::PluginInputDomainAdapter::ShiftData); - Vamp::HostExt::PluginBufferingAdapter* adapter = new Vamp::HostExt::PluginBufferingAdapter(ia); + vamp::host::PluginBufferingAdapter* adapter = new vamp::host::PluginBufferingAdapter(ia); int blocksize = adapter->getPreferredBlockSize(); if (!adapter->initialise(1, blocksize, blocksize))