2 * Copyright (C) 2000-2018 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2012-2015 Tim Mayberry <mojofunk@gmail.com>
7 * Copyright (C) 2014-2018 John Emmas <john@creativepost.co.uk>
8 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2018 Ben Loftis <ben@harrisonconsoles.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "libardour-config.h"
32 #include <sys/types.h>
37 #include "pbd/gstdio_compat.h"
43 #ifdef WINDOWS_VST_SUPPORT
44 #include "ardour/vst_info_file.h"
46 #include "pbd/basename.h"
55 #endif // WINDOWS_VST_SUPPORT
58 #include "ardour/vst_info_file.h"
59 #include "ardour/linux_vst_support.h"
60 #include "pbd/basename.h"
62 #endif //LXVST_SUPPORT
65 #include "ardour/vst_info_file.h"
66 #include "ardour/mac_vst_support.h"
67 #include "ardour/mac_vst_plugin.h"
68 #include "pbd/basename.h"
69 #include "pbd/pathexpand.h"
71 #endif //MACVST_SUPPORT
73 #include <glibmm/miscutils.h>
74 #include <glibmm/pattern.h>
75 #include <glibmm/fileutils.h>
76 #include <glibmm/miscutils.h>
78 #include "pbd/convert.h"
79 #include "pbd/file_utils.h"
80 #include "pbd/tokenizer.h"
81 #include "pbd/whitespace.h"
83 #include "ardour/directory_names.h"
84 #include "ardour/debug.h"
85 #include "ardour/filesystem_paths.h"
86 #include "ardour/ladspa.h"
87 #include "ardour/ladspa_plugin.h"
88 #include "ardour/luascripting.h"
89 #include "ardour/luaproc.h"
90 #include "ardour/plugin.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/rc_configuration.h"
94 #include "ardour/search_paths.h"
97 #include "ardour/lv2_plugin.h"
100 #ifdef WINDOWS_VST_SUPPORT
101 #include "ardour/windows_vst_plugin.h"
105 #include "ardour/lxvst_plugin.h"
108 #ifdef AUDIOUNIT_SUPPORT
109 #include "ardour/audio_unit.h"
110 #include <Carbon/Carbon.h>
113 #include "pbd/error.h"
114 #include "pbd/stl_delete.h"
116 #include "pbd/i18n.h"
118 #include "ardour/debug.h"
120 using namespace ARDOUR;
124 PluginManager* PluginManager::_instance = 0;
125 std::string PluginManager::scanner_bin_path = "";
128 PluginManager::instance()
131 _instance = new PluginManager;
136 PluginManager::PluginManager ()
137 : _windows_vst_plugin_info(0)
138 , _lxvst_plugin_info(0)
139 , _mac_vst_plugin_info(0)
140 , _ladspa_plugin_info(0)
141 , _lv2_plugin_info(0)
143 , _lua_plugin_info(0)
144 , _cancel_scan(false)
145 , _cancel_timeout(false)
150 #if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
151 // source-tree (ardev, etc)
152 PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
154 #ifdef PLATFORM_WINDOWS
155 // on windows the .exe needs to be in the same folder with libardour.dll
156 vstsp += Glib::build_filename(windows_package_directory_path(), "bin");
158 // on Unices additional internal-use binaries are deployed to $libdir
159 vstsp += ARDOUR::ardour_dll_directory();
162 if (!PBD::find_file (vstsp,
163 #ifdef PLATFORM_WINDOWS
164 #ifdef DEBUGGABLE_SCANNER_APP
165 #if defined(DEBUG) || defined(_DEBUG)
166 "ardour-vst-scannerD.exe"
168 "ardour-vst-scannerRDC.exe"
171 "ardour-vst-scanner.exe"
176 , scanner_bin_path)) {
177 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() << endmsg;
185 if ((s = getenv ("LADSPA_RDF_PATH"))){
189 if (lrdf_path.length() == 0) {
190 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
193 add_lrdf_data(lrdf_path);
194 add_ladspa_presets();
195 #ifdef WINDOWS_VST_SUPPORT
196 if (Config->get_use_windows_vst ()) {
197 add_windows_vst_presets ();
199 #endif /* WINDOWS_VST_SUPPORT */
202 if (Config->get_use_lxvst()) {
205 #endif /* Native LinuxVST support*/
207 #ifdef MACVST_SUPPORT
208 if (Config->get_use_macvst ()) {
209 add_mac_vst_presets ();
213 if ((s = getenv ("VST_PATH"))) {
214 windows_vst_path = s;
215 } else if ((s = getenv ("VST_PLUGINS"))) {
216 windows_vst_path = s;
219 if (windows_vst_path.length() == 0) {
220 windows_vst_path = vst_search_path ();
223 if ((s = getenv ("LXVST_PATH"))) {
225 } else if ((s = getenv ("LXVST_PLUGINS"))) {
229 if (lxvst_path.length() == 0) {
230 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
231 "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
232 "/usr/lib/vst:/usr/local/lib/vst";
235 /* first time setup, use 'default' path */
236 if (Config->get_plugin_path_lxvst() == X_("@default@")) {
237 Config->set_plugin_path_lxvst(get_default_lxvst_path());
239 if (Config->get_plugin_path_vst() == X_("@default@")) {
240 Config->set_plugin_path_vst(get_default_windows_vst_path());
243 if (_instance == 0) {
247 BootMessage (_("Discovering Plugins"));
249 LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
253 PluginManager::~PluginManager()
255 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
256 // don't bother, just exit quickly.
257 delete _windows_vst_plugin_info;
258 delete _lxvst_plugin_info;
259 delete _mac_vst_plugin_info;
260 delete _ladspa_plugin_info;
261 delete _lv2_plugin_info;
262 delete _au_plugin_info;
263 delete _lua_plugin_info;
268 PluginManager::refresh (bool cache_only)
270 Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
276 DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
277 _cancel_scan = false;
279 BootMessage (_("Scanning LADSPA Plugins"));
281 BootMessage (_("Scanning Lua DSP Processors"));
284 BootMessage (_("Scanning LV2 Plugins"));
287 if (Config->get_conceal_lv1_if_lv2_exists()) {
288 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
289 for (PluginInfoList::const_iterator j = _lv2_plugin_info->begin(); j != _lv2_plugin_info->end(); ++j) {
290 if ((*i)->creator == (*j)->creator && (*i)->name == (*j)->name) {
291 PluginStatus ps (LADSPA, (*i)->unique_id, Concealed);
292 if (find (statuses.begin(), statuses.end(), ps) == statuses.end()) {
294 statuses.insert (ps);
300 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end();) {
301 PluginStatusList::iterator j = i++;
302 if ((*j).status == Concealed) {
308 #ifdef WINDOWS_VST_SUPPORT
309 if (Config->get_use_windows_vst()) {
311 BootMessage (_("Scanning Windows VST Plugins"));
313 BootMessage (_("Discovering Windows VST Plugins"));
315 windows_vst_refresh (cache_only);
317 #endif // WINDOWS_VST_SUPPORT
320 if(Config->get_use_lxvst()) {
322 BootMessage (_("Scanning Linux VST Plugins"));
324 BootMessage (_("Discovering Linux VST Plugins"));
326 lxvst_refresh(cache_only);
328 #endif //Native linuxVST SUPPORT
330 #ifdef MACVST_SUPPORT
331 if(Config->get_use_macvst ()) {
333 BootMessage (_("Scanning Mac VST Plugins"));
335 BootMessage (_("Discovering Mac VST Plugins"));
337 mac_vst_refresh (cache_only);
338 } else if (_mac_vst_plugin_info) {
339 _mac_vst_plugin_info->clear ();
341 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
343 #endif //Native Mac VST SUPPORT
345 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
347 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
348 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
350 if (g_file_get_contents(fn.c_str (), &bl, NULL, NULL)) {
351 if (Config->get_verbose_plugin_scan()) {
352 PBD::info << _("VST Blacklist: ") << fn << "\n" << bl << "-----" << endmsg;
354 PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg;
362 #ifdef AUDIOUNIT_SUPPORT
364 BootMessage (_("Scanning AU Plugins"));
366 BootMessage (_("Discovering AU Plugins"));
368 au_refresh (cache_only);
371 BootMessage (_("Plugin Scan Complete..."));
372 PluginListChanged (); /* EMIT SIGNAL */
373 PluginScanMessage(X_("closeme"), "", false);
374 _cancel_scan = false;
378 PluginManager::cancel_plugin_scan ()
384 PluginManager::cancel_plugin_timeout ()
386 _cancel_timeout = true;
390 PluginManager::clear_vst_cache ()
392 #if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
393 #ifdef WINDOWS_VST_SUPPORT
395 vector<string> fsi_files;
396 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true);
397 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
398 ::g_unlink(i->c_str());
402 vector<string> fsi_files;
403 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
404 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
405 ::g_unlink(i->c_str());
409 vector<string> fsi_files;
410 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true);
411 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
412 ::g_unlink(i->c_str());
419 vector<string> fsi_files;
420 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true);
421 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
422 ::g_unlink(i->c_str());
426 vector<string> fsi_files;
427 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
428 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
429 ::g_unlink(i->c_str());
433 vector<string> fsi_files;
434 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true);
435 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
436 ::g_unlink(i->c_str());
440 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
442 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_info");
443 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
444 PBD::remove_directory (dir);
448 #endif // old cache cleanup
450 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
452 string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
453 vector<string> fsi_files;
454 find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false);
455 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
456 ::g_unlink(i->c_str());
463 PluginManager::clear_vst_blacklist ()
465 #if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0)
467 #ifdef WINDOWS_VST_SUPPORT
469 vector<string> fsi_files;
470 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true);
471 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
472 ::g_unlink(i->c_str());
479 vector<string> fsi_files;
480 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true);
481 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
482 ::g_unlink(i->c_str());
486 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
488 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_blacklist");
489 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
490 PBD::remove_directory (dir);
495 #endif // old blacklist cleanup
497 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
499 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
500 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
501 ::g_unlink (fn.c_str());
509 PluginManager::clear_au_cache ()
511 #ifdef AUDIOUNIT_SUPPORT
512 AUPluginInfo::clear_cache ();
517 PluginManager::clear_au_blacklist ()
519 #ifdef AUDIOUNIT_SUPPORT
520 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
521 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
522 ::g_unlink(fn.c_str());
528 PluginManager::lua_refresh ()
530 if (_lua_plugin_info) {
531 _lua_plugin_info->clear ();
533 _lua_plugin_info = new ARDOUR::PluginInfoList ();
535 ARDOUR::LuaScriptList & _scripts (LuaScripting::instance ().scripts (LuaScriptInfo::DSP));
536 for (LuaScriptList::const_iterator s = _scripts.begin(); s != _scripts.end(); ++s) {
537 LuaPluginInfoPtr lpi (new LuaPluginInfo(*s));
538 _lua_plugin_info->push_back (lpi);
539 set_tags (lpi->type, lpi->unique_id, lpi->category, lpi->name, FromPlug);
544 PluginManager::lua_refresh_cb ()
546 Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
551 PluginListChanged (); /* EMIT SIGNAL */
555 PluginManager::ladspa_refresh ()
557 if (_ladspa_plugin_info) {
558 _ladspa_plugin_info->clear ();
560 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
563 /* allow LADSPA_PATH to augment, not override standard locations */
565 /* Only add standard locations to ladspa_path if it doesn't
566 * already contain them. Check for trailing G_DIR_SEPARATOR too.
569 vector<string> ladspa_modules;
571 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
573 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so");
574 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib");
575 find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll");
577 for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
578 ARDOUR::PluginScanMessage(_("LADSPA"), *i, false);
579 ladspa_discover (*i);
584 static bool rdf_filter (const string &str, void* /*arg*/)
586 return str[0] != '.' &&
587 ((str.find(".rdf") == (str.length() - 4)) ||
588 (str.find(".rdfs") == (str.length() - 5)) ||
589 (str.find(".n3") == (str.length() - 3)) ||
590 (str.find(".ttl") == (str.length() - 4)));
595 PluginManager::add_ladspa_presets()
597 add_presets ("ladspa");
601 PluginManager::add_windows_vst_presets()
603 add_presets ("windows-vst");
607 PluginManager::add_mac_vst_presets()
609 add_presets ("mac-vst");
613 PluginManager::add_lxvst_presets()
615 add_presets ("lxvst");
619 PluginManager::add_presets(string domain)
622 vector<string> presets;
623 vector<string>::iterator x;
626 if ((envvar = getenv ("HOME")) == 0) {
630 string path = string_compose("%1/.%2/rdf", envvar, domain);
631 find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
633 for (x = presets.begin(); x != presets.end (); ++x) {
634 string file = "file:" + *x;
635 if (lrdf_read_file(file.c_str())) {
636 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
644 PluginManager::add_lrdf_data (const string &path)
647 vector<string> rdf_files;
648 vector<string>::iterator x;
650 find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
652 for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
653 const string uri(string("file://") + *x);
655 if (lrdf_read_file(uri.c_str())) {
656 warning << "Could not parse rdf file: " << uri << endmsg;
663 PluginManager::ladspa_discover (string path)
665 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
667 Glib::Module module (path);
668 const LADSPA_Descriptor *descriptor;
669 LADSPA_Descriptor_Function dfunc;
673 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
674 path, Glib::Module::get_last_error()) << endmsg;
679 if (!module.get_symbol("ladspa_descriptor", func)) {
680 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
681 error << Glib::Module::get_last_error() << endmsg;
685 dfunc = (LADSPA_Descriptor_Function)func;
687 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
689 for (uint32_t i = 0; ; ++i) {
690 /* if a ladspa plugin allocates memory here
691 * it is never free()ed (or plugin-dependent only when unloading).
692 * For some plugins memory allocated is incremental, we should
693 * avoid re-scanning plugins and file bug reports.
695 if ((descriptor = dfunc (i)) == 0) {
699 if (!ladspa_plugin_whitelist.empty()) {
700 if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
705 PluginInfoPtr info(new LadspaPluginInfo);
706 info->name = descriptor->Name;
707 info->category = get_ladspa_category(descriptor->UniqueID);
710 info->n_inputs = ChanCount();
711 info->n_outputs = ChanCount();
712 info->type = ARDOUR::LADSPA;
714 string::size_type pos = 0;
715 string creator = descriptor->Maker;
716 /* stupid LADSPA creator strings */
717 #ifdef PLATFORM_WINDOWS
718 while (pos < creator.length() && creator[pos] > -2 && creator[pos] < 256 && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
720 while (pos < creator.length() && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
723 /* If there were too few characters to create a
724 * meaningful name, mark this creator as 'Unknown'
726 if (creator.length() < 2 || pos < 3) {
727 info->creator = "Unknown";
729 info->creator = creator.substr (0, pos);
730 strip_whitespace_edges (info->creator);
734 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
735 info->unique_id = buf;
737 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
738 if (LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n])) {
739 if (LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n])) {
740 info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
742 else if (LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n])) {
743 info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
748 if(_ladspa_plugin_info->empty()){
749 _ladspa_plugin_info->push_back (info);
752 //Ensure that the plugin is not already in the plugin list.
756 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
757 if(0 == info->unique_id.compare((*i)->unique_id)){
763 _ladspa_plugin_info->push_back (info);
764 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
767 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
774 PluginManager::get_ladspa_category (uint32_t plugin_id)
778 lrdf_statement pattern;
780 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
781 pattern.subject = buf;
782 pattern.predicate = const_cast<char*>(RDF_TYPE);
784 pattern.object_type = lrdf_uri;
786 lrdf_statement* matches1 = lrdf_matches (&pattern);
792 pattern.subject = matches1->object;
793 pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
795 pattern.object_type = lrdf_literal;
797 lrdf_statement* matches2 = lrdf_matches (&pattern);
798 lrdf_free_statements(matches1);
804 string label = matches2->object;
805 lrdf_free_statements(matches2);
807 /* Kludge LADSPA class names to be singular and match LV2 class names.
808 This avoids duplicate plugin menus for every class, which is necessary
809 to make the plugin category menu at all usable, but is obviously a
812 In the short term, lrdf could be updated so the labels match and a new
813 release made. To support both specs, we should probably be mapping the
814 URIs to the same category in code and perhaps tweaking that hierarchy
815 dynamically to suit the user. Personally, I (drobilla) think that time
816 is better spent replacing the little-used LRDF.
818 In the longer term, we will abandon LRDF entirely in favour of LV2 and
819 use that class hierarchy. Aside from fixing this problem properly, that
820 will also allow for translated labels. SWH plugins have been LV2 for
821 ages; TAP needs porting. I don't know of anything else with LRDF data.
823 if (label == "Utilities") {
825 } else if (label == "Pitch shifters") {
826 return "Pitch Shifter";
827 } else if (label != "Dynamics" && label != "Chorus"
828 &&label[label.length() - 1] == 's'
829 && label[label.length() - 2] != 's') {
830 return label.substr(0, label.length() - 1);
841 PluginManager::lv2_refresh ()
843 DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
844 delete _lv2_plugin_info;
845 _lv2_plugin_info = LV2PluginInfo::discover();
847 for (PluginInfoList::iterator i = _lv2_plugin_info->begin(); i != _lv2_plugin_info->end(); ++i) {
848 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
853 #ifdef AUDIOUNIT_SUPPORT
855 PluginManager::au_refresh (bool cache_only)
857 DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
859 // disable automatic discovery in case we crash
860 bool discover_at_start = Config->get_discover_audio_units ();
861 Config->set_discover_audio_units (false);
862 Config->save_state();
864 delete _au_plugin_info;
865 _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
867 // successful scan re-enabled automatic discovery if it was set
868 Config->set_discover_audio_units (discover_at_start);
869 Config->save_state();
871 for (PluginInfoList::iterator i = _au_plugin_info->begin(); i != _au_plugin_info->end(); ++i) {
872 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
878 #ifdef WINDOWS_VST_SUPPORT
881 PluginManager::windows_vst_refresh (bool cache_only)
883 if (_windows_vst_plugin_info) {
884 _windows_vst_plugin_info->clear ();
886 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
889 windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
892 static bool windows_vst_filter (const string& str, void * /*arg*/)
894 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
895 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
899 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
901 vector<string> plugin_objects;
902 vector<string>::iterator x;
905 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
907 if (Session::get_disable_all_loaded_plugins ()) {
908 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
912 if (Config->get_verbose_plugin_scan()) {
913 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
916 find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
918 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
919 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
920 windows_vst_discover (*x, cache_only || cancelled());
923 if (Config->get_verbose_plugin_scan()) {
924 info << _("--- Windows VST plugins Scan Done") << endmsg;
930 static std::string dll_info (std::string path) {
934 off_t pe_hdr_off = 0;
936 int fd = g_open(path.c_str(), O_RDONLY, 0444);
939 return _("cannot open dll"); // TODO strerror()
942 if (68 != read (fd, buf, 68)) {
943 rv = _("invalid dll, file too small");
946 if (buf[0] != 'M' && buf[1] != 'Z') {
951 pe_hdr_off = *((int32_t*) &buf[60]);
952 if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
953 rv = _("cannot determine dll type");
956 if (6 != read (fd, buf, 6)) {
957 rv = _("cannot read dll PE header");
961 if (buf[0] != 'P' && buf[1] != 'E') {
962 rv = _("invalid dll PE header");
966 type = *((uint16_t*) &buf[4]);
969 rv = _("i386 (32-bit)");
975 rv = _("x64 (64-bit)");
978 rv = _("Native Architecture");
981 rv = _("Unknown Architecture");
985 assert (rv.length() > 0);
991 PluginManager::windows_vst_discover (string path, bool cache_only)
993 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
995 if (Config->get_verbose_plugin_scan()) {
997 info << string_compose (_(" * %1 (cache only)"), path) << endmsg;
999 info << string_compose (_(" * %1 - %2"), path, dll_info (path)) << endmsg;
1003 _cancel_timeout = false;
1004 vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
1005 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1007 // TODO get extended error messae from vstfx_get_info_fst() e.g blacklisted, 32/64bit compat,
1008 // .err file scanner output etc.
1010 if (finfos->empty()) {
1011 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
1012 if (Config->get_verbose_plugin_scan()) {
1013 info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg;
1018 uint32_t discovered = 0;
1019 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1020 VSTInfo* finfo = *x;
1022 if (!finfo->canProcessReplacing) {
1023 warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"),
1024 finfo->name, PROGRAM_NAME)
1029 PluginInfoPtr info (new WindowsVSTPluginInfo (finfo));
1032 /* what a joke freeware VST is */
1033 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1034 info->name = PBD::basename_nosuffix (path);
1037 /* if we don't have any tags for this plugin, make some up. */
1038 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1040 // TODO: check dup-IDs (lxvst AND windows vst)
1041 bool duplicate = false;
1043 if (!_windows_vst_plugin_info->empty()) {
1044 for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
1045 if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) {
1046 warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg;
1054 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1055 _windows_vst_plugin_info->push_back (info);
1057 if (Config->get_verbose_plugin_scan()) {
1058 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1063 vstfx_free_info_list (finfos);
1064 return discovered > 0 ? 0 : -1;
1067 #endif // WINDOWS_VST_SUPPORT
1069 #ifdef MACVST_SUPPORT
1071 PluginManager::mac_vst_refresh (bool cache_only)
1073 if (_mac_vst_plugin_info) {
1074 _mac_vst_plugin_info->clear ();
1076 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1079 mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1082 static bool mac_vst_filter (const string& str)
1084 string plist = Glib::build_filename (str, "Contents", "Info.plist");
1085 if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1088 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1092 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1094 if (Session::get_disable_all_loaded_plugins ()) {
1095 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1099 Searchpath paths (path);
1100 /* customized version of run_functor_for_paths() */
1101 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1102 string expanded_path = path_expand (*i);
1103 if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
1105 Glib::Dir dir(expanded_path);
1106 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
1107 string fullpath = Glib::build_filename (expanded_path, *di);
1109 /* we're only interested in bundles */
1110 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1114 if (mac_vst_filter (fullpath)) {
1115 ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1116 mac_vst_discover (fullpath, cache_only || cancelled());
1120 /* don't descend into AU bundles in the VST dir */
1121 if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
1126 mac_vst_discover_from_path (fullpath, cache_only);
1128 } catch (Glib::FileError& err) { }
1135 PluginManager::mac_vst_discover (string path, bool cache_only)
1137 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1139 _cancel_timeout = false;
1141 vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
1142 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1144 if (finfos->empty()) {
1145 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1149 uint32_t discovered = 0;
1150 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1151 VSTInfo* finfo = *x;
1153 if (!finfo->canProcessReplacing) {
1154 warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1155 finfo->name, PROGRAM_NAME)
1160 PluginInfoPtr info (new MacVSTPluginInfo (finfo));
1163 /* if we don't have any tags for this plugin, make some up. */
1164 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1166 bool duplicate = false;
1167 if (!_mac_vst_plugin_info->empty()) {
1168 for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
1169 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1170 warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
1178 _mac_vst_plugin_info->push_back (info);
1183 vstfx_free_info_list (finfos);
1184 return discovered > 0 ? 0 : -1;
1187 #endif // MAC_VST_SUPPORT
1189 #ifdef LXVST_SUPPORT
1192 PluginManager::lxvst_refresh (bool cache_only)
1194 if (_lxvst_plugin_info) {
1195 _lxvst_plugin_info->clear ();
1197 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1200 lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1203 static bool lxvst_filter (const string& str, void *)
1205 /* Not a dotfile, has a prefix before a period, suffix is "so" */
1207 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1211 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1213 vector<string> plugin_objects;
1214 vector<string>::iterator x;
1217 if (Session::get_disable_all_loaded_plugins ()) {
1218 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1226 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1228 find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1230 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
1231 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
1232 lxvst_discover (*x, cache_only || cancelled());
1239 PluginManager::lxvst_discover (string path, bool cache_only)
1241 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1243 _cancel_timeout = false;
1244 vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
1245 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1247 if (finfos->empty()) {
1248 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1252 uint32_t discovered = 0;
1253 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1254 VSTInfo* finfo = *x;
1256 if (!finfo->canProcessReplacing) {
1257 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1258 finfo->name, PROGRAM_NAME)
1263 PluginInfoPtr info(new LXVSTPluginInfo (finfo));
1266 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1267 info->name = PBD::basename_nosuffix (path);
1270 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1272 /* Make sure we don't find the same plugin in more than one place along
1273 * the LXVST_PATH We can't use a simple 'find' because the path is included
1274 * in the PluginInfo, and that is the one thing we can be sure MUST be
1275 * different if a duplicate instance is found. So we just compare the type
1276 * and unique ID (which for some VSTs isn't actually unique...)
1279 // TODO: check dup-IDs with windowsVST, too
1280 bool duplicate = false;
1281 if (!_lxvst_plugin_info->empty()) {
1282 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
1283 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1284 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
1292 _lxvst_plugin_info->push_back (info);
1297 vstfx_free_info_list (finfos);
1298 return discovered > 0 ? 0 : -1;
1301 #endif // LXVST_SUPPORT
1304 PluginManager::PluginStatusType
1305 PluginManager::get_status (const PluginInfoPtr& pi) const
1307 PluginStatus ps (pi->type, pi->unique_id);
1308 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
1309 if (i == statuses.end()) {
1317 PluginManager::save_statuses ()
1319 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1322 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1323 if ((*i).status == Concealed) {
1326 switch ((*i).type) {
1337 ofs << "Windows-VST";
1352 switch ((*i).status) {
1370 ofs << (*i).unique_id;;
1373 g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1377 PluginManager::load_statuses ()
1380 find_file (plugin_metadata_search_path(), "plugin_statuses", path); // note: if no user folder is found, this will find the resources path
1382 if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL)) {
1385 stringstream ifs (fbuf);
1389 std::string sstatus;
1392 PluginStatusType status;
1408 /* rest of the line is the plugin ID */
1410 ifs.getline (buf, sizeof (buf), '\n');
1415 if (sstatus == "Normal") {
1417 } else if (sstatus == "Favorite") {
1419 } else if (sstatus == "Hidden") {
1422 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus) << endmsg;
1427 if (stype == "LADSPA") {
1429 } else if (stype == "AudioUnit") {
1431 } else if (stype == "LV2") {
1433 } else if (stype == "Windows-VST") {
1435 } else if (stype == "LXVST") {
1437 } else if (stype == "MacVST") {
1439 } else if (stype == "Lua") {
1442 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1448 strip_whitespace_edges (id);
1449 set_status (type, id, status);
1454 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1456 PluginStatus ps (t, id, status);
1457 statuses.erase (ps);
1459 if (status != Normal && status != Concealed) {
1460 statuses.insert (ps);
1463 PluginStatusChanged (t, id, status); /* EMIT SIGNAL */
1467 PluginManager::to_generic_vst (const PluginType t)
1481 bool operator() (std::string a, std::string b) {
1482 return a.compare (b) < 0;
1487 PluginManager::get_tags (const PluginInfoPtr& pi) const
1489 vector<std::string> tags;
1491 PluginTag ps (to_generic_vst(pi->type), pi->unique_id, "", "", FromPlug);
1492 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1493 if (i != ptags.end ()) {
1494 PBD::tokenize (i->tags, string(" "), std::back_inserter (tags), true);
1496 sort (tags.begin(), tags.end(), sorter);
1502 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1506 vector<std::string> tags = get_tags(pi);
1507 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1508 if (t != tags.begin ()) {
1518 PluginManager::user_plugin_metadata_dir () const
1520 std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1521 g_mkdir_with_parents (dir.c_str(), 0744);
1526 PluginManager::load_plugin_order_file (XMLNode &n) const
1528 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1530 info << string_compose (_("Loading plugin order file %1"), path) << endmsg;
1531 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1536 if (tree.read (path)) {
1540 error << string_compose (_("Cannot parse Plugin Order info from %1"), path) << endmsg;
1547 PluginManager::save_plugin_order_file (XMLNode &elem) const
1549 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1551 info << string_compose (_("Saving plugin order file %1"), path) << endmsg;
1554 tree.set_root (&elem);
1555 if (!tree.write (path)) {
1556 error << string_compose (_("Could not save Plugin Order info to %1"), path) << endmsg;
1558 tree.set_root (0); // note: must disconnect the elem from XMLTree, or it will try to delete memory it didn't allocate
1563 PluginManager::save_tags ()
1565 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1566 XMLNode* root = new XMLNode (X_("PluginTags"));
1568 for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1570 if ((*i).type == LADSPA) {
1571 uint32_t id = atoi ((*i).unique_id);
1572 if (id >= 9300 && id <= 9399) {
1573 continue; /* do not write mixbus channelstrip ladspa's in the tagfile */
1577 if ((*i).tagtype == FromFactoryFile || (*i).tagtype == FromUserFile) {
1578 /* user file should contain only plugins that are (a) newly user-tagged or (b) previously unknown */
1581 XMLNode* node = new XMLNode (X_("Plugin"));
1582 node->set_property (X_("type"), to_generic_vst ((*i).type));
1583 node->set_property (X_("id"), (*i).unique_id);
1584 node->set_property (X_("tags"), (*i).tags);
1585 node->set_property (X_("name"), (*i).name);
1586 if ((*i).tagtype >= FromUserFile) {
1587 node->set_property (X_("user-set"), "1");
1589 root->add_child_nocopy (*node);
1593 tree.set_root (root);
1594 if (!tree.write (path)) {
1595 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1600 PluginManager::load_tags ()
1602 vector<std::string> tmp;
1603 find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1605 for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
1606 p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
1607 std::string path = *p;
1608 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1609 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1614 if (!tree.read (path)) {
1615 error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1619 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1625 if (!(*i)->get_property (X_("type"), type) ||
1626 !(*i)->get_property (X_("id"), id) ||
1627 !(*i)->get_property (X_("tags"), tags) ||
1628 !(*i)->get_property (X_("name"), name)) {
1630 if (!(*i)->get_property (X_("user-set"), user_set)) {
1633 strip_whitespace_edges (tags);
1634 set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile);
1640 PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype)
1642 string sanitized = sanitize_tag (tag);
1644 PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype);
1645 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1646 if (i == ptags.end()) {
1648 } else if ((uint32_t) ttype >= (uint32_t) (*i).tagtype) { // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
1652 if (ttype == FromGui) {
1653 PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
1658 PluginManager::reset_tags (PluginInfoPtr const& pi)
1660 PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
1662 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1663 if (i != ptags.end()) {
1670 PluginManager::sanitize_tag (const std::string to_sanitize) const
1672 if (to_sanitize.empty ()) {
1675 string sanitized = to_sanitize;
1676 vector<string> tags;
1677 if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1679 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1684 /* convert tokens to lower-case, space-separated list */
1686 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1687 if (t != tags.begin ()) {
1688 sanitized.append(" ");
1690 sanitized.append (downcase (*t));
1696 std::vector<std::string>
1697 PluginManager::get_all_tags (TagFilter tag_filter) const
1699 std::vector<std::string> ret;
1701 PluginTagList::const_iterator pt;
1702 for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1703 if ((*pt).tags.empty ()) {
1707 /* if favorites_only then we need to check the info ptr and maybe skip */
1708 if (tag_filter == OnlyFavorites) {
1709 PluginStatus stat ((*pt).type, (*pt).unique_id);
1710 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1711 if ((i != statuses.end()) && (i->status == Favorite)) {
1712 /* it's a favorite! */
1717 if (tag_filter == NoHidden) {
1718 PluginStatus stat ((*pt).type, (*pt).unique_id);
1719 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1720 if ((i != statuses.end()) && ((i->status == Hidden) || (i->status == Concealed))) {
1725 /* parse each plugin's tag string into separate tags */
1726 vector<string> tags;
1727 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1729 cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1734 /* maybe add the tags we've found */
1735 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1736 /* if this tag isn't already in the list, add it */
1737 vector<string>::iterator i = find (ret.begin(), ret.end(), *t);
1738 if (i == ret.end()) {
1744 /* sort in alphabetical order */
1746 sort (ret.begin(), ret.end(), sorter);
1752 const ARDOUR::PluginInfoList&
1753 PluginManager::windows_vst_plugin_info ()
1755 #ifdef WINDOWS_VST_SUPPORT
1756 if (!_windows_vst_plugin_info) {
1757 windows_vst_refresh ();
1759 return *_windows_vst_plugin_info;
1761 return _empty_plugin_info;
1765 const ARDOUR::PluginInfoList&
1766 PluginManager::mac_vst_plugin_info ()
1768 #ifdef MACVST_SUPPORT
1769 assert(_mac_vst_plugin_info);
1770 return *_mac_vst_plugin_info;
1772 return _empty_plugin_info;
1776 const ARDOUR::PluginInfoList&
1777 PluginManager::lxvst_plugin_info ()
1779 #ifdef LXVST_SUPPORT
1780 assert(_lxvst_plugin_info);
1781 return *_lxvst_plugin_info;
1783 return _empty_plugin_info;
1787 const ARDOUR::PluginInfoList&
1788 PluginManager::ladspa_plugin_info ()
1790 assert(_ladspa_plugin_info);
1791 return *_ladspa_plugin_info;
1794 const ARDOUR::PluginInfoList&
1795 PluginManager::lv2_plugin_info ()
1798 assert(_lv2_plugin_info);
1799 return *_lv2_plugin_info;
1801 return _empty_plugin_info;
1805 const ARDOUR::PluginInfoList&
1806 PluginManager::au_plugin_info ()
1808 #ifdef AUDIOUNIT_SUPPORT
1809 if (_au_plugin_info) {
1810 return *_au_plugin_info;
1813 return _empty_plugin_info;
1816 const ARDOUR::PluginInfoList&
1817 PluginManager::lua_plugin_info ()
1819 assert(_lua_plugin_info);
1820 return *_lua_plugin_info;