comparison plugin/LADSPAPluginFactory.cpp @ 0:da6937383da8

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children d86891498eef
comparison
equal deleted inserted replaced
-1:000000000000 0:da6937383da8
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 A waveform viewer and audio annotation editor.
5 Chris Cannam, Queen Mary University of London, 2005
6
7 This is experimental software. Not for distribution.
8 */
9
10 /*
11 This is a modified version of a source file from the
12 Rosegarden MIDI and audio sequencer and notation editor.
13 This file copyright 2000-2005 Chris Cannam and Richard Bown.
14 */
15
16 #include "LADSPAPluginFactory.h"
17 #include <iostream>
18
19 #include <QDir>
20 #include <QFile>
21 #include <QTextStream>
22
23 #include <cmath>
24
25 #include "LADSPAPluginInstance.h"
26 #include "PluginIdentifier.h"
27
28 #include "base/System.h"
29
30 #ifdef HAVE_LIBLRDF
31 #include "lrdf.h"
32 #endif // HAVE_LIBLRDF
33
34
35 LADSPAPluginFactory::LADSPAPluginFactory()
36 {
37 }
38
39 LADSPAPluginFactory::~LADSPAPluginFactory()
40 {
41 for (std::set<RealTimePluginInstance *>::iterator i = m_instances.begin();
42 i != m_instances.end(); ++i) {
43 (*i)->setFactory(0);
44 delete *i;
45 }
46 m_instances.clear();
47 unloadUnusedLibraries();
48 }
49
50 const std::vector<QString> &
51 LADSPAPluginFactory::getPluginIdentifiers() const
52 {
53 return m_identifiers;
54 }
55
56 void
57 LADSPAPluginFactory::enumeratePlugins(std::vector<QString> &list)
58 {
59 for (std::vector<QString>::iterator i = m_identifiers.begin();
60 i != m_identifiers.end(); ++i) {
61
62 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(*i);
63
64 if (!descriptor) {
65 std::cerr << "WARNING: LADSPAPluginFactory::enumeratePlugins: couldn't get descriptor for identifier " << i->toStdString() << std::endl;
66 continue;
67 }
68
69 list.push_back(*i);
70 list.push_back(descriptor->Name);
71 list.push_back(QString("%1").arg(descriptor->UniqueID));
72 list.push_back(descriptor->Label);
73 list.push_back(descriptor->Maker);
74 list.push_back(descriptor->Copyright);
75 list.push_back("false"); // is synth
76 list.push_back("false"); // is grouped
77
78 if (m_taxonomy.find(descriptor->UniqueID) != m_taxonomy.end() &&
79 m_taxonomy[descriptor->UniqueID] != "") {
80 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString()<< " found in taxonomy as " << m_taxonomy[descriptor->UniqueID] << std::endl;
81 list.push_back(m_taxonomy[descriptor->UniqueID]);
82
83 } else if (m_fallbackCategories.find(*i) !=
84 m_fallbackCategories.end()) {
85 list.push_back(m_fallbackCategories[*i]);
86 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString() <<" found in fallbacks as " << m_fallbackCategories[*i] << std::endl;
87
88 } else {
89 list.push_back("");
90 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString() << " not found (despite having " << m_fallbackCategories.size() << " fallbacks)" << std::endl;
91
92 }
93
94 list.push_back(QString("%1").arg(descriptor->PortCount));
95
96 for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
97
98 int type = 0;
99 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
100 type |= PortType::Control;
101 } else {
102 type |= PortType::Audio;
103 }
104 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
105 type |= PortType::Input;
106 } else {
107 type |= PortType::Output;
108 }
109
110 list.push_back(QString("%1").arg(p));
111 list.push_back(descriptor->PortNames[p]);
112 list.push_back(QString("%1").arg(type));
113 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
114 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
115 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
116 list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
117 }
118 }
119
120 unloadUnusedLibraries();
121 }
122
123 float
124 LADSPAPluginFactory::getPortMinimum(const LADSPA_Descriptor *descriptor, int port)
125 {
126 LADSPA_PortRangeHintDescriptor d =
127 descriptor->PortRangeHints[port].HintDescriptor;
128
129 float minimum = 0.0;
130
131 if (LADSPA_IS_HINT_BOUNDED_BELOW(d)) {
132 float lb = descriptor->PortRangeHints[port].LowerBound;
133 minimum = lb;
134 } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
135 float ub = descriptor->PortRangeHints[port].UpperBound;
136 minimum = std::min(0.0, ub - 1.0);
137 }
138
139 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
140 minimum *= m_sampleRate;
141 }
142
143 return minimum;
144 }
145
146 float
147 LADSPAPluginFactory::getPortMaximum(const LADSPA_Descriptor *descriptor, int port)
148 {
149 LADSPA_PortRangeHintDescriptor d =
150 descriptor->PortRangeHints[port].HintDescriptor;
151
152 float maximum = 1.0;
153
154 if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
155 float ub = descriptor->PortRangeHints[port].UpperBound;
156 maximum = ub;
157 } else {
158 float lb = descriptor->PortRangeHints[port].LowerBound;
159 maximum = lb + 1.0;
160 }
161
162 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
163 maximum *= m_sampleRate;
164 }
165
166 return maximum;
167 }
168
169 float
170 LADSPAPluginFactory::getPortDefault(const LADSPA_Descriptor *descriptor, int port)
171 {
172 float minimum = getPortMinimum(descriptor, port);
173 float maximum = getPortMaximum(descriptor, port);
174 float deft;
175
176 if (m_portDefaults.find(descriptor->UniqueID) !=
177 m_portDefaults.end()) {
178 if (m_portDefaults[descriptor->UniqueID].find(port) !=
179 m_portDefaults[descriptor->UniqueID].end()) {
180
181 deft = m_portDefaults[descriptor->UniqueID][port];
182 if (deft < minimum) deft = minimum;
183 if (deft > maximum) deft = maximum;
184 return deft;
185 }
186 }
187
188 LADSPA_PortRangeHintDescriptor d =
189 descriptor->PortRangeHints[port].HintDescriptor;
190
191 bool logarithmic = LADSPA_IS_HINT_LOGARITHMIC(d);
192
193 if (!LADSPA_IS_HINT_HAS_DEFAULT(d)) {
194
195 deft = minimum;
196
197 } else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(d)) {
198
199 deft = minimum;
200
201 } else if (LADSPA_IS_HINT_DEFAULT_LOW(d)) {
202
203 if (logarithmic) {
204 deft = powf(10, log10(minimum) * 0.75 +
205 log10(maximum) * 0.25);
206 } else {
207 deft = minimum * 0.75 + maximum * 0.25;
208 }
209
210 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(d)) {
211
212 if (logarithmic) {
213 deft = powf(10, log10(minimum) * 0.5 +
214 log10(maximum) * 0.5);
215 } else {
216 deft = minimum * 0.5 + maximum * 0.5;
217 }
218
219 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(d)) {
220
221 if (logarithmic) {
222 deft = powf(10, log10(minimum) * 0.25 +
223 log10(maximum) * 0.75);
224 } else {
225 deft = minimum * 0.25 + maximum * 0.75;
226 }
227
228 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(d)) {
229
230 deft = maximum;
231
232 } else if (LADSPA_IS_HINT_DEFAULT_0(d)) {
233
234 deft = 0.0;
235
236 } else if (LADSPA_IS_HINT_DEFAULT_1(d)) {
237
238 deft = 1.0;
239
240 } else if (LADSPA_IS_HINT_DEFAULT_100(d)) {
241
242 deft = 100.0;
243
244 } else if (LADSPA_IS_HINT_DEFAULT_440(d)) {
245
246 deft = 440.0;
247
248 } else {
249
250 deft = minimum;
251 }
252
253 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
254 deft *= m_sampleRate;
255 }
256
257 return deft;
258 }
259
260 int
261 LADSPAPluginFactory::getPortDisplayHint(const LADSPA_Descriptor *descriptor, int port)
262 {
263 LADSPA_PortRangeHintDescriptor d =
264 descriptor->PortRangeHints[port].HintDescriptor;
265 int hint = PortHint::NoHint;
266
267 if (LADSPA_IS_HINT_TOGGLED(d)) hint |= PortHint::Toggled;
268 if (LADSPA_IS_HINT_INTEGER(d)) hint |= PortHint::Integer;
269 if (LADSPA_IS_HINT_LOGARITHMIC(d)) hint |= PortHint::Logarithmic;
270
271 return hint;
272 }
273
274
275 RealTimePluginInstance *
276 LADSPAPluginFactory::instantiatePlugin(QString identifier,
277 int instrument,
278 int position,
279 unsigned int sampleRate,
280 unsigned int blockSize,
281 unsigned int channels)
282 {
283 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(identifier);
284
285 if (descriptor) {
286
287 LADSPAPluginInstance *instance =
288 new LADSPAPluginInstance
289 (this, instrument, identifier, position, sampleRate, blockSize, channels,
290 descriptor);
291
292 m_instances.insert(instance);
293
294 return instance;
295 }
296
297 return 0;
298 }
299
300 void
301 LADSPAPluginFactory::releasePlugin(RealTimePluginInstance *instance,
302 QString identifier)
303 {
304 if (m_instances.find(instance) == m_instances.end()) {
305 std::cerr << "WARNING: LADSPAPluginFactory::releasePlugin: Not one of mine!"
306 << std::endl;
307 return;
308 }
309
310 QString type, soname, label;
311 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
312
313 m_instances.erase(instance);
314
315 bool stillInUse = false;
316
317 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
318 ii != m_instances.end(); ++ii) {
319 QString itype, isoname, ilabel;
320 PluginIdentifier::parseIdentifier((*ii)->getIdentifier(), itype, isoname, ilabel);
321 if (isoname == soname) {
322 // std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " is still in use for plugin " << ilabel << std::endl;
323 stillInUse = true;
324 break;
325 }
326 }
327
328 if (!stillInUse) {
329 // std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " no longer in use, unloading" << std::endl;
330 unloadLibrary(soname);
331 }
332 }
333
334 const LADSPA_Descriptor *
335 LADSPAPluginFactory::getLADSPADescriptor(QString identifier)
336 {
337 QString type, soname, label;
338 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
339
340 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
341 loadLibrary(soname);
342 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
343 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: loadLibrary failed for " << soname.toStdString() << std::endl;
344 return 0;
345 }
346 }
347
348 void *libraryHandle = m_libraryHandles[soname];
349
350 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
351 DLSYM(libraryHandle, "ladspa_descriptor");
352
353 if (!fn) {
354 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No descriptor function in library " << soname.toStdString() << std::endl;
355 return 0;
356 }
357
358 const LADSPA_Descriptor *descriptor = 0;
359
360 int index = 0;
361 while ((descriptor = fn(index))) {
362 if (descriptor->Label == label) return descriptor;
363 ++index;
364 }
365
366 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No such plugin as " << label.toStdString() << " in library " << soname.toStdString() << std::endl;
367
368 return 0;
369 }
370
371 void
372 LADSPAPluginFactory::loadLibrary(QString soName)
373 {
374 void *libraryHandle = DLOPEN(soName, RTLD_NOW);
375 if (libraryHandle) m_libraryHandles[soName] = libraryHandle;
376 }
377
378 void
379 LADSPAPluginFactory::unloadLibrary(QString soName)
380 {
381 LibraryHandleMap::iterator li = m_libraryHandles.find(soName);
382 if (li != m_libraryHandles.end()) {
383 // std::cerr << "unloading " << soname.toStdString() << std::endl;
384 DLCLOSE(m_libraryHandles[soName]);
385 m_libraryHandles.erase(li);
386 }
387 }
388
389 void
390 LADSPAPluginFactory::unloadUnusedLibraries()
391 {
392 std::vector<QString> toUnload;
393
394 for (LibraryHandleMap::iterator i = m_libraryHandles.begin();
395 i != m_libraryHandles.end(); ++i) {
396
397 bool stillInUse = false;
398
399 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
400 ii != m_instances.end(); ++ii) {
401
402 QString itype, isoname, ilabel;
403 PluginIdentifier::parseIdentifier((*ii)->getIdentifier(), itype, isoname, ilabel);
404 if (isoname == i->first) {
405 stillInUse = true;
406 break;
407 }
408 }
409
410 if (!stillInUse) toUnload.push_back(i->first);
411 }
412
413 for (std::vector<QString>::iterator i = toUnload.begin();
414 i != toUnload.end(); ++i) {
415 unloadLibrary(*i);
416 }
417 }
418
419
420 // It is only later, after they've gone,
421 // I realize they have delivered a letter.
422 // It's a letter from my wife. "What are you doing
423 // there?" my wife asks. "Are you drinking?"
424 // I study the postmark for hours. Then it, too, begins to fade.
425 // I hope someday to forget all this.
426
427
428 std::vector<QString>
429 LADSPAPluginFactory::getPluginPath()
430 {
431 std::vector<QString> pathList;
432 std::string path;
433
434 char *cpath = getenv("LADSPA_PATH");
435 if (cpath) path = cpath;
436
437 if (path == "") {
438 path = "/usr/local/lib/ladspa:/usr/lib/ladspa";
439 char *home = getenv("HOME");
440 if (home) path = std::string(home) + "/.ladspa:" + path;
441 }
442
443 std::string::size_type index = 0, newindex = 0;
444
445 while ((newindex = path.find(':', index)) < path.size()) {
446 pathList.push_back(path.substr(index, newindex - index).c_str());
447 index = newindex + 1;
448 }
449
450 pathList.push_back(path.substr(index).c_str());
451
452 return pathList;
453 }
454
455
456 #ifdef HAVE_LIBLRDF
457 std::vector<QString>
458 LADSPAPluginFactory::getLRDFPath(QString &baseUri)
459 {
460 std::vector<QString> pathList = getPluginPath();
461 std::vector<QString> lrdfPaths;
462
463 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
464 lrdfPaths.push_back("/usr/share/ladspa/rdf");
465
466 for (std::vector<QString>::iterator i = pathList.begin();
467 i != pathList.end(); ++i) {
468 lrdfPaths.push_back(*i + "/rdf");
469 }
470
471 baseUri = LADSPA_BASE;
472 return lrdfPaths;
473 }
474 #endif
475
476 void
477 LADSPAPluginFactory::discoverPlugins()
478 {
479 std::vector<QString> pathList = getPluginPath();
480
481 // std::cerr << "LADSPAPluginFactory::discoverPlugins - "
482 // << "discovering plugins; path is ";
483 for (std::vector<QString>::iterator i = pathList.begin();
484 i != pathList.end(); ++i) {
485 std::cerr << "[" << i->toStdString() << "] ";
486 }
487 std::cerr << std::endl;
488
489 #ifdef HAVE_LIBLRDF
490 // Initialise liblrdf and read the description files
491 //
492 lrdf_init();
493
494 QString baseUri;
495 std::vector<QString> lrdfPaths = getLRDFPath(baseUri);
496
497 bool haveSomething = false;
498
499 for (size_t i = 0; i < lrdfPaths.size(); ++i) {
500 QDir dir(lrdfPaths[i], "*.rdf;*.rdfs");
501 for (unsigned int j = 0; j < dir.count(); ++j) {
502 if (!lrdf_read_file(QString("file:" + lrdfPaths[i] + "/" + dir[j]).toStdString().c_str())) {
503 // std::cerr << "LADSPAPluginFactory: read RDF file " << (lrdfPaths[i] + "/" + dir[j]) << std::endl;
504 haveSomething = true;
505 }
506 }
507 }
508
509 if (haveSomething) {
510 generateTaxonomy(baseUri + "Plugin", "");
511 }
512 #endif // HAVE_LIBLRDF
513
514 generateFallbackCategories();
515
516 for (std::vector<QString>::iterator i = pathList.begin();
517 i != pathList.end(); ++i) {
518
519 QDir pluginDir(*i, PLUGIN_GLOB);
520
521 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
522 discoverPlugins(QString("%1/%2").arg(*i).arg(pluginDir[j]));
523 }
524 }
525
526 #ifdef HAVE_LIBLRDF
527 // Cleanup after the RDF library
528 //
529 lrdf_cleanup();
530 #endif // HAVE_LIBLRDF
531 }
532
533 void
534 LADSPAPluginFactory::discoverPlugins(QString soname)
535 {
536 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
537
538 if (!libraryHandle) {
539 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: couldn't load plugin library "
540 << soname.toStdString() << " - " << DLERROR() << std::endl;
541 return;
542 }
543
544 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
545 DLSYM(libraryHandle, "ladspa_descriptor");
546
547 if (!fn) {
548 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: No descriptor function in " << soname.toStdString() << std::endl;
549 return;
550 }
551
552 const LADSPA_Descriptor *descriptor = 0;
553
554 int index = 0;
555 while ((descriptor = fn(index))) {
556
557 #ifdef HAVE_LIBLRDF
558 char *def_uri = 0;
559 lrdf_defaults *defs = 0;
560
561 QString category = m_taxonomy[descriptor->UniqueID];
562
563 if (category == "" && descriptor->Name != 0) {
564 std::string name = descriptor->Name;
565 if (name.length() > 4 &&
566 name.substr(name.length() - 4) == " VST") {
567 category = "VST effects";
568 m_taxonomy[descriptor->UniqueID] = category;
569 }
570 }
571
572 // std::cerr << "Plugin id is " << descriptor->UniqueID
573 // << ", category is \"" << (category ? category : QString("(none)"))
574 // << "\", name is " << descriptor->Name
575 // << ", label is " << descriptor->Label
576 // << std::endl;
577
578 def_uri = lrdf_get_default_uri(descriptor->UniqueID);
579 if (def_uri) {
580 defs = lrdf_get_setting_values(def_uri);
581 }
582
583 int controlPortNumber = 1;
584
585 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
586
587 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
588
589 if (def_uri && defs) {
590
591 for (int j = 0; j < defs->count; j++) {
592 if (defs->items[j].pid == controlPortNumber) {
593 // 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;
594 m_portDefaults[descriptor->UniqueID][i] =
595 defs->items[j].value;
596 }
597 }
598 }
599
600 ++controlPortNumber;
601 }
602 }
603 #endif // HAVE_LIBLRDF
604
605 QString identifier = PluginIdentifier::createIdentifier
606 ("ladspa", soname, descriptor->Label);
607 m_identifiers.push_back(identifier);
608
609 ++index;
610 }
611
612 if (DLCLOSE(libraryHandle) != 0) {
613 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins - can't unload " << libraryHandle << std::endl;
614 return;
615 }
616 }
617
618 void
619 LADSPAPluginFactory::generateFallbackCategories()
620 {
621 std::vector<QString> pluginPath = getPluginPath();
622 std::vector<QString> path;
623
624 for (size_t i = 0; i < pluginPath.size(); ++i) {
625 if (pluginPath[i].contains("/lib/")) {
626 QString p(pluginPath[i]);
627 p.replace("/lib/", "/share/");
628 path.push_back(p);
629 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << p << std::endl;
630 }
631 path.push_back(pluginPath[i]);
632 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << pluginPath[i] << std::endl;
633 }
634
635 for (size_t i = 0; i < path.size(); ++i) {
636
637 QDir dir(path[i], "*.cat");
638
639 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << std::endl;
640 for (unsigned int j = 0; j < dir.count(); ++j) {
641
642 QFile file(path[i] + "/" + dir[j]);
643
644 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i] + "/" + dir[j]) << std::endl;
645
646 if (file.open(QIODevice::ReadOnly)) {
647 // std::cerr << "...opened" << std::endl;
648 QTextStream stream(&file);
649 QString line;
650
651 while (!stream.atEnd()) {
652 line = stream.readLine();
653 // std::cerr << "line is: \"" << line << "\"" << std::endl;
654 QString id = line.section("::", 0, 0);
655 QString cat = line.section("::", 1, 1);
656 m_fallbackCategories[id] = cat;
657 // std::cerr << "set id \"" << id << "\" to cat \"" << cat << "\"" << std::endl;
658 }
659 }
660 }
661 }
662 }
663
664 void
665 LADSPAPluginFactory::generateTaxonomy(QString uri, QString base)
666 {
667 #ifdef HAVE_LIBLRDF
668 lrdf_uris *uris = lrdf_get_instances(uri.toStdString().c_str());
669
670 if (uris != NULL) {
671 for (int i = 0; i < uris->count; ++i) {
672 m_taxonomy[lrdf_get_uid(uris->items[i])] = base;
673 }
674 lrdf_free_uris(uris);
675 }
676
677 uris = lrdf_get_subclasses(uri.toStdString().c_str());
678
679 if (uris != NULL) {
680 for (int i = 0; i < uris->count; ++i) {
681 char *label = lrdf_get_label(uris->items[i]);
682 generateTaxonomy(uris->items[i],
683 base + (base.length() > 0 ? " > " : "") + label);
684 }
685 lrdf_free_uris(uris);
686 }
687 #endif
688 }
689
690