annotate plugin/NativeVampPluginFactory.cpp @ 1520:954d0cf29ca7 import-audio-data

Switch the normalisation option in WritableWaveFileModel from normalising on read to normalising on write, so that the saved file is already normalised and therefore can be read again without having to remember to normalise it
author Chris Cannam
date Wed, 12 Sep 2018 13:56:56 +0100
parents 91bb68146dfc
children 232d6ddf257d
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1225 7 This file copyright 2006-2016 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@1225 16 #include "NativeVampPluginFactory.h"
Chris@0 17 #include "PluginIdentifier.h"
Chris@0 18
Chris@1225 19 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@1225 20 #include <vamp-hostsdk/PluginWrapper.h>
Chris@1225 21
Chris@150 22 #include "system/System.h"
Chris@66 23
Chris@1179 24 #include "PluginScan.h"
Chris@1179 25
Chris@66 26 #include <QDir>
Chris@66 27 #include <QFile>
Chris@66 28 #include <QFileInfo>
Chris@165 29 #include <QTextStream>
Chris@66 30
Chris@0 31 #include <iostream>
Chris@0 32
Chris@408 33 #include "base/Profiler.h"
Chris@408 34
Chris@1225 35 #include <QMutex>
Chris@1225 36 #include <QMutexLocker>
Chris@1223 37
Chris@1164 38 using namespace std;
Chris@1164 39
Chris@249 40 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
Chris@249 41
Chris@1225 42 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
Chris@1225 43 public:
Chris@1225 44 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
Chris@1225 45 NativeVampPluginFactory *factory) :
Chris@1225 46 PluginWrapper(plugin), m_factory(factory) { }
Chris@1225 47 virtual ~PluginDeletionNotifyAdapter();
Chris@1225 48 protected:
Chris@1225 49 NativeVampPluginFactory *m_factory;
Chris@1225 50 };
Chris@0 51
Chris@1225 52 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
Chris@0 53 {
Chris@1225 54 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
Chris@1225 55 Vamp::Plugin *p = m_plugin;
Chris@1225 56 delete m_plugin;
Chris@1225 57 m_plugin = 0;
Chris@1225 58 // acceptable use after free here, as pluginDeleted uses p only as
Chris@1225 59 // pointer key and does not deref it
Chris@1225 60 if (m_factory) m_factory->pluginDeleted(p);
Chris@66 61 }
Chris@66 62
Chris@1164 63 vector<QString>
Chris@1225 64 NativeVampPluginFactory::getPluginPath()
Chris@0 65 {
Chris@1225 66 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@1225 67
Chris@1225 68 vector<string> p = Vamp::PluginHostAdapter::getPluginPath();
Chris@1225 69 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
Chris@1225 70 return m_pluginPath;
Chris@1225 71 }
Chris@1225 72
Chris@1249 73 static
Chris@1249 74 QList<PluginScan::Candidate>
Chris@1249 75 getCandidateLibraries()
Chris@1249 76 {
Chris@1249 77 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 78 return PluginScan::getInstance()->getCandidateLibrariesFor
Chris@1249 79 (PluginScan::VampPlugin);
Chris@1249 80 #else
Chris@1249 81 auto path = Vamp::PluginHostAdapter::getPluginPath();
Chris@1249 82 QList<PluginScan::Candidate> candidates;
Chris@1249 83 for (string dirname: path) {
Chris@1249 84 SVDEBUG << "NativeVampPluginFactory: scanning directory myself: "
Chris@1249 85 << dirname << endl;
Chris@1249 86 #if defined(_WIN32)
Chris@1249 87 #define PLUGIN_GLOB "*.dll"
Chris@1249 88 #elif defined(__APPLE__)
Chris@1249 89 #define PLUGIN_GLOB "*.dylib *.so"
Chris@1249 90 #else
Chris@1249 91 #define PLUGIN_GLOB "*.so"
Chris@1249 92 #endif
Chris@1249 93 QDir dir(dirname.c_str(), PLUGIN_GLOB,
Chris@1249 94 QDir::Name | QDir::IgnoreCase,
Chris@1249 95 QDir::Files | QDir::Readable);
Chris@1249 96
Chris@1249 97 for (unsigned int i = 0; i < dir.count(); ++i) {
Chris@1464 98 QString libpath = dir.filePath(dir[i]);
Chris@1464 99 candidates.push_back({ libpath, "" });
Chris@1249 100 }
Chris@1249 101 }
Chris@1249 102
Chris@1249 103 return candidates;
Chris@1249 104 #endif
Chris@1249 105 }
Chris@1249 106
Chris@1225 107 vector<QString>
Chris@1227 108 NativeVampPluginFactory::getPluginIdentifiers(QString &)
Chris@1225 109 {
Chris@1225 110 Profiler profiler("NativeVampPluginFactory::getPluginIdentifiers");
Chris@1225 111
Chris@1225 112 QMutexLocker locker(&m_mutex);
Chris@1225 113
Chris@1225 114 if (!m_identifiers.empty()) {
Chris@1225 115 return m_identifiers;
Chris@1225 116 }
Chris@1249 117
Chris@1249 118 auto candidates = getCandidateLibraries();
Chris@0 119
Chris@1249 120 SVDEBUG << "INFO: Have " << candidates.size() << " candidate Vamp plugin libraries" << endl;
Chris@1249 121
Chris@1246 122 for (auto candidate : candidates) {
Chris@1246 123
Chris@1464 124 QString libpath = candidate.libraryPath;
Chris@1225 125
Chris@1464 126 SVDEBUG << "INFO: Considering candidate Vamp plugin library " << libpath << endl;
Chris@1249 127
Chris@1464 128 void *libraryHandle = DLOPEN(libpath, RTLD_LAZY | RTLD_LOCAL);
Chris@1225 129
Chris@1225 130 if (!libraryHandle) {
Chris@1464 131 SVDEBUG << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to load library " << libpath << ": " << DLERROR() << endl;
Chris@1225 132 continue;
Chris@1225 133 }
Chris@1225 134
Chris@1225 135 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@1225 136 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@1225 137
Chris@1225 138 if (!fn) {
Chris@1464 139 SVDEBUG << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: No descriptor function in " << libpath << endl;
Chris@1225 140 if (DLCLOSE(libraryHandle) != 0) {
Chris@1464 141 SVDEBUG << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << libpath << endl;
Chris@1225 142 }
Chris@1225 143 continue;
Chris@1225 144 }
Chris@1225 145
Chris@1225 146 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 147 cerr << "NativeVampPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
Chris@1225 148 #endif
Chris@1225 149
Chris@1225 150 const VampPluginDescriptor *descriptor = 0;
Chris@1225 151 int index = 0;
Chris@1225 152
Chris@1225 153 map<string, int> known;
Chris@1225 154 bool ok = true;
Chris@1225 155
Chris@1225 156 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@1225 157
Chris@1225 158 if (known.find(descriptor->identifier) != known.end()) {
Chris@1247 159 SVDEBUG << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Plugin library "
Chris@1464 160 << libpath
Chris@1464 161 << " returns the same plugin identifier \""
Chris@1464 162 << descriptor->identifier << "\" at indices "
Chris@1464 163 << known[descriptor->identifier] << " and "
Chris@1464 164 << index << endl;
Chris@1464 165 SVDEBUG << "NativeVampPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
Chris@1225 166 ok = false;
Chris@1225 167 break;
Chris@1225 168 } else {
Chris@1225 169 known[descriptor->identifier] = index;
Chris@1225 170 }
Chris@1225 171
Chris@1225 172 ++index;
Chris@1225 173 }
Chris@1225 174
Chris@1225 175 if (ok) {
Chris@1225 176
Chris@1225 177 index = 0;
Chris@1225 178
Chris@1225 179 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@1225 180
Chris@1225 181 QString id = PluginIdentifier::createIdentifier
Chris@1464 182 ("vamp", libpath, descriptor->identifier);
Chris@1225 183 m_identifiers.push_back(id);
Chris@1464 184 m_libraries[id] = libpath;
Chris@1225 185 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 186 cerr << "NativeVampPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
Chris@1225 187 #endif
Chris@1225 188 ++index;
Chris@1225 189 }
Chris@1225 190 }
Chris@1225 191
Chris@1225 192 if (DLCLOSE(libraryHandle) != 0) {
Chris@1464 193 SVDEBUG << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << libpath << endl;
Chris@1225 194 }
Chris@0 195 }
Chris@0 196
Chris@1225 197 generateTaxonomy();
Chris@1225 198
Chris@0 199 // Plugins can change the locale, revert it to default.
Chris@608 200 RestoreStartupLocale();
Chris@608 201
Chris@1225 202 return m_identifiers;
Chris@1225 203 }
Chris@1225 204
Chris@1225 205 QString
Chris@1225 206 NativeVampPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@1225 207 {
Chris@1225 208 QString file = "";
Chris@1225 209
Chris@1225 210 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 211 cerr << "NativeVampPluginFactory::findPluginFile(\""
Chris@1225 212 << soname << "\", \"" << inDir << "\")"
Chris@1225 213 << endl;
Chris@1225 214 #endif
Chris@1225 215
Chris@1225 216 if (inDir != "") {
Chris@1225 217
Chris@1225 218 QDir dir(inDir, PLUGIN_GLOB,
Chris@1225 219 QDir::Name | QDir::IgnoreCase,
Chris@1225 220 QDir::Files | QDir::Readable);
Chris@1225 221 if (!dir.exists()) return "";
Chris@1225 222
Chris@1225 223 file = dir.filePath(QFileInfo(soname).fileName());
Chris@1225 224
Chris@1225 225 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
Chris@1225 226
Chris@1225 227 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 228 cerr << "NativeVampPluginFactory::findPluginFile: "
Chris@1225 229 << "found trivially at " << file << endl;
Chris@1225 230 #endif
Chris@1225 231
Chris@1225 232 return file;
Chris@1225 233 }
Chris@1225 234
Chris@1429 235 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@1225 236 file = dir.filePath(dir[j]);
Chris@1225 237 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@1225 238
Chris@1225 239 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 240 cerr << "NativeVampPluginFactory::findPluginFile: "
Chris@1225 241 << "found \"" << soname << "\" at " << file << endl;
Chris@1225 242 #endif
Chris@1225 243
Chris@1225 244 return file;
Chris@1225 245 }
Chris@1225 246 }
Chris@1225 247
Chris@1225 248 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 249 cerr << "NativeVampPluginFactory::findPluginFile (with dir): "
Chris@1225 250 << "not found" << endl;
Chris@1225 251 #endif
Chris@1225 252
Chris@1225 253 return "";
Chris@1225 254
Chris@1225 255 } else {
Chris@1225 256
Chris@1225 257 QFileInfo fi(soname);
Chris@1225 258
Chris@1225 259 if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
Chris@1225 260 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 261 cerr << "NativeVampPluginFactory::findPluginFile: "
Chris@1225 262 << "found trivially at " << soname << endl;
Chris@1225 263 #endif
Chris@1225 264 return soname;
Chris@1225 265 }
Chris@1225 266
Chris@1225 267 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@1225 268 file = findPluginFile(soname, fi.absolutePath());
Chris@1225 269 if (file != "") return file;
Chris@1225 270 }
Chris@1225 271
Chris@1225 272 vector<QString> path = getPluginPath();
Chris@1225 273 for (vector<QString>::iterator i = path.begin();
Chris@1225 274 i != path.end(); ++i) {
Chris@1225 275 if (*i != "") {
Chris@1225 276 file = findPluginFile(soname, *i);
Chris@1225 277 if (file != "") return file;
Chris@1225 278 }
Chris@1225 279 }
Chris@1225 280
Chris@1225 281 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 282 cerr << "NativeVampPluginFactory::findPluginFile: "
Chris@1225 283 << "not found" << endl;
Chris@1225 284 #endif
Chris@1225 285
Chris@1225 286 return "";
Chris@1225 287 }
Chris@1225 288 }
Chris@1225 289
Chris@1225 290 Vamp::Plugin *
Chris@1225 291 NativeVampPluginFactory::instantiatePlugin(QString identifier,
Chris@1225 292 sv_samplerate_t inputSampleRate)
Chris@1225 293 {
Chris@1225 294 Profiler profiler("NativeVampPluginFactory::instantiatePlugin");
Chris@1225 295
Chris@1225 296 Vamp::Plugin *rv = 0;
Chris@1225 297 Vamp::PluginHostAdapter *plugin = 0;
Chris@1225 298
Chris@1225 299 const VampPluginDescriptor *descriptor = 0;
Chris@1225 300 int index = 0;
Chris@1225 301
Chris@1225 302 QString type, soname, label;
Chris@1225 303 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@1225 304 if (type != "vamp") {
Chris@1225 305 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 306 cerr << "NativeVampPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
Chris@1225 307 #endif
Chris@1429 308 return 0;
Chris@1225 309 }
Chris@1225 310
Chris@1225 311 QString found = findPluginFile(soname);
Chris@1225 312
Chris@1225 313 if (found == "") {
Chris@1247 314 SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl;
Chris@1225 315 return 0;
Chris@1225 316 } else if (found != soname) {
Chris@1225 317
Chris@1225 318 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 319 cerr << "NativeVampPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl;
Chris@1225 320 cerr << soname << " -> " << found << endl;
Chris@1225 321 #endif
Chris@1225 322
Chris@1225 323 }
Chris@1225 324
Chris@1225 325 soname = found;
Chris@1225 326
Chris@1225 327 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@1225 328
Chris@1225 329 if (!libraryHandle) {
Chris@1247 330 SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@1225 331 return 0;
Chris@1225 332 }
Chris@1225 333
Chris@1225 334 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@1225 335 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@1225 336
Chris@1225 337 if (!fn) {
Chris@1247 338 SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl;
Chris@1225 339 goto done;
Chris@1225 340 }
Chris@1225 341
Chris@1225 342 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@1225 343 if (label == descriptor->identifier) break;
Chris@1225 344 ++index;
Chris@1225 345 }
Chris@1225 346
Chris@1225 347 if (!descriptor) {
Chris@1247 348 SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl;
Chris@1225 349 goto done;
Chris@1225 350 }
Chris@1225 351
Chris@1225 352 plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate));
Chris@1225 353
Chris@1225 354 if (plugin) {
Chris@1225 355 m_handleMap[plugin] = libraryHandle;
Chris@1225 356 rv = new PluginDeletionNotifyAdapter(plugin, this);
Chris@1225 357 }
Chris@1225 358
Chris@1225 359 // SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl;
Chris@1225 360
Chris@1225 361 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@1225 362
Chris@1225 363 done:
Chris@1225 364 if (!rv) {
Chris@1225 365 if (DLCLOSE(libraryHandle) != 0) {
Chris@1247 366 SVDEBUG << "WARNING: NativeVampPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
Chris@1225 367 }
Chris@1225 368 }
Chris@1225 369
Chris@1225 370 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 371 cerr << "NativeVampPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
Chris@1225 372 #endif
Chris@1225 373
Chris@0 374 return rv;
Chris@0 375 }
Chris@0 376
Chris@1225 377 void
Chris@1225 378 NativeVampPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
Chris@0 379 {
Chris@1225 380 void *handle = m_handleMap[plugin];
Chris@1225 381 if (handle) {
Chris@1225 382 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1225 383 cerr << "unloading library " << handle << " for plugin " << plugin << endl;
Chris@1225 384 #endif
Chris@1225 385 DLCLOSE(handle);
Chris@1225 386 }
Chris@1225 387 m_handleMap.erase(plugin);
Chris@1225 388 }
Chris@408 389
Chris@1225 390 QString
Chris@1225 391 NativeVampPluginFactory::getPluginCategory(QString identifier)
Chris@1225 392 {
Chris@1225 393 return m_taxonomy[identifier];
Chris@1225 394 }
Chris@1225 395
Chris@1464 396 QString
Chris@1464 397 NativeVampPluginFactory::getPluginLibraryPath(QString identifier)
Chris@1464 398 {
Chris@1464 399 return m_libraries[identifier];
Chris@1464 400 }
Chris@1464 401
Chris@1225 402 void
Chris@1225 403 NativeVampPluginFactory::generateTaxonomy()
Chris@1225 404 {
Chris@1225 405 vector<QString> pluginPath = getPluginPath();
Chris@1225 406 vector<QString> path;
Chris@1225 407
Chris@1225 408 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@1429 409 if (pluginPath[i].contains("/lib/")) {
Chris@1429 410 QString p(pluginPath[i]);
Chris@1225 411 path.push_back(p);
Chris@1429 412 p.replace("/lib/", "/share/");
Chris@1429 413 path.push_back(p);
Chris@1429 414 }
Chris@1429 415 path.push_back(pluginPath[i]);
Chris@1225 416 }
Chris@1225 417
Chris@1225 418 for (size_t i = 0; i < path.size(); ++i) {
Chris@1225 419
Chris@1429 420 QDir dir(path[i], "*.cat");
Chris@1225 421
Chris@1429 422 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
Chris@1429 423 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@1225 424
Chris@1429 425 QFile file(path[i] + "/" + dir[j]);
Chris@1225 426
Chris@1429 427 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
Chris@1225 428
Chris@1429 429 if (file.open(QIODevice::ReadOnly)) {
Chris@1429 430 // cerr << "...opened" << endl;
Chris@1429 431 QTextStream stream(&file);
Chris@1429 432 QString line;
Chris@1225 433
Chris@1429 434 while (!stream.atEnd()) {
Chris@1429 435 line = stream.readLine();
Chris@1429 436 // cerr << "line is: \"" << line << "\"" << endl;
Chris@1429 437 QString id = PluginIdentifier::canonicalise
Chris@1225 438 (line.section("::", 0, 0));
Chris@1429 439 QString cat = line.section("::", 1, 1);
Chris@1429 440 m_taxonomy[id] = cat;
Chris@1429 441 // cerr << "NativeVampPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
Chris@1429 442 }
Chris@1429 443 }
Chris@1429 444 }
Chris@1225 445 }
Chris@1225 446 }
Chris@1225 447
Chris@1225 448 piper_vamp::PluginStaticData
Chris@1225 449 NativeVampPluginFactory::getPluginStaticData(QString identifier)
Chris@1225 450 {
Chris@1209 451 QMutexLocker locker(&m_mutex);
Chris@1209 452
Chris@1225 453 if (m_pluginData.find(identifier) != m_pluginData.end()) {
Chris@1225 454 return m_pluginData[identifier];
Chris@1209 455 }
Chris@1210 456
Chris@66 457 QString type, soname, label;
Chris@66 458 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@1210 459 std::string pluginKey = (soname + ":" + label).toStdString();
Chris@0 460
Chris@1225 461 std::vector<std::string> catlist;
Chris@1225 462 for (auto s: getPluginCategory(identifier).split(" > ")) {
Chris@1225 463 catlist.push_back(s.toStdString());
Chris@1225 464 }
Chris@1225 465
Chris@1225 466 Vamp::Plugin *p = instantiatePlugin(identifier, 44100);
Chris@1225 467 if (!p) return {};
Chris@66 468
Chris@1225 469 auto psd = piper_vamp::PluginStaticData::fromPlugin(pluginKey,
Chris@1225 470 catlist,
Chris@1225 471 p);
Chris@1225 472
Chris@1225 473 delete p;
Chris@1225 474
Chris@1225 475 m_pluginData[identifier] = psd;
Chris@1225 476 return psd;
Chris@298 477 }
Chris@298 478