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