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