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