Mercurial > hg > svcore
changeset 1225:ba16388b937d piper
Restore native-Vamp factory and make the choice between Piper and Native a preference
author | Chris Cannam |
---|---|
date | Fri, 21 Oct 2016 11:49:27 +0100 |
parents | ab050519c4ba |
children | 91ff08313375 |
files | base/Preferences.cpp base/Preferences.h plugin/FeatureExtractionPluginFactory.cpp plugin/FeatureExtractionPluginFactory.h plugin/NativeVampPluginFactory.cpp plugin/NativeVampPluginFactory.h plugin/PiperVampPluginFactory.cpp plugin/PiperVampPluginFactory.h svcore.pro transform/FeatureExtractionModelTransformer.cpp transform/ModelTransformerFactory.cpp transform/Transform.cpp transform/TransformFactory.cpp |
diffstat | 13 files changed, 760 insertions(+), 303 deletions(-) [+] |
line wrap: on
line diff
--- a/base/Preferences.cpp Thu Oct 20 18:31:02 2016 +0100 +++ b/base/Preferences.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -41,6 +41,7 @@ m_propertyBoxLayout(VerticallyStacked), m_windowType(HanningWindow), m_resampleQuality(1), + m_runPluginsInProcess(true), m_omitRecentTemps(true), m_tempDirRoot(""), m_fixedSampleRate(0), @@ -65,6 +66,7 @@ m_windowType = WindowType (settings.value("window-type", int(HanningWindow)).toInt()); m_resampleQuality = settings.value("resample-quality", 1).toInt(); + m_runPluginsInProcess = settings.value("run-vamp-plugins-in-process", true).toBool(); m_fixedSampleRate = settings.value("fixed-sample-rate", 0).toDouble(); m_resampleOnLoad = settings.value("resample-on-load", false).toBool(); m_normaliseAudio = settings.value("normalise-audio", false).toBool(); @@ -266,6 +268,10 @@ return m_resampleQuality; } + if (name == "Run Vamp Plugins In Process") { + return m_runPluginsInProcess; + } + if (name == "Omit Temporaries from Recent Files") { if (deflt) *deflt = 1; return m_omitRecentTemps ? 1 : 0; @@ -414,6 +420,8 @@ setWindowType(WindowType(value)); } else if (name == "Resample Quality") { setResampleQuality(value); + } else if (name == "Run Vamp Plugins In Process") { + setRunPluginsInProcess(value ? true : false); } else if (name == "Omit Temporaries from Recent Files") { setOmitTempsFromRecentFiles(value ? true : false); } else if (name == "Background Mode") { @@ -519,6 +527,19 @@ } void +Preferences::setRunPluginsInProcess(bool run) +{ + if (m_runPluginsInProcess != run) { + m_runPluginsInProcess = run; + QSettings settings; + settings.beginGroup("Preferences"); + settings.setValue("run-vamp-plugins-in-process", run); + settings.endGroup(); + emit propertyChanged("Run Vamp Plugins In Process"); + } +} + +void Preferences::setOmitTempsFromRecentFiles(bool omit) { if (m_omitRecentTemps != omit) {
--- a/base/Preferences.h Thu Oct 20 18:31:02 2016 +0100 +++ b/base/Preferences.h Fri Oct 21 11:49:27 2016 +0100 @@ -53,6 +53,8 @@ WindowType getWindowType() const { return m_windowType; } int getResampleQuality() const { return m_resampleQuality; } + bool getRunPluginsInProcess() const { return m_runPluginsInProcess; } + //!!! harmonise with PaneStack enum PropertyBoxLayout { VerticallyStacked, @@ -114,6 +116,7 @@ void setPropertyBoxLayout(PropertyBoxLayout layout); void setWindowType(WindowType type); void setResampleQuality(int quality); + void setRunPluginsInProcess(bool r); void setOmitTempsFromRecentFiles(bool omit); void setTemporaryDirectoryRoot(QString tempDirRoot); void setFixedSampleRate(sv_samplerate_t); @@ -151,6 +154,7 @@ PropertyBoxLayout m_propertyBoxLayout; WindowType m_windowType; int m_resampleQuality; + bool m_runPluginsInProcess; bool m_omitRecentTemps; QString m_tempDirRoot; sv_samplerate_t m_fixedSampleRate;
--- a/plugin/FeatureExtractionPluginFactory.cpp Thu Oct 20 18:31:02 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,183 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam and QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FeatureExtractionPluginFactory.h" -#include "PluginIdentifier.h" - -#include "system/System.h" - -#include "PluginScan.h" - -#ifdef _WIN32 -#undef VOID -#undef ERROR -#define CAPNP_LITE 1 -#endif -#include "vamp-client/AutoPlugin.h" - -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QTextStream> - -#include <iostream> - -#include "base/Profiler.h" - -#include "vamp-client/ProcessQtTransport.h" -#include "vamp-client/CapnpRRClient.h" - -using namespace std; - -//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 - -static FeatureExtractionPluginFactory *_nativeInstance = 0; - -FeatureExtractionPluginFactory * -FeatureExtractionPluginFactory::instance(QString pluginType) -{ - if (pluginType == "vamp") { - if (!_nativeInstance) { -// SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl; - _nativeInstance = new FeatureExtractionPluginFactory(); - } - return _nativeInstance; - } - - else return 0; -} - -FeatureExtractionPluginFactory * -FeatureExtractionPluginFactory::instanceFor(QString identifier) -{ - QString type, soName, label; - PluginIdentifier::parseIdentifier(identifier, type, soName, label); - return instance(type); -} - -FeatureExtractionPluginFactory::FeatureExtractionPluginFactory() : - m_serverName("piper-cpp/bin/piper-vamp-server") //!!! -{ -} - -vector<QString> -FeatureExtractionPluginFactory::getAllPluginIdentifiers() -{ - FeatureExtractionPluginFactory *factory; - vector<QString> rv; - - factory = instance("vamp"); - if (factory) { - vector<QString> tmp = factory->getPluginIdentifiers(); - for (size_t i = 0; i < tmp.size(); ++i) { -// cerr << "identifier: " << tmp[i] << endl; - rv.push_back(tmp[i]); - } - } - - // Plugins can change the locale, revert it to default. - RestoreStartupLocale(); - - return rv; -} - -vector<QString> -FeatureExtractionPluginFactory::getPluginIdentifiers() -{ - Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); - - QMutexLocker locker(&m_mutex); - - if (m_pluginData.empty()) { - populate(); - } - - vector<QString> rv; - - for (const auto &d: m_pluginData) { - rv.push_back(QString("vamp:") + QString::fromStdString(d.pluginKey)); - } - - return rv; -} - -Vamp::Plugin * -FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, - sv_samplerate_t inputSampleRate) -{ - Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); - - QString type, soname, label; - PluginIdentifier::parseIdentifier(identifier, type, soname, label); - std::string pluginKey = (soname + ":" + label).toStdString(); - - auto ap = new piper_vamp::client::AutoPlugin - (m_serverName, pluginKey, float(inputSampleRate), 0); - - if (!ap->isOK()) { - delete ap; - return 0; - } else { - return ap; - } -} - -piper_vamp::PluginStaticData -FeatureExtractionPluginFactory::getPluginStaticData(QString identifier) -{ - QString type, soname, label; - PluginIdentifier::parseIdentifier(identifier, type, soname, label); - std::string pluginKey = (soname + ":" + label).toStdString(); - - for (const auto &d: m_pluginData) { - if (d.pluginKey == pluginKey) { - return d; - } - } - return {}; -} - -QString -FeatureExtractionPluginFactory::getPluginCategory(QString identifier) -{ - if (m_taxonomy.find(identifier) != m_taxonomy.end()) { - return m_taxonomy[identifier]; - } else { - return {}; - } -} - -void -FeatureExtractionPluginFactory::populate() -{ - piper_vamp::client::ProcessQtTransport transport(m_serverName); - piper_vamp::client::CapnpRRClient client(&transport); - piper_vamp::ListResponse lr = client.listPluginData(); - m_pluginData = lr.available; - - for (const auto &pd: m_pluginData) { - - QString identifier = - QString("vamp:") + QString::fromStdString(pd.pluginKey); - - QStringList catlist; - for (const auto &cs: pd.category) { - catlist.push_back(QString::fromStdString(cs)); - } - - m_taxonomy[identifier] = catlist.join(" > "); - } -} -
--- a/plugin/FeatureExtractionPluginFactory.h Thu Oct 20 18:31:02 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FEATURE_EXTRACTION_PLUGIN_FACTORY_H_ -#define _FEATURE_EXTRACTION_PLUGIN_FACTORY_H_ - -#include <QString> -#include <QMutex> -#include <vector> -#include <map> - -#include <vamp-hostsdk/Plugin.h> - -#include "base/Debug.h" -#include "base/BaseTypes.h" - -#include "vamp-support/PluginStaticData.h" - -class FeatureExtractionPluginFactory -{ -public: - FeatureExtractionPluginFactory(); - virtual ~FeatureExtractionPluginFactory() { } - - static FeatureExtractionPluginFactory *instance(QString pluginType); - static FeatureExtractionPluginFactory *instanceFor(QString identifier); - static std::vector<QString> getAllPluginIdentifiers(); - - virtual std::vector<QString> getPluginIdentifiers(); - - virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier); - - // We don't set blockSize or channels on this -- they're - // negotiated and handled via initialize() on the plugin - virtual Vamp::Plugin *instantiatePlugin(QString identifier, - sv_samplerate_t inputSampleRate); - - /** - * Get category metadata about a plugin (without instantiating it). - */ - virtual QString getPluginCategory(QString identifier); - -protected: - std::string m_serverName; - QMutex m_mutex; - std::vector<piper_vamp::PluginStaticData> m_pluginData; - std::map<QString, QString> m_taxonomy; - void populate(); -}; - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/NativeVampPluginFactory.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -0,0 +1,432 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2016 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "NativeVampPluginFactory.h" +#include "PluginIdentifier.h" + +#include <vamp-hostsdk/PluginHostAdapter.h> +#include <vamp-hostsdk/PluginWrapper.h> + +#include "system/System.h" + +#include "PluginScan.h" + +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QTextStream> + +#include <iostream> + +#include "base/Profiler.h" + +#include <QMutex> +#include <QMutexLocker> + +using namespace std; + +//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 + +class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { +public: + PluginDeletionNotifyAdapter(Vamp::Plugin *plugin, + NativeVampPluginFactory *factory) : + PluginWrapper(plugin), m_factory(factory) { } + virtual ~PluginDeletionNotifyAdapter(); +protected: + NativeVampPluginFactory *m_factory; +}; + +PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() +{ + // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn + Vamp::Plugin *p = m_plugin; + delete m_plugin; + m_plugin = 0; + // acceptable use after free here, as pluginDeleted uses p only as + // pointer key and does not deref it + if (m_factory) m_factory->pluginDeleted(p); +} + +vector<QString> +NativeVampPluginFactory::getPluginPath() +{ + if (!m_pluginPath.empty()) return m_pluginPath; + + vector<string> p = Vamp::PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); + return m_pluginPath; +} + +vector<QString> +NativeVampPluginFactory::getPluginIdentifiers() +{ + Profiler profiler("NativeVampPluginFactory::getPluginIdentifiers"); + + QMutexLocker locker(&m_mutex); + + if (!m_identifiers.empty()) { + return m_identifiers; + } + + QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor + (PluginScan::VampPlugin); + + for (QString soname : candidates) { + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); + + if (!libraryHandle) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; + continue; + } + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; + } + continue; + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl; +#endif + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + map<string, int> known; + bool ok = true; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + if (known.find(descriptor->identifier) != known.end()) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Plugin library " + << soname + << " returns the same plugin identifier \"" + << descriptor->identifier << "\" at indices " + << known[descriptor->identifier] << " and " + << index << endl; + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl; + ok = false; + break; + } else { + known[descriptor->identifier] = index; + } + + ++index; + } + + if (ok) { + + index = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + QString id = PluginIdentifier::createIdentifier + ("vamp", soname, descriptor->identifier); + m_identifiers.push_back(id); +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl; +#endif + ++index; + } + } + + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; + } + } + + generateTaxonomy(); + + // Plugins can change the locale, revert it to default. + RestoreStartupLocale(); + + return m_identifiers; +} + +QString +NativeVampPluginFactory::findPluginFile(QString soname, QString inDir) +{ + QString file = ""; + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile(\"" + << soname << "\", \"" << inDir << "\")" + << endl; +#endif + + if (inDir != "") { + + QDir dir(inDir, PLUGIN_GLOB, + QDir::Name | QDir::IgnoreCase, + QDir::Files | QDir::Readable); + if (!dir.exists()) return ""; + + file = dir.filePath(QFileInfo(soname).fileName()); + + if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found trivially at " << file << endl; +#endif + + return file; + } + + for (unsigned int j = 0; j < dir.count(); ++j) { + file = dir.filePath(dir[j]); + if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found \"" << soname << "\" at " << file << endl; +#endif + + return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile (with dir): " + << "not found" << endl; +#endif + + return ""; + + } else { + + QFileInfo fi(soname); + + if (fi.isAbsolute() && fi.exists() && fi.isFile()) { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found trivially at " << soname << endl; +#endif + return soname; + } + + if (fi.isAbsolute() && fi.absolutePath() != "") { + file = findPluginFile(soname, fi.absolutePath()); + if (file != "") return file; + } + + vector<QString> path = getPluginPath(); + for (vector<QString>::iterator i = path.begin(); + i != path.end(); ++i) { + if (*i != "") { + file = findPluginFile(soname, *i); + if (file != "") return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "not found" << endl; +#endif + + return ""; + } +} + +Vamp::Plugin * +NativeVampPluginFactory::instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) +{ + Profiler profiler("NativeVampPluginFactory::instantiatePlugin"); + + Vamp::Plugin *rv = 0; + Vamp::PluginHostAdapter *plugin = 0; + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + QString type, soname, label; + PluginIdentifier::parseIdentifier(identifier, type, soname, label); + if (type != "vamp") { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; +#endif + return 0; + } + + QString found = findPluginFile(soname); + + if (found == "") { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl; + return 0; + } else if (found != soname) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl; + cerr << soname << " -> " << found << endl; +#endif + + } + + soname = found; + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); + + if (!libraryHandle) { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl; + return 0; + } + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + cerr << "NativeVampPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl; + goto done; + } + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + if (label == descriptor->identifier) break; + ++index; + } + + if (!descriptor) { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl; + goto done; + } + + plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate)); + + if (plugin) { + m_handleMap[plugin] = libraryHandle; + rv = new PluginDeletionNotifyAdapter(plugin, this); + } + +// SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl; + + //!!! need to dlclose() when plugins from a given library are unloaded + +done: + if (!rv) { + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; +#endif + + return rv; +} + +void +NativeVampPluginFactory::pluginDeleted(Vamp::Plugin *plugin) +{ + void *handle = m_handleMap[plugin]; + if (handle) { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "unloading library " << handle << " for plugin " << plugin << endl; +#endif + DLCLOSE(handle); + } + m_handleMap.erase(plugin); +} + +QString +NativeVampPluginFactory::getPluginCategory(QString identifier) +{ + return m_taxonomy[identifier]; +} + +void +NativeVampPluginFactory::generateTaxonomy() +{ + vector<QString> pluginPath = getPluginPath(); + vector<QString> path; + + for (size_t i = 0; i < pluginPath.size(); ++i) { + if (pluginPath[i].contains("/lib/")) { + QString p(pluginPath[i]); + path.push_back(p); + p.replace("/lib/", "/share/"); + path.push_back(p); + } + path.push_back(pluginPath[i]); + } + + for (size_t i = 0; i < path.size(); ++i) { + + QDir dir(path[i], "*.cat"); + +// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl; + for (unsigned int j = 0; j < dir.count(); ++j) { + + QFile file(path[i] + "/" + dir[j]); + +// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl; + + if (file.open(QIODevice::ReadOnly)) { +// cerr << "...opened" << endl; + QTextStream stream(&file); + QString line; + + while (!stream.atEnd()) { + line = stream.readLine(); +// cerr << "line is: \"" << line << "\"" << endl; + QString id = PluginIdentifier::canonicalise + (line.section("::", 0, 0)); + QString cat = line.section("::", 1, 1); + m_taxonomy[id] = cat; +// cerr << "NativeVampPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl; + } + } + } + } +} + +piper_vamp::PluginStaticData +NativeVampPluginFactory::getPluginStaticData(QString identifier) +{ + QMutexLocker locker(&m_mutex); + + if (m_pluginData.find(identifier) != m_pluginData.end()) { + return m_pluginData[identifier]; + } + + QString type, soname, label; + PluginIdentifier::parseIdentifier(identifier, type, soname, label); + std::string pluginKey = (soname + ":" + label).toStdString(); + + std::vector<std::string> catlist; + for (auto s: getPluginCategory(identifier).split(" > ")) { + catlist.push_back(s.toStdString()); + } + + Vamp::Plugin *p = instantiatePlugin(identifier, 44100); + if (!p) return {}; + + auto psd = piper_vamp::PluginStaticData::fromPlugin(pluginKey, + catlist, + p); + + delete p; + + m_pluginData[identifier] = psd; + return psd; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/NativeVampPluginFactory.h Fri Oct 21 11:49:27 2016 +0100 @@ -0,0 +1,66 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2016 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef SV_NATIVE_VAMP_PLUGIN_FACTORY_H +#define SV_NATIVE_VAMP_PLUGIN_FACTORY_H + +#include "FeatureExtractionPluginFactory.h" + +#include <vector> +#include <map> + +#include "base/Debug.h" + +#include <QMutex> + +/** + * FeatureExtractionPluginFactory type for Vamp plugins hosted + * in-process. + */ +class NativeVampPluginFactory : public FeatureExtractionPluginFactory +{ +public: + virtual ~NativeVampPluginFactory() { } + + virtual std::vector<QString> getPluginIdentifiers(); + + virtual QString findPluginFile(QString soname, QString inDir = ""); + + virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier); + + virtual Vamp::Plugin *instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate); + + /** + * Get category metadata about a plugin (without instantiating it). + */ + virtual QString getPluginCategory(QString identifier); + +protected: + QMutex m_mutex; + std::vector<QString> m_pluginPath; + std::vector<QString> m_identifiers; + std::map<QString, QString> m_taxonomy; // identifier -> category string + std::map<QString, piper_vamp::PluginStaticData> m_pluginData; // identifier -> data (created opportunistically) + + friend class PluginDeletionNotifyAdapter; + void pluginDeleted(Vamp::Plugin *); + std::map<Vamp::Plugin *, void *> m_handleMap; + + std::vector<QString> getPluginPath(); + void generateTaxonomy(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PiperVampPluginFactory.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -0,0 +1,135 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "PiperVampPluginFactory.h" +#include "PluginIdentifier.h" + +#include "system/System.h" + +#include "PluginScan.h" + +#ifdef _WIN32 +#undef VOID +#undef ERROR +#define CAPNP_LITE 1 +#endif + +#include "vamp-client/AutoPlugin.h" + +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QTextStream> + +#include <iostream> + +#include "base/Profiler.h" + +#include "vamp-client/ProcessQtTransport.h" +#include "vamp-client/CapnpRRClient.h" + +using namespace std; + +//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 + +PiperVampPluginFactory::PiperVampPluginFactory() : + m_serverName("piper-cpp/bin/piper-vamp-server") //!!! +{ +} + +vector<QString> +PiperVampPluginFactory::getPluginIdentifiers() +{ + Profiler profiler("PiperVampPluginFactory::getPluginIdentifiers"); + + QMutexLocker locker(&m_mutex); + + if (m_pluginData.empty()) { + populate(); + } + + vector<QString> rv; + + for (const auto &d: m_pluginData) { + rv.push_back(QString("vamp:") + QString::fromStdString(d.second.pluginKey)); + } + + return rv; +} + +Vamp::Plugin * +PiperVampPluginFactory::instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) +{ + Profiler profiler("PiperVampPluginFactory::instantiatePlugin"); + + auto psd = getPluginStaticData(identifier); + if (psd.pluginKey == "") { + return 0; + } + + auto ap = new piper_vamp::client::AutoPlugin + (m_serverName, psd.pluginKey, float(inputSampleRate), 0); + if (!ap->isOK()) { + delete ap; + return 0; + } + + return ap; +} + +piper_vamp::PluginStaticData +PiperVampPluginFactory::getPluginStaticData(QString identifier) +{ + if (m_pluginData.find(identifier) != m_pluginData.end()) { + return m_pluginData[identifier]; + } else { + return {}; + } +} + +QString +PiperVampPluginFactory::getPluginCategory(QString identifier) +{ + if (m_taxonomy.find(identifier) != m_taxonomy.end()) { + return m_taxonomy[identifier]; + } else { + return {}; + } +} + +void +PiperVampPluginFactory::populate() +{ + piper_vamp::client::ProcessQtTransport transport(m_serverName); + piper_vamp::client::CapnpRRClient client(&transport); + piper_vamp::ListResponse lr = client.listPluginData(); + + for (const auto &pd: lr.available) { + + QString identifier = + QString("vamp:") + QString::fromStdString(pd.pluginKey); + + m_pluginData[identifier] = pd; + + QStringList catlist; + for (const auto &cs: pd.category) { + catlist.push_back(QString::fromStdString(cs)); + } + + m_taxonomy[identifier] = catlist.join(" > "); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PiperVampPluginFactory.h Fri Oct 21 11:49:27 2016 +0100 @@ -0,0 +1,57 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2016 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef SV_PIPER_VAMP_PLUGIN_FACTORY_H +#define SV_PIPER_VAMP_PLUGIN_FACTORY_H + +#include "FeatureExtractionPluginFactory.h" + +#include <QMutex> +#include <vector> +#include <map> + +#include "base/Debug.h" + +/** + * FeatureExtractionPluginFactory type for Vamp plugins hosted in a + * separate process using Piper protocol. + */ +class PiperVampPluginFactory : public FeatureExtractionPluginFactory +{ +public: + PiperVampPluginFactory(); + + virtual ~PiperVampPluginFactory() { } + + virtual std::vector<QString> getPluginIdentifiers() override; + + virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier) + override; + + virtual Vamp::Plugin *instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) + override; + + virtual QString getPluginCategory(QString identifier) override; + +protected: + QMutex m_mutex; + std::string m_serverName; + std::map<QString, piper_vamp::PluginStaticData> m_pluginData; // identifier -> data + std::map<QString, QString> m_taxonomy; // identifier -> category string + void populate(); +}; + +#endif
--- a/svcore.pro Thu Oct 20 18:31:02 2016 +0100 +++ b/svcore.pro Fri Oct 21 11:49:27 2016 +0100 @@ -237,6 +237,8 @@ plugin/FeatureExtractionPluginFactory.h \ plugin/LADSPAPluginFactory.h \ plugin/LADSPAPluginInstance.h \ + plugin/NativeVampPluginFactory.h \ + plugin/PiperVampPluginFactory.h \ plugin/PluginIdentifier.h \ plugin/PluginXml.h \ plugin/RealTimePluginFactory.h \ @@ -258,6 +260,8 @@ plugin/FeatureExtractionPluginFactory.cpp \ plugin/LADSPAPluginFactory.cpp \ plugin/LADSPAPluginInstance.cpp \ + plugin/NativeVampPluginFactory.cpp \ + plugin/PiperVampPluginFactory.cpp \ plugin/PluginIdentifier.cpp \ plugin/PluginXml.cpp \ plugin/RealTimePluginFactory.cpp \
--- a/transform/FeatureExtractionModelTransformer.cpp Thu Oct 20 18:31:02 2016 +0100 +++ b/transform/FeatureExtractionModelTransformer.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -16,6 +16,9 @@ #include "FeatureExtractionModelTransformer.h" #include "plugin/FeatureExtractionPluginFactory.h" +#include "plugin/NativeVampPluginFactory.h" +#include "plugin/PiperVampPluginFactory.h" + #include "plugin/PluginXml.h" #include <vamp-hostsdk/Plugin.h> @@ -92,8 +95,7 @@ QString pluginId = primaryTransform.getPluginIdentifier(); - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); + FeatureExtractionPluginFactory *factory = PiperVampPluginFactory::instance(); if (!factory) { m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId); @@ -731,9 +733,6 @@ if (m_abandoned) break; - cerr << "calling process() from thread " - << QThread::currentThreadId() << endl; - Vamp::Plugin::FeatureSet features = m_plugin->process (buffers, RealTime::frame2RealTime(blockFrame, sampleRate).toVampRealTime());
--- a/transform/ModelTransformerFactory.cpp Thu Oct 20 18:31:02 2016 +0100 +++ b/transform/ModelTransformerFactory.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -93,17 +93,7 @@ Vamp::PluginBase *plugin = 0; - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl; - - Vamp::Plugin *vp = - FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin - (id, float(inputModel->getSampleRate())); - - plugin = vp; - - } else if (RealTimePluginFactory::instanceFor(id)) { + if (RealTimePluginFactory::instanceFor(id)) { RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); @@ -120,6 +110,16 @@ (id, 0, 0, sampleRate, blockSize, channels); plugin = rtp; + + } else { + + cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl; + + Vamp::Plugin *vp = + FeatureExtractionPluginFactory::instance()->instantiatePlugin + (id, float(inputModel->getSampleRate())); + + plugin = vp; } if (plugin) { @@ -171,20 +171,15 @@ QString id = transforms[0].getPluginIdentifier(); - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - transformer = - new FeatureExtractionModelTransformer(input, transforms); - - } else if (RealTimePluginFactory::instanceFor(id)) { + if (RealTimePluginFactory::instanceFor(id)) { transformer = new RealTimeEffectModelTransformer(input, transforms[0]); } else { - SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \"" - << transforms[0].getIdentifier() << "\"" << endl; - return transformer; + + transformer = + new FeatureExtractionModelTransformer(input, transforms); } if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
--- a/transform/Transform.cpp Thu Oct 20 18:31:02 2016 +0100 +++ b/transform/Transform.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -202,12 +202,10 @@ Transform::Type Transform::getType() const { - if (FeatureExtractionPluginFactory::instanceFor(getPluginIdentifier())) { - return FeatureExtraction; - } else if (RealTimePluginFactory::instanceFor(getPluginIdentifier())) { + if (RealTimePluginFactory::instanceFor(getPluginIdentifier())) { return RealTimeEffect; } else { - return UnknownType; + return FeatureExtraction; } }
--- a/transform/TransformFactory.cpp Thu Oct 20 18:31:02 2016 +0100 +++ b/transform/TransformFactory.cpp Fri Oct 21 11:49:27 2016 +0100 @@ -16,6 +16,7 @@ #include "TransformFactory.h" #include "plugin/FeatureExtractionPluginFactory.h" + #include "plugin/RealTimePluginFactory.h" #include "plugin/RealTimePluginInstance.h" #include "plugin/PluginXml.h" @@ -402,22 +403,17 @@ void TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) { - std::vector<QString> plugs = - FeatureExtractionPluginFactory::getAllPluginIdentifiers(); + FeatureExtractionPluginFactory *factory = + FeatureExtractionPluginFactory::instance(); + + std::vector<QString> plugs = factory->getPluginIdentifiers(); + if (m_exiting) return; for (int i = 0; i < (int)plugs.size(); ++i) { QString pluginId = plugs[i]; - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); - - if (!factory) { - cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId << endl; - continue; - } - piper_vamp::PluginStaticData psd = factory->getPluginStaticData(pluginId); if (psd.pluginKey == "") { @@ -794,8 +790,8 @@ // cerr << "TransformFactory::instantiateDefaultPluginFor: identifier \"" // << identifier << "\" is a feature extraction transform" << endl; - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); + FeatureExtractionPluginFactory *factory = + FeatureExtractionPluginFactory::instance(); if (factory) { plugin = factory->instantiatePlugin(pluginId, rate); @@ -914,22 +910,7 @@ { QString id = identifier.section(':', 0, 2); - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - Vamp::Plugin *plugin = - FeatureExtractionPluginFactory::instanceFor(id)-> - instantiatePlugin(id, 44100); - if (!plugin) return false; - - min = (int)plugin->getMinChannelCount(); - max = (int)plugin->getMaxChannelCount(); - delete plugin; - - return true; - - } else if (RealTimePluginFactory::instanceFor(id)) { - - // don't need to instantiate + if (RealTimePluginFactory::instanceFor(id)) { const RealTimePluginDescriptor *descriptor = RealTimePluginFactory::instanceFor(id)-> @@ -940,6 +921,17 @@ max = descriptor->audioInputPortCount; return true; + + } else { + + auto psd = FeatureExtractionPluginFactory::instance()-> + getPluginStaticData(id); + if (psd.pluginKey == "") return false; + + min = (int)psd.minChannelCount; + max = (int)psd.maxChannelCount; + + return true; } return false;