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, true);
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);
738 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
741 // GDB WILL NOT LIKE YOU IF YOU DO THIS
748 PluginManager::get_ladspa_category (uint32_t plugin_id)
752 lrdf_statement pattern;
754 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
755 pattern.subject = buf;
756 pattern.predicate = const_cast<char*>(RDF_TYPE);
758 pattern.object_type = lrdf_uri;
760 lrdf_statement* matches1 = lrdf_matches (&pattern);
766 pattern.subject = matches1->object;
767 pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
769 pattern.object_type = lrdf_literal;
771 lrdf_statement* matches2 = lrdf_matches (&pattern);
772 lrdf_free_statements(matches1);
778 string label = matches2->object;
779 lrdf_free_statements(matches2);
781 /* Kludge LADSPA class names to be singular and match LV2 class names.
782 This avoids duplicate plugin menus for every class, which is necessary
783 to make the plugin category menu at all usable, but is obviously a
786 In the short term, lrdf could be updated so the labels match and a new
787 release made. To support both specs, we should probably be mapping the
788 URIs to the same category in code and perhaps tweaking that hierarchy
789 dynamically to suit the user. Personally, I (drobilla) think that time
790 is better spent replacing the little-used LRDF.
792 In the longer term, we will abandon LRDF entirely in favour of LV2 and
793 use that class hierarchy. Aside from fixing this problem properly, that
794 will also allow for translated labels. SWH plugins have been LV2 for
795 ages; TAP needs porting. I don't know of anything else with LRDF data.
797 if (label == "Utilities") {
799 } else if (label == "Pitch shifters") {
800 return "Pitch Shifter";
801 } else if (label != "Dynamics" && label != "Chorus"
802 &&label[label.length() - 1] == 's'
803 && label[label.length() - 2] != 's') {
804 return label.substr(0, label.length() - 1);
815 PluginManager::lv2_refresh ()
817 DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
818 delete _lv2_plugin_info;
819 _lv2_plugin_info = LV2PluginInfo::discover();
821 for (PluginInfoList::iterator i = _lv2_plugin_info->begin(); i != _lv2_plugin_info->end(); ++i) {
822 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, true);
827 #ifdef AUDIOUNIT_SUPPORT
829 PluginManager::au_refresh (bool cache_only)
831 DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
833 // disable automatic discovery in case we crash
834 bool discover_at_start = Config->get_discover_audio_units ();
835 Config->set_discover_audio_units (false);
836 Config->save_state();
838 delete _au_plugin_info;
839 _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
841 // successful scan re-enabled automatic discovery if it was set
842 Config->set_discover_audio_units (discover_at_start);
843 Config->save_state();
845 for (PluginInfoList::iterator i = _au_plugin_info->begin(); i != _au_plugin_info->end(); ++i) {
846 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, true);
852 #ifdef WINDOWS_VST_SUPPORT
855 PluginManager::windows_vst_refresh (bool cache_only)
857 if (_windows_vst_plugin_info) {
858 _windows_vst_plugin_info->clear ();
860 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
863 windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
866 static bool windows_vst_filter (const string& str, void * /*arg*/)
868 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
869 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
873 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
875 vector<string> plugin_objects;
876 vector<string>::iterator x;
879 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
881 if (Session::get_disable_all_loaded_plugins ()) {
882 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
886 if (Config->get_verbose_plugin_scan()) {
887 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
890 find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
892 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
893 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
894 windows_vst_discover (*x, cache_only || cancelled());
897 if (Config->get_verbose_plugin_scan()) {
898 info << _("--- Windows VST plugins Scan Done") << endmsg;
904 static std::string dll_info (std::string path) {
908 off_t pe_hdr_off = 0;
910 int fd = g_open(path.c_str(), O_RDONLY, 0444);
913 return _("cannot open dll"); // TODO strerror()
916 if (68 != read (fd, buf, 68)) {
917 rv = _("invalid dll, file too small");
920 if (buf[0] != 'M' && buf[1] != 'Z') {
925 pe_hdr_off = *((int32_t*) &buf[60]);
926 if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
927 rv = _("cannot determine dll type");
930 if (6 != read (fd, buf, 6)) {
931 rv = _("cannot read dll PE header");
935 if (buf[0] != 'P' && buf[1] != 'E') {
936 rv = _("invalid dll PE header");
940 type = *((uint16_t*) &buf[4]);
943 rv = _("i386 (32-bit)");
949 rv = _("x64 (64-bit)");
952 rv = _("Native Architecture");
955 rv = _("Unknown Architecture");
959 assert (rv.length() > 0);
965 PluginManager::windows_vst_discover (string path, bool cache_only)
967 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
969 if (Config->get_verbose_plugin_scan()) {
971 info << string_compose (_(" * %1 (cache only)"), path) << endmsg;
973 info << string_compose (_(" * %1 - %2"), path, dll_info (path)) << endmsg;
977 _cancel_timeout = false;
978 vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
979 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
981 // TODO get extended error messae from vstfx_get_info_fst() e.g blacklisted, 32/64bit compat,
982 // .err file scanner output etc.
984 if (finfos->empty()) {
985 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
986 if (Config->get_verbose_plugin_scan()) {
987 info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg;
992 uint32_t discovered = 0;
993 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
997 if (!finfo->canProcessReplacing) {
998 warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"),
999 finfo->name, PROGRAM_NAME)
1004 PluginInfoPtr info (new WindowsVSTPluginInfo);
1006 /* what a joke freeware VST is */
1008 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1009 info->name = PBD::basename_nosuffix (path);
1011 info->name = finfo->name;
1015 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1016 info->unique_id = buf;
1017 info->category = finfo->category;
1019 info->creator = finfo->creator;
1021 info->n_inputs.set_audio (finfo->numInputs);
1022 info->n_outputs.set_audio (finfo->numOutputs);
1023 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1024 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1025 info->type = ARDOUR::Windows_VST;
1027 /* if we don't have any tags for this plugin, make some up. */
1028 set_tags (info->type, info->unique_id, info->category, true);
1030 // TODO: check dup-IDs (lxvst AND windows vst)
1031 bool duplicate = false;
1033 if (!_windows_vst_plugin_info->empty()) {
1034 for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
1035 if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) {
1036 warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg;
1044 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1045 _windows_vst_plugin_info->push_back (info);
1047 if (Config->get_verbose_plugin_scan()) {
1048 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1053 vstfx_free_info_list (finfos);
1054 return discovered > 0 ? 0 : -1;
1057 #endif // WINDOWS_VST_SUPPORT
1059 #ifdef MACVST_SUPPORT
1061 PluginManager::mac_vst_refresh (bool cache_only)
1063 if (_mac_vst_plugin_info) {
1064 _mac_vst_plugin_info->clear ();
1066 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1069 mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1072 static bool mac_vst_filter (const string& str)
1074 string plist = Glib::build_filename (str, "Contents", "Info.plist");
1075 if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1078 return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1082 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1084 if (Session::get_disable_all_loaded_plugins ()) {
1085 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1089 Searchpath paths (path);
1090 /* customized version of run_functor_for_paths() */
1091 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1092 string expanded_path = path_expand (*i);
1093 if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
1095 Glib::Dir dir(expanded_path);
1096 for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
1097 string fullpath = Glib::build_filename (expanded_path, *di);
1099 /* we're only interested in bundles */
1100 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1104 if (mac_vst_filter (fullpath)) {
1105 ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1106 mac_vst_discover (fullpath, cache_only || cancelled());
1110 /* don't descend into AU bundles in the VST dir */
1111 if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
1116 mac_vst_discover_from_path (fullpath, cache_only);
1118 } catch (Glib::FileError& err) { }
1125 PluginManager::mac_vst_discover (string path, bool cache_only)
1127 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1129 _cancel_timeout = false;
1131 vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
1132 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1134 if (finfos->empty()) {
1135 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1139 uint32_t discovered = 0;
1140 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1141 VSTInfo* finfo = *x;
1144 if (!finfo->canProcessReplacing) {
1145 warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1146 finfo->name, PROGRAM_NAME)
1151 PluginInfoPtr info (new MacVSTPluginInfo);
1153 info->name = finfo->name;
1155 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1156 info->unique_id = buf;
1157 info->category = finfo->Category;
1159 info->creator = finfo->creator;
1161 info->n_inputs.set_audio (finfo->numInputs);
1162 info->n_outputs.set_audio (finfo->numOutputs);
1163 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1164 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1165 info->type = ARDOUR::MacVST;
1167 /* if we don't have any tags for this plugin, make some up. */
1168 set_tags (info->type, info->unique_id, info->category, true);
1170 bool duplicate = false;
1171 if (!_mac_vst_plugin_info->empty()) {
1172 for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
1173 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1174 warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
1182 _mac_vst_plugin_info->push_back (info);
1187 vstfx_free_info_list (finfos);
1188 return discovered > 0 ? 0 : -1;
1191 #endif // MAC_VST_SUPPORT
1193 #ifdef LXVST_SUPPORT
1196 PluginManager::lxvst_refresh (bool cache_only)
1198 if (_lxvst_plugin_info) {
1199 _lxvst_plugin_info->clear ();
1201 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1204 lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1207 static bool lxvst_filter (const string& str, void *)
1209 /* Not a dotfile, has a prefix before a period, suffix is "so" */
1211 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1215 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1217 vector<string> plugin_objects;
1218 vector<string>::iterator x;
1221 if (Session::get_disable_all_loaded_plugins ()) {
1222 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1230 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1232 find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1234 for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
1235 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
1236 lxvst_discover (*x, cache_only || cancelled());
1243 PluginManager::lxvst_discover (string path, bool cache_only)
1245 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1247 _cancel_timeout = false;
1248 vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
1249 cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1251 if (finfos->empty()) {
1252 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1256 uint32_t discovered = 0;
1257 for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1258 VSTInfo* finfo = *x;
1261 if (!finfo->canProcessReplacing) {
1262 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1263 finfo->name, PROGRAM_NAME)
1268 PluginInfoPtr info(new LXVSTPluginInfo);
1270 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1271 info->name = PBD::basename_nosuffix (path);
1273 info->name = finfo->name;
1277 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1278 info->unique_id = buf;
1279 info->category = finfo->Category;
1281 info->creator = finfo->creator;
1283 info->n_inputs.set_audio (finfo->numInputs);
1284 info->n_outputs.set_audio (finfo->numOutputs);
1285 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1286 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1287 info->type = ARDOUR::LXVST;
1289 set_tags (info->type, info->unique_id, info->category, true);
1291 /* Make sure we don't find the same plugin in more than one place along
1292 * the LXVST_PATH We can't use a simple 'find' because the path is included
1293 * in the PluginInfo, and that is the one thing we can be sure MUST be
1294 * different if a duplicate instance is found. So we just compare the type
1295 * and unique ID (which for some VSTs isn't actually unique...)
1298 // TODO: check dup-IDs with windowsVST, too
1299 bool duplicate = false;
1300 if (!_lxvst_plugin_info->empty()) {
1301 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
1302 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1303 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
1311 _lxvst_plugin_info->push_back (info);
1316 vstfx_free_info_list (finfos);
1317 return discovered > 0 ? 0 : -1;
1320 #endif // LXVST_SUPPORT
1323 PluginManager::PluginStatusType
1324 PluginManager::get_status (const PluginInfoPtr& pi) const
1326 PluginStatus ps (pi->type, pi->unique_id);
1327 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
1328 if (i == statuses.end()) {
1336 PluginManager::save_statuses ()
1338 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1341 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1342 switch ((*i).type) {
1353 ofs << "Windows-VST";
1368 switch ((*i).status) {
1382 ofs << (*i).unique_id;;
1385 g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1389 PluginManager::load_statuses ()
1392 find_file (plugin_metadata_search_path(), "plugin_statuses", path); //note: if no user folder is found, this will find the resources path
1394 if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL)) {
1397 stringstream ifs (fbuf);
1401 std::string sstatus;
1404 PluginStatusType status;
1421 /* rest of the line is the plugin ID */
1423 ifs.getline (buf, sizeof (buf), '\n');
1428 if (sstatus == "Normal") {
1430 } else if (sstatus == "Favorite") {
1432 } else if (sstatus == "Hidden") {
1435 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1441 if (stype == "LADSPA") {
1443 } else if (stype == "AudioUnit") {
1445 } else if (stype == "LV2") {
1447 } else if (stype == "Windows-VST") {
1449 } else if (stype == "LXVST") {
1451 } else if (stype == "MacVST") {
1453 } else if (stype == "Lua") {
1456 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1462 strip_whitespace_edges (id);
1463 set_status (type, id, status);
1468 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1470 PluginStatus ps (t, id, status);
1471 statuses.erase (ps);
1473 if (status != Normal) {
1474 statuses.insert (ps);
1477 PluginStatusesChanged (t, id, status); /* EMIT SIGNAL */
1481 PluginManager::to_generic_vst (const PluginType t)
1495 bool operator() (std::string a, std::string b) {
1496 return a.compare (b) < 0;
1501 PluginManager::get_tags (const PluginInfoPtr& pi) const
1503 vector<std::string> tags;
1505 PluginTag ps (to_generic_vst(pi->type), pi->unique_id, "", false);
1506 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1507 if (i != ptags.end ()) {
1508 PBD::tokenize (i->tags, string(" "), std::back_inserter (tags), true);
1510 sort (tags.begin(), tags.end(), sorter);
1516 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1520 vector<std::string> tags = get_tags(pi);
1521 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1522 if (t != tags.begin ()) {
1532 PluginManager::user_plugin_metadata_dir () const
1534 std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1535 g_mkdir_with_parents (dir.c_str(), 0744);
1540 PluginManager::save_tags ()
1542 std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1543 XMLNode* root = new XMLNode (X_("PluginTags"));
1545 for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1546 if (!(*i).user_set) {
1549 XMLNode* node = new XMLNode (X_("Plugin"));
1550 node->set_property (X_("type"), to_generic_vst ((*i).type));
1551 node->set_property (X_("id"), (*i).unique_id);
1552 node->set_property (X_("tags"), (*i).tags);
1553 node->set_property (X_("user-set"), (*i).user_set);
1554 root->add_child_nocopy (*node);
1558 tree.set_root (root);
1559 if (!tree.write (path)) {
1560 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1565 PluginManager::load_tags ()
1567 vector<std::string> tmp;
1568 find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1570 for (vector<std::string>::const_reverse_iterator p = tmp.rbegin (); p != tmp.rend(); ++p) {
1571 std::string path = *p;
1572 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1573 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1578 if (!tree.read (path)) {
1579 error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1583 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1588 if (!(*i)->get_property (X_("type"), type) ||
1589 !(*i)->get_property (X_("id"), id) ||
1590 !(*i)->get_property (X_("tags"), tags)) {
1592 if (!(*i)->get_property (X_("user-set"), user_set)) {
1595 strip_whitespace_edges (tags);
1596 set_tags (type, id, tags, !user_set);
1602 PluginManager::set_tags (PluginType t, string id, string tag, bool factory, bool force)
1604 string sanitized = sanitize_tag (tag);
1606 PluginTag ps (to_generic_vst (t), id, sanitized, !factory);
1607 PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1608 if (i == ptags.end()) {
1610 } else if (!factory || force || !(*i).user_set) {
1614 if (!factory || force) {
1615 PluginTagsChanged (t, id, sanitized); /* EMIT SIGNAL */
1620 PluginManager::reset_tags (PluginInfoPtr const& pi)
1622 set_tags (pi->type, pi->unique_id, pi->category, true, true);
1626 PluginManager::sanitize_tag (const std::string to_sanitize) const
1628 if (to_sanitize.empty ()) {
1631 string sanitized = to_sanitize;
1632 vector<string> tags;
1633 if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1635 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1640 /* convert tokens to lower-case, space-separated list */
1642 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1643 if (t != tags.begin ()) {
1644 sanitized.append(" ");
1646 sanitized.append (downcase (*t));
1652 std::vector<std::string>
1653 PluginManager::get_all_tags (bool favorites_only) const
1655 std::vector<std::string> ret;
1657 PluginTagList::const_iterator pt;
1658 for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1659 if ((*pt).tags.empty ()) {
1663 /* if favorites_only then we need to check the info ptr and maybe skip */
1664 if (favorites_only) {
1665 PluginStatus stat ((*pt).type, (*pt).unique_id);
1666 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
1667 if ((i != statuses.end()) && (i->status == Favorite)) {
1668 /* it's a favorite! */
1674 /* parse each plugin's tag string into separate tags */
1675 vector<string> tags;
1676 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1678 cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1683 /* maybe add the tags we've found */
1684 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1685 /* if this tag isn't already in the list, add it */
1686 vector<string>::iterator i = find (ret.begin(), ret.end(), *t);
1687 if (i == ret.end()) {
1693 /* sort in alphabetical order */
1695 sort (ret.begin(), ret.end(), sorter);
1701 const ARDOUR::PluginInfoList&
1702 PluginManager::windows_vst_plugin_info ()
1704 #ifdef WINDOWS_VST_SUPPORT
1705 if (!_windows_vst_plugin_info) {
1706 windows_vst_refresh ();
1708 return *_windows_vst_plugin_info;
1710 return _empty_plugin_info;
1714 const ARDOUR::PluginInfoList&
1715 PluginManager::mac_vst_plugin_info ()
1717 #ifdef MACVST_SUPPORT
1718 assert(_mac_vst_plugin_info);
1719 return *_mac_vst_plugin_info;
1721 return _empty_plugin_info;
1725 const ARDOUR::PluginInfoList&
1726 PluginManager::lxvst_plugin_info ()
1728 #ifdef LXVST_SUPPORT
1729 assert(_lxvst_plugin_info);
1730 return *_lxvst_plugin_info;
1732 return _empty_plugin_info;
1736 const ARDOUR::PluginInfoList&
1737 PluginManager::ladspa_plugin_info ()
1739 assert(_ladspa_plugin_info);
1740 return *_ladspa_plugin_info;
1743 const ARDOUR::PluginInfoList&
1744 PluginManager::lv2_plugin_info ()
1747 assert(_lv2_plugin_info);
1748 return *_lv2_plugin_info;
1750 return _empty_plugin_info;
1754 const ARDOUR::PluginInfoList&
1755 PluginManager::au_plugin_info ()
1757 #ifdef AUDIOUNIT_SUPPORT
1758 if (_au_plugin_info) {
1759 return *_au_plugin_info;
1762 return _empty_plugin_info;
1765 const ARDOUR::PluginInfoList&
1766 PluginManager::lua_plugin_info ()
1768 assert(_lua_plugin_info);
1769 return *_lua_plugin_info;