2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "libardour-config.h"
26 #include <sys/types.h>
31 #include "pbd/gstdio_compat.h"
37 #ifdef WINDOWS_VST_SUPPORT
38 #include "ardour/vst_info_file.h"
40 #include "pbd/basename.h"
49 #endif // WINDOWS_VST_SUPPORT
52 #include "ardour/vst_info_file.h"
53 #include "ardour/linux_vst_support.h"
54 #include "pbd/basename.h"
56 #endif //LXVST_SUPPORT
59 #include "ardour/vst_info_file.h"
60 #include "ardour/mac_vst_support.h"
61 #include "ardour/mac_vst_plugin.h"
62 #include "pbd/basename.h"
63 #include "pbd/pathexpand.h"
65 #endif //MACVST_SUPPORT
67 #include <glibmm/miscutils.h>
68 #include <glibmm/pattern.h>
69 #include <glibmm/fileutils.h>
70 #include <glibmm/miscutils.h>
72 #include "pbd/convert.h"
73 #include "pbd/file_utils.h"
74 #include "pbd/tokenizer.h"
75 #include "pbd/whitespace.h"
77 #include "ardour/directory_names.h"
78 #include "ardour/debug.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ladspa.h"
81 #include "ardour/ladspa_plugin.h"
82 #include "ardour/luascripting.h"
83 #include "ardour/luaproc.h"
84 #include "ardour/plugin.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/rc_configuration.h"
88 #include "ardour/search_paths.h"
91 #include "ardour/lv2_plugin.h"
94 #ifdef WINDOWS_VST_SUPPORT
95 #include "ardour/windows_vst_plugin.h"
99 #include "ardour/lxvst_plugin.h"
102 #ifdef AUDIOUNIT_SUPPORT
103 #include "ardour/audio_unit.h"
104 #include <Carbon/Carbon.h>
107 #include "pbd/error.h"
108 #include "pbd/stl_delete.h"
110 #include "pbd/i18n.h"
112 #include "ardour/debug.h"
114 using namespace ARDOUR;
118 PluginManager* PluginManager::_instance = 0;
119 std::string PluginManager::scanner_bin_path = "";
122 PluginManager::instance()
125 _instance = new PluginManager;
130 PluginManager::PluginManager ()
131 : _windows_vst_plugin_info(0)
132 , _lxvst_plugin_info(0)
133 , _mac_vst_plugin_info(0)
134 , _ladspa_plugin_info(0)
135 , _lv2_plugin_info(0)
137 , _lua_plugin_info(0)
138 , _cancel_scan(false)
139 , _cancel_timeout(false)
144 #if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
145 // source-tree (ardev, etc)
146 PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
148 #ifdef PLATFORM_WINDOWS
149 // on windows the .exe needs to be in the same folder with libardour.dll
150 vstsp += Glib::build_filename(windows_package_directory_path(), "bin");
152 // on Unices additional internal-use binaries are deployed to $libdir
153 vstsp += ARDOUR::ardour_dll_directory();
156 if (!PBD::find_file (vstsp,
157 #ifdef PLATFORM_WINDOWS
158 #ifdef DEBUGGABLE_SCANNER_APP
159 #if defined(DEBUG) || defined(_DEBUG)
160 "ardour-vst-scannerD.exe"
162 "ardour-vst-scannerRDC.exe"
165 "ardour-vst-scanner.exe"
170 , scanner_bin_path)) {
171 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() << endmsg;
179 if ((s = getenv ("LADSPA_RDF_PATH"))){
183 if (lrdf_path.length() == 0) {
184 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
187 add_lrdf_data(lrdf_path);
188 add_ladspa_presets();
189 #ifdef WINDOWS_VST_SUPPORT
190 if (Config->get_use_windows_vst ()) {
191 add_windows_vst_presets ();
193 #endif /* WINDOWS_VST_SUPPORT */
196 if (Config->get_use_lxvst()) {
199 #endif /* Native LinuxVST support*/
201 #ifdef MACVST_SUPPORT
202 if (Config->get_use_macvst ()) {
203 add_mac_vst_presets ();
207 if ((s = getenv ("VST_PATH"))) {
208 windows_vst_path = s;
209 } else if ((s = getenv ("VST_PLUGINS"))) {
210 windows_vst_path = s;
213 if (windows_vst_path.length() == 0) {
214 windows_vst_path = vst_search_path ();
217 if ((s = getenv ("LXVST_PATH"))) {
219 } else if ((s = getenv ("LXVST_PLUGINS"))) {
223 if (lxvst_path.length() == 0) {
224 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
225 "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
226 "/usr/lib/vst:/usr/local/lib/vst";
229 /* first time setup, use 'default' path */
230 if (Config->get_plugin_path_lxvst() == X_("@default@")) {
231 Config->set_plugin_path_lxvst(get_default_lxvst_path());
233 if (Config->get_plugin_path_vst() == X_("@default@")) {
234 Config->set_plugin_path_vst(get_default_windows_vst_path());
237 if (_instance == 0) {
241 BootMessage (_("Discovering Plugins"));
243 LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
247 PluginManager::~PluginManager()
249 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
250 // don't bother, just exit quickly.
251 delete _windows_vst_plugin_info;
252 delete _lxvst_plugin_info;
253 delete _mac_vst_plugin_info;
254 delete _ladspa_plugin_info;
255 delete _lv2_plugin_info;
256 delete _au_plugin_info;
257 delete _lua_plugin_info;
262 PluginManager::refresh (bool cache_only)
264 Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
270 DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
271 _cancel_scan = false;
273 BootMessage (_("Scanning LADSPA Plugins"));
275 BootMessage (_("Scanning Lua DSP Processors"));
278 BootMessage (_("Scanning LV2 Plugins"));
281 #ifdef WINDOWS_VST_SUPPORT
282 if (Config->get_use_windows_vst()) {
284 BootMessage (_("Scanning Windows VST Plugins"));
286 BootMessage (_("Discovering Windows VST Plugins"));
288 windows_vst_refresh (cache_only);
290 #endif // WINDOWS_VST_SUPPORT
293 if(Config->get_use_lxvst()) {
295 BootMessage (_("Scanning Linux VST Plugins"));
297 BootMessage (_("Discovering Linux VST Plugins"));
299 lxvst_refresh(cache_only);
301 #endif //Native linuxVST SUPPORT
303 #ifdef MACVST_SUPPORT
304 if(Config->get_use_macvst ()) {
306 BootMessage (_("Scanning Mac VST Plugins"));
308 BootMessage (_("Discovering Mac VST Plugins"));
310 mac_vst_refresh (cache_only);
311 } else if (_mac_vst_plugin_info) {
312 _mac_vst_plugin_info->clear ();
314 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
316 #endif //Native Mac VST SUPPORT
318 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
320 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
321 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
323 if (g_file_get_contents(fn.c_str (), &bl, NULL, NULL)) {
324 if (Config->get_verbose_plugin_scan()) {
325 PBD::info << _("VST Blacklist: ") << fn << "\n" << bl << "-----" << endmsg;
327 PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg;
335 #ifdef AUDIOUNIT_SUPPORT
337 BootMessage (_("Scanning AU Plugins"));
339 BootMessage (_("Discovering AU Plugins"));
341 au_refresh (cache_only);
344 BootMessage (_("Plugin Scan Complete..."));
345 PluginListChanged (); /* EMIT SIGNAL */
346 PluginScanMessage(X_("closeme"), "", false);
347 _cancel_scan = false;
351 PluginManager::cancel_plugin_scan ()
357 PluginManager::cancel_plugin_timeout ()
359 _cancel_timeout = true;
363 PluginManager::clear_vst_cache ()
365 #if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
366 #ifdef WINDOWS_VST_SUPPORT
368 vector<string> fsi_files;
369 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true);
370 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
371 ::g_unlink(i->c_str());
375 vector<string> fsi_files;
376 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
377 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
378 ::g_unlink(i->c_str());
382 vector<string> fsi_files;
383 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true);
384 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
385 ::g_unlink(i->c_str());
392 vector<string> fsi_files;
393 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true);
394 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
395 ::g_unlink(i->c_str());
399 vector<string> fsi_files;
400 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
401 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
402 ::g_unlink(i->c_str());
406 vector<string> fsi_files;
407 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true);
408 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
409 ::g_unlink(i->c_str());
413 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
415 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_info");
416 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
417 PBD::remove_directory (dir);
421 #endif // old cache cleanup
423 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
425 string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
426 vector<string> fsi_files;
427 find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false);
428 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
429 ::g_unlink(i->c_str());
436 PluginManager::clear_vst_blacklist ()
438 #if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0)
440 #ifdef WINDOWS_VST_SUPPORT
442 vector<string> fsi_files;
443 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true);
444 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
445 ::g_unlink(i->c_str());
452 vector<string> fsi_files;
453 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true);
454 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
455 ::g_unlink(i->c_str());
459 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
461 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_blacklist");
462 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
463 PBD::remove_directory (dir);
468 #endif // old blacklist cleanup
470 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
472 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
473 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
474 ::g_unlink (fn.c_str());
482 PluginManager::clear_au_cache ()
484 #ifdef AUDIOUNIT_SUPPORT
485 AUPluginInfo::clear_cache ();
490 PluginManager::clear_au_blacklist ()
492 #ifdef AUDIOUNIT_SUPPORT
493 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
494 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
495 ::g_unlink(fn.c_str());
501 PluginManager::lua_refresh ()
503 if (_lua_plugin_info) {
504 _lua_plugin_info->clear ();
506 _lua_plugin_info = new ARDOUR::PluginInfoList ();
508 ARDOUR::LuaScriptList & _scripts (LuaScripting::instance ().scripts (LuaScriptInfo::DSP));
509 for (LuaScriptList::const_iterator s = _scripts.begin(); s != _scripts.end(); ++s) {
510 LuaPluginInfoPtr lpi (new LuaPluginInfo(*s));
511 _lua_plugin_info->push_back (lpi);
512 set_tags (lpi->type, lpi->unique_id, lpi->category, lpi->name, FromPlug);
517 PluginManager::lua_refresh_cb ()
519 Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
524 PluginListChanged (); /* EMIT SIGNAL */
528 PluginManager::ladspa_refresh ()
530 if (_ladspa_plugin_info) {
531 _ladspa_plugin_info->clear ();
533 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
536 /* allow LADSPA_PATH to augment, not override standard locations */
538 /* Only add standard locations to ladspa_path if it doesn't
539 * already contain them. Check for trailing G_DIR_SEPARATOR too.
542 vector<string> ladspa_modules;
544 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
546 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so");
547 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib");
548 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll");
550 for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
551 ARDOUR::PluginScanMessage(_("LADSPA"), *i, false);
552 ladspa_discover (*i);
557 static bool rdf_filter (const string &str, void* /*arg*/)
559 return str[0] != '.' &&
560 ((str.find(".rdf") == (str.length() - 4)) ||
561 (str.find(".rdfs") == (str.length() - 5)) ||
562 (str.find(".n3") == (str.length() - 3)) ||
563 (str.find(".ttl") == (str.length() - 4)));
568 PluginManager::add_ladspa_presets()
570 add_presets ("ladspa");
574 PluginManager::add_windows_vst_presets()
576 add_presets ("windows-vst");
580 PluginManager::add_mac_vst_presets()
582 add_presets ("mac-vst");
586 PluginManager::add_lxvst_presets()
588 add_presets ("lxvst");
592 PluginManager::add_presets(string domain)
595 vector<string> presets;
596 vector<string>::iterator x;
599 if ((envvar = getenv ("HOME")) == 0) {
603 string path = string_compose("%1/.%2/rdf", envvar, domain);
604 find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
606 for (x = presets.begin(); x != presets.end (); ++x) {
607 string file = "file:" + *x;
608 if (lrdf_read_file(file.c_str())) {
609 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
617 PluginManager::add_lrdf_data (const string &path)
620 vector<string> rdf_files;
621 vector<string>::iterator x;
623 find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
625 for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
626 const string uri(string("file://") + *x);
628 if (lrdf_read_file(uri.c_str())) {
629 warning << "Could not parse rdf file: " << uri << endmsg;
636 PluginManager::ladspa_discover (string path)
638 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
640 Glib::Module module(path);
641 const LADSPA_Descriptor *descriptor;
642 LADSPA_Descriptor_Function dfunc;
646 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
647 path, Glib::Module::get_last_error()) << endmsg;
652 if (!module.get_symbol("ladspa_descriptor", func)) {
653 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
654 error << Glib::Module::get_last_error() << endmsg;
658 dfunc = (LADSPA_Descriptor_Function)func;
660 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
662 for (uint32_t i = 0; ; ++i) {
663 /* if a ladspa plugin allocates memory here
664 * it is never free()ed (or plugin-dependent only when unloading).
665 * For some plugins memory allocated is incremental, we should
666 * avoid re-scanning plugins and file bug reports.
668 if ((descriptor = dfunc (i)) == 0) {
672 if (!ladspa_plugin_whitelist.empty()) {
673 if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
678 PluginInfoPtr info(new LadspaPluginInfo);
679 info->name = descriptor->Name;
680 info->category = get_ladspa_category(descriptor->UniqueID);
683 info->n_inputs = ChanCount();
684 info->n_outputs = ChanCount();
685 info->type = ARDOUR::LADSPA;
687 string::size_type pos = 0;
688 string creator = descriptor->Maker;
689 /* stupid LADSPA creator strings */
690 #ifdef PLATFORM_WINDOWS
691 while (pos < creator.length() && creator[pos] > -2 && creator[pos] < 256 && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
693 while (pos < creator.length() && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
696 /* If there were too few characters to create a
697 * meaningful name, mark this creator as 'Unknown'
699 if (creator.length() < 2 || pos < 3) {
700 info->creator = "Unknown";
702 info->creator = creator.substr (0, pos);
706 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
707 info->unique_id = buf;
709 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
710 if (LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n])) {
711 if (LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n])) {
712 info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
714 else if (LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n])) {
715 info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
720 if(_ladspa_plugin_info->empty()){
721 _ladspa_plugin_info->push_back (info);
724 //Ensure that the plugin is not already in the plugin list.
728 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
729 if(0 == info->unique_id.compare((*i)->unique_id)){
735 _ladspa_plugin_info->push_back (info);
736 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
739 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
742 // GDB WILL NOT LIKE YOU IF YOU DO THIS
749 PluginManager::get_ladspa_category (uint32_t plugin_id)
753 lrdf_statement pattern;
755 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
756 pattern.subject = buf;
757 pattern.predicate = const_cast<char*>(RDF_TYPE);
759 pattern.object_type = lrdf_uri;
761 lrdf_statement* matches1 = lrdf_matches (&pattern);
767 pattern.subject = matches1->object;
768 pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
770 pattern.object_type = lrdf_literal;
772 lrdf_statement* matches2 = lrdf_matches (&pattern);
773 lrdf_free_statements(matches1);
779 string label = matches2->object;
780 lrdf_free_statements(matches2);
782 /* Kludge LADSPA class names to be singular and match LV2 class names.
783 This avoids duplicate plugin menus for every class, which is necessary
784 to make the plugin category menu at all usable, but is obviously a
787 In the short term, lrdf could be updated so the labels match and a new
788 release made. To support both specs, we should probably be mapping the
789 URIs to the same category in code and perhaps tweaking that hierarchy
790 dynamically to suit the user. Personally, I (drobilla) think that time
791 is better spent replacing the little-used LRDF.
793 In the longer term, we will abandon LRDF entirely in favour of LV2 and
794 use that class hierarchy. Aside from fixing this problem properly, that
795 will also allow for translated labels. SWH plugins have been LV2 for
796 ages; TAP needs porting. I don't know of anything else with LRDF data.
798 if (label == "Utilities") {
800 } else if (label == "Pitch shifters") {
801 return "Pitch Shifter";
802 } else if (label != "Dynamics" && label != "Chorus"
803 &&label[label.length() - 1] == 's'
804 && label[label.length() - 2] != 's') {
805 return label.substr(0, label.length() - 1);
816 PluginManager::lv2_refresh ()
818 DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
819 delete _lv2_plugin_info;
820 _lv2_plugin_info = LV2PluginInfo::discover();
822 for (PluginInfoList::iterator i = _lv2_plugin_info->begin(); i != _lv2_plugin_info->end(); ++i) {
823 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
828 #ifdef AUDIOUNIT_SUPPORT
830 PluginManager::au_refresh (bool cache_only)
832 DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
834 // disable automatic discovery in case we crash
835 bool discover_at_start = Config->get_discover_audio_units ();
836 Config->set_discover_audio_units (false);
837 Config->save_state();
839 delete _au_plugin_info;
840 _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
842 // successful scan re-enabled automatic discovery if it was set
843 Config->set_discover_audio_units (discover_at_start);
844 Config->save_state();
846 for (PluginInfoList::iterator i = _au_plugin_info->begin(); i != _au_plugin_info->end(); ++i) {
847 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
853 #ifdef WINDOWS_VST_SUPPORT
856 PluginManager::windows_vst_refresh (bool cache_only)
858 if (_windows_vst_plugin_info) {
859 _windows_vst_plugin_info->clear ();
861 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
864 windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
867 static bool windows_vst_filter (const string& str, void * /*arg*/)
869 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
870 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
874 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
876 vector<string> plugin_objects;
877 vector<string>::iterator x;
880 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
882 if (Session::get_disable_all_loaded_plugins ()) {
883 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
887 if (Config->get_verbose_plugin_scan()) {
888 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
891 find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
893 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
894 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
895 windows_vst_discover (*x, cache_only || cancelled());
898 if (Config->get_verbose_plugin_scan()) {
899 info << _("--- Windows VST plugins Scan Done") << endmsg;
905 static std::string dll_info (std::string path) {
909 off_t pe_hdr_off = 0;
911 int fd = g_open(path.c_str(), O_RDONLY, 0444);
914 return _("cannot open dll"); // TODO strerror()
917 if (68 != read (fd, buf, 68)) {
918 rv = _("invalid dll, file too small");
921 if (buf[0] != 'M' && buf[1] != 'Z') {
926 pe_hdr_off = *((int32_t*) &buf[60]);
927 if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
928 rv = _("cannot determine dll type");
931 if (6 != read (fd, buf, 6)) {
932 rv = _("cannot read dll PE header");
936 if (buf[0] != 'P' && buf[1] != 'E') {
937 rv = _("invalid dll PE header");
941 type = *((uint16_t*) &buf[4]);
944 rv = _("i386 (32-bit)");
950 rv = _("x64 (64-bit)");
953 rv = _("Native Architecture");
956 rv = _("Unknown Architecture");
960 assert (rv.length() > 0);
966 PluginManager::windows_vst_discover (string path, bool cache_only)
968 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
970 if (Config->get_verbose_plugin_scan()) {
972 info << string_compose (_(" * %1 (cache only)"), path) << endmsg;
974 info << string_compose (_(" * %1 - %2"), path, dll_info (path)) << endmsg;
978 _cancel_timeout = false;
979 vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
980 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
982 // TODO get extended error messae from vstfx_get_info_fst() e.g blacklisted, 32/64bit compat,
983 // .err file scanner output etc.
985 if (finfos->empty()) {
986 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
987 if (Config->get_verbose_plugin_scan()) {
988 info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg;
993 uint32_t discovered = 0;
994 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
998 if (!finfo->canProcessReplacing) {
999 warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"),
1000 finfo->name, PROGRAM_NAME)
1005 PluginInfoPtr info (new WindowsVSTPluginInfo);
1007 /* what a joke freeware VST is */
1009 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1010 info->name = PBD::basename_nosuffix (path);
1012 info->name = finfo->name;
1016 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1017 info->unique_id = buf;
1018 info->category = finfo->Category;
1020 info->creator = finfo->creator;
1022 info->n_inputs.set_audio (finfo->numInputs);
1023 info->n_outputs.set_audio (finfo->numOutputs);
1024 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1025 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1026 info->type = ARDOUR::Windows_VST;
1028 /* if we don't have any tags for this plugin, make some up. */
1029 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1031 // TODO: check dup-IDs (lxvst AND windows vst)
1032 bool duplicate = false;
1034 if (!_windows_vst_plugin_info->empty()) {
1035 for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
1036 if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) {
1037 warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg;
1045 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1046 _windows_vst_plugin_info->push_back (info);
1048 if (Config->get_verbose_plugin_scan()) {
1049 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1054 vstfx_free_info_list (finfos);
1055 return discovered > 0 ? 0 : -1;
1058 #endif // WINDOWS_VST_SUPPORT
1060 #ifdef MACVST_SUPPORT
1062 PluginManager::mac_vst_refresh (bool cache_only)
1064 if (_mac_vst_plugin_info) {
1065 _mac_vst_plugin_info->clear ();
1067 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1070 mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1073 static bool mac_vst_filter (const string& str)
1075 string plist = Glib::build_filename (str, "Contents", "Info.plist");
1076 if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1079 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1083 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1085 if (Session::get_disable_all_loaded_plugins ()) {
1086 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1090 Searchpath paths (path);
1091 /* customized version of run_functor_for_paths() */
1092 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1093 string expanded_path = path_expand (*i);
1094 if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
1096 Glib::Dir dir(expanded_path);
1097 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
1098 string fullpath = Glib::build_filename (expanded_path, *di);
1100 /* we're only interested in bundles */
1101 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1105 if (mac_vst_filter (fullpath)) {
1106 ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1107 mac_vst_discover (fullpath, cache_only || cancelled());
1111 /* don't descend into AU bundles in the VST dir */
1112 if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
1117 mac_vst_discover_from_path (fullpath, cache_only);
1119 } catch (Glib::FileError& err) { }
1126 PluginManager::mac_vst_discover (string path, bool cache_only)
1128 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1130 _cancel_timeout = false;
1132 vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
1133 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1135 if (finfos->empty()) {
1136 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1140 uint32_t discovered = 0;
1141 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1142 VSTInfo* finfo = *x;
1145 if (!finfo->canProcessReplacing) {
1146 warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1147 finfo->name, PROGRAM_NAME)
1152 PluginInfoPtr info (new MacVSTPluginInfo);
1154 info->name = finfo->name;
1156 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1157 info->unique_id = buf;
1158 info->category = finfo->Category;
1160 info->creator = finfo->creator;
1162 info->n_inputs.set_audio (finfo->numInputs);
1163 info->n_outputs.set_audio (finfo->numOutputs);
1164 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1165 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1166 info->type = ARDOUR::MacVST;
1168 /* if we don't have any tags for this plugin, make some up. */
1169 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1171 bool duplicate = false;
1172 if (!_mac_vst_plugin_info->empty()) {
1173 for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
1174 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1175 warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
1183 _mac_vst_plugin_info->push_back (info);
1188 vstfx_free_info_list (finfos);
1189 return discovered > 0 ? 0 : -1;
1192 #endif // MAC_VST_SUPPORT
1194 #ifdef LXVST_SUPPORT
1197 PluginManager::lxvst_refresh (bool cache_only)
1199 if (_lxvst_plugin_info) {
1200 _lxvst_plugin_info->clear ();
1202 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1205 lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1208 static bool lxvst_filter (const string& str, void *)
1210 /* Not a dotfile, has a prefix before a period, suffix is "so" */
1212 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1216 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1218 vector<string> plugin_objects;
1219 vector<string>::iterator x;
1222 if (Session::get_disable_all_loaded_plugins ()) {
1223 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1231 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1233 find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1235 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
1236 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
1237 lxvst_discover (*x, cache_only || cancelled());
1244 PluginManager::lxvst_discover (string path, bool cache_only)
1246 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1248 _cancel_timeout = false;
1249 vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
1250 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1252 if (finfos->empty()) {
1253 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1257 uint32_t discovered = 0;
1258 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1259 VSTInfo* finfo = *x;
1262 if (!finfo->canProcessReplacing) {
1263 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1264 finfo->name, PROGRAM_NAME)
1269 PluginInfoPtr info(new LXVSTPluginInfo);
1271 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1272 info->name = PBD::basename_nosuffix (path);
1274 info->name = finfo->name;
1278 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1279 info->unique_id = buf;
1280 info->category = finfo->Category;
1282 info->creator = finfo->creator;
1284 info->n_inputs.set_audio (finfo->numInputs);
1285 info->n_outputs.set_audio (finfo->numOutputs);
1286 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1287 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1288 info->type = ARDOUR::LXVST;
1290 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1292 /* Make sure we don't find the same plugin in more than one place along
1293 * the LXVST_PATH We can't use a simple 'find' because the path is included
1294 * in the PluginInfo, and that is the one thing we can be sure MUST be
1295 * different if a duplicate instance is found. So we just compare the type
1296 * and unique ID (which for some VSTs isn't actually unique...)
1299 // TODO: check dup-IDs with windowsVST, too
1300 bool duplicate = false;
1301 if (!_lxvst_plugin_info->empty()) {
1302 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
1303 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1304 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
1312 _lxvst_plugin_info->push_back (info);
1317 vstfx_free_info_list (finfos);
1318 return discovered > 0 ? 0 : -1;
1321 #endif // LXVST_SUPPORT
1324 PluginManager::PluginStatusType
1325 PluginManager::get_status (const PluginInfoPtr& pi) const
1327 PluginStatus ps (pi->type, pi->unique_id);
1328 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
1329 if (i == statuses.end()) {
1337 PluginManager::save_statuses ()
1339 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1342 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1343 switch ((*i).type) {
1354 ofs << "Windows-VST";
1369 switch ((*i).status) {
1383 ofs << (*i).unique_id;;
1386 g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1390 PluginManager::load_statuses ()
1393 find_file (plugin_metadata_search_path(), "plugin_statuses", path); //note: if no user folder is found, this will find the resources path
1395 if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL)) {
1398 stringstream ifs (fbuf);
1402 std::string sstatus;
1405 PluginStatusType status;
1422 /* rest of the line is the plugin ID */
1424 ifs.getline (buf, sizeof (buf), '\n');
1429 if (sstatus == "Normal") {
1431 } else if (sstatus == "Favorite") {
1433 } else if (sstatus == "Hidden") {
1436 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1442 if (stype == "LADSPA") {
1444 } else if (stype == "AudioUnit") {
1446 } else if (stype == "LV2") {
1448 } else if (stype == "Windows-VST") {
1450 } else if (stype == "LXVST") {
1452 } else if (stype == "MacVST") {
1454 } else if (stype == "Lua") {
1457 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1463 strip_whitespace_edges (id);
1464 set_status (type, id, status);
1469 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1471 PluginStatus ps (t, id, status);
1472 statuses.erase (ps);
1474 if (status != Normal) {
1475 statuses.insert (ps);
1478 PluginStatusChanged (t, id, status); /* EMIT SIGNAL */
1482 PluginManager::to_generic_vst (const PluginType t)
1496 bool operator() (std::string a, std::string b) {
1497 return a.compare (b) < 0;
1502 PluginManager::get_tags (const PluginInfoPtr& pi) const
1504 vector<std::string> tags;
1506 PluginTag ps (to_generic_vst(pi->type), pi->unique_id, "", "", FromPlug);
1507 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1508 if (i != ptags.end ()) {
1509 PBD::tokenize (i->tags, string(" "), std::back_inserter (tags), true);
1511 sort (tags.begin(), tags.end(), sorter);
1517 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1521 vector<std::string> tags = get_tags(pi);
1522 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1523 if (t != tags.begin ()) {
1533 PluginManager::user_plugin_metadata_dir () const
1535 std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1536 g_mkdir_with_parents (dir.c_str(), 0744);
1541 PluginManager::load_plugin_order_file (XMLNode &n) const
1543 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1545 info << string_compose (_("Loading plugin order file %1"), path) << endmsg;
1546 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1551 if (tree.read (path)) {
1555 error << string_compose (_("Cannot parse Plugin Order info from %1"), path) << endmsg;
1562 PluginManager::save_plugin_order_file (XMLNode &elem) const
1564 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1566 info << string_compose (_("Saving plugin order file %1"), path) << endmsg;
1569 tree.set_root (&elem);
1570 if (!tree.write (path)) {
1571 error << string_compose (_("Could not save Plugin Order info to %1"), path) << endmsg;
1573 tree.set_root (0); //note: must disconnect the elem from XMLTree, or it will try to delete memory it didn't allocate
1578 PluginManager::save_tags ()
1580 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1581 XMLNode* root = new XMLNode (X_("PluginTags"));
1583 for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1584 if ( (*i).tagtype == FromFactoryFile || (*i).tagtype == FromUserFile ) {
1585 /* user file should contain only plugins that are (a) newly user-tagged or (b) previously unknown */
1588 XMLNode* node = new XMLNode (X_("Plugin"));
1589 node->set_property (X_("type"), to_generic_vst ((*i).type));
1590 node->set_property (X_("id"), (*i).unique_id);
1591 node->set_property (X_("tags"), (*i).tags);
1592 node->set_property (X_("name"), (*i).name);
1593 if ( (*i).tagtype >= FromUserFile ) {
1594 node->set_property (X_("user-set"), "1");
1596 root->add_child_nocopy (*node);
1600 tree.set_root (root);
1601 if (!tree.write (path)) {
1602 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1607 PluginManager::load_tags ()
1609 vector<std::string> tmp;
1610 find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1612 for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
1613 p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
1614 std::string path = *p;
1615 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1616 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1621 if (!tree.read (path)) {
1622 error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1626 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1632 if (!(*i)->get_property (X_("type"), type) ||
1633 !(*i)->get_property (X_("id"), id) ||
1634 !(*i)->get_property (X_("tags"), tags) ||
1635 !(*i)->get_property (X_("name"), name)) {
1637 if (!(*i)->get_property (X_("user-set"), user_set)) {
1640 strip_whitespace_edges (tags);
1641 set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile );
1647 PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype )
1649 string sanitized = sanitize_tag (tag);
1651 PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype );
1652 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1653 if (i == ptags.end()) {
1655 } else if ( (uint32_t) ttype >= (uint32_t) (*i).tagtype ) { // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
1659 if ( ttype == FromGui ) {
1660 PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
1665 PluginManager::reset_tags (PluginInfoPtr const& pi)
1667 PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
1669 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1670 if (i != ptags.end()) {
1677 PluginManager::sanitize_tag (const std::string to_sanitize) const
1679 if (to_sanitize.empty ()) {
1682 string sanitized = to_sanitize;
1683 vector<string> tags;
1684 if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1686 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1691 /* convert tokens to lower-case, space-separated list */
1693 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1694 if (t != tags.begin ()) {
1695 sanitized.append(" ");
1697 sanitized.append (downcase (*t));
1703 std::vector<std::string>
1704 PluginManager::get_all_tags (TagFilter tag_filter) const
1706 std::vector<std::string> ret;
1708 PluginTagList::const_iterator pt;
1709 for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1710 if ((*pt).tags.empty ()) {
1714 /* if favorites_only then we need to check the info ptr and maybe skip */
1715 if (tag_filter == OnlyFavorites) {
1716 PluginStatus stat ((*pt).type, (*pt).unique_id);
1717 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1718 if ((i != statuses.end()) && (i->status == Favorite)) {
1719 /* it's a favorite! */
1724 if (tag_filter == NoHidden) {
1725 PluginStatus stat ((*pt).type, (*pt).unique_id);
1726 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1727 if ((i != statuses.end()) && (i->status == Hidden)) {
1732 /* parse each plugin's tag string into separate tags */
1733 vector<string> tags;
1734 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1736 cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1741 /* maybe add the tags we've found */
1742 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1743 /* if this tag isn't already in the list, add it */
1744 vector<string>::iterator i = find (ret.begin(), ret.end(), *t);
1745 if (i == ret.end()) {
1751 /* sort in alphabetical order */
1753 sort (ret.begin(), ret.end(), sorter);
1759 const ARDOUR::PluginInfoList&
1760 PluginManager::windows_vst_plugin_info ()
1762 #ifdef WINDOWS_VST_SUPPORT
1763 if (!_windows_vst_plugin_info) {
1764 windows_vst_refresh ();
1766 return *_windows_vst_plugin_info;
1768 return _empty_plugin_info;
1772 const ARDOUR::PluginInfoList&
1773 PluginManager::mac_vst_plugin_info ()
1775 #ifdef MACVST_SUPPORT
1776 assert(_mac_vst_plugin_info);
1777 return *_mac_vst_plugin_info;
1779 return _empty_plugin_info;
1783 const ARDOUR::PluginInfoList&
1784 PluginManager::lxvst_plugin_info ()
1786 #ifdef LXVST_SUPPORT
1787 assert(_lxvst_plugin_info);
1788 return *_lxvst_plugin_info;
1790 return _empty_plugin_info;
1794 const ARDOUR::PluginInfoList&
1795 PluginManager::ladspa_plugin_info ()
1797 assert(_ladspa_plugin_info);
1798 return *_ladspa_plugin_info;
1801 const ARDOUR::PluginInfoList&
1802 PluginManager::lv2_plugin_info ()
1805 assert(_lv2_plugin_info);
1806 return *_lv2_plugin_info;
1808 return _empty_plugin_info;
1812 const ARDOUR::PluginInfoList&
1813 PluginManager::au_plugin_info ()
1815 #ifdef AUDIOUNIT_SUPPORT
1816 if (_au_plugin_info) {
1817 return *_au_plugin_info;
1820 return _empty_plugin_info;
1823 const ARDOUR::PluginInfoList&
1824 PluginManager::lua_plugin_info ()
1826 assert(_lua_plugin_info);
1827 return *_lua_plugin_info;