svcore  1.9
DSSIPluginFactory.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 /*
00016    This is a modified version of a source file from the 
00017    Rosegarden MIDI and audio sequencer and notation editor.
00018    This file copyright 2000-2006 Chris Cannam.
00019 */
00020 
00021 #include "DSSIPluginFactory.h"
00022 #include <iostream>
00023 
00024 #include <QString>
00025 
00026 #include "DSSIPluginInstance.h"
00027 #include "PluginIdentifier.h"
00028 
00029 #include <cstdlib>
00030 
00031 #include "base/Profiler.h"
00032 
00034 #include "plugin/plugins/SamplePlayer.h"
00035 
00036 #include "system/System.h"
00037 
00038 #ifdef HAVE_LRDF
00039 #include "lrdf.h"
00040 #endif // HAVE_LRDF
00041 
00042 
00043 DSSIPluginFactory::DSSIPluginFactory() :
00044     LADSPAPluginFactory()
00045 {
00046     m_hostDescriptor.DSSI_API_Version = 2;
00047     m_hostDescriptor.request_transport_information = NULL;
00048     m_hostDescriptor.request_midi_send = DSSIPluginInstance::requestMidiSend;
00049     m_hostDescriptor.request_non_rt_thread = DSSIPluginInstance::requestNonRTThread;
00050     m_hostDescriptor.midi_send = DSSIPluginInstance::midiSend;
00051 }
00052 
00053 DSSIPluginFactory::~DSSIPluginFactory()
00054 {
00055     // nothing else to do here either
00056 }
00057 
00058 void
00059 DSSIPluginFactory::enumeratePlugins(std::vector<QString> &list)
00060 {
00061     Profiler profiler("DSSIPluginFactory::enumeratePlugins");
00062 
00063     for (std::vector<QString>::iterator i = m_identifiers.begin();
00064          i != m_identifiers.end(); ++i) {
00065 
00066         const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i);
00067         if (!ddesc) continue;
00068 
00069         const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin;
00070         if (!descriptor) continue;
00071         
00072 //      SVDEBUG << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << endl;
00073 
00074         list.push_back(*i);
00075         list.push_back(descriptor->Name);
00076         list.push_back(QString("%1").arg(descriptor->UniqueID));
00077         list.push_back(descriptor->Label);
00078         list.push_back(descriptor->Maker);
00079         list.push_back(descriptor->Copyright);
00080         list.push_back((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false");
00081         list.push_back(ddesc->run_multiple_synths ? "true" : "false");
00082         list.push_back(m_taxonomy[*i]);
00083         list.push_back(QString("%1").arg(descriptor->PortCount));
00084 
00085         for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
00086 
00087             int type = 0;
00088             if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
00089                 type |= PortType::Control;
00090             } else {
00091                 type |= PortType::Audio;
00092             }
00093             if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
00094                 type |= PortType::Input;
00095             } else {
00096                 type |= PortType::Output;
00097             }
00098 
00099             list.push_back(QString("%1").arg(p));
00100             list.push_back(descriptor->PortNames[p]);
00101             list.push_back(QString("%1").arg(type));
00102             list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
00103             list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
00104             list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
00105             list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
00106         }
00107     }
00108 
00109     unloadUnusedLibraries();
00110 }
00111         
00112 RealTimePluginInstance *
00113 DSSIPluginFactory::instantiatePlugin(QString identifier,
00114                                      int instrument,
00115                                      int position,
00116                                      unsigned int sampleRate,
00117                                      unsigned int blockSize,
00118                                      unsigned int channels)
00119 {
00120     Profiler profiler("DSSIPluginFactory::instantiatePlugin");
00121 
00122     const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier);
00123 
00124     if (descriptor) {
00125 
00126         DSSIPluginInstance *instance =
00127             new DSSIPluginInstance
00128             (this, instrument, identifier, position, sampleRate, blockSize, channels,
00129              descriptor);
00130 
00131         m_instances.insert(instance);
00132 
00133         return instance;
00134     }
00135 
00136     return 0;
00137 }
00138 
00139 const DSSI_Descriptor *
00140 DSSIPluginFactory::getDSSIDescriptor(QString identifier)
00141 {
00142     QString type, soname, label;
00143     PluginIdentifier::parseIdentifier(identifier, type, soname, label);
00144 
00145     if (soname == PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
00146         if (label == "sample_player") {
00147             const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0);
00148             if (descriptor) {
00149                 descriptor->receive_host_descriptor(&m_hostDescriptor);
00150             }
00151             return descriptor;
00152         } else {
00153             return 0;
00154         }
00155     }
00156     
00157     bool firstInLibrary = false;
00158 
00159     if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
00160         loadLibrary(soname);
00161         if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
00162             cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname << endl;
00163             return 0;
00164         }
00165         firstInLibrary = true;
00166     }
00167 
00168     void *libraryHandle = m_libraryHandles[soname];
00169 
00170     DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
00171         DLSYM(libraryHandle, "dssi_descriptor");
00172 
00173     if (!fn) {
00174         cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname << endl;
00175         return 0;
00176     }
00177 
00178     const DSSI_Descriptor *descriptor = 0;
00179     
00180     int index = 0;
00181     while ((descriptor = fn(index))) {
00182         if (descriptor->LADSPA_Plugin->Label == label) {
00183             if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) {
00184                 descriptor->receive_host_descriptor(&m_hostDescriptor);
00185             }
00186             return descriptor;
00187         }
00188         ++index;
00189     }
00190 
00191     cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label << " in library " << soname << endl;
00192 
00193     return 0;
00194 }
00195 
00196 const LADSPA_Descriptor *
00197 DSSIPluginFactory::getLADSPADescriptor(QString identifier)
00198 {
00199     const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier);
00200     if (dssiDescriptor) return dssiDescriptor->LADSPA_Plugin;
00201     else return 0;
00202 }
00203 
00204 
00205 std::vector<QString>
00206 DSSIPluginFactory::getPluginPath()
00207 {
00208     std::vector<QString> pathList;
00209     std::string path;
00210 
00211     char *cpath = getenv("DSSI_PATH");
00212     if (cpath) path = cpath;
00213 
00214     if (path == "") {
00215 
00216         path = DEFAULT_DSSI_PATH;
00217 
00218         char *home = getenv("HOME");
00219         if (home) {
00220             std::string::size_type f;
00221             while ((f = path.find("$HOME")) != std::string::npos &&
00222                    f < path.length()) {
00223                 path.replace(f, 5, home);
00224             }
00225         }
00226 
00227 #ifdef _WIN32
00228         char *pfiles = getenv("ProgramFiles");
00229         if (!pfiles) pfiles = "C:\\Program Files";
00230         {
00231         std::string::size_type f;
00232         while ((f = path.find("%ProgramFiles%")) != std::string::npos &&
00233                f < path.length()) {
00234             path.replace(f, 14, pfiles);
00235         }
00236         }
00237 #endif
00238     }
00239 
00240     std::string::size_type index = 0, newindex = 0;
00241 
00242     while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) {
00243         pathList.push_back(path.substr(index, newindex - index).c_str());
00244         index = newindex + 1;
00245     }
00246     
00247     pathList.push_back(path.substr(index).c_str());
00248 
00249     return pathList;
00250 }
00251 
00252 
00253 std::vector<QString>
00254 DSSIPluginFactory::getLRDFPath(QString &baseUri)
00255 {
00256     std::vector<QString> lrdfPaths;
00257 
00258 #ifdef HAVE_LRDF
00259     std::vector<QString> pathList = getPluginPath();
00260 
00261     lrdfPaths.push_back("/usr/local/share/dssi/rdf");
00262     lrdfPaths.push_back("/usr/share/dssi/rdf");
00263 
00264     lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
00265     lrdfPaths.push_back("/usr/share/ladspa/rdf");
00266 
00267     for (std::vector<QString>::iterator i = pathList.begin();
00268          i != pathList.end(); ++i) {
00269         lrdfPaths.push_back(*i + "/rdf");
00270     }
00271 
00272 #ifdef DSSI_BASE
00273     baseUri = DSSI_BASE;
00274 #else
00275     baseUri = "http://dssi.sourceforge.net/ontology#";
00276 #endif
00277 #else
00278     // avoid unused parameter
00279     baseUri = "";
00280 #endif
00281 
00282     return lrdfPaths;
00283 }    
00284 
00285 
00286 void
00287 DSSIPluginFactory::discoverPluginsFrom(QString soname)
00288 {
00289     Profiler profiler("DSSIPluginFactory::discoverPlugins");
00290 
00291     // Note that soname is expected to be a full path at this point,
00292     // of a file that is known to exist
00293 
00294     void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
00295 
00296     if (!libraryHandle) {
00297         cerr << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library "
00298                   << soname << " - " << DLERROR() << endl;
00299         return;
00300     }
00301 
00302     DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
00303         DLSYM(libraryHandle, "dssi_descriptor");
00304 
00305     if (!fn) {
00306         cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname << endl;
00307         return;
00308     }
00309 
00310     const DSSI_Descriptor *descriptor = 0;
00311     
00312     int index = 0;
00313     while ((descriptor = fn(index))) {
00314 
00315         const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin;
00316         if (!ladspaDescriptor) {
00317             cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname << endl;
00318             ++index;
00319             continue;
00320         }
00321 
00322         RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
00323         rtd->name = ladspaDescriptor->Name;
00324         rtd->label = ladspaDescriptor->Label;
00325         rtd->maker = ladspaDescriptor->Maker;
00326         rtd->copyright = ladspaDescriptor->Copyright;
00327         rtd->category = "";
00328         rtd->isSynth = (descriptor->run_synth ||
00329                         descriptor->run_multiple_synths);
00330         rtd->parameterCount = 0;
00331         rtd->audioInputPortCount = 0;
00332         rtd->audioOutputPortCount = 0;
00333         rtd->controlOutputPortCount = 0;
00334 
00335         QString identifier = PluginIdentifier::createIdentifier
00336             ("dssi", soname, ladspaDescriptor->Label);
00337 
00338 #ifdef HAVE_LRDF
00339         char *def_uri = 0;
00340         lrdf_defaults *defs = 0;
00341                 
00342         QString category = m_taxonomy[identifier];
00343 
00344         if (category == "" && m_lrdfTaxonomy[ladspaDescriptor->UniqueID] != "") {
00345             m_taxonomy[identifier] = m_lrdfTaxonomy[ladspaDescriptor->UniqueID];
00346             category = m_taxonomy[identifier];
00347         }
00348 
00349         if (category == "") {
00350             std::string name = rtd->name;
00351             if (name.length() > 4 &&
00352                 name.substr(name.length() - 4) == " VST") {
00353                 if (descriptor->run_synth || descriptor->run_multiple_synths) {
00354                     category = "VST instruments";
00355                 } else {
00356                     category = "VST effects";
00357                 }
00358                 m_taxonomy[identifier] = category;
00359             }
00360         }
00361 
00362         rtd->category = category.toStdString();
00363         
00364 //      cerr << "Plugin id is " << ladspaDescriptor->UniqueID
00365 //                  << ", identifier is \"" << identifier
00366 //                << "\", category is \"" << category
00367 //                << "\", name is " << ladspaDescriptor->Name
00368 //                << ", label is " << ladspaDescriptor->Label
00369 //                << endl;
00370         
00371         def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID);
00372         if (def_uri) {
00373             defs = lrdf_get_setting_values(def_uri);
00374         }
00375         
00376         unsigned int controlPortNumber = 1;
00377         
00378         for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
00379             
00380             if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
00381                 
00382                 if (def_uri && defs) {
00383                     
00384                     for (unsigned int j = 0; j < defs->count; j++) {
00385                         if (defs->items[j].pid == controlPortNumber) {
00386 //                          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;
00387                             m_portDefaults[ladspaDescriptor->UniqueID][i] =
00388                                 defs->items[j].value;
00389                         }
00390                     }
00391                 }
00392                 
00393                 ++controlPortNumber;
00394             }
00395         }
00396 #endif // HAVE_LRDF
00397 
00398         for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
00399             if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
00400                 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
00401                     ++rtd->parameterCount;
00402                 } else {
00403                     if (strcmp(ladspaDescriptor->PortNames[i], "latency") &&
00404                         strcmp(ladspaDescriptor->PortNames[i], "_latency")) {
00405                         ++rtd->controlOutputPortCount;
00406                         rtd->controlOutputPortNames.push_back
00407                             (ladspaDescriptor->PortNames[i]);
00408                     }
00409                 }
00410             } else {
00411                 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
00412                     ++rtd->audioInputPortCount;
00413                 } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) {
00414                     ++rtd->audioOutputPortCount;
00415                 }
00416             }
00417         }
00418 
00419         m_identifiers.push_back(identifier);
00420 
00421         m_rtDescriptors[identifier] = rtd;
00422 
00423         ++index;
00424     }
00425 
00426     if (DLCLOSE(libraryHandle) != 0) {
00427         cerr << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << endl;
00428         return;
00429     }
00430 }
00431 
00432     
00433