DSSIPluginFactory.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.
19 */
20 
21 #include "DSSIPluginFactory.h"
22 #include <iostream>
23 
24 #include <QString>
25 
26 #include "DSSIPluginInstance.h"
27 #include "PluginIdentifier.h"
28 
29 #include <cstdlib>
30 
31 #include "base/Profiler.h"
32 
35 
36 #include "system/System.h"
37 
38 #ifdef HAVE_LRDF
39 #include "lrdf.h"
40 #endif // HAVE_LRDF
41 
42 using std::string;
43 
46 {
47  m_hostDescriptor.DSSI_API_Version = 2;
48  m_hostDescriptor.request_transport_information = nullptr;
52 }
53 
55 {
56  // nothing else to do here either
57 }
58 
59 void
60 DSSIPluginFactory::enumeratePlugins(std::vector<QString> &list)
61 {
62  Profiler profiler("DSSIPluginFactory::enumeratePlugins");
63 
64  for (std::vector<QString>::iterator i = m_identifiers.begin();
65  i != m_identifiers.end(); ++i) {
66 
67  const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i);
68  if (!ddesc) continue;
69 
70  const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin;
71  if (!descriptor) continue;
72 
73 // SVDEBUG << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << endl;
74 
75  list.push_back(*i);
76  list.push_back(descriptor->Name);
77  list.push_back(QString("%1").arg(descriptor->UniqueID));
78  list.push_back(descriptor->Label);
79  list.push_back(descriptor->Maker);
80  list.push_back(descriptor->Copyright);
81  list.push_back((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false");
82  list.push_back(ddesc->run_multiple_synths ? "true" : "false");
83  list.push_back(m_taxonomy[*i]);
84  list.push_back(QString("%1").arg(descriptor->PortCount));
85 
86  for (int p = 0; p < (int)descriptor->PortCount; ++p) {
87 
88  int type = 0;
89  if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
90  type |= PortType::Control;
91  } else {
92  type |= PortType::Audio;
93  }
94  if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
95  type |= PortType::Input;
96  } else {
97  type |= PortType::Output;
98  }
99 
100  list.push_back(QString("%1").arg(p));
101  list.push_back(descriptor->PortNames[p]);
102  list.push_back(QString("%1").arg(type));
103  list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
104  list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
105  list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
106  list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
107  }
108  }
109 
111 }
112 
113 std::shared_ptr<RealTimePluginInstance>
115  int instrument,
116  int position,
117  sv_samplerate_t sampleRate,
118  int blockSize,
119  int channels)
120 {
121  Profiler profiler("DSSIPluginFactory::instantiatePlugin");
122 
123  const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier);
124 
125  if (descriptor) {
126 
127  auto instance =
128  std::shared_ptr<RealTimePluginInstance>
129  (new DSSIPluginInstance
130  (this, instrument, identifier, position,
131  sampleRate, blockSize, channels, descriptor));
132 
133  m_instances.insert(instance);
134 
135  return instance;
136  }
137 
138  return nullptr;
139 }
140 
141 const DSSI_Descriptor *
143 {
144  QString type, soname, label;
145  PluginIdentifier::parseIdentifier(identifier, type, soname, label);
146 
148  if (label == "sample_player") {
149  const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0);
150  if (descriptor) {
151  descriptor->receive_host_descriptor(&m_hostDescriptor);
152  }
153  return descriptor;
154  } else {
155  return nullptr;
156  }
157  }
158 
159  bool firstInLibrary = false;
160 
161  if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
162  loadLibrary(soname);
163  if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
164  SVCERR << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname << endl;
165  return nullptr;
166  }
167  firstInLibrary = true;
168  }
169 
170  void *libraryHandle = m_libraryHandles[soname];
171 
172  DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
173  DLSYM(libraryHandle, "dssi_descriptor");
174 
175  if (!fn) {
176  SVCERR << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname << endl;
177  return nullptr;
178  }
179 
180  const DSSI_Descriptor *descriptor = nullptr;
181 
182  int index = 0;
183  while ((descriptor = fn(index))) {
184  if (descriptor->LADSPA_Plugin->Label == label) {
185  if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) {
186  descriptor->receive_host_descriptor(&m_hostDescriptor);
187  }
188  return descriptor;
189  }
190  ++index;
191  }
192 
193  SVCERR << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label << " in library " << soname << endl;
194 
195  return nullptr;
196 }
197 
198 const LADSPA_Descriptor *
200 {
201  const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier);
202  if (dssiDescriptor) return dssiDescriptor->LADSPA_Plugin;
203  else return nullptr;
204 }
205 
206 
207 std::vector<QString>
209 {
210  std::vector<QString> pathList;
211  string path;
212 
213  (void)getEnvUtf8("DSSI_PATH", path);
214 
215  if (path == "") {
216 
217  path = DEFAULT_DSSI_PATH;
218 
219  string home;
220  if (getEnvUtf8("HOME", home)) {
221  string::size_type f;
222  while ((f = path.find("$HOME")) != string::npos &&
223  f < path.length()) {
224  path.replace(f, 5, home);
225  }
226  }
227 
228 #ifdef _WIN32
229  string pfiles;
230  if (!getEnvUtf8("ProgramFiles", pfiles)) {
231  pfiles = "C:\\Program Files";
232  }
233 
234  string::size_type f;
235  while ((f = path.find("%ProgramFiles%")) != string::npos &&
236  f < path.length()) {
237  path.replace(f, 14, pfiles);
238  }
239 #endif
240  }
241 
242  string::size_type index = 0, newindex = 0;
243 
244  while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) {
245  pathList.push_back(path.substr(index, newindex - index).c_str());
246  index = newindex + 1;
247  }
248 
249  pathList.push_back(path.substr(index).c_str());
250 
251  return pathList;
252 }
253 
254 
255 std::vector<QString>
257 {
258  std::vector<QString> lrdfPaths;
259 
260 #ifdef HAVE_LRDF
261  std::vector<QString> pathList = getPluginPath();
262 
263  lrdfPaths.push_back("/usr/local/share/dssi/rdf");
264  lrdfPaths.push_back("/usr/share/dssi/rdf");
265 
266  lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
267  lrdfPaths.push_back("/usr/share/ladspa/rdf");
268 
269  for (std::vector<QString>::iterator i = pathList.begin();
270  i != pathList.end(); ++i) {
271  lrdfPaths.push_back(*i + "/rdf");
272  }
273 
274 #ifdef DSSI_BASE
275  baseUri = DSSI_BASE;
276 #else
277  baseUri = "http://dssi.sourceforge.net/ontology#";
278 #endif
279 #else
280  // avoid unused parameter
281  baseUri = "";
282 #endif
283 
284  return lrdfPaths;
285 }
286 
287 
288 void
290 {
291  Profiler profiler("DSSIPluginFactory::discoverPlugins");
292 
293  // Note that soname is expected to be a full path at this point,
294  // of a file that is known to exist
295 
296  void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
297 
298  if (!libraryHandle) {
299  SVCERR << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library "
300  << soname << " - " << DLERROR() << endl;
301  return;
302  }
303 
304  DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
305  DLSYM(libraryHandle, "dssi_descriptor");
306 
307  if (!fn) {
308  SVCERR << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname << endl;
309  return;
310  }
311 
312  const DSSI_Descriptor *descriptor = nullptr;
313 
314  int index = 0;
315  while ((descriptor = fn(index))) {
316 
317  const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin;
318  if (!ladspaDescriptor) {
319  SVCERR << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname << endl;
320  ++index;
321  continue;
322  }
323 
325  rtd.name = ladspaDescriptor->Name;
326  rtd.label = ladspaDescriptor->Label;
327  rtd.maker = ladspaDescriptor->Maker;
328  rtd.copyright = ladspaDescriptor->Copyright;
329  rtd.category = "";
330  rtd.isSynth = (descriptor->run_synth ||
331  descriptor->run_multiple_synths);
332  rtd.parameterCount = 0;
333  rtd.audioInputPortCount = 0;
334  rtd.audioOutputPortCount = 0;
335  rtd.controlOutputPortCount = 0;
336 
337  QString identifier = PluginIdentifier::createIdentifier
338  ("dssi", soname, ladspaDescriptor->Label);
339 
340 #ifdef HAVE_LRDF
341  char *def_uri = nullptr;
342  lrdf_defaults *defs = nullptr;
343 
344  QString category = m_taxonomy[identifier];
345 
346  if (category == "" && m_lrdfTaxonomy[ladspaDescriptor->UniqueID] != "") {
347  m_taxonomy[identifier] = m_lrdfTaxonomy[ladspaDescriptor->UniqueID];
348  category = m_taxonomy[identifier];
349  }
350 
351  if (category == "") {
352  string name = rtd.name;
353  if (name.length() > 4 &&
354  name.substr(name.length() - 4) == " VST") {
355  if (descriptor->run_synth || descriptor->run_multiple_synths) {
356  category = "VST instruments";
357  } else {
358  category = "VST effects";
359  }
360  m_taxonomy[identifier] = category;
361  }
362  }
363 
364  rtd.category = category.toStdString();
365 
366 // SVCERR << "Plugin id is " << ladspaDescriptor->UniqueID
367 // << ", identifier is \"" << identifier
368 // << "\", category is \"" << category
369 // << "\", name is " << ladspaDescriptor->Name
370 // << ", label is " << ladspaDescriptor->Label
371 // << endl;
372 
373  def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID);
374  if (def_uri) {
375  defs = lrdf_get_setting_values(def_uri);
376  }
377 
378  unsigned int controlPortNumber = 1;
379 
380  for (int i = 0; i < (int)ladspaDescriptor->PortCount; i++) {
381 
382  if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
383 
384  if (def_uri && defs) {
385 
386  for (int j = 0; j < (int)defs->count; j++) {
387  if (defs->items[j].pid == controlPortNumber) {
388 // 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 " << ladspaDescriptor->PortNames[i] << endl;
389  m_portDefaults[ladspaDescriptor->UniqueID][i] =
390  defs->items[j].value;
391  }
392  }
393  }
394 
395  ++controlPortNumber;
396  }
397  }
398 #endif // HAVE_LRDF
399 
400  for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
401  if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
402  if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
403  ++rtd.parameterCount;
404  } else {
405  if (strcmp(ladspaDescriptor->PortNames[i], "latency") &&
406  strcmp(ladspaDescriptor->PortNames[i], "_latency")) {
408  rtd.controlOutputPortNames.push_back
409  (ladspaDescriptor->PortNames[i]);
410  }
411  }
412  } else {
413  if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
414  ++rtd.audioInputPortCount;
415  } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) {
416  ++rtd.audioOutputPortCount;
417  }
418  }
419  }
420 
421  m_identifiers.push_back(identifier);
422 
423  m_libraries[identifier] = soname;
424 
425  m_rtDescriptors[identifier] = rtd;
426 
427  ++index;
428  }
429 
430  if (DLCLOSE(libraryHandle) != 0) {
431  SVCERR << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << endl;
432  return;
433  }
434 }
435 
436 
437 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
std::vector< QString > getLRDFPath(QString &baseUri) override
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 enumeratePlugins(std::vector< QString > &list) override
Append to the given list descriptions of all the available plugins and their ports.
static int requestMidiSend(LADSPA_Handle instance, unsigned char ports, unsigned char channels)
int getPortDisplayHint(const LADSPA_Descriptor *, int port)
static const int Input
const LADSPA_Descriptor * getLADSPADescriptor(QString identifier) override
static void midiSend(LADSPA_Handle instance, snd_seq_event_t *events, unsigned long eventCount)
void discoverPluginsFrom(QString soName) override
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
static void parseIdentifier(QString identifier, QString &type, QString &soName, QString &label)
static QString createIdentifier(QString type, QString soName, QString label)
static std::vector< QString > getPluginPath()
float getPortDefault(const LADSPA_Descriptor *, int port)
static const DSSI_Descriptor * getDescriptor(unsigned long index)
std::set< std::weak_ptr< RealTimePluginInstance >, std::owner_less< std::weak_ptr< RealTimePluginInstance > > > m_instances
float getPortMaximum(const LADSPA_Descriptor *, int port)
static QString BUILTIN_PLUGIN_SONAME
virtual const DSSI_Descriptor * getDSSIDescriptor(QString identifier)
DSSI_Host_Descriptor m_hostDescriptor
static const int Audio
std::map< unsigned long, std::map< int, float > > m_portDefaults
std::shared_ptr< RealTimePluginInstance > instantiatePlugin(QString identifier, int clientId, int position, sv_samplerate_t sampleRate, int blockSize, int channels) override
Instantiate a plugin.
std::map< QString, RealTimePluginDescriptor > m_rtDescriptors
#define DLCLOSE(a)
Definition: System.h:99
#define PATH_SEPARATOR
Definition: System.h:135
std::map< QString, QString > m_taxonomy
static int requestNonRTThread(LADSPA_Handle instance, void(*runFunction)(LADSPA_Handle))
std::vector< QString > m_identifiers
std::map< unsigned long, QString > m_lrdfTaxonomy
static RealTimePluginFactory * instance(QString pluginType)
#define SVCERR
Definition: Debug.h:109
#define DEFAULT_DSSI_PATH
Definition: System.h:138
void loadLibrary(QString soName)
static const int Control
float getPortMinimum(const LADSPA_Descriptor *, int port)
static const int Output
#define DLSYM(a, b)
Definition: System.h:98
Profile point instance class.
Definition: Profiler.h:93