FeatureExtractionPluginFactory.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "FeatureExtractionPluginFactory.h"
00017 #include "PluginIdentifier.h"
00018 
00019 #include "vamp/vamp.h"
00020 #include "vamp-sdk/PluginHostAdapter.h"
00021 #include "vamp-sdk/hostext/PluginWrapper.h"
00022 
00023 #include "system/System.h"
00024 
00025 #include <QDir>
00026 #include <QFile>
00027 #include <QFileInfo>
00028 #include <QTextStream>
00029 
00030 #include <iostream>
00031 
00032 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
00033 
00034 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
00035 public:
00036     PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
00037                                 FeatureExtractionPluginFactory *factory) :
00038         PluginWrapper(plugin), m_factory(factory) { }
00039     virtual ~PluginDeletionNotifyAdapter();
00040 protected:
00041     FeatureExtractionPluginFactory *m_factory;
00042 };
00043 
00044 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
00045 {
00046     // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
00047     Vamp::Plugin *p = m_plugin;
00048     delete m_plugin;
00049     m_plugin = 0;
00050     if (m_factory) m_factory->pluginDeleted(p);
00051 }
00052 
00053 static FeatureExtractionPluginFactory *_nativeInstance = 0;
00054 
00055 FeatureExtractionPluginFactory *
00056 FeatureExtractionPluginFactory::instance(QString pluginType)
00057 {
00058     if (pluginType == "vamp") {
00059         if (!_nativeInstance) {
00060 //          std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString()
00061 //                    << "): creating new FeatureExtractionPluginFactory" << std::endl;
00062             _nativeInstance = new FeatureExtractionPluginFactory();
00063         }
00064         return _nativeInstance;
00065     }
00066 
00067     else return 0;
00068 }
00069 
00070 FeatureExtractionPluginFactory *
00071 FeatureExtractionPluginFactory::instanceFor(QString identifier)
00072 {
00073     QString type, soName, label;
00074     PluginIdentifier::parseIdentifier(identifier, type, soName, label);
00075     return instance(type);
00076 }
00077 
00078 std::vector<QString>
00079 FeatureExtractionPluginFactory::getPluginPath()
00080 {
00081     if (!m_pluginPath.empty()) return m_pluginPath;
00082 
00083     std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath();
00084     for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
00085     return m_pluginPath;
00086 }
00087 
00088 std::vector<QString>
00089 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
00090 {
00091     FeatureExtractionPluginFactory *factory;
00092     std::vector<QString> rv;
00093     
00094     factory = instance("vamp");
00095     if (factory) {
00096         std::vector<QString> tmp = factory->getPluginIdentifiers();
00097         for (size_t i = 0; i < tmp.size(); ++i) {
00098 //            std::cerr << "identifier: " << tmp[i].toStdString() << std::endl;
00099             rv.push_back(tmp[i]);
00100         }
00101     }
00102 
00103     // Plugins can change the locale, revert it to default.
00104     setlocale(LC_ALL, "C");
00105     return rv;
00106 }
00107 
00108 std::vector<QString>
00109 FeatureExtractionPluginFactory::getPluginIdentifiers()
00110 {
00111     std::vector<QString> rv;
00112     std::vector<QString> path = getPluginPath();
00113     
00114     for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
00115 
00116 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00117         std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl;
00118 #endif
00119 
00120         QDir pluginDir(*i, PLUGIN_GLOB,
00121                        QDir::Name | QDir::IgnoreCase,
00122                        QDir::Files | QDir::Readable);
00123 
00124         for (unsigned int j = 0; j < pluginDir.count(); ++j) {
00125 
00126             QString soname = pluginDir.filePath(pluginDir[j]);
00127 
00128 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00129             std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname.toStdString() << std::endl;
00130 #endif
00131 
00132             void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
00133             
00134             if (!libraryHandle) {
00135                 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
00136                 continue;
00137             }
00138 
00139 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00140             std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << std::endl;
00141 #endif
00142 
00143             VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
00144                 DLSYM(libraryHandle, "vampGetPluginDescriptor");
00145 
00146             if (!fn) {
00147                 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl;
00148                 if (DLCLOSE(libraryHandle) != 0) {
00149                     std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
00150                 }
00151                 continue;
00152             }
00153 
00154 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00155             std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << std::endl;
00156 #endif
00157 
00158             const VampPluginDescriptor *descriptor = 0;
00159             int index = 0;
00160 
00161             std::map<std::string, int> known;
00162             bool ok = true;
00163 
00164             while ((descriptor = fn(VAMP_API_VERSION, index))) {
00165 
00166                 if (known.find(descriptor->identifier) != known.end()) {
00167                     std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
00168                               << soname.toStdString()
00169                               << " returns the same plugin identifier \""
00170                               << descriptor->identifier << "\" at indices "
00171                               << known[descriptor->identifier] << " and "
00172                               << index << std::endl;
00173                     std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << std::endl;
00174                     ok = false;
00175                     break;
00176                 } else {
00177                     known[descriptor->identifier] = index;
00178                 }
00179 
00180                 ++index;
00181             }
00182 
00183             if (ok) {
00184 
00185                 index = 0;
00186 
00187                 while ((descriptor = fn(VAMP_API_VERSION, index))) {
00188 
00189                     QString id = PluginIdentifier::createIdentifier
00190                         ("vamp", soname, descriptor->identifier);
00191                     rv.push_back(id);
00192 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00193                     std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id.toStdString() << " at index " << index << std::endl;
00194 #endif
00195                     ++index;
00196                 }
00197             }
00198             
00199             if (DLCLOSE(libraryHandle) != 0) {
00200                 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
00201             }
00202         }
00203     }
00204 
00205     generateTaxonomy();
00206 
00207     return rv;
00208 }
00209 
00210 QString
00211 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
00212 {
00213     QString file = "";
00214 
00215 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00216     std::cerr << "FeatureExtractionPluginFactory::findPluginFile(\""
00217               << soname.toStdString() << "\", \"" << inDir.toStdString() << "\")"
00218               << std::endl;
00219 #endif
00220 
00221     if (inDir != "") {
00222 
00223         QDir dir(inDir, PLUGIN_GLOB,
00224                  QDir::Name | QDir::IgnoreCase,
00225                  QDir::Files | QDir::Readable);
00226         if (!dir.exists()) return "";
00227 
00228         file = dir.filePath(QFileInfo(soname).fileName());
00229 
00230         if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
00231 
00232 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00233             std::cerr << "FeatureExtractionPluginFactory::findPluginFile: "
00234                       << "found trivially at " << file.toStdString() << std::endl;
00235 #endif
00236 
00237             return file;
00238         }
00239 
00240         for (unsigned int j = 0; j < dir.count(); ++j) {
00241             file = dir.filePath(dir[j]);
00242             if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
00243 
00244 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00245                 std::cerr << "FeatureExtractionPluginFactory::findPluginFile: "
00246                           << "found \"" << soname.toStdString() << "\" at " << file.toStdString() << std::endl;
00247 #endif
00248 
00249                 return file;
00250             }
00251         }
00252 
00253 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00254         std::cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): "
00255                   << "not found" << std::endl;
00256 #endif
00257 
00258         return "";
00259 
00260     } else {
00261 
00262         QFileInfo fi(soname);
00263 
00264         if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
00265 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00266             std::cerr << "FeatureExtractionPluginFactory::findPluginFile: "
00267                       << "found trivially at " << soname.toStdString() << std::endl;
00268 #endif
00269             return soname;
00270         }
00271 
00272         if (fi.isAbsolute() && fi.absolutePath() != "") {
00273             file = findPluginFile(soname, fi.absolutePath());
00274             if (file != "") return file;
00275         }
00276 
00277         std::vector<QString> path = getPluginPath();
00278         for (std::vector<QString>::iterator i = path.begin();
00279              i != path.end(); ++i) {
00280             if (*i != "") {
00281                 file = findPluginFile(soname, *i);
00282                 if (file != "") return file;
00283             }
00284         }
00285 
00286 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00287         std::cerr << "FeatureExtractionPluginFactory::findPluginFile: "
00288                   << "not found" << std::endl;
00289 #endif
00290 
00291         return "";
00292     }
00293 }
00294 
00295 Vamp::Plugin *
00296 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
00297                                                   float inputSampleRate)
00298 {
00299     Vamp::Plugin *rv = 0;
00300     Vamp::PluginHostAdapter *plugin = 0;
00301 
00302     const VampPluginDescriptor *descriptor = 0;
00303     int index = 0;
00304 
00305     QString type, soname, label;
00306     PluginIdentifier::parseIdentifier(identifier, type, soname, label);
00307     if (type != "vamp") {
00308         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl;
00309         return 0;
00310     }
00311 
00312     QString found = findPluginFile(soname);
00313 
00314     if (found == "") {
00315         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl;
00316         return 0;
00317     } else if (found != soname) {
00318 
00319 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
00320         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl;
00321         std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl;
00322 #endif
00323 
00324     }        
00325 
00326     soname = found;
00327 
00328     void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
00329             
00330     if (!libraryHandle) {
00331         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
00332         return 0;
00333     }
00334 
00335     VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
00336         DLSYM(libraryHandle, "vampGetPluginDescriptor");
00337     
00338     if (!fn) {
00339         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl;
00340         goto done;
00341     }
00342 
00343     while ((descriptor = fn(VAMP_API_VERSION, index))) {
00344         if (label == descriptor->identifier) break;
00345         ++index;
00346     }
00347 
00348     if (!descriptor) {
00349         std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl;
00350         goto done;
00351     }
00352 
00353     plugin = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
00354 
00355     if (plugin) {
00356         m_handleMap[plugin] = libraryHandle;
00357         rv = new PluginDeletionNotifyAdapter(plugin, this);
00358     }
00359 
00360 //    std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl;
00361 
00363 
00364 done:
00365     if (!rv) {
00366         if (DLCLOSE(libraryHandle) != 0) {
00367             std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl;
00368         }
00369     }
00370 
00371 //    std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label.toStdString() << " from library " << soname.toStdString() << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << std::endl;
00372     
00373     return rv;
00374 }
00375 
00376 void
00377 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
00378 {
00379     void *handle = m_handleMap[plugin];
00380     if (handle) {
00381 //        std::cerr << "unloading library " << handle << " for plugin " << plugin << std::endl;
00382         DLCLOSE(handle);
00383     }
00384     m_handleMap.erase(plugin);
00385 }
00386 
00387 QString
00388 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
00389 {
00390     return m_taxonomy[identifier];
00391 }
00392 
00393 void
00394 FeatureExtractionPluginFactory::generateTaxonomy()
00395 {
00396     std::vector<QString> pluginPath = getPluginPath();
00397     std::vector<QString> path;
00398 
00399     for (size_t i = 0; i < pluginPath.size(); ++i) {
00400         if (pluginPath[i].contains("/lib/")) {
00401             QString p(pluginPath[i]);
00402             path.push_back(p);
00403             p.replace("/lib/", "/share/");
00404             path.push_back(p);
00405         }
00406         path.push_back(pluginPath[i]);
00407     }
00408 
00409     for (size_t i = 0; i < path.size(); ++i) {
00410 
00411         QDir dir(path[i], "*.cat");
00412 
00413 //      std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl;
00414         for (unsigned int j = 0; j < dir.count(); ++j) {
00415 
00416             QFile file(path[i] + "/" + dir[j]);
00417 
00418 //          std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl;
00419 
00420             if (file.open(QIODevice::ReadOnly)) {
00421 //                  std::cerr << "...opened" << std::endl;
00422                 QTextStream stream(&file);
00423                 QString line;
00424 
00425                 while (!stream.atEnd()) {
00426                     line = stream.readLine();
00427 //                  std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl;
00428                     QString id = PluginIdentifier::canonicalise
00429                         (line.section("::", 0, 0));
00430                     QString cat = line.section("::", 1, 1);
00431                     m_taxonomy[id] = cat;
00432 //                  std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl;
00433                 }
00434             }
00435         }
00436     }
00437 }    

Generated on Wed Feb 20 15:45:25 2008 for SonicVisualiser by  doxygen 1.5.1