Prepare plugin-meta-data config-dir and files
[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/whitespace.h"
73 #include "pbd/file_utils.h"
74
75 #include "ardour/directory_names.h"
76 #include "ardour/debug.h"
77 #include "ardour/filesystem_paths.h"
78 #include "ardour/ladspa.h"
79 #include "ardour/ladspa_plugin.h"
80 #include "ardour/luascripting.h"
81 #include "ardour/luaproc.h"
82 #include "ardour/plugin.h"
83 #include "ardour/plugin_manager.h"
84 #include "ardour/rc_configuration.h"
85
86 #include "ardour/search_paths.h"
87
88 #ifdef LV2_SUPPORT
89 #include "ardour/lv2_plugin.h"
90 #endif
91
92 #ifdef WINDOWS_VST_SUPPORT
93 #include "ardour/windows_vst_plugin.h"
94 #endif
95
96 #ifdef LXVST_SUPPORT
97 #include "ardour/lxvst_plugin.h"
98 #endif
99
100 #ifdef AUDIOUNIT_SUPPORT
101 #include "ardour/audio_unit.h"
102 #include <Carbon/Carbon.h>
103 #endif
104
105 #include "pbd/error.h"
106 #include "pbd/stl_delete.h"
107
108 #include "pbd/i18n.h"
109
110 #include "ardour/debug.h"
111
112 using namespace ARDOUR;
113 using namespace PBD;
114 using namespace std;
115
116 PluginManager* PluginManager::_instance = 0;
117 std::string PluginManager::scanner_bin_path = "";
118
119 PluginManager&
120 PluginManager::instance()
121 {
122         if (!_instance) {
123                 _instance = new PluginManager;
124         }
125         return *_instance;
126 }
127
128 PluginManager::PluginManager ()
129         : _windows_vst_plugin_info(0)
130         , _lxvst_plugin_info(0)
131         , _mac_vst_plugin_info(0)
132         , _ladspa_plugin_info(0)
133         , _lv2_plugin_info(0)
134         , _au_plugin_info(0)
135         , _lua_plugin_info(0)
136         , _cancel_scan(false)
137         , _cancel_timeout(false)
138 {
139         char* s;
140         string lrdf_path;
141
142 #if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
143         // source-tree (ardev, etc)
144         PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
145
146 #ifdef PLATFORM_WINDOWS
147         // on windows the .exe needs to be in the same folder with libardour.dll
148         vstsp += Glib::build_filename(windows_package_directory_path(), "bin");
149 #else
150         // on Unices additional internal-use binaries are deployed to $libdir
151         vstsp += ARDOUR::ardour_dll_directory();
152 #endif
153
154         if (!PBD::find_file (vstsp,
155 #ifdef PLATFORM_WINDOWS
156     #ifdef DEBUGGABLE_SCANNER_APP
157         #if defined(DEBUG) || defined(_DEBUG)
158                                 "ardour-vst-scannerD.exe"
159         #else
160                                 "ardour-vst-scannerRDC.exe"
161         #endif
162     #else
163                                 "ardour-vst-scanner.exe"
164     #endif
165 #else
166                                 "ardour-vst-scanner"
167 #endif
168                                 , scanner_bin_path)) {
169                 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() <<  endmsg;
170         }
171 #endif
172
173         load_statuses ();
174
175         if ((s = getenv ("LADSPA_RDF_PATH"))){
176                 lrdf_path = s;
177         }
178
179         if (lrdf_path.length() == 0) {
180                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
181         }
182
183         add_lrdf_data(lrdf_path);
184         add_ladspa_presets();
185 #ifdef WINDOWS_VST_SUPPORT
186         if (Config->get_use_windows_vst ()) {
187                 add_windows_vst_presets ();
188         }
189 #endif /* WINDOWS_VST_SUPPORT */
190
191 #ifdef LXVST_SUPPORT
192         if (Config->get_use_lxvst()) {
193                 add_lxvst_presets();
194         }
195 #endif /* Native LinuxVST support*/
196
197 #ifdef MACVST_SUPPORT
198         if (Config->get_use_macvst ()) {
199                 add_mac_vst_presets ();
200         }
201 #endif
202
203         if ((s = getenv ("VST_PATH"))) {
204                 windows_vst_path = s;
205         } else if ((s = getenv ("VST_PLUGINS"))) {
206                 windows_vst_path = s;
207         }
208
209         if (windows_vst_path.length() == 0) {
210                 windows_vst_path = vst_search_path ();
211         }
212
213         if ((s = getenv ("LXVST_PATH"))) {
214                 lxvst_path = s;
215         } else if ((s = getenv ("LXVST_PLUGINS"))) {
216                 lxvst_path = s;
217         }
218
219         if (lxvst_path.length() == 0) {
220                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
221                         "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
222                         "/usr/lib/vst:/usr/local/lib/vst";
223         }
224
225         /* first time setup, use 'default' path */
226         if (Config->get_plugin_path_lxvst() == X_("@default@")) {
227                 Config->set_plugin_path_lxvst(get_default_lxvst_path());
228         }
229         if (Config->get_plugin_path_vst() == X_("@default@")) {
230                 Config->set_plugin_path_vst(get_default_windows_vst_path());
231         }
232
233         if (_instance == 0) {
234                 _instance = this;
235         }
236
237         BootMessage (_("Discovering Plugins"));
238
239         LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
240 }
241
242
243 PluginManager::~PluginManager()
244 {
245         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
246                 // don't bother, just exit quickly.
247                 delete _windows_vst_plugin_info;
248                 delete _lxvst_plugin_info;
249                 delete _mac_vst_plugin_info;
250                 delete _ladspa_plugin_info;
251                 delete _lv2_plugin_info;
252                 delete _au_plugin_info;
253                 delete _lua_plugin_info;
254         }
255 }
256
257 void
258 PluginManager::refresh (bool cache_only)
259 {
260         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
261
262         if (!lm.locked()) {
263                 return;
264         }
265
266         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
267         _cancel_scan = false;
268
269         BootMessage (_("Scanning LADSPA Plugins"));
270         ladspa_refresh ();
271         BootMessage (_("Scanning Lua DSP Processors"));
272         lua_refresh ();
273 #ifdef LV2_SUPPORT
274         BootMessage (_("Scanning LV2 Plugins"));
275         lv2_refresh ();
276 #endif
277 #ifdef WINDOWS_VST_SUPPORT
278         if (Config->get_use_windows_vst()) {
279                 if (cache_only) {
280                         BootMessage (_("Scanning Windows VST Plugins"));
281                 } else {
282                         BootMessage (_("Discovering Windows VST Plugins"));
283                 }
284                 windows_vst_refresh (cache_only);
285         }
286 #endif // WINDOWS_VST_SUPPORT
287
288 #ifdef LXVST_SUPPORT
289         if(Config->get_use_lxvst()) {
290                 if (cache_only) {
291                         BootMessage (_("Scanning Linux VST Plugins"));
292                 } else {
293                         BootMessage (_("Discovering Linux VST Plugins"));
294                 }
295                 lxvst_refresh(cache_only);
296         }
297 #endif //Native linuxVST SUPPORT
298
299 #ifdef MACVST_SUPPORT
300         if(Config->get_use_macvst ()) {
301                 if (cache_only) {
302                         BootMessage (_("Scanning Mac VST Plugins"));
303                 } else {
304                         BootMessage (_("Discovering Mac VST Plugins"));
305                 }
306                 mac_vst_refresh (cache_only);
307         } else if (_mac_vst_plugin_info) {
308                 _mac_vst_plugin_info->clear ();
309         } else {
310                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
311         }
312 #endif //Native Mac VST SUPPORT
313
314 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
315                 if (!cache_only) {
316                         string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
317                         if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
318                                 gchar *bl = NULL;
319                                 if (g_file_get_contents(fn.c_str (), &bl, NULL, NULL)) {
320                                         if (Config->get_verbose_plugin_scan()) {
321                                                 PBD::info << _("VST Blacklist: ") << fn << "\n" << bl << "-----" << endmsg;
322                                         } else {
323                                                 PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg;
324                                         }
325                                         g_free (bl);
326                                 }
327                         }
328                 }
329 #endif
330
331 #ifdef AUDIOUNIT_SUPPORT
332         if (cache_only) {
333                 BootMessage (_("Scanning AU Plugins"));
334         } else {
335                 BootMessage (_("Discovering AU Plugins"));
336         }
337         au_refresh (cache_only);
338 #endif
339
340         BootMessage (_("Plugin Scan Complete..."));
341         PluginListChanged (); /* EMIT SIGNAL */
342         PluginScanMessage(X_("closeme"), "", false);
343         _cancel_scan = false;
344 }
345
346 void
347 PluginManager::cancel_plugin_scan ()
348 {
349         _cancel_scan = true;
350 }
351
352 void
353 PluginManager::cancel_plugin_timeout ()
354 {
355         _cancel_timeout = true;
356 }
357
358 void
359 PluginManager::clear_vst_cache ()
360 {
361 #if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
362 #ifdef WINDOWS_VST_SUPPORT
363         {
364                 vector<string> fsi_files;
365                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true);
366                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
367                         ::g_unlink(i->c_str());
368                 }
369         }
370         {
371                 vector<string> fsi_files;
372                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
373                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
374                         ::g_unlink(i->c_str());
375                 }
376         }
377         {
378                 vector<string> fsi_files;
379                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true);
380                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
381                         ::g_unlink(i->c_str());
382                 }
383         }
384 #endif
385
386 #ifdef LXVST_SUPPORT
387         {
388                 vector<string> fsi_files;
389                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true);
390                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
391                         ::g_unlink(i->c_str());
392                 }
393         }
394         {
395                 vector<string> fsi_files;
396                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
397                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
398                         ::g_unlink(i->c_str());
399                 }
400         }
401         {
402                 vector<string> fsi_files;
403                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true);
404                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
405                         ::g_unlink(i->c_str());
406                 }
407         }
408 #endif
409 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
410         {
411                 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_info");
412                 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
413                         PBD::remove_directory (dir);
414                 }
415         }
416 #endif
417 #endif // old cache cleanup
418
419 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
420         {
421                 string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
422                 vector<string> fsi_files;
423                 find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false);
424                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
425                         ::g_unlink(i->c_str());
426                 }
427         }
428 #endif
429 }
430
431 void
432 PluginManager::clear_vst_blacklist ()
433 {
434 #if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0)
435
436 #ifdef WINDOWS_VST_SUPPORT
437         {
438                 vector<string> fsi_files;
439                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true);
440                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
441                         ::g_unlink(i->c_str());
442                 }
443         }
444 #endif
445
446 #ifdef LXVST_SUPPORT
447         {
448                 vector<string> fsi_files;
449                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true);
450                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
451                         ::g_unlink(i->c_str());
452                 }
453         }
454 #endif
455 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
456         {
457                 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_blacklist");
458                 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
459                         PBD::remove_directory (dir);
460                 }
461         }
462 #endif
463
464 #endif // old blacklist cleanup
465
466 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
467         {
468                 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
469                 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
470                         ::g_unlink (fn.c_str());
471                 }
472         }
473 #endif
474
475 }
476
477 void
478 PluginManager::clear_au_cache ()
479 {
480 #ifdef AUDIOUNIT_SUPPORT
481         AUPluginInfo::clear_cache ();
482 #endif
483 }
484
485 void
486 PluginManager::clear_au_blacklist ()
487 {
488 #ifdef AUDIOUNIT_SUPPORT
489         string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
490         if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
491                 ::g_unlink(fn.c_str());
492         }
493 #endif
494 }
495
496 void
497 PluginManager::lua_refresh ()
498 {
499         if (_lua_plugin_info) {
500                 _lua_plugin_info->clear ();
501         } else {
502                 _lua_plugin_info = new ARDOUR::PluginInfoList ();
503         }
504         ARDOUR::LuaScriptList & _scripts (LuaScripting::instance ().scripts (LuaScriptInfo::DSP));
505         for (LuaScriptList::const_iterator s = _scripts.begin(); s != _scripts.end(); ++s) {
506                 LuaPluginInfoPtr lpi (new LuaPluginInfo(*s));
507                 _lua_plugin_info->push_back (lpi);
508         }
509 }
510
511 void
512 PluginManager::lua_refresh_cb ()
513 {
514         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
515         if (!lm.locked()) {
516                 return;
517         }
518         lua_refresh ();
519         PluginListChanged (); /* EMIT SIGNAL */
520 }
521
522 void
523 PluginManager::ladspa_refresh ()
524 {
525         if (_ladspa_plugin_info) {
526                 _ladspa_plugin_info->clear ();
527         } else {
528                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
529         }
530
531         /* allow LADSPA_PATH to augment, not override standard locations */
532
533         /* Only add standard locations to ladspa_path if it doesn't
534          * already contain them. Check for trailing G_DIR_SEPARATOR too.
535          */
536
537         vector<string> ladspa_modules;
538
539         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
540
541         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so");
542         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib");
543         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll");
544
545         for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
546                 ARDOUR::PluginScanMessage(_("LADSPA"), *i, false);
547                 ladspa_discover (*i);
548         }
549 }
550
551 #ifdef HAVE_LRDF
552 static bool rdf_filter (const string &str, void* /*arg*/)
553 {
554         return str[0] != '.' &&
555                    ((str.find(".rdf")  == (str.length() - 4)) ||
556             (str.find(".rdfs") == (str.length() - 5)) ||
557                     (str.find(".n3")   == (str.length() - 3)) ||
558                     (str.find(".ttl")  == (str.length() - 4)));
559 }
560 #endif
561
562 void
563 PluginManager::add_ladspa_presets()
564 {
565         add_presets ("ladspa");
566 }
567
568 void
569 PluginManager::add_windows_vst_presets()
570 {
571         add_presets ("windows-vst");
572 }
573
574 void
575 PluginManager::add_mac_vst_presets()
576 {
577         add_presets ("mac-vst");
578 }
579
580 void
581 PluginManager::add_lxvst_presets()
582 {
583         add_presets ("lxvst");
584 }
585
586 void
587 PluginManager::add_presets(string domain)
588 {
589 #ifdef HAVE_LRDF
590         vector<string> presets;
591         vector<string>::iterator x;
592
593         char* envvar;
594         if ((envvar = getenv ("HOME")) == 0) {
595                 return;
596         }
597
598         string path = string_compose("%1/.%2/rdf", envvar, domain);
599         find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
600
601         for (x = presets.begin(); x != presets.end (); ++x) {
602                 string file = "file:" + *x;
603                 if (lrdf_read_file(file.c_str())) {
604                         warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
605                 }
606         }
607
608 #endif
609 }
610
611 void
612 PluginManager::add_lrdf_data (const string &path)
613 {
614 #ifdef HAVE_LRDF
615         vector<string> rdf_files;
616         vector<string>::iterator x;
617
618         find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
619
620         for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
621                 const string uri(string("file://") + *x);
622
623                 if (lrdf_read_file(uri.c_str())) {
624                         warning << "Could not parse rdf file: " << uri << endmsg;
625                 }
626         }
627 #endif
628 }
629
630 int
631 PluginManager::ladspa_discover (string path)
632 {
633         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
634
635         Glib::Module module(path);
636         const LADSPA_Descriptor *descriptor;
637         LADSPA_Descriptor_Function dfunc;
638         void* func = 0;
639
640         if (!module) {
641                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
642                         path, Glib::Module::get_last_error()) << endmsg;
643                 return -1;
644         }
645
646
647         if (!module.get_symbol("ladspa_descriptor", func)) {
648                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
649                 error << Glib::Module::get_last_error() << endmsg;
650                 return -1;
651         }
652
653         dfunc = (LADSPA_Descriptor_Function)func;
654
655         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
656
657         for (uint32_t i = 0; ; ++i) {
658                 /* if a ladspa plugin allocates memory here
659                  * it is never free()ed (or plugin-dependent only when unloading).
660                  * For some plugins memory allocated is incremental, we should
661                  * avoid re-scanning plugins and file bug reports.
662                  */
663                 if ((descriptor = dfunc (i)) == 0) {
664                         break;
665                 }
666
667                 if (!ladspa_plugin_whitelist.empty()) {
668                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
669                                 continue;
670                         }
671                 }
672
673                 PluginInfoPtr info(new LadspaPluginInfo);
674                 info->name = descriptor->Name;
675                 info->category = get_ladspa_category(descriptor->UniqueID);
676                 info->creator = descriptor->Maker;
677                 info->path = path;
678                 info->index = i;
679                 info->n_inputs = ChanCount();
680                 info->n_outputs = ChanCount();
681                 info->type = ARDOUR::LADSPA;
682
683                 char buf[32];
684                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
685                 info->unique_id = buf;
686
687                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
688                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
689                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
690                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
691                                 }
692                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
693                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
694                                 }
695                         }
696                 }
697
698                 if(_ladspa_plugin_info->empty()){
699                         _ladspa_plugin_info->push_back (info);
700                 }
701
702                 //Ensure that the plugin is not already in the plugin list.
703
704                 bool found = false;
705
706                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
707                         if(0 == info->unique_id.compare((*i)->unique_id)){
708                               found = true;
709                         }
710                 }
711
712                 if(!found){
713                     _ladspa_plugin_info->push_back (info);
714                 }
715
716                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
717         }
718
719 // GDB WILL NOT LIKE YOU IF YOU DO THIS
720 //      dlclose (module);
721
722         return 0;
723 }
724
725 string
726 PluginManager::get_ladspa_category (uint32_t plugin_id)
727 {
728 #ifdef HAVE_LRDF
729         char buf[256];
730         lrdf_statement pattern;
731
732         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
733         pattern.subject = buf;
734         pattern.predicate = const_cast<char*>(RDF_TYPE);
735         pattern.object = 0;
736         pattern.object_type = lrdf_uri;
737
738         lrdf_statement* matches1 = lrdf_matches (&pattern);
739
740         if (!matches1) {
741                 return "Unknown";
742         }
743
744         pattern.subject = matches1->object;
745         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
746         pattern.object = 0;
747         pattern.object_type = lrdf_literal;
748
749         lrdf_statement* matches2 = lrdf_matches (&pattern);
750         lrdf_free_statements(matches1);
751
752         if (!matches2) {
753                 return ("Unknown");
754         }
755
756         string label = matches2->object;
757         lrdf_free_statements(matches2);
758
759         /* Kludge LADSPA class names to be singular and match LV2 class names.
760            This avoids duplicate plugin menus for every class, which is necessary
761            to make the plugin category menu at all usable, but is obviously a
762            filthy kludge.
763
764            In the short term, lrdf could be updated so the labels match and a new
765            release made. To support both specs, we should probably be mapping the
766            URIs to the same category in code and perhaps tweaking that hierarchy
767            dynamically to suit the user. Personally, I (drobilla) think that time
768            is better spent replacing the little-used LRDF.
769
770            In the longer term, we will abandon LRDF entirely in favour of LV2 and
771            use that class hierarchy. Aside from fixing this problem properly, that
772            will also allow for translated labels. SWH plugins have been LV2 for
773            ages; TAP needs porting. I don't know of anything else with LRDF data.
774         */
775         if (label == "Utilities") {
776                 return "Utility";
777         } else if (label == "Pitch shifters") {
778                 return "Pitch Shifter";
779         } else if (label != "Dynamics" && label != "Chorus"
780                    &&label[label.length() - 1] == 's'
781                    && label[label.length() - 2] != 's') {
782                 return label.substr(0, label.length() - 1);
783         } else {
784                 return label;
785         }
786 #else
787                 return ("Unknown");
788 #endif
789 }
790
791 #ifdef LV2_SUPPORT
792 void
793 PluginManager::lv2_refresh ()
794 {
795         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
796         delete _lv2_plugin_info;
797         _lv2_plugin_info = LV2PluginInfo::discover();
798 }
799 #endif
800
801 #ifdef AUDIOUNIT_SUPPORT
802 void
803 PluginManager::au_refresh (bool cache_only)
804 {
805         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
806
807         // disable automatic discovery in case we crash
808         bool discover_at_start = Config->get_discover_audio_units ();
809         Config->set_discover_audio_units (false);
810         Config->save_state();
811
812         delete _au_plugin_info;
813         _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
814
815         // successful scan re-enabled automatic discovery if it was set
816         Config->set_discover_audio_units (discover_at_start);
817         Config->save_state();
818 }
819
820 #endif
821
822 #ifdef WINDOWS_VST_SUPPORT
823
824 void
825 PluginManager::windows_vst_refresh (bool cache_only)
826 {
827         if (_windows_vst_plugin_info) {
828                 _windows_vst_plugin_info->clear ();
829         } else {
830                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
831         }
832
833         windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
834 }
835
836 static bool windows_vst_filter (const string& str, void * /*arg*/)
837 {
838         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
839         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
840 }
841
842 int
843 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
844 {
845         vector<string> plugin_objects;
846         vector<string>::iterator x;
847         int ret = 0;
848
849         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
850
851         if (Session::get_disable_all_loaded_plugins ()) {
852                 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
853                 return -1;
854         }
855
856         if (Config->get_verbose_plugin_scan()) {
857                 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
858         }
859
860         find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
861
862         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
863                 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
864                 windows_vst_discover (*x, cache_only || cancelled());
865         }
866
867         if (Config->get_verbose_plugin_scan()) {
868                 info << _("--- Windows VST plugins Scan Done") << endmsg;
869         }
870
871         return ret;
872 }
873
874 static std::string dll_info (std::string path) {
875         std::string rv;
876         uint8_t buf[68];
877         uint16_t type = 0;
878         off_t pe_hdr_off = 0;
879
880         int fd = g_open(path.c_str(), O_RDONLY, 0444);
881
882         if (fd < 0) {
883                 return _("cannot open dll"); // TODO strerror()
884         }
885
886         if (68 != read (fd, buf, 68)) {
887                 rv = _("invalid dll, file too small");
888                 goto errorout;
889         }
890         if (buf[0] != 'M' && buf[1] != 'Z') {
891                 rv = _("not a dll");
892                 goto errorout;
893         }
894
895         pe_hdr_off = *((int32_t*) &buf[60]);
896         if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
897                 rv = _("cannot determine dll type");
898                 goto errorout;
899         }
900         if (6 != read (fd, buf, 6)) {
901                 rv = _("cannot read dll PE header");
902                 goto errorout;
903         }
904
905         if (buf[0] != 'P' && buf[1] != 'E') {
906                 rv = _("invalid dll PE header");
907                 goto errorout;
908         }
909
910         type = *((uint16_t*) &buf[4]);
911         switch (type) {
912                 case 0x014c:
913                         rv = _("i386 (32-bit)");
914                         break;
915                 case  0x0200:
916                         rv = _("Itanium");
917                         break;
918                 case 0x8664:
919                         rv = _("x64 (64-bit)");
920                         break;
921                 case 0:
922                         rv = _("Native Architecture");
923                         break;
924                 default:
925                         rv = _("Unknown Architecture");
926                         break;
927         }
928 errorout:
929         assert (rv.length() > 0);
930         close (fd);
931         return rv;
932 }
933
934 int
935 PluginManager::windows_vst_discover (string path, bool cache_only)
936 {
937         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
938
939         if (Config->get_verbose_plugin_scan()) {
940                 if (cache_only) {
941                         info << string_compose (_(" *  %1 (cache only)"), path) << endmsg;
942                 } else {
943                         info << string_compose (_(" *  %1 - %2"), path, dll_info (path)) << endmsg;
944                 }
945         }
946
947         _cancel_timeout = false;
948         vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
949                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
950
951         // TODO  get extended error messae from vstfx_get_info_fst() e.g  blacklisted, 32/64bit compat,
952         // .err file scanner output etc.
953
954         if (finfos->empty()) {
955                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
956                 if (Config->get_verbose_plugin_scan()) {
957                         info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg;
958                 }
959                 return -1;
960         }
961
962         uint32_t discovered = 0;
963         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
964                 VSTInfo* finfo = *x;
965                 char buf[32];
966
967                 if (!finfo->canProcessReplacing) {
968                         warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"),
969                                                          finfo->name, PROGRAM_NAME)
970                                 << endl;
971                         continue;
972                 }
973
974                 PluginInfoPtr info (new WindowsVSTPluginInfo);
975
976                 /* what a joke freeware VST is */
977
978                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
979                         info->name = PBD::basename_nosuffix (path);
980                 } else {
981                         info->name = finfo->name;
982                 }
983
984
985                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
986                 info->unique_id = buf;
987                 info->category = "VST";
988                 info->path = path;
989                 info->creator = finfo->creator;
990                 info->index = 0;
991                 info->n_inputs.set_audio (finfo->numInputs);
992                 info->n_outputs.set_audio (finfo->numOutputs);
993                 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
994                 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
995                 info->type = ARDOUR::Windows_VST;
996
997                 // TODO: check dup-IDs (lxvst AND windows vst)
998                 bool duplicate = false;
999
1000                 if (!_windows_vst_plugin_info->empty()) {
1001                         for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
1002                                 if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) {
1003                                         warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg;
1004                                         duplicate = true;
1005                                         break;
1006                                 }
1007                         }
1008                 }
1009
1010                 if (!duplicate) {
1011                         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1012                         _windows_vst_plugin_info->push_back (info);
1013                         discovered++;
1014                         if (Config->get_verbose_plugin_scan()) {
1015                                 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1016                         }
1017                 }
1018         }
1019
1020         vstfx_free_info_list (finfos);
1021         return discovered > 0 ? 0 : -1;
1022 }
1023
1024 #endif // WINDOWS_VST_SUPPORT
1025
1026 #ifdef MACVST_SUPPORT
1027 void
1028 PluginManager::mac_vst_refresh (bool cache_only)
1029 {
1030         if (_mac_vst_plugin_info) {
1031                 _mac_vst_plugin_info->clear ();
1032         } else {
1033                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1034         }
1035
1036         mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1037 }
1038
1039 static bool mac_vst_filter (const string& str)
1040 {
1041         string plist = Glib::build_filename (str, "Contents", "Info.plist");
1042         if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1043                 return false;
1044         }
1045         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1046 }
1047
1048 int
1049 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1050 {
1051         if (Session::get_disable_all_loaded_plugins ()) {
1052                 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1053                 return -1;
1054         }
1055
1056         Searchpath paths (path);
1057         /* customized version of run_functor_for_paths() */
1058         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1059                 string expanded_path = path_expand (*i);
1060                 if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
1061                 try {
1062                         Glib::Dir dir(expanded_path);
1063                         for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
1064                                 string fullpath = Glib::build_filename (expanded_path, *di);
1065
1066                                 /* we're only interested in bundles */
1067                                 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1068                                         continue;
1069                                 }
1070
1071                                 if (mac_vst_filter (fullpath)) {
1072                                         ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1073                                         mac_vst_discover (fullpath, cache_only || cancelled());
1074                                         continue;
1075                                 }
1076
1077                                 /* don't descend into AU bundles in the VST dir */
1078                                 if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
1079                                         continue;
1080                                 }
1081
1082                                 /* recurse */
1083                                 mac_vst_discover_from_path (fullpath, cache_only);
1084                         }
1085                 } catch (Glib::FileError& err) { }
1086         }
1087
1088         return 0;
1089 }
1090
1091 int
1092 PluginManager::mac_vst_discover (string path, bool cache_only)
1093 {
1094         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1095
1096         _cancel_timeout = false;
1097
1098         vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
1099                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1100
1101         if (finfos->empty()) {
1102                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1103                 return -1;
1104         }
1105
1106         uint32_t discovered = 0;
1107         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1108                 VSTInfo* finfo = *x;
1109                 char buf[32];
1110
1111                 if (!finfo->canProcessReplacing) {
1112                         warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1113                                                          finfo->name, PROGRAM_NAME)
1114                                 << endl;
1115                         continue;
1116                 }
1117
1118                 PluginInfoPtr info (new MacVSTPluginInfo);
1119
1120                 info->name = finfo->name;
1121
1122                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1123                 info->unique_id = buf;
1124                 info->category = "MacVST";
1125                 info->path = path;
1126                 info->creator = finfo->creator;
1127                 info->index = 0;
1128                 info->n_inputs.set_audio (finfo->numInputs);
1129                 info->n_outputs.set_audio (finfo->numOutputs);
1130                 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1131                 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1132                 info->type = ARDOUR::MacVST;
1133
1134                 bool duplicate = false;
1135                 if (!_mac_vst_plugin_info->empty()) {
1136                         for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
1137                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1138                                         warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
1139                                         duplicate = true;
1140                                         break;
1141                                 }
1142                         }
1143                 }
1144
1145                 if (!duplicate) {
1146                         _mac_vst_plugin_info->push_back (info);
1147                         discovered++;
1148                 }
1149         }
1150
1151         vstfx_free_info_list (finfos);
1152         return discovered > 0 ? 0 : -1;
1153 }
1154
1155 #endif // MAC_VST_SUPPORT
1156
1157 #ifdef LXVST_SUPPORT
1158
1159 void
1160 PluginManager::lxvst_refresh (bool cache_only)
1161 {
1162         if (_lxvst_plugin_info) {
1163                 _lxvst_plugin_info->clear ();
1164         } else {
1165                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1166         }
1167
1168         lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1169 }
1170
1171 static bool lxvst_filter (const string& str, void *)
1172 {
1173         /* Not a dotfile, has a prefix before a period, suffix is "so" */
1174
1175         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1176 }
1177
1178 int
1179 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1180 {
1181         vector<string> plugin_objects;
1182         vector<string>::iterator x;
1183         int ret = 0;
1184
1185         if (Session::get_disable_all_loaded_plugins ()) {
1186                 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1187                 return -1;
1188         }
1189
1190 #ifndef NDEBUG
1191         (void) path;
1192 #endif
1193
1194         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1195
1196         find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1197
1198         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
1199                 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
1200                 lxvst_discover (*x, cache_only || cancelled());
1201         }
1202
1203         return ret;
1204 }
1205
1206 int
1207 PluginManager::lxvst_discover (string path, bool cache_only)
1208 {
1209         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1210
1211         _cancel_timeout = false;
1212         vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
1213                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1214
1215         if (finfos->empty()) {
1216                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1217                 return -1;
1218         }
1219
1220         uint32_t discovered = 0;
1221         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1222                 VSTInfo* finfo = *x;
1223                 char buf[32];
1224
1225                 if (!finfo->canProcessReplacing) {
1226                         warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1227                                                          finfo->name, PROGRAM_NAME)
1228                                 << endl;
1229                         continue;
1230                 }
1231
1232                 PluginInfoPtr info(new LXVSTPluginInfo);
1233
1234                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1235                         info->name = PBD::basename_nosuffix (path);
1236                 } else {
1237                         info->name = finfo->name;
1238                 }
1239
1240
1241                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
1242                 info->unique_id = buf;
1243                 info->category = "linuxVSTs";
1244                 info->path = path;
1245                 info->creator = finfo->creator;
1246                 info->index = 0;
1247                 info->n_inputs.set_audio (finfo->numInputs);
1248                 info->n_outputs.set_audio (finfo->numOutputs);
1249                 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
1250                 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
1251                 info->type = ARDOUR::LXVST;
1252
1253                                         /* Make sure we don't find the same plugin in more than one place along
1254                          the LXVST_PATH We can't use a simple 'find' because the path is included
1255                          in the PluginInfo, and that is the one thing we can be sure MUST be
1256                          different if a duplicate instance is found.  So we just compare the type
1257                          and unique ID (which for some VSTs isn't actually unique...)
1258                 */
1259
1260                 // TODO: check dup-IDs with windowsVST, too
1261                 bool duplicate = false;
1262                 if (!_lxvst_plugin_info->empty()) {
1263                         for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
1264                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1265                                         warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
1266                                         duplicate = true;
1267                                         break;
1268                                 }
1269                         }
1270                 }
1271
1272                 if (!duplicate) {
1273                         _lxvst_plugin_info->push_back (info);
1274                         discovered++;
1275                 }
1276         }
1277
1278         vstfx_free_info_list (finfos);
1279         return discovered > 0 ? 0 : -1;
1280 }
1281
1282 #endif // LXVST_SUPPORT
1283
1284
1285 PluginManager::PluginStatusType
1286 PluginManager::get_status (const PluginInfoPtr& pi) const
1287 {
1288         PluginStatus ps (pi->type, pi->unique_id);
1289         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
1290         if (i ==  statuses.end() ) {
1291                 return Normal;
1292         } else {
1293                 return i->status;
1294         }
1295 }
1296
1297 void
1298 PluginManager::save_statuses ()
1299 {
1300         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
1301         stringstream ofs;
1302
1303         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1304                 switch ((*i).type) {
1305                 case LADSPA:
1306                         ofs << "LADSPA";
1307                         break;
1308                 case AudioUnit:
1309                         ofs << "AudioUnit";
1310                         break;
1311                 case LV2:
1312                         ofs << "LV2";
1313                         break;
1314                 case Windows_VST:
1315                         ofs << "Windows-VST";
1316                         break;
1317                 case LXVST:
1318                         ofs << "LXVST";
1319                         break;
1320                 case MacVST:
1321                         ofs << "MacVST";
1322                         break;
1323                 case Lua:
1324                         ofs << "Lua";
1325                         break;
1326                 }
1327
1328                 ofs << ' ';
1329
1330                 switch ((*i).status) {
1331                 case Normal:
1332                         ofs << "Normal";
1333                         break;
1334                 case Favorite:
1335                         ofs << "Favorite";
1336                         break;
1337                 case Hidden:
1338                         ofs << "Hidden";
1339                         break;
1340                 }
1341
1342                 ofs << ' ';
1343                 ofs << (*i).unique_id;;
1344                 ofs << endl;
1345         }
1346         g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1347         PluginStatusesChanged (); /* EMIT SIGNAL */
1348 }
1349
1350 void
1351 PluginManager::load_statuses ()
1352 {
1353         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
1354         gchar *fbuf = NULL;
1355         if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL))  {
1356                 return;
1357         }
1358         stringstream ifs (fbuf);
1359         g_free (fbuf);
1360
1361         std::string stype;
1362         std::string sstatus;
1363         std::string id;
1364         PluginType type;
1365         PluginStatusType status;
1366         char buf[1024];
1367
1368         while (ifs) {
1369
1370                 ifs >> stype;
1371                 if (!ifs) {
1372                         break;
1373
1374                 }
1375
1376                 ifs >> sstatus;
1377                 if (!ifs) {
1378                         break;
1379
1380                 }
1381
1382                 /* rest of the line is the plugin ID */
1383
1384                 ifs.getline (buf, sizeof (buf), '\n');
1385                 if (!ifs) {
1386                         break;
1387                 }
1388
1389                 if (sstatus == "Normal") {
1390                         status = Normal;
1391                 } else if (sstatus == "Favorite") {
1392                         status = Favorite;
1393                 } else if (sstatus == "Hidden") {
1394                         status = Hidden;
1395                 } else {
1396                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1397                                   << endmsg;
1398                         statuses.clear ();
1399                         break;
1400                 }
1401
1402                 if (stype == "LADSPA") {
1403                         type = LADSPA;
1404                 } else if (stype == "AudioUnit") {
1405                         type = AudioUnit;
1406                 } else if (stype == "LV2") {
1407                         type = LV2;
1408                 } else if (stype == "Windows-VST") {
1409                         type = Windows_VST;
1410                 } else if (stype == "LXVST") {
1411                         type = LXVST;
1412                 } else if (stype == "MacVST") {
1413                         type = MacVST;
1414                 } else if (stype == "Lua") {
1415                         type = Lua;
1416                 } else {
1417                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1418                               << endmsg;
1419                         continue;
1420                 }
1421
1422                 id = buf;
1423                 strip_whitespace_edges (id);
1424                 set_status (type, id, status);
1425         }
1426 }
1427
1428 void
1429 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1430 {
1431         PluginStatus ps (t, id, status);
1432         statuses.erase (ps);
1433
1434         if (status == Normal) {
1435                 return;
1436         }
1437
1438         statuses.insert (ps);
1439 }
1440
1441 std::string
1442 PluginManager::user_plugin_metadata_dir () const
1443 {
1444         std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1445         g_mkdir_with_parents (dir.c_str(), 0744);
1446         return dir;
1447 }
1448
1449 const ARDOUR::PluginInfoList&
1450 PluginManager::windows_vst_plugin_info ()
1451 {
1452 #ifdef WINDOWS_VST_SUPPORT
1453         if (!_windows_vst_plugin_info) {
1454                 windows_vst_refresh ();
1455         }
1456         return *_windows_vst_plugin_info;
1457 #else
1458         return _empty_plugin_info;
1459 #endif
1460 }
1461
1462 const ARDOUR::PluginInfoList&
1463 PluginManager::mac_vst_plugin_info ()
1464 {
1465 #ifdef MACVST_SUPPORT
1466         assert(_mac_vst_plugin_info);
1467         return *_mac_vst_plugin_info;
1468 #else
1469         return _empty_plugin_info;
1470 #endif
1471 }
1472
1473 const ARDOUR::PluginInfoList&
1474 PluginManager::lxvst_plugin_info ()
1475 {
1476 #ifdef LXVST_SUPPORT
1477         assert(_lxvst_plugin_info);
1478         return *_lxvst_plugin_info;
1479 #else
1480         return _empty_plugin_info;
1481 #endif
1482 }
1483
1484 const ARDOUR::PluginInfoList&
1485 PluginManager::ladspa_plugin_info ()
1486 {
1487         assert(_ladspa_plugin_info);
1488         return *_ladspa_plugin_info;
1489 }
1490
1491 const ARDOUR::PluginInfoList&
1492 PluginManager::lv2_plugin_info ()
1493 {
1494 #ifdef LV2_SUPPORT
1495         assert(_lv2_plugin_info);
1496         return *_lv2_plugin_info;
1497 #else
1498         return _empty_plugin_info;
1499 #endif
1500 }
1501
1502 const ARDOUR::PluginInfoList&
1503 PluginManager::au_plugin_info ()
1504 {
1505 #ifdef AUDIOUNIT_SUPPORT
1506         if (_au_plugin_info) {
1507                 return *_au_plugin_info;
1508         }
1509 #endif
1510         return _empty_plugin_info;
1511 }
1512
1513 const ARDOUR::PluginInfoList&
1514 PluginManager::lua_plugin_info ()
1515 {
1516         assert(_lua_plugin_info);
1517         return *_lua_plugin_info;
1518 }