#include <sys/types.h>
#include <cstdio>
#include <cstdlib>
-#include <fstream>
+
+#include <glib.h>
+#include "pbd/gstdio_compat.h"
#ifdef HAVE_LRDF
#include <lrdf.h>
#endif
#ifdef WINDOWS_VST_SUPPORT
+#include "ardour/vst_info_file.h"
#include "fst.h"
#include "pbd/basename.h"
#include <cstring>
+
+// dll-info
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+
#endif // WINDOWS_VST_SUPPORT
#ifdef LXVST_SUPPORT
+#include "ardour/vst_info_file.h"
#include "ardour/linux_vst_support.h"
#include "pbd/basename.h"
#include <cstring>
#endif //LXVST_SUPPORT
+#ifdef MACVST_SUPPORT
+#include "ardour/vst_info_file.h"
+#include "ardour/mac_vst_support.h"
+#include "ardour/mac_vst_plugin.h"
+#include "pbd/basename.h"
+#include "pbd/pathexpand.h"
+#include <cstring>
+#endif //MACVST_SUPPORT
+
#include <glibmm/miscutils.h>
#include <glibmm/pattern.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
-#include "pbd/pathscanner.h"
#include "pbd/whitespace.h"
#include "pbd/file_utils.h"
#include "ardour/filesystem_paths.h"
#include "ardour/ladspa.h"
#include "ardour/ladspa_plugin.h"
+#include "ardour/luascripting.h"
+#include "ardour/luaproc.h"
#include "ardour/plugin.h"
#include "ardour/plugin_manager.h"
#include "ardour/rc_configuration.h"
-#include "ardour/ladspa_search_path.h"
+#include "ardour/search_paths.h"
#ifdef LV2_SUPPORT
#include "ardour/lv2_plugin.h"
#include "pbd/error.h"
#include "pbd/stl_delete.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
#include "ardour/debug.h"
using namespace std;
PluginManager* PluginManager::_instance = 0;
+std::string PluginManager::scanner_bin_path = "";
PluginManager&
-PluginManager::instance()
+PluginManager::instance()
{
if (!_instance) {
_instance = new PluginManager;
PluginManager::PluginManager ()
: _windows_vst_plugin_info(0)
, _lxvst_plugin_info(0)
+ , _mac_vst_plugin_info(0)
, _ladspa_plugin_info(0)
, _lv2_plugin_info(0)
, _au_plugin_info(0)
+ , _lua_plugin_info(0)
+ , _cancel_scan(false)
+ , _cancel_timeout(false)
{
char* s;
string lrdf_path;
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_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"))){
}
#endif /* Native LinuxVST support*/
+#ifdef MACVST_SUPPORT
+ if (Config->get_use_macvst ()) {
+ add_mac_vst_presets ();
+ }
+#endif
+
if ((s = getenv ("VST_PATH"))) {
windows_vst_path = s;
} else if ((s = getenv ("VST_PLUGINS"))) {
windows_vst_path = s;
}
+ if (windows_vst_path.length() == 0) {
+ windows_vst_path = vst_search_path ();
+ }
+
if ((s = getenv ("LXVST_PATH"))) {
lxvst_path = s;
} else if ((s = getenv ("LXVST_PLUGINS"))) {
lxvst_path = s;
}
- if (_instance == 0) {
- _instance = 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"));
+
+ LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
}
PluginManager::~PluginManager()
{
+ if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+ // don't bother, just exit quickly.
+ delete _windows_vst_plugin_info;
+ delete _lxvst_plugin_info;
+ delete _mac_vst_plugin_info;
+ delete _ladspa_plugin_info;
+ delete _lv2_plugin_info;
+ delete _au_plugin_info;
+ delete _lua_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 ();
+ BootMessage (_("Scanning Lua DSP Processors"));
+ lua_refresh ();
#ifdef LV2_SUPPORT
+ BootMessage (_("Scanning LV2 Plugins"));
lv2_refresh ();
#endif
#ifdef WINDOWS_VST_SUPPORT
if (Config->get_use_windows_vst()) {
- windows_vst_refresh ();
+ 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()) {
- lxvst_refresh();
+ if (cache_only) {
+ BootMessage (_("Scanning Linux VST Plugins"));
+ } else {
+ BootMessage (_("Discovering Linux VST Plugins"));
+ }
+ lxvst_refresh(cache_only);
}
#endif //Native linuxVST SUPPORT
+#ifdef MACVST_SUPPORT
+ if(Config->get_use_macvst ()) {
+ if (cache_only) {
+ BootMessage (_("Scanning Mac VST Plugins"));
+ } else {
+ BootMessage (_("Discovering Mac VST Plugins"));
+ }
+ mac_vst_refresh (cache_only);
+ } else if (_mac_vst_plugin_info) {
+ _mac_vst_plugin_info->clear ();
+ } else {
+ _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
+ }
+#endif //Native Mac VST SUPPORT
+
+#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_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
- 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::cancel_plugin_scan ()
+{
+ _cancel_scan = true;
+}
+
+void
+PluginManager::cancel_plugin_timeout ()
+{
+ _cancel_timeout = true;
+}
+
+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<string> fsi_files;
+ 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());
+ }
+ }
+#endif
+
+#ifdef LXVST_SUPPORT
+ {
+ vector<string> fsi_files;
+ 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
+#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 || defined MACVST_SUPPORT)
+ {
+ string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
+ vector<string> fsi_files;
+ 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());
+ }
+ }
+#endif
+}
+
+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(), "\\" VST_EXT_BLACKLIST "$", true);
+ for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
+ ::g_unlink(i->c_str());
+ }
+ }
+#endif
+
+#ifdef LXVST_SUPPORT
+ {
+ vector<string> fsi_files;
+ 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
+#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
+
+#endif // old blacklist cleanup
+
+#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_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
+PluginManager::clear_au_cache ()
+{
+#ifdef AUDIOUNIT_SUPPORT
+ AUPluginInfo::clear_cache ();
+#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
+PluginManager::lua_refresh ()
+{
+ if (_lua_plugin_info) {
+ _lua_plugin_info->clear ();
+ } else {
+ _lua_plugin_info = new ARDOUR::PluginInfoList ();
+ }
+ ARDOUR::LuaScriptList & _scripts (LuaScripting::instance ().scripts (LuaScriptInfo::DSP));
+ for (LuaScriptList::const_iterator s = _scripts.begin(); s != _scripts.end(); ++s) {
+ LuaPluginInfoPtr lpi (new LuaPluginInfo(*s));
+ _lua_plugin_info->push_back (lpi);
+ }
+}
+
+void
+PluginManager::lua_refresh_cb ()
+{
+ Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
+ if (!lm.locked()) {
+ return;
+ }
+ lua_refresh ();
PluginListChanged (); /* EMIT SIGNAL */
}
/* Only add standard locations to ladspa_path if it doesn't
* already contain them. Check for trailing G_DIR_SEPARATOR too.
*/
-
+
vector<string> ladspa_modules;
DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
- Glib::PatternSpec so_extension_pattern("*.so");
- Glib::PatternSpec dylib_extension_pattern("*.dylib");
- Glib::PatternSpec dll_extension_pattern("*.dll");
-
- find_matching_files_in_search_path (ladspa_search_path (),
- so_extension_pattern, ladspa_modules);
-
- find_matching_files_in_search_path (ladspa_search_path (),
- dylib_extension_pattern, ladspa_modules);
-
- find_matching_files_in_search_path (ladspa_search_path (),
- dll_extension_pattern, ladspa_modules);
+ 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<std::string>::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] != '.' &&
(str.find(".n3") == (str.length() - 3)) ||
(str.find(".ttl") == (str.length() - 4)));
}
+#endif
void
PluginManager::add_ladspa_presets()
add_presets ("windows-vst");
}
+void
+PluginManager::add_mac_vst_presets()
+{
+ add_presets ("mac-vst");
+}
+
void
PluginManager::add_lxvst_presets()
{
PluginManager::add_presets(string domain)
{
#ifdef HAVE_LRDF
- PathScanner scanner;
- vector<string *> *presets;
- vector<string *>::iterator x;
+ vector<string> presets;
+ vector<string>::iterator x;
char* envvar;
if ((envvar = getenv ("HOME")) == 0) {
}
string path = string_compose("%1/.%2/rdf", envvar, domain);
- presets = scanner (path, rdf_filter, 0, false, 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
}
PluginManager::add_lrdf_data (const string &path)
{
#ifdef HAVE_LRDF
- PathScanner scanner;
- vector<string *>* rdf_files;
- vector<string *>::iterator x;
+ vector<string> rdf_files;
+ vector<string>::iterator x;
- rdf_files = scanner (path, rdf_filter, 0, false, 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
}
DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
for (uint32_t i = 0; ; ++i) {
+ /* if a ladspa plugin allocates memory here
+ * it is never free()ed (or plugin-dependent only when unloading).
+ * For some plugins memory allocated is incremental, we should
+ * avoid re-scanning plugins and file bug reports.
+ */
if ((descriptor = dfunc (i)) == 0) {
break;
}
#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 WINDOWS_VST_SUPPORT
void
-PluginManager::windows_vst_refresh ()
+PluginManager::windows_vst_refresh (bool cache_only)
{
if (_windows_vst_plugin_info) {
_windows_vst_plugin_info->clear ();
_windows_vst_plugin_info = new ARDOUR::PluginInfoList();
}
- if (windows_vst_path.length() == 0) {
- windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
- }
+ windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
+}
- windows_vst_discover_from_path (windows_vst_path);
+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 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
}
int
-PluginManager::add_windows_vst_directory (string path)
+PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
{
- if (windows_vst_discover_from_path (path) == 0) {
- windows_vst_path += ':';
- windows_vst_path += path;
- return 0;
+ vector<string> plugin_objects;
+ vector<string>::iterator x;
+ int ret = 0;
+
+ DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
+
+ if (Session::get_disable_all_loaded_plugins ()) {
+ info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
+ return -1;
}
- return -1;
+
+ if (Config->get_verbose_plugin_scan()) {
+ info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
+ }
+
+ find_files_matching_filter (plugin_objects, path, 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;
}
-static bool windows_vst_filter (const string& str, void *arg)
-{
- /* Not a dotfile, has a prefix before a period, suffix is "dll" */
+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()
+ }
- return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
+ 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_from_path (string path)
+PluginManager::windows_vst_discover (string path, bool cache_only)
{
- PathScanner scanner;
- vector<string *> *plugin_objects;
- vector<string *>::iterator x;
- int ret = 0;
+ 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;
+ }
+ }
- DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
+ _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);
- plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
+ // TODO get extended error messae from vstfx_get_info_fst() e.g blacklisted, 32/64bit compat,
+ // .err file scanner output etc.
- if (plugin_objects) {
- for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
- windows_vst_discover (**x);
+ 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;
+ }
- vector_delete (plugin_objects);
+ uint32_t discovered = 0;
+ for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
+ VSTInfo* finfo = *x;
+ char buf[32];
+
+ 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;
+ }
+
+ 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) ? 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;
+ }
+ }
+ }
+
+ 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;
+ }
+ }
}
- return ret;
+ vstfx_free_info_list (finfos);
+ return discovered > 0 ? 0 : -1;
}
-int
-PluginManager::windows_vst_discover (string path)
+#endif // WINDOWS_VST_SUPPORT
+
+#ifdef MACVST_SUPPORT
+void
+PluginManager::mac_vst_refresh (bool cache_only)
+{
+ if (_mac_vst_plugin_info) {
+ _mac_vst_plugin_info->clear ();
+ } else {
+ _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
+ }
+
+ mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
+}
+
+static bool mac_vst_filter (const string& str)
{
- VSTInfo* finfo;
- char buf[32];
+ string plist = Glib::build_filename (str, "Contents", "Info.plist");
+ if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
+ return false;
+ }
+ return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
+}
- if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
- warning << "Cannot get Windows VST information from " << path << endmsg;
+int
+PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
+{
+ if (Session::get_disable_all_loaded_plugins ()) {
+ info << _("Disabled MacVST scan (safe mode)") << endmsg;
return -1;
}
- if (!finfo->canProcessReplacing) {
- warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
- finfo->name, PROGRAM_NAME)
- << endl;
+ Searchpath paths (path);
+ /* customized version of run_functor_for_paths() */
+ for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+ string expanded_path = path_expand (*i);
+ if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
+ try {
+ Glib::Dir dir(expanded_path);
+ for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
+ string fullpath = Glib::build_filename (expanded_path, *di);
+
+ /* we're only interested in bundles */
+ if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
+ continue;
+ }
+
+ if (mac_vst_filter (fullpath)) {
+ ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
+ mac_vst_discover (fullpath, cache_only || cancelled());
+ continue;
+ }
+
+ /* don't descend into AU bundles in the VST dir */
+ if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
+ continue;
+ }
+
+ /* recurse */
+ mac_vst_discover_from_path (fullpath, cache_only);
+ }
+ } catch (Glib::FileError& err) { }
}
- PluginInfoPtr info (new WindowsVSTPluginInfo);
+ return 0;
+}
+
+int
+PluginManager::mac_vst_discover (string path, bool cache_only)
+{
+ DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
+
+ _cancel_timeout = false;
- /* what a joke freeware VST is */
+ vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
+ cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
- if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
- info->name = PBD::basename_nosuffix (path);
- } else {
- info->name = finfo->name;
+ if (finfos->empty()) {
+ DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
+ return -1;
}
+ uint32_t discovered = 0;
+ for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
+ VSTInfo* finfo = *x;
+ char buf[32];
- 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::Windows_VST;
+ if (!finfo->canProcessReplacing) {
+ warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
+ finfo->name, PROGRAM_NAME)
+ << endl;
+ continue;
+ }
- _windows_vst_plugin_info->push_back (info);
- fst_free_info (finfo);
+ PluginInfoPtr info (new MacVSTPluginInfo);
- return 0;
+ info->name = finfo->name;
+
+ snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
+ info->unique_id = buf;
+ info->category = "MacVST";
+ 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::MacVST;
+
+ bool duplicate = false;
+ if (!_mac_vst_plugin_info->empty()) {
+ for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
+ if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
+ warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
+ duplicate = true;
+ break;
+ }
+ }
+ }
+
+ if (!duplicate) {
+ _mac_vst_plugin_info->push_back (info);
+ discovered++;
+ }
+ }
+
+ vstfx_free_info_list (finfos);
+ return discovered > 0 ? 0 : -1;
}
-#endif // WINDOWS_VST_SUPPORT
+#endif // MAC_VST_SUPPORT
#ifdef LXVST_SUPPORT
void
-PluginManager::lxvst_refresh ()
+PluginManager::lxvst_refresh (bool cache_only)
{
if (_lxvst_plugin_info) {
_lxvst_plugin_info->clear ();
_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:"
- "/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";
- }
-
- 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 *)
}
int
-PluginManager::lxvst_discover_from_path (string path)
+PluginManager::lxvst_discover_from_path (string path, bool cache_only)
{
- PathScanner scanner;
- vector<string *> *plugin_objects;
- vector<string *>::iterator x;
+ vector<string> plugin_objects;
+ vector<string>::iterator x;
int ret = 0;
+ if (Session::get_disable_all_loaded_plugins ()) {
+ info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
+ return -1;
+ }
+
#ifndef NDEBUG
(void) path;
#endif
DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
- plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
-
- 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);
- vector_delete (plugin_objects);
+ for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
+ ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
+ lxvst_discover (*x, cache_only || cancelled());
}
return ret;
}
int
-PluginManager::lxvst_discover (string path)
+PluginManager::lxvst_discover (string path, bool cache_only)
{
- VSTInfo* finfo;
- char buf[32];
-
DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
- if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
+ _cancel_timeout = false;
+ vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
+ cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
+
+ 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 %2 at this time"),
- finfo->name, PROGRAM_NAME)
- << endl;
- }
+ uint32_t discovered = 0;
+ for (vector<VSTInfo *>::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;
- }
+ PluginInfoPtr info(new LXVSTPluginInfo);
-
- 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)) {
- warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
- vstfx_free_info(finfo);
- return 0;
+ 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
PluginManager::PluginStatusType
-PluginManager::get_status (const PluginInfoPtr& pi)
+PluginManager::get_status (const PluginInfoPtr& pi) const
{
PluginStatus ps (pi->type, pi->unique_id);
PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
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) {
case LXVST:
ofs << "LXVST";
break;
+ case MacVST:
+ ofs << "MacVST";
+ break;
+ case Lua:
+ ofs << "Lua";
+ break;
}
ofs << ' ';
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;
type = Windows_VST;
} else if (stype == "LXVST") {
type = LXVST;
+ } else if (stype == "MacVST") {
+ type = MacVST;
+ } else if (stype == "Lua") {
+ type = Lua;
} else {
error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
<< endmsg;
strip_whitespace_edges (id);
set_status (type, id, status);
}
-
- ifs.close ();
}
void
statuses.insert (ps);
}
-ARDOUR::PluginInfoList&
+const ARDOUR::PluginInfoList&
PluginManager::windows_vst_plugin_info ()
{
#ifdef WINDOWS_VST_SUPPORT
#endif
}
-ARDOUR::PluginInfoList&
+const ARDOUR::PluginInfoList&
+PluginManager::mac_vst_plugin_info ()
+{
+#ifdef MACVST_SUPPORT
+ assert(_mac_vst_plugin_info);
+ return *_mac_vst_plugin_info;
+#else
+ return _empty_plugin_info;
+#endif
+}
+
+const 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;
#endif
}
-ARDOUR::PluginInfoList&
+const ARDOUR::PluginInfoList&
PluginManager::ladspa_plugin_info ()
{
- if (!_ladspa_plugin_info)
- ladspa_refresh();
+ assert(_ladspa_plugin_info);
return *_ladspa_plugin_info;
}
-ARDOUR::PluginInfoList&
+const 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;
#endif
}
-ARDOUR::PluginInfoList&
+const 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;
+}
+
+const ARDOUR::PluginInfoList&
+PluginManager::lua_plugin_info ()
+{
+ assert(_lua_plugin_info);
+ return *_lua_plugin_info;
}