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