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