X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_manager.cc;h=b0d40f6124a14aa61a69da4702f4c0334fbc64bf;hb=535d60237486e2227d22e5febbcfbf868abb11e3;hp=af7bc0f906f207b3d42d2a12a6bf8eb099383650;hpb=49ab8ea4551ec82ae8b561cb256f762fd7f831f2;p=ardour.git diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index af7bc0f906..b0d40f6124 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2004 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,50 +15,84 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#ifdef WAF_BUILD +#include "libardour-config.h" +#endif + +#define __STDC_FORMAT_MACROS 1 +#include + #include #include #include #include +#include +#include #ifdef VST_SUPPORT #include -#include -#include +#include "pbd/basename.h" +#include #endif // VST_SUPPORT -#include +#include + +#include "pbd/pathscanner.h" +#include "pbd/whitespace.h" + +#include "ardour/ladspa.h" +#include "ardour/session.h" +#include "ardour/plugin_manager.h" +#include "ardour/plugin.h" +#include "ardour/ladspa_plugin.h" +#include "ardour/filesystem_paths.h" + +#ifdef HAVE_SLV2 +#include +#include "ardour/lv2_plugin.h" +#endif -#include -#include -#include -#include -#include -#include +#ifdef VST_SUPPORT +#include "ardour/vst_plugin.h" +#endif -#include -#include +#ifdef HAVE_AUDIOUNITS +#include "ardour/audio_unit.h" +#include +#endif -#ifdef HAVE_COREAUDIO -#include -#include -#endif // HAVE_COREAUDIO +#include "pbd/error.h" +#include "pbd/stl_delete.h" #include "i18n.h" using namespace ARDOUR; using namespace PBD; +using namespace std; PluginManager* PluginManager::_manager = 0; -PluginManager::PluginManager (AudioEngine& e) - : _engine (e) +PluginManager::PluginManager () + : _vst_plugin_info(0) + , _ladspa_plugin_info(0) + , _lv2_plugin_info(0) + , _au_plugin_info(0) { char* s; string lrdf_path; + load_statuses (); + +#ifdef HAVE_AUDIOUNITS + ProcessSerialNumber psn = { 0, kCurrentProcess }; + OSStatus returnCode = TransformProcessType(& psn, kProcessTransformToForegroundApplication); + if( returnCode != 0) { + error << _("Cannot become GUI app") << endmsg; + } +#endif + if ((s = getenv ("LADSPA_RDF_PATH"))){ lrdf_path = s; } @@ -85,44 +119,97 @@ PluginManager::PluginManager (AudioEngine& e) vst_path = s; } - refresh (); - if (_manager == 0) { _manager = this; } + + /* the plugin manager is constructed too early to use Profile */ + + if (getenv ("ARDOUR_SAE")) { + ladspa_plugin_whitelist.push_back (1203); // single band parametric + ladspa_plugin_whitelist.push_back (1772); // caps compressor + ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter + ladspa_plugin_whitelist.push_back (1075); // simple RMS expander + ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s) + ladspa_plugin_whitelist.push_back (1216); // gverb + ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter + } + +#ifdef HAVE_SLV2 + _lv2_world = new LV2World(); +#endif + + BootMessage (_("Discovering Plugins")); } void PluginManager::refresh () { ladspa_refresh (); +#ifdef HAVE_SLV2 + lv2_refresh (); +#endif #ifdef VST_SUPPORT if (Config->get_use_vst()) { vst_refresh (); } #endif // VST_SUPPORT +#ifdef HAVE_AUDIOUNITS + au_refresh (); +#endif -#ifdef HAVE_COREAUDIO - au_discover (); -#endif // HAVE_COREAUDIO + PluginListChanged (); /* EMIT SIGNAL */ } void PluginManager::ladspa_refresh () { - for (std::list::iterator i = _ladspa_plugin_info.begin(); i != _ladspa_plugin_info.end(); ++i) { - delete *i; - } + if (_ladspa_plugin_info) + _ladspa_plugin_info->clear (); + else + _ladspa_plugin_info = new ARDOUR::PluginInfoList (); + + static const char *standard_paths[] = { + "/usr/local/lib64/ladspa", + "/usr/local/lib/ladspa", + "/usr/lib64/ladspa", + "/usr/lib/ladspa", + "/Library/Audio/Plug-Ins/LADSPA", + "" + }; + + /* allow LADSPA_PATH to augment, not override standard locations */ + + /* Only add standard locations to ladspa_path if it doesn't + * already contain them. Check for trailing '/'s too. + */ + + int i; + for (i = 0; standard_paths[i][0]; i++) { + size_t found = ladspa_path.find(standard_paths[i]); + if (found != ladspa_path.npos) { + switch (ladspa_path[found + strlen(standard_paths[i])]) { + case ':' : + case '\0': + continue; + case '/' : + if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' || + ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') { + continue; + } + } + } + if (!ladspa_path.empty()) + ladspa_path += ":"; - _ladspa_plugin_info.clear (); + ladspa_path += standard_paths[i]; - if (ladspa_path.length() == 0) { - ladspa_path = "/usr/local/lib/ladspa:/usr/lib/ladspa"; } ladspa_discover_from_path (ladspa_path); } + int PluginManager::add_ladspa_directory (string path) { @@ -130,19 +217,19 @@ PluginManager::add_ladspa_directory (string path) ladspa_path += ':'; ladspa_path += path; return 0; - } + } return -1; } -static bool ladspa_filter (const string& str, void *arg) +static bool ladspa_filter (const string& str, void */*arg*/) { /* Not a dotfile, has a prefix before a period, suffix is "so" */ - + return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3)); } int -PluginManager::ladspa_discover_from_path (string path) +PluginManager::ladspa_discover_from_path (string /*path*/) { PathScanner scanner; vector *plugin_objects; @@ -161,12 +248,13 @@ PluginManager::ladspa_discover_from_path (string path) return ret; } -static bool rdf_filter (const string &str, void *arg) +static bool rdf_filter (const string &str, void* /*arg*/) { - return str[0] != '.' && + return str[0] != '.' && ((str.find(".rdf") == (str.length() - 4)) || (str.find(".rdfs") == (str.length() - 5)) || - (str.find(".n3") == (str.length() - 3))); + (str.find(".n3") == (str.length() - 3)) || + (str.find(".ttl") == (str.length() - 4))); } void @@ -231,10 +319,9 @@ PluginManager::add_lrdf_data (const string &path) vector_delete (rdf_files); } -int +int PluginManager::ladspa_discover (string path) { - PluginInfo *info; void *module; const LADSPA_Descriptor *descriptor; LADSPA_Descriptor_Function dfunc; @@ -259,113 +346,60 @@ PluginManager::ladspa_discover (string path) break; } - info = new PluginInfo; + if (!ladspa_plugin_whitelist.empty()) { + if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) { + continue; + } + } + + PluginInfoPtr info(new LadspaPluginInfo); info->name = descriptor->Name; info->category = get_ladspa_category(descriptor->UniqueID); + info->creator = descriptor->Maker; info->path = path; info->index = i; - info->n_inputs = 0; - info->n_outputs = 0; - info->type = PluginInfo::LADSPA; - info->unique_id = descriptor->UniqueID; - + info->n_inputs = ChanCount(); + info->n_outputs = ChanCount(); + info->type = ARDOUR::LADSPA; + + char buf[32]; + snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID); + info->unique_id = buf; + for (uint32_t n=0; n < descriptor->PortCount; ++n) { if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) { if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) { - info->n_inputs++; + info->n_inputs.set_audio(info->n_inputs.n_audio() + 1); } else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) { - info->n_outputs++; + info->n_outputs.set_audio(info->n_outputs.n_audio() + 1); } } } - _ladspa_plugin_info.push_back (info); - } - -// GDB WILL NOT LIKE YOU IF YOU DO THIS -// dlclose (module); - - return 0; -} - -boost::shared_ptr -PluginManager::load (Session& session, PluginInfo *info) -{ - void *module; + if(_ladspa_plugin_info->empty()){ + _ladspa_plugin_info->push_back (info); + } - try { - boost::shared_ptr plugin; + //Ensure that the plugin is not already in the plugin list. - if (info->type == PluginInfo::VST) { + bool found = false; -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - FSTHandle* handle; - - if ((handle = fst_load (info->path.c_str())) == 0) { - error << string_compose(_("VST: cannot load module from \"%1\""), info->path) << endmsg; - } else { - plugin.reset (new VSTPlugin (_engine, session, handle)); - } - } else { - error << _("You asked ardour to not use any VST plugins") << endmsg; - } -#else // !VST_SUPPORT - error << _("This version of ardour has no support for VST plugins") << endmsg; - return boost::shared_ptr ((Plugin*) 0); -#endif // !VST_SUPPORT - - } else { - - if ((module = dlopen (info->path.c_str(), RTLD_NOW)) == 0) { - error << string_compose(_("LADSPA: cannot load module from \"%1\""), info->path) << endmsg; - error << dlerror() << endmsg; - } else { - plugin.reset (new LadspaPlugin (module, _engine, session, info->index, session.frame_rate())); + for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) { + if(0 == info->unique_id.compare((*i)->unique_id)){ + found = true; } } - plugin->set_info(*info); - return plugin; + if(!found){ + _ladspa_plugin_info->push_back (info); + } } - catch (failed_constructor &err) { - return boost::shared_ptr ((Plugin*) 0); - } -} +// GDB WILL NOT LIKE YOU IF YOU DO THIS +// dlclose (module); -boost::shared_ptr -ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) -{ - PluginManager *mgr = PluginManager::the_manager(); - list::iterator i; - list* plugs = 0; - - switch (type) { - case PluginInfo::LADSPA: - plugs = &mgr->ladspa_plugin_info(); - break; - case PluginInfo::VST: - plugs = &mgr->vst_plugin_info(); - unique_id = 0; // VST plugins don't have a unique id. - break; - case PluginInfo::AudioUnit: - plugs = &mgr->au_plugin_info(); - unique_id = 0; - break; - default: - return boost::shared_ptr ((Plugin *) 0); - } - - for (i = plugs->begin(); i != plugs->end(); ++i) { - if ((name == "" || (*i)->name == name) && - (unique_id == 0 || (*i)->unique_id == unique_id)) { - return mgr->load (session, *i); - } - } - - return boost::shared_ptr ((Plugin*) 0); + return 0; } string @@ -376,18 +410,18 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id); pattern.subject = buf; - pattern.predicate = RDF_TYPE; + pattern.predicate = (char*)RDF_TYPE; pattern.object = 0; pattern.object_type = lrdf_uri; lrdf_statement* matches1 = lrdf_matches (&pattern); if (!matches1) { - return _("Unknown"); + return "Unknown"; } pattern.subject = matches1->object; - pattern.predicate = LADSPA_BASE "hasLabel"; + pattern.predicate = (char*)(LADSPA_BASE "hasLabel"); pattern.object = 0; pattern.object_type = lrdf_literal; @@ -395,7 +429,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) lrdf_free_statements(matches1); if (!matches2) { - return _("Unknown"); + return ("Unknown"); } string label = matches2->object; @@ -404,16 +438,34 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) return label; } +#ifdef HAVE_SLV2 +void +PluginManager::lv2_refresh () +{ + delete _lv2_plugin_info; + _lv2_plugin_info = LV2PluginInfo::discover(_lv2_world); +} +#endif + +#ifdef HAVE_AUDIOUNITS +void +PluginManager::au_refresh () +{ + delete _au_plugin_info; + _au_plugin_info = AUPluginInfo::discover(); +} + +#endif + #ifdef VST_SUPPORT void PluginManager::vst_refresh () { - for (std::list::iterator i = _vst_plugin_info.begin(); i != _vst_plugin_info.end(); ++i) { - delete *i; - } - - _vst_plugin_info.clear (); + if (_vst_plugin_info) + _vst_plugin_info->clear (); + else + _vst_plugin_info = new ARDOUR::PluginInfoList(); if (vst_path.length() == 0) { vst_path = "/usr/local/lib/vst:/usr/lib/vst"; @@ -429,14 +481,14 @@ PluginManager::add_vst_directory (string path) vst_path += ':'; vst_path += path; return 0; - } + } return -1; } static bool vst_filter (const string& str, void *arg) { /* Not a dotfile, has a prefix before a period, suffix is "dll" */ - + return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4)); } @@ -466,9 +518,10 @@ int PluginManager::vst_discover (string path) { FSTInfo* finfo; - PluginInfo* info; + char buf[32]; if ((finfo = fst_get_info (const_cast (path.c_str()))) == 0) { + warning << "Cannot get VST information from " << path << endmsg; return -1; } @@ -477,10 +530,10 @@ PluginManager::vst_discover (string path) finfo->name) << endl; } - - info = new PluginInfo; - /* what a goddam joke freeware VST is */ + PluginInfoPtr info(new VSTPluginInfo); + + /* what a joke freeware VST is */ if (!strcasecmp ("The Unnamed plugin", finfo->name)) { info->name = PBD::basename_nosuffix (path); @@ -488,14 +541,18 @@ PluginManager::vst_discover (string path) info->name = finfo->name; } + + snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); + info->unique_id = buf; info->category = "VST"; info->path = path; + info->creator = finfo->creator; info->index = 0; - info->n_inputs = finfo->numInputs; - info->n_outputs = finfo->numOutputs; - info->type = PluginInfo::VST; - - _vst_plugin_info.push_back (info); + info->n_inputs.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->type = ARDOUR::VST; + + _vst_plugin_info->push_back (info); fst_free_info (finfo); return 0; @@ -503,93 +560,197 @@ PluginManager::vst_discover (string path) #endif // VST_SUPPORT -#ifdef HAVE_COREAUDIO +PluginManager::PluginStatusType +PluginManager::get_status (const PluginInfoPtr& pi) +{ + PluginStatus ps (pi->type, pi->unique_id); + PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps); + if (i == statuses.end() ) { + return Normal; + } else { + return i->status; + } +} -int -PluginManager::au_discover () +void +PluginManager::save_statuses () { - _au_plugin_info.clear (); + ofstream ofs; + sys::path path = user_config_directory(); + path /= "plugin_statuses"; + + ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc)); + + if (!ofs) { + return; + } + + for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) { + switch ((*i).type) { + case LADSPA: + ofs << "LADSPA"; + break; + case AudioUnit: + ofs << "AudioUnit"; + break; + case LV2: + ofs << "LV2"; + break; + case VST: + ofs << "VST"; + break; + } + + ofs << ' '; + + switch ((*i).status) { + case Normal: + ofs << "Normal"; + break; + case Favorite: + ofs << "Favorite"; + break; + case Hidden: + ofs << "Hidden"; + break; + } - int numTypes = 2; // this magic number was retrieved from the apple AUHost example. + ofs << ' '; + ofs << (*i).unique_id;; + ofs << endl; + } + + ofs.close (); +} + +void +PluginManager::load_statuses () +{ + sys::path path = user_config_directory(); + path /= "plugin_statuses"; + ifstream ifs (path.to_string().c_str()); - ComponentDescription desc; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - desc.componentSubType = 0; - desc.componentManufacturer = 0; + if (!ifs) { + return; + } - vector vCompDescs; + std::string stype; + std::string sstatus; + std::string id; + PluginType type; + PluginStatusType status; + char buf[1024]; + + while (ifs) { + + ifs >> stype; + if (!ifs) { + break; - for (int i = 0; i < numTypes; ++i) { - if (i == 1) { - desc.componentType = kAudioUnitType_MusicEffect; - } else { - desc.componentType = kAudioUnitType_Effect; } - - Component comp = 0; - - comp = FindNextComponent (NULL, &desc); - while (comp != NULL) { - ComponentDescription temp; - GetComponentInfo (comp, &temp, NULL, NULL, NULL); - vCompDescs.push_back(temp); - comp = FindNextComponent (comp, &desc); + + ifs >> sstatus; + if (!ifs) { + break; + } - } - PluginInfo* plug; - for (unsigned int i = 0; i < vCompDescs.size(); ++i) { - - // the following large block is just for determining the name of the plugin. - CFStringRef itemName = NULL; - // Marc Poirier -style item name - Component auComponent = FindNextComponent (0, &(vCompDescs[i])); - if (auComponent != NULL) { - ComponentDescription dummydesc; - Handle nameHandle = NewHandle(sizeof(void*)); - if (nameHandle != NULL) { - OSErr err = GetComponentInfo(auComponent, &dummydesc, nameHandle, NULL, NULL); - if (err == noErr) { - ConstStr255Param nameString = (ConstStr255Param) (*nameHandle); - if (nameString != NULL) { - itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding()); - } - } - DisposeHandle(nameHandle); - } + /* rest of the line is the plugin ID */ + + ifs.getline (buf, sizeof (buf), '\n'); + if (!ifs) { + break; } - - // if Marc-style fails, do the original way - if (itemName == NULL) { - CFStringRef compTypeString = UTCreateStringForOSType(vCompDescs[i].componentType); - CFStringRef compSubTypeString = UTCreateStringForOSType(vCompDescs[i].componentSubType); - CFStringRef compManufacturerString = UTCreateStringForOSType(vCompDescs[i].componentManufacturer); - - itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), - compTypeString, compManufacturerString, compSubTypeString); - - if (compTypeString != NULL) - CFRelease(compTypeString); - if (compSubTypeString != NULL) - CFRelease(compSubTypeString); - if (compManufacturerString != NULL) - CFRelease(compManufacturerString); + + if (sstatus == "Normal") { + status = Normal; + } else if (sstatus == "Favorite") { + status = Favorite; + } else if (sstatus == "Hidden") { + status = Hidden; + } else { + error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus) + << endmsg; + statuses.clear (); + break; + } + + if (stype == "LADSPA") { + type = LADSPA; + } else if (stype == "AudioUnit") { + type = AudioUnit; + } else if (stype == "LV2") { + type = LV2; + } else if (stype == "VST") { + type = VST; + } else { + error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype) + << endmsg; + continue; } - string realname = CFStringRefToStdString(itemName); - - plug = new PluginInfo; - plug->name = realname; - plug->type = PluginInfo::AudioUnit; - plug->n_inputs = 0; - plug->n_outputs = 0; - plug->category = "AudioUnit"; - _au_plugin_info.push_back(plug); + id = buf; + strip_whitespace_edges (id); + set_status (type, id, status); + } + + ifs.close (); +} + +void +PluginManager::set_status (PluginType t, string id, PluginStatusType status) +{ + PluginStatus ps (t, id, status); + statuses.erase (ps); + + if (status == Normal) { + return; } - return 0; + pair res = statuses.insert (ps); + //cerr << "Added " << t << " " << id << " " << status << " success ? " << res.second << endl; +} + +ARDOUR::PluginInfoList& +PluginManager::vst_plugin_info () +{ +#ifdef VST_SUPPORT + if (!_vst_plugin_info) + vst_refresh(); + return *_vst_plugin_info; +#else + return _empty_plugin_info; +#endif } -#endif // HAVE_COREAUDIO +ARDOUR::PluginInfoList& +PluginManager::ladspa_plugin_info () +{ + if (!_ladspa_plugin_info) + ladspa_refresh(); + return *_ladspa_plugin_info; +} +ARDOUR::PluginInfoList& +PluginManager::lv2_plugin_info () +{ +#ifdef HAVE_SLV2 + if (!_lv2_plugin_info) + lv2_refresh(); + return *_lv2_plugin_info; +#else + return _empty_plugin_info; +#endif +} + +ARDOUR::PluginInfoList& +PluginManager::au_plugin_info () +{ +#ifdef HAVE_AUDIOUNITS + if (!_au_plugin_info) + au_refresh(); + return *_au_plugin_info; +#else + return _empty_plugin_info; +#endif +}