annotate vamp-hostsdk/PluginLoader.cpp @ 57:09a1aac6c362 host-factory-stuff

* add wrapper base * make loader able to look up categories
author cannam
date Wed, 09 May 2007 15:21:37 +0000
parents 4ab6224110ef
children
rev   line source
cannam@56 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@56 2
cannam@56 3 /*
cannam@56 4 Vamp
cannam@56 5
cannam@56 6 An API for audio analysis and feature extraction plugins.
cannam@56 7
cannam@56 8 Centre for Digital Music, Queen Mary, University of London.
cannam@56 9 Copyright 2006 Chris Cannam.
cannam@56 10
cannam@56 11 Permission is hereby granted, free of charge, to any person
cannam@56 12 obtaining a copy of this software and associated documentation
cannam@56 13 files (the "Software"), to deal in the Software without
cannam@56 14 restriction, including without limitation the rights to use, copy,
cannam@56 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@56 16 of the Software, and to permit persons to whom the Software is
cannam@56 17 furnished to do so, subject to the following conditions:
cannam@56 18
cannam@56 19 The above copyright notice and this permission notice shall be
cannam@56 20 included in all copies or substantial portions of the Software.
cannam@56 21
cannam@56 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@56 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@56 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@56 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@56 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@56 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@56 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@56 29
cannam@56 30 Except as contained in this notice, the names of the Centre for
cannam@56 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@56 32 shall not be used in advertising or otherwise to promote the sale,
cannam@56 33 use or other dealings in this Software without prior written
cannam@56 34 authorization.
cannam@56 35 */
cannam@56 36
cannam@56 37 #include "PluginLoader.h"
cannam@56 38 #include "PluginHostAdapter.h"
cannam@56 39
cannam@56 40 #include "system.h"
cannam@56 41
cannam@57 42 #include <fstream>
cannam@57 43
cannam@56 44 #include <dirent.h> // POSIX directory open and read
cannam@56 45
cannam@57 46 using namespace std;
cannam@57 47
cannam@56 48 namespace Vamp {
cannam@56 49
cannam@56 50 PluginLoader::PluginLoader()
cannam@56 51 {
cannam@56 52 }
cannam@56 53
cannam@56 54 PluginLoader::~PluginLoader()
cannam@56 55 {
cannam@56 56 }
cannam@56 57
cannam@57 58 vector<PluginLoader::PluginKey>
cannam@56 59 PluginLoader::listPlugins()
cannam@56 60 {
cannam@56 61 if (m_pluginLibraryMap.empty()) {
cannam@56 62
cannam@57 63 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@56 64
cannam@56 65 size_t suffixLen = strlen(PLUGIN_SUFFIX);
cannam@56 66
cannam@56 67 for (size_t i = 0; i < path.size(); ++i) {
cannam@57 68
cannam@57 69 vector<string> files = getFilesInDir(path[i], PLUGIN_SUFFIX);
cannam@57 70
cannam@56 71
cannam@57 72 for (vector<string>::iterator fi = files.begin();
cannam@57 73 fi != files.end(); ++fi) {
cannam@56 74
cannam@57 75 string basename = *fi;
cannam@57 76 basename = basename.substr(0, basename.length() - suffixLen - 1);
cannam@56 77
cannam@57 78 string fullPath = path[i];
cannam@57 79 fullPath = fullPath + "/" + *fi; //!!! systemize
cannam@56 80 void *handle = DLOPEN(fullPath, RTLD_LAZY);
cannam@56 81
cannam@56 82 if (!handle) {
cannam@57 83 cerr << "Vamp::PluginLoader: " << *fi
cannam@56 84 << ": unable to load library (" << DLERROR()
cannam@57 85 << ")" << endl;
cannam@56 86 continue;
cannam@56 87 }
cannam@56 88
cannam@56 89 VampGetPluginDescriptorFunction fn =
cannam@56 90 (VampGetPluginDescriptorFunction)DLSYM
cannam@56 91 (handle, "vampGetPluginDescriptor");
cannam@56 92
cannam@56 93 if (!fn) {
cannam@56 94 DLCLOSE(handle);
cannam@56 95 continue;
cannam@56 96 }
cannam@56 97
cannam@56 98 int index = 0;
cannam@56 99 const VampPluginDescriptor *descriptor = 0;
cannam@56 100
cannam@56 101 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@56 102 PluginKey key = basename + ":" + descriptor->identifier;
cannam@56 103 if (m_pluginLibraryMap.find(key) ==
cannam@56 104 m_pluginLibraryMap.end()) {
cannam@56 105 m_pluginLibraryMap[key] = fullPath;
cannam@56 106 }
cannam@56 107 ++index;
cannam@56 108 }
cannam@56 109
cannam@56 110 DLCLOSE(handle);
cannam@56 111 }
cannam@56 112 }
cannam@56 113 }
cannam@56 114
cannam@57 115 vector<PluginKey> plugins;
cannam@57 116 for (map<PluginKey, string>::iterator mi =
cannam@56 117 m_pluginLibraryMap.begin();
cannam@56 118 mi != m_pluginLibraryMap.end(); ++mi) {
cannam@56 119 plugins.push_back(mi->first);
cannam@56 120 }
cannam@56 121
cannam@56 122 return plugins;
cannam@56 123 }
cannam@56 124
cannam@57 125 PluginLoader::PluginCategoryHierarchy
cannam@57 126 PluginLoader::getPluginCategory(PluginKey plugin)
cannam@57 127 {
cannam@57 128 if (m_taxonomy.empty()) generateTaxonomy();
cannam@57 129 if (m_taxonomy.find(plugin) == m_taxonomy.end()) return PluginCategoryHierarchy();
cannam@57 130 return m_taxonomy[plugin];
cannam@57 131 }
cannam@57 132
cannam@57 133 string
cannam@57 134 PluginLoader::getLibraryPathForPlugin(PluginKey plugin)
cannam@56 135 {
cannam@56 136 if (m_pluginLibraryMap.empty()) (void)listPlugins();
cannam@57 137 if (m_pluginLibraryMap.find(plugin) == m_pluginLibraryMap.end()) return "";
cannam@57 138 return m_pluginLibraryMap[plugin];
cannam@56 139 }
cannam@56 140
cannam@56 141 Plugin *
cannam@56 142 PluginLoader::load(PluginKey key, float inputSampleRate)
cannam@56 143 {
cannam@57 144 string fullPath = getLibraryPathForPlugin(key);
cannam@56 145 if (fullPath == "") return 0;
cannam@56 146
cannam@57 147 string::size_type ki = key.find(':');
cannam@57 148 if (ki == string::npos) {
cannam@56 149 //!!! flag error
cannam@56 150 return 0;
cannam@56 151 }
cannam@56 152
cannam@57 153 string identifier = key.substr(ki + 1);
cannam@56 154
cannam@56 155 void *handle = DLOPEN(fullPath, RTLD_LAZY);
cannam@56 156
cannam@56 157 if (!handle) {
cannam@57 158 cerr << "Vamp::PluginLoader: " << fullPath
cannam@56 159 << ": unable to load library (" << DLERROR()
cannam@57 160 << ")" << endl;
cannam@56 161 return 0;
cannam@56 162 }
cannam@56 163
cannam@56 164 VampGetPluginDescriptorFunction fn =
cannam@56 165 (VampGetPluginDescriptorFunction)DLSYM
cannam@56 166 (handle, "vampGetPluginDescriptor");
cannam@56 167
cannam@56 168 if (!fn) {
cannam@56 169 //!!! refcount this! --!!! no, POSIX says dlopen/dlclose will
cannam@56 170 // reference count. check on win32
cannam@56 171 DLCLOSE(handle);
cannam@56 172 return 0;
cannam@56 173 }
cannam@56 174
cannam@56 175 int index = 0;
cannam@56 176 const VampPluginDescriptor *descriptor = 0;
cannam@56 177
cannam@56 178 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@57 179 if (string(descriptor->identifier) == identifier) {
cannam@56 180 return new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@56 181 }
cannam@56 182 ++index;
cannam@56 183 }
cannam@56 184
cannam@56 185 //!!! flag error
cannam@56 186 return 0;
cannam@56 187 }
cannam@56 188
cannam@57 189 vector<string>
cannam@57 190 PluginLoader::getFilesInDir(string dir, string extension)
cannam@57 191 {
cannam@57 192 vector<string> files;
cannam@57 193
cannam@57 194 DIR *d = opendir(dir.c_str());
cannam@57 195 if (!d) return files;
cannam@57 196
cannam@57 197 struct dirent *e = 0;
cannam@57 198 while ((e = readdir(d))) {
cannam@57 199
cannam@57 200 if (!(e->d_type & DT_REG) || !e->d_name) {
cannam@57 201 continue;
cannam@57 202 }
cannam@57 203
cannam@57 204 int len = strlen(e->d_name);
cannam@57 205 if (len < int(extension.length() + 2) ||
cannam@57 206 e->d_name[len - extension.length() - 1] != '.' ||
cannam@57 207 strcmp(e->d_name + len - extension.length(), extension.c_str())) {
cannam@57 208 continue;
cannam@57 209 }
cannam@57 210
cannam@57 211 files.push_back(e->d_name);
cannam@57 212 }
cannam@57 213
cannam@57 214 closedir(d);
cannam@57 215
cannam@57 216 return files;
cannam@56 217 }
cannam@56 218
cannam@57 219 void
cannam@57 220 PluginLoader::generateTaxonomy()
cannam@57 221 {
cannam@57 222 // cerr << "PluginLoader::generateTaxonomy" << endl;
cannam@57 223
cannam@57 224 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@57 225 string libfragment = "/lib/";
cannam@57 226 vector<string> catpath;
cannam@57 227
cannam@57 228 string suffix = "cat";
cannam@57 229
cannam@57 230 for (vector<string>::iterator i = path.begin();
cannam@57 231 i != path.end(); ++i) {
cannam@57 232
cannam@57 233 string dir = *i;
cannam@57 234 string::size_type li = dir.find(libfragment);
cannam@57 235
cannam@57 236 if (li != string::npos) {
cannam@57 237 catpath.push_back
cannam@57 238 (dir.substr(0, li)
cannam@57 239 + "/share/"
cannam@57 240 + dir.substr(li + libfragment.length()));
cannam@57 241 }
cannam@57 242
cannam@57 243 catpath.push_back(dir);
cannam@57 244 }
cannam@57 245
cannam@57 246 char buffer[1024];
cannam@57 247
cannam@57 248 for (vector<string>::iterator i = catpath.begin();
cannam@57 249 i != catpath.end(); ++i) {
cannam@57 250
cannam@57 251 vector<string> files = getFilesInDir(*i, suffix);
cannam@57 252
cannam@57 253 for (vector<string>::iterator fi = files.begin();
cannam@57 254 fi != files.end(); ++fi) {
cannam@57 255
cannam@57 256 string filepath = *i + "/" + *fi; //!!! systemize
cannam@57 257 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@57 258
cannam@57 259 if (is.fail()) {
cannam@57 260 // cerr << "failed to open: " << filepath << endl;
cannam@57 261 continue;
cannam@57 262 }
cannam@57 263
cannam@57 264 // cerr << "opened: " << filepath << endl;
cannam@57 265
cannam@57 266 while (!!is.getline(buffer, 1024)) {
cannam@57 267
cannam@57 268 string line(buffer);
cannam@57 269
cannam@57 270 // cerr << "line = " << line << endl;
cannam@57 271
cannam@57 272 string::size_type di = line.find("::");
cannam@57 273 if (di == string::npos) continue;
cannam@57 274
cannam@57 275 string id = line.substr(0, di);
cannam@57 276 string encodedCat = line.substr(di + 2);
cannam@57 277
cannam@57 278 if (id.substr(0, 5) != "vamp:") continue;
cannam@57 279 id = id.substr(5);
cannam@57 280
cannam@57 281 while (encodedCat.length() >= 1 &&
cannam@57 282 encodedCat[encodedCat.length()-1] == '\r') {
cannam@57 283 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@57 284 }
cannam@57 285
cannam@57 286 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@57 287
cannam@57 288 PluginCategoryHierarchy category;
cannam@57 289 string::size_type ai;
cannam@57 290 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@57 291 category.push_back(encodedCat.substr(0, ai));
cannam@57 292 encodedCat = encodedCat.substr(ai + 3);
cannam@57 293 }
cannam@57 294 if (encodedCat != "") category.push_back(encodedCat);
cannam@57 295
cannam@57 296 m_taxonomy[id] = category;
cannam@57 297 }
cannam@57 298 }
cannam@57 299 }
cannam@57 300 }
cannam@57 301
cannam@57 302
cannam@57 303 }