Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@52: Sonic Visualiser Chris@52: An audio file viewer and annotation editor. Chris@52: Centre for Digital Music, Queen Mary, University of London. Chris@0: Chris@52: This program is free software; you can redistribute it and/or Chris@52: modify it under the terms of the GNU General Public License as Chris@52: published by the Free Software Foundation; either version 2 of the Chris@52: License, or (at your option) any later version. See the file Chris@52: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: /* Chris@0: This is a modified version of a source file from the Chris@0: Rosegarden MIDI and audio sequencer and notation editor. Chris@17: This file copyright 2000-2006 Chris Cannam. Chris@0: */ Chris@0: Chris@0: #include "DSSIPluginFactory.h" Chris@0: #include Chris@0: Chris@0: #include Chris@0: Chris@0: #include "DSSIPluginInstance.h" Chris@0: #include "PluginIdentifier.h" Chris@0: Chris@405: #include Chris@405: Chris@408: #include "base/Profiler.h" Chris@408: Chris@0: //!!! Chris@150: #include "plugin/plugins/SamplePlayer.h" Chris@0: Chris@150: #include "system/System.h" Chris@0: Chris@35: #ifdef HAVE_LRDF Chris@0: #include "lrdf.h" Chris@35: #endif // HAVE_LRDF Chris@0: Chris@0: Chris@0: DSSIPluginFactory::DSSIPluginFactory() : Chris@0: LADSPAPluginFactory() Chris@0: { Chris@0: m_hostDescriptor.DSSI_API_Version = 2; Chris@0: m_hostDescriptor.request_transport_information = NULL; Chris@0: m_hostDescriptor.request_midi_send = DSSIPluginInstance::requestMidiSend; Chris@0: m_hostDescriptor.request_non_rt_thread = DSSIPluginInstance::requestNonRTThread; Chris@0: m_hostDescriptor.midi_send = DSSIPluginInstance::midiSend; Chris@0: } Chris@0: Chris@0: DSSIPluginFactory::~DSSIPluginFactory() Chris@0: { Chris@0: // nothing else to do here either Chris@0: } Chris@0: Chris@0: void Chris@0: DSSIPluginFactory::enumeratePlugins(std::vector &list) Chris@0: { Chris@408: Profiler profiler("DSSIPluginFactory::enumeratePlugins"); Chris@408: Chris@0: for (std::vector::iterator i = m_identifiers.begin(); Chris@1429: i != m_identifiers.end(); ++i) { Chris@0: Chris@1429: const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i); Chris@1429: if (!ddesc) continue; Chris@0: Chris@1429: const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin; Chris@1429: if (!descriptor) continue; Chris@1429: Chris@1429: // SVDEBUG << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << endl; Chris@0: Chris@1429: list.push_back(*i); Chris@1429: list.push_back(descriptor->Name); Chris@1429: list.push_back(QString("%1").arg(descriptor->UniqueID)); Chris@1429: list.push_back(descriptor->Label); Chris@1429: list.push_back(descriptor->Maker); Chris@1429: list.push_back(descriptor->Copyright); Chris@1429: list.push_back((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false"); Chris@1429: list.push_back(ddesc->run_multiple_synths ? "true" : "false"); Chris@1429: list.push_back(m_taxonomy[*i]); Chris@1429: list.push_back(QString("%1").arg(descriptor->PortCount)); Chris@0: Chris@1429: for (int p = 0; p < (int)descriptor->PortCount; ++p) { Chris@0: Chris@1429: int type = 0; Chris@1429: if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) { Chris@1429: type |= PortType::Control; Chris@1429: } else { Chris@1429: type |= PortType::Audio; Chris@1429: } Chris@1429: if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) { Chris@1429: type |= PortType::Input; Chris@1429: } else { Chris@1429: type |= PortType::Output; Chris@1429: } Chris@0: Chris@1429: list.push_back(QString("%1").arg(p)); Chris@1429: list.push_back(descriptor->PortNames[p]); Chris@1429: list.push_back(QString("%1").arg(type)); Chris@1429: list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p))); Chris@1429: list.push_back(QString("%1").arg(getPortMinimum(descriptor, p))); Chris@1429: list.push_back(QString("%1").arg(getPortMaximum(descriptor, p))); Chris@1429: list.push_back(QString("%1").arg(getPortDefault(descriptor, p))); Chris@1429: } Chris@0: } Chris@0: Chris@0: unloadUnusedLibraries(); Chris@0: } Chris@1429: Chris@0: RealTimePluginInstance * Chris@0: DSSIPluginFactory::instantiatePlugin(QString identifier, Chris@1429: int instrument, Chris@1429: int position, Chris@1429: sv_samplerate_t sampleRate, Chris@1429: int blockSize, Chris@1429: int channels) Chris@0: { Chris@408: Profiler profiler("DSSIPluginFactory::instantiatePlugin"); Chris@408: Chris@0: const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier); Chris@0: Chris@0: if (descriptor) { Chris@0: Chris@1429: DSSIPluginInstance *instance = Chris@1429: new DSSIPluginInstance Chris@1429: (this, instrument, identifier, position, sampleRate, blockSize, channels, Chris@1429: descriptor); Chris@0: Chris@1429: m_instances.insert(instance); Chris@0: Chris@1429: return instance; Chris@0: } Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: const DSSI_Descriptor * Chris@0: DSSIPluginFactory::getDSSIDescriptor(QString identifier) Chris@0: { Chris@0: QString type, soname, label; Chris@0: PluginIdentifier::parseIdentifier(identifier, type, soname, label); Chris@0: Chris@0: if (soname == PluginIdentifier::BUILTIN_PLUGIN_SONAME) { Chris@1429: if (label == "sample_player") { Chris@1429: const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0); Chris@1429: if (descriptor) { Chris@1429: descriptor->receive_host_descriptor(&m_hostDescriptor); Chris@1429: } Chris@1429: return descriptor; Chris@1429: } else { Chris@1429: return 0; Chris@1429: } Chris@0: } Chris@0: Chris@0: bool firstInLibrary = false; Chris@0: Chris@0: if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { Chris@1429: loadLibrary(soname); Chris@1429: if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { Chris@1429: cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname << endl; Chris@1429: return 0; Chris@1429: } Chris@1429: firstInLibrary = true; Chris@0: } Chris@0: Chris@0: void *libraryHandle = m_libraryHandles[soname]; Chris@0: Chris@0: DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function) Chris@1429: DLSYM(libraryHandle, "dssi_descriptor"); Chris@0: Chris@0: if (!fn) { Chris@1429: cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname << endl; Chris@1429: return 0; Chris@0: } Chris@0: Chris@0: const DSSI_Descriptor *descriptor = 0; Chris@0: Chris@0: int index = 0; Chris@0: while ((descriptor = fn(index))) { Chris@1429: if (descriptor->LADSPA_Plugin->Label == label) { Chris@1429: if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) { Chris@1429: descriptor->receive_host_descriptor(&m_hostDescriptor); Chris@1429: } Chris@1429: return descriptor; Chris@1429: } Chris@1429: ++index; Chris@0: } Chris@0: Chris@843: cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label << " in library " << soname << endl; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: const LADSPA_Descriptor * Chris@0: DSSIPluginFactory::getLADSPADescriptor(QString identifier) Chris@0: { Chris@0: const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier); Chris@0: if (dssiDescriptor) return dssiDescriptor->LADSPA_Plugin; Chris@0: else return 0; Chris@0: } Chris@0: Chris@0: Chris@0: std::vector Chris@0: DSSIPluginFactory::getPluginPath() Chris@0: { Chris@0: std::vector pathList; Chris@0: std::string path; Chris@0: Chris@0: char *cpath = getenv("DSSI_PATH"); Chris@0: if (cpath) path = cpath; Chris@0: Chris@0: if (path == "") { Chris@186: Chris@186: path = DEFAULT_DSSI_PATH; Chris@186: Chris@1429: char *home = getenv("HOME"); Chris@1429: if (home) { Chris@186: std::string::size_type f; Chris@186: while ((f = path.find("$HOME")) != std::string::npos && Chris@186: f < path.length()) { Chris@186: path.replace(f, 5, home); Chris@186: } Chris@66: } Chris@186: Chris@186: #ifdef _WIN32 Chris@1218: const char *pfiles = getenv("ProgramFiles"); Chris@220: if (!pfiles) pfiles = "C:\\Program Files"; Chris@220: { Chris@186: std::string::size_type f; Chris@186: while ((f = path.find("%ProgramFiles%")) != std::string::npos && Chris@186: f < path.length()) { Chris@186: path.replace(f, 14, pfiles); Chris@186: } Chris@220: } Chris@186: #endif Chris@0: } Chris@0: Chris@0: std::string::size_type index = 0, newindex = 0; Chris@0: Chris@223: while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) { Chris@1429: pathList.push_back(path.substr(index, newindex - index).c_str()); Chris@1429: index = newindex + 1; Chris@0: } Chris@0: Chris@0: pathList.push_back(path.substr(index).c_str()); Chris@0: Chris@0: return pathList; Chris@0: } Chris@0: Chris@0: Chris@0: std::vector Chris@0: DSSIPluginFactory::getLRDFPath(QString &baseUri) Chris@0: { Chris@150: std::vector lrdfPaths; Chris@150: Chris@150: #ifdef HAVE_LRDF Chris@0: std::vector pathList = getPluginPath(); Chris@0: Chris@0: lrdfPaths.push_back("/usr/local/share/dssi/rdf"); Chris@0: lrdfPaths.push_back("/usr/share/dssi/rdf"); Chris@0: Chris@0: lrdfPaths.push_back("/usr/local/share/ladspa/rdf"); Chris@0: lrdfPaths.push_back("/usr/share/ladspa/rdf"); Chris@0: Chris@0: for (std::vector::iterator i = pathList.begin(); Chris@1429: i != pathList.end(); ++i) { Chris@1429: lrdfPaths.push_back(*i + "/rdf"); Chris@0: } Chris@0: Chris@0: #ifdef DSSI_BASE Chris@0: baseUri = DSSI_BASE; Chris@0: #else Chris@0: baseUri = "http://dssi.sourceforge.net/ontology#"; Chris@0: #endif Chris@953: #else Chris@953: // avoid unused parameter Chris@953: baseUri = ""; Chris@150: #endif Chris@0: Chris@0: return lrdfPaths; Chris@0: } Chris@0: Chris@0: Chris@0: void Chris@929: DSSIPluginFactory::discoverPluginsFrom(QString soname) Chris@0: { Chris@408: Profiler profiler("DSSIPluginFactory::discoverPlugins"); Chris@408: Chris@0: // Note that soname is expected to be a full path at this point, Chris@0: // of a file that is known to exist Chris@0: Chris@0: void *libraryHandle = DLOPEN(soname, RTLD_LAZY); Chris@0: Chris@0: if (!libraryHandle) { Chris@843: cerr << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library " Chris@843: << soname << " - " << DLERROR() << endl; Chris@0: return; Chris@0: } Chris@0: Chris@0: DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function) Chris@1429: DLSYM(libraryHandle, "dssi_descriptor"); Chris@0: Chris@0: if (!fn) { Chris@1429: cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname << endl; Chris@1429: return; Chris@0: } Chris@0: Chris@0: const DSSI_Descriptor *descriptor = 0; Chris@0: Chris@0: int index = 0; Chris@0: while ((descriptor = fn(index))) { Chris@0: Chris@1429: const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin; Chris@1429: if (!ladspaDescriptor) { Chris@1429: cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname << endl; Chris@1429: ++index; Chris@1429: continue; Chris@1429: } Chris@0: Chris@60: RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor; Chris@60: rtd->name = ladspaDescriptor->Name; Chris@60: rtd->label = ladspaDescriptor->Label; Chris@60: rtd->maker = ladspaDescriptor->Maker; Chris@60: rtd->copyright = ladspaDescriptor->Copyright; Chris@60: rtd->category = ""; Chris@60: rtd->isSynth = (descriptor->run_synth || Chris@60: descriptor->run_multiple_synths); Chris@60: rtd->parameterCount = 0; Chris@60: rtd->audioInputPortCount = 0; Chris@166: rtd->audioOutputPortCount = 0; Chris@60: rtd->controlOutputPortCount = 0; Chris@60: Chris@1429: QString identifier = PluginIdentifier::createIdentifier Chris@1429: ("dssi", soname, ladspaDescriptor->Label); Chris@165: Chris@35: #ifdef HAVE_LRDF Chris@1429: char *def_uri = 0; Chris@1429: lrdf_defaults *defs = 0; Chris@1429: Chris@1429: QString category = m_taxonomy[identifier]; Chris@165: Chris@166: if (category == "" && m_lrdfTaxonomy[ladspaDescriptor->UniqueID] != "") { Chris@166: m_taxonomy[identifier] = m_lrdfTaxonomy[ladspaDescriptor->UniqueID]; Chris@165: category = m_taxonomy[identifier]; Chris@165: } Chris@0: Chris@1429: if (category == "") { Chris@1429: std::string name = rtd->name; Chris@1429: if (name.length() > 4 && Chris@1429: name.substr(name.length() - 4) == " VST") { Chris@1429: if (descriptor->run_synth || descriptor->run_multiple_synths) { Chris@1429: category = "VST instruments"; Chris@1429: } else { Chris@1429: category = "VST effects"; Chris@1429: } Chris@1429: m_taxonomy[identifier] = category; Chris@1429: } Chris@1429: } Chris@60: Chris@60: rtd->category = category.toStdString(); Chris@1429: Chris@1429: // cerr << "Plugin id is " << ladspaDescriptor->UniqueID Chris@844: // << ", identifier is \"" << identifier Chris@1429: // << "\", category is \"" << category Chris@1429: // << "\", name is " << ladspaDescriptor->Name Chris@1429: // << ", label is " << ladspaDescriptor->Label Chris@1429: // << endl; Chris@1429: Chris@1429: def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID); Chris@1429: if (def_uri) { Chris@1429: defs = lrdf_get_setting_values(def_uri); Chris@1429: } Chris@1429: Chris@1429: unsigned int controlPortNumber = 1; Chris@1429: Chris@1429: for (int i = 0; i < (int)ladspaDescriptor->PortCount; i++) { Chris@1429: Chris@1429: if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) { Chris@1429: Chris@1429: if (def_uri && defs) { Chris@1429: Chris@1429: for (int j = 0; j < (int)defs->count; j++) { Chris@1429: if (defs->items[j].pid == controlPortNumber) { Chris@1429: // 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; Chris@1429: m_portDefaults[ladspaDescriptor->UniqueID][i] = Chris@1429: defs->items[j].value; Chris@1429: } Chris@1429: } Chris@1429: } Chris@1429: Chris@1429: ++controlPortNumber; Chris@1429: } Chris@1429: } Chris@35: #endif // HAVE_LRDF Chris@0: Chris@1429: for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) { Chris@1429: if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) { Chris@60: if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) { Chris@60: ++rtd->parameterCount; Chris@60: } else { Chris@60: if (strcmp(ladspaDescriptor->PortNames[i], "latency") && Chris@60: strcmp(ladspaDescriptor->PortNames[i], "_latency")) { Chris@60: ++rtd->controlOutputPortCount; Chris@60: rtd->controlOutputPortNames.push_back Chris@60: (ladspaDescriptor->PortNames[i]); Chris@60: } Chris@60: } Chris@60: } else { Chris@60: if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) { Chris@60: ++rtd->audioInputPortCount; Chris@166: } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) { Chris@166: ++rtd->audioOutputPortCount; Chris@60: } Chris@60: } Chris@60: } Chris@60: Chris@1429: m_identifiers.push_back(identifier); Chris@0: Chris@60: m_rtDescriptors[identifier] = rtd; Chris@60: Chris@1429: ++index; Chris@0: } Chris@0: Chris@0: if (DLCLOSE(libraryHandle) != 0) { Chris@843: cerr << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << endl; Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: Chris@0: