annotate plugin/FeatureExtractionPluginFactory.cpp @ 66:7afcfe666910

* Modify to use Vamp SDK for proper feature extraction plugins. Requires that the vamp-plugin-sdk directory tree be present below plugin/ (it's separate in Subversion).
author Chris Cannam
date Fri, 31 Mar 2006 15:56:35 +0000
parents d397ea0a79f5
children e32c6a6cb40f
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@0 19 #include "plugins/BeatDetect.h" //!!!
Chris@19 20 #include "plugins/ChromagramPlugin.h" //!!!
Chris@0 21 #include "plugins/ZeroCrossing.h" //!!!
Chris@47 22 #include "plugins/SpectralCentroid.h" //!!!
Martin@37 23 #include "plugins/TonalChangeDetect.h" //!!!
Chris@0 24
Chris@66 25 #include "vamp/vamp.h"
Chris@66 26 #include "vamp-sdk/PluginHostAdapter.h"
Chris@66 27
Chris@66 28 #include "base/System.h"
Chris@66 29
Chris@66 30 #include <QDir>
Chris@66 31 #include <QFile>
Chris@66 32 #include <QFileInfo>
Chris@66 33
Chris@0 34 #include <iostream>
Chris@0 35
Chris@0 36 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 37
Chris@0 38 FeatureExtractionPluginFactory *
Chris@0 39 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 40 {
Chris@66 41 if (pluginType == "vamp" || pluginType == "sv") { //!!!
Chris@0 42 if (!_nativeInstance) {
Chris@0 43 std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString()
Chris@0 44 << "): creating new FeatureExtractionPluginFactory" << std::endl;
Chris@0 45 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 46 }
Chris@0 47 return _nativeInstance;
Chris@0 48 }
Chris@0 49
Chris@0 50 else return 0;
Chris@0 51 }
Chris@0 52
Chris@0 53 FeatureExtractionPluginFactory *
Chris@0 54 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 55 {
Chris@0 56 QString type, soName, label;
Chris@0 57 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 58 return instance(type);
Chris@0 59 }
Chris@0 60
Chris@0 61 std::vector<QString>
Chris@66 62 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 63 {
Chris@66 64 std::vector<QString> path;
Chris@66 65 std::string envPath;
Chris@66 66
Chris@66 67 char *cpath = getenv("Vamp_PATH");
Chris@66 68 if (cpath) envPath = cpath;
Chris@66 69
Chris@66 70 if (envPath == "") {
Chris@66 71 //!!! system dependent
Chris@66 72 envPath = "/usr/local/lib/vamp:/usr/lib/vamp";
Chris@66 73 char *chome = getenv("HOME");
Chris@66 74 if (chome) {
Chris@66 75 envPath = std::string(chome) + "/vamp:" +
Chris@66 76 std::string(chome) + "/.vamp:" + envPath;
Chris@66 77 }
Chris@66 78 }
Chris@66 79
Chris@66 80 std::string::size_type index = 0, newindex = 0;
Chris@66 81
Chris@66 82 while ((newindex = envPath.find(':', index)) < envPath.size()) {
Chris@66 83 path.push_back(envPath.substr(index, newindex - index).c_str());
Chris@66 84 index = newindex + 1;
Chris@66 85 }
Chris@66 86
Chris@66 87 path.push_back(envPath.substr(index).c_str());
Chris@66 88
Chris@66 89 return path;
Chris@66 90 }
Chris@66 91
Chris@66 92 std::vector<QString>
Chris@0 93 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 94 {
Chris@0 95 FeatureExtractionPluginFactory *factory;
Chris@0 96 std::vector<QString> rv;
Chris@0 97
Chris@66 98 factory = instance("vamp");
Chris@0 99 if (factory) {
Chris@0 100 std::vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 101 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@0 102 rv.push_back(tmp[i]);
Chris@0 103 }
Chris@0 104 }
Chris@0 105
Chris@0 106 // Plugins can change the locale, revert it to default.
Chris@0 107 setlocale(LC_ALL, "C");
Chris@0 108 return rv;
Chris@0 109 }
Chris@0 110
Chris@0 111 std::vector<QString>
Chris@0 112 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 113 {
Chris@0 114 std::vector<QString> rv;
Chris@0 115 rv.push_back("sv:_builtin:beats"); //!!!
Chris@19 116 rv.push_back("sv:_builtin:chromagram"); //!!!
Chris@0 117 rv.push_back("sv:_builtin:zerocrossing"); //!!!
Chris@47 118 rv.push_back("sv:_builtin:spectralcentroid"); //!!!
Chris@47 119 rv.push_back("sv:_builtin:tonalchange"); //!!!
Chris@66 120
Chris@66 121 std::vector<QString> path = getPluginPath();
Chris@66 122
Chris@66 123 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
Chris@66 124
Chris@66 125 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl;
Chris@66 126
Chris@66 127 QDir pluginDir(*i, PLUGIN_GLOB,
Chris@66 128 QDir::Name | QDir::IgnoreCase,
Chris@66 129 QDir::Files | QDir::Readable);
Chris@66 130
Chris@66 131 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@66 132
Chris@66 133 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@66 134
Chris@66 135 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 136
Chris@66 137 if (!libraryHandle) {
Chris@66 138 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << std::endl;
Chris@66 139 continue;
Chris@66 140 }
Chris@66 141
Chris@66 142 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 143 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 144
Chris@66 145 if (!fn) {
Chris@66 146 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 147 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 148 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 149 }
Chris@66 150 continue;
Chris@66 151 }
Chris@66 152
Chris@66 153 const VampPluginDescriptor *descriptor = 0;
Chris@66 154 int index = 0;
Chris@66 155
Chris@66 156 while ((descriptor = fn(index))) {
Chris@66 157 QString id = QString("vamp:%1:%2").arg(soname).arg(descriptor->name);
Chris@66 158 rv.push_back(id);
Chris@66 159 std::cerr << "Found id " << id.toStdString() << std::endl;
Chris@66 160 ++index;
Chris@66 161 }
Chris@66 162
Chris@66 163 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 164 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 165 }
Chris@66 166 }
Chris@66 167 }
Chris@66 168
Chris@0 169 return rv;
Chris@0 170 }
Chris@0 171
Chris@66 172 QString
Chris@66 173 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 174 {
Chris@66 175 QString file = "";
Chris@66 176
Chris@66 177 if (inDir != "") {
Chris@66 178
Chris@66 179 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 180 QDir::Name | QDir::IgnoreCase,
Chris@66 181 QDir::Files | QDir::Readable);
Chris@66 182 if (!dir.exists()) return "";
Chris@66 183
Chris@66 184 file = dir.filePath(QFileInfo(soname).fileName());
Chris@66 185 if (QFileInfo(file).exists()) {
Chris@66 186 return file;
Chris@66 187 }
Chris@66 188
Chris@66 189 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 190 file = dir.filePath(dir[j]);
Chris@66 191 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@66 192 return file;
Chris@66 193 }
Chris@66 194 }
Chris@66 195
Chris@66 196 return "";
Chris@66 197
Chris@66 198 } else {
Chris@66 199
Chris@66 200 QFileInfo fi(soname);
Chris@66 201 if (fi.exists()) return soname;
Chris@66 202
Chris@66 203 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 204 file = findPluginFile(soname, fi.absolutePath());
Chris@66 205 if (file != "") return file;
Chris@66 206 }
Chris@66 207
Chris@66 208 std::vector<QString> path = getPluginPath();
Chris@66 209 for (std::vector<QString>::iterator i = path.begin();
Chris@66 210 i != path.end(); ++i) {
Chris@66 211 if (*i != "") {
Chris@66 212 file = findPluginFile(soname, *i);
Chris@66 213 if (file != "") return file;
Chris@66 214 }
Chris@66 215 }
Chris@66 216
Chris@66 217 return "";
Chris@66 218 }
Chris@66 219 }
Chris@66 220
Chris@66 221 Vamp::Plugin *
Chris@0 222 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@0 223 float inputSampleRate)
Chris@0 224 {
Chris@66 225 Vamp::Plugin *rv = 0;
Chris@66 226
Chris@66 227 const VampPluginDescriptor *descriptor = 0;
Chris@66 228 int index = 0;
Chris@66 229
Chris@66 230 QString type, soname, label;
Chris@66 231 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@66 232 if (type != "vamp" && type != "sv") { //!!!
Chris@0 233 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl;
Chris@0 234 return 0;
Chris@0 235 }
Chris@0 236
Chris@0 237 //!!!
Chris@66 238 if (type == "sv" && soname == PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
Chris@66 239
Chris@66 240 if (label == "beats") {
Chris@66 241 return new BeatDetector(inputSampleRate); //!!!
Chris@66 242 }
Chris@66 243
Chris@66 244 if (label == "chromagram") {
Chris@66 245 return new ChromagramPlugin(inputSampleRate); //!!!
Chris@66 246 }
Chris@66 247
Chris@66 248 if (label == "zerocrossing") {
Chris@66 249 return new ZeroCrossing(inputSampleRate); //!!!
Chris@66 250 }
Chris@66 251
Chris@66 252 if (label == "spectralcentroid") {
Chris@66 253 return new SpectralCentroid(inputSampleRate); //!!!
Chris@66 254 }
Chris@66 255
Chris@66 256 if (label == "tonalchange") {
Chris@66 257 return new TonalChangeDetect(inputSampleRate); //!!!
Chris@66 258 }
Chris@66 259
Chris@66 260 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Unknown plugin \"" << identifier.toStdString() << "\"" << std::endl;
Chris@66 261
Chris@66 262 return 0;
Chris@0 263 }
Chris@0 264
Chris@66 265 QString found = findPluginFile(soname);
Chris@66 266
Chris@66 267 if (found == "") {
Chris@66 268 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl;
Chris@66 269 } else if (found != soname) {
Chris@66 270 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: WARNING: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl;
Chris@0 271 }
Chris@0 272
Chris@66 273 soname = found;
Chris@66 274
Chris@66 275 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 276
Chris@66 277 if (!libraryHandle) {
Chris@66 278 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << std::endl;
Chris@66 279 return 0;
Chris@19 280 }
Chris@19 281
Chris@66 282 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 283 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 284
Chris@66 285 if (!fn) {
Chris@66 286 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 287 goto done;
Chris@0 288 }
Chris@0 289
Chris@66 290 while ((descriptor = fn(index))) {
Chris@66 291 if (label == descriptor->name) break;
Chris@66 292 ++index;
Chris@47 293 }
Chris@47 294
Chris@66 295 if (!descriptor) {
Chris@66 296 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl;
Chris@66 297 goto done;
Martin@37 298 }
Martin@37 299
Chris@66 300 rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Chris@66 301
Chris@66 302 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 303
Chris@66 304 done:
Chris@66 305 if (!rv) {
Chris@66 306 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 307 std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 308 }
Chris@66 309 }
Chris@66 310 return rv;
Chris@0 311 }
Chris@0 312