Mercurial > hg > easaier-soundaccess
comparison plugin/FeatureExtractionPluginFactory.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006 Chris Cannam and QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "FeatureExtractionPluginFactory.h" | |
17 #include "PluginIdentifier.h" | |
18 | |
19 #include "vamp/vamp.h" | |
20 #include "vamp-sdk/PluginHostAdapter.h" | |
21 | |
22 #include "system/System.h" | |
23 | |
24 #include <QDir> | |
25 #include <QFile> | |
26 #include <QFileInfo> | |
27 #include <QTextStream> | |
28 | |
29 #include <iostream> | |
30 | |
31 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 | |
32 | |
33 static FeatureExtractionPluginFactory *_nativeInstance = 0; | |
34 | |
35 FeatureExtractionPluginFactory * | |
36 FeatureExtractionPluginFactory::instance(QString pluginType) | |
37 { | |
38 if (pluginType == "vamp") { | |
39 if (!_nativeInstance) { | |
40 // std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString() | |
41 // << "): creating new FeatureExtractionPluginFactory" << std::endl; | |
42 _nativeInstance = new FeatureExtractionPluginFactory(); | |
43 } | |
44 return _nativeInstance; | |
45 } | |
46 | |
47 else return 0; | |
48 } | |
49 | |
50 FeatureExtractionPluginFactory * | |
51 FeatureExtractionPluginFactory::instanceFor(QString identifier) | |
52 { | |
53 QString type, soName, label; | |
54 PluginIdentifier::parseIdentifier(identifier, type, soName, label); | |
55 return instance(type); | |
56 } | |
57 | |
58 std::vector<QString> | |
59 FeatureExtractionPluginFactory::getPluginPath() | |
60 { | |
61 if (!m_pluginPath.empty()) return m_pluginPath; | |
62 | |
63 std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath(); | |
64 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); | |
65 return m_pluginPath; | |
66 } | |
67 | |
68 std::vector<QString> | |
69 FeatureExtractionPluginFactory::getAllPluginIdentifiers() | |
70 { | |
71 FeatureExtractionPluginFactory *factory; | |
72 std::vector<QString> rv; | |
73 | |
74 factory = instance("vamp"); | |
75 if (factory) { | |
76 std::vector<QString> tmp = factory->getPluginIdentifiers(); | |
77 for (size_t i = 0; i < tmp.size(); ++i) { | |
78 rv.push_back(tmp[i]); | |
79 } | |
80 } | |
81 | |
82 // Plugins can change the locale, revert it to default. | |
83 setlocale(LC_ALL, "C"); | |
84 return rv; | |
85 } | |
86 | |
87 std::vector<QString> | |
88 FeatureExtractionPluginFactory::getPluginIdentifiers() | |
89 { | |
90 std::vector<QString> rv; | |
91 std::vector<QString> path = getPluginPath(); | |
92 | |
93 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) { | |
94 | |
95 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
96 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl; | |
97 #endif | |
98 | |
99 QDir pluginDir(*i, PLUGIN_GLOB, | |
100 QDir::Name | QDir::IgnoreCase, | |
101 QDir::Files | QDir::Readable); | |
102 | |
103 for (unsigned int j = 0; j < pluginDir.count(); ++j) { | |
104 | |
105 QString soname = pluginDir.filePath(pluginDir[j]); | |
106 | |
107 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
108 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname.toStdString() << std::endl; | |
109 #endif | |
110 | |
111 void *libraryHandle = DLOPEN(soname, RTLD_LAZY); | |
112 | |
113 if (!libraryHandle) { | |
114 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; | |
115 continue; | |
116 } | |
117 | |
118 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
119 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << std::endl; | |
120 #endif | |
121 | |
122 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) | |
123 DLSYM(libraryHandle, "vampGetPluginDescriptor"); | |
124 | |
125 if (!fn) { | |
126 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl; | |
127 if (DLCLOSE(libraryHandle) != 0) { | |
128 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; | |
129 } | |
130 continue; | |
131 } | |
132 | |
133 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
134 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << std::endl; | |
135 #endif | |
136 | |
137 const VampPluginDescriptor *descriptor = 0; | |
138 int index = 0; | |
139 | |
140 std::map<std::string, int> known; | |
141 bool ok = true; | |
142 | |
143 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
144 | |
145 if (known.find(descriptor->identifier) != known.end()) { | |
146 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library " | |
147 << soname.toStdString() | |
148 << " returns the same plugin identifier \"" | |
149 << descriptor->identifier << "\" at indices " | |
150 << known[descriptor->identifier] << " and " | |
151 << index << std::endl; | |
152 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << std::endl; | |
153 ok = false; | |
154 break; | |
155 } else { | |
156 known[descriptor->identifier] = index; | |
157 } | |
158 | |
159 ++index; | |
160 } | |
161 | |
162 if (ok) { | |
163 | |
164 index = 0; | |
165 | |
166 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
167 | |
168 QString id = PluginIdentifier::createIdentifier | |
169 ("vamp", soname, descriptor->identifier); | |
170 rv.push_back(id); | |
171 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
172 std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id.toStdString() << " at index " << index << std::endl; | |
173 #endif | |
174 ++index; | |
175 } | |
176 } | |
177 | |
178 if (DLCLOSE(libraryHandle) != 0) { | |
179 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; | |
180 } | |
181 } | |
182 } | |
183 | |
184 generateTaxonomy(); | |
185 | |
186 return rv; | |
187 } | |
188 | |
189 QString | |
190 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) | |
191 { | |
192 QString file = ""; | |
193 | |
194 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
195 std::cerr << "FeatureExtractionPluginFactory::findPluginFile(\"" | |
196 << soname.toStdString() << "\", \"" << inDir.toStdString() << "\")" | |
197 << std::endl; | |
198 #endif | |
199 | |
200 if (inDir != "") { | |
201 | |
202 QDir dir(inDir, PLUGIN_GLOB, | |
203 QDir::Name | QDir::IgnoreCase, | |
204 QDir::Files | QDir::Readable); | |
205 if (!dir.exists()) return ""; | |
206 | |
207 file = dir.filePath(QFileInfo(soname).fileName()); | |
208 | |
209 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { | |
210 | |
211 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
212 std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
213 << "found trivially at " << file.toStdString() << std::endl; | |
214 #endif | |
215 | |
216 return file; | |
217 } | |
218 | |
219 for (unsigned int j = 0; j < dir.count(); ++j) { | |
220 file = dir.filePath(dir[j]); | |
221 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { | |
222 | |
223 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
224 std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
225 << "found at " << file.toStdString() << std::endl; | |
226 #endif | |
227 | |
228 return file; | |
229 } | |
230 } | |
231 | |
232 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
233 std::cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): " | |
234 << "not found" << std::endl; | |
235 #endif | |
236 | |
237 return ""; | |
238 | |
239 } else { | |
240 | |
241 QFileInfo fi(soname); | |
242 | |
243 if (fi.isAbsolute() && fi.exists() && fi.isFile()) { | |
244 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
245 std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
246 << "found trivially at " << soname.toStdString() << std::endl; | |
247 #endif | |
248 return soname; | |
249 } | |
250 | |
251 if (fi.isAbsolute() && fi.absolutePath() != "") { | |
252 file = findPluginFile(soname, fi.absolutePath()); | |
253 if (file != "") return file; | |
254 } | |
255 | |
256 std::vector<QString> path = getPluginPath(); | |
257 for (std::vector<QString>::iterator i = path.begin(); | |
258 i != path.end(); ++i) { | |
259 if (*i != "") { | |
260 file = findPluginFile(soname, *i); | |
261 if (file != "") return file; | |
262 } | |
263 } | |
264 | |
265 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
266 std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
267 << "not found" << std::endl; | |
268 #endif | |
269 | |
270 return ""; | |
271 } | |
272 } | |
273 | |
274 Vamp::Plugin * | |
275 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, | |
276 float inputSampleRate) | |
277 { | |
278 Vamp::Plugin *rv = 0; | |
279 | |
280 const VampPluginDescriptor *descriptor = 0; | |
281 int index = 0; | |
282 | |
283 QString type, soname, label; | |
284 PluginIdentifier::parseIdentifier(identifier, type, soname, label); | |
285 if (type != "vamp") { | |
286 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl; | |
287 return 0; | |
288 } | |
289 | |
290 QString found = findPluginFile(soname); | |
291 | |
292 if (found == "") { | |
293 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl; | |
294 return 0; | |
295 } else if (found != soname) { | |
296 | |
297 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
298 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl; | |
299 std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl; | |
300 #endif | |
301 | |
302 } | |
303 | |
304 soname = found; | |
305 | |
306 void *libraryHandle = DLOPEN(soname, RTLD_LAZY); | |
307 | |
308 if (!libraryHandle) { | |
309 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; | |
310 return 0; | |
311 } | |
312 | |
313 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) | |
314 DLSYM(libraryHandle, "vampGetPluginDescriptor"); | |
315 | |
316 if (!fn) { | |
317 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl; | |
318 goto done; | |
319 } | |
320 | |
321 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
322 if (label == descriptor->identifier) break; | |
323 ++index; | |
324 } | |
325 | |
326 if (!descriptor) { | |
327 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl; | |
328 goto done; | |
329 } | |
330 | |
331 rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate); | |
332 | |
333 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl; | |
334 | |
335 //!!! need to dlclose() when plugins from a given library are unloaded | |
336 | |
337 done: | |
338 if (!rv) { | |
339 if (DLCLOSE(libraryHandle) != 0) { | |
340 std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl; | |
341 } | |
342 } | |
343 | |
344 // 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; | |
345 | |
346 return rv; | |
347 } | |
348 | |
349 QString | |
350 FeatureExtractionPluginFactory::getPluginCategory(QString identifier) | |
351 { | |
352 return m_taxonomy[identifier]; | |
353 } | |
354 | |
355 void | |
356 FeatureExtractionPluginFactory::generateTaxonomy() | |
357 { | |
358 std::vector<QString> pluginPath = getPluginPath(); | |
359 std::vector<QString> path; | |
360 | |
361 for (size_t i = 0; i < pluginPath.size(); ++i) { | |
362 if (pluginPath[i].contains("/lib/")) { | |
363 QString p(pluginPath[i]); | |
364 path.push_back(p); | |
365 p.replace("/lib/", "/share/"); | |
366 path.push_back(p); | |
367 } | |
368 path.push_back(pluginPath[i]); | |
369 } | |
370 | |
371 for (size_t i = 0; i < path.size(); ++i) { | |
372 | |
373 QDir dir(path[i], "*.cat"); | |
374 | |
375 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl; | |
376 for (unsigned int j = 0; j < dir.count(); ++j) { | |
377 | |
378 QFile file(path[i] + "/" + dir[j]); | |
379 | |
380 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl; | |
381 | |
382 if (file.open(QIODevice::ReadOnly)) { | |
383 // std::cerr << "...opened" << std::endl; | |
384 QTextStream stream(&file); | |
385 QString line; | |
386 | |
387 while (!stream.atEnd()) { | |
388 line = stream.readLine(); | |
389 // std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl; | |
390 QString id = PluginIdentifier::canonicalise | |
391 (line.section("::", 0, 0)); | |
392 QString cat = line.section("::", 1, 1); | |
393 m_taxonomy[id] = cat; | |
394 // std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl; | |
395 } | |
396 } | |
397 } | |
398 } | |
399 } |