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