a2c8010efae92be1b3ac1385cb4ea5fe32d46bca
[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, true);
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                 }
737
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));
739         }
740
741 // GDB WILL NOT LIKE YOU IF YOU DO THIS
742 //      dlclose (module);
743
744         return 0;
745 }
746
747 string
748 PluginManager::get_ladspa_category (uint32_t plugin_id)
749 {
750 #ifdef HAVE_LRDF
751         char buf[256];
752         lrdf_statement pattern;
753
754         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
755         pattern.subject = buf;
756         pattern.predicate = const_cast<char*>(RDF_TYPE);
757         pattern.object = 0;
758         pattern.object_type = lrdf_uri;
759
760         lrdf_statement* matches1 = lrdf_matches (&pattern);
761
762         if (!matches1) {
763                 return "Unknown";
764         }
765
766         pattern.subject = matches1->object;
767         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
768         pattern.object = 0;
769         pattern.object_type = lrdf_literal;
770
771         lrdf_statement* matches2 = lrdf_matches (&pattern);
772         lrdf_free_statements(matches1);
773
774         if (!matches2) {
775                 return ("Unknown");
776         }
777
778         string label = matches2->object;
779         lrdf_free_statements(matches2);
780
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
784            filthy kludge.
785
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.
791
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.
796         */
797         if (label == "Utilities") {
798                 return "Utility";
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);
805         } else {
806                 return label;
807         }
808 #else
809                 return ("Unknown");
810 #endif
811 }
812
813 #ifdef LV2_SUPPORT
814 void
815 PluginManager::lv2_refresh ()
816 {
817         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
818         delete _lv2_plugin_info;
819         _lv2_plugin_info = LV2PluginInfo::discover();
820
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);
823         }
824 }
825 #endif
826
827 #ifdef AUDIOUNIT_SUPPORT
828 void
829 PluginManager::au_refresh (bool cache_only)
830 {
831         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
832
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();
837
838         delete _au_plugin_info;
839         _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
840
841         // successful scan re-enabled automatic discovery if it was set
842         Config->set_discover_audio_units (discover_at_start);
843         Config->save_state();
844
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);
847         }
848 }
849
850 #endif
851
852 #ifdef WINDOWS_VST_SUPPORT
853
854 void
855 PluginManager::windows_vst_refresh (bool cache_only)
856 {
857         if (_windows_vst_plugin_info) {
858                 _windows_vst_plugin_info->clear ();
859         } else {
860                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
861         }
862
863         windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
864 }
865
866 static bool windows_vst_filter (const string& str, void * /*arg*/)
867 {
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));
870 }
871
872 int
873 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
874 {
875         vector<string> plugin_objects;
876         vector<string>::iterator x;
877         int ret = 0;
878
879         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
880
881         if (Session::get_disable_all_loaded_plugins ()) {
882                 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
883                 return -1;
884         }
885
886         if (Config->get_verbose_plugin_scan()) {
887                 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
888         }
889
890         find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
891
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());
895         }
896
897         if (Config->get_verbose_plugin_scan()) {
898                 info << _("--- Windows VST plugins Scan Done") << endmsg;
899         }
900
901         return ret;
902 }
903
904 static std::string dll_info (std::string path) {
905         std::string rv;
906         uint8_t buf[68];
907         uint16_t type = 0;
908         off_t pe_hdr_off = 0;
909
910         int fd = g_open(path.c_str(), O_RDONLY, 0444);
911
912         if (fd < 0) {
913                 return _("cannot open dll"); // TODO strerror()
914         }
915
916         if (68 != read (fd, buf, 68)) {
917                 rv = _("invalid dll, file too small");
918                 goto errorout;
919         }
920         if (buf[0] != 'M' && buf[1] != 'Z') {
921                 rv = _("not a dll");
922                 goto errorout;
923         }
924
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");
928                 goto errorout;
929         }
930         if (6 != read (fd, buf, 6)) {
931                 rv = _("cannot read dll PE header");
932                 goto errorout;
933         }
934
935         if (buf[0] != 'P' && buf[1] != 'E') {
936                 rv = _("invalid dll PE header");
937                 goto errorout;
938         }
939
940         type = *((uint16_t*) &buf[4]);
941         switch (type) {
942                 case 0x014c:
943                         rv = _("i386 (32-bit)");
944                         break;
945                 case  0x0200:
946                         rv = _("Itanium");
947                         break;
948                 case 0x8664:
949                         rv = _("x64 (64-bit)");
950                         break;
951                 case 0:
952                         rv = _("Native Architecture");
953                         break;
954                 default:
955                         rv = _("Unknown Architecture");
956                         break;
957         }
958 errorout:
959         assert (rv.length() > 0);
960         close (fd);
961         return rv;
962 }
963
964 int
965 PluginManager::windows_vst_discover (string path, bool cache_only)
966 {
967         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
968
969         if (Config->get_verbose_plugin_scan()) {
970                 if (cache_only) {
971                         info << string_compose (_(" *  %1 (cache only)"), path) << endmsg;
972                 } else {
973                         info << string_compose (_(" *  %1 - %2"), path, dll_info (path)) << endmsg;
974                 }
975         }
976
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);
980
981         // TODO  get extended error messae from vstfx_get_info_fst() e.g  blacklisted, 32/64bit compat,
982         // .err file scanner output etc.
983
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;
988                 }
989                 return -1;
990         }
991
992         uint32_t discovered = 0;
993         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
994                 VSTInfo* finfo = *x;
995                 char buf[32];
996
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)
1000                                 << endl;
1001                         continue;
1002                 }
1003
1004                 PluginInfoPtr info (new WindowsVSTPluginInfo);
1005
1006                 /* what a joke freeware VST is */
1007
1008                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1009                         info->name = PBD::basename_nosuffix (path);
1010                 } else {
1011                         info->name = finfo->name;
1012                 }
1013
1014
1015                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1016                 info->unique_id = buf;
1017                 info->category = finfo->category;
1018                 info->path = path;
1019                 info->creator = finfo->creator;
1020                 info->index = 0;
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;
1026
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);
1029
1030                 // TODO: check dup-IDs (lxvst AND windows vst)
1031                 bool duplicate = false;
1032
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;
1037                                         duplicate = true;
1038                                         break;
1039                                 }
1040                         }
1041                 }
1042
1043                 if (!duplicate) {
1044                         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1045                         _windows_vst_plugin_info->push_back (info);
1046                         discovered++;
1047                         if (Config->get_verbose_plugin_scan()) {
1048                                 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1049                         }
1050                 }
1051         }
1052
1053         vstfx_free_info_list (finfos);
1054         return discovered > 0 ? 0 : -1;
1055 }
1056
1057 #endif // WINDOWS_VST_SUPPORT
1058
1059 #ifdef MACVST_SUPPORT
1060 void
1061 PluginManager::mac_vst_refresh (bool cache_only)
1062 {
1063         if (_mac_vst_plugin_info) {
1064                 _mac_vst_plugin_info->clear ();
1065         } else {
1066                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1067         }
1068
1069         mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1070 }
1071
1072 static bool mac_vst_filter (const string& str)
1073 {
1074         string plist = Glib::build_filename (str, "Contents", "Info.plist");
1075         if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1076                 return false;
1077         }
1078         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1079 }
1080
1081 int
1082 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1083 {
1084         if (Session::get_disable_all_loaded_plugins ()) {
1085                 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1086                 return -1;
1087         }
1088
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;
1094                 try {
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);
1098
1099                                 /* we're only interested in bundles */
1100                                 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1101                                         continue;
1102                                 }
1103
1104                                 if (mac_vst_filter (fullpath)) {
1105                                         ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1106                                         mac_vst_discover (fullpath, cache_only || cancelled());
1107                                         continue;
1108                                 }
1109
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)))) {
1112                                         continue;
1113                                 }
1114
1115                                 /* recurse */
1116                                 mac_vst_discover_from_path (fullpath, cache_only);
1117                         }
1118                 } catch (Glib::FileError& err) { }
1119         }
1120
1121         return 0;
1122 }
1123
1124 int
1125 PluginManager::mac_vst_discover (string path, bool cache_only)
1126 {
1127         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1128
1129         _cancel_timeout = false;
1130
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);
1133
1134         if (finfos->empty()) {
1135                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1136                 return -1;
1137         }
1138
1139         uint32_t discovered = 0;
1140         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1141                 VSTInfo* finfo = *x;
1142                 char buf[32];
1143
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)
1147                                 << endl;
1148                         continue;
1149                 }
1150
1151                 PluginInfoPtr info (new MacVSTPluginInfo);
1152
1153                 info->name = finfo->name;
1154
1155                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1156                 info->unique_id = buf;
1157                 info->category = finfo->Category;
1158                 info->path = path;
1159                 info->creator = finfo->creator;
1160                 info->index = 0;
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;
1166
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);
1169
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";
1175                                         duplicate = true;
1176                                         break;
1177                                 }
1178                         }
1179                 }
1180
1181                 if (!duplicate) {
1182                         _mac_vst_plugin_info->push_back (info);
1183                         discovered++;
1184                 }
1185         }
1186
1187         vstfx_free_info_list (finfos);
1188         return discovered > 0 ? 0 : -1;
1189 }
1190
1191 #endif // MAC_VST_SUPPORT
1192
1193 #ifdef LXVST_SUPPORT
1194
1195 void
1196 PluginManager::lxvst_refresh (bool cache_only)
1197 {
1198         if (_lxvst_plugin_info) {
1199                 _lxvst_plugin_info->clear ();
1200         } else {
1201                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1202         }
1203
1204         lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1205 }
1206
1207 static bool lxvst_filter (const string& str, void *)
1208 {
1209         /* Not a dotfile, has a prefix before a period, suffix is "so" */
1210
1211         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1212 }
1213
1214 int
1215 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1216 {
1217         vector<string> plugin_objects;
1218         vector<string>::iterator x;
1219         int ret = 0;
1220
1221         if (Session::get_disable_all_loaded_plugins ()) {
1222                 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1223                 return -1;
1224         }
1225
1226 #ifndef NDEBUG
1227         (void) path;
1228 #endif
1229
1230         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1231
1232         find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1233
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());
1237         }
1238
1239         return ret;
1240 }
1241
1242 int
1243 PluginManager::lxvst_discover (string path, bool cache_only)
1244 {
1245         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1246
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);
1250
1251         if (finfos->empty()) {
1252                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1253                 return -1;
1254         }
1255
1256         uint32_t discovered = 0;
1257         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1258                 VSTInfo* finfo = *x;
1259                 char buf[32];
1260
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)
1264                                 << endl;
1265                         continue;
1266                 }
1267
1268                 PluginInfoPtr info(new LXVSTPluginInfo);
1269
1270                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1271                         info->name = PBD::basename_nosuffix (path);
1272                 } else {
1273                         info->name = finfo->name;
1274                 }
1275
1276
1277                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1278                 info->unique_id = buf;
1279                 info->category = finfo->Category;
1280                 info->path = path;
1281                 info->creator = finfo->creator;
1282                 info->index = 0;
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;
1288
1289                 set_tags (info->type, info->unique_id, info->category, true);
1290
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...)
1296                  */
1297
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";
1304                                         duplicate = true;
1305                                         break;
1306                                 }
1307                         }
1308                 }
1309
1310                 if (!duplicate) {
1311                         _lxvst_plugin_info->push_back (info);
1312                         discovered++;
1313                 }
1314         }
1315
1316         vstfx_free_info_list (finfos);
1317         return discovered > 0 ? 0 : -1;
1318 }
1319
1320 #endif // LXVST_SUPPORT
1321
1322
1323 PluginManager::PluginStatusType
1324 PluginManager::get_status (const PluginInfoPtr& pi) const
1325 {
1326         PluginStatus ps (pi->type, pi->unique_id);
1327         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
1328         if (i ==  statuses.end()) {
1329                 return Normal;
1330         } else {
1331                 return i->status;
1332         }
1333 }
1334
1335 void
1336 PluginManager::save_statuses ()
1337 {
1338         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1339         stringstream ofs;
1340
1341         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1342                 switch ((*i).type) {
1343                 case LADSPA:
1344                         ofs << "LADSPA";
1345                         break;
1346                 case AudioUnit:
1347                         ofs << "AudioUnit";
1348                         break;
1349                 case LV2:
1350                         ofs << "LV2";
1351                         break;
1352                 case Windows_VST:
1353                         ofs << "Windows-VST";
1354                         break;
1355                 case LXVST:
1356                         ofs << "LXVST";
1357                         break;
1358                 case MacVST:
1359                         ofs << "MacVST";
1360                         break;
1361                 case Lua:
1362                         ofs << "Lua";
1363                         break;
1364                 }
1365
1366                 ofs << ' ';
1367
1368                 switch ((*i).status) {
1369                 case Normal:
1370                         ofs << "Normal";
1371                         break;
1372                 case Favorite:
1373                         ofs << "Favorite";
1374                         break;
1375                 case Hidden:
1376                         ofs << "Hidden";
1377                         break;
1378                 }
1379
1380                 ofs << ' ';
1381
1382                 ofs << (*i).unique_id;;
1383                 ofs << endl;
1384         }
1385         g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1386 }
1387
1388 void
1389 PluginManager::load_statuses ()
1390 {
1391         std::string path;
1392         find_file (plugin_metadata_search_path(), "plugin_statuses", path);  //note: if no user folder is found, this will find the resources path
1393         gchar *fbuf = NULL;
1394         if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL))  {
1395                 return;
1396         }
1397         stringstream ifs (fbuf);
1398         g_free (fbuf);
1399
1400         std::string stype;
1401         std::string sstatus;
1402         std::string id;
1403         PluginType type;
1404         PluginStatusType status;
1405         char buf[1024];
1406
1407         while (ifs) {
1408
1409                 ifs >> stype;
1410                 if (!ifs) {
1411                         break;
1412
1413                 }
1414
1415                 ifs >> sstatus;
1416                 if (!ifs) {
1417                         break;
1418
1419                 }
1420
1421                 /* rest of the line is the plugin ID */
1422
1423                 ifs.getline (buf, sizeof (buf), '\n');
1424                 if (!ifs) {
1425                         break;
1426                 }
1427
1428                 if (sstatus == "Normal") {
1429                         status = Normal;
1430                 } else if (sstatus == "Favorite") {
1431                         status = Favorite;
1432                 } else if (sstatus == "Hidden") {
1433                         status = Hidden;
1434                 } else {
1435                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1436                                   << endmsg;
1437                         statuses.clear ();
1438                         break;
1439                 }
1440
1441                 if (stype == "LADSPA") {
1442                         type = LADSPA;
1443                 } else if (stype == "AudioUnit") {
1444                         type = AudioUnit;
1445                 } else if (stype == "LV2") {
1446                         type = LV2;
1447                 } else if (stype == "Windows-VST") {
1448                         type = Windows_VST;
1449                 } else if (stype == "LXVST") {
1450                         type = LXVST;
1451                 } else if (stype == "MacVST") {
1452                         type = MacVST;
1453                 } else if (stype == "Lua") {
1454                         type = Lua;
1455                 } else {
1456                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1457                               << endmsg;
1458                         continue;
1459                 }
1460
1461                 id = buf;
1462                 strip_whitespace_edges (id);
1463                 set_status (type, id, status);
1464         }
1465 }
1466
1467 void
1468 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1469 {
1470         PluginStatus ps (t, id, status);
1471         statuses.erase (ps);
1472
1473         if (status != Normal) {
1474                 statuses.insert (ps);
1475         }
1476
1477         PluginStatusesChanged (t, id, status); /* EMIT SIGNAL */
1478 }
1479
1480 PluginType
1481 PluginManager::to_generic_vst (const PluginType t)
1482 {
1483         switch (t) {
1484                 case Windows_VST:
1485                 case LXVST:
1486                 case MacVST:
1487                         return LXVST;
1488                 default:
1489                         break;
1490         }
1491         return t;
1492 }
1493
1494 struct SortByTag {
1495         bool operator() (std::string a, std::string b) {
1496                 return a.compare (b) < 0;
1497         }
1498 };
1499
1500 vector<std::string>
1501 PluginManager::get_tags (const PluginInfoPtr& pi) const
1502 {
1503         vector<std::string> tags;
1504
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);
1509                 SortByTag sorter;
1510                 sort (tags.begin(), tags.end(), sorter);
1511         }
1512         return tags;
1513 }
1514
1515 std::string
1516 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1517 {
1518         std::string ret;
1519
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 ()) {
1523                         ret.append(" ");
1524                 }
1525                 ret.append(*t);
1526         }
1527
1528         return ret;
1529 }
1530
1531 std::string
1532 PluginManager::user_plugin_metadata_dir () const
1533 {
1534         std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1535         g_mkdir_with_parents (dir.c_str(), 0744);
1536         return dir;
1537 }
1538
1539 void
1540 PluginManager::save_tags ()
1541 {
1542         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1543         XMLNode* root = new XMLNode (X_("PluginTags"));
1544
1545         for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1546                 if (!(*i).user_set) {
1547                         continue;
1548                 }
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);
1555         }
1556
1557         XMLTree tree;
1558         tree.set_root (root);
1559         if (!tree.write (path)) {
1560                 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1561         }
1562 }
1563
1564 void
1565 PluginManager::load_tags ()
1566 {
1567         vector<std::string> tmp;
1568         find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1569
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)) {
1574                         return;
1575                 }
1576
1577                 XMLTree tree;
1578                 if (!tree.read (path)) {
1579                         error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1580                         return;
1581                 }
1582
1583                 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1584                         PluginType type;
1585                         string id;
1586                         string tags;
1587                         bool user_set;
1588                         if (!(*i)->get_property (X_("type"), type) ||
1589                                         !(*i)->get_property (X_("id"), id) ||
1590                                         !(*i)->get_property (X_("tags"), tags)) {
1591                         }
1592                         if (!(*i)->get_property (X_("user-set"), user_set)) {
1593                                 user_set = false;
1594                         }
1595                         strip_whitespace_edges (tags);
1596                         set_tags (type, id, tags, !user_set);
1597                 }
1598         }
1599 }
1600
1601 void
1602 PluginManager::set_tags (PluginType t, string id, string tag, bool factory, bool force)
1603 {
1604         string sanitized = sanitize_tag (tag);
1605
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()) {
1609                 ptags.insert (ps);
1610         } else if (!factory || force || !(*i).user_set) {
1611                 ptags.erase (ps);
1612                 ptags.insert (ps);
1613         }
1614         if (!factory || force) {
1615                 PluginTagsChanged (t, id, sanitized); /* EMIT SIGNAL */
1616         }
1617 }
1618
1619 void
1620 PluginManager::reset_tags (PluginInfoPtr const& pi)
1621 {
1622         set_tags (pi->type, pi->unique_id, pi->category, true, true);
1623 }
1624
1625 std::string
1626 PluginManager::sanitize_tag (const std::string to_sanitize) const
1627 {
1628         if (to_sanitize.empty ()) {
1629                 return "";
1630         }
1631         string sanitized = to_sanitize;
1632         vector<string> tags;
1633         if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1634 #ifndef NDEBUG
1635                 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1636 #endif
1637                 return "";
1638         }
1639
1640         /* convert tokens to lower-case, space-separated list */
1641         sanitized = "";
1642         for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1643                 if (t != tags.begin ()) {
1644                         sanitized.append(" ");
1645                 }
1646                 sanitized.append (downcase (*t));
1647         }
1648
1649         return sanitized;
1650 }
1651
1652 std::vector<std::string>
1653 PluginManager::get_all_tags (bool favorites_only) const
1654 {
1655         std::vector<std::string> ret;
1656
1657         PluginTagList::const_iterator pt;
1658         for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1659                 if ((*pt).tags.empty ()) {
1660                         continue;
1661                 }
1662
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! */
1669                         } else {
1670                                 continue;
1671                         }
1672                 }
1673
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)) {
1677 #ifndef NDEBUG
1678                         cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1679 #endif
1680                         continue;
1681                 }
1682
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()) {
1688                                 ret.push_back (*t);
1689                         }
1690                 }
1691         }
1692
1693         /* sort in alphabetical order */
1694         SortByTag sorter;
1695         sort (ret.begin(), ret.end(), sorter);
1696
1697         return ret;
1698 }
1699
1700
1701 const ARDOUR::PluginInfoList&
1702 PluginManager::windows_vst_plugin_info ()
1703 {
1704 #ifdef WINDOWS_VST_SUPPORT
1705         if (!_windows_vst_plugin_info) {
1706                 windows_vst_refresh ();
1707         }
1708         return *_windows_vst_plugin_info;
1709 #else
1710         return _empty_plugin_info;
1711 #endif
1712 }
1713
1714 const ARDOUR::PluginInfoList&
1715 PluginManager::mac_vst_plugin_info ()
1716 {
1717 #ifdef MACVST_SUPPORT
1718         assert(_mac_vst_plugin_info);
1719         return *_mac_vst_plugin_info;
1720 #else
1721         return _empty_plugin_info;
1722 #endif
1723 }
1724
1725 const ARDOUR::PluginInfoList&
1726 PluginManager::lxvst_plugin_info ()
1727 {
1728 #ifdef LXVST_SUPPORT
1729         assert(_lxvst_plugin_info);
1730         return *_lxvst_plugin_info;
1731 #else
1732         return _empty_plugin_info;
1733 #endif
1734 }
1735
1736 const ARDOUR::PluginInfoList&
1737 PluginManager::ladspa_plugin_info ()
1738 {
1739         assert(_ladspa_plugin_info);
1740         return *_ladspa_plugin_info;
1741 }
1742
1743 const ARDOUR::PluginInfoList&
1744 PluginManager::lv2_plugin_info ()
1745 {
1746 #ifdef LV2_SUPPORT
1747         assert(_lv2_plugin_info);
1748         return *_lv2_plugin_info;
1749 #else
1750         return _empty_plugin_info;
1751 #endif
1752 }
1753
1754 const ARDOUR::PluginInfoList&
1755 PluginManager::au_plugin_info ()
1756 {
1757 #ifdef AUDIOUNIT_SUPPORT
1758         if (_au_plugin_info) {
1759                 return *_au_plugin_info;
1760         }
1761 #endif
1762         return _empty_plugin_info;
1763 }
1764
1765 const ARDOUR::PluginInfoList&
1766 PluginManager::lua_plugin_info ()
1767 {
1768         assert(_lua_plugin_info);
1769         return *_lua_plugin_info;
1770 }