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::save_tags ()
1543 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1544 XMLNode* root = new XMLNode (X_("PluginTags"));
1546 for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1547 if ( (*i).tagtype == FromFactoryFile || (*i).tagtype == FromUserFile ) {
1548 /* user file should contain only plugins that are (a) newly user-tagged or (b) previously unknown */
1551 XMLNode* node = new XMLNode (X_("Plugin"));
1552 node->set_property (X_("type"), to_generic_vst ((*i).type));
1553 node->set_property (X_("id"), (*i).unique_id);
1554 node->set_property (X_("tags"), (*i).tags);
1555 node->set_property (X_("name"), (*i).name);
1556 if ( (*i).tagtype >= FromUserFile ) {
1557 node->set_property (X_("user-set"), "1");
1559 root->add_child_nocopy (*node);
1563 tree.set_root (root);
1564 if (!tree.write (path)) {
1565 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1570 PluginManager::load_tags ()
1572 vector<std::string> tmp;
1573 find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1575 for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
1576 p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
1577 std::string path = *p;
1578 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1579 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1584 if (!tree.read (path)) {
1585 error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1589 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1595 if (!(*i)->get_property (X_("type"), type) ||
1596 !(*i)->get_property (X_("id"), id) ||
1597 !(*i)->get_property (X_("tags"), tags) ||
1598 !(*i)->get_property (X_("name"), name)) {
1600 if (!(*i)->get_property (X_("user-set"), user_set)) {
1603 strip_whitespace_edges (tags);
1604 set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile );
1610 PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype )
1612 string sanitized = sanitize_tag (tag);
1614 PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype );
1615 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1616 if (i == ptags.end()) {
1618 } else if ( (uint32_t) ttype >= (uint32_t) (*i).tagtype ) { // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
1622 if ( ttype == FromGui ) {
1623 PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
1628 PluginManager::reset_tags (PluginInfoPtr const& pi)
1630 PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
1632 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1633 if (i != ptags.end()) {
1640 PluginManager::sanitize_tag (const std::string to_sanitize) const
1642 if (to_sanitize.empty ()) {
1645 string sanitized = to_sanitize;
1646 vector<string> tags;
1647 if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1649 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1654 /* convert tokens to lower-case, space-separated list */
1656 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1657 if (t != tags.begin ()) {
1658 sanitized.append(" ");
1660 sanitized.append (downcase (*t));
1666 std::vector<std::string>
1667 PluginManager::get_all_tags (TagFilter tag_filter) const
1669 std::vector<std::string> ret;
1671 PluginTagList::const_iterator pt;
1672 for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1673 if ((*pt).tags.empty ()) {
1677 /* if favorites_only then we need to check the info ptr and maybe skip */
1678 if (tag_filter == OnlyFavorites) {
1679 PluginStatus stat ((*pt).type, (*pt).unique_id);
1680 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1681 if ((i != statuses.end()) && (i->status == Favorite)) {
1682 /* it's a favorite! */
1687 if (tag_filter == NoHidden) {
1688 PluginStatus stat ((*pt).type, (*pt).unique_id);
1689 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1690 if ((i != statuses.end()) && (i->status == Hidden)) {
1695 /* parse each plugin's tag string into separate tags */
1696 vector<string> tags;
1697 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1699 cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1704 /* maybe add the tags we've found */
1705 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1706 /* if this tag isn't already in the list, add it */
1707 vector<string>::iterator i = find (ret.begin(), ret.end(), *t);
1708 if (i == ret.end()) {
1714 /* sort in alphabetical order */
1716 sort (ret.begin(), ret.end(), sorter);
1722 const ARDOUR::PluginInfoList&
1723 PluginManager::windows_vst_plugin_info ()
1725 #ifdef WINDOWS_VST_SUPPORT
1726 if (!_windows_vst_plugin_info) {
1727 windows_vst_refresh ();
1729 return *_windows_vst_plugin_info;
1731 return _empty_plugin_info;
1735 const ARDOUR::PluginInfoList&
1736 PluginManager::mac_vst_plugin_info ()
1738 #ifdef MACVST_SUPPORT
1739 assert(_mac_vst_plugin_info);
1740 return *_mac_vst_plugin_info;
1742 return _empty_plugin_info;
1746 const ARDOUR::PluginInfoList&
1747 PluginManager::lxvst_plugin_info ()
1749 #ifdef LXVST_SUPPORT
1750 assert(_lxvst_plugin_info);
1751 return *_lxvst_plugin_info;
1753 return _empty_plugin_info;
1757 const ARDOUR::PluginInfoList&
1758 PluginManager::ladspa_plugin_info ()
1760 assert(_ladspa_plugin_info);
1761 return *_ladspa_plugin_info;
1764 const ARDOUR::PluginInfoList&
1765 PluginManager::lv2_plugin_info ()
1768 assert(_lv2_plugin_info);
1769 return *_lv2_plugin_info;
1771 return _empty_plugin_info;
1775 const ARDOUR::PluginInfoList&
1776 PluginManager::au_plugin_info ()
1778 #ifdef AUDIOUNIT_SUPPORT
1779 if (_au_plugin_info) {
1780 return *_au_plugin_info;
1783 return _empty_plugin_info;
1786 const ARDOUR::PluginInfoList&
1787 PluginManager::lua_plugin_info ()
1789 assert(_lua_plugin_info);
1790 return *_lua_plugin_info;