annotate plugin/FeatureExtractionPluginFactory.cpp @ 123:0f37e92e1782

* 1502816 file export is too slow and memory-hungry Use text stream when writing to file instead of accumulating into a string. * 1500625 Auto-align in MIDI layer confusing Make value extents convert to Hz in return value * 1494623: Duplicate display of frame 0 from vamp plugin output
author Chris Cannam
date Thu, 15 Jun 2006 15:48:05 +0000
parents c30728d5625c
children 4b2ea82fd0ed
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@52 7 This file copyright 2006 Chris Cannam.
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@0 16 #include "FeatureExtractionPluginFactory.h"
Chris@0 17 #include "PluginIdentifier.h"
Chris@0 18
Chris@66 19 #include "vamp/vamp.h"
Chris@66 20 #include "vamp-sdk/PluginHostAdapter.h"
Chris@66 21
Chris@66 22 #include "base/System.h"
Chris@66 23
Chris@66 24 #include <QDir>
Chris@66 25 #include <QFile>
Chris@66 26 #include <QFileInfo>
Chris@66 27
Chris@0 28 #include <iostream>
Chris@0 29
Chris@0 30 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 31
Chris@0 32 FeatureExtractionPluginFactory *
Chris@0 33 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 34 {
Chris@71 35 if (pluginType == "vamp") {
Chris@0 36 if (!_nativeInstance) {
Chris@0 37 std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString()
Chris@0 38 << "): creating new FeatureExtractionPluginFactory" << std::endl;
Chris@0 39 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 40 }
Chris@0 41 return _nativeInstance;
Chris@0 42 }
Chris@0 43
Chris@0 44 else return 0;
Chris@0 45 }
Chris@0 46
Chris@0 47 FeatureExtractionPluginFactory *
Chris@0 48 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 49 {
Chris@0 50 QString type, soName, label;
Chris@0 51 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 52 return instance(type);
Chris@0 53 }
Chris@0 54
Chris@0 55 std::vector<QString>
Chris@66 56 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 57 {
Chris@117 58 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@117 59
Chris@66 60 std::vector<QString> path;
Chris@66 61 std::string envPath;
Chris@66 62
Chris@78 63 char *cpath = getenv("VAMP_PATH");
Chris@66 64 if (cpath) envPath = cpath;
Chris@66 65
Chris@66 66 if (envPath == "") {
Chris@78 67 envPath = DEFAULT_VAMP_PATH;
Chris@66 68 char *chome = getenv("HOME");
Chris@66 69 if (chome) {
Chris@78 70 std::string home(chome);
Chris@78 71 int f;
Chris@78 72 while ((f = envPath.find("$HOME")) >= 0 && f < envPath.length()) {
Chris@78 73 envPath.replace(f, 5, home);
Chris@78 74 }
Chris@66 75 }
Chris@83 76 #ifdef Q_WS_WIN32
Chris@83 77 char *cpfiles = getenv("ProgramFiles");
Chris@83 78 if (!cpfiles) cpfiles = "C:\\Program Files";
Chris@83 79 std::string pfiles(cpfiles);
Chris@83 80 int f;
Chris@83 81 while ((f = envPath.find("%ProgramFiles%")) >= 0 && f < envPath.length()) {
Chris@83 82 envPath.replace(f, 14, pfiles);
Chris@83 83 }
Chris@83 84 #endif
Chris@66 85 }
Chris@66 86
Chris@78 87 std::cerr << "VAMP path is: \"" << envPath << "\"" << std::endl;
Chris@78 88
Chris@66 89 std::string::size_type index = 0, newindex = 0;
Chris@66 90
Chris@78 91 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
Chris@66 92 path.push_back(envPath.substr(index, newindex - index).c_str());
Chris@66 93 index = newindex + 1;
Chris@66 94 }
Chris@66 95
Chris@66 96 path.push_back(envPath.substr(index).c_str());
Chris@66 97
Chris@117 98 m_pluginPath = path;
Chris@66 99 return path;
Chris@66 100 }
Chris@66 101
Chris@66 102 std::vector<QString>
Chris@0 103 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 104 {
Chris@0 105 FeatureExtractionPluginFactory *factory;
Chris@0 106 std::vector<QString> rv;
Chris@0 107
Chris@66 108 factory = instance("vamp");
Chris@0 109 if (factory) {
Chris@0 110 std::vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 111 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@0 112 rv.push_back(tmp[i]);
Chris@0 113 }
Chris@0 114 }
Chris@0 115
Chris@0 116 // Plugins can change the locale, revert it to default.
Chris@0 117 setlocale(LC_ALL, "C");
Chris@0 118 return rv;
Chris@0 119 }
Chris@0 120
Chris@0 121 std::vector<QString>
Chris@0 122 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 123 {
Chris@0 124 std::vector<QString> rv;
Chris@66 125 std::vector<QString> path = getPluginPath();
Chris@66 126
Chris@66 127 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
Chris@66 128
Chris@117 129 // std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl;
Chris@66 130
Chris@66 131 QDir pluginDir(*i, PLUGIN_GLOB,
Chris@66 132 QDir::Name | QDir::IgnoreCase,
Chris@66 133 QDir::Files | QDir::Readable);
Chris@66 134
Chris@66 135 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@66 136
Chris@66 137 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@66 138
Chris@66 139 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 140
Chris@66 141 if (!libraryHandle) {
Chris@71 142 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 143 continue;
Chris@66 144 }
Chris@66 145
Chris@66 146 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 147 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 148
Chris@66 149 if (!fn) {
Chris@66 150 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 151 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 152 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 153 }
Chris@66 154 continue;
Chris@66 155 }
Chris@66 156
Chris@66 157 const VampPluginDescriptor *descriptor = 0;
Chris@66 158 int index = 0;
Chris@66 159
Chris@66 160 while ((descriptor = fn(index))) {
Chris@82 161 QString id = PluginIdentifier::createIdentifier
Chris@82 162 ("vamp", soname, descriptor->name);
Chris@66 163 rv.push_back(id);
Chris@66 164 std::cerr << "Found id " << id.toStdString() << std::endl;
Chris@66 165 ++index;
Chris@66 166 }
Chris@66 167
Chris@66 168 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 169 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 170 }
Chris@66 171 }
Chris@66 172 }
Chris@66 173
Chris@0 174 return rv;
Chris@0 175 }
Chris@0 176
Chris@66 177 QString
Chris@66 178 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 179 {
Chris@66 180 QString file = "";
Chris@66 181
Chris@66 182 if (inDir != "") {
Chris@66 183
Chris@66 184 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 185 QDir::Name | QDir::IgnoreCase,
Chris@66 186 QDir::Files | QDir::Readable);
Chris@66 187 if (!dir.exists()) return "";
Chris@66 188
Chris@66 189 file = dir.filePath(QFileInfo(soname).fileName());
Chris@66 190 if (QFileInfo(file).exists()) {
Chris@66 191 return file;
Chris@66 192 }
Chris@66 193
Chris@66 194 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 195 file = dir.filePath(dir[j]);
Chris@66 196 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@66 197 return file;
Chris@66 198 }
Chris@66 199 }
Chris@66 200
Chris@66 201 return "";
Chris@66 202
Chris@66 203 } else {
Chris@66 204
Chris@66 205 QFileInfo fi(soname);
Chris@66 206 if (fi.exists()) return soname;
Chris@66 207
Chris@66 208 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 209 file = findPluginFile(soname, fi.absolutePath());
Chris@66 210 if (file != "") return file;
Chris@66 211 }
Chris@66 212
Chris@66 213 std::vector<QString> path = getPluginPath();
Chris@66 214 for (std::vector<QString>::iterator i = path.begin();
Chris@66 215 i != path.end(); ++i) {
Chris@66 216 if (*i != "") {
Chris@66 217 file = findPluginFile(soname, *i);
Chris@66 218 if (file != "") return file;
Chris@66 219 }
Chris@66 220 }
Chris@66 221
Chris@66 222 return "";
Chris@66 223 }
Chris@66 224 }
Chris@66 225
Chris@66 226 Vamp::Plugin *
Chris@0 227 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@0 228 float inputSampleRate)
Chris@0 229 {
Chris@66 230 Vamp::Plugin *rv = 0;
Chris@66 231
Chris@66 232 const VampPluginDescriptor *descriptor = 0;
Chris@66 233 int index = 0;
Chris@66 234
Chris@66 235 QString type, soname, label;
Chris@66 236 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 237 if (type != "vamp") {
Chris@0 238 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl;
Chris@0 239 return 0;
Chris@0 240 }
Chris@0 241
Chris@66 242 QString found = findPluginFile(soname);
Chris@66 243
Chris@66 244 if (found == "") {
Chris@66 245 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl;
Chris@117 246 return 0;
Chris@66 247 } else if (found != soname) {
Chris@117 248 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: WARNING: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl;
Chris@117 249 // std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl;
Chris@0 250 }
Chris@0 251
Chris@66 252 soname = found;
Chris@66 253
Chris@66 254 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 255
Chris@66 256 if (!libraryHandle) {
Chris@71 257 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 258 return 0;
Chris@19 259 }
Chris@19 260
Chris@66 261 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 262 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 263
Chris@66 264 if (!fn) {
Chris@66 265 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 266 goto done;
Chris@0 267 }
Chris@0 268
Chris@66 269 while ((descriptor = fn(index))) {
Chris@66 270 if (label == descriptor->name) break;
Chris@66 271 ++index;
Chris@47 272 }
Chris@47 273
Chris@66 274 if (!descriptor) {
Chris@66 275 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl;
Chris@66 276 goto done;
Martin@37 277 }
Martin@37 278
Chris@66 279 rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Chris@66 280
Chris@117 281 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl;
Chris@79 282
Chris@66 283 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 284
Chris@66 285 done:
Chris@66 286 if (!rv) {
Chris@66 287 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 288 std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 289 }
Chris@66 290 }
Chris@73 291
Chris@73 292 // 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;
Chris@73 293
Chris@66 294 return rv;
Chris@0 295 }
Chris@0 296