X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_manager.cc;h=7a14154d3c2e449712b12c09f8e696b82a5724e4;hb=449b57d583b63507241939540da630511b8e335b;hp=88dc4c13a7d9db82e27365fe7299ec1d03e2d7cb;hpb=4aeebb914eedf9279e4904786ce42518611de137;p=ardour.git diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 88dc4c13a7..7a14154d3c 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -25,27 +25,35 @@ #include #include -#include -#include #include #include -#ifdef VST_SUPPORT -#include +#ifdef HAVE_LRDF +#include +#endif + +#ifdef WINDOWS_VST_SUPPORT +#include "ardour/vst_info_file.h" +#include "fst.h" #include "pbd/basename.h" #include -#endif // VST_SUPPORT +#endif // WINDOWS_VST_SUPPORT #ifdef LXVST_SUPPORT -#include -#include +#include "ardour/vst_info_file.h" +#include "ardour/linux_vst_support.h" +#include "pbd/basename.h" #include #endif //LXVST_SUPPORT +#include +#include +#include +#include #include -#include "pbd/pathscanner.h" #include "pbd/whitespace.h" +#include "pbd/file_utils.h" #include "ardour/debug.h" #include "ardour/filesystem_paths.h" @@ -53,14 +61,16 @@ #include "ardour/ladspa_plugin.h" #include "ardour/plugin.h" #include "ardour/plugin_manager.h" -#include "ardour/session.h" +#include "ardour/rc_configuration.h" + +#include "ardour/search_paths.h" #ifdef LV2_SUPPORT #include "ardour/lv2_plugin.h" #endif -#ifdef VST_SUPPORT -#include "ardour/vst_plugin.h" +#ifdef WINDOWS_VST_SUPPORT +#include "ardour/windows_vst_plugin.h" #endif #ifdef LXVST_SUPPORT @@ -77,22 +87,67 @@ #include "i18n.h" +#include "ardour/debug.h" + using namespace ARDOUR; using namespace PBD; using namespace std; -PluginManager* PluginManager::_manager = 0; +PluginManager* PluginManager::_instance = 0; +std::string PluginManager::scanner_bin_path = ""; + +PluginManager& +PluginManager::instance() +{ + if (!_instance) { + _instance = new PluginManager; + } + return *_instance; +} PluginManager::PluginManager () - : _vst_plugin_info(0) + : _windows_vst_plugin_info(0) , _lxvst_plugin_info(0) , _ladspa_plugin_info(0) , _lv2_plugin_info(0) , _au_plugin_info(0) + , _cancel_scan(false) + , _cancel_timeout(false) { char* s; string lrdf_path; +#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT + // source-tree (ardev, etc) + PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst")); + +#ifdef PLATFORM_WINDOWS + // on windows the .exe needs to be in the same folder with libardour.dll + vstsp += Glib::build_filename(windows_package_directory_path(), "bin"); +#else + // on Unices additional internal-use binaries are deployed to $libdir + vstsp += ARDOUR::ardour_dll_directory(); +#endif + + if (!PBD::find_file (vstsp, +#ifdef PLATFORM_WINDOWS + #ifdef DEBUGGABLE_SCANNER_APP + #if defined(DEBUG) || defined(_DEBUG) + "ardour-vst-scannerD.exe" + #else + "ardour-vst-scannerRDC.exe" + #endif + #else + "ardour-vst-scanner.exe" + #endif +#else + "ardour-vst-scanner" +#endif + , scanner_bin_path)) { + PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() << endmsg; + } +#endif + load_statuses (); if ((s = getenv ("LADSPA_RDF_PATH"))){ @@ -105,11 +160,11 @@ PluginManager::PluginManager () add_lrdf_data(lrdf_path); add_ladspa_presets(); -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - add_vst_presets(); +#ifdef WINDOWS_VST_SUPPORT + if (Config->get_use_windows_vst ()) { + add_windows_vst_presets (); } -#endif /* VST_SUPPORT */ +#endif /* WINDOWS_VST_SUPPORT */ #ifdef LXVST_SUPPORT if (Config->get_use_lxvst()) { @@ -117,14 +172,14 @@ PluginManager::PluginManager () } #endif /* Native LinuxVST support*/ - if ((s = getenv ("LADSPA_PATH"))) { - ladspa_path = s; - } - if ((s = getenv ("VST_PATH"))) { - vst_path = s; + windows_vst_path = s; } else if ((s = getenv ("VST_PLUGINS"))) { - vst_path = s; + windows_vst_path = s; + } + + if (windows_vst_path.length() == 0) { + windows_vst_path = vst_search_path (); } if ((s = getenv ("LXVST_PATH"))) { @@ -133,20 +188,22 @@ PluginManager::PluginManager () lxvst_path = s; } - if (_manager == 0) { - _manager = this; + if (lxvst_path.length() == 0) { + lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:" + "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:" + "/usr/lib/vst:/usr/local/lib/vst"; } - /* the plugin manager is constructed too early to use Profile */ + /* first time setup, use 'default' path */ + if (Config->get_plugin_path_lxvst() == X_("@default@")) { + Config->set_plugin_path_lxvst(get_default_lxvst_path()); + } + if (Config->get_plugin_path_vst() == X_("@default@")) { + Config->set_plugin_path_vst(get_default_windows_vst_path()); + } - 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 + if (_instance == 0) { + _instance = this; } BootMessage (_("Discovering Plugins")); @@ -155,126 +212,267 @@ PluginManager::PluginManager () PluginManager::~PluginManager() { + if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) { + // don't bother, just exit quickly. + delete _windows_vst_plugin_info; + delete _lxvst_plugin_info; + delete _ladspa_plugin_info; + delete _lv2_plugin_info; + delete _au_plugin_info; + } } - void -PluginManager::refresh () +PluginManager::refresh (bool cache_only) { + Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK); + + if (!lm.locked()) { + return; + } + DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n"); + _cancel_scan = false; + BootMessage (_("Scanning LADSPA Plugins")); ladspa_refresh (); #ifdef LV2_SUPPORT + BootMessage (_("Scanning LV2 Plugins")); lv2_refresh (); #endif -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - vst_refresh (); +#ifdef WINDOWS_VST_SUPPORT + if (Config->get_use_windows_vst()) { + if (cache_only) { + BootMessage (_("Scanning Windows VST Plugins")); + } else { + BootMessage (_("Discovering Windows VST Plugins")); + } + windows_vst_refresh (cache_only); } -#endif // VST_SUPPORT +#endif // WINDOWS_VST_SUPPORT #ifdef LXVST_SUPPORT if(Config->get_use_lxvst()) { - lxvst_refresh(); + if (cache_only) { + BootMessage (_("Scanning Linux VST Plugins")); + } else { + BootMessage (_("Discovering Linux VST Plugins")); + } + lxvst_refresh(cache_only); } #endif //Native linuxVST SUPPORT +#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT) + if (!cache_only) { + string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST); + if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) { + std::string bl; + std::ifstream ifs (fn.c_str ()); + bl.assign ((std::istreambuf_iterator (ifs)), (std::istreambuf_iterator ())); + PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg; + } + } +#endif + #ifdef AUDIOUNIT_SUPPORT - au_refresh (); + if (cache_only) { + BootMessage (_("Scanning AU Plugins")); + } else { + BootMessage (_("Discovering AU Plugins")); + } + au_refresh (cache_only); #endif + BootMessage (_("Plugin Scan Complete...")); PluginListChanged (); /* EMIT SIGNAL */ + PluginScanMessage(X_("closeme"), "", false); + _cancel_scan = false; } void -PluginManager::ladspa_refresh () +PluginManager::cancel_plugin_scan () { - 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", - "" - }; + _cancel_scan = true; +} - /* allow LADSPA_PATH to augment, not override standard locations */ +void +PluginManager::cancel_plugin_timeout () +{ + _cancel_timeout = true; +} - /* Only add standard locations to ladspa_path if it doesn't - * already contain them. Check for trailing G_DIR_SEPARATOR too. - */ +void +PluginManager::clear_vst_cache () +{ +#if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0) +#ifdef WINDOWS_VST_SUPPORT + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } +#endif - 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; - } - } +#ifdef LXVST_SUPPORT + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); } - if (!ladspa_path.empty()) - ladspa_path += ":"; + } + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } +#endif +#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT) + { + string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_info"); + if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) { + PBD::remove_directory (dir); + } + } +#endif +#endif // old cache cleanup + +#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT) + { + string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst"); + vector fsi_files; + find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } +#endif +} - ladspa_path += standard_paths[i]; +void +PluginManager::clear_vst_blacklist () +{ +#if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0) + +#ifdef WINDOWS_VST_SUPPORT + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } + } +#endif +#ifdef LXVST_SUPPORT + { + vector fsi_files; + find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true); + for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { + ::g_unlink(i->c_str()); + } } +#endif +#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT) + { + string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_blacklist"); + if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) { + PBD::remove_directory (dir); + } + } +#endif - DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_path)); +#endif // old blacklist cleanup - ladspa_discover_from_path (ladspa_path); -} +#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT) + { + string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST); + if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) { + ::g_unlink (fn.c_str()); + } + } +#endif +} -int -PluginManager::add_ladspa_directory (string path) +void +PluginManager::clear_au_cache () { - if (ladspa_discover_from_path (path) == 0) { - ladspa_path += ':'; - ladspa_path += path; - return 0; +#ifdef AUDIOUNIT_SUPPORT + // AUPluginInfo::au_cache_path () + string fn = Glib::build_filename (ARDOUR::user_config_directory(), "au_cache"); + if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) { + ::g_unlink(fn.c_str()); } - return -1; +#endif } -static bool ladspa_filter (const string& str, void */*arg*/) +void +PluginManager::clear_au_blacklist () { - /* Not a dotfile, has a prefix before a period, suffix is "so" */ - - return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3)); +#ifdef AUDIOUNIT_SUPPORT + string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt"); + if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) { + ::g_unlink(fn.c_str()); + } +#endif } -int -PluginManager::ladspa_discover_from_path (string /*path*/) +void +PluginManager::ladspa_refresh () { - PathScanner scanner; - vector *plugin_objects; - vector::iterator x; - int ret = 0; + if (_ladspa_plugin_info) { + _ladspa_plugin_info->clear (); + } else { + _ladspa_plugin_info = new ARDOUR::PluginInfoList (); + } - plugin_objects = scanner (ladspa_path, ladspa_filter, 0, true, true); + /* allow LADSPA_PATH to augment, not override standard locations */ - if (plugin_objects) { - for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) { - ladspa_discover (**x); - } - } + /* Only add standard locations to ladspa_path if it doesn't + * already contain them. Check for trailing G_DIR_SEPARATOR too. + */ - vector_delete (plugin_objects); - return ret; + vector ladspa_modules; + + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string())); + + find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so"); + find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib"); + find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll"); + + for (vector::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) { + ARDOUR::PluginScanMessage(_("LADSPA"), *i, false); + ladspa_discover (*i); + } } +#ifdef HAVE_LRDF static bool rdf_filter (const string &str, void* /*arg*/) { return str[0] != '.' && @@ -283,6 +481,7 @@ static bool rdf_filter (const string &str, void* /*arg*/) (str.find(".n3") == (str.length() - 3)) || (str.find(".ttl") == (str.length() - 4))); } +#endif void PluginManager::add_ladspa_presets() @@ -291,9 +490,9 @@ PluginManager::add_ladspa_presets() } void -PluginManager::add_vst_presets() +PluginManager::add_windows_vst_presets() { - add_presets ("vst"); + add_presets ("windows-vst"); } void @@ -305,10 +504,9 @@ PluginManager::add_lxvst_presets() void PluginManager::add_presets(string domain) { - - PathScanner scanner; - vector *presets; - vector::iterator x; +#ifdef HAVE_LRDF + vector presets; + vector::iterator x; char* envvar; if ((envvar = getenv ("HOME")) == 0) { @@ -316,64 +514,64 @@ PluginManager::add_presets(string domain) } string path = string_compose("%1/.%2/rdf", envvar, domain); - presets = scanner (path, rdf_filter, 0, true, true); + find_files_matching_filter (presets, path, rdf_filter, 0, false, true); - if (presets) { - for (x = presets->begin(); x != presets->end (); ++x) { - string file = "file:" + **x; - if (lrdf_read_file(file.c_str())) { - warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg; - } + for (x = presets.begin(); x != presets.end (); ++x) { + string file = "file:" + *x; + if (lrdf_read_file(file.c_str())) { + warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg; } } - vector_delete (presets); +#endif } void PluginManager::add_lrdf_data (const string &path) { - PathScanner scanner; - vector* rdf_files; - vector::iterator x; +#ifdef HAVE_LRDF + vector rdf_files; + vector::iterator x; - rdf_files = scanner (path, rdf_filter, 0, true, true); + find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true); - if (rdf_files) { - for (x = rdf_files->begin(); x != rdf_files->end (); ++x) { - const string uri(string("file://") + **x); + for (x = rdf_files.begin(); x != rdf_files.end (); ++x) { + const string uri(string("file://") + *x); - if (lrdf_read_file(uri.c_str())) { - warning << "Could not parse rdf file: " << uri << endmsg; - } + if (lrdf_read_file(uri.c_str())) { + warning << "Could not parse rdf file: " << uri << endmsg; } } - - vector_delete (rdf_files); +#endif } int PluginManager::ladspa_discover (string path) { - void *module; + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path)); + + Glib::Module module(path); const LADSPA_Descriptor *descriptor; LADSPA_Descriptor_Function dfunc; - const char *errstr; + void* func = 0; - if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) { - error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg; + if (!module) { + error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), + path, Glib::Module::get_last_error()) << endmsg; return -1; } - dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor"); - if ((errstr = dlerror()) != 0) { + if (!module.get_symbol("ladspa_descriptor", func)) { error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg; - error << errstr << endmsg; - dlclose (module); + error << Glib::Module::get_last_error() << endmsg; return -1; } + dfunc = (LADSPA_Descriptor_Function)func; + + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path)); + for (uint32_t i = 0; ; ++i) { if ((descriptor = dfunc (i)) == 0) { break; @@ -427,6 +625,8 @@ PluginManager::ladspa_discover (string path) if(!found){ _ladspa_plugin_info->push_back (info); } + + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs)); } // GDB WILL NOT LIKE YOU IF YOU DO THIS @@ -438,12 +638,13 @@ PluginManager::ladspa_discover (string path) string PluginManager::get_ladspa_category (uint32_t plugin_id) { +#ifdef HAVE_LRDF char buf[256]; lrdf_statement pattern; snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id); pattern.subject = buf; - pattern.predicate = (char*)RDF_TYPE; + pattern.predicate = const_cast(RDF_TYPE); pattern.object = 0; pattern.object_type = lrdf_uri; @@ -454,7 +655,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) } pattern.subject = matches1->object; - pattern.predicate = (char*)(LADSPA_BASE "hasLabel"); + pattern.predicate = const_cast(LADSPA_BASE "hasLabel"); pattern.object = 0; pattern.object_type = lrdf_literal; @@ -495,12 +696,16 @@ PluginManager::get_ladspa_category (uint32_t plugin_id) } else { return label; } +#else + return ("Unknown"); +#endif } #ifdef LV2_SUPPORT void PluginManager::lv2_refresh () { + DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n"); delete _lv2_plugin_info; _lv2_plugin_info = LV2PluginInfo::discover(); } @@ -508,123 +713,164 @@ PluginManager::lv2_refresh () #ifdef AUDIOUNIT_SUPPORT void -PluginManager::au_refresh () +PluginManager::au_refresh (bool cache_only) { DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n"); + + // disable automatic discovery in case we crash + bool discover_at_start = Config->get_discover_audio_units (); + Config->set_discover_audio_units (false); + Config->save_state(); + delete _au_plugin_info; - _au_plugin_info = AUPluginInfo::discover(); + _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start); + + // successful scan re-enabled automatic discovery if it was set + Config->set_discover_audio_units (discover_at_start); + Config->save_state(); } #endif -#ifdef VST_SUPPORT +#ifdef WINDOWS_VST_SUPPORT void -PluginManager::vst_refresh () +PluginManager::windows_vst_refresh (bool cache_only) { - 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"; + if (_windows_vst_plugin_info) { + _windows_vst_plugin_info->clear (); + } else { + _windows_vst_plugin_info = new ARDOUR::PluginInfoList(); } - vst_discover_from_path (vst_path); + windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only); } -int -PluginManager::add_vst_directory (string path) -{ - if (vst_discover_from_path (path) == 0) { - vst_path += ':'; - vst_path += path; - return 0; - } - return -1; -} - -static bool vst_filter (const string& str, void *arg) +static bool windows_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)); + return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4)); } int -PluginManager::vst_discover_from_path (string path) +PluginManager::windows_vst_discover_from_path (string path, bool cache_only) { - PathScanner scanner; - vector *plugin_objects; - vector::iterator x; + vector plugin_objects; + vector::iterator x; int ret = 0; - info << "detecting VST plugins along " << path << endmsg; + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path)); - plugin_objects = scanner (vst_path, vst_filter, 0, true, true); + if (Config->get_verbose_plugin_scan()) { + info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg; + } - if (plugin_objects) { - for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) { - vst_discover (**x); - } + find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true, true); + + for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) { + ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled()); + windows_vst_discover (*x, cache_only || cancelled()); + } + + if (Config->get_verbose_plugin_scan()) { + info << _("--- Windows VST plugins Scan Done") << endmsg; } - vector_delete (plugin_objects); return ret; } int -PluginManager::vst_discover (string path) +PluginManager::windows_vst_discover (string path, bool cache_only) { - FSTInfo* finfo; - char buf[32]; + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path)); - if ((finfo = fst_get_info (const_cast (path.c_str()))) == 0) { - warning << "Cannot get VST information from " << path << endmsg; - return -1; + if (Config->get_verbose_plugin_scan()) { + info << string_compose (_(" * %1 %2"), path, (cache_only ? _(" (cache only)") : "")) << endmsg; } - if (!finfo->canProcessReplacing) { - warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"), - finfo->name) - << endl; + _cancel_timeout = false; + vector * finfos = vstfx_get_info_fst (const_cast (path.c_str()), + cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP); + + // TODO get extended error messae from vstfx_get_info_fst() e.g blacklisted, 32/64bit compat, + // .err file scanner output etc. + + if (finfos->empty()) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path)); + if (Config->get_verbose_plugin_scan()) { + info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg; + } + return -1; } - PluginInfoPtr info(new VSTPluginInfo); + uint32_t discovered = 0; + for (vector::iterator x = finfos->begin(); x != finfos->end(); ++x) { + VSTInfo* finfo = *x; + char buf[32]; - /* what a joke freeware VST is */ + if (!finfo->canProcessReplacing) { + warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"), + finfo->name, PROGRAM_NAME) + << endl; + continue; + } - if (!strcasecmp ("The Unnamed plugin", finfo->name)) { - info->name = PBD::basename_nosuffix (path); - } else { - info->name = finfo->name; - } + PluginInfoPtr info (new WindowsVSTPluginInfo); + + /* what a joke freeware VST is */ + 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 = "VST"; - 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::VST; - _vst_plugin_info->push_back (info); - fst_free_info (finfo); + 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.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0); + info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0); + info->type = ARDOUR::Windows_VST; + + // TODO: check dup-IDs (lxvst AND windows vst) + bool duplicate = false; + + if (!_windows_vst_plugin_info->empty()) { + for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) { + if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) { + warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg; + duplicate = true; + break; + } + } + } - return 0; + if (!duplicate) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id)); + _windows_vst_plugin_info->push_back (info); + discovered++; + if (Config->get_verbose_plugin_scan()) { + PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg; + } + } + } + + vstfx_free_info_list (finfos); + return discovered > 0 ? 0 : -1; } -#endif // VST_SUPPORT +#endif // WINDOWS_VST_SUPPORT #ifdef LXVST_SUPPORT void -PluginManager::lxvst_refresh () +PluginManager::lxvst_refresh (bool cache_only) { if (_lxvst_plugin_info) { _lxvst_plugin_info->clear (); @@ -632,22 +878,7 @@ PluginManager::lxvst_refresh () _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; + lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only); } static bool lxvst_filter (const string& str, void *) @@ -658,86 +889,102 @@ static bool lxvst_filter (const string& str, void *) } int -PluginManager::lxvst_discover_from_path (string path) +PluginManager::lxvst_discover_from_path (string path, bool cache_only) { - PathScanner scanner; - vector *plugin_objects; - vector::iterator x; + vector plugin_objects; + vector::iterator x; int ret = 0; - info << "Discovering linuxVST plugins along " << path << endmsg; +#ifndef NDEBUG + (void) path; +#endif - plugin_objects = scanner (lxvst_path, lxvst_filter, 0, true, true); + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path)); - if (plugin_objects) { - for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) { - lxvst_discover (**x); - } - } + find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true); - info << "Done linuxVST discover" << endmsg; + for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) { + ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled()); + lxvst_discover (*x, cache_only || cancelled()); + } - vector_delete (plugin_objects); return ret; } int -PluginManager::lxvst_discover (string path) +PluginManager::lxvst_discover (string path, bool cache_only) { - VSTFXInfo* finfo; - char buf[32]; + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path)); + + _cancel_timeout = false; + vector * finfos = vstfx_get_info_lx (const_cast (path.c_str()), + cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP); - if ((finfo = vstfx_get_info (const_cast (path.c_str()))) == 0) { - warning << "Cannot get linuxVST information from " << path << endmsg; + if (finfos->empty()) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path)); 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; - } + uint32_t discovered = 0; + for (vector::iterator x = finfos->begin(); x != finfos->end(); ++x) { + VSTInfo* finfo = *x; + char buf[32]; - PluginInfoPtr info(new LXVSTPluginInfo); + if (!finfo->canProcessReplacing) { + warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"), + finfo->name, PROGRAM_NAME) + << endl; + continue; + } - 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; - - /* Make sure we don't find the same plugin in more than one place along - the LXVST_PATH We can't use a simple 'find' because the path is included - in the PluginInfo, and that is the one thing we can be sure MUST be - different if a duplicate instance is found. So we just compare the type - and unique ID (which for some VSTs isn't actually unique...) - */ - - if (!_lxvst_plugin_info->empty()) { - for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) { - if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) { - vstfx_free_info(finfo); - return 0; + 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) ? 1 : 0); + info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0); + info->type = ARDOUR::LXVST; + + /* Make sure we don't find the same plugin in more than one place along + the LXVST_PATH We can't use a simple 'find' because the path is included + in the PluginInfo, and that is the one thing we can be sure MUST be + different if a duplicate instance is found. So we just compare the type + and unique ID (which for some VSTs isn't actually unique...) + */ + + // TODO: check dup-IDs with windowsVST, too + bool duplicate = false; + if (!_lxvst_plugin_info->empty()) { + for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) { + if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) { + warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n"; + duplicate = true; + break; + } } } + + if (!duplicate) { + _lxvst_plugin_info->push_back (info); + discovered++; + } } - - _lxvst_plugin_info->push_back (info); - vstfx_free_info (finfo); - return 0; + vstfx_free_info_list (finfos); + return discovered > 0 ? 0 : -1; } #endif // LXVST_SUPPORT @@ -759,10 +1006,9 @@ void PluginManager::save_statuses () { ofstream ofs; - sys::path path = user_config_directory(); - path /= "plugin_statuses"; + std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses"); - ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc)); + ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc)); if (!ofs) { return; @@ -779,8 +1025,8 @@ PluginManager::save_statuses () case LV2: ofs << "LV2"; break; - case VST: - ofs << "VST"; + case Windows_VST: + ofs << "Windows-VST"; break; case LXVST: ofs << "LXVST"; @@ -812,9 +1058,8 @@ PluginManager::save_statuses () void PluginManager::load_statuses () { - sys::path path = user_config_directory(); - path /= "plugin_statuses"; - ifstream ifs (path.to_string().c_str()); + std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses"); + ifstream ifs (path.c_str()); if (!ifs) { return; @@ -867,8 +1112,8 @@ PluginManager::load_statuses () type = AudioUnit; } else if (stype == "LV2") { type = LV2; - } else if (stype == "VST") { - type = VST; + } else if (stype == "Windows-VST") { + type = Windows_VST; } else if (stype == "LXVST") { type = LXVST; } else { @@ -899,12 +1144,13 @@ PluginManager::set_status (PluginType t, string id, PluginStatusType status) } ARDOUR::PluginInfoList& -PluginManager::vst_plugin_info () +PluginManager::windows_vst_plugin_info () { -#ifdef VST_SUPPORT - if (!_vst_plugin_info) - vst_refresh(); - return *_vst_plugin_info; +#ifdef WINDOWS_VST_SUPPORT + if (!_windows_vst_plugin_info) { + windows_vst_refresh (); + } + return *_windows_vst_plugin_info; #else return _empty_plugin_info; #endif @@ -914,8 +1160,7 @@ ARDOUR::PluginInfoList& PluginManager::lxvst_plugin_info () { #ifdef LXVST_SUPPORT - if (!_lxvst_plugin_info) - lxvst_refresh(); + assert(_lxvst_plugin_info); return *_lxvst_plugin_info; #else return _empty_plugin_info; @@ -925,8 +1170,7 @@ PluginManager::lxvst_plugin_info () ARDOUR::PluginInfoList& PluginManager::ladspa_plugin_info () { - if (!_ladspa_plugin_info) - ladspa_refresh(); + assert(_ladspa_plugin_info); return *_ladspa_plugin_info; } @@ -934,8 +1178,7 @@ ARDOUR::PluginInfoList& PluginManager::lv2_plugin_info () { #ifdef LV2_SUPPORT - if (!_lv2_plugin_info) - lv2_refresh(); + assert(_lv2_plugin_info); return *_lv2_plugin_info; #else return _empty_plugin_info; @@ -946,10 +1189,9 @@ ARDOUR::PluginInfoList& PluginManager::au_plugin_info () { #ifdef AUDIOUNIT_SUPPORT - if (!_au_plugin_info) - au_refresh(); - return *_au_plugin_info; -#else - return _empty_plugin_info; + if (_au_plugin_info) { + return *_au_plugin_info; + } #endif + return _empty_plugin_info; }