add new API for retrieving port flags from backend
[ardour.git] / libs / ardour / plugin_manager.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <stdint.h>
25
26 #include <sys/types.h>
27 #include <cstdio>
28 #include <cstdlib>
29
30 #include <glib.h>
31 #include "pbd/gstdio_compat.h"
32
33 #ifdef HAVE_LRDF
34 #include <lrdf.h>
35 #endif
36
37 #ifdef WINDOWS_VST_SUPPORT
38 #include "ardour/vst_info_file.h"
39 #include "fst.h"
40 #include "pbd/basename.h"
41 #include <cstring>
42
43 // dll-info
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <stdint.h>
48
49 #endif // WINDOWS_VST_SUPPORT
50
51 #ifdef LXVST_SUPPORT
52 #include "ardour/vst_info_file.h"
53 #include "ardour/linux_vst_support.h"
54 #include "pbd/basename.h"
55 #include <cstring>
56 #endif //LXVST_SUPPORT
57
58 #ifdef MACVST_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"
64 #include <cstring>
65 #endif //MACVST_SUPPORT
66
67 #include <glibmm/miscutils.h>
68 #include <glibmm/pattern.h>
69 #include <glibmm/fileutils.h>
70 #include <glibmm/miscutils.h>
71
72 #include "pbd/convert.h"
73 #include "pbd/file_utils.h"
74 #include "pbd/tokenizer.h"
75 #include "pbd/whitespace.h"
76
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"
87
88 #include "ardour/search_paths.h"
89
90 #ifdef LV2_SUPPORT
91 #include "ardour/lv2_plugin.h"
92 #endif
93
94 #ifdef WINDOWS_VST_SUPPORT
95 #include "ardour/windows_vst_plugin.h"
96 #endif
97
98 #ifdef LXVST_SUPPORT
99 #include "ardour/lxvst_plugin.h"
100 #endif
101
102 #ifdef AUDIOUNIT_SUPPORT
103 #include "ardour/audio_unit.h"
104 #include <Carbon/Carbon.h>
105 #endif
106
107 #include "pbd/error.h"
108 #include "pbd/stl_delete.h"
109
110 #include "pbd/i18n.h"
111
112 #include "ardour/debug.h"
113
114 using namespace ARDOUR;
115 using namespace PBD;
116 using namespace std;
117
118 PluginManager* PluginManager::_instance = 0;
119 std::string PluginManager::scanner_bin_path = "";
120
121 PluginManager&
122 PluginManager::instance()
123 {
124         if (!_instance) {
125                 _instance = new PluginManager;
126         }
127         return *_instance;
128 }
129
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)
136         , _au_plugin_info(0)
137         , _lua_plugin_info(0)
138         , _cancel_scan(false)
139         , _cancel_timeout(false)
140 {
141         char* s;
142         string lrdf_path;
143
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"));
147
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");
151 #else
152         // on Unices additional internal-use binaries are deployed to $libdir
153         vstsp += ARDOUR::ardour_dll_directory();
154 #endif
155
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"
161         #else
162                                 "ardour-vst-scannerRDC.exe"
163         #endif
164     #else
165                                 "ardour-vst-scanner.exe"
166     #endif
167 #else
168                                 "ardour-vst-scanner"
169 #endif
170                                 , scanner_bin_path)) {
171                 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() <<  endmsg;
172         }
173 #endif
174
175         load_statuses ();
176
177         load_tags ();
178
179         if ((s = getenv ("LADSPA_RDF_PATH"))){
180                 lrdf_path = s;
181         }
182
183         if (lrdf_path.length() == 0) {
184                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
185         }
186
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 ();
192         }
193 #endif /* WINDOWS_VST_SUPPORT */
194
195 #ifdef LXVST_SUPPORT
196         if (Config->get_use_lxvst()) {
197                 add_lxvst_presets();
198         }
199 #endif /* Native LinuxVST support*/
200
201 #ifdef MACVST_SUPPORT
202         if (Config->get_use_macvst ()) {
203                 add_mac_vst_presets ();
204         }
205 #endif
206
207         if ((s = getenv ("VST_PATH"))) {
208                 windows_vst_path = s;
209         } else if ((s = getenv ("VST_PLUGINS"))) {
210                 windows_vst_path = s;
211         }
212
213         if (windows_vst_path.length() == 0) {
214                 windows_vst_path = vst_search_path ();
215         }
216
217         if ((s = getenv ("LXVST_PATH"))) {
218                 lxvst_path = s;
219         } else if ((s = getenv ("LXVST_PLUGINS"))) {
220                 lxvst_path = s;
221         }
222
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";
227         }
228
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());
232         }
233         if (Config->get_plugin_path_vst() == X_("@default@")) {
234                 Config->set_plugin_path_vst(get_default_windows_vst_path());
235         }
236
237         if (_instance == 0) {
238                 _instance = this;
239         }
240
241         BootMessage (_("Discovering Plugins"));
242
243         LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
244 }
245
246
247 PluginManager::~PluginManager()
248 {
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;
258         }
259 }
260
261 void
262 PluginManager::refresh (bool cache_only)
263 {
264         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
265
266         if (!lm.locked()) {
267                 return;
268         }
269
270         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
271         _cancel_scan = false;
272
273         BootMessage (_("Scanning LADSPA Plugins"));
274         ladspa_refresh ();
275         BootMessage (_("Scanning Lua DSP Processors"));
276         lua_refresh ();
277 #ifdef LV2_SUPPORT
278         BootMessage (_("Scanning LV2 Plugins"));
279         lv2_refresh ();
280 #endif
281 #ifdef WINDOWS_VST_SUPPORT
282         if (Config->get_use_windows_vst()) {
283                 if (cache_only) {
284                         BootMessage (_("Scanning Windows VST Plugins"));
285                 } else {
286                         BootMessage (_("Discovering Windows VST Plugins"));
287                 }
288                 windows_vst_refresh (cache_only);
289         }
290 #endif // WINDOWS_VST_SUPPORT
291
292 #ifdef LXVST_SUPPORT
293         if(Config->get_use_lxvst()) {
294                 if (cache_only) {
295                         BootMessage (_("Scanning Linux VST Plugins"));
296                 } else {
297                         BootMessage (_("Discovering Linux VST Plugins"));
298                 }
299                 lxvst_refresh(cache_only);
300         }
301 #endif //Native linuxVST SUPPORT
302
303 #ifdef MACVST_SUPPORT
304         if(Config->get_use_macvst ()) {
305                 if (cache_only) {
306                         BootMessage (_("Scanning Mac VST Plugins"));
307                 } else {
308                         BootMessage (_("Discovering Mac VST Plugins"));
309                 }
310                 mac_vst_refresh (cache_only);
311         } else if (_mac_vst_plugin_info) {
312                 _mac_vst_plugin_info->clear ();
313         } else {
314                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
315         }
316 #endif //Native Mac VST SUPPORT
317
318 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
319                 if (!cache_only) {
320                         string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
321                         if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
322                                 gchar *bl = NULL;
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;
326                                         } else {
327                                                 PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg;
328                                         }
329                                         g_free (bl);
330                                 }
331                         }
332                 }
333 #endif
334
335 #ifdef AUDIOUNIT_SUPPORT
336         if (cache_only) {
337                 BootMessage (_("Scanning AU Plugins"));
338         } else {
339                 BootMessage (_("Discovering AU Plugins"));
340         }
341         au_refresh (cache_only);
342 #endif
343
344         BootMessage (_("Plugin Scan Complete..."));
345         PluginListChanged (); /* EMIT SIGNAL */
346         PluginScanMessage(X_("closeme"), "", false);
347         _cancel_scan = false;
348 }
349
350 void
351 PluginManager::cancel_plugin_scan ()
352 {
353         _cancel_scan = true;
354 }
355
356 void
357 PluginManager::cancel_plugin_timeout ()
358 {
359         _cancel_timeout = true;
360 }
361
362 void
363 PluginManager::clear_vst_cache ()
364 {
365 #if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
366 #ifdef WINDOWS_VST_SUPPORT
367         {
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());
372                 }
373         }
374         {
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());
379                 }
380         }
381         {
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());
386                 }
387         }
388 #endif
389
390 #ifdef LXVST_SUPPORT
391         {
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());
396                 }
397         }
398         {
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());
403                 }
404         }
405         {
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());
410                 }
411         }
412 #endif
413 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
414         {
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);
418                 }
419         }
420 #endif
421 #endif // old cache cleanup
422
423 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
424         {
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());
430                 }
431         }
432 #endif
433 }
434
435 void
436 PluginManager::clear_vst_blacklist ()
437 {
438 #if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0)
439
440 #ifdef WINDOWS_VST_SUPPORT
441         {
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());
446                 }
447         }
448 #endif
449
450 #ifdef LXVST_SUPPORT
451         {
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());
456                 }
457         }
458 #endif
459 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
460         {
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);
464                 }
465         }
466 #endif
467
468 #endif // old blacklist cleanup
469
470 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
471         {
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());
475                 }
476         }
477 #endif
478
479 }
480
481 void
482 PluginManager::clear_au_cache ()
483 {
484 #ifdef AUDIOUNIT_SUPPORT
485         AUPluginInfo::clear_cache ();
486 #endif
487 }
488
489 void
490 PluginManager::clear_au_blacklist ()
491 {
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());
496         }
497 #endif
498 }
499
500 void
501 PluginManager::lua_refresh ()
502 {
503         if (_lua_plugin_info) {
504                 _lua_plugin_info->clear ();
505         } else {
506                 _lua_plugin_info = new ARDOUR::PluginInfoList ();
507         }
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);
513         }
514 }
515
516 void
517 PluginManager::lua_refresh_cb ()
518 {
519         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
520         if (!lm.locked()) {
521                 return;
522         }
523         lua_refresh ();
524         PluginListChanged (); /* EMIT SIGNAL */
525 }
526
527 void
528 PluginManager::ladspa_refresh ()
529 {
530         if (_ladspa_plugin_info) {
531                 _ladspa_plugin_info->clear ();
532         } else {
533                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
534         }
535
536         /* allow LADSPA_PATH to augment, not override standard locations */
537
538         /* Only add standard locations to ladspa_path if it doesn't
539          * already contain them. Check for trailing G_DIR_SEPARATOR too.
540          */
541
542         vector<string> ladspa_modules;
543
544         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
545
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");
549
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);
553         }
554 }
555
556 #ifdef HAVE_LRDF
557 static bool rdf_filter (const string &str, void* /*arg*/)
558 {
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)));
564 }
565 #endif
566
567 void
568 PluginManager::add_ladspa_presets()
569 {
570         add_presets ("ladspa");
571 }
572
573 void
574 PluginManager::add_windows_vst_presets()
575 {
576         add_presets ("windows-vst");
577 }
578
579 void
580 PluginManager::add_mac_vst_presets()
581 {
582         add_presets ("mac-vst");
583 }
584
585 void
586 PluginManager::add_lxvst_presets()
587 {
588         add_presets ("lxvst");
589 }
590
591 void
592 PluginManager::add_presets(string domain)
593 {
594 #ifdef HAVE_LRDF
595         vector<string> presets;
596         vector<string>::iterator x;
597
598         char* envvar;
599         if ((envvar = getenv ("HOME")) == 0) {
600                 return;
601         }
602
603         string path = string_compose("%1/.%2/rdf", envvar, domain);
604         find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
605
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;
610                 }
611         }
612
613 #endif
614 }
615
616 void
617 PluginManager::add_lrdf_data (const string &path)
618 {
619 #ifdef HAVE_LRDF
620         vector<string> rdf_files;
621         vector<string>::iterator x;
622
623         find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
624
625         for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
626                 const string uri(string("file://") + *x);
627
628                 if (lrdf_read_file(uri.c_str())) {
629                         warning << "Could not parse rdf file: " << uri << endmsg;
630                 }
631         }
632 #endif
633 }
634
635 int
636 PluginManager::ladspa_discover (string path)
637 {
638         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
639
640         Glib::Module module(path);
641         const LADSPA_Descriptor *descriptor;
642         LADSPA_Descriptor_Function dfunc;
643         void* func = 0;
644
645         if (!module) {
646                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
647                         path, Glib::Module::get_last_error()) << endmsg;
648                 return -1;
649         }
650
651
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;
655                 return -1;
656         }
657
658         dfunc = (LADSPA_Descriptor_Function)func;
659
660         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
661
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.
667                  */
668                 if ((descriptor = dfunc (i)) == 0) {
669                         break;
670                 }
671
672                 if (!ladspa_plugin_whitelist.empty()) {
673                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
674                                 continue;
675                         }
676                 }
677
678                 PluginInfoPtr info(new LadspaPluginInfo);
679                 info->name = descriptor->Name;
680                 info->category = get_ladspa_category(descriptor->UniqueID);
681                 info->path = path;
682                 info->index = i;
683                 info->n_inputs = ChanCount();
684                 info->n_outputs = ChanCount();
685                 info->type = ARDOUR::LADSPA;
686
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;
692 #else
693                 while (pos < creator.length() && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
694 #endif
695
696                 /* If there were too few characters to create a
697                  * meaningful name, mark this creator as 'Unknown'
698                  */
699                 if (creator.length() < 2 || pos < 3) {
700                         info->creator = "Unknown";
701                 } else{
702                         info->creator = creator.substr (0, pos);
703                 }
704
705                 char buf[32];
706                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
707                 info->unique_id = buf;
708
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);
713                                 }
714                                 else if (LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n])) {
715                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
716                                 }
717                         }
718                 }
719
720                 if(_ladspa_plugin_info->empty()){
721                         _ladspa_plugin_info->push_back (info);
722                 }
723
724                 //Ensure that the plugin is not already in the plugin list.
725
726                 bool found = false;
727
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)){
730                               found = true;
731                         }
732                 }
733
734                 if(!found){
735                     _ladspa_plugin_info->push_back (info);
736                         set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
737                 }
738
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));
740         }
741
742 // GDB WILL NOT LIKE YOU IF YOU DO THIS
743 //      dlclose (module);
744
745         return 0;
746 }
747
748 string
749 PluginManager::get_ladspa_category (uint32_t plugin_id)
750 {
751 #ifdef HAVE_LRDF
752         char buf[256];
753         lrdf_statement pattern;
754
755         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
756         pattern.subject = buf;
757         pattern.predicate = const_cast<char*>(RDF_TYPE);
758         pattern.object = 0;
759         pattern.object_type = lrdf_uri;
760
761         lrdf_statement* matches1 = lrdf_matches (&pattern);
762
763         if (!matches1) {
764                 return "Unknown";
765         }
766
767         pattern.subject = matches1->object;
768         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
769         pattern.object = 0;
770         pattern.object_type = lrdf_literal;
771
772         lrdf_statement* matches2 = lrdf_matches (&pattern);
773         lrdf_free_statements(matches1);
774
775         if (!matches2) {
776                 return ("Unknown");
777         }
778
779         string label = matches2->object;
780         lrdf_free_statements(matches2);
781
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
785            filthy kludge.
786
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.
792
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.
797         */
798         if (label == "Utilities") {
799                 return "Utility";
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);
806         } else {
807                 return label;
808         }
809 #else
810                 return ("Unknown");
811 #endif
812 }
813
814 #ifdef LV2_SUPPORT
815 void
816 PluginManager::lv2_refresh ()
817 {
818         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
819         delete _lv2_plugin_info;
820         _lv2_plugin_info = LV2PluginInfo::discover();
821
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);
824         }
825 }
826 #endif
827
828 #ifdef AUDIOUNIT_SUPPORT
829 void
830 PluginManager::au_refresh (bool cache_only)
831 {
832         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
833
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();
838
839         delete _au_plugin_info;
840         _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
841
842         // successful scan re-enabled automatic discovery if it was set
843         Config->set_discover_audio_units (discover_at_start);
844         Config->save_state();
845
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);
848         }
849 }
850
851 #endif
852
853 #ifdef WINDOWS_VST_SUPPORT
854
855 void
856 PluginManager::windows_vst_refresh (bool cache_only)
857 {
858         if (_windows_vst_plugin_info) {
859                 _windows_vst_plugin_info->clear ();
860         } else {
861                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
862         }
863
864         windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
865 }
866
867 static bool windows_vst_filter (const string& str, void * /*arg*/)
868 {
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));
871 }
872
873 int
874 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
875 {
876         vector<string> plugin_objects;
877         vector<string>::iterator x;
878         int ret = 0;
879
880         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
881
882         if (Session::get_disable_all_loaded_plugins ()) {
883                 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
884                 return -1;
885         }
886
887         if (Config->get_verbose_plugin_scan()) {
888                 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
889         }
890
891         find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
892
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());
896         }
897
898         if (Config->get_verbose_plugin_scan()) {
899                 info << _("--- Windows VST plugins Scan Done") << endmsg;
900         }
901
902         return ret;
903 }
904
905 static std::string dll_info (std::string path) {
906         std::string rv;
907         uint8_t buf[68];
908         uint16_t type = 0;
909         off_t pe_hdr_off = 0;
910
911         int fd = g_open(path.c_str(), O_RDONLY, 0444);
912
913         if (fd < 0) {
914                 return _("cannot open dll"); // TODO strerror()
915         }
916
917         if (68 != read (fd, buf, 68)) {
918                 rv = _("invalid dll, file too small");
919                 goto errorout;
920         }
921         if (buf[0] != 'M' && buf[1] != 'Z') {
922                 rv = _("not a dll");
923                 goto errorout;
924         }
925
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");
929                 goto errorout;
930         }
931         if (6 != read (fd, buf, 6)) {
932                 rv = _("cannot read dll PE header");
933                 goto errorout;
934         }
935
936         if (buf[0] != 'P' && buf[1] != 'E') {
937                 rv = _("invalid dll PE header");
938                 goto errorout;
939         }
940
941         type = *((uint16_t*) &buf[4]);
942         switch (type) {
943                 case 0x014c:
944                         rv = _("i386 (32-bit)");
945                         break;
946                 case  0x0200:
947                         rv = _("Itanium");
948                         break;
949                 case 0x8664:
950                         rv = _("x64 (64-bit)");
951                         break;
952                 case 0:
953                         rv = _("Native Architecture");
954                         break;
955                 default:
956                         rv = _("Unknown Architecture");
957                         break;
958         }
959 errorout:
960         assert (rv.length() > 0);
961         close (fd);
962         return rv;
963 }
964
965 int
966 PluginManager::windows_vst_discover (string path, bool cache_only)
967 {
968         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
969
970         if (Config->get_verbose_plugin_scan()) {
971                 if (cache_only) {
972                         info << string_compose (_(" *  %1 (cache only)"), path) << endmsg;
973                 } else {
974                         info << string_compose (_(" *  %1 - %2"), path, dll_info (path)) << endmsg;
975                 }
976         }
977
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);
981
982         // TODO  get extended error messae from vstfx_get_info_fst() e.g  blacklisted, 32/64bit compat,
983         // .err file scanner output etc.
984
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;
989                 }
990                 return -1;
991         }
992
993         uint32_t discovered = 0;
994         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
995                 VSTInfo* finfo = *x;
996                 char buf[32];
997
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)
1001                                 << endl;
1002                         continue;
1003                 }
1004
1005                 PluginInfoPtr info (new WindowsVSTPluginInfo);
1006
1007                 /* what a joke freeware VST is */
1008
1009                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1010                         info->name = PBD::basename_nosuffix (path);
1011                 } else {
1012                         info->name = finfo->name;
1013                 }
1014
1015
1016                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1017                 info->unique_id = buf;
1018                 info->category = finfo->Category;
1019                 info->path = path;
1020                 info->creator = finfo->creator;
1021                 info->index = 0;
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;
1027
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);
1030
1031                 // TODO: check dup-IDs (lxvst AND windows vst)
1032                 bool duplicate = false;
1033
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;
1038                                         duplicate = true;
1039                                         break;
1040                                 }
1041                         }
1042                 }
1043
1044                 if (!duplicate) {
1045                         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1046                         _windows_vst_plugin_info->push_back (info);
1047                         discovered++;
1048                         if (Config->get_verbose_plugin_scan()) {
1049                                 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1050                         }
1051                 }
1052         }
1053
1054         vstfx_free_info_list (finfos);
1055         return discovered > 0 ? 0 : -1;
1056 }
1057
1058 #endif // WINDOWS_VST_SUPPORT
1059
1060 #ifdef MACVST_SUPPORT
1061 void
1062 PluginManager::mac_vst_refresh (bool cache_only)
1063 {
1064         if (_mac_vst_plugin_info) {
1065                 _mac_vst_plugin_info->clear ();
1066         } else {
1067                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1068         }
1069
1070         mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1071 }
1072
1073 static bool mac_vst_filter (const string& str)
1074 {
1075         string plist = Glib::build_filename (str, "Contents", "Info.plist");
1076         if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1077                 return false;
1078         }
1079         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1080 }
1081
1082 int
1083 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1084 {
1085         if (Session::get_disable_all_loaded_plugins ()) {
1086                 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1087                 return -1;
1088         }
1089
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;
1095                 try {
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);
1099
1100                                 /* we're only interested in bundles */
1101                                 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1102                                         continue;
1103                                 }
1104
1105                                 if (mac_vst_filter (fullpath)) {
1106                                         ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1107                                         mac_vst_discover (fullpath, cache_only || cancelled());
1108                                         continue;
1109                                 }
1110
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)))) {
1113                                         continue;
1114                                 }
1115
1116                                 /* recurse */
1117                                 mac_vst_discover_from_path (fullpath, cache_only);
1118                         }
1119                 } catch (Glib::FileError& err) { }
1120         }
1121
1122         return 0;
1123 }
1124
1125 int
1126 PluginManager::mac_vst_discover (string path, bool cache_only)
1127 {
1128         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1129
1130         _cancel_timeout = false;
1131
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);
1134
1135         if (finfos->empty()) {
1136                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1137                 return -1;
1138         }
1139
1140         uint32_t discovered = 0;
1141         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1142                 VSTInfo* finfo = *x;
1143                 char buf[32];
1144
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)
1148                                 << endl;
1149                         continue;
1150                 }
1151
1152                 PluginInfoPtr info (new MacVSTPluginInfo);
1153
1154                 info->name = finfo->name;
1155
1156                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1157                 info->unique_id = buf;
1158                 info->category = finfo->Category;
1159                 info->path = path;
1160                 info->creator = finfo->creator;
1161                 info->index = 0;
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;
1167
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);
1170
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";
1176                                         duplicate = true;
1177                                         break;
1178                                 }
1179                         }
1180                 }
1181
1182                 if (!duplicate) {
1183                         _mac_vst_plugin_info->push_back (info);
1184                         discovered++;
1185                 }
1186         }
1187
1188         vstfx_free_info_list (finfos);
1189         return discovered > 0 ? 0 : -1;
1190 }
1191
1192 #endif // MAC_VST_SUPPORT
1193
1194 #ifdef LXVST_SUPPORT
1195
1196 void
1197 PluginManager::lxvst_refresh (bool cache_only)
1198 {
1199         if (_lxvst_plugin_info) {
1200                 _lxvst_plugin_info->clear ();
1201         } else {
1202                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1203         }
1204
1205         lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1206 }
1207
1208 static bool lxvst_filter (const string& str, void *)
1209 {
1210         /* Not a dotfile, has a prefix before a period, suffix is "so" */
1211
1212         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1213 }
1214
1215 int
1216 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1217 {
1218         vector<string> plugin_objects;
1219         vector<string>::iterator x;
1220         int ret = 0;
1221
1222         if (Session::get_disable_all_loaded_plugins ()) {
1223                 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1224                 return -1;
1225         }
1226
1227 #ifndef NDEBUG
1228         (void) path;
1229 #endif
1230
1231         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1232
1233         find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1234
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());
1238         }
1239
1240         return ret;
1241 }
1242
1243 int
1244 PluginManager::lxvst_discover (string path, bool cache_only)
1245 {
1246         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1247
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);
1251
1252         if (finfos->empty()) {
1253                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1254                 return -1;
1255         }
1256
1257         uint32_t discovered = 0;
1258         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1259                 VSTInfo* finfo = *x;
1260                 char buf[32];
1261
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)
1265                                 << endl;
1266                         continue;
1267                 }
1268
1269                 PluginInfoPtr info(new LXVSTPluginInfo);
1270
1271                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1272                         info->name = PBD::basename_nosuffix (path);
1273                 } else {
1274                         info->name = finfo->name;
1275                 }
1276
1277
1278                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1279                 info->unique_id = buf;
1280                 info->category = finfo->Category;
1281                 info->path = path;
1282                 info->creator = finfo->creator;
1283                 info->index = 0;
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;
1289
1290                 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1291
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...)
1297                  */
1298
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";
1305                                         duplicate = true;
1306                                         break;
1307                                 }
1308                         }
1309                 }
1310
1311                 if (!duplicate) {
1312                         _lxvst_plugin_info->push_back (info);
1313                         discovered++;
1314                 }
1315         }
1316
1317         vstfx_free_info_list (finfos);
1318         return discovered > 0 ? 0 : -1;
1319 }
1320
1321 #endif // LXVST_SUPPORT
1322
1323
1324 PluginManager::PluginStatusType
1325 PluginManager::get_status (const PluginInfoPtr& pi) const
1326 {
1327         PluginStatus ps (pi->type, pi->unique_id);
1328         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
1329         if (i ==  statuses.end()) {
1330                 return Normal;
1331         } else {
1332                 return i->status;
1333         }
1334 }
1335
1336 void
1337 PluginManager::save_statuses ()
1338 {
1339         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1340         stringstream ofs;
1341
1342         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1343                 switch ((*i).type) {
1344                 case LADSPA:
1345                         ofs << "LADSPA";
1346                         break;
1347                 case AudioUnit:
1348                         ofs << "AudioUnit";
1349                         break;
1350                 case LV2:
1351                         ofs << "LV2";
1352                         break;
1353                 case Windows_VST:
1354                         ofs << "Windows-VST";
1355                         break;
1356                 case LXVST:
1357                         ofs << "LXVST";
1358                         break;
1359                 case MacVST:
1360                         ofs << "MacVST";
1361                         break;
1362                 case Lua:
1363                         ofs << "Lua";
1364                         break;
1365                 }
1366
1367                 ofs << ' ';
1368
1369                 switch ((*i).status) {
1370                 case Normal:
1371                         ofs << "Normal";
1372                         break;
1373                 case Favorite:
1374                         ofs << "Favorite";
1375                         break;
1376                 case Hidden:
1377                         ofs << "Hidden";
1378                         break;
1379                 }
1380
1381                 ofs << ' ';
1382
1383                 ofs << (*i).unique_id;;
1384                 ofs << endl;
1385         }
1386         g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1387 }
1388
1389 void
1390 PluginManager::load_statuses ()
1391 {
1392         std::string path;
1393         find_file (plugin_metadata_search_path(), "plugin_statuses", path);  //note: if no user folder is found, this will find the resources path
1394         gchar *fbuf = NULL;
1395         if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL))  {
1396                 return;
1397         }
1398         stringstream ifs (fbuf);
1399         g_free (fbuf);
1400
1401         std::string stype;
1402         std::string sstatus;
1403         std::string id;
1404         PluginType type;
1405         PluginStatusType status;
1406         char buf[1024];
1407
1408         while (ifs) {
1409
1410                 ifs >> stype;
1411                 if (!ifs) {
1412                         break;
1413
1414                 }
1415
1416                 ifs >> sstatus;
1417                 if (!ifs) {
1418                         break;
1419
1420                 }
1421
1422                 /* rest of the line is the plugin ID */
1423
1424                 ifs.getline (buf, sizeof (buf), '\n');
1425                 if (!ifs) {
1426                         break;
1427                 }
1428
1429                 if (sstatus == "Normal") {
1430                         status = Normal;
1431                 } else if (sstatus == "Favorite") {
1432                         status = Favorite;
1433                 } else if (sstatus == "Hidden") {
1434                         status = Hidden;
1435                 } else {
1436                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1437                                   << endmsg;
1438                         statuses.clear ();
1439                         break;
1440                 }
1441
1442                 if (stype == "LADSPA") {
1443                         type = LADSPA;
1444                 } else if (stype == "AudioUnit") {
1445                         type = AudioUnit;
1446                 } else if (stype == "LV2") {
1447                         type = LV2;
1448                 } else if (stype == "Windows-VST") {
1449                         type = Windows_VST;
1450                 } else if (stype == "LXVST") {
1451                         type = LXVST;
1452                 } else if (stype == "MacVST") {
1453                         type = MacVST;
1454                 } else if (stype == "Lua") {
1455                         type = Lua;
1456                 } else {
1457                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1458                               << endmsg;
1459                         continue;
1460                 }
1461
1462                 id = buf;
1463                 strip_whitespace_edges (id);
1464                 set_status (type, id, status);
1465         }
1466 }
1467
1468 void
1469 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1470 {
1471         PluginStatus ps (t, id, status);
1472         statuses.erase (ps);
1473
1474         if (status != Normal) {
1475                 statuses.insert (ps);
1476         }
1477
1478         PluginStatusChanged (t, id, status); /* EMIT SIGNAL */
1479 }
1480
1481 PluginType
1482 PluginManager::to_generic_vst (const PluginType t)
1483 {
1484         switch (t) {
1485                 case Windows_VST:
1486                 case LXVST:
1487                 case MacVST:
1488                         return LXVST;
1489                 default:
1490                         break;
1491         }
1492         return t;
1493 }
1494
1495 struct SortByTag {
1496         bool operator() (std::string a, std::string b) {
1497                 return a.compare (b) < 0;
1498         }
1499 };
1500
1501 vector<std::string>
1502 PluginManager::get_tags (const PluginInfoPtr& pi) const
1503 {
1504         vector<std::string> tags;
1505
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);
1510                 SortByTag sorter;
1511                 sort (tags.begin(), tags.end(), sorter);
1512         }
1513         return tags;
1514 }
1515
1516 std::string
1517 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1518 {
1519         std::string ret;
1520
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 ()) {
1524                         ret.append(" ");
1525                 }
1526                 ret.append(*t);
1527         }
1528
1529         return ret;
1530 }
1531
1532 std::string
1533 PluginManager::user_plugin_metadata_dir () const
1534 {
1535         std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1536         g_mkdir_with_parents (dir.c_str(), 0744);
1537         return dir;
1538 }
1539
1540 bool
1541 PluginManager::load_plugin_order_file (XMLNode &n) const
1542 {
1543         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1544
1545         info << string_compose (_("Loading plugin order file %1"), path) << endmsg;
1546         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1547                 return false;
1548         }
1549
1550         XMLTree tree;
1551         if (tree.read (path)) {
1552                 n = *(tree.root());
1553                 return true;
1554         } else {
1555                 error << string_compose (_("Cannot parse Plugin Order info from %1"), path) << endmsg;
1556                 return false;
1557         }
1558 }
1559
1560
1561 void
1562 PluginManager::save_plugin_order_file (XMLNode &elem) const
1563 {
1564         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1565
1566         info << string_compose (_("Saving plugin order file %1"), path) << endmsg;
1567
1568         XMLTree tree;
1569         tree.set_root (&elem);
1570         if (!tree.write (path)) {
1571                 error << string_compose (_("Could not save Plugin Order info to %1"), path) << endmsg;
1572         }
1573         tree.set_root (0);  //note: must disconnect the elem from XMLTree, or it will try to delete memory it didn't allocate
1574 }
1575
1576
1577 void
1578 PluginManager::save_tags ()
1579 {
1580         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1581         XMLNode* root = new XMLNode (X_("PluginTags"));
1582
1583         for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1584                 if ( (*i).tagtype == FromFactoryFile || (*i).tagtype == FromUserFile ) {
1585                         /* user file should contain only plugins that are (a) newly user-tagged or (b) previously unknown */
1586                         continue;
1587                 }
1588                 XMLNode* node = new XMLNode (X_("Plugin"));
1589                 node->set_property (X_("type"), to_generic_vst ((*i).type));
1590                 node->set_property (X_("id"), (*i).unique_id);
1591                 node->set_property (X_("tags"), (*i).tags);
1592                 node->set_property (X_("name"), (*i).name);
1593                 if ( (*i).tagtype >= FromUserFile ) {
1594                         node->set_property (X_("user-set"), "1");
1595                 }
1596                 root->add_child_nocopy (*node);
1597         }
1598
1599         XMLTree tree;
1600         tree.set_root (root);
1601         if (!tree.write (path)) {
1602                 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1603         }
1604 }
1605
1606 void
1607 PluginManager::load_tags ()
1608 {
1609         vector<std::string> tmp;
1610         find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1611
1612         for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
1613                         p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
1614                 std::string path = *p;
1615                 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1616                 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1617                         return;
1618                 }
1619
1620                 XMLTree tree;
1621                 if (!tree.read (path)) {
1622                         error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1623                         return;
1624                 }
1625
1626                 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1627                         PluginType type;
1628                         string id;
1629                         string tags;
1630                         string name;
1631                         bool user_set;
1632                         if (!(*i)->get_property (X_("type"), type) ||
1633                                         !(*i)->get_property (X_("id"), id) ||
1634                                         !(*i)->get_property (X_("tags"), tags) ||
1635                                         !(*i)->get_property (X_("name"), name)) {
1636                         }
1637                         if (!(*i)->get_property (X_("user-set"), user_set)) {
1638                                 user_set = false;
1639                         }
1640                         strip_whitespace_edges (tags);
1641                         set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile );
1642                 }
1643         }
1644 }
1645
1646 void
1647 PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype )
1648 {
1649         string sanitized = sanitize_tag (tag);
1650
1651         PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype );
1652         PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1653         if (i == ptags.end()) {
1654                 ptags.insert (ps);
1655         } else if ( (uint32_t) ttype >=  (uint32_t) (*i).tagtype ) {  // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
1656                 ptags.erase (ps);
1657                 ptags.insert (ps);
1658         }
1659         if ( ttype == FromGui ) {
1660                 PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
1661         }
1662 }
1663
1664 void
1665 PluginManager::reset_tags (PluginInfoPtr const& pi)
1666 {
1667         PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
1668
1669         PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1670         if (i != ptags.end()) {
1671                 ptags.erase (ps);
1672                 ptags.insert (ps);
1673         }
1674 }
1675
1676 std::string
1677 PluginManager::sanitize_tag (const std::string to_sanitize) const
1678 {
1679         if (to_sanitize.empty ()) {
1680                 return "";
1681         }
1682         string sanitized = to_sanitize;
1683         vector<string> tags;
1684         if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1685 #ifndef NDEBUG
1686                 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1687 #endif
1688                 return "";
1689         }
1690
1691         /* convert tokens to lower-case, space-separated list */
1692         sanitized = "";
1693         for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1694                 if (t != tags.begin ()) {
1695                         sanitized.append(" ");
1696                 }
1697                 sanitized.append (downcase (*t));
1698         }
1699
1700         return sanitized;
1701 }
1702
1703 std::vector<std::string>
1704 PluginManager::get_all_tags (TagFilter tag_filter) const
1705 {
1706         std::vector<std::string> ret;
1707
1708         PluginTagList::const_iterator pt;
1709         for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1710                 if ((*pt).tags.empty ()) {
1711                         continue;
1712                 }
1713
1714                 /* if favorites_only then we need to check the info ptr and maybe skip */
1715                 if (tag_filter == OnlyFavorites) {
1716                         PluginStatus stat ((*pt).type, (*pt).unique_id);
1717                         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), stat);
1718                         if ((i != statuses.end()) && (i->status == Favorite)) {
1719                                 /* it's a favorite! */
1720                         } else {
1721                                 continue;
1722                         }
1723                 }
1724                 if (tag_filter == NoHidden) {
1725                         PluginStatus stat ((*pt).type, (*pt).unique_id);
1726                         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), stat);
1727                         if ((i != statuses.end()) && (i->status == Hidden)) {
1728                                 continue;
1729                         }
1730                 }
1731
1732                 /* parse each plugin's tag string into separate tags */
1733                 vector<string> tags;
1734                 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1735 #ifndef NDEBUG
1736                         cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1737 #endif
1738                         continue;
1739                 }
1740
1741                 /* maybe add the tags we've found */
1742                 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1743                         /* if this tag isn't already in the list, add it */
1744                         vector<string>::iterator i =  find (ret.begin(), ret.end(), *t);
1745                         if (i == ret.end()) {
1746                                 ret.push_back (*t);
1747                         }
1748                 }
1749         }
1750
1751         /* sort in alphabetical order */
1752         SortByTag sorter;
1753         sort (ret.begin(), ret.end(), sorter);
1754
1755         return ret;
1756 }
1757
1758
1759 const ARDOUR::PluginInfoList&
1760 PluginManager::windows_vst_plugin_info ()
1761 {
1762 #ifdef WINDOWS_VST_SUPPORT
1763         if (!_windows_vst_plugin_info) {
1764                 windows_vst_refresh ();
1765         }
1766         return *_windows_vst_plugin_info;
1767 #else
1768         return _empty_plugin_info;
1769 #endif
1770 }
1771
1772 const ARDOUR::PluginInfoList&
1773 PluginManager::mac_vst_plugin_info ()
1774 {
1775 #ifdef MACVST_SUPPORT
1776         assert(_mac_vst_plugin_info);
1777         return *_mac_vst_plugin_info;
1778 #else
1779         return _empty_plugin_info;
1780 #endif
1781 }
1782
1783 const ARDOUR::PluginInfoList&
1784 PluginManager::lxvst_plugin_info ()
1785 {
1786 #ifdef LXVST_SUPPORT
1787         assert(_lxvst_plugin_info);
1788         return *_lxvst_plugin_info;
1789 #else
1790         return _empty_plugin_info;
1791 #endif
1792 }
1793
1794 const ARDOUR::PluginInfoList&
1795 PluginManager::ladspa_plugin_info ()
1796 {
1797         assert(_ladspa_plugin_info);
1798         return *_ladspa_plugin_info;
1799 }
1800
1801 const ARDOUR::PluginInfoList&
1802 PluginManager::lv2_plugin_info ()
1803 {
1804 #ifdef LV2_SUPPORT
1805         assert(_lv2_plugin_info);
1806         return *_lv2_plugin_info;
1807 #else
1808         return _empty_plugin_info;
1809 #endif
1810 }
1811
1812 const ARDOUR::PluginInfoList&
1813 PluginManager::au_plugin_info ()
1814 {
1815 #ifdef AUDIOUNIT_SUPPORT
1816         if (_au_plugin_info) {
1817                 return *_au_plugin_info;
1818         }
1819 #endif
1820         return _empty_plugin_info;
1821 }
1822
1823 const ARDOUR::PluginInfoList&
1824 PluginManager::lua_plugin_info ()
1825 {
1826         assert(_lua_plugin_info);
1827         return *_lua_plugin_info;
1828 }