X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_manager.cc;h=613fc85c6d6bd983628bad77c6f438547b1a0164;hb=0938a42440cc82ce8d0cb064840c258c863714ab;hp=bf624127005324ae31d424c23131d905eac7afe9;hpb=e0aaed6d65f160c328cb8b56d7c6552ee15d65e2;p=ardour.git diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index bf62412700..613fc85c6d 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2006 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 @@ -17,7 +17,10 @@ */ -#define __STDC_FORMAT_MACROS 1 +#ifdef WAF_BUILD +#include "libardour-config.h" +#endif + #include #include @@ -33,9 +36,16 @@ #include #endif // VST_SUPPORT +#ifdef LXVST_SUPPORT +#include +#include +#include +#endif //LXVST_SUPPORT + #include #include "pbd/pathscanner.h" +#include "pbd/whitespace.h" #include "ardour/ladspa.h" #include "ardour/session.h" @@ -44,8 +54,7 @@ #include "ardour/ladspa_plugin.h" #include "ardour/filesystem_paths.h" -#ifdef HAVE_SLV2 -#include +#ifdef LV2_SUPPORT #include "ardour/lv2_plugin.h" #endif @@ -53,6 +62,10 @@ #include "ardour/vst_plugin.h" #endif +#ifdef LXVST_SUPPORT +#include "ardour/lxvst_plugin.h" +#endif + #ifdef HAVE_AUDIOUNITS #include "ardour/audio_unit.h" #include @@ -70,14 +83,19 @@ using namespace std; PluginManager* PluginManager::_manager = 0; PluginManager::PluginManager () + : _vst_plugin_info(0) + , _lxvst_plugin_info(0) + , _ladspa_plugin_info(0) + , _lv2_plugin_info(0) + , _au_plugin_info(0) { char* s; string lrdf_path; - load_favorites (); + load_statuses (); -#ifdef GTKOSX - ProcessSerialNumber psn = { 0, kCurrentProcess }; +#ifdef HAVE_AUDIOUNITS + ProcessSerialNumber psn = { 0, kCurrentProcess }; OSStatus returnCode = TransformProcessType(& psn, kProcessTransformToForegroundApplication); if( returnCode != 0) { error << _("Cannot become GUI app") << endmsg; @@ -100,6 +118,12 @@ PluginManager::PluginManager () } #endif /* VST_SUPPORT */ +#ifdef LXVST_SUPPORT + if (Config->get_use_lxvst()) { + add_lxvst_presets(); + } +#endif /* Native LinuxVST support*/ + if ((s = getenv ("LADSPA_PATH"))) { ladspa_path = s; } @@ -110,6 +134,12 @@ PluginManager::PluginManager () vst_path = s; } + if ((s = getenv ("LXVST_PATH"))) { + lxvst_path = s; + } else if ((s = getenv ("LXVST_PLUGINS"))) { + lxvst_path = s; + } + if (_manager == 0) { _manager = this; } @@ -124,22 +154,22 @@ PluginManager::PluginManager () 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")); +} - refresh (); + +PluginManager::~PluginManager() +{ } + void PluginManager::refresh () { ladspa_refresh (); -#ifdef HAVE_SLV2 +#ifdef LV2_SUPPORT lv2_refresh (); #endif #ifdef VST_SUPPORT @@ -147,53 +177,65 @@ PluginManager::refresh () vst_refresh (); } #endif // VST_SUPPORT + +#ifdef LXVST_SUPPORT + if(Config->get_use_lxvst()) { + lxvst_refresh(); + } +#endif //Native linuxVST SUPPORT + #ifdef HAVE_AUDIOUNITS au_refresh (); #endif + + PluginListChanged (); /* EMIT SIGNAL */ } void PluginManager::ladspa_refresh () { - _ladspa_plugin_info.clear (); - - 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_path += standard_paths[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 G_DIR_SEPARATOR 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 G_DIR_SEPARATOR : + 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_path += standard_paths[i]; + + } + ladspa_discover_from_path (ladspa_path); } @@ -205,19 +247,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; @@ -236,12 +278,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 @@ -255,6 +298,13 @@ PluginManager::add_vst_presets() { add_presets ("vst"); } + +void +PluginManager::add_lxvst_presets() +{ + add_presets ("lxvst"); +} + void PluginManager::add_presets(string domain) { @@ -289,13 +339,12 @@ PluginManager::add_lrdf_data (const string &path) PathScanner scanner; vector* rdf_files; vector::iterator x; - string uri; rdf_files = scanner (path, rdf_filter, 0, true, true); if (rdf_files) { for (x = rdf_files->begin(); x != rdf_files->end (); ++x) { - uri = "file://" + **x; + const string uri(string("file://") + **x); if (lrdf_read_file(uri.c_str())) { warning << "Could not parse rdf file: " << uri << endmsg; @@ -306,7 +355,7 @@ PluginManager::add_lrdf_data (const string &path) vector_delete (rdf_files); } -int +int PluginManager::ladspa_discover (string path) { void *module; @@ -337,7 +386,7 @@ PluginManager::ladspa_discover (string path) 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; @@ -348,11 +397,11 @@ PluginManager::ladspa_discover (string path) 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]) ) { @@ -364,7 +413,23 @@ PluginManager::ladspa_discover (string path) } } - _ladspa_plugin_info.push_back (info); + if(_ladspa_plugin_info->empty()){ + _ladspa_plugin_info->push_back (info); + } + + //Ensure that the plugin is not already in the plugin list. + + bool found = false; + + 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; + } + } + + if(!found){ + _ladspa_plugin_info->push_back (info); + } } // GDB WILL NOT LIKE YOU IF YOU DO THIS @@ -388,7 +453,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) lrdf_statement* matches1 = lrdf_matches (&pattern); if (!matches1) { - return ""; + return "Unknown"; } pattern.subject = matches1->object; @@ -400,27 +465,47 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) lrdf_free_statements(matches1); if (!matches2) { - return (""); + return ("Unknown"); } string label = matches2->object; lrdf_free_statements(matches2); - return label; + /* Kludge LADSPA class names to be singular and match LV2 class names. + This avoids duplicate plugin menus for every class, which is necessary + to make the plugin category menu at all usable, but is obviously a + filthy kludge. + + In the short term, lrdf could be updated so the labels match and a new + release made. To support both specs, we should probably be mapping the + URIs to the same category in code and perhaps tweaking that hierarchy + dynamically to suit the user. Personally, I (drobilla) think that time + is better spent replacing the little-used LRDF. + + In the longer term, we will abandon LRDF entirely in favour of LV2 and + use that class hierarchy. Aside from fixing this problem properly, that + will also allow for translated labels. SWH plugins have been LV2 for + ages; TAP needs porting. I don't know of anything else with LRDF data. + */ + if (label == "Utilities") { + return "Utility"; + } else if (label == "Pitch shifters") { + return "Pitch Shifter"; + } else if (label != "Dynamics" && label != "Chorus" + &&label[label.length() - 1] == 's' + && label[label.length() - 2] != 's') { + return label.substr(0, label.length() - 1); + } else { + return label; + } } -#ifdef HAVE_SLV2 +#ifdef LV2_SUPPORT void PluginManager::lv2_refresh () { - lv2_discover(); -} - -int -PluginManager::lv2_discover () -{ - _lv2_plugin_info = LV2PluginInfo::discover(_lv2_world); - return 0; + delete _lv2_plugin_info; + _lv2_plugin_info = LV2PluginInfo::discover(); } #endif @@ -428,14 +513,8 @@ PluginManager::lv2_discover () void PluginManager::au_refresh () { - au_discover(); -} - -int -PluginManager::au_discover () -{ + delete _au_plugin_info; _au_plugin_info = AUPluginInfo::discover(); - return 0; } #endif @@ -445,7 +524,10 @@ PluginManager::au_discover () void PluginManager::vst_refresh () { - _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"; @@ -461,7 +543,7 @@ PluginManager::add_vst_directory (string path) vst_path += ':'; vst_path += path; return 0; - } + } return -1; } @@ -510,7 +592,7 @@ PluginManager::vst_discover (string path) finfo->name) << endl; } - + PluginInfoPtr info(new VSTPluginInfo); /* what a joke freeware VST is */ @@ -521,18 +603,19 @@ 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; - // need to set info->creator but FST doesn't provide it + info->creator = finfo->creator; info->index = 0; - info->n_inputs = finfo->numInputs; - info->n_outputs = finfo->numOutputs; + info->n_inputs.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); info->type = ARDOUR::VST; - - _vst_plugin_info.push_back (info); + + _vst_plugin_info->push_back (info); fst_free_info (finfo); return 0; @@ -540,19 +623,130 @@ PluginManager::vst_discover (string path) #endif // VST_SUPPORT -bool -PluginManager::is_a_favorite_plugin (const PluginInfoPtr& pi) +#ifdef LXVST_SUPPORT + +void +PluginManager::lxvst_refresh () +{ + if (_lxvst_plugin_info) { + _lxvst_plugin_info->clear (); + } else { + _lxvst_plugin_info = new ARDOUR::PluginInfoList(); + } + + if (lxvst_path.length() == 0) { + lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst"; + } + + lxvst_discover_from_path (lxvst_path); +} + +int +PluginManager::add_lxvst_directory (string path) +{ + if (lxvst_discover_from_path (path) == 0) { + lxvst_path += ':'; + lxvst_path += path; + return 0; + } + return -1; +} + +static bool lxvst_filter (const string& str, void *) +{ + /* 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::lxvst_discover_from_path (string path) +{ + PathScanner scanner; + vector *plugin_objects; + vector::iterator x; + int ret = 0; + + info << "Discovering linuxVST plugins along " << path << endmsg; + + plugin_objects = scanner (lxvst_path, lxvst_filter, 0, true, true); + + if (plugin_objects) { + for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) { + lxvst_discover (**x); + } + } + + info << "Done linuxVST discover" << endmsg; + + vector_delete (plugin_objects); + return ret; +} + +int +PluginManager::lxvst_discover (string path) +{ + VSTFXInfo* finfo; + char buf[32]; + + if ((finfo = vstfx_get_info (const_cast (path.c_str()))) == 0) { + warning << "Cannot get linuxVST information from " << path << endmsg; + return -1; + } + + if (!finfo->canProcessReplacing) { + warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"), + finfo->name) + << endl; + } + + PluginInfoPtr info(new LXVSTPluginInfo); + + if (!strcasecmp ("The Unnamed plugin", finfo->name)) { + info->name = PBD::basename_nosuffix (path); + } else { + info->name = finfo->name; + } + + + snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); + info->unique_id = buf; + info->category = "linuxVSTs"; + info->path = path; + info->creator = finfo->creator; + info->index = 0; + info->n_inputs.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); + info->type = ARDOUR::LXVST; + + _lxvst_plugin_info->push_back (info); + vstfx_free_info (finfo); + + return 0; +} + +#endif // LXVST_SUPPORT + + +PluginManager::PluginStatusType +PluginManager::get_status (const PluginInfoPtr& pi) { - FavoritePlugin fp (pi->type, pi->unique_id); - return find (favorites.begin(), favorites.end(), fp) != favorites.end(); + 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; + } } void -PluginManager::save_favorites () +PluginManager::save_statuses () { ofstream ofs; sys::path path = user_config_directory(); - path /= "favorite_plugins"; + path /= "plugin_statuses"; ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc)); @@ -560,7 +754,7 @@ PluginManager::save_favorites () return; } - for (FavoritePluginList::iterator i = favorites.begin(); i != favorites.end(); ++i) { + for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) { switch ((*i).type) { case LADSPA: ofs << "LADSPA"; @@ -574,28 +768,50 @@ PluginManager::save_favorites () case VST: ofs << "VST"; break; + case LXVST: + ofs << "LXVST"; + break; + } + + ofs << ' '; + + switch ((*i).status) { + case Normal: + ofs << "Normal"; + break; + case Favorite: + ofs << "Favorite"; + break; + case Hidden: + ofs << "Hidden"; + break; } - - ofs << ' ' << (*i).unique_id << endl; + + ofs << ' '; + ofs << (*i).unique_id;; + ofs << endl; } ofs.close (); } void -PluginManager::load_favorites () +PluginManager::load_statuses () { sys::path path = user_config_directory(); - path /= "favorite_plugins"; + path /= "plugin_statuses"; ifstream ifs (path.to_string().c_str()); if (!ifs) { return; } - + std::string stype; + std::string sstatus; std::string id; PluginType type; + PluginStatusType status; + char buf[1024]; while (ifs) { @@ -604,11 +820,33 @@ PluginManager::load_favorites () break; } - ifs >> id; + + ifs >> sstatus; + if (!ifs) { + break; + + } + + /* rest of the line is the plugin ID */ + + ifs.getline (buf, sizeof (buf), '\n'); if (!ifs) { break; } + 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") { @@ -617,29 +855,87 @@ PluginManager::load_favorites () type = LV2; } else if (stype == "VST") { type = VST; + } else if (stype == "LXVST") { + type = LXVST; } else { - error << string_compose (_("unknown favorite plugin type \"%1\" - ignored"), stype) + error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype) << endmsg; continue; } - - add_favorite (type, id); + + id = buf; + strip_whitespace_edges (id); + set_status (type, id, status); } - + ifs.close (); } void -PluginManager::add_favorite (PluginType t, string id) +PluginManager::set_status (PluginType t, string id, PluginStatusType status) { - FavoritePlugin fp (t, id); - pair res = favorites.insert (fp); - //cerr << "Added " << t << " " << id << " success ? " << res.second << endl; + PluginStatus ps (t, id, status); + statuses.erase (ps); + + if (status == Normal) { + return; + } + + statuses.insert (ps); } -void -PluginManager::remove_favorite (PluginType t, string id) +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 +} + +ARDOUR::PluginInfoList& +PluginManager::lxvst_plugin_info () { - FavoritePlugin fp (t, id); - favorites.erase (fp); +#ifdef LXVST_SUPPORT + if (!_lxvst_plugin_info) + lxvst_refresh(); + return *_lxvst_plugin_info; +#else + return _empty_plugin_info; +#endif +} + +ARDOUR::PluginInfoList& +PluginManager::ladspa_plugin_info () +{ + if (!_ladspa_plugin_info) + ladspa_refresh(); + return *_ladspa_plugin_info; +} + +ARDOUR::PluginInfoList& +PluginManager::lv2_plugin_info () +{ +#ifdef LV2_SUPPORT + 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 }