annotate plugin/NativeVampPluginFactory.cpp @ 1464:91bb68146dfc

Add getPluginLibraryPath throughout, in order to provide diagnostic about which plugins were loaded from where
author Chris Cannam
date Fri, 11 May 2018 14:11:04 +0100
parents 48e9f538e6e9
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