Mercurial > hg > easaier-soundaccess
comparison plugin/LADSPAPluginFactory.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children | afcf540ae3a2 |
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 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 */ | |
14 | |
15 /* | |
16 This is a modified version of a source file from the | |
17 Rosegarden MIDI and audio sequencer and notation editor. | |
18 This file copyright 2000-2006 Chris Cannam and Richard Bown. | |
19 */ | |
20 | |
21 #include "LADSPAPluginFactory.h" | |
22 #include <iostream> | |
23 | |
24 #include <QDir> | |
25 #include <QFile> | |
26 #include <QTextStream> | |
27 | |
28 #include <cmath> | |
29 | |
30 #include "LADSPAPluginInstance.h" | |
31 #include "PluginIdentifier.h" | |
32 | |
33 #include "system/System.h" | |
34 #include "base/Preferences.h" | |
35 | |
36 //#define DEBUG_LADSPA_PLUGIN_FACTORY 1 | |
37 | |
38 #ifdef HAVE_LRDF | |
39 #include "lrdf.h" | |
40 #endif // HAVE_LRDF | |
41 | |
42 | |
43 LADSPAPluginFactory::LADSPAPluginFactory() | |
44 { | |
45 #ifdef HAVE_LRDF | |
46 lrdf_init(); | |
47 #endif | |
48 } | |
49 | |
50 LADSPAPluginFactory::~LADSPAPluginFactory() | |
51 { | |
52 for (std::set<RealTimePluginInstance *>::iterator i = m_instances.begin(); | |
53 i != m_instances.end(); ++i) { | |
54 (*i)->setFactory(0); | |
55 delete *i; | |
56 } | |
57 m_instances.clear(); | |
58 unloadUnusedLibraries(); | |
59 | |
60 #ifdef HAVE_LRDF | |
61 lrdf_cleanup(); | |
62 #endif // HAVE_LRDF | |
63 } | |
64 | |
65 const std::vector<QString> & | |
66 LADSPAPluginFactory::getPluginIdentifiers() const | |
67 { | |
68 return m_identifiers; | |
69 } | |
70 | |
71 void | |
72 LADSPAPluginFactory::enumeratePlugins(std::vector<QString> &list) | |
73 { | |
74 for (std::vector<QString>::iterator i = m_identifiers.begin(); | |
75 i != m_identifiers.end(); ++i) { | |
76 | |
77 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(*i); | |
78 | |
79 if (!descriptor) { | |
80 std::cerr << "WARNING: LADSPAPluginFactory::enumeratePlugins: couldn't get descriptor for identifier " << i->toStdString() << std::endl; | |
81 continue; | |
82 } | |
83 | |
84 list.push_back(*i); | |
85 list.push_back(descriptor->Name); | |
86 list.push_back(QString("%1").arg(descriptor->UniqueID)); | |
87 list.push_back(descriptor->Label); | |
88 list.push_back(descriptor->Maker); | |
89 list.push_back(descriptor->Copyright); | |
90 list.push_back("false"); // is synth | |
91 list.push_back("false"); // is grouped | |
92 | |
93 if (m_taxonomy.find(*i) != m_taxonomy.end() && m_taxonomy[*i] != "") { | |
94 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString()<< " found in taxonomy as " << m_taxonomy[descriptor->UniqueID] << std::endl; | |
95 list.push_back(m_taxonomy[*i]); | |
96 } else { | |
97 list.push_back(""); | |
98 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString() << " not found (despite having " << m_fallbackCategories.size() << " fallbacks)" << std::endl; | |
99 | |
100 } | |
101 | |
102 list.push_back(QString("%1").arg(descriptor->PortCount)); | |
103 | |
104 for (unsigned long p = 0; p < descriptor->PortCount; ++p) { | |
105 | |
106 int type = 0; | |
107 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) { | |
108 type |= PortType::Control; | |
109 } else { | |
110 type |= PortType::Audio; | |
111 } | |
112 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) { | |
113 type |= PortType::Input; | |
114 } else { | |
115 type |= PortType::Output; | |
116 } | |
117 | |
118 list.push_back(QString("%1").arg(p)); | |
119 list.push_back(descriptor->PortNames[p]); | |
120 list.push_back(QString("%1").arg(type)); | |
121 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p))); | |
122 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p))); | |
123 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p))); | |
124 list.push_back(QString("%1").arg(getPortDefault(descriptor, p))); | |
125 } | |
126 } | |
127 | |
128 unloadUnusedLibraries(); | |
129 } | |
130 | |
131 const RealTimePluginDescriptor * | |
132 LADSPAPluginFactory::getPluginDescriptor(QString identifier) const | |
133 { | |
134 std::map<QString, RealTimePluginDescriptor *>::const_iterator i = | |
135 m_rtDescriptors.find(identifier); | |
136 | |
137 if (i != m_rtDescriptors.end()) { | |
138 return i->second; | |
139 } | |
140 | |
141 return 0; | |
142 } | |
143 | |
144 float | |
145 LADSPAPluginFactory::getPortMinimum(const LADSPA_Descriptor *descriptor, int port) | |
146 { | |
147 LADSPA_PortRangeHintDescriptor d = | |
148 descriptor->PortRangeHints[port].HintDescriptor; | |
149 | |
150 float minimum = 0.0; | |
151 | |
152 if (LADSPA_IS_HINT_BOUNDED_BELOW(d)) { | |
153 float lb = descriptor->PortRangeHints[port].LowerBound; | |
154 minimum = lb; | |
155 } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { | |
156 float ub = descriptor->PortRangeHints[port].UpperBound; | |
157 minimum = min(0.0, ub - 1.0); | |
158 } | |
159 | |
160 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) { | |
161 minimum *= m_sampleRate; | |
162 } | |
163 | |
164 return minimum; | |
165 } | |
166 | |
167 float | |
168 LADSPAPluginFactory::getPortMaximum(const LADSPA_Descriptor *descriptor, int port) | |
169 { | |
170 LADSPA_PortRangeHintDescriptor d = | |
171 descriptor->PortRangeHints[port].HintDescriptor; | |
172 | |
173 float maximum = 1.0; | |
174 | |
175 if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { | |
176 float ub = descriptor->PortRangeHints[port].UpperBound; | |
177 maximum = ub; | |
178 } else { | |
179 float lb = descriptor->PortRangeHints[port].LowerBound; | |
180 maximum = lb + 1.0; | |
181 } | |
182 | |
183 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) { | |
184 maximum *= m_sampleRate; | |
185 } | |
186 | |
187 return maximum; | |
188 } | |
189 | |
190 float | |
191 LADSPAPluginFactory::getPortDefault(const LADSPA_Descriptor *descriptor, int port) | |
192 { | |
193 float minimum = getPortMinimum(descriptor, port); | |
194 float maximum = getPortMaximum(descriptor, port); | |
195 float deft; | |
196 | |
197 if (m_portDefaults.find(descriptor->UniqueID) != | |
198 m_portDefaults.end()) { | |
199 if (m_portDefaults[descriptor->UniqueID].find(port) != | |
200 m_portDefaults[descriptor->UniqueID].end()) { | |
201 | |
202 deft = m_portDefaults[descriptor->UniqueID][port]; | |
203 if (deft < minimum) deft = minimum; | |
204 if (deft > maximum) deft = maximum; | |
205 return deft; | |
206 } | |
207 } | |
208 | |
209 LADSPA_PortRangeHintDescriptor d = | |
210 descriptor->PortRangeHints[port].HintDescriptor; | |
211 | |
212 bool logarithmic = LADSPA_IS_HINT_LOGARITHMIC(d); | |
213 | |
214 if (!LADSPA_IS_HINT_HAS_DEFAULT(d)) { | |
215 | |
216 deft = minimum; | |
217 | |
218 } else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(d)) { | |
219 | |
220 deft = minimum; | |
221 | |
222 } else if (LADSPA_IS_HINT_DEFAULT_LOW(d)) { | |
223 | |
224 if (logarithmic) { | |
225 deft = powf(10, log10(minimum) * 0.75 + | |
226 log10(maximum) * 0.25); | |
227 } else { | |
228 deft = minimum * 0.75 + maximum * 0.25; | |
229 } | |
230 | |
231 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(d)) { | |
232 | |
233 if (logarithmic) { | |
234 deft = powf(10, log10(minimum) * 0.5 + | |
235 log10(maximum) * 0.5); | |
236 } else { | |
237 deft = minimum * 0.5 + maximum * 0.5; | |
238 } | |
239 | |
240 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(d)) { | |
241 | |
242 if (logarithmic) { | |
243 deft = powf(10, log10(minimum) * 0.25 + | |
244 log10(maximum) * 0.75); | |
245 } else { | |
246 deft = minimum * 0.25 + maximum * 0.75; | |
247 } | |
248 | |
249 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(d)) { | |
250 | |
251 deft = maximum; | |
252 | |
253 } else if (LADSPA_IS_HINT_DEFAULT_0(d)) { | |
254 | |
255 deft = 0.0; | |
256 | |
257 } else if (LADSPA_IS_HINT_DEFAULT_1(d)) { | |
258 | |
259 deft = 1.0; | |
260 | |
261 } else if (LADSPA_IS_HINT_DEFAULT_100(d)) { | |
262 | |
263 deft = 100.0; | |
264 | |
265 } else if (LADSPA_IS_HINT_DEFAULT_440(d)) { | |
266 | |
267 // deft = 440.0; | |
268 deft = Preferences::getInstance()->getTuningFrequency(); | |
269 | |
270 } else { | |
271 | |
272 deft = minimum; | |
273 } | |
274 | |
275 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) { | |
276 deft *= m_sampleRate; | |
277 } | |
278 | |
279 return deft; | |
280 } | |
281 | |
282 float | |
283 LADSPAPluginFactory::getPortQuantization(const LADSPA_Descriptor *descriptor, int port) | |
284 { | |
285 int displayHint = getPortDisplayHint(descriptor, port); | |
286 if (displayHint & PortHint::Toggled) { | |
287 return lrintf(getPortMaximum(descriptor, port)) - | |
288 lrintf(getPortMinimum(descriptor, port)); | |
289 } | |
290 if (displayHint & PortHint::Integer) { | |
291 return 1.0; | |
292 } | |
293 return 0.0; | |
294 } | |
295 | |
296 int | |
297 LADSPAPluginFactory::getPortDisplayHint(const LADSPA_Descriptor *descriptor, int port) | |
298 { | |
299 LADSPA_PortRangeHintDescriptor d = | |
300 descriptor->PortRangeHints[port].HintDescriptor; | |
301 int hint = PortHint::NoHint; | |
302 | |
303 if (LADSPA_IS_HINT_TOGGLED(d)) hint |= PortHint::Toggled; | |
304 if (LADSPA_IS_HINT_INTEGER(d)) hint |= PortHint::Integer; | |
305 if (LADSPA_IS_HINT_LOGARITHMIC(d)) hint |= PortHint::Logarithmic; | |
306 | |
307 return hint; | |
308 } | |
309 | |
310 | |
311 RealTimePluginInstance * | |
312 LADSPAPluginFactory::instantiatePlugin(QString identifier, | |
313 int instrument, | |
314 int position, | |
315 unsigned int sampleRate, | |
316 unsigned int blockSize, | |
317 unsigned int channels) | |
318 { | |
319 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(identifier); | |
320 | |
321 if (descriptor) { | |
322 | |
323 LADSPAPluginInstance *instance = | |
324 new LADSPAPluginInstance | |
325 (this, instrument, identifier, position, sampleRate, blockSize, channels, | |
326 descriptor); | |
327 | |
328 m_instances.insert(instance); | |
329 | |
330 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
331 std::cerr << "LADSPAPluginFactory::instantiatePlugin(" | |
332 << identifier.toStdString() << ": now have " << m_instances.size() << " instances" << std::endl; | |
333 #endif | |
334 | |
335 return instance; | |
336 } | |
337 | |
338 return 0; | |
339 } | |
340 | |
341 void | |
342 LADSPAPluginFactory::releasePlugin(RealTimePluginInstance *instance, | |
343 QString identifier) | |
344 { | |
345 if (m_instances.find(instance) == m_instances.end()) { | |
346 std::cerr << "WARNING: LADSPAPluginFactory::releasePlugin: Not one of mine!" | |
347 << std::endl; | |
348 return; | |
349 } | |
350 | |
351 QString type, soname, label; | |
352 PluginIdentifier::parseIdentifier(identifier, type, soname, label); | |
353 | |
354 m_instances.erase(instance); | |
355 | |
356 bool stillInUse = false; | |
357 | |
358 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin(); | |
359 ii != m_instances.end(); ++ii) { | |
360 QString itype, isoname, ilabel; | |
361 PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel); | |
362 if (isoname == soname) { | |
363 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
364 std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " is still in use for plugin " << ilabel.toStdString() << std::endl; | |
365 #endif | |
366 stillInUse = true; | |
367 break; | |
368 } | |
369 } | |
370 | |
371 if (!stillInUse) { | |
372 if (soname != PluginIdentifier::BUILTIN_PLUGIN_SONAME) { | |
373 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
374 std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " no longer in use, unloading" << std::endl; | |
375 #endif | |
376 unloadLibrary(soname); | |
377 } | |
378 } | |
379 | |
380 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
381 std::cerr << "LADSPAPluginFactory::releasePlugin(" | |
382 << identifier.toStdString() << ": now have " << m_instances.size() << " instances" << std::endl; | |
383 #endif | |
384 } | |
385 | |
386 const LADSPA_Descriptor * | |
387 LADSPAPluginFactory::getLADSPADescriptor(QString identifier) | |
388 { | |
389 QString type, soname, label; | |
390 PluginIdentifier::parseIdentifier(identifier, type, soname, label); | |
391 | |
392 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { | |
393 loadLibrary(soname); | |
394 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { | |
395 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: loadLibrary failed for " << soname.toStdString() << std::endl; | |
396 return 0; | |
397 } | |
398 } | |
399 | |
400 void *libraryHandle = m_libraryHandles[soname]; | |
401 | |
402 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function) | |
403 DLSYM(libraryHandle, "ladspa_descriptor"); | |
404 | |
405 if (!fn) { | |
406 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No descriptor function in library " << soname.toStdString() << std::endl; | |
407 return 0; | |
408 } | |
409 | |
410 const LADSPA_Descriptor *descriptor = 0; | |
411 | |
412 int index = 0; | |
413 while ((descriptor = fn(index))) { | |
414 if (descriptor->Label == label) return descriptor; | |
415 ++index; | |
416 } | |
417 | |
418 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No such plugin as " << label.toStdString() << " in library " << soname.toStdString() << std::endl; | |
419 | |
420 return 0; | |
421 } | |
422 | |
423 void | |
424 LADSPAPluginFactory::loadLibrary(QString soName) | |
425 { | |
426 void *libraryHandle = DLOPEN(soName, RTLD_NOW); | |
427 if (libraryHandle) { | |
428 m_libraryHandles[soName] = libraryHandle; | |
429 std::cerr << "LADSPAPluginFactory::loadLibrary: Loaded library \"" << soName.toStdString() << "\"" << std::endl; | |
430 return; | |
431 } | |
432 | |
433 if (QFileInfo(soName).exists()) { | |
434 DLERROR(); | |
435 std::cerr << "LADSPAPluginFactory::loadLibrary: Library \"" << soName.toStdString() << "\" exists, but failed to load it" << std::endl; | |
436 return; | |
437 } | |
438 | |
439 std::vector<QString> pathList = getPluginPath(); | |
440 | |
441 QString fileName = QFile(soName).fileName(); | |
442 QString base = QFileInfo(soName).baseName(); | |
443 | |
444 for (std::vector<QString>::iterator i = pathList.begin(); | |
445 i != pathList.end(); ++i) { | |
446 | |
447 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
448 std::cerr << "Looking at: " << (*i).toStdString() << std::endl; | |
449 #endif | |
450 | |
451 QDir dir(*i, PLUGIN_GLOB, | |
452 QDir::Name | QDir::IgnoreCase, | |
453 QDir::Files | QDir::Readable); | |
454 | |
455 if (QFileInfo(dir.filePath(fileName)).exists()) { | |
456 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
457 std::cerr << "Loading: " << fileName.toStdString() << std::endl; | |
458 #endif | |
459 libraryHandle = DLOPEN(dir.filePath(fileName), RTLD_NOW); | |
460 if (libraryHandle) { | |
461 m_libraryHandles[soName] = libraryHandle; | |
462 return; | |
463 } | |
464 } | |
465 | |
466 for (unsigned int j = 0; j < dir.count(); ++j) { | |
467 QString file = dir.filePath(dir[j]); | |
468 if (QFileInfo(file).baseName() == base) { | |
469 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY | |
470 std::cerr << "Loading: " << file.toStdString() << std::endl; | |
471 #endif | |
472 libraryHandle = DLOPEN(file, RTLD_NOW); | |
473 if (libraryHandle) { | |
474 m_libraryHandles[soName] = libraryHandle; | |
475 return; | |
476 } | |
477 } | |
478 } | |
479 } | |
480 | |
481 std::cerr << "LADSPAPluginFactory::loadLibrary: Failed to locate plugin library \"" << soName.toStdString() << "\"" << std::endl; | |
482 } | |
483 | |
484 void | |
485 LADSPAPluginFactory::unloadLibrary(QString soName) | |
486 { | |
487 LibraryHandleMap::iterator li = m_libraryHandles.find(soName); | |
488 if (li != m_libraryHandles.end()) { | |
489 // std::cerr << "unloading " << soname.toStdString() << std::endl; | |
490 DLCLOSE(m_libraryHandles[soName]); | |
491 m_libraryHandles.erase(li); | |
492 } | |
493 } | |
494 | |
495 void | |
496 LADSPAPluginFactory::unloadUnusedLibraries() | |
497 { | |
498 std::vector<QString> toUnload; | |
499 | |
500 for (LibraryHandleMap::iterator i = m_libraryHandles.begin(); | |
501 i != m_libraryHandles.end(); ++i) { | |
502 | |
503 bool stillInUse = false; | |
504 | |
505 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin(); | |
506 ii != m_instances.end(); ++ii) { | |
507 | |
508 QString itype, isoname, ilabel; | |
509 PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel); | |
510 if (isoname == i->first) { | |
511 stillInUse = true; | |
512 break; | |
513 } | |
514 } | |
515 | |
516 if (!stillInUse) toUnload.push_back(i->first); | |
517 } | |
518 | |
519 for (std::vector<QString>::iterator i = toUnload.begin(); | |
520 i != toUnload.end(); ++i) { | |
521 if (*i != PluginIdentifier::BUILTIN_PLUGIN_SONAME) { | |
522 unloadLibrary(*i); | |
523 } | |
524 } | |
525 } | |
526 | |
527 | |
528 // It is only later, after they've gone, | |
529 // I realize they have delivered a letter. | |
530 // It's a letter from my wife. "What are you doing | |
531 // there?" my wife asks. "Are you drinking?" | |
532 // I study the postmark for hours. Then it, too, begins to fade. | |
533 // I hope someday to forget all this. | |
534 | |
535 | |
536 std::vector<QString> | |
537 LADSPAPluginFactory::getPluginPath() | |
538 { | |
539 std::vector<QString> pathList; | |
540 std::string path; | |
541 | |
542 char *cpath = getenv("LADSPA_PATH"); | |
543 if (cpath) path = cpath; | |
544 | |
545 if (path == "") { | |
546 | |
547 path = DEFAULT_LADSPA_PATH; | |
548 | |
549 char *home = getenv("HOME"); | |
550 if (home) { | |
551 std::string::size_type f; | |
552 while ((f = path.find("$HOME")) != std::string::npos && | |
553 f < path.length()) { | |
554 path.replace(f, 5, home); | |
555 } | |
556 } | |
557 | |
558 #ifdef _WIN32 | |
559 char *pfiles = getenv("ProgramFiles"); | |
560 if (!pfiles) pfiles = "C:\\Program Files"; | |
561 { | |
562 std::string::size_type f; | |
563 while ((f = path.find("%ProgramFiles%")) != std::string::npos && | |
564 f < path.length()) { | |
565 path.replace(f, 14, pfiles); | |
566 } | |
567 } | |
568 #endif | |
569 } | |
570 | |
571 std::string::size_type index = 0, newindex = 0; | |
572 | |
573 while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) { | |
574 pathList.push_back(path.substr(index, newindex - index).c_str()); | |
575 index = newindex + 1; | |
576 } | |
577 | |
578 pathList.push_back(path.substr(index).c_str()); | |
579 | |
580 return pathList; | |
581 } | |
582 | |
583 | |
584 std::vector<QString> | |
585 LADSPAPluginFactory::getLRDFPath(QString &baseUri) | |
586 { | |
587 std::vector<QString> lrdfPaths; | |
588 | |
589 #ifdef HAVE_LRDF | |
590 std::vector<QString> pathList = getPluginPath(); | |
591 | |
592 lrdfPaths.push_back("/usr/local/share/ladspa/rdf"); | |
593 lrdfPaths.push_back("/usr/share/ladspa/rdf"); | |
594 | |
595 for (std::vector<QString>::iterator i = pathList.begin(); | |
596 i != pathList.end(); ++i) { | |
597 lrdfPaths.push_back(*i + "/rdf"); | |
598 } | |
599 | |
600 baseUri = LADSPA_BASE; | |
601 #endif | |
602 | |
603 return lrdfPaths; | |
604 } | |
605 | |
606 void | |
607 LADSPAPluginFactory::discoverPlugins() | |
608 { | |
609 std::vector<QString> pathList = getPluginPath(); | |
610 | |
611 // std::cerr << "LADSPAPluginFactory::discoverPlugins - " | |
612 // << "discovering plugins; path is "; | |
613 // for (std::vector<QString>::iterator i = pathList.begin(); | |
614 // i != pathList.end(); ++i) { | |
615 // std::cerr << "[" << i->toStdString() << "] "; | |
616 // } | |
617 // std::cerr << std::endl; | |
618 | |
619 #ifdef HAVE_LRDF | |
620 // read the description files | |
621 // | |
622 QString baseUri; | |
623 std::vector<QString> lrdfPaths = getLRDFPath(baseUri); | |
624 | |
625 bool haveSomething = false; | |
626 | |
627 for (size_t i = 0; i < lrdfPaths.size(); ++i) { | |
628 QDir dir(lrdfPaths[i], "*.rdf;*.rdfs"); | |
629 for (unsigned int j = 0; j < dir.count(); ++j) { | |
630 if (!lrdf_read_file(QString("file:" + lrdfPaths[i] + "/" + dir[j]).toStdString().c_str())) { | |
631 // std::cerr << "LADSPAPluginFactory: read RDF file " << (lrdfPaths[i] + "/" + dir[j]) << std::endl; | |
632 haveSomething = true; | |
633 } | |
634 } | |
635 } | |
636 | |
637 if (haveSomething) { | |
638 generateTaxonomy(baseUri + "Plugin", ""); | |
639 } | |
640 #endif // HAVE_LRDF | |
641 | |
642 generateFallbackCategories(); | |
643 | |
644 for (std::vector<QString>::iterator i = pathList.begin(); | |
645 i != pathList.end(); ++i) { | |
646 | |
647 QDir pluginDir(*i, PLUGIN_GLOB); | |
648 | |
649 for (unsigned int j = 0; j < pluginDir.count(); ++j) { | |
650 discoverPlugins(QString("%1/%2").arg(*i).arg(pluginDir[j])); | |
651 } | |
652 } | |
653 } | |
654 | |
655 void | |
656 LADSPAPluginFactory::discoverPlugins(QString soname) | |
657 { | |
658 void *libraryHandle = DLOPEN(soname, RTLD_LAZY); | |
659 | |
660 if (!libraryHandle) { | |
661 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: couldn't load plugin library " | |
662 << soname.toStdString() << " - " << DLERROR() << std::endl; | |
663 return; | |
664 } | |
665 | |
666 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function) | |
667 DLSYM(libraryHandle, "ladspa_descriptor"); | |
668 | |
669 if (!fn) { | |
670 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: No descriptor function in " << soname.toStdString() << std::endl; | |
671 return; | |
672 } | |
673 | |
674 const LADSPA_Descriptor *descriptor = 0; | |
675 | |
676 int index = 0; | |
677 while ((descriptor = fn(index))) { | |
678 | |
679 RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor; | |
680 rtd->name = descriptor->Name; | |
681 rtd->label = descriptor->Label; | |
682 rtd->maker = descriptor->Maker; | |
683 rtd->copyright = descriptor->Copyright; | |
684 rtd->category = ""; | |
685 rtd->isSynth = false; | |
686 rtd->parameterCount = 0; | |
687 rtd->audioInputPortCount = 0; | |
688 rtd->audioOutputPortCount = 0; | |
689 rtd->controlOutputPortCount = 0; | |
690 | |
691 QString identifier = PluginIdentifier::createIdentifier | |
692 ("ladspa", soname, descriptor->Label); | |
693 | |
694 #ifdef HAVE_LRDF | |
695 char *def_uri = 0; | |
696 lrdf_defaults *defs = 0; | |
697 | |
698 if (m_lrdfTaxonomy[descriptor->UniqueID] != "") { | |
699 m_taxonomy[identifier] = m_lrdfTaxonomy[descriptor->UniqueID]; | |
700 // std::cerr << "set id \"" << identifier.toStdString() << "\" to cat \"" << m_taxonomy[identifier].toStdString() << "\" from LRDF" << std::endl; | |
701 // std::cout << identifier.toStdString() << "::" << m_taxonomy[identifier].toStdString() << std::endl; | |
702 } | |
703 | |
704 QString category = m_taxonomy[identifier]; | |
705 | |
706 if (category == "" && descriptor->Name != 0) { | |
707 std::string name = descriptor->Name; | |
708 if (name.length() > 4 && | |
709 name.substr(name.length() - 4) == " VST") { | |
710 category = "VST effects"; | |
711 m_taxonomy[identifier] = category; | |
712 } | |
713 } | |
714 | |
715 rtd->category = category.toStdString(); | |
716 | |
717 // std::cerr << "Plugin id is " << descriptor->UniqueID | |
718 // << ", category is \"" << (category ? category : QString("(none)")) | |
719 // << "\", name is " << descriptor->Name | |
720 // << ", label is " << descriptor->Label | |
721 // << std::endl; | |
722 | |
723 def_uri = lrdf_get_default_uri(descriptor->UniqueID); | |
724 if (def_uri) { | |
725 defs = lrdf_get_setting_values(def_uri); | |
726 } | |
727 | |
728 unsigned int controlPortNumber = 1; | |
729 | |
730 for (unsigned long i = 0; i < descriptor->PortCount; i++) { | |
731 | |
732 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) { | |
733 | |
734 if (def_uri && defs) { | |
735 | |
736 for (unsigned int j = 0; j < defs->count; j++) { | |
737 if (defs->items[j].pid == controlPortNumber) { | |
738 // std::cerr << "Default for this port (" << defs->items[j].pid << ", " << defs->items[j].label << ") is " << defs->items[j].value << "; applying this to port number " << i << " with name " << descriptor->PortNames[i] << std::endl; | |
739 m_portDefaults[descriptor->UniqueID][i] = | |
740 defs->items[j].value; | |
741 } | |
742 } | |
743 } | |
744 | |
745 ++controlPortNumber; | |
746 } | |
747 } | |
748 #endif // HAVE_LRDF | |
749 | |
750 for (unsigned long i = 0; i < descriptor->PortCount; i++) { | |
751 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) { | |
752 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { | |
753 ++rtd->parameterCount; | |
754 } else { | |
755 if (strcmp(descriptor->PortNames[i], "latency") && | |
756 strcmp(descriptor->PortNames[i], "_latency")) { | |
757 ++rtd->controlOutputPortCount; | |
758 rtd->controlOutputPortNames.push_back | |
759 (descriptor->PortNames[i]); | |
760 } | |
761 } | |
762 } else { | |
763 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { | |
764 ++rtd->audioInputPortCount; | |
765 } else if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[i])) { | |
766 ++rtd->audioOutputPortCount; | |
767 } | |
768 } | |
769 } | |
770 | |
771 m_identifiers.push_back(identifier); | |
772 | |
773 m_rtDescriptors[identifier] = rtd; | |
774 | |
775 ++index; | |
776 } | |
777 | |
778 if (DLCLOSE(libraryHandle) != 0) { | |
779 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins - can't unload " << libraryHandle << std::endl; | |
780 return; | |
781 } | |
782 } | |
783 | |
784 void | |
785 LADSPAPluginFactory::generateFallbackCategories() | |
786 { | |
787 std::vector<QString> pluginPath = getPluginPath(); | |
788 std::vector<QString> path; | |
789 | |
790 for (size_t i = 0; i < pluginPath.size(); ++i) { | |
791 if (pluginPath[i].contains("/lib/")) { | |
792 QString p(pluginPath[i]); | |
793 path.push_back(p); | |
794 p.replace("/lib/", "/share/"); | |
795 path.push_back(p); | |
796 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << p.toStdString() << std::endl; | |
797 } | |
798 path.push_back(pluginPath[i]); | |
799 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << pluginPath[i].toStdString() << std::endl; | |
800 } | |
801 | |
802 for (size_t i = 0; i < path.size(); ++i) { | |
803 | |
804 QDir dir(path[i], "*.cat"); | |
805 | |
806 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl; | |
807 for (unsigned int j = 0; j < dir.count(); ++j) { | |
808 | |
809 QFile file(path[i] + "/" + dir[j]); | |
810 | |
811 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl; | |
812 | |
813 if (file.open(QIODevice::ReadOnly)) { | |
814 // std::cerr << "...opened" << std::endl; | |
815 QTextStream stream(&file); | |
816 QString line; | |
817 | |
818 while (!stream.atEnd()) { | |
819 line = stream.readLine(); | |
820 // std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl; | |
821 QString id = PluginIdentifier::canonicalise | |
822 (line.section("::", 0, 0)); | |
823 QString cat = line.section("::", 1, 1); | |
824 m_taxonomy[id] = cat; | |
825 // std::cerr << "set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl; | |
826 } | |
827 } | |
828 } | |
829 } | |
830 } | |
831 | |
832 void | |
833 LADSPAPluginFactory::generateTaxonomy(QString uri, QString base) | |
834 { | |
835 #ifdef HAVE_LRDF | |
836 lrdf_uris *uris = lrdf_get_instances(uri.toStdString().c_str()); | |
837 | |
838 if (uris != NULL) { | |
839 for (unsigned int i = 0; i < uris->count; ++i) { | |
840 m_lrdfTaxonomy[lrdf_get_uid(uris->items[i])] = base; | |
841 } | |
842 lrdf_free_uris(uris); | |
843 } | |
844 | |
845 uris = lrdf_get_subclasses(uri.toStdString().c_str()); | |
846 | |
847 if (uris != NULL) { | |
848 for (unsigned int i = 0; i < uris->count; ++i) { | |
849 char *label = lrdf_get_label(uris->items[i]); | |
850 generateTaxonomy(uris->items[i], | |
851 base + (base.length() > 0 ? " > " : "") + label); | |
852 } | |
853 lrdf_free_uris(uris); | |
854 } | |
855 #endif | |
856 } | |
857 | |
858 QString | |
859 LADSPAPluginFactory::getPluginCategory(QString identifier) | |
860 { | |
861 return m_taxonomy[identifier]; | |
862 } | |
863 |