add kxstudio linux vst dirs to LXVST default search path
[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 <lrdf.h>
29 #include <dlfcn.h>
30 #include <cstdlib>
31 #include <fstream>
32
33 #ifdef WINDOWS_VST_SUPPORT
34 #include "fst.h"
35 #include "pbd/basename.h"
36 #include <cstring>
37 #endif // WINDOWS_VST_SUPPORT
38
39 #ifdef LXVST_SUPPORT
40 #include "ardour/linux_vst_support.h"
41 #include "pbd/basename.h"
42 #include <cstring>
43 #endif //LXVST_SUPPORT
44
45 #include <glibmm/miscutils.h>
46
47 #include "pbd/pathscanner.h"
48 #include "pbd/whitespace.h"
49
50 #include "ardour/debug.h"
51 #include "ardour/filesystem_paths.h"
52 #include "ardour/ladspa.h"
53 #include "ardour/ladspa_plugin.h"
54 #include "ardour/plugin.h"
55 #include "ardour/plugin_manager.h"
56 #include "ardour/rc_configuration.h"
57
58 #ifdef LV2_SUPPORT
59 #include "ardour/lv2_plugin.h"
60 #endif
61
62 #ifdef WINDOWS_VST_SUPPORT
63 #include "ardour/windows_vst_plugin.h"
64 #endif
65
66 #ifdef LXVST_SUPPORT
67 #include "ardour/lxvst_plugin.h"
68 #endif
69
70 #ifdef AUDIOUNIT_SUPPORT
71 #include "ardour/audio_unit.h"
72 #include <Carbon/Carbon.h>
73 #endif
74
75 #include "pbd/error.h"
76 #include "pbd/stl_delete.h"
77
78 #include "i18n.h"
79
80 using namespace ARDOUR;
81 using namespace PBD;
82 using namespace std;
83
84 PluginManager* PluginManager::_instance = 0;
85
86 PluginManager&
87 PluginManager::instance() 
88 {
89         if (!_instance) {
90                 _instance = new PluginManager;
91         }
92         return *_instance;
93 }
94
95 PluginManager::PluginManager ()
96         : _windows_vst_plugin_info(0)
97         , _lxvst_plugin_info(0)
98         , _ladspa_plugin_info(0)
99         , _lv2_plugin_info(0)
100         , _au_plugin_info(0)
101 {
102         char* s;
103         string lrdf_path;
104
105         load_statuses ();
106
107         if ((s = getenv ("LADSPA_RDF_PATH"))){
108                 lrdf_path = s;
109         }
110
111         if (lrdf_path.length() == 0) {
112                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
113         }
114
115         add_lrdf_data(lrdf_path);
116         add_ladspa_presets();
117 #ifdef WINDOWS_VST_SUPPORT
118         if (Config->get_use_windows_vst ()) {
119                 add_windows_vst_presets ();
120         }
121 #endif /* WINDOWS_VST_SUPPORT */
122
123 #ifdef LXVST_SUPPORT
124         if (Config->get_use_lxvst()) {
125                 add_lxvst_presets();
126         }
127 #endif /* Native LinuxVST support*/
128
129         if ((s = getenv ("LADSPA_PATH"))) {
130                 ladspa_path = s;
131         }
132
133         if ((s = getenv ("VST_PATH"))) {
134                 windows_vst_path = s;
135         } else if ((s = getenv ("VST_PLUGINS"))) {
136                 windows_vst_path = s;
137         }
138
139         if ((s = getenv ("LXVST_PATH"))) {
140                 lxvst_path = s;
141         } else if ((s = getenv ("LXVST_PLUGINS"))) {
142                 lxvst_path = s;
143         }
144
145         if (_instance == 0) {
146                 _instance = this;
147         }
148
149         /* the plugin manager is constructed too early to use Profile */
150
151         if (getenv ("ARDOUR_SAE")) {
152                 ladspa_plugin_whitelist.push_back (1203); // single band parametric
153                 ladspa_plugin_whitelist.push_back (1772); // caps compressor
154                 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
155                 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
156                 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
157                 ladspa_plugin_whitelist.push_back (1216); // gverb
158                 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
159         }
160
161         BootMessage (_("Discovering Plugins"));
162 }
163
164
165 PluginManager::~PluginManager()
166 {
167 }
168
169
170 void
171 PluginManager::refresh ()
172 {
173         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
174
175         ladspa_refresh ();
176 #ifdef LV2_SUPPORT
177         lv2_refresh ();
178 #endif
179 #ifdef WINDOWS_VST_SUPPORT
180         if (Config->get_use_windows_vst()) {
181                 windows_vst_refresh ();
182         }
183 #endif // WINDOWS_VST_SUPPORT
184
185 #ifdef LXVST_SUPPORT
186         if(Config->get_use_lxvst()) {
187                 lxvst_refresh();
188         }
189 #endif //Native linuxVST SUPPORT
190
191 #ifdef AUDIOUNIT_SUPPORT
192         au_refresh ();
193 #endif
194
195         PluginListChanged (); /* EMIT SIGNAL */
196 }
197
198 void
199 PluginManager::ladspa_refresh ()
200 {
201         if (_ladspa_plugin_info)
202                 _ladspa_plugin_info->clear ();
203         else
204                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
205
206         static const char *standard_paths[] = {
207                 "/usr/local/lib64/ladspa",
208                 "/usr/local/lib/ladspa",
209                 "/usr/lib64/ladspa",
210                 "/usr/lib/ladspa",
211                 "/Library/Audio/Plug-Ins/LADSPA",
212                 ""
213         };
214
215         /* allow LADSPA_PATH to augment, not override standard locations */
216
217         /* Only add standard locations to ladspa_path if it doesn't
218          * already contain them. Check for trailing G_DIR_SEPARATOR too.
219          */
220
221         int i;
222         for (i = 0; standard_paths[i][0]; i++) {
223                 size_t found = ladspa_path.find(standard_paths[i]);
224                 if (found != ladspa_path.npos) {
225                         switch (ladspa_path[found + strlen(standard_paths[i])]) {
226                                 case ':' :
227                                 case '\0':
228                                         continue;
229                                 case G_DIR_SEPARATOR :
230                                         if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
231                                             ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
232                                                 continue;
233                                         }
234                         }
235                 }
236                 if (!ladspa_path.empty())
237                         ladspa_path += ":";
238
239                 ladspa_path += standard_paths[i];
240
241         }
242
243         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_path));
244
245         ladspa_discover_from_path (ladspa_path);
246 }
247
248
249 int
250 PluginManager::add_ladspa_directory (string path)
251 {
252         if (ladspa_discover_from_path (path) == 0) {
253                 ladspa_path += ':';
254                 ladspa_path += path;
255                 return 0;
256         }
257         return -1;
258 }
259
260 static bool ladspa_filter (const string& str, void */*arg*/)
261 {
262         /* Not a dotfile, has a prefix before a period, suffix is "so" */
263
264         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
265 }
266
267 int
268 PluginManager::ladspa_discover_from_path (string /*path*/)
269 {
270         PathScanner scanner;
271         vector<string *> *plugin_objects;
272         vector<string *>::iterator x;
273         int ret = 0;
274
275         plugin_objects = scanner (ladspa_path, ladspa_filter, 0, false, true);
276
277         if (plugin_objects) {
278                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
279                         ladspa_discover (**x);
280                 }
281
282                 vector_delete (plugin_objects);
283         }
284
285         return ret;
286 }
287
288 static bool rdf_filter (const string &str, void* /*arg*/)
289 {
290         return str[0] != '.' &&
291                    ((str.find(".rdf")  == (str.length() - 4)) ||
292             (str.find(".rdfs") == (str.length() - 5)) ||
293                     (str.find(".n3")   == (str.length() - 3)) ||
294                     (str.find(".ttl")  == (str.length() - 4)));
295 }
296
297 void
298 PluginManager::add_ladspa_presets()
299 {
300         add_presets ("ladspa");
301 }
302
303 void
304 PluginManager::add_windows_vst_presets()
305 {
306         add_presets ("windows-vst");
307 }
308
309 void
310 PluginManager::add_lxvst_presets()
311 {
312         add_presets ("lxvst");
313 }
314
315 void
316 PluginManager::add_presets(string domain)
317 {
318
319         PathScanner scanner;
320         vector<string *> *presets;
321         vector<string *>::iterator x;
322
323         char* envvar;
324         if ((envvar = getenv ("HOME")) == 0) {
325                 return;
326         }
327
328         string path = string_compose("%1/.%2/rdf", envvar, domain);
329         presets = scanner (path, rdf_filter, 0, false, true);
330
331         if (presets) {
332                 for (x = presets->begin(); x != presets->end (); ++x) {
333                         string file = "file:" + **x;
334                         if (lrdf_read_file(file.c_str())) {
335                                 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
336                         }
337                 }
338                 
339                 vector_delete (presets);
340         }
341 }
342
343 void
344 PluginManager::add_lrdf_data (const string &path)
345 {
346         PathScanner scanner;
347         vector<string *>* rdf_files;
348         vector<string *>::iterator x;
349
350         rdf_files = scanner (path, rdf_filter, 0, false, true);
351
352         if (rdf_files) {
353                 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
354                         const string uri(string("file://") + **x);
355
356                         if (lrdf_read_file(uri.c_str())) {
357                                 warning << "Could not parse rdf file: " << uri << endmsg;
358                         }
359                 }
360
361                 vector_delete (rdf_files);
362         }
363 }
364
365 int
366 PluginManager::ladspa_discover (string path)
367 {
368         void *module;
369         const LADSPA_Descriptor *descriptor;
370         LADSPA_Descriptor_Function dfunc;
371         const char *errstr;
372
373         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
374                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
375                 return -1;
376         }
377
378         dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
379
380         if ((errstr = dlerror()) != 0) {
381                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
382                 error << errstr << endmsg;
383                 dlclose (module);
384                 return -1;
385         }
386
387         for (uint32_t i = 0; ; ++i) {
388                 if ((descriptor = dfunc (i)) == 0) {
389                         break;
390                 }
391
392                 if (!ladspa_plugin_whitelist.empty()) {
393                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
394                                 continue;
395                         }
396                 }
397
398                 PluginInfoPtr info(new LadspaPluginInfo);
399                 info->name = descriptor->Name;
400                 info->category = get_ladspa_category(descriptor->UniqueID);
401                 info->creator = descriptor->Maker;
402                 info->path = path;
403                 info->index = i;
404                 info->n_inputs = ChanCount();
405                 info->n_outputs = ChanCount();
406                 info->type = ARDOUR::LADSPA;
407
408                 char buf[32];
409                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
410                 info->unique_id = buf;
411
412                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
413                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
414                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
415                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
416                                 }
417                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
418                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
419                                 }
420                         }
421                 }
422
423                 if(_ladspa_plugin_info->empty()){
424                         _ladspa_plugin_info->push_back (info);
425                 }
426
427                 //Ensure that the plugin is not already in the plugin list.
428
429                 bool found = false;
430
431                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
432                         if(0 == info->unique_id.compare((*i)->unique_id)){
433                               found = true;
434                         }
435                 }
436
437                 if(!found){
438                     _ladspa_plugin_info->push_back (info);
439                 }
440         }
441
442 // GDB WILL NOT LIKE YOU IF YOU DO THIS
443 //      dlclose (module);
444
445         return 0;
446 }
447
448 string
449 PluginManager::get_ladspa_category (uint32_t plugin_id)
450 {
451         char buf[256];
452         lrdf_statement pattern;
453
454         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
455         pattern.subject = buf;
456         pattern.predicate = const_cast<char*>(RDF_TYPE);
457         pattern.object = 0;
458         pattern.object_type = lrdf_uri;
459
460         lrdf_statement* matches1 = lrdf_matches (&pattern);
461
462         if (!matches1) {
463                 return "Unknown";
464         }
465
466         pattern.subject = matches1->object;
467         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
468         pattern.object = 0;
469         pattern.object_type = lrdf_literal;
470
471         lrdf_statement* matches2 = lrdf_matches (&pattern);
472         lrdf_free_statements(matches1);
473
474         if (!matches2) {
475                 return ("Unknown");
476         }
477
478         string label = matches2->object;
479         lrdf_free_statements(matches2);
480
481         /* Kludge LADSPA class names to be singular and match LV2 class names.
482            This avoids duplicate plugin menus for every class, which is necessary
483            to make the plugin category menu at all usable, but is obviously a
484            filthy kludge.
485
486            In the short term, lrdf could be updated so the labels match and a new
487            release made. To support both specs, we should probably be mapping the
488            URIs to the same category in code and perhaps tweaking that hierarchy
489            dynamically to suit the user. Personally, I (drobilla) think that time
490            is better spent replacing the little-used LRDF.
491
492            In the longer term, we will abandon LRDF entirely in favour of LV2 and
493            use that class hierarchy. Aside from fixing this problem properly, that
494            will also allow for translated labels. SWH plugins have been LV2 for
495            ages; TAP needs porting. I don't know of anything else with LRDF data.
496         */
497         if (label == "Utilities") {
498                 return "Utility";
499         } else if (label == "Pitch shifters") {
500                 return "Pitch Shifter";
501         } else if (label != "Dynamics" && label != "Chorus"
502                    &&label[label.length() - 1] == 's'
503                    && label[label.length() - 2] != 's') {
504                 return label.substr(0, label.length() - 1);
505         } else {
506                 return label;
507         }
508 }
509
510 #ifdef LV2_SUPPORT
511 void
512 PluginManager::lv2_refresh ()
513 {
514         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
515         delete _lv2_plugin_info;
516         _lv2_plugin_info = LV2PluginInfo::discover();
517 }
518 #endif
519
520 #ifdef AUDIOUNIT_SUPPORT
521 void
522 PluginManager::au_refresh ()
523 {
524         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
525         delete _au_plugin_info;
526         _au_plugin_info = AUPluginInfo::discover();
527 }
528
529 #endif
530
531 #ifdef WINDOWS_VST_SUPPORT
532
533 void
534 PluginManager::windows_vst_refresh ()
535 {
536         if (_windows_vst_plugin_info) {
537                 _windows_vst_plugin_info->clear ();
538         } else {
539                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
540         }
541
542         if (windows_vst_path.length() == 0) {
543                 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
544         }
545
546         windows_vst_discover_from_path (windows_vst_path);
547 }
548
549 int
550 PluginManager::add_windows_vst_directory (string path)
551 {
552         if (windows_vst_discover_from_path (path) == 0) {
553                 windows_vst_path += ':';
554                 windows_vst_path += path;
555                 return 0;
556         }
557         return -1;
558 }
559
560 static bool windows_vst_filter (const string& str, void *arg)
561 {
562         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
563
564         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
565 }
566
567 int
568 PluginManager::windows_vst_discover_from_path (string path)
569 {
570         PathScanner scanner;
571         vector<string *> *plugin_objects;
572         vector<string *>::iterator x;
573         int ret = 0;
574
575         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
576
577         plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
578
579         if (plugin_objects) {
580                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
581                         windows_vst_discover (**x);
582                 }
583
584                 vector_delete (plugin_objects);
585         }
586
587         return ret;
588 }
589
590 int
591 PluginManager::windows_vst_discover (string path)
592 {
593         VSTInfo* finfo;
594         char buf[32];
595
596         if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
597                 warning << "Cannot get Windows VST information from " << path << endmsg;
598                 return -1;
599         }
600
601         if (!finfo->canProcessReplacing) {
602                 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
603                                            finfo->name, PROGRAM_NAME)
604                         << endl;
605         }
606
607         PluginInfoPtr info (new WindowsVSTPluginInfo);
608
609         /* what a joke freeware VST is */
610
611         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
612                 info->name = PBD::basename_nosuffix (path);
613         } else {
614                 info->name = finfo->name;
615         }
616
617
618         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
619         info->unique_id = buf;
620         info->category = "VST";
621         info->path = path;
622         info->creator = finfo->creator;
623         info->index = 0;
624         info->n_inputs.set_audio (finfo->numInputs);
625         info->n_outputs.set_audio (finfo->numOutputs);
626         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
627         info->type = ARDOUR::Windows_VST;
628
629         _windows_vst_plugin_info->push_back (info);
630         fst_free_info (finfo);
631
632         return 0;
633 }
634
635 #endif // WINDOWS_VST_SUPPORT
636
637 #ifdef LXVST_SUPPORT
638
639 void
640 PluginManager::lxvst_refresh ()
641 {
642         if (_lxvst_plugin_info) {
643                 _lxvst_plugin_info->clear ();
644         } else {
645                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
646         }
647
648         if (lxvst_path.length() == 0) {
649                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
650                         "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
651                         "/usr/lib/vst:/usr/local/lib/vst";
652         }
653
654         lxvst_discover_from_path (lxvst_path);
655 }
656
657 int
658 PluginManager::add_lxvst_directory (string path)
659 {
660         if (lxvst_discover_from_path (path) == 0) {
661                 lxvst_path += ':';
662                 lxvst_path += path;
663                 return 0;
664         }
665         return -1;
666 }
667
668 static bool lxvst_filter (const string& str, void *)
669 {
670         /* Not a dotfile, has a prefix before a period, suffix is "so" */
671
672         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
673 }
674
675 int
676 PluginManager::lxvst_discover_from_path (string path)
677 {
678         PathScanner scanner;
679         vector<string *> *plugin_objects;
680         vector<string *>::iterator x;
681         int ret = 0;
682
683         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
684
685         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
686
687         if (plugin_objects) {
688                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
689                         lxvst_discover (**x);
690                 }
691
692                 vector_delete (plugin_objects);
693         }
694
695         return ret;
696 }
697
698 int
699 PluginManager::lxvst_discover (string path)
700 {
701         VSTInfo* finfo;
702         char buf[32];
703
704         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
705
706         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
707                 return -1;
708         }
709
710         if (!finfo->canProcessReplacing) {
711                 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
712                                            finfo->name, PROGRAM_NAME)
713                         << endl;
714         }
715
716         PluginInfoPtr info(new LXVSTPluginInfo);
717
718         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
719                 info->name = PBD::basename_nosuffix (path);
720         } else {
721                 info->name = finfo->name;
722         }
723
724         
725         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
726         info->unique_id = buf;
727         info->category = "linuxVSTs";
728         info->path = path;
729         info->creator = finfo->creator;
730         info->index = 0;
731         info->n_inputs.set_audio (finfo->numInputs);
732         info->n_outputs.set_audio (finfo->numOutputs);
733         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
734         info->type = ARDOUR::LXVST;
735
736         /* Make sure we don't find the same plugin in more than one place along
737            the LXVST_PATH We can't use a simple 'find' because the path is included
738            in the PluginInfo, and that is the one thing we can be sure MUST be
739            different if a duplicate instance is found.  So we just compare the type
740            and unique ID (which for some VSTs isn't actually unique...)
741         */
742         
743         if (!_lxvst_plugin_info->empty()) {
744                 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
745                         if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
746                                 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
747                                 vstfx_free_info(finfo);
748                                 return 0;
749                         }
750                 }
751         }
752         
753         _lxvst_plugin_info->push_back (info);
754         vstfx_free_info (finfo);
755
756         return 0;
757 }
758
759 #endif // LXVST_SUPPORT
760
761
762 PluginManager::PluginStatusType
763 PluginManager::get_status (const PluginInfoPtr& pi)
764 {
765         PluginStatus ps (pi->type, pi->unique_id);
766         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
767         if (i ==  statuses.end() ) {
768                 return Normal;
769         } else {
770                 return i->status;
771         }
772 }
773
774 void
775 PluginManager::save_statuses ()
776 {
777         ofstream ofs;
778         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
779
780         ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
781
782         if (!ofs) {
783                 return;
784         }
785
786         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
787                 switch ((*i).type) {
788                 case LADSPA:
789                         ofs << "LADSPA";
790                         break;
791                 case AudioUnit:
792                         ofs << "AudioUnit";
793                         break;
794                 case LV2:
795                         ofs << "LV2";
796                         break;
797                 case Windows_VST:
798                         ofs << "Windows-VST";
799                         break;
800                 case LXVST:
801                         ofs << "LXVST";
802                         break;
803                 }
804
805                 ofs << ' ';
806
807                 switch ((*i).status) {
808                 case Normal:
809                         ofs << "Normal";
810                         break;
811                 case Favorite:
812                         ofs << "Favorite";
813                         break;
814                 case Hidden:
815                         ofs << "Hidden";
816                         break;
817                 }
818
819                 ofs << ' ';
820                 ofs << (*i).unique_id;;
821                 ofs << endl;
822         }
823
824         ofs.close ();
825 }
826
827 void
828 PluginManager::load_statuses ()
829 {
830         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
831         ifstream ifs (path.c_str());
832
833         if (!ifs) {
834                 return;
835         }
836
837         std::string stype;
838         std::string sstatus;
839         std::string id;
840         PluginType type;
841         PluginStatusType status;
842         char buf[1024];
843
844         while (ifs) {
845
846                 ifs >> stype;
847                 if (!ifs) {
848                         break;
849
850                 }
851
852                 ifs >> sstatus;
853                 if (!ifs) {
854                         break;
855
856                 }
857
858                 /* rest of the line is the plugin ID */
859
860                 ifs.getline (buf, sizeof (buf), '\n');
861                 if (!ifs) {
862                         break;
863                 }
864
865                 if (sstatus == "Normal") {
866                         status = Normal;
867                 } else if (sstatus == "Favorite") {
868                         status = Favorite;
869                 } else if (sstatus == "Hidden") {
870                         status = Hidden;
871                 } else {
872                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
873                                   << endmsg;
874                         statuses.clear ();
875                         break;
876                 }
877
878                 if (stype == "LADSPA") {
879                         type = LADSPA;
880                 } else if (stype == "AudioUnit") {
881                         type = AudioUnit;
882                 } else if (stype == "LV2") {
883                         type = LV2;
884                 } else if (stype == "Windows-VST") {
885                         type = Windows_VST;
886                 } else if (stype == "LXVST") {
887                         type = LXVST;
888                 } else {
889                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
890                               << endmsg;
891                         continue;
892                 }
893
894                 id = buf;
895                 strip_whitespace_edges (id);
896                 set_status (type, id, status);
897         }
898
899         ifs.close ();
900 }
901
902 void
903 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
904 {
905         PluginStatus ps (t, id, status);
906         statuses.erase (ps);
907
908         if (status == Normal) {
909                 return;
910         }
911
912         statuses.insert (ps);
913 }
914
915 ARDOUR::PluginInfoList&
916 PluginManager::windows_vst_plugin_info ()
917 {
918 #ifdef WINDOWS_VST_SUPPORT
919         if (!_windows_vst_plugin_info) {
920                 windows_vst_refresh ();
921         }
922         return *_windows_vst_plugin_info;
923 #else
924         return _empty_plugin_info;
925 #endif
926 }
927
928 ARDOUR::PluginInfoList&
929 PluginManager::lxvst_plugin_info ()
930 {
931 #ifdef LXVST_SUPPORT
932         if (!_lxvst_plugin_info)
933                 lxvst_refresh();
934         return *_lxvst_plugin_info;
935 #else
936         return _empty_plugin_info;
937 #endif
938 }
939
940 ARDOUR::PluginInfoList&
941 PluginManager::ladspa_plugin_info ()
942 {
943         if (!_ladspa_plugin_info)
944                 ladspa_refresh();
945         return *_ladspa_plugin_info;
946 }
947
948 ARDOUR::PluginInfoList&
949 PluginManager::lv2_plugin_info ()
950 {
951 #ifdef LV2_SUPPORT
952         if (!_lv2_plugin_info)
953                 lv2_refresh();
954         return *_lv2_plugin_info;
955 #else
956         return _empty_plugin_info;
957 #endif
958 }
959
960 ARDOUR::PluginInfoList&
961 PluginManager::au_plugin_info ()
962 {
963 #ifdef AUDIOUNIT_SUPPORT
964         if (!_au_plugin_info)
965                 au_refresh();
966         return *_au_plugin_info;
967 #else
968         return _empty_plugin_info;
969 #endif
970 }