VST cache rework (part one)
[ardour.git] / libs / ardour / plugin_manager.cc
index 344b2ef9b63bf61c01929c410963807ffa637b77..9dd1d4b6805419b1b19a54bd74016cd13b3af8c0 100644 (file)
@@ -49,6 +49,8 @@
 #include <glib/gstdio.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/pattern.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
 
 #include "pbd/whitespace.h"
 #include "pbd/file_utils.h"
@@ -116,12 +118,17 @@ PluginManager::PluginManager ()
        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(g_win32_get_package_installation_directory_of_module (0), "bin");
 #else
-       vstsp += Glib::getenv("PATH");
+       // 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
@@ -218,6 +225,12 @@ PluginManager::~PluginManager()
 void
 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;
 
@@ -229,20 +242,32 @@ PluginManager::refresh (bool cache_only)
 #endif
 #ifdef WINDOWS_VST_SUPPORT
        if (Config->get_use_windows_vst()) {
-               BootMessage (_("Scanning Windows VST Plugins"));
+               if (cache_only) {
+                       BootMessage (_("Scanning Windows VST Plugins"));
+               } else {
+                       BootMessage (_("Discovering Windows VST Plugins"));
+               }
                windows_vst_refresh (cache_only);
        }
 #endif // WINDOWS_VST_SUPPORT
 
 #ifdef LXVST_SUPPORT
        if(Config->get_use_lxvst()) {
-               BootMessage (_("Scanning Linux VST Plugins"));
+               if (cache_only) {
+                       BootMessage (_("Scanning Linux VST Plugins"));
+               } else {
+                       BootMessage (_("Discovering Linux VST Plugins"));
+               }
                lxvst_refresh(cache_only);
        }
 #endif //Native linuxVST SUPPORT
 
 #ifdef AUDIOUNIT_SUPPORT
-       BootMessage (_("Scanning AU Plugins"));
+       if (cache_only) {
+               BootMessage (_("Scanning AU Plugins"));
+       } else {
+               BootMessage (_("Discovering AU Plugins"));
+       }
        au_refresh (cache_only);
 #endif
 
@@ -267,11 +292,25 @@ PluginManager::cancel_plugin_timeout ()
 void
 PluginManager::clear_vst_cache ()
 {
-       // see also libs/ardour/vst_info_file.cc - vstfx_infofile_path()
+#if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
 #ifdef WINDOWS_VST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true);
+               for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
+                       ::g_unlink(i->c_str());
+               }
+       }
+       {
+               vector<string> fsi_files;
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
+               for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
+                       ::g_unlink(i->c_str());
+               }
+       }
+       {
+               vector<string> fsi_files;
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -281,18 +320,33 @@ PluginManager::clear_vst_cache ()
 #ifdef LXVST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true);
+               for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
+                       ::g_unlink(i->c_str());
+               }
+       }
+       {
+               vector<string> fsi_files;
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
+               for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
+                       ::g_unlink(i->c_str());
+               }
+       }
+       {
+               vector<string> fsi_files;
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
        }
 #endif
+#endif // old cache cleanup
 
 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
        {
-               string personal = get_personal_vst_info_cache_dir();
+               string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, personal, "\\.fsi$");
+               find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -303,10 +357,12 @@ PluginManager::clear_vst_cache ()
 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<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
@@ -316,24 +372,47 @@ PluginManager::clear_vst_blacklist ()
 #ifdef LXVST_SUPPORT
        {
                vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsb$");
+               find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true);
                for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
                        ::g_unlink(i->c_str());
                }
        }
 #endif
 
+#endif // old blacklist cleanup
+
 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
        {
-               string personal = get_personal_vst_blacklist_dir();
-
-               vector<string> fsi_files;
-               find_files_matching_regex (fsi_files, personal, "\\.fsb$");
-               for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
-                       ::g_unlink(i->c_str());
+               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
+
+}
+
+void
+PluginManager::clear_au_cache ()
+{
+#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());
+       }
+#endif
+}
+
+void
+PluginManager::clear_au_blacklist ()
+{
+#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
 }
 
 void
@@ -365,6 +444,7 @@ PluginManager::ladspa_refresh ()
        }
 }
 
+#ifdef HAVE_LRDF
 static bool rdf_filter (const string &str, void* /*arg*/)
 {
        return str[0] != '.' &&
@@ -373,6 +453,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()
@@ -607,19 +688,17 @@ void
 PluginManager::au_refresh (bool cache_only)
 {
        DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
-       if (cache_only && !Config->get_discover_audio_units ()) {
-               return;
-       }
-       delete _au_plugin_info;
 
-       // disable automatic scan in case we crash
+       // 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();
 
-       _au_plugin_info = AUPluginInfo::discover();
+       delete _au_plugin_info;
+       _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
 
-       // successful scan re-enabled automatic discovery
-       Config->set_discover_audio_units (true);
+       // successful scan re-enabled automatic discovery if it was set
+       Config->set_discover_audio_units (discover_at_start);
        Config->save_state();
 }
 
@@ -642,8 +721,7 @@ PluginManager::windows_vst_refresh (bool cache_only)
 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
@@ -653,15 +731,23 @@ PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
        vector<string>::iterator x;
        int ret = 0;
 
-       DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
+       DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
+
+       if (Config->get_verbose_plugin_scan()) {
+               info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
+       }
 
-       find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true);
+       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;
+       }
+
        return ret;
 }
 
@@ -670,12 +756,22 @@ PluginManager::windows_vst_discover (string path, bool cache_only)
 {
        DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
 
+       if (Config->get_verbose_plugin_scan()) {
+               info << string_compose (_(" *  %1 %2"), path, (cache_only ? _(" (cache only)") : "")) << endmsg;
+       }
+
        _cancel_timeout = false;
        vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (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;
        }
 
@@ -685,7 +781,7 @@ PluginManager::windows_vst_discover (string path, bool cache_only)
                char buf[32];
 
                if (!finfo->canProcessReplacing) {
-                       warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
+                       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;
@@ -719,8 +815,8 @@ PluginManager::windows_vst_discover (string path, bool cache_only)
 
                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 << "Ignoring duplicate Windows VST plugin " << info->name << "\n";
+                               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;
                                }
@@ -731,6 +827,9 @@ PluginManager::windows_vst_discover (string path, bool cache_only)
                        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\" added)."), info->name) << endmsg;
+                       }
                }
        }
 
@@ -774,7 +873,7 @@ PluginManager::lxvst_discover_from_path (string path, bool cache_only)
 
        DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
 
-       find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true);
+       find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
 
        for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
                ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());