Chris@0: /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: A waveform viewer and audio annotation editor. Chris@2: Chris Cannam, Queen Mary University of London, 2005-2006 Chris@0: Chris@0: This is experimental software. Not for distribution. 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@0: This file copyright 2000-2005 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@0: //!!! Chris@0: #include "plugins/SamplePlayer.h" Chris@0: Chris@0: #include "base/System.h" Chris@0: Chris@0: #ifdef HAVE_LIBLRDF Chris@0: #include "lrdf.h" Chris@0: #endif // HAVE_LIBLRDF 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@0: for (std::vector::iterator i = m_identifiers.begin(); Chris@0: i != m_identifiers.end(); ++i) { Chris@0: Chris@0: const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i); Chris@0: if (!ddesc) continue; Chris@0: Chris@0: const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin; Chris@0: if (!descriptor) continue; Chris@0: Chris@0: // std::cerr << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << std::endl; Chris@0: Chris@0: list.push_back(*i); Chris@0: list.push_back(descriptor->Name); Chris@0: list.push_back(QString("%1").arg(descriptor->UniqueID)); Chris@0: list.push_back(descriptor->Label); Chris@0: list.push_back(descriptor->Maker); Chris@0: list.push_back(descriptor->Copyright); Chris@0: list.push_back((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false"); Chris@0: list.push_back(ddesc->run_multiple_synths ? "true" : "false"); Chris@0: list.push_back(m_taxonomy[descriptor->UniqueID]); Chris@0: list.push_back(QString("%1").arg(descriptor->PortCount)); Chris@0: Chris@0: for (unsigned long p = 0; p < descriptor->PortCount; ++p) { Chris@0: Chris@0: int type = 0; Chris@0: if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) { Chris@0: type |= PortType::Control; Chris@0: } else { Chris@0: type |= PortType::Audio; Chris@0: } Chris@0: if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) { Chris@0: type |= PortType::Input; Chris@0: } else { Chris@0: type |= PortType::Output; Chris@0: } Chris@0: Chris@0: list.push_back(QString("%1").arg(p)); Chris@0: list.push_back(descriptor->PortNames[p]); Chris@0: list.push_back(QString("%1").arg(type)); Chris@0: list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p))); Chris@0: list.push_back(QString("%1").arg(getPortMinimum(descriptor, p))); Chris@0: list.push_back(QString("%1").arg(getPortMaximum(descriptor, p))); Chris@0: list.push_back(QString("%1").arg(getPortDefault(descriptor, p))); Chris@0: } Chris@0: } Chris@0: Chris@0: unloadUnusedLibraries(); Chris@0: } Chris@0: Chris@0: RealTimePluginInstance * Chris@0: DSSIPluginFactory::instantiatePlugin(QString identifier, Chris@0: int instrument, Chris@0: int position, Chris@0: unsigned int sampleRate, Chris@0: unsigned int blockSize, Chris@0: unsigned int channels) Chris@0: { Chris@0: const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier); Chris@0: Chris@0: if (descriptor) { Chris@0: Chris@0: DSSIPluginInstance *instance = Chris@0: new DSSIPluginInstance Chris@0: (this, instrument, identifier, position, sampleRate, blockSize, channels, Chris@0: descriptor); Chris@0: Chris@0: m_instances.insert(instance); Chris@0: Chris@0: 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@0: if (label == "sample_player") { Chris@0: const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0); Chris@0: if (descriptor) { Chris@0: descriptor->receive_host_descriptor(&m_hostDescriptor); Chris@0: } Chris@0: return descriptor; Chris@0: } else { Chris@0: return 0; Chris@0: } Chris@0: } Chris@0: Chris@0: bool firstInLibrary = false; Chris@0: Chris@0: if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { Chris@0: loadLibrary(soname); Chris@0: if (m_libraryHandles.find(soname) == m_libraryHandles.end()) { Chris@0: std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname.toStdString() << std::endl; Chris@0: return 0; Chris@0: } Chris@0: 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@0: DLSYM(libraryHandle, "dssi_descriptor"); Chris@0: Chris@0: if (!fn) { Chris@0: std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname.toStdString() << std::endl; Chris@0: 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@0: if (descriptor->LADSPA_Plugin->Label == label) { Chris@0: if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) { Chris@0: descriptor->receive_host_descriptor(&m_hostDescriptor); Chris@0: } Chris@0: return descriptor; Chris@0: } Chris@0: ++index; Chris@0: } Chris@0: Chris@0: std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label.toStdString() << " in library " << soname.toStdString() << std::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@0: path = "/usr/local/lib/dssi:/usr/lib/dssi"; Chris@0: char *home = getenv("HOME"); Chris@0: if (home) path = std::string(home) + "/.dssi:" + path; Chris@0: } Chris@0: Chris@0: std::string::size_type index = 0, newindex = 0; Chris@0: Chris@0: while ((newindex = path.find(':', index)) < path.size()) { Chris@0: pathList.push_back(path.substr(index, newindex - index).c_str()); Chris@0: 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: #ifdef HAVE_LIBLRDF Chris@0: std::vector Chris@0: DSSIPluginFactory::getLRDFPath(QString &baseUri) Chris@0: { Chris@0: std::vector pathList = getPluginPath(); Chris@0: std::vector lrdfPaths; 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@0: i != pathList.end(); ++i) { Chris@0: 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@0: Chris@0: return lrdfPaths; Chris@0: } Chris@0: #endif Chris@0: Chris@0: Chris@0: void Chris@0: DSSIPluginFactory::discoverPlugins(QString soname) Chris@0: { 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@0: std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library " Chris@0: << soname.toStdString() << " - " << DLERROR() << std::endl; Chris@0: return; Chris@0: } Chris@0: Chris@0: DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function) Chris@0: DLSYM(libraryHandle, "dssi_descriptor"); Chris@0: Chris@0: if (!fn) { Chris@0: std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname.toStdString() << std::endl; Chris@0: 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@0: const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin; Chris@0: if (!ladspaDescriptor) { Chris@0: std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname.toStdString() << std::endl; Chris@0: ++index; Chris@0: continue; Chris@0: } Chris@0: Chris@0: #ifdef HAVE_LIBLRDF Chris@0: char *def_uri = 0; Chris@0: lrdf_defaults *defs = 0; Chris@0: Chris@0: QString category = m_taxonomy[ladspaDescriptor->UniqueID]; Chris@0: Chris@0: if (category == "" && ladspaDescriptor->Name != 0) { Chris@0: std::string name = ladspaDescriptor->Name; Chris@0: if (name.length() > 4 && Chris@0: name.substr(name.length() - 4) == " VST") { Chris@0: if (descriptor->run_synth || descriptor->run_multiple_synths) { Chris@0: category = "VST instruments"; Chris@0: } else { Chris@0: category = "VST effects"; Chris@0: } Chris@0: m_taxonomy[ladspaDescriptor->UniqueID] = category; Chris@0: } Chris@0: } Chris@0: Chris@0: // std::cerr << "Plugin id is " << ladspaDescriptor->UniqueID Chris@0: // << ", category is \"" << (category ? category : QString("(none)")) Chris@0: // << "\", name is " << ladspaDescriptor->Name Chris@0: // << ", label is " << ladspaDescriptor->Label Chris@0: // << std::endl; Chris@0: Chris@0: def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID); Chris@0: if (def_uri) { Chris@0: defs = lrdf_get_setting_values(def_uri); Chris@0: } Chris@0: Chris@0: int controlPortNumber = 1; Chris@0: Chris@0: for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) { Chris@0: Chris@0: if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) { Chris@0: Chris@0: if (def_uri && defs) { Chris@0: Chris@0: for (int j = 0; j < defs->count; j++) { Chris@0: if (defs->items[j].pid == controlPortNumber) { Chris@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; Chris@0: m_portDefaults[ladspaDescriptor->UniqueID][i] = Chris@0: defs->items[j].value; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: ++controlPortNumber; Chris@0: } Chris@0: } Chris@0: #endif // HAVE_LIBLRDF Chris@0: Chris@0: QString identifier = PluginIdentifier::createIdentifier Chris@0: ("dssi", soname, ladspaDescriptor->Label); Chris@0: m_identifiers.push_back(identifier); Chris@0: Chris@0: ++index; Chris@0: } Chris@0: Chris@0: if (DLCLOSE(libraryHandle) != 0) { Chris@0: std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << std::endl; Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: Chris@0: