Use std::string instead of PBD::sys::path in pbd/search_path.h, pbd/file_utils.h...
[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 #include "pbd/filesystem.h"
50
51 #include "ardour/debug.h"
52 #include "ardour/filesystem_paths.h"
53 #include "ardour/ladspa.h"
54 #include "ardour/ladspa_plugin.h"
55 #include "ardour/plugin.h"
56 #include "ardour/plugin_manager.h"
57 #include "ardour/rc_configuration.h"
58
59 #ifdef LV2_SUPPORT
60 #include "ardour/lv2_plugin.h"
61 #endif
62
63 #ifdef WINDOWS_VST_SUPPORT
64 #include "ardour/windows_vst_plugin.h"
65 #endif
66
67 #ifdef LXVST_SUPPORT
68 #include "ardour/lxvst_plugin.h"
69 #endif
70
71 #ifdef AUDIOUNIT_SUPPORT
72 #include "ardour/audio_unit.h"
73 #include <Carbon/Carbon.h>
74 #endif
75
76 #include "pbd/error.h"
77 #include "pbd/stl_delete.h"
78
79 #include "i18n.h"
80
81 using namespace ARDOUR;
82 using namespace PBD;
83 using namespace std;
84
85 PluginManager* PluginManager::_instance = 0;
86
87 PluginManager&
88 PluginManager::instance() 
89 {
90         if (!_instance) {
91                 _instance = new PluginManager;
92         }
93         return *_instance;
94 }
95
96 PluginManager::PluginManager ()
97         : _windows_vst_plugin_info(0)
98         , _lxvst_plugin_info(0)
99         , _ladspa_plugin_info(0)
100         , _lv2_plugin_info(0)
101         , _au_plugin_info(0)
102 {
103         char* s;
104         string lrdf_path;
105
106         load_statuses ();
107
108         if ((s = getenv ("LADSPA_RDF_PATH"))){
109                 lrdf_path = s;
110         }
111
112         if (lrdf_path.length() == 0) {
113                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
114         }
115
116         add_lrdf_data(lrdf_path);
117         add_ladspa_presets();
118 #ifdef WINDOWS_VST_SUPPORT
119         if (Config->get_use_windows_vst ()) {
120                 add_windows_vst_presets ();
121         }
122 #endif /* WINDOWS_VST_SUPPORT */
123
124 #ifdef LXVST_SUPPORT
125         if (Config->get_use_lxvst()) {
126                 add_lxvst_presets();
127         }
128 #endif /* Native LinuxVST support*/
129
130         if ((s = getenv ("LADSPA_PATH"))) {
131                 ladspa_path = s;
132         }
133
134         if ((s = getenv ("VST_PATH"))) {
135                 windows_vst_path = s;
136         } else if ((s = getenv ("VST_PLUGINS"))) {
137                 windows_vst_path = s;
138         }
139
140         if ((s = getenv ("LXVST_PATH"))) {
141                 lxvst_path = s;
142         } else if ((s = getenv ("LXVST_PLUGINS"))) {
143                 lxvst_path = s;
144         }
145
146         if (_instance == 0) {
147                 _instance = this;
148         }
149
150         /* the plugin manager is constructed too early to use Profile */
151
152         if (getenv ("ARDOUR_SAE")) {
153                 ladspa_plugin_whitelist.push_back (1203); // single band parametric
154                 ladspa_plugin_whitelist.push_back (1772); // caps compressor
155                 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
156                 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
157                 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
158                 ladspa_plugin_whitelist.push_back (1216); // gverb
159                 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
160         }
161
162         BootMessage (_("Discovering Plugins"));
163 }
164
165
166 PluginManager::~PluginManager()
167 {
168 }
169
170
171 void
172 PluginManager::refresh ()
173 {
174         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
175
176         ladspa_refresh ();
177 #ifdef LV2_SUPPORT
178         lv2_refresh ();
179 #endif
180 #ifdef WINDOWS_VST_SUPPORT
181         if (Config->get_use_windows_vst()) {
182                 windows_vst_refresh ();
183         }
184 #endif // WINDOWS_VST_SUPPORT
185
186 #ifdef LXVST_SUPPORT
187         if(Config->get_use_lxvst()) {
188                 lxvst_refresh();
189         }
190 #endif //Native linuxVST SUPPORT
191
192 #ifdef AUDIOUNIT_SUPPORT
193         au_refresh ();
194 #endif
195
196         PluginListChanged (); /* EMIT SIGNAL */
197 }
198
199 void
200 PluginManager::ladspa_refresh ()
201 {
202         if (_ladspa_plugin_info)
203                 _ladspa_plugin_info->clear ();
204         else
205                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
206
207         static const char *standard_paths[] = {
208                 "/usr/local/lib64/ladspa",
209                 "/usr/local/lib/ladspa",
210                 "/usr/lib64/ladspa",
211                 "/usr/lib/ladspa",
212                 "/Library/Audio/Plug-Ins/LADSPA",
213                 ""
214         };
215
216         /* allow LADSPA_PATH to augment, not override standard locations */
217
218         /* Only add standard locations to ladspa_path if it doesn't
219          * already contain them. Check for trailing G_DIR_SEPARATOR too.
220          */
221
222         int i;
223         for (i = 0; standard_paths[i][0]; i++) {
224                 size_t found = ladspa_path.find(standard_paths[i]);
225                 if (found != ladspa_path.npos) {
226                         switch (ladspa_path[found + strlen(standard_paths[i])]) {
227                                 case ':' :
228                                 case '\0':
229                                         continue;
230                                 case G_DIR_SEPARATOR :
231                                         if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
232                                             ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
233                                                 continue;
234                                         }
235                         }
236                 }
237                 if (!ladspa_path.empty())
238                         ladspa_path += ":";
239
240                 ladspa_path += standard_paths[i];
241
242         }
243
244         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_path));
245
246         ladspa_discover_from_path (ladspa_path);
247 }
248
249
250 int
251 PluginManager::add_ladspa_directory (string path)
252 {
253         if (ladspa_discover_from_path (path) == 0) {
254                 ladspa_path += ':';
255                 ladspa_path += path;
256                 return 0;
257         }
258         return -1;
259 }
260
261 static bool ladspa_filter (const string& str, void */*arg*/)
262 {
263         /* Not a dotfile, has a prefix before a period, suffix is "so" */
264
265         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
266 }
267
268 int
269 PluginManager::ladspa_discover_from_path (string /*path*/)
270 {
271         PathScanner scanner;
272         vector<string *> *plugin_objects;
273         vector<string *>::iterator x;
274         int ret = 0;
275
276         plugin_objects = scanner (ladspa_path, ladspa_filter, 0, false, true);
277
278         if (plugin_objects) {
279                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
280                         ladspa_discover (**x);
281                 }
282         }
283
284         vector_delete (plugin_objects);
285         return ret;
286 }
287
288 static bool rdf_filter (const string &str, void* /*arg*/)
289 {
290         return str[0] != '.' &&
291                    ((str.find(".rdf")  == (str.length() - 4)) ||
292             (str.find(".rdfs") == (str.length() - 5)) ||
293                     (str.find(".n3")   == (str.length() - 3)) ||
294                     (str.find(".ttl")  == (str.length() - 4)));
295 }
296
297 void
298 PluginManager::add_ladspa_presets()
299 {
300         add_presets ("ladspa");
301 }
302
303 void
304 PluginManager::add_windows_vst_presets()
305 {
306         add_presets ("windows-vst");
307 }
308
309 void
310 PluginManager::add_lxvst_presets()
311 {
312         add_presets ("lxvst");
313 }
314
315 void
316 PluginManager::add_presets(string domain)
317 {
318
319         PathScanner scanner;
320         vector<string *> *presets;
321         vector<string *>::iterator x;
322
323         char* envvar;
324         if ((envvar = getenv ("HOME")) == 0) {
325                 return;
326         }
327
328         string path = string_compose("%1/.%2/rdf", envvar, domain);
329         presets = scanner (path, rdf_filter, 0, false, true);
330
331         if (presets) {
332                 for (x = presets->begin(); x != presets->end (); ++x) {
333                         string file = "file:" + **x;
334                         if (lrdf_read_file(file.c_str())) {
335                                 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
336                         }
337                 }
338         }
339
340         vector_delete (presets);
341 }
342
343 void
344 PluginManager::add_lrdf_data (const string &path)
345 {
346         PathScanner scanner;
347         vector<string *>* rdf_files;
348         vector<string *>::iterator x;
349
350         rdf_files = scanner (path, rdf_filter, 0, false, true);
351
352         if (rdf_files) {
353                 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
354                         const string uri(string("file://") + **x);
355
356                         if (lrdf_read_file(uri.c_str())) {
357                                 warning << "Could not parse rdf file: " << uri << endmsg;
358                         }
359                 }
360         }
361
362         vector_delete (rdf_files);
363 }
364
365 int
366 PluginManager::ladspa_discover (string path)
367 {
368         void *module;
369         const LADSPA_Descriptor *descriptor;
370         LADSPA_Descriptor_Function dfunc;
371         const char *errstr;
372
373         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
374                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
375                 return -1;
376         }
377
378         dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
379
380         if ((errstr = dlerror()) != 0) {
381                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
382                 error << errstr << endmsg;
383                 dlclose (module);
384                 return -1;
385         }
386
387         for (uint32_t i = 0; ; ++i) {
388                 if ((descriptor = dfunc (i)) == 0) {
389                         break;
390                 }
391
392                 if (!ladspa_plugin_whitelist.empty()) {
393                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
394                                 continue;
395                         }
396                 }
397
398                 PluginInfoPtr info(new LadspaPluginInfo);
399                 info->name = descriptor->Name;
400                 info->category = get_ladspa_category(descriptor->UniqueID);
401                 info->creator = descriptor->Maker;
402                 info->path = path;
403                 info->index = i;
404                 info->n_inputs = ChanCount();
405                 info->n_outputs = ChanCount();
406                 info->type = ARDOUR::LADSPA;
407
408                 char buf[32];
409                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
410                 info->unique_id = buf;
411
412                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
413                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
414                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
415                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
416                                 }
417                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
418                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
419                                 }
420                         }
421                 }
422
423                 if(_ladspa_plugin_info->empty()){
424                         _ladspa_plugin_info->push_back (info);
425                 }
426
427                 //Ensure that the plugin is not already in the plugin list.
428
429                 bool found = false;
430
431                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
432                         if(0 == info->unique_id.compare((*i)->unique_id)){
433                               found = true;
434                         }
435                 }
436
437                 if(!found){
438                     _ladspa_plugin_info->push_back (info);
439                 }
440         }
441
442 // GDB WILL NOT LIKE YOU IF YOU DO THIS
443 //      dlclose (module);
444
445         return 0;
446 }
447
448 string
449 PluginManager::get_ladspa_category (uint32_t plugin_id)
450 {
451         char buf[256];
452         lrdf_statement pattern;
453
454         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
455         pattern.subject = buf;
456         pattern.predicate = (char*)RDF_TYPE;
457         pattern.object = 0;
458         pattern.object_type = lrdf_uri;
459
460         lrdf_statement* matches1 = lrdf_matches (&pattern);
461
462         if (!matches1) {
463                 return "Unknown";
464         }
465
466         pattern.subject = matches1->object;
467         pattern.predicate = (char*)(LADSPA_BASE "hasLabel");
468         pattern.object = 0;
469         pattern.object_type = lrdf_literal;
470
471         lrdf_statement* matches2 = lrdf_matches (&pattern);
472         lrdf_free_statements(matches1);
473
474         if (!matches2) {
475                 return ("Unknown");
476         }
477
478         string label = matches2->object;
479         lrdf_free_statements(matches2);
480
481         /* Kludge LADSPA class names to be singular and match LV2 class names.
482            This avoids duplicate plugin menus for every class, which is necessary
483            to make the plugin category menu at all usable, but is obviously a
484            filthy kludge.
485
486            In the short term, lrdf could be updated so the labels match and a new
487            release made. To support both specs, we should probably be mapping the
488            URIs to the same category in code and perhaps tweaking that hierarchy
489            dynamically to suit the user. Personally, I (drobilla) think that time
490            is better spent replacing the little-used LRDF.
491
492            In the longer term, we will abandon LRDF entirely in favour of LV2 and
493            use that class hierarchy. Aside from fixing this problem properly, that
494            will also allow for translated labels. SWH plugins have been LV2 for
495            ages; TAP needs porting. I don't know of anything else with LRDF data.
496         */
497         if (label == "Utilities") {
498                 return "Utility";
499         } else if (label == "Pitch shifters") {
500                 return "Pitch Shifter";
501         } else if (label != "Dynamics" && label != "Chorus"
502                    &&label[label.length() - 1] == 's'
503                    && label[label.length() - 2] != 's') {
504                 return label.substr(0, label.length() - 1);
505         } else {
506                 return label;
507         }
508 }
509
510 #ifdef LV2_SUPPORT
511 void
512 PluginManager::lv2_refresh ()
513 {
514         delete _lv2_plugin_info;
515         _lv2_plugin_info = LV2PluginInfo::discover();
516 }
517 #endif
518
519 #ifdef AUDIOUNIT_SUPPORT
520 void
521 PluginManager::au_refresh ()
522 {
523         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
524         delete _au_plugin_info;
525         _au_plugin_info = AUPluginInfo::discover();
526 }
527
528 #endif
529
530 #ifdef WINDOWS_VST_SUPPORT
531
532 void
533 PluginManager::windows_vst_refresh ()
534 {
535         if (_windows_vst_plugin_info) {
536                 _windows_vst_plugin_info->clear ();
537         } else {
538                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
539         }
540
541         if (windows_vst_path.length() == 0) {
542                 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
543         }
544
545         windows_vst_discover_from_path (windows_vst_path);
546 }
547
548 int
549 PluginManager::add_windows_vst_directory (string path)
550 {
551         if (windows_vst_discover_from_path (path) == 0) {
552                 windows_vst_path += ':';
553                 windows_vst_path += path;
554                 return 0;
555         }
556         return -1;
557 }
558
559 static bool windows_vst_filter (const string& str, void *arg)
560 {
561         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
562
563         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
564 }
565
566 int
567 PluginManager::windows_vst_discover_from_path (string path)
568 {
569         PathScanner scanner;
570         vector<string *> *plugin_objects;
571         vector<string *>::iterator x;
572         int ret = 0;
573
574         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
575
576         plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
577
578         if (plugin_objects) {
579                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
580                         windows_vst_discover (**x);
581                 }
582         }
583
584         vector_delete (plugin_objects);
585         return ret;
586 }
587
588 int
589 PluginManager::windows_vst_discover (string path)
590 {
591         VSTInfo* finfo;
592         char buf[32];
593
594         if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
595                 warning << "Cannot get Windows VST information from " << path << endmsg;
596                 return -1;
597         }
598
599         if (!finfo->canProcessReplacing) {
600                 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
601                                     finfo->name)
602                         << endl;
603         }
604
605         PluginInfoPtr info (new WindowsVSTPluginInfo);
606
607         /* what a joke freeware VST is */
608
609         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
610                 info->name = PBD::basename_nosuffix (path);
611         } else {
612                 info->name = finfo->name;
613         }
614
615
616         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
617         info->unique_id = buf;
618         info->category = "VST";
619         info->path = path;
620         info->creator = finfo->creator;
621         info->index = 0;
622         info->n_inputs.set_audio (finfo->numInputs);
623         info->n_outputs.set_audio (finfo->numOutputs);
624         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
625         info->type = ARDOUR::Windows_VST;
626
627         _windows_vst_plugin_info->push_back (info);
628         fst_free_info (finfo);
629
630         return 0;
631 }
632
633 #endif // WINDOWS_VST_SUPPORT
634
635 #ifdef LXVST_SUPPORT
636
637 void
638 PluginManager::lxvst_refresh ()
639 {
640         if (_lxvst_plugin_info) {
641                 _lxvst_plugin_info->clear ();
642         } else {
643                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
644         }
645
646         if (lxvst_path.length() == 0) {
647                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
648         }
649
650         lxvst_discover_from_path (lxvst_path);
651 }
652
653 int
654 PluginManager::add_lxvst_directory (string path)
655 {
656         if (lxvst_discover_from_path (path) == 0) {
657                 lxvst_path += ':';
658                 lxvst_path += path;
659                 return 0;
660         }
661         return -1;
662 }
663
664 static bool lxvst_filter (const string& str, void *)
665 {
666         /* Not a dotfile, has a prefix before a period, suffix is "so" */
667
668         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
669 }
670
671 int
672 PluginManager::lxvst_discover_from_path (string path)
673 {
674         PathScanner scanner;
675         vector<string *> *plugin_objects;
676         vector<string *>::iterator x;
677         int ret = 0;
678
679         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
680
681         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
682
683         if (plugin_objects) {
684                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
685                         lxvst_discover (**x);
686                 }
687         }
688
689         vector_delete (plugin_objects);
690         return ret;
691 }
692
693 int
694 PluginManager::lxvst_discover (string path)
695 {
696         VSTInfo* finfo;
697         char buf[32];
698
699         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
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 }