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