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