6034bba680c718f75c451c4cf634c821e6ae5818
[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         }
652
653         lxvst_discover_from_path (lxvst_path);
654 }
655
656 int
657 PluginManager::add_lxvst_directory (string path)
658 {
659         if (lxvst_discover_from_path (path) == 0) {
660                 lxvst_path += ':';
661                 lxvst_path += path;
662                 return 0;
663         }
664         return -1;
665 }
666
667 static bool lxvst_filter (const string& str, void *)
668 {
669         /* Not a dotfile, has a prefix before a period, suffix is "so" */
670
671         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
672 }
673
674 int
675 PluginManager::lxvst_discover_from_path (string path)
676 {
677         PathScanner scanner;
678         vector<string *> *plugin_objects;
679         vector<string *>::iterator x;
680         int ret = 0;
681
682         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
683
684         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
685
686         if (plugin_objects) {
687                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
688                         lxvst_discover (**x);
689                 }
690
691                 vector_delete (plugin_objects);
692         }
693
694         return ret;
695 }
696
697 int
698 PluginManager::lxvst_discover (string path)
699 {
700         VSTInfo* finfo;
701         char buf[32];
702
703         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
704
705         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
706                 return -1;
707         }
708
709         if (!finfo->canProcessReplacing) {
710                 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
711                                            finfo->name, PROGRAM_NAME)
712                         << endl;
713         }
714
715         PluginInfoPtr info(new LXVSTPluginInfo);
716
717         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
718                 info->name = PBD::basename_nosuffix (path);
719         } else {
720                 info->name = finfo->name;
721         }
722
723         
724         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
725         info->unique_id = buf;
726         info->category = "linuxVSTs";
727         info->path = path;
728         info->creator = finfo->creator;
729         info->index = 0;
730         info->n_inputs.set_audio (finfo->numInputs);
731         info->n_outputs.set_audio (finfo->numOutputs);
732         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
733         info->type = ARDOUR::LXVST;
734
735         /* Make sure we don't find the same plugin in more than one place along
736            the LXVST_PATH We can't use a simple 'find' because the path is included
737            in the PluginInfo, and that is the one thing we can be sure MUST be
738            different if a duplicate instance is found.  So we just compare the type
739            and unique ID (which for some VSTs isn't actually unique...)
740         */
741         
742         if (!_lxvst_plugin_info->empty()) {
743                 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
744                         if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
745                                 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
746                                 vstfx_free_info(finfo);
747                                 return 0;
748                         }
749                 }
750         }
751         
752         _lxvst_plugin_info->push_back (info);
753         vstfx_free_info (finfo);
754
755         return 0;
756 }
757
758 #endif // LXVST_SUPPORT
759
760
761 PluginManager::PluginStatusType
762 PluginManager::get_status (const PluginInfoPtr& pi)
763 {
764         PluginStatus ps (pi->type, pi->unique_id);
765         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
766         if (i ==  statuses.end() ) {
767                 return Normal;
768         } else {
769                 return i->status;
770         }
771 }
772
773 void
774 PluginManager::save_statuses ()
775 {
776         ofstream ofs;
777         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
778
779         ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
780
781         if (!ofs) {
782                 return;
783         }
784
785         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
786                 switch ((*i).type) {
787                 case LADSPA:
788                         ofs << "LADSPA";
789                         break;
790                 case AudioUnit:
791                         ofs << "AudioUnit";
792                         break;
793                 case LV2:
794                         ofs << "LV2";
795                         break;
796                 case Windows_VST:
797                         ofs << "Windows-VST";
798                         break;
799                 case LXVST:
800                         ofs << "LXVST";
801                         break;
802                 }
803
804                 ofs << ' ';
805
806                 switch ((*i).status) {
807                 case Normal:
808                         ofs << "Normal";
809                         break;
810                 case Favorite:
811                         ofs << "Favorite";
812                         break;
813                 case Hidden:
814                         ofs << "Hidden";
815                         break;
816                 }
817
818                 ofs << ' ';
819                 ofs << (*i).unique_id;;
820                 ofs << endl;
821         }
822
823         ofs.close ();
824 }
825
826 void
827 PluginManager::load_statuses ()
828 {
829         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
830         ifstream ifs (path.c_str());
831
832         if (!ifs) {
833                 return;
834         }
835
836         std::string stype;
837         std::string sstatus;
838         std::string id;
839         PluginType type;
840         PluginStatusType status;
841         char buf[1024];
842
843         while (ifs) {
844
845                 ifs >> stype;
846                 if (!ifs) {
847                         break;
848
849                 }
850
851                 ifs >> sstatus;
852                 if (!ifs) {
853                         break;
854
855                 }
856
857                 /* rest of the line is the plugin ID */
858
859                 ifs.getline (buf, sizeof (buf), '\n');
860                 if (!ifs) {
861                         break;
862                 }
863
864                 if (sstatus == "Normal") {
865                         status = Normal;
866                 } else if (sstatus == "Favorite") {
867                         status = Favorite;
868                 } else if (sstatus == "Hidden") {
869                         status = Hidden;
870                 } else {
871                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
872                                   << endmsg;
873                         statuses.clear ();
874                         break;
875                 }
876
877                 if (stype == "LADSPA") {
878                         type = LADSPA;
879                 } else if (stype == "AudioUnit") {
880                         type = AudioUnit;
881                 } else if (stype == "LV2") {
882                         type = LV2;
883                 } else if (stype == "Windows-VST") {
884                         type = Windows_VST;
885                 } else if (stype == "LXVST") {
886                         type = LXVST;
887                 } else {
888                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
889                               << endmsg;
890                         continue;
891                 }
892
893                 id = buf;
894                 strip_whitespace_edges (id);
895                 set_status (type, id, status);
896         }
897
898         ifs.close ();
899 }
900
901 void
902 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
903 {
904         PluginStatus ps (t, id, status);
905         statuses.erase (ps);
906
907         if (status == Normal) {
908                 return;
909         }
910
911         statuses.insert (ps);
912 }
913
914 ARDOUR::PluginInfoList&
915 PluginManager::windows_vst_plugin_info ()
916 {
917 #ifdef WINDOWS_VST_SUPPORT
918         if (!_windows_vst_plugin_info) {
919                 windows_vst_refresh ();
920         }
921         return *_windows_vst_plugin_info;
922 #else
923         return _empty_plugin_info;
924 #endif
925 }
926
927 ARDOUR::PluginInfoList&
928 PluginManager::lxvst_plugin_info ()
929 {
930 #ifdef LXVST_SUPPORT
931         if (!_lxvst_plugin_info)
932                 lxvst_refresh();
933         return *_lxvst_plugin_info;
934 #else
935         return _empty_plugin_info;
936 #endif
937 }
938
939 ARDOUR::PluginInfoList&
940 PluginManager::ladspa_plugin_info ()
941 {
942         if (!_ladspa_plugin_info)
943                 ladspa_refresh();
944         return *_ladspa_plugin_info;
945 }
946
947 ARDOUR::PluginInfoList&
948 PluginManager::lv2_plugin_info ()
949 {
950 #ifdef LV2_SUPPORT
951         if (!_lv2_plugin_info)
952                 lv2_refresh();
953         return *_lv2_plugin_info;
954 #else
955         return _empty_plugin_info;
956 #endif
957 }
958
959 ARDOUR::PluginInfoList&
960 PluginManager::au_plugin_info ()
961 {
962 #ifdef AUDIOUNIT_SUPPORT
963         if (!_au_plugin_info)
964                 au_refresh();
965         return *_au_plugin_info;
966 #else
967         return _empty_plugin_info;
968 #endif
969 }