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