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
33 //!!!
34 #include "plugin/plugins/SamplePlayer.h"
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
DSSIPluginFactory()44 DSSIPluginFactory::DSSIPluginFactory() :
45 LADSPAPluginFactory()
46 {
47 m_hostDescriptor.DSSI_API_Version = 2;
48 m_hostDescriptor.request_transport_information = nullptr;
49 m_hostDescriptor.request_midi_send = DSSIPluginInstance::requestMidiSend;
50 m_hostDescriptor.request_non_rt_thread = DSSIPluginInstance::requestNonRTThread;
51 m_hostDescriptor.midi_send = DSSIPluginInstance::midiSend;
52 }
53
~DSSIPluginFactory()54 DSSIPluginFactory::~DSSIPluginFactory()
55 {
56 // nothing else to do here either
57 }
58
59 void
enumeratePlugins(std::vector<QString> & list)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
110 unloadUnusedLibraries();
111 }
112
113 RealTimePluginInstance *
instantiatePlugin(QString identifier,int instrument,int position,sv_samplerate_t sampleRate,int blockSize,int channels)114 DSSIPluginFactory::instantiatePlugin(QString identifier,
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 DSSIPluginInstance *instance =
128 new DSSIPluginInstance
129 (this, instrument, identifier, position, sampleRate, blockSize, channels,
130 descriptor);
131
132 m_instances.insert(instance);
133
134 return instance;
135 }
136
137 return nullptr;
138 }
139
140 const DSSI_Descriptor *
getDSSIDescriptor(QString identifier)141 DSSIPluginFactory::getDSSIDescriptor(QString identifier)
142 {
143 QString type, soname, label;
144 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
145
146 if (soname == PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
147 if (label == "sample_player") {
148 const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0);
149 if (descriptor) {
150 descriptor->receive_host_descriptor(&m_hostDescriptor);
151 }
152 return descriptor;
153 } else {
154 return nullptr;
155 }
156 }
157
158 bool firstInLibrary = false;
159
160 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
161 loadLibrary(soname);
162 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
163 cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname << endl;
164 return nullptr;
165 }
166 firstInLibrary = true;
167 }
168
169 void *libraryHandle = m_libraryHandles[soname];
170
171 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
172 DLSYM(libraryHandle, "dssi_descriptor");
173
174 if (!fn) {
175 cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname << endl;
176 return nullptr;
177 }
178
179 const DSSI_Descriptor *descriptor = nullptr;
180
181 int index = 0;
182 while ((descriptor = fn(index))) {
183 if (descriptor->LADSPA_Plugin->Label == label) {
184 if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) {
185 descriptor->receive_host_descriptor(&m_hostDescriptor);
186 }
187 return descriptor;
188 }
189 ++index;
190 }
191
192 cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label << " in library " << soname << endl;
193
194 return nullptr;
195 }
196
197 const LADSPA_Descriptor *
getLADSPADescriptor(QString identifier)198 DSSIPluginFactory::getLADSPADescriptor(QString identifier)
199 {
200 const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier);
201 if (dssiDescriptor) return dssiDescriptor->LADSPA_Plugin;
202 else return nullptr;
203 }
204
205
206 std::vector<QString>
getPluginPath()207 DSSIPluginFactory::getPluginPath()
208 {
209 std::vector<QString> pathList;
210 string path;
211
212 (void)getEnvUtf8("DSSI_PATH", path);
213
214 if (path == "") {
215
216 path = DEFAULT_DSSI_PATH;
217
218 string home;
219 if (getEnvUtf8("HOME", home)) {
220 string::size_type f;
221 while ((f = path.find("$HOME")) != string::npos &&
222 f < path.length()) {
223 path.replace(f, 5, home);
224 }
225 }
226
227 #ifdef _WIN32
228 string pfiles;
229 if (!getEnvUtf8("ProgramFiles", pfiles)) {
230 pfiles = "C:\\Program Files";
231 }
232
233 string::size_type f;
234 while ((f = path.find("%ProgramFiles%")) != string::npos &&
235 f < path.length()) {
236 path.replace(f, 14, pfiles);
237 }
238 #endif
239 }
240
241 string::size_type index = 0, newindex = 0;
242
243 while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) {
244 pathList.push_back(path.substr(index, newindex - index).c_str());
245 index = newindex + 1;
246 }
247
248 pathList.push_back(path.substr(index).c_str());
249
250 return pathList;
251 }
252
253
254 std::vector<QString>
getLRDFPath(QString & baseUri)255 DSSIPluginFactory::getLRDFPath(QString &baseUri)
256 {
257 std::vector<QString> lrdfPaths;
258
259 #ifdef HAVE_LRDF
260 std::vector<QString> pathList = getPluginPath();
261
262 lrdfPaths.push_back("/usr/local/share/dssi/rdf");
263 lrdfPaths.push_back("/usr/share/dssi/rdf");
264
265 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
266 lrdfPaths.push_back("/usr/share/ladspa/rdf");
267
268 for (std::vector<QString>::iterator i = pathList.begin();
269 i != pathList.end(); ++i) {
270 lrdfPaths.push_back(*i + "/rdf");
271 }
272
273 #ifdef DSSI_BASE
274 baseUri = DSSI_BASE;
275 #else
276 baseUri = "http://dssi.sourceforge.net/ontology#";
277 #endif
278 #else
279 // avoid unused parameter
280 baseUri = "";
281 #endif
282
283 return lrdfPaths;
284 }
285
286
287 void
discoverPluginsFrom(QString soname)288 DSSIPluginFactory::discoverPluginsFrom(QString soname)
289 {
290 Profiler profiler("DSSIPluginFactory::discoverPlugins");
291
292 // Note that soname is expected to be a full path at this point,
293 // of a file that is known to exist
294
295 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
296
297 if (!libraryHandle) {
298 cerr << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library "
299 << soname << " - " << DLERROR() << endl;
300 return;
301 }
302
303 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
304 DLSYM(libraryHandle, "dssi_descriptor");
305
306 if (!fn) {
307 cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname << endl;
308 return;
309 }
310
311 const DSSI_Descriptor *descriptor = nullptr;
312
313 int index = 0;
314 while ((descriptor = fn(index))) {
315
316 const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin;
317 if (!ladspaDescriptor) {
318 cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname << endl;
319 ++index;
320 continue;
321 }
322
323 RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
324 rtd->name = ladspaDescriptor->Name;
325 rtd->label = ladspaDescriptor->Label;
326 rtd->maker = ladspaDescriptor->Maker;
327 rtd->copyright = ladspaDescriptor->Copyright;
328 rtd->category = "";
329 rtd->isSynth = (descriptor->run_synth ||
330 descriptor->run_multiple_synths);
331 rtd->parameterCount = 0;
332 rtd->audioInputPortCount = 0;
333 rtd->audioOutputPortCount = 0;
334 rtd->controlOutputPortCount = 0;
335
336 QString identifier = PluginIdentifier::createIdentifier
337 ("dssi", soname, ladspaDescriptor->Label);
338
339 #ifdef HAVE_LRDF
340 char *def_uri = nullptr;
341 lrdf_defaults *defs = nullptr;
342
343 QString category = m_taxonomy[identifier];
344
345 if (category == "" && m_lrdfTaxonomy[ladspaDescriptor->UniqueID] != "") {
346 m_taxonomy[identifier] = m_lrdfTaxonomy[ladspaDescriptor->UniqueID];
347 category = m_taxonomy[identifier];
348 }
349
350 if (category == "") {
351 string name = rtd->name;
352 if (name.length() > 4 &&
353 name.substr(name.length() - 4) == " VST") {
354 if (descriptor->run_synth || descriptor->run_multiple_synths) {
355 category = "VST instruments";
356 } else {
357 category = "VST effects";
358 }
359 m_taxonomy[identifier] = category;
360 }
361 }
362
363 rtd->category = category.toStdString();
364
365 // cerr << "Plugin id is " << ladspaDescriptor->UniqueID
366 // << ", identifier is \"" << identifier
367 // << "\", category is \"" << category
368 // << "\", name is " << ladspaDescriptor->Name
369 // << ", label is " << ladspaDescriptor->Label
370 // << endl;
371
372 def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID);
373 if (def_uri) {
374 defs = lrdf_get_setting_values(def_uri);
375 }
376
377 unsigned int controlPortNumber = 1;
378
379 for (int i = 0; i < (int)ladspaDescriptor->PortCount; i++) {
380
381 if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
382
383 if (def_uri && defs) {
384
385 for (int j = 0; j < (int)defs->count; j++) {
386 if (defs->items[j].pid == controlPortNumber) {
387 // 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 " << ladspaDescriptor->PortNames[i] << endl;
388 m_portDefaults[ladspaDescriptor->UniqueID][i] =
389 defs->items[j].value;
390 }
391 }
392 }
393
394 ++controlPortNumber;
395 }
396 }
397 #endif // HAVE_LRDF
398
399 for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
400 if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
401 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
402 ++rtd->parameterCount;
403 } else {
404 if (strcmp(ladspaDescriptor->PortNames[i], "latency") &&
405 strcmp(ladspaDescriptor->PortNames[i], "_latency")) {
406 ++rtd->controlOutputPortCount;
407 rtd->controlOutputPortNames.push_back
408 (ladspaDescriptor->PortNames[i]);
409 }
410 }
411 } else {
412 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
413 ++rtd->audioInputPortCount;
414 } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) {
415 ++rtd->audioOutputPortCount;
416 }
417 }
418 }
419
420 m_identifiers.push_back(identifier);
421
422 m_libraries[identifier] = soname;
423
424 m_rtDescriptors[identifier] = rtd;
425
426 ++index;
427 }
428
429 if (DLCLOSE(libraryHandle) != 0) {
430 cerr << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << endl;
431 return;
432 }
433 }
434
435
436
437