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