| 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@1579 | 47     ~PluginDeletionNotifyAdapter() override; | 
| 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@1582 | 57     m_plugin = nullptr; | 
| 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@1582 | 150         const VampPluginDescriptor *descriptor = nullptr; | 
| 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@1582 | 296     Vamp::Plugin *rv = nullptr; | 
| Chris@1582 | 297     Vamp::PluginHostAdapter *plugin = nullptr; | 
| Chris@1225 | 298 | 
| Chris@1582 | 299     const VampPluginDescriptor *descriptor = nullptr; | 
| 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@1582 | 308         return nullptr; | 
| 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@1582 | 315         return nullptr; | 
| 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@1582 | 331         return nullptr; | 
| 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 |