Rename windows VST stuff with a Windows prefix.
[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/vstfx.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/session.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
283         vector_delete (plugin_objects);
284         return ret;
285 }
286
287 static bool rdf_filter (const string &str, void* /*arg*/)
288 {
289         return str[0] != '.' &&
290                    ((str.find(".rdf")  == (str.length() - 4)) ||
291             (str.find(".rdfs") == (str.length() - 5)) ||
292                     (str.find(".n3")   == (str.length() - 3)) ||
293                     (str.find(".ttl")  == (str.length() - 4)));
294 }
295
296 void
297 PluginManager::add_ladspa_presets()
298 {
299         add_presets ("ladspa");
300 }
301
302 void
303 PluginManager::add_windows_vst_presets()
304 {
305         add_presets ("windows-vst");
306 }
307
308 void
309 PluginManager::add_lxvst_presets()
310 {
311         add_presets ("lxvst");
312 }
313
314 void
315 PluginManager::add_presets(string domain)
316 {
317
318         PathScanner scanner;
319         vector<string *> *presets;
320         vector<string *>::iterator x;
321
322         char* envvar;
323         if ((envvar = getenv ("HOME")) == 0) {
324                 return;
325         }
326
327         string path = string_compose("%1/.%2/rdf", envvar, domain);
328         presets = scanner (path, rdf_filter, 0, false, true);
329
330         if (presets) {
331                 for (x = presets->begin(); x != presets->end (); ++x) {
332                         string file = "file:" + **x;
333                         if (lrdf_read_file(file.c_str())) {
334                                 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
335                         }
336                 }
337         }
338
339         vector_delete (presets);
340 }
341
342 void
343 PluginManager::add_lrdf_data (const string &path)
344 {
345         PathScanner scanner;
346         vector<string *>* rdf_files;
347         vector<string *>::iterator x;
348
349         rdf_files = scanner (path, rdf_filter, 0, false, true);
350
351         if (rdf_files) {
352                 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
353                         const string uri(string("file://") + **x);
354
355                         if (lrdf_read_file(uri.c_str())) {
356                                 warning << "Could not parse rdf file: " << uri << endmsg;
357                         }
358                 }
359         }
360
361         vector_delete (rdf_files);
362 }
363
364 int
365 PluginManager::ladspa_discover (string path)
366 {
367         void *module;
368         const LADSPA_Descriptor *descriptor;
369         LADSPA_Descriptor_Function dfunc;
370         const char *errstr;
371
372         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
373                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
374                 return -1;
375         }
376
377         dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
378
379         if ((errstr = dlerror()) != 0) {
380                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
381                 error << errstr << endmsg;
382                 dlclose (module);
383                 return -1;
384         }
385
386         for (uint32_t i = 0; ; ++i) {
387                 if ((descriptor = dfunc (i)) == 0) {
388                         break;
389                 }
390
391                 if (!ladspa_plugin_whitelist.empty()) {
392                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
393                                 continue;
394                         }
395                 }
396
397                 PluginInfoPtr info(new LadspaPluginInfo);
398                 info->name = descriptor->Name;
399                 info->category = get_ladspa_category(descriptor->UniqueID);
400                 info->creator = descriptor->Maker;
401                 info->path = path;
402                 info->index = i;
403                 info->n_inputs = ChanCount();
404                 info->n_outputs = ChanCount();
405                 info->type = ARDOUR::LADSPA;
406
407                 char buf[32];
408                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
409                 info->unique_id = buf;
410
411                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
412                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
413                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
414                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
415                                 }
416                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
417                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
418                                 }
419                         }
420                 }
421
422                 if(_ladspa_plugin_info->empty()){
423                         _ladspa_plugin_info->push_back (info);
424                 }
425
426                 //Ensure that the plugin is not already in the plugin list.
427
428                 bool found = false;
429
430                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
431                         if(0 == info->unique_id.compare((*i)->unique_id)){
432                               found = true;
433                         }
434                 }
435
436                 if(!found){
437                     _ladspa_plugin_info->push_back (info);
438                 }
439         }
440
441 // GDB WILL NOT LIKE YOU IF YOU DO THIS
442 //      dlclose (module);
443
444         return 0;
445 }
446
447 string
448 PluginManager::get_ladspa_category (uint32_t plugin_id)
449 {
450         char buf[256];
451         lrdf_statement pattern;
452
453         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
454         pattern.subject = buf;
455         pattern.predicate = (char*)RDF_TYPE;
456         pattern.object = 0;
457         pattern.object_type = lrdf_uri;
458
459         lrdf_statement* matches1 = lrdf_matches (&pattern);
460
461         if (!matches1) {
462                 return "Unknown";
463         }
464
465         pattern.subject = matches1->object;
466         pattern.predicate = (char*)(LADSPA_BASE "hasLabel");
467         pattern.object = 0;
468         pattern.object_type = lrdf_literal;
469
470         lrdf_statement* matches2 = lrdf_matches (&pattern);
471         lrdf_free_statements(matches1);
472
473         if (!matches2) {
474                 return ("Unknown");
475         }
476
477         string label = matches2->object;
478         lrdf_free_statements(matches2);
479
480         /* Kludge LADSPA class names to be singular and match LV2 class names.
481            This avoids duplicate plugin menus for every class, which is necessary
482            to make the plugin category menu at all usable, but is obviously a
483            filthy kludge.
484
485            In the short term, lrdf could be updated so the labels match and a new
486            release made. To support both specs, we should probably be mapping the
487            URIs to the same category in code and perhaps tweaking that hierarchy
488            dynamically to suit the user. Personally, I (drobilla) think that time
489            is better spent replacing the little-used LRDF.
490
491            In the longer term, we will abandon LRDF entirely in favour of LV2 and
492            use that class hierarchy. Aside from fixing this problem properly, that
493            will also allow for translated labels. SWH plugins have been LV2 for
494            ages; TAP needs porting. I don't know of anything else with LRDF data.
495         */
496         if (label == "Utilities") {
497                 return "Utility";
498         } else if (label == "Pitch shifters") {
499                 return "Pitch Shifter";
500         } else if (label != "Dynamics" && label != "Chorus"
501                    &&label[label.length() - 1] == 's'
502                    && label[label.length() - 2] != 's') {
503                 return label.substr(0, label.length() - 1);
504         } else {
505                 return label;
506         }
507 }
508
509 #ifdef LV2_SUPPORT
510 void
511 PluginManager::lv2_refresh ()
512 {
513         delete _lv2_plugin_info;
514         _lv2_plugin_info = LV2PluginInfo::discover();
515 }
516 #endif
517
518 #ifdef AUDIOUNIT_SUPPORT
519 void
520 PluginManager::au_refresh ()
521 {
522         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
523         delete _au_plugin_info;
524         _au_plugin_info = AUPluginInfo::discover();
525 }
526
527 #endif
528
529 #ifdef WINDOWS_VST_SUPPORT
530
531 void
532 PluginManager::windows_vst_refresh ()
533 {
534         if (_windows_vst_plugin_info) {
535                 _windows_vst_plugin_info->clear ();
536         } else {
537                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
538         }
539
540         if (windows_vst_path.length() == 0) {
541                 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
542         }
543
544         windows_vst_discover_from_path (windows_vst_path);
545 }
546
547 int
548 PluginManager::add_windows_vst_directory (string path)
549 {
550         if (windows_vst_discover_from_path (path) == 0) {
551                 windows_vst_path += ':';
552                 windows_vst_path += path;
553                 return 0;
554         }
555         return -1;
556 }
557
558 static bool windows_vst_filter (const string& str, void *arg)
559 {
560         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
561
562         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
563 }
564
565 int
566 PluginManager::windows_vst_discover_from_path (string path)
567 {
568         PathScanner scanner;
569         vector<string *> *plugin_objects;
570         vector<string *>::iterator x;
571         int ret = 0;
572
573         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
574
575         plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
576
577         if (plugin_objects) {
578                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
579                         windows_vst_discover (**x);
580                 }
581         }
582
583         vector_delete (plugin_objects);
584         return ret;
585 }
586
587 int
588 PluginManager::windows_vst_discover (string path)
589 {
590         FSTInfo* finfo;
591         char buf[32];
592
593         if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
594                 warning << "Cannot get Windows VST information from " << path << endmsg;
595                 return -1;
596         }
597
598         if (!finfo->canProcessReplacing) {
599                 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
600                                     finfo->name)
601                         << endl;
602         }
603
604         PluginInfoPtr info (new WindowsVSTPluginInfo);
605
606         /* what a joke freeware VST is */
607
608         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
609                 info->name = PBD::basename_nosuffix (path);
610         } else {
611                 info->name = finfo->name;
612         }
613
614
615         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
616         info->unique_id = buf;
617         info->category = "VST";
618         info->path = path;
619         info->creator = finfo->creator;
620         info->index = 0;
621         info->n_inputs.set_audio (finfo->numInputs);
622         info->n_outputs.set_audio (finfo->numOutputs);
623         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
624         info->type = ARDOUR::Windows_VST;
625
626         _windows_vst_plugin_info->push_back (info);
627         fst_free_info (finfo);
628
629         return 0;
630 }
631
632 #endif // WINDOWS_VST_SUPPORT
633
634 #ifdef LXVST_SUPPORT
635
636 void
637 PluginManager::lxvst_refresh ()
638 {
639         if (_lxvst_plugin_info) {
640                 _lxvst_plugin_info->clear ();
641         } else {
642                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
643         }
644
645         if (lxvst_path.length() == 0) {
646                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
647         }
648
649         lxvst_discover_from_path (lxvst_path);
650 }
651
652 int
653 PluginManager::add_lxvst_directory (string path)
654 {
655         if (lxvst_discover_from_path (path) == 0) {
656                 lxvst_path += ':';
657                 lxvst_path += path;
658                 return 0;
659         }
660         return -1;
661 }
662
663 static bool lxvst_filter (const string& str, void *)
664 {
665         /* Not a dotfile, has a prefix before a period, suffix is "so" */
666
667         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
668 }
669
670 int
671 PluginManager::lxvst_discover_from_path (string path)
672 {
673         PathScanner scanner;
674         vector<string *> *plugin_objects;
675         vector<string *>::iterator x;
676         int ret = 0;
677
678         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
679
680         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
681
682         if (plugin_objects) {
683                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
684                         lxvst_discover (**x);
685                 }
686         }
687
688         vector_delete (plugin_objects);
689         return ret;
690 }
691
692 int
693 PluginManager::lxvst_discover (string path)
694 {
695         VSTFXInfo* finfo;
696         char buf[32];
697
698         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
699                 warning << "Cannot get linuxVST information from " << path << endmsg;
700                 return -1;
701         }
702
703         if (!finfo->canProcessReplacing) {
704                 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
705                                     finfo->name)
706                         << endl;
707         }
708
709         PluginInfoPtr info(new LXVSTPluginInfo);
710
711         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
712                 info->name = PBD::basename_nosuffix (path);
713         } else {
714                 info->name = finfo->name;
715         }
716
717         
718         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
719         info->unique_id = buf;
720         info->category = "linuxVSTs";
721         info->path = path;
722         info->creator = finfo->creator;
723         info->index = 0;
724         info->n_inputs.set_audio (finfo->numInputs);
725         info->n_outputs.set_audio (finfo->numOutputs);
726         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
727         info->type = ARDOUR::LXVST;
728
729         /* Make sure we don't find the same plugin in more than one place along
730            the LXVST_PATH We can't use a simple 'find' because the path is included
731            in the PluginInfo, and that is the one thing we can be sure MUST be
732            different if a duplicate instance is found.  So we just compare the type
733            and unique ID (which for some VSTs isn't actually unique...)
734         */
735         
736         if (!_lxvst_plugin_info->empty()) {
737                 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
738                         if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
739                                 vstfx_free_info(finfo);
740                                 return 0;
741                         }
742                 }
743         }
744         
745         _lxvst_plugin_info->push_back (info);
746         vstfx_free_info (finfo);
747
748         return 0;
749 }
750
751 #endif // LXVST_SUPPORT
752
753
754 PluginManager::PluginStatusType
755 PluginManager::get_status (const PluginInfoPtr& pi)
756 {
757         PluginStatus ps (pi->type, pi->unique_id);
758         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
759         if (i ==  statuses.end() ) {
760                 return Normal;
761         } else {
762                 return i->status;
763         }
764 }
765
766 void
767 PluginManager::save_statuses ()
768 {
769         ofstream ofs;
770         sys::path path = user_config_directory();
771         path /= "plugin_statuses";
772
773         ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc));
774
775         if (!ofs) {
776                 return;
777         }
778
779         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
780                 switch ((*i).type) {
781                 case LADSPA:
782                         ofs << "LADSPA";
783                         break;
784                 case AudioUnit:
785                         ofs << "AudioUnit";
786                         break;
787                 case LV2:
788                         ofs << "LV2";
789                         break;
790                 case Windows_VST:
791                         ofs << "Windows-VST";
792                         break;
793                 case LXVST:
794                         ofs << "LXVST";
795                         break;
796                 }
797
798                 ofs << ' ';
799
800                 switch ((*i).status) {
801                 case Normal:
802                         ofs << "Normal";
803                         break;
804                 case Favorite:
805                         ofs << "Favorite";
806                         break;
807                 case Hidden:
808                         ofs << "Hidden";
809                         break;
810                 }
811
812                 ofs << ' ';
813                 ofs << (*i).unique_id;;
814                 ofs << endl;
815         }
816
817         ofs.close ();
818 }
819
820 void
821 PluginManager::load_statuses ()
822 {
823         sys::path path = user_config_directory();
824         path /= "plugin_statuses";
825         ifstream ifs (path.to_string().c_str());
826
827         if (!ifs) {
828                 return;
829         }
830
831         std::string stype;
832         std::string sstatus;
833         std::string id;
834         PluginType type;
835         PluginStatusType status;
836         char buf[1024];
837
838         while (ifs) {
839
840                 ifs >> stype;
841                 if (!ifs) {
842                         break;
843
844                 }
845
846                 ifs >> sstatus;
847                 if (!ifs) {
848                         break;
849
850                 }
851
852                 /* rest of the line is the plugin ID */
853
854                 ifs.getline (buf, sizeof (buf), '\n');
855                 if (!ifs) {
856                         break;
857                 }
858
859                 if (sstatus == "Normal") {
860                         status = Normal;
861                 } else if (sstatus == "Favorite") {
862                         status = Favorite;
863                 } else if (sstatus == "Hidden") {
864                         status = Hidden;
865                 } else {
866                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
867                                   << endmsg;
868                         statuses.clear ();
869                         break;
870                 }
871
872                 if (stype == "LADSPA") {
873                         type = LADSPA;
874                 } else if (stype == "AudioUnit") {
875                         type = AudioUnit;
876                 } else if (stype == "LV2") {
877                         type = LV2;
878                 } else if (stype == "Windows-VST") {
879                         type = Windows_VST;
880                 } else if (stype == "LXVST") {
881                         type = LXVST;
882                 } else {
883                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
884                               << endmsg;
885                         continue;
886                 }
887
888                 id = buf;
889                 strip_whitespace_edges (id);
890                 set_status (type, id, status);
891         }
892
893         ifs.close ();
894 }
895
896 void
897 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
898 {
899         PluginStatus ps (t, id, status);
900         statuses.erase (ps);
901
902         if (status == Normal) {
903                 return;
904         }
905
906         statuses.insert (ps);
907 }
908
909 ARDOUR::PluginInfoList&
910 PluginManager::windows_vst_plugin_info ()
911 {
912 #ifdef WINDOWS_VST_SUPPORT
913         if (!_windows_vst_plugin_info) {
914                 windows_vst_refresh ();
915         }
916         return *_windows_vst_plugin_info;
917 #else
918         return _empty_plugin_info;
919 #endif
920 }
921
922 ARDOUR::PluginInfoList&
923 PluginManager::lxvst_plugin_info ()
924 {
925 #ifdef LXVST_SUPPORT
926         if (!_lxvst_plugin_info)
927                 lxvst_refresh();
928         return *_lxvst_plugin_info;
929 #else
930         return _empty_plugin_info;
931 #endif
932 }
933
934 ARDOUR::PluginInfoList&
935 PluginManager::ladspa_plugin_info ()
936 {
937         if (!_ladspa_plugin_info)
938                 ladspa_refresh();
939         return *_ladspa_plugin_info;
940 }
941
942 ARDOUR::PluginInfoList&
943 PluginManager::lv2_plugin_info ()
944 {
945 #ifdef LV2_SUPPORT
946         if (!_lv2_plugin_info)
947                 lv2_refresh();
948         return *_lv2_plugin_info;
949 #else
950         return _empty_plugin_info;
951 #endif
952 }
953
954 ARDOUR::PluginInfoList&
955 PluginManager::au_plugin_info ()
956 {
957 #ifdef AUDIOUNIT_SUPPORT
958         if (!_au_plugin_info)
959                 au_refresh();
960         return *_au_plugin_info;
961 #else
962         return _empty_plugin_info;
963 #endif
964 }