X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_manager.cc;h=89ddc5ff19f303fb204bd979f96be89e362a3426;hb=424cacfbc83516d9e935bd93135e58b34dcfc002;hp=e88541317c586ff42fc7c3dce307878d461688d4;hpb=a2d1f894b05b23b58fad5d87c309bd42286b24b9;p=ardour.git diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index e88541317c..89ddc5ff19 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -26,7 +26,9 @@ #include #include #include -#include + +#include +#include "pbd/gstdio_compat.h" #ifdef HAVE_LRDF #include @@ -37,6 +39,13 @@ #include "fst.h" #include "pbd/basename.h" #include + +// dll-info +#include +#include +#include +#include + #endif // WINDOWS_VST_SUPPORT #ifdef LXVST_SUPPORT @@ -46,7 +55,6 @@ #include #endif //LXVST_SUPPORT -#include #include #include #include @@ -123,7 +131,7 @@ PluginManager::PluginManager () #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"); + 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(); @@ -225,6 +233,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; @@ -236,20 +250,49 @@ 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 +#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)) { + gchar *bl = NULL; + if (g_file_get_contents(fn.c_str (), &bl, NULL, NULL)) { + if (Config->get_verbose_plugin_scan()) { + PBD::info << _("VST Blacklist: ") << fn << "\n" << bl << "-----" << endmsg; + } else { + PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg; + } + g_free (bl); + } + } + } +#endif + #ifdef AUDIOUNIT_SUPPORT - BootMessage (_("Scanning AU Plugins")); + if (cache_only) { + BootMessage (_("Scanning AU Plugins")); + } else { + BootMessage (_("Discovering AU Plugins")); + } au_refresh (cache_only); #endif @@ -274,8 +317,15 @@ 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 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); @@ -283,9 +333,23 @@ PluginManager::clear_vst_cache () ::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 #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()); + } + } { vector fsi_files; find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true); @@ -293,13 +357,29 @@ PluginManager::clear_vst_cache () ::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 personal = get_personal_vst_info_cache_dir(); + string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst"); vector fsi_files; - find_files_matching_regex (fsi_files, personal, "\\.fsi$", /* user cache is flat, no recursion */ false); + 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()); } @@ -310,10 +390,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 fsi_files; - find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$", true); + 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()); } @@ -323,24 +405,32 @@ PluginManager::clear_vst_blacklist () #ifdef LXVST_SUPPORT { vector fsi_files; - find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsb$", true); + 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 personal = get_personal_vst_blacklist_dir(); + 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 - vector fsi_files; - find_files_matching_regex (fsi_files, personal, "\\.fsb$", /* flat user cache */ false); - for (vector::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) { - ::g_unlink(i->c_str()); +#endif // old blacklist cleanup + +#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 + } void @@ -639,31 +729,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; - _au_plugin_info = AUPluginInfo::discover(); - // 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(); - /* note: AU require a CAComponentDescription pointer provided by the OS. - * Ardour only caches port and i/o config. It can't just 'scan' without - * 'discovering' (like we do for VST). - * - * So in case discovery fails, we assume the worst: the Description - * is broken (malicious plugins) and even a simple 'scan' would always - * crash ardour on startup. Hence we disable Auto-Scan on start. - * - * If the crash happens at any later time (description is available), - * Ardour will blacklist the plugin in question -- unless - * the crash happens during realtime-run. - */ + 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(); } @@ -686,8 +762,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 @@ -697,7 +772,11 @@ PluginManager::windows_vst_discover_from_path (string path, bool cache_only) vector::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, true); @@ -706,20 +785,98 @@ PluginManager::windows_vst_discover_from_path (string path, bool cache_only) windows_vst_discover (*x, cache_only || cancelled()); } + if (Config->get_verbose_plugin_scan()) { + info << _("--- Windows VST plugins Scan Done") << endmsg; + } + return ret; } +static std::string dll_info (std::string path) { + std::string rv; + uint8_t buf[68]; + uint16_t type = 0; + off_t pe_hdr_off = 0; + + int fd = g_open(path.c_str(), O_RDONLY, 0444); + + if (fd < 0) { + return _("cannot open dll"); // TODO strerror() + } + + if (68 != read (fd, buf, 68)) { + rv = _("invalid dll, file too small"); + goto errorout; + } + if (buf[0] != 'M' && buf[1] != 'Z') { + rv = _("not a dll"); + goto errorout; + } + + pe_hdr_off = *((int32_t*) &buf[60]); + if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) { + rv = _("cannot determine dll type"); + goto errorout; + } + if (6 != read (fd, buf, 6)) { + rv = _("cannot read dll PE header"); + goto errorout; + } + + if (buf[0] != 'P' && buf[1] != 'E') { + rv = _("invalid dll PE header"); + goto errorout; + } + + type = *((uint16_t*) &buf[4]); + switch (type) { + case 0x014c: + rv = _("i386 (32-bit)"); + break; + case 0x0200: + rv = _("Itanium"); + break; + case 0x8664: + rv = _("x64 (64-bit)"); + break; + case 0: + rv = _("Native Architecture"); + break; + default: + rv = _("Unknown Architecture"); + break; + } +errorout: + assert (rv.length() > 0); + close (fd); + return rv; +} + int 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()) { + if (cache_only) { + info << string_compose (_(" * %1 (cache only)"), path) << endmsg; + } else { + info << string_compose (_(" * %1 - %2"), path, dll_info (path)) << endmsg; + } + } + _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; } @@ -729,7 +886,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; @@ -763,8 +920,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; } @@ -775,6 +932,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\" was added)."), info->name) << endmsg; + } } } @@ -922,14 +1082,8 @@ PluginManager::get_status (const PluginInfoPtr& pi) void PluginManager::save_statuses () { - ofstream ofs; std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses"); - - ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc)); - - if (!ofs) { - return; - } + stringstream ofs; for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) { switch ((*i).type) { @@ -948,6 +1102,10 @@ PluginManager::save_statuses () case LXVST: ofs << "LXVST"; break; + case Lua: + assert (0); + continue; + break; } ofs << ' '; @@ -968,19 +1126,20 @@ PluginManager::save_statuses () ofs << (*i).unique_id;; ofs << endl; } - - ofs.close (); + g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL); + PluginStatusesChanged (); /* EMIT SIGNAL */ } void PluginManager::load_statuses () { std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses"); - ifstream ifs (path.c_str()); - - if (!ifs) { + gchar *fbuf = NULL; + if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL)) { return; } + stringstream ifs (fbuf); + g_free (fbuf); std::string stype; std::string sstatus; @@ -1043,8 +1202,6 @@ PluginManager::load_statuses () strip_whitespace_edges (id); set_status (type, id, status); } - - ifs.close (); } void