1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "DSSIPluginFactory.h"
17 #include <cstdlib>
18 #include "misc/Strings.h"
19
20 #include <dlfcn.h>
21 #include "base/AudioPluginInstance.h"
22 #include "DSSIPluginInstance.h"
23 #include "MappedStudio.h"
24 #include "PluginIdentifier.h"
25 #include <lrdf.h>
26
27 namespace Rosegarden
28 {
29
DSSIPluginFactory()30 DSSIPluginFactory::DSSIPluginFactory() :
31 LADSPAPluginFactory()
32 {
33 // nothing else to do
34 }
35
~DSSIPluginFactory()36 DSSIPluginFactory::~DSSIPluginFactory()
37 {
38 // nothing else to do here either
39 }
40
41 void
enumeratePlugins(MappedObjectPropertyList & list)42 DSSIPluginFactory::enumeratePlugins(MappedObjectPropertyList &list)
43 {
44 for (std::vector<QString>::iterator i = m_identifiers.begin();
45 i != m_identifiers.end(); ++i) {
46
47 const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i);
48 if (!ddesc)
49 continue;
50
51 const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin;
52 if (!descriptor)
53 continue;
54
55 // std::cerr << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << std::endl;
56
57 list.push_back(*i);
58 list.push_back(descriptor->Name);
59 list.push_back(QString("%1").arg(descriptor->UniqueID));
60 list.push_back(descriptor->Label);
61 list.push_back(descriptor->Maker);
62 list.push_back(descriptor->Copyright);
63 list.push_back((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false");
64 list.push_back(ddesc->run_multiple_synths ? "true" : "false");
65 list.push_back(m_taxonomy[descriptor->UniqueID]);
66 list.push_back(QString("%1").arg(descriptor->PortCount));
67
68 for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
69
70 int type = 0;
71 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
72 type |= PluginPort::Control;
73 } else {
74 type |= PluginPort::Audio;
75 }
76 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
77 type |= PluginPort::Input;
78 } else {
79 type |= PluginPort::Output;
80 }
81
82 list.push_back(QString("%1").arg(p));
83 list.push_back(descriptor->PortNames[p]);
84 list.push_back(QString("%1").arg(type));
85 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
86 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
87 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
88 list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
89 }
90 }
91
92 unloadUnusedLibraries();
93 }
94
95
96 void
populatePluginSlot(QString identifier,MappedPluginSlot & slot)97 DSSIPluginFactory::populatePluginSlot(QString identifier, MappedPluginSlot &slot)
98 {
99 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(identifier);
100 if (!descriptor)
101 return ;
102
103 if (descriptor) {
104
105 slot.setStringProperty(MappedPluginSlot::Label, descriptor->Label);
106 slot.setStringProperty(MappedPluginSlot::PluginName, descriptor->Name);
107 slot.setStringProperty(MappedPluginSlot::Author, descriptor->Maker);
108 slot.setStringProperty(MappedPluginSlot::Copyright, descriptor->Copyright);
109 slot.setProperty(MappedPluginSlot::PortCount, descriptor->PortCount);
110 slot.setStringProperty(MappedPluginSlot::Category, m_taxonomy[descriptor->UniqueID]);
111
112 slot.destroyChildren();
113
114 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
115
116 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) &&
117 LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
118
119 MappedStudio *studio = dynamic_cast<MappedStudio *>(slot.getParent());
120 if (!studio) {
121 std::cerr << "WARNING: DSSIPluginFactory::populatePluginSlot: can't find studio" << std::endl;
122 return ;
123 }
124
125 MappedPluginPort *port =
126 dynamic_cast<MappedPluginPort *>
127 (studio->createObject(MappedObject::PluginPort));
128
129 slot.addChild(port);
130 port->setParent(&slot);
131
132 port->setProperty(MappedPluginPort::PortNumber, i);
133 port->setStringProperty(MappedPluginPort::Name,
134 descriptor->PortNames[i]);
135 port->setProperty(MappedPluginPort::Maximum,
136 getPortMaximum(descriptor, i));
137 port->setProperty(MappedPluginPort::Minimum,
138 getPortMinimum(descriptor, i));
139 port->setProperty(MappedPluginPort::Default,
140 getPortDefault(descriptor, i));
141 port->setProperty(MappedPluginPort::DisplayHint,
142 getPortDisplayHint(descriptor, i));
143 }
144 }
145 }
146
147 //!!! leak here if the plugin is not instantiated too...?
148 }
149
150 RunnablePluginInstance *
instantiatePlugin(QString identifier,int instrument,int position,unsigned int sampleRate,unsigned int blockSize,unsigned int channels)151 DSSIPluginFactory::instantiatePlugin(QString identifier,
152 int instrument,
153 int position,
154 unsigned int sampleRate,
155 unsigned int blockSize,
156 unsigned int channels)
157 {
158 const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier);
159
160 if (descriptor) {
161
162 DSSIPluginInstance *instance =
163 new DSSIPluginInstance
164 (this, instrument, identifier, position, sampleRate, blockSize, channels,
165 descriptor);
166
167 m_instances.insert(instance);
168
169 return instance;
170 }
171
172 return nullptr;
173 }
174
175
176 const DSSI_Descriptor *
getDSSIDescriptor(QString identifier)177 DSSIPluginFactory::getDSSIDescriptor(QString identifier)
178 {
179 QString type, soname, label;
180 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
181
182 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
183 loadLibrary(soname);
184 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
185 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname << std::endl;
186 return nullptr;
187 }
188 }
189
190 void *libraryHandle = m_libraryHandles[soname];
191
192 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
193 dlsym(libraryHandle, "dssi_descriptor");
194
195 if (!fn) {
196 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname << std::endl;
197 return nullptr;
198 }
199
200 const DSSI_Descriptor *descriptor = nullptr;
201
202 int index = 0;
203 while ((descriptor = fn(index))) {
204 if (descriptor->LADSPA_Plugin->Label == label)
205 return descriptor;
206 ++index;
207 }
208
209 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label << " in library " << soname << std::endl;
210
211 return nullptr;
212 }
213
214 const LADSPA_Descriptor *
getLADSPADescriptor(QString identifier)215 DSSIPluginFactory::getLADSPADescriptor(QString identifier)
216 {
217 const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier);
218 if (dssiDescriptor)
219 return dssiDescriptor->LADSPA_Plugin;
220 else
221 return nullptr;
222 }
223
224
225 std::vector<QString>
getPluginPath()226 DSSIPluginFactory::getPluginPath()
227 {
228 std::vector<QString> pathList;
229 std::string path;
230
231 char *cpath = getenv("DSSI_PATH");
232 if (cpath)
233 path = cpath;
234
235 if (path == "") {
236 // ??? Probably should offer "Additional DSSI search paths" in the
237 // preferences.
238 path = "/usr/local/lib/dssi:/usr/lib/dssi:/usr/local/lib64/dssi:"
239 "/usr/lib64/dssi:/usr/lib/x86_64-linux-gnu/dssi";
240 char *home = getenv("HOME");
241 if (home)
242 path = std::string(home) + "/.dssi:" + path;
243 }
244
245 std::string::size_type index = 0, newindex = 0;
246
247 while ((newindex = path.find(':', index)) < path.size()) {
248 pathList.push_back(path.substr(index, newindex - index).c_str());
249 index = newindex + 1;
250 }
251
252 pathList.push_back(path.substr(index).c_str());
253
254 return pathList;
255 }
256
257
258 std::vector<QString>
getLRDFPath(QString & baseUri)259 DSSIPluginFactory::getLRDFPath(QString &baseUri)
260 {
261 std::vector<QString> pathList = getPluginPath();
262 std::vector<QString> lrdfPaths;
263
264 lrdfPaths.push_back("/usr/local/share/dssi/rdf");
265 lrdfPaths.push_back("/usr/share/dssi/rdf");
266
267 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
268 lrdfPaths.push_back("/usr/share/ladspa/rdf");
269
270 for (std::vector<QString>::iterator i = pathList.begin();
271 i != pathList.end(); ++i) {
272 lrdfPaths.push_back(*i + "/rdf");
273 }
274
275 #ifdef DSSI_BASE
276 baseUri = DSSI_BASE;
277 #else
278
279 baseUri = "http://dssi.sourceforge.net/ontology#";
280 #endif
281
282 return lrdfPaths;
283 }
284
285
286 void
discoverPlugin(const QString & soName)287 DSSIPluginFactory::discoverPlugin(const QString &soName)
288 {
289 void *libraryHandle = dlopen( qstrtostr(soName).c_str(), RTLD_LAZY);
290
291 if (!libraryHandle) {
292 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugin: couldn't dlopen "
293 << soName << " - " << dlerror() << std::endl;
294 return ;
295 }
296
297 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
298 dlsym(libraryHandle, "dssi_descriptor");
299
300 if (!fn) {
301 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugin: No descriptor function in " << soName << std::endl;
302 return ;
303 }
304
305 const DSSI_Descriptor *descriptor = nullptr;
306
307 int index = 0;
308 while ((descriptor = fn(index))) {
309
310 const LADSPA_Descriptor * ladspaDescriptor = descriptor->LADSPA_Plugin;
311 if (!ladspaDescriptor) {
312 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugin: No LADSPA descriptor for plugin " << index << " in " << soName << std::endl;
313 ++index;
314 continue;
315 }
316
317 char *def_uri = nullptr;
318 lrdf_defaults *defs = nullptr;
319
320 QString category = m_taxonomy[ladspaDescriptor->UniqueID];
321
322 if (category == "" && ladspaDescriptor->Name != nullptr) {
323 std::string name = ladspaDescriptor->Name;
324 if (name.length() > 4 &&
325 name.substr(name.length() - 4) == " VST") {
326 if (descriptor->run_synth || descriptor->run_multiple_synths) {
327 category = "VST instruments";
328 } else {
329 category = "VST effects";
330 }
331 m_taxonomy[ladspaDescriptor->UniqueID] = category;
332 }
333 }
334
335 // std::cerr << "Plugin id is " << ladspaDescriptor->UniqueID
336 // << ", category is \"" << (category ? category : QString("(none)"))
337 // << "\", name is " << ladspaDescriptor->Name
338 // << ", label is " << ladspaDescriptor->Label
339 // << std::endl;
340
341 def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID);
342 if (def_uri) {
343 defs = lrdf_get_setting_values(def_uri);
344 }
345
346 int controlPortNumber = 1;
347
348 for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
349
350 if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
351
352 if (def_uri && defs) {
353
354 for (unsigned int j = 0; j < defs->count; j++) {
355 if (defs->items[j].pid == (unsigned long)controlPortNumber) {
356 // 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 " << ladspaDescriptor->PortNames[i] << std::endl;
357 m_portDefaults[ladspaDescriptor->UniqueID][i] =
358 defs->items[j].value;
359 }
360 }
361 }
362
363 ++controlPortNumber;
364 }
365 }
366
367 QString identifier = PluginIdentifier::createIdentifier
368 ("dssi", soName, ladspaDescriptor->Label);
369 m_identifiers.push_back(identifier);
370
371 ++index;
372 }
373
374 if (dlclose(libraryHandle) != 0) {
375 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugin - can't unload " << libraryHandle << std::endl;
376 return ;
377 }
378 }
379
380
381 }
382
383