restore ability to create TOC and CUE files during export. this is an option in a...
[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/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         VSTInfo* 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         VSTInfo* 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                                 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
740                                 vstfx_free_info(finfo);
741                                 return 0;
742                         }
743                 }
744         }
745         
746         _lxvst_plugin_info->push_back (info);
747         vstfx_free_info (finfo);
748
749         return 0;
750 }
751
752 #endif // LXVST_SUPPORT
753
754
755 PluginManager::PluginStatusType
756 PluginManager::get_status (const PluginInfoPtr& pi)
757 {
758         PluginStatus ps (pi->type, pi->unique_id);
759         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
760         if (i ==  statuses.end() ) {
761                 return Normal;
762         } else {
763                 return i->status;
764         }
765 }
766
767 void
768 PluginManager::save_statuses ()
769 {
770         ofstream ofs;
771         sys::path path = user_config_directory();
772         path /= "plugin_statuses";
773
774         ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc));
775
776         if (!ofs) {
777                 return;
778         }
779
780         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
781                 switch ((*i).type) {
782                 case LADSPA:
783                         ofs << "LADSPA";
784                         break;
785                 case AudioUnit:
786                         ofs << "AudioUnit";
787                         break;
788                 case LV2:
789                         ofs << "LV2";
790                         break;
791                 case Windows_VST:
792                         ofs << "Windows-VST";
793                         break;
794                 case LXVST:
795                         ofs << "LXVST";
796                         break;
797                 }
798
799                 ofs << ' ';
800
801                 switch ((*i).status) {
802                 case Normal:
803                         ofs << "Normal";
804                         break;
805                 case Favorite:
806                         ofs << "Favorite";
807                         break;
808                 case Hidden:
809                         ofs << "Hidden";
810                         break;
811                 }
812
813                 ofs << ' ';
814                 ofs << (*i).unique_id;;
815                 ofs << endl;
816         }
817
818         ofs.close ();
819 }
820
821 void
822 PluginManager::load_statuses ()
823 {
824         sys::path path = user_config_directory();
825         path /= "plugin_statuses";
826         ifstream ifs (path.to_string().c_str());
827
828         if (!ifs) {
829                 return;
830         }
831
832         std::string stype;
833         std::string sstatus;
834         std::string id;
835         PluginType type;
836         PluginStatusType status;
837         char buf[1024];
838
839         while (ifs) {
840
841                 ifs >> stype;
842                 if (!ifs) {
843                         break;
844
845                 }
846
847                 ifs >> sstatus;
848                 if (!ifs) {
849                         break;
850
851                 }
852
853                 /* rest of the line is the plugin ID */
854
855                 ifs.getline (buf, sizeof (buf), '\n');
856                 if (!ifs) {
857                         break;
858                 }
859
860                 if (sstatus == "Normal") {
861                         status = Normal;
862                 } else if (sstatus == "Favorite") {
863                         status = Favorite;
864                 } else if (sstatus == "Hidden") {
865                         status = Hidden;
866                 } else {
867                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
868                                   << endmsg;
869                         statuses.clear ();
870                         break;
871                 }
872
873                 if (stype == "LADSPA") {
874                         type = LADSPA;
875                 } else if (stype == "AudioUnit") {
876                         type = AudioUnit;
877                 } else if (stype == "LV2") {
878                         type = LV2;
879                 } else if (stype == "Windows-VST") {
880                         type = Windows_VST;
881                 } else if (stype == "LXVST") {
882                         type = LXVST;
883                 } else {
884                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
885                               << endmsg;
886                         continue;
887                 }
888
889                 id = buf;
890                 strip_whitespace_edges (id);
891                 set_status (type, id, status);
892         }
893
894         ifs.close ();
895 }
896
897 void
898 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
899 {
900         PluginStatus ps (t, id, status);
901         statuses.erase (ps);
902
903         if (status == Normal) {
904                 return;
905         }
906
907         statuses.insert (ps);
908 }
909
910 ARDOUR::PluginInfoList&
911 PluginManager::windows_vst_plugin_info ()
912 {
913 #ifdef WINDOWS_VST_SUPPORT
914         if (!_windows_vst_plugin_info) {
915                 windows_vst_refresh ();
916         }
917         return *_windows_vst_plugin_info;
918 #else
919         return _empty_plugin_info;
920 #endif
921 }
922
923 ARDOUR::PluginInfoList&
924 PluginManager::lxvst_plugin_info ()
925 {
926 #ifdef LXVST_SUPPORT
927         if (!_lxvst_plugin_info)
928                 lxvst_refresh();
929         return *_lxvst_plugin_info;
930 #else
931         return _empty_plugin_info;
932 #endif
933 }
934
935 ARDOUR::PluginInfoList&
936 PluginManager::ladspa_plugin_info ()
937 {
938         if (!_ladspa_plugin_info)
939                 ladspa_refresh();
940         return *_ladspa_plugin_info;
941 }
942
943 ARDOUR::PluginInfoList&
944 PluginManager::lv2_plugin_info ()
945 {
946 #ifdef LV2_SUPPORT
947         if (!_lv2_plugin_info)
948                 lv2_refresh();
949         return *_lv2_plugin_info;
950 #else
951         return _empty_plugin_info;
952 #endif
953 }
954
955 ARDOUR::PluginInfoList&
956 PluginManager::au_plugin_info ()
957 {
958 #ifdef AUDIOUNIT_SUPPORT
959         if (!_au_plugin_info)
960                 au_refresh();
961         return *_au_plugin_info;
962 #else
963         return _empty_plugin_info;
964 #endif
965 }